aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Davis <jeremy.davis@sonarsource.com>2024-12-03 15:44:01 +0100
committerSteve Marion <steve.marion@sonarsource.com>2024-12-18 11:13:22 +0100
commit46b8d5813f2264efe04dea84225815ac26d7fe29 (patch)
tree7ed0d98f18ed2e11adb424515e222c15193c476c
parentfb8c7e82be68bebdf4473a3020c91699e8021467 (diff)
downloadsonarqube-46b8d5813f2264efe04dea84225815ac26d7fe29.tar.gz
sonarqube-46b8d5813f2264efe04dea84225815ac26d7fe29.zip
SONAR-23605 Move sonar-web to private
-rw-r--r--server/sonar-web/.eslintrc108
-rw-r--r--server/sonar-web/.eslintrc-ci7
-rw-r--r--server/sonar-web/.gitignore23
-rw-r--r--server/sonar-web/.prettierrc14
-rw-r--r--server/sonar-web/.vscode/extensions.json9
-rw-r--r--server/sonar-web/.yarn/plugins/@yarnpkg/plugin-echo-execute.cjs8
-rwxr-xr-xserver/sonar-web/.yarn/releases/yarn-4.2.2.cjs894
-rw-r--r--server/sonar-web/.yarnrc.yml13
-rw-r--r--server/sonar-web/__mocks__/@emotion/react.ts32
-rw-r--r--server/sonar-web/__mocks__/lodash.ts27
-rw-r--r--server/sonar-web/__mocks__/react-intl.tsx62
-rw-r--r--server/sonar-web/__mocks__/react-virtualized.tsx39
-rw-r--r--server/sonar-web/__mocks__/react-virtualized/dist/commonjs/AutoSizer.ts38
-rw-r--r--server/sonar-web/__mocks__/react-virtualized/dist/commonjs/WindowScroller.ts40
-rw-r--r--server/sonar-web/babel.config.js23
-rw-r--r--server/sonar-web/config/jest/CSSStub.js21
-rw-r--r--server/sonar-web/config/jest/DataDogReporter.js90
-rw-r--r--server/sonar-web/config/jest/FileStub.js21
-rw-r--r--server/sonar-web/config/jest/GlobalSetup.js23
-rw-r--r--server/sonar-web/config/jest/JestPreprocess.js27
-rw-r--r--server/sonar-web/config/jest/SetupFailOnConsole.ts34
-rw-r--r--server/sonar-web/config/jest/SetupJestAxe.ts28
-rw-r--r--server/sonar-web/config/jest/SetupReactTestingLibrary.ts97
-rw-r--r--server/sonar-web/config/jest/SetupTestEnvironment.ts197
-rw-r--r--server/sonar-web/config/jest/SetupTheme.js28
-rw-r--r--server/sonar-web/config/jest/jest.polyfills.js29
-rw-r--r--server/sonar-web/config/license.ts70
-rw-r--r--server/sonar-web/config/vite-dev-server-html-plugin.mjs33
-rw-r--r--server/sonar-web/config/vite-dev-server-l10n-plugin.mjs84
-rw-r--r--server/sonar-web/eslint-local-rules/__tests__/convert-class-to-function-component-test.js61
-rw-r--r--server/sonar-web/eslint-local-rules/__tests__/no-api-imports-test.js82
-rw-r--r--server/sonar-web/eslint-local-rules/__tests__/no-conditional-rendering-of-spinner-test.js68
-rw-r--r--server/sonar-web/eslint-local-rules/__tests__/no-implicit-coercion-test.js236
-rw-r--r--server/sonar-web/eslint-local-rules/__tests__/no-within-test.js56
-rw-r--r--server/sonar-web/eslint-local-rules/__tests__/use-await-expect-async-matcher-test.js45
-rw-r--r--server/sonar-web/eslint-local-rules/__tests__/use-jest-mocked-test.js39
-rw-r--r--server/sonar-web/eslint-local-rules/convert-class-to-function-component.js44
-rw-r--r--server/sonar-web/eslint-local-rules/index.js33
-rw-r--r--server/sonar-web/eslint-local-rules/lib/__tests__/use-enum-test.js54
-rw-r--r--server/sonar-web/eslint-local-rules/lib/use-enum.js41
-rw-r--r--server/sonar-web/eslint-local-rules/no-api-imports.js63
-rw-r--r--server/sonar-web/eslint-local-rules/no-conditional-rendering-of-spinner.js60
-rw-r--r--server/sonar-web/eslint-local-rules/no-implicit-coercion.js80
-rw-r--r--server/sonar-web/eslint-local-rules/no-within.js64
-rw-r--r--server/sonar-web/eslint-local-rules/test-config/react.tsx19
-rw-r--r--server/sonar-web/eslint-local-rules/test-config/tsconfig.json6
-rw-r--r--server/sonar-web/eslint-local-rules/use-await-expect-async-matcher.js43
-rw-r--r--server/sonar-web/eslint-local-rules/use-componentqualifier-enum.js22
-rw-r--r--server/sonar-web/eslint-local-rules/use-jest-mocked.js39
-rw-r--r--server/sonar-web/eslint-local-rules/use-metrickey-enum.js146
-rw-r--r--server/sonar-web/eslint-local-rules/use-metrictype-enum.js26
-rw-r--r--server/sonar-web/eslint-local-rules/use-visibility-enum.js22
-rw-r--r--server/sonar-web/jest.config.js101
-rw-r--r--server/sonar-web/public/.htaccess40
-rw-r--r--server/sonar-web/public/WEB-INF/web.xml201
-rw-r--r--server/sonar-web/public/apple-touch-icon.pngbin23411 -> 0 bytes
-rw-r--r--server/sonar-web/public/favicon.icobin15086 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-Black.woff2bin102868 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-BlackItalic.woff2bin108752 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-Bold.woff2bin106140 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-BoldItalic.woff2bin111808 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-ExtraBold.woff2bin106108 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-ExtraBoldItalic.woff2bin111708 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-ExtraLight.woff2bin104232 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-ExtraLightItalic.woff2bin111392 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-Italic.woff2bin106876 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-Light.woff2bin104332 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-LightItalic.woff2bin111332 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-Medium.woff2bin105924 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-MediumItalic.woff2bin112184 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-Regular.woff2bin98868 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-SemiBold.woff2bin105804 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-SemiBoldItalic.woff2bin112048 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-Thin.woff2bin99632 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/Inter-ThinItalic.woff2bin106496 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Inter/inter.css134
-rw-r--r--server/sonar-web/public/fonts/Ubuntu/UFL.txt96
-rw-r--r--server/sonar-web/public/fonts/Ubuntu/Ubuntu.css29
-rw-r--r--server/sonar-web/public/fonts/Ubuntu/UbuntuMono-Bold.woff2bin77156 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Ubuntu/UbuntuMono-BoldItalic.woff2bin94780 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Ubuntu/UbuntuMono-Italic.woff2bin81344 -> 0 bytes
-rw-r--r--server/sonar-web/public/fonts/Ubuntu/UbuntuMono-Regular.woff2bin79680 -> 0 bytes
-rw-r--r--server/sonar-web/public/images/activity-chart.svg1
-rw-r--r--server/sonar-web/public/images/alm/azure.svg3
-rw-r--r--server/sonar-web/public/images/alm/azure_grey.svg15
-rw-r--r--server/sonar-web/public/images/alm/bitbucket-white.svg10
-rw-r--r--server/sonar-web/public/images/alm/bitbucket.svg10
-rw-r--r--server/sonar-web/public/images/alm/bitbucket_grey.svg10
-rw-r--r--server/sonar-web/public/images/alm/github-white.svg4
-rw-r--r--server/sonar-web/public/images/alm/github.svg3
-rw-r--r--server/sonar-web/public/images/alm/github_grey.svg10
-rw-r--r--server/sonar-web/public/images/alm/gitlab.svg1
-rw-r--r--server/sonar-web/public/images/alm/gitlab_grey.svg13
-rw-r--r--server/sonar-web/public/images/check.svg3
-rw-r--r--server/sonar-web/public/images/cross.svg3
-rw-r--r--server/sonar-web/public/images/embed-doc/sq-icon.svg1
-rw-r--r--server/sonar-web/public/images/embed-doc/x-icon-black.svg3
-rw-r--r--server/sonar-web/public/images/filter-large.svg1
-rw-r--r--server/sonar-web/public/images/hotspot-large.svg1
-rw-r--r--server/sonar-web/public/images/loading.gifbin3048 -> 0 bytes
-rw-r--r--server/sonar-web/public/images/mode-tour/step1.pngbin223211 -> 0 bytes
-rw-r--r--server/sonar-web/public/images/mode-tour/step2.pngbin30382 -> 0 bytes
-rw-r--r--server/sonar-web/public/images/mode-tour/step3.pngbin57542 -> 0 bytes
-rw-r--r--server/sonar-web/public/images/mode-tour/step4.pngbin30668 -> 0 bytes
-rw-r--r--server/sonar-web/public/images/mode-tour/step4_se.pngbin7947 -> 0 bytes
-rw-r--r--server/sonar-web/public/images/saml.pngbin15683 -> 0 bytes
-rw-r--r--server/sonar-web/public/images/sonar-logo-horizontal.pngbin2470 -> 0 bytes
-rw-r--r--server/sonar-web/public/images/source-code.svg1
-rw-r--r--server/sonar-web/public/images/tutorials/azure-pipelines.svg1
-rw-r--r--server/sonar-web/public/images/tutorials/commit.svg1
-rw-r--r--server/sonar-web/public/images/tutorials/github-actions.svg3
-rw-r--r--server/sonar-web/public/images/tutorials/jenkins.svg283
-rw-r--r--server/sonar-web/public/images/tutorials/manual.svg16
-rw-r--r--server/sonar-web/public/images/tutorials/refresh.svg1
-rw-r--r--server/sonar-web/public/mstile-512x512.pngbin137594 -> 0 bytes
-rw-r--r--server/sonar-web/public/robots.txt3
-rw-r--r--server/sonar-web/scripts/update-cwes.js127
-rw-r--r--server/sonar-web/scripts/validate-package-json.js36
-rw-r--r--server/sonar-web/src/main/js/@types/css.d.ts28
-rw-r--r--server/sonar-web/src/main/js/@types/emotion.d.ts26
-rw-r--r--server/sonar-web/src/main/js/@types/highlightjs-apex.d.ts27
-rw-r--r--server/sonar-web/src/main/js/@types/highlightjs-sap-abap.d.ts27
-rw-r--r--server/sonar-web/src/main/js/@types/json.d.ts24
-rw-r--r--server/sonar-web/src/main/js/@types/lunr.d.ts61
-rw-r--r--server/sonar-web/src/main/js/@types/md.d.ts24
-rw-r--r--server/sonar-web/src/main/js/api/ai-code-assurance.ts34
-rw-r--r--server/sonar-web/src/main/js/api/alm-integrations.ts273
-rw-r--r--server/sonar-web/src/main/js/api/alm-settings.ts160
-rw-r--r--server/sonar-web/src/main/js/api/application.ts64
-rw-r--r--server/sonar-web/src/main/js/api/auth.ts41
-rw-r--r--server/sonar-web/src/main/js/api/branches.ts62
-rw-r--r--server/sonar-web/src/main/js/api/ce.ts95
-rw-r--r--server/sonar-web/src/main/js/api/component-report.ts64
-rw-r--r--server/sonar-web/src/main/js/api/components.ts256
-rw-r--r--server/sonar-web/src/main/js/api/cves.ts28
-rw-r--r--server/sonar-web/src/main/js/api/dependencies.ts40
-rw-r--r--server/sonar-web/src/main/js/api/dop-translation.ts85
-rw-r--r--server/sonar-web/src/main/js/api/editions.ts36
-rw-r--r--server/sonar-web/src/main/js/api/favorites.ts34
-rw-r--r--server/sonar-web/src/main/js/api/features.ts26
-rw-r--r--server/sonar-web/src/main/js/api/fix-suggestions.ts72
-rw-r--r--server/sonar-web/src/main/js/api/github-provisioning.ts63
-rw-r--r--server/sonar-web/src/main/js/api/gitlab-provisioning.ts93
-rw-r--r--server/sonar-web/src/main/js/api/group-memberships.ts44
-rw-r--r--server/sonar-web/src/main/js/api/issue-filters.ts25
-rw-r--r--server/sonar-web/src/main/js/api/issues.ts166
-rw-r--r--server/sonar-web/src/main/js/api/l10n.ts28
-rw-r--r--server/sonar-web/src/main/js/api/languages.ts27
-rw-r--r--server/sonar-web/src/main/js/api/measures.ts60
-rw-r--r--server/sonar-web/src/main/js/api/messages.ts47
-rw-r--r--server/sonar-web/src/main/js/api/metrics.ts59
-rw-r--r--server/sonar-web/src/main/js/api/mocks/AiCodeAssuredServiceMock.ts49
-rw-r--r--server/sonar-web/src/main/js/api/mocks/AlmIntegrationsServiceMock.ts404
-rw-r--r--server/sonar-web/src/main/js/api/mocks/AlmSettingsServiceMock.ts357
-rw-r--r--server/sonar-web/src/main/js/api/mocks/ApplicationServiceMock.ts70
-rw-r--r--server/sonar-web/src/main/js/api/mocks/BranchesServiceMock.ts117
-rw-r--r--server/sonar-web/src/main/js/api/mocks/CodingRulesServiceMock.ts768
-rw-r--r--server/sonar-web/src/main/js/api/mocks/ComponentsServiceMock.ts426
-rw-r--r--server/sonar-web/src/main/js/api/mocks/ComputeEngineServiceMock.ts274
-rw-r--r--server/sonar-web/src/main/js/api/mocks/CveServiceMock.ts60
-rw-r--r--server/sonar-web/src/main/js/api/mocks/DependenciesServiceMock.ts75
-rw-r--r--server/sonar-web/src/main/js/api/mocks/DopTranslationServiceMock.ts199
-rw-r--r--server/sonar-web/src/main/js/api/mocks/FixSuggestionsServiceMock.ts106
-rw-r--r--server/sonar-web/src/main/js/api/mocks/GithubProvisioningServiceMock.ts214
-rw-r--r--server/sonar-web/src/main/js/api/mocks/GitlabProvisioningServiceMock.ts170
-rw-r--r--server/sonar-web/src/main/js/api/mocks/GroupMembersipsServiceMock.ts89
-rw-r--r--server/sonar-web/src/main/js/api/mocks/GroupsServiceMock.ts111
-rw-r--r--server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts756
-rw-r--r--server/sonar-web/src/main/js/api/mocks/MeasuresServiceMock.ts135
-rw-r--r--server/sonar-web/src/main/js/api/mocks/MessagesServiceMock.ts89
-rw-r--r--server/sonar-web/src/main/js/api/mocks/ModeServiceMock.ts67
-rw-r--r--server/sonar-web/src/main/js/api/mocks/NavigationServiceMock.ts78
-rw-r--r--server/sonar-web/src/main/js/api/mocks/NewCodeDefinitionServiceMock.ts127
-rw-r--r--server/sonar-web/src/main/js/api/mocks/NotificationsMock.ts82
-rw-r--r--server/sonar-web/src/main/js/api/mocks/PermissionsServiceMock.ts492
-rw-r--r--server/sonar-web/src/main/js/api/mocks/PluginsServiceMock.ts242
-rw-r--r--server/sonar-web/src/main/js/api/mocks/ProjectActivityServiceMock.ts262
-rw-r--r--server/sonar-web/src/main/js/api/mocks/ProjectBadgesServiceMock.tsx57
-rw-r--r--server/sonar-web/src/main/js/api/mocks/ProjectDumpServiceMock.ts99
-rw-r--r--server/sonar-web/src/main/js/api/mocks/ProjectLinksServiceMock.ts66
-rw-r--r--server/sonar-web/src/main/js/api/mocks/ProjectsManagementServiceMock.ts188
-rw-r--r--server/sonar-web/src/main/js/api/mocks/ProjectsServiceMock.tsx134
-rw-r--r--server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts837
-rw-r--r--server/sonar-web/src/main/js/api/mocks/QualityProfilesServiceMock.ts846
-rw-r--r--server/sonar-web/src/main/js/api/mocks/ScimProvisioningServiceMock.ts52
-rw-r--r--server/sonar-web/src/main/js/api/mocks/SecurityHotspotServiceMock.ts346
-rw-r--r--server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts333
-rw-r--r--server/sonar-web/src/main/js/api/mocks/SourcesServiceMock.ts51
-rw-r--r--server/sonar-web/src/main/js/api/mocks/SystemServiceMock.ts160
-rw-r--r--server/sonar-web/src/main/js/api/mocks/TimeMachineServiceMock.ts128
-rw-r--r--server/sonar-web/src/main/js/api/mocks/UserTokensMock.ts115
-rw-r--r--server/sonar-web/src/main/js/api/mocks/UsersServiceMock.ts303
-rw-r--r--server/sonar-web/src/main/js/api/mocks/WebApiServiceMock.ts117
-rw-r--r--server/sonar-web/src/main/js/api/mocks/WebhooksMock.ts142
-rw-r--r--server/sonar-web/src/main/js/api/mocks/data/branches.ts62
-rw-r--r--server/sonar-web/src/main/js/api/mocks/data/components.ts404
-rw-r--r--server/sonar-web/src/main/js/api/mocks/data/dop-translation.ts46
-rw-r--r--server/sonar-web/src/main/js/api/mocks/data/ids.ts131
-rw-r--r--server/sonar-web/src/main/js/api/mocks/data/issues.ts500
-rw-r--r--server/sonar-web/src/main/js/api/mocks/data/measures.ts379
-rw-r--r--server/sonar-web/src/main/js/api/mocks/data/projects.ts1955
-rw-r--r--server/sonar-web/src/main/js/api/mocks/data/qualityProfiles.ts72
-rw-r--r--server/sonar-web/src/main/js/api/mocks/data/rules.ts374
-rw-r--r--server/sonar-web/src/main/js/api/mocks/data/sources.ts92
-rw-r--r--server/sonar-web/src/main/js/api/mocks/data/utils.ts54
-rw-r--r--server/sonar-web/src/main/js/api/mocks/data/web-api.ts774
-rw-r--r--server/sonar-web/src/main/js/api/mocks/data/webhooks.ts101
-rw-r--r--server/sonar-web/src/main/js/api/mode.ts32
-rw-r--r--server/sonar-web/src/main/js/api/navigation.ts46
-rw-r--r--server/sonar-web/src/main/js/api/newCodeDefinition.ts54
-rw-r--r--server/sonar-web/src/main/js/api/notifications.ts36
-rw-r--r--server/sonar-web/src/main/js/api/permissions.ts231
-rw-r--r--server/sonar-web/src/main/js/api/plugins.ts67
-rw-r--r--server/sonar-web/src/main/js/api/project-badges.ts33
-rw-r--r--server/sonar-web/src/main/js/api/project-dump.ts36
-rw-r--r--server/sonar-web/src/main/js/api/project-management.ts94
-rw-r--r--server/sonar-web/src/main/js/api/projectActivity.ts118
-rw-r--r--server/sonar-web/src/main/js/api/projectLinks.ts43
-rw-r--r--server/sonar-web/src/main/js/api/quality-gates.ts201
-rw-r--r--server/sonar-web/src/main/js/api/quality-profiles.ts364
-rw-r--r--server/sonar-web/src/main/js/api/regulatory-report.ts29
-rw-r--r--server/sonar-web/src/main/js/api/rules.ts107
-rw-r--r--server/sonar-web/src/main/js/api/scim-provisioning.ts37
-rw-r--r--server/sonar-web/src/main/js/api/security-hotspots.ts130
-rw-r--r--server/sonar-web/src/main/js/api/settings.ts120
-rw-r--r--server/sonar-web/src/main/js/api/sources.ts26
-rw-r--r--server/sonar-web/src/main/js/api/static.ts28
-rw-r--r--server/sonar-web/src/main/js/api/system.ts104
-rw-r--r--server/sonar-web/src/main/js/api/time-machine.ts74
-rw-r--r--server/sonar-web/src/main/js/api/user-tokens.ts43
-rw-r--r--server/sonar-web/src/main/js/api/user_groups.ts51
-rw-r--r--server/sonar-web/src/main/js/api/users.ts105
-rw-r--r--server/sonar-web/src/main/js/api/web-api.ts49
-rw-r--r--server/sonar-web/src/main/js/api/webhooks.ts62
-rw-r--r--server/sonar-web/src/main/js/app/components/AdminContainer.tsx166
-rw-r--r--server/sonar-web/src/main/js/app/components/AdminContext.tsx41
-rw-r--r--server/sonar-web/src/main/js/app/components/AlmSynchronisationWarning.tsx183
-rw-r--r--server/sonar-web/src/main/js/app/components/App.tsx101
-rw-r--r--server/sonar-web/src/main/js/app/components/ChangeInCalculationPill.tsx56
-rw-r--r--server/sonar-web/src/main/js/app/components/ComponentContainer.tsx425
-rw-r--r--server/sonar-web/src/main/js/app/components/ComponentContainerNotFound.tsx47
-rw-r--r--server/sonar-web/src/main/js/app/components/DocumentationRedirect.tsx50
-rw-r--r--server/sonar-web/src/main/js/app/components/FormattingHelp.tsx182
-rw-r--r--server/sonar-web/src/main/js/app/components/GitHubSynchronisationWarning.tsx39
-rw-r--r--server/sonar-web/src/main/js/app/components/GitLabSynchronisationWarning.tsx39
-rw-r--r--server/sonar-web/src/main/js/app/components/GlobalContainer.tsx135
-rw-r--r--server/sonar-web/src/main/js/app/components/GlobalFooter.tsx183
-rw-r--r--server/sonar-web/src/main/js/app/components/GlobalFooterBranding.tsx65
-rw-r--r--server/sonar-web/src/main/js/app/components/KeyboardShortcutsModal.tsx214
-rw-r--r--server/sonar-web/src/main/js/app/components/Landing.tsx41
-rw-r--r--server/sonar-web/src/main/js/app/components/LicensePromptModal.tsx51
-rw-r--r--server/sonar-web/src/main/js/app/components/MigrationContainer.tsx39
-rw-r--r--server/sonar-web/src/main/js/app/components/ModeTour.tsx252
-rw-r--r--server/sonar-web/src/main/js/app/components/NonAdminPagesContainer.tsx54
-rw-r--r--server/sonar-web/src/main/js/app/components/NotFound.tsx42
-rw-r--r--server/sonar-web/src/main/js/app/components/PageTracker.tsx78
-rw-r--r--server/sonar-web/src/main/js/app/components/PluginRiskConsent.tsx93
-rw-r--r--server/sonar-web/src/main/js/app/components/ProjectAdminContainer.tsx89
-rw-r--r--server/sonar-web/src/main/js/app/components/RecentHistory.ts69
-rw-r--r--server/sonar-web/src/main/js/app/components/ResetPassword.tsx65
-rw-r--r--server/sonar-web/src/main/js/app/components/SimpleContainer.tsx40
-rw-r--r--server/sonar-web/src/main/js/app/components/SimpleSessionsContainer.tsx38
-rw-r--r--server/sonar-web/src/main/js/app/components/SonarLintConnection.tsx177
-rw-r--r--server/sonar-web/src/main/js/app/components/StartupModal.tsx83
-rw-r--r--server/sonar-web/src/main/js/app/components/SystemAnnouncement.tsx103
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/AdminContainer-test.tsx182
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/App-test.tsx56
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/CalculationChangeMessage-test.tsx87
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx672
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/ComponentContainerNotFound-test.tsx41
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/DocumentationRedirect-test.tsx42
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/FormattingHelp-test.tsx29
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/GlobalFooter-test.tsx157
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/KeyboardShortcutsModal-test.tsx75
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/Landing-test.tsx46
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/MigrationContainer-test.tsx76
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/ModeTour-test.tsx225
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/NonAdminPagesContainer-test.tsx58
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/PageTracker-test.tsx87
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/PluginRiskConsent-test.tsx101
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/ProjectAdminContainer-test.tsx62
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/RecentHistory-test.tsx105
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/ResetPassword-test.tsx82
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/SonarLintConnection-test.tsx155
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx109
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/SystemAnnouncement-test.tsx102
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/UpdateNotification-it.tsx637
-rw-r--r--server/sonar-web/src/main/js/app/components/admin/StickyTable.tsx33
-rw-r--r--server/sonar-web/src/main/js/app/components/admin/withAdminPagesOutletContext.tsx33
-rw-r--r--server/sonar-web/src/main/js/app/components/app-state/AppStateContext.tsx36
-rw-r--r--server/sonar-web/src/main/js/app/components/app-state/AppStateContextProvider.tsx34
-rw-r--r--server/sonar-web/src/main/js/app/components/app-state/withAppStateContext.tsx50
-rw-r--r--server/sonar-web/src/main/js/app/components/available-features/AvailableFeaturesContext.tsx26
-rw-r--r--server/sonar-web/src/main/js/app/components/available-features/withAvailableFeatures.tsx59
-rw-r--r--server/sonar-web/src/main/js/app/components/calculation-notification/CalculationChangeMessage.tsx65
-rw-r--r--server/sonar-web/src/main/js/app/components/componentContext/ComponentContext.ts28
-rw-r--r--server/sonar-web/src/main/js/app/components/componentContext/withComponentContext.tsx76
-rw-r--r--server/sonar-web/src/main/js/app/components/current-user/CurrentUserContext.ts53
-rw-r--r--server/sonar-web/src/main/js/app/components/current-user/CurrentUserContextProvider.tsx70
-rw-r--r--server/sonar-web/src/main/js/app/components/current-user/withCurrentUserContext.tsx47
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/CreateApplicationForm.tsx197
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/Extension.tsx143
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/GlobalAdminPageExtension.tsx32
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/GlobalPageExtension.tsx51
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/PortfolioPage.tsx25
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/PortfoliosPage.tsx25
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/ProjectAdminPageExtension.tsx44
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/ProjectPageExtension.tsx55
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/__tests__/Extension-test.tsx139
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/__tests__/GlobalAdminPageExtension-test.tsx65
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/__tests__/GlobalPageExtension-test.tsx65
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/__tests__/ProjectAdminPageExtension-test.tsx79
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/__tests__/ProjectPageExtension-test.tsx94
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/__tests__/exposeLibraries-test.ts31
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts57
-rw-r--r--server/sonar-web/src/main/js/app/components/global-search/GlobalSearch.tsx435
-rw-r--r--server/sonar-web/src/main/js/app/components/global-search/GlobalSearchResult.tsx69
-rw-r--r--server/sonar-web/src/main/js/app/components/global-search/GlobalSearchResults.tsx96
-rw-r--r--server/sonar-web/src/main/js/app/components/global-search/GlobalSearchShowMore.tsx71
-rw-r--r--server/sonar-web/src/main/js/app/components/global-search/__tests__/GlobalSearch-it.tsx214
-rw-r--r--server/sonar-web/src/main/js/app/components/global-search/utils.ts50
-rw-r--r--server/sonar-web/src/main/js/app/components/indexation/IndexationContext.ts24
-rw-r--r--server/sonar-web/src/main/js/app/components/indexation/IndexationContextProvider.tsx73
-rw-r--r--server/sonar-web/src/main/js/app/components/indexation/IndexationNotification.tsx144
-rw-r--r--server/sonar-web/src/main/js/app/components/indexation/IndexationNotificationHelper.ts86
-rw-r--r--server/sonar-web/src/main/js/app/components/indexation/IndexationNotificationRenderer.tsx327
-rw-r--r--server/sonar-web/src/main/js/app/components/indexation/PageUnavailableDueToIndexation.tsx63
-rw-r--r--server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationContextProvider-test.tsx81
-rw-r--r--server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationNotification-test.tsx204
-rw-r--r--server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationNotificationHelper-test.tsx94
-rw-r--r--server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationNotificationRenderer-test.tsx71
-rw-r--r--server/sonar-web/src/main/js/app/components/indexation/__tests__/PageUnavailableDueToIndexation-test.tsx85
-rw-r--r--server/sonar-web/src/main/js/app/components/languages/LanguagesContext.ts24
-rw-r--r--server/sonar-web/src/main/js/app/components/languages/LanguagesContextProvider.tsx62
-rw-r--r--server/sonar-web/src/main/js/app/components/languages/__tests__/LanguagesContextProvider-test.tsx61
-rw-r--r--server/sonar-web/src/main/js/app/components/languages/withLanguagesContext.tsx46
-rw-r--r--server/sonar-web/src/main/js/app/components/metrics/MetricsContext.tsx24
-rw-r--r--server/sonar-web/src/main/js/app/components/metrics/MetricsContextProvider.tsx63
-rw-r--r--server/sonar-web/src/main/js/app/components/metrics/RatingComponent.tsx139
-rw-r--r--server/sonar-web/src/main/js/app/components/metrics/__tests__/MetricsContextProvider-test.tsx62
-rw-r--r--server/sonar-web/src/main/js/app/components/metrics/withMetricsContext.tsx50
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/Breadcrumb.tsx80
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx89
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/ComponentNavProjectBindingErrorNotif.tsx66
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/Header.tsx45
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx582
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx246
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavProjectBindingErrorNotif-test.tsx56
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/Header-test.tsx205
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/Menu-test.tsx192
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/__tests__/utils-test.ts67
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchHelpTooltip.tsx135
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchLikeNavigation.tsx139
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLike.tsx47
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLikeMergeInformation.tsx54
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/Menu.tsx205
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/MenuItem.tsx75
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/MenuItemList.tsx139
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/PRLink.tsx88
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/QualityGateStatus.tsx52
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/utils.ts55
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx57
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx168
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMore.tsx58
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx75
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserMenu.tsx38
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/global/MainSonarQubeBar.tsx54
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNav-test.tsx59
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavMenu-test.tsx63
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx43
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/settings/PendingPluginsActionNotif.tsx84
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.tsx261
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/settings/SystemRestartNotif.tsx41
-rw-r--r--server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.tsx91
-rw-r--r--server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/PromotionNotification-test.tsx65
-rw-r--r--server/sonar-web/src/main/js/app/components/update-notification/SQCBUpdateBanners.tsx128
-rw-r--r--server/sonar-web/src/main/js/app/components/update-notification/SQSUpdateBanner.tsx99
-rw-r--r--server/sonar-web/src/main/js/app/components/update-notification/UpdateNotification.tsx65
-rw-r--r--server/sonar-web/src/main/js/app/components/update-notification/helpers.ts114
-rw-r--r--server/sonar-web/src/main/js/app/index.ts87
-rw-r--r--server/sonar-web/src/main/js/apps/projects/__tests__/utils-test.ts221
-rw-r--r--server/sonar-web/src/main/js/apps/projects/query.ts269
-rw-r--r--server/sonar-web/src/main/js/apps/projects/types.ts46
-rw-r--r--server/sonar-web/src/main/js/apps/projects/utils.ts409
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/__tests__/utils-test.ts141
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/utils.ts339
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfileApp-it.tsx565
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx424
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/__tests__/__snapshots__/utils-test.ts.snap143
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/__tests__/utils-test.ts66
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/constants.ts22
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/qualityProfilesContext.tsx53
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/types.ts77
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/utils.ts113
-rw-r--r--server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts224
-rw-r--r--server/sonar-web/src/main/js/apps/settings/constants.ts215
-rw-r--r--server/sonar-web/src/main/js/apps/settings/utils.ts271
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/SourceViewer.tsx639
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx346
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/SourceViewerContext.tsx37
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.tsx298
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/SourceViewerPreview.tsx343
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewer-it.tsx459
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/components/DuplicationPopup.tsx180
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/components/Line.css33
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx245
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/components/LineCode.tsx237
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/components/LineDuplicationBlock.tsx83
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesIndicator.tsx95
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesList.tsx81
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/components/LineOptionsPopup.tsx55
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/components/LineSCM.tsx93
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/components/SCMPopup.tsx60
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/__snapshots__/loadIssues-test.ts.snap136
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/duplications-test.ts50
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/highlight-test.ts56
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/indexing-test.ts61
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/issueLocations-test.ts48
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/loadIssues-test.ts104
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/helpers/duplications.ts50
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/helpers/getCoverageStatus.ts35
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/helpers/highlight.ts187
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/helpers/indexing.ts102
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/helpers/issueLocations.ts60
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/helpers/lines.ts58
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/helpers/loadIssues.ts103
-rw-r--r--server/sonar-web/src/main/js/components/SourceViewer/styles.css148
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/AddGraphMetric.tsx153
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/AddGraphMetricPopup.tsx120
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/ChartLegend.tsx58
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/DataTableModal.tsx224
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/DefinitionChangeEventInner.tsx174
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/EventInner.tsx86
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphHistory.tsx175
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphsHeader.tsx95
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphsHistory.tsx129
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphsLegendCustom.tsx84
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphsLegendItem.tsx82
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphsLegendStatic.tsx57
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphsTooltips.tsx144
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContent.tsx40
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentCoverage.tsx63
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentDuplication.tsx58
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentEvents.tsx45
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphsZoom.tsx77
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/RichQualityGateEventInner.tsx129
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/RichQualityProfileEventInner.tsx74
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/SqUpgradeActivityEventMessage.tsx42
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/__tests__/ActivityGraph-it.tsx405
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/__tests__/DataTableModal-it.tsx135
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/__tests__/EventInner-it.tsx260
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltips-it.tsx119
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/utils-test.ts.snap80
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/__tests__/utils-test.ts260
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/utils.ts240
-rw-r--r--server/sonar-web/src/main/js/components/branding/SonarQubeConnectionIllustration.tsx199
-rw-r--r--server/sonar-web/src/main/js/components/branding/SonarQubeIDEPromotionIllustration.tsx107
-rw-r--r--server/sonar-web/src/main/js/components/branding/SonarQubeProductLogo.tsx38
-rw-r--r--server/sonar-web/src/main/js/components/branding/__tests__/SonarQubeConnectionIllustration-test.tsx39
-rw-r--r--server/sonar-web/src/main/js/components/branding/__tests__/__snapshots__/SonarQubeConnectionIllustration-test.tsx.snap189
-rw-r--r--server/sonar-web/src/main/js/components/charts/AdvancedTimeline.css66
-rw-r--r--server/sonar-web/src/main/js/components/charts/AdvancedTimeline.tsx683
-rw-r--r--server/sonar-web/src/main/js/components/charts/ColorBoxLegend.tsx69
-rw-r--r--server/sonar-web/src/main/js/components/charts/ColorGradientLegend.tsx140
-rw-r--r--server/sonar-web/src/main/js/components/charts/DonutChart.tsx89
-rw-r--r--server/sonar-web/src/main/js/components/charts/LanguageDistribution.tsx80
-rw-r--r--server/sonar-web/src/main/js/components/charts/LineChart.css46
-rw-r--r--server/sonar-web/src/main/js/components/charts/SplitLine.tsx47
-rw-r--r--server/sonar-web/src/main/js/components/charts/SplitLinePopover.tsx64
-rw-r--r--server/sonar-web/src/main/js/components/charts/ZoomTimeLine.tsx424
-rw-r--r--server/sonar-web/src/main/js/components/charts/__tests__/AdvancedTimeline-test.tsx110
-rw-r--r--server/sonar-web/src/main/js/components/charts/__tests__/LanguageDistribution-test.tsx37
-rw-r--r--server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/AdvancedTimeline-test.tsx.snap2904
-rw-r--r--server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/LanguageDistribution-test.tsx.snap147
-rw-r--r--server/sonar-web/src/main/js/components/common/ActivityLink.tsx50
-rw-r--r--server/sonar-web/src/main/js/components/common/DisableableSelectOption.tsx44
-rw-r--r--server/sonar-web/src/main/js/components/common/DocumentationLink.tsx40
-rw-r--r--server/sonar-web/src/main/js/components/common/EmailInput.tsx85
-rw-r--r--server/sonar-web/src/main/js/components/common/EmptySearch.tsx35
-rw-r--r--server/sonar-web/src/main/js/components/common/FormattingTips.tsx56
-rw-r--r--server/sonar-web/src/main/js/components/common/FormattingTipsWithLink.tsx71
-rw-r--r--server/sonar-web/src/main/js/components/common/InstanceMessage.tsx37
-rw-r--r--server/sonar-web/src/main/js/components/common/Link.tsx78
-rw-r--r--server/sonar-web/src/main/js/components/common/LocationMessage.tsx29
-rw-r--r--server/sonar-web/src/main/js/components/common/MetaLink.tsx74
-rw-r--r--server/sonar-web/src/main/js/components/common/ModeBanner.tsx114
-rw-r--r--server/sonar-web/src/main/js/components/common/PageCounter.tsx39
-rw-r--r--server/sonar-web/src/main/js/components/common/PrivacyBadgeContainer.tsx42
-rw-r--r--server/sonar-web/src/main/js/components/common/ResetPasswordForm.tsx124
-rw-r--r--server/sonar-web/src/main/js/components/common/RestartButton.tsx67
-rw-r--r--server/sonar-web/src/main/js/components/common/ScreenPositionHelper.tsx70
-rw-r--r--server/sonar-web/src/main/js/components/common/StatusIndicator.tsx44
-rw-r--r--server/sonar-web/src/main/js/components/common/UserPasswordInput.tsx190
-rw-r--r--server/sonar-web/src/main/js/components/common/VisibilitySelector.tsx53
-rw-r--r--server/sonar-web/src/main/js/components/common/__mocks__/ScreenPositionHelper.tsx31
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/ActivityLink-test.tsx58
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/FormattingTips-test.tsx54
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/FormattingTipsWithLink-test.tsx54
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/Link-test.tsx50
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/ModeBanner-test.tsx144
-rw-r--r--server/sonar-web/src/main/js/components/controls/ClickEventBoundary.tsx36
-rw-r--r--server/sonar-web/src/main/js/components/controls/ComponentReportActions.tsx141
-rw-r--r--server/sonar-web/src/main/js/components/controls/ComponentReportActionsRenderer.tsx112
-rw-r--r--server/sonar-web/src/main/js/components/controls/ConfirmButton.tsx60
-rw-r--r--server/sonar-web/src/main/js/components/controls/ConfirmModal.tsx104
-rw-r--r--server/sonar-web/src/main/js/components/controls/DocumentClickHandler.tsx54
-rw-r--r--server/sonar-web/src/main/js/components/controls/EscKeydownHandler.tsx49
-rw-r--r--server/sonar-web/src/main/js/components/controls/Favorite.tsx84
-rw-r--r--server/sonar-web/src/main/js/components/controls/FocusOutHandler.tsx61
-rw-r--r--server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx93
-rw-r--r--server/sonar-web/src/main/js/components/controls/InputValidationField.tsx54
-rw-r--r--server/sonar-web/src/main/js/components/controls/ListFooter.tsx131
-rw-r--r--server/sonar-web/src/main/js/components/controls/ManagedFilter.tsx62
-rw-r--r--server/sonar-web/src/main/js/components/controls/ModalButton.tsx85
-rw-r--r--server/sonar-web/src/main/js/components/controls/ModalValidationField.tsx73
-rw-r--r--server/sonar-web/src/main/js/components/controls/OutsideClickHandler.tsx69
-rw-r--r--server/sonar-web/src/main/js/components/controls/ScreenPositionFixer.tsx114
-rw-r--r--server/sonar-web/src/main/js/components/controls/SelectList.tsx204
-rw-r--r--server/sonar-web/src/main/js/components/controls/SelectListListContainer.tsx135
-rw-r--r--server/sonar-web/src/main/js/components/controls/SelectListListElement.tsx63
-rw-r--r--server/sonar-web/src/main/js/components/controls/Tooltip.css135
-rw-r--r--server/sonar-web/src/main/js/components/controls/Tooltip.tsx495
-rw-r--r--server/sonar-web/src/main/js/components/controls/UpDownKeyboardHandler.tsx120
-rw-r--r--server/sonar-web/src/main/js/components/controls/ValidationForm.tsx68
-rw-r--r--server/sonar-web/src/main/js/components/controls/ValidationModal.tsx84
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/ComponentReportActions-test.tsx173
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/Favorite-test.tsx74
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx70
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx82
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/SelectList-test.tsx149
-rw-r--r--server/sonar-web/src/main/js/components/devops-platform/AlmSettingsInstanceSelector.tsx88
-rw-r--r--server/sonar-web/src/main/js/components/embed-docs-modal/DocItemLink.tsx35
-rw-r--r--server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx115
-rw-r--r--server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopupHelper.tsx72
-rw-r--r--server/sonar-web/src/main/js/components/embed-docs-modal/Suggestions.tsx82
-rw-r--r--server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsContext.ts39
-rw-r--r--server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsProvider.tsx75
-rw-r--r--server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx87
-rw-r--r--server/sonar-web/src/main/js/components/facets/Facet.tsx163
-rw-r--r--server/sonar-web/src/main/js/components/facets/FacetHelp.tsx77
-rw-r--r--server/sonar-web/src/main/js/components/facets/SeverityFacet.tsx72
-rw-r--r--server/sonar-web/src/main/js/components/facets/StandardSeverityFacet.tsx56
-rw-r--r--server/sonar-web/src/main/js/components/hoc/__tests__/withIndexationGuard-test.tsx58
-rw-r--r--server/sonar-web/src/main/js/components/hoc/whenLoggedIn.tsx46
-rw-r--r--server/sonar-web/src/main/js/components/hoc/withCLanguageFeature.tsx49
-rw-r--r--server/sonar-web/src/main/js/components/hoc/withIndexationContext.tsx54
-rw-r--r--server/sonar-web/src/main/js/components/hoc/withIndexationGuard.tsx38
-rw-r--r--server/sonar-web/src/main/js/components/hoc/withKeyboardNavigation.tsx165
-rw-r--r--server/sonar-web/src/main/js/components/hoc/withLocation.tsx32
-rw-r--r--server/sonar-web/src/main/js/components/icon-mappers/AIAssuredIcon.tsx61
-rw-r--r--server/sonar-web/src/main/js/components/icon-mappers/BranchLikeIcon.tsx58
-rw-r--r--server/sonar-web/src/main/js/components/icon-mappers/IssueSeverityIcon.tsx52
-rw-r--r--server/sonar-web/src/main/js/components/icon-mappers/IssueStatusIcon.tsx62
-rw-r--r--server/sonar-web/src/main/js/components/icon-mappers/IssueTypeIcon.tsx59
-rw-r--r--server/sonar-web/src/main/js/components/icon-mappers/SeverityIcon.tsx55
-rw-r--r--server/sonar-web/src/main/js/components/icon-mappers/SoftwareImpactSeverityIcon.tsx69
-rw-r--r--server/sonar-web/src/main/js/components/icon-mappers/__tests__/BranchLikeIcon-test.tsx42
-rw-r--r--server/sonar-web/src/main/js/components/illustrations/AiAssuredIllustration.tsx49
-rw-r--r--server/sonar-web/src/main/js/components/illustrations/AiCodeAssuranceCheckIllustration.tsx79
-rw-r--r--server/sonar-web/src/main/js/components/illustrations/AiCodeAssuranceIllustration.tsx71
-rw-r--r--server/sonar-web/src/main/js/components/intl/DateFormatter.tsx50
-rw-r--r--server/sonar-web/src/main/js/components/intl/DateFromNow.tsx69
-rw-r--r--server/sonar-web/src/main/js/components/intl/DateTimeFormatter.tsx46
-rw-r--r--server/sonar-web/src/main/js/components/intl/TimeFormatter.tsx51
-rw-r--r--server/sonar-web/src/main/js/components/intl/TranslatedMessage.tsx28
-rw-r--r--server/sonar-web/src/main/js/components/intl/__mocks__/DateFromNow.tsx31
-rw-r--r--server/sonar-web/src/main/js/components/intl/__tests__/DateFormatter-test.tsx43
-rw-r--r--server/sonar-web/src/main/js/components/intl/__tests__/DateFromNow-test.tsx65
-rw-r--r--server/sonar-web/src/main/js/components/intl/__tests__/DateTimeFormatter-test.tsx40
-rw-r--r--server/sonar-web/src/main/js/components/intl/__tests__/TimeFormatter-test.tsx43
-rw-r--r--server/sonar-web/src/main/js/components/intl/__tests__/dateUtils-test.ts43
-rw-r--r--server/sonar-web/src/main/js/components/intl/dateUtils.ts58
-rw-r--r--server/sonar-web/src/main/js/components/issue/Issue.css266
-rw-r--r--server/sonar-web/src/main/js/components/issue/Issue.tsx136
-rw-r--r--server/sonar-web/src/main/js/components/issue/__tests__/Issue-it.tsx476
-rw-r--r--server/sonar-web/src/main/js/components/issue/__tests__/actions-test.ts84
-rw-r--r--server/sonar-web/src/main/js/components/issue/actions.ts56
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/DeprecatedFieldTooltip.tsx44
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueActionsBar.tsx102
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueAssign.tsx160
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueChangelogDiff.tsx117
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueMessage.tsx85
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueMetaBar.tsx175
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssuePrioritized.tsx31
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueSeverity.tsx44
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueTags.tsx86
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.tsx52
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueTransition.tsx130
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueTransitionItem.tsx82
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueTransitionOverlay.tsx122
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueTransitionOverlayHeader.tsx64
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueType.tsx43
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueView.tsx226
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/SelectedTransitionItem.tsx56
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/SonarLintBadge.tsx91
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/__tests__/IssueChangelogDiff-test.tsx72
-rw-r--r--server/sonar-web/src/main/js/components/issue/helpers.ts33
-rw-r--r--server/sonar-web/src/main/js/components/issue/popups/IssueTagsPopup.tsx70
-rw-r--r--server/sonar-web/src/main/js/components/locations/SingleFileLocationNavigator.css43
-rw-r--r--server/sonar-web/src/main/js/components/locations/SingleFileLocationNavigator.tsx107
-rw-r--r--server/sonar-web/src/main/js/components/logos/SonarLintLogo.tsx67
-rw-r--r--server/sonar-web/src/main/js/components/measure/MeasureIndicator.tsx63
-rw-r--r--server/sonar-web/src/main/js/components/measure/RatingTooltipContent.tsx93
-rw-r--r--server/sonar-web/src/main/js/components/measure/__tests__/MeasureIndicator-test.tsx61
-rw-r--r--server/sonar-web/src/main/js/components/measure/__tests__/__snapshots__/MeasureIndicator-test.tsx.snap116
-rw-r--r--server/sonar-web/src/main/js/components/measure/__tests__/utils-test.tsx35
-rw-r--r--server/sonar-web/src/main/js/components/measure/utils.ts66
-rw-r--r--server/sonar-web/src/main/js/components/new-code-definition/BranchNCDAutoUpdateMessage.tsx98
-rw-r--r--server/sonar-web/src/main/js/components/new-code-definition/GlobalNewCodeDefinitionDescription.tsx68
-rw-r--r--server/sonar-web/src/main/js/components/new-code-definition/NCDAutoUpdateMessage.tsx140
-rw-r--r--server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionAnalysisWarning.tsx46
-rw-r--r--server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionDaysOption.tsx179
-rw-r--r--server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionPreviousVersionOption.tsx54
-rw-r--r--server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionSelector.tsx187
-rw-r--r--server/sonar-web/src/main/js/components/new-code-definition/__tests__/NCDAutoUpdateMessage-test.tsx216
-rw-r--r--server/sonar-web/src/main/js/components/new-code-definition/utils.ts70
-rw-r--r--server/sonar-web/src/main/js/components/notifications/NotificationsList.tsx171
-rw-r--r--server/sonar-web/src/main/js/components/permissions/AllHoldersList.tsx136
-rw-r--r--server/sonar-web/src/main/js/components/permissions/GroupHolder.tsx136
-rw-r--r--server/sonar-web/src/main/js/components/permissions/HoldersList.tsx204
-rw-r--r--server/sonar-web/src/main/js/components/permissions/PermissionCell.tsx110
-rw-r--r--server/sonar-web/src/main/js/components/permissions/PermissionHeader.tsx104
-rw-r--r--server/sonar-web/src/main/js/components/permissions/SearchForm.tsx53
-rw-r--r--server/sonar-web/src/main/js/components/permissions/UserHolder.tsx131
-rw-r--r--server/sonar-web/src/main/js/components/permissions/usePermissionChange.tsx101
-rw-r--r--server/sonar-web/src/main/js/components/rules/AiCodeFixTab.tsx91
-rw-r--r--server/sonar-web/src/main/js/components/rules/CveDetails.tsx68
-rw-r--r--server/sonar-web/src/main/js/components/rules/IssueSuggestionFileSnippet.tsx218
-rw-r--r--server/sonar-web/src/main/js/components/rules/IssueSuggestionLine.tsx145
-rw-r--r--server/sonar-web/src/main/js/components/rules/IssueTabViewer.tsx432
-rw-r--r--server/sonar-web/src/main/js/components/rules/MoreInfoRuleDescription.tsx120
-rw-r--r--server/sonar-web/src/main/js/components/rules/OtherContextOption.tsx51
-rw-r--r--server/sonar-web/src/main/js/components/rules/RuleDescription.tsx247
-rw-r--r--server/sonar-web/src/main/js/components/rules/RuleTabViewer.tsx308
-rw-r--r--server/sonar-web/src/main/js/components/rules/TabSelectorContext.ts25
-rw-r--r--server/sonar-web/src/main/js/components/rules/educationPrinciples/DefenseInDepth.tsx47
-rw-r--r--server/sonar-web/src/main/js/components/rules/educationPrinciples/NeverTrustUserInput.tsx52
-rw-r--r--server/sonar-web/src/main/js/components/search-navigator.css320
-rw-r--r--server/sonar-web/src/main/js/components/shared/AppVersionStatus.tsx60
-rw-r--r--server/sonar-web/src/main/js/components/shared/CleanCodeAttributePill.tsx68
-rw-r--r--server/sonar-web/src/main/js/components/shared/ComponentMissingMqrMetricsMessage.tsx90
-rw-r--r--server/sonar-web/src/main/js/components/shared/DrilldownLink.tsx76
-rw-r--r--server/sonar-web/src/main/js/components/shared/IssueTypePill.tsx128
-rw-r--r--server/sonar-web/src/main/js/components/shared/SeverityHelper.tsx40
-rw-r--r--server/sonar-web/src/main/js/components/shared/SoftwareImpactPill.tsx168
-rw-r--r--server/sonar-web/src/main/js/components/shared/SoftwareImpactPillList.tsx90
-rw-r--r--server/sonar-web/src/main/js/components/shared/StatusHelper.tsx37
-rw-r--r--server/sonar-web/src/main/js/components/shared/TypeHelper.tsx45
-rw-r--r--server/sonar-web/src/main/js/components/shared/__tests__/utils-test.ts86
-rw-r--r--server/sonar-web/src/main/js/components/shared/utils.ts147
-rw-r--r--server/sonar-web/src/main/js/components/tags/TagsList.tsx62
-rw-r--r--server/sonar-web/src/main/js/components/templates/FilterBarTemplate.tsx188
-rw-r--r--server/sonar-web/src/main/js/components/templates/__tests__/FilterBarTemplate-test.tsx43
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx116
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx296
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-it.tsx259
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/__tests__/utils-test.ts101
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/AzurePipelinesTutorial.tsx102
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/BranchAnalysisStepContent.tsx52
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ExtensionInstallationStepContent.tsx52
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/JavaToolInstallation.tsx83
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ServiceEndpointStepContent.tsx105
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/AzurePipelinesTutorial-it.tsx256
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/AzurePipelinesTutorial-it.tsx.snap91
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/AlertClassicEditor.tsx47
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/AnalysisCommand.tsx63
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/ClangGCC.tsx187
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/DotNet.tsx60
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/JavaGradle.tsx76
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/JavaMaven.tsx75
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/Other.tsx61
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/PrepareAnalysisCommand.tsx204
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/PublishSteps.tsx88
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/AnalysisCommand.tsx91
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/BitbucketPipelinesTutorial.tsx125
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/PreambuleYaml.tsx44
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/RepositoryVariables.tsx134
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/__tests__/BitbucketPipelinesTutorial-it.tsx231
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/__tests__/__snapshots__/BitbucketPipelinesTutorial-it.tsx.snap353
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/CFamily.ts80
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Dart.ts61
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/DotNet.ts60
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Gradle.ts55
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Maven.ts60
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Others.ts55
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/AllSet.tsx88
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/BuildConfigSelection.tsx84
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/CompilationInfo.tsx54
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/CreateYmlFile.tsx53
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/DefaultProjectKey.tsx50
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/EditTokenModal.tsx272
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/GithubCFamilyExampleRepositories.tsx77
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/GradleBuild.tsx73
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/GradleBuildSelection.tsx50
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/InlineSnippet.tsx37
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/LabelActionPair.tsx33
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/LabelValuePair.tsx36
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/ProjectTokenScopeInfo.tsx52
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/RenderOptions.tsx60
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/SentenceWithFilename.tsx45
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/SentenceWithHighlights.tsx53
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/Step.tsx87
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/TokenStepGenerator.tsx65
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/YamlFileStep.tsx54
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/__tests__/EditTokenModal-test.tsx157
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/__tests__/GithubCFamilyExampleRepositories-test.tsx52
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/AnalysisCommand.tsx111
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/GitHubActionTutorial.tsx100
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/SecretStep.tsx159
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/GithubActionTutorial-it.tsx261
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/GithubActionTutorial-it.tsx.snap708
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/CFamily.tsx162
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/DotNet.tsx86
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/Gradle.tsx81
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/JavaMaven.tsx78
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/MonorepoDocLinkFallback.tsx34
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/commands/Others.tsx104
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/constants.ts22
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/github-action/utils.ts45
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx198
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx71
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/gitlabci/YmlFileStep.tsx268
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/GitLabCITutorial-it.tsx156
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/GitLabCITutorial-it.tsx.snap368
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommand.tsx241
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsStep.tsx89
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx99
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/MultiBranchPipelineStep.tsx260
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/PipelineStep.tsx113
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx83
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/SelectAlmStep.tsx54
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx84
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepBitbucket.tsx169
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepGitLab.tsx94
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepGithub.tsx100
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsTutorial-it.tsx298
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-it.tsx.snap1461
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/CFamily.tsx165
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/CreateJenkinsfileBulletPoint.tsx78
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNet.tsx68
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetCore.tsx64
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetFramework.tsx61
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetPrereqsMSBuild.tsx68
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetPrereqsScanner.tsx73
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Gradle.tsx74
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Maven.tsx45
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Other.tsx48
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/BuildToolForm.tsx94
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/DoneNextSteps.tsx136
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/OtherTutorial.tsx90
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/ProjectAnalysisStep.tsx86
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/TokenStep.tsx439
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/__tests__/DoneNextSteps-it.tsx62
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/__tests__/OtherTutorial-it.tsx354
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/__tests__/__snapshots__/OtherTutorial-it.tsx.snap372
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/AnalysisCommand.tsx97
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/ClangGCCCommand.tsx57
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/DotNet.tsx56
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetCore.tsx52
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetExecute.tsx68
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetFramework.tsx64
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/DownloadBuildWrapper.tsx92
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/DownloadScanner.tsx123
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/ExecBuildWrapper.tsx65
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/ExecScanner.tsx79
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/JavaGradle.tsx122
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/JavaMaven.tsx69
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/Other.tsx50
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/test-utils.ts127
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/types.ts65
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/utils.ts218
-rw-r--r--server/sonar-web/src/main/js/components/ui/AdminPageHeader.tsx55
-rw-r--r--server/sonar-web/src/main/js/components/ui/AiCodeAssuranceBanner.tsx81
-rw-r--r--server/sonar-web/src/main/js/components/ui/Avatar.tsx44
-rw-r--r--server/sonar-web/src/main/js/components/ui/DismissableAlert.tsx64
-rw-r--r--server/sonar-web/src/main/js/components/ui/FilesCounter.tsx51
-rw-r--r--server/sonar-web/src/main/js/components/ui/MandatoryFieldsExplanation.tsx39
-rw-r--r--server/sonar-web/src/main/js/components/ui/Rating.css65
-rw-r--r--server/sonar-web/src/main/js/components/ui/Rating.tsx59
-rw-r--r--server/sonar-web/src/main/js/components/ui/__tests__/AdminPageHeader-test.tsx39
-rw-r--r--server/sonar-web/src/main/js/components/ui/__tests__/Avatar-test.tsx40
-rw-r--r--server/sonar-web/src/main/js/components/ui/icon/SheildCheckIcon.tsx47
-rw-r--r--server/sonar-web/src/main/js/components/ui/icon/SheildCrossIcon.tsx51
-rw-r--r--server/sonar-web/src/main/js/components/ui/icon/ShieldIcon.tsx43
-rw-r--r--server/sonar-web/src/main/js/components/ui/popups.css289
-rw-r--r--server/sonar-web/src/main/js/components/ui/popups.tsx92
-rw-r--r--server/sonar-web/src/main/js/components/upgrade/SystemUpgradeButton.tsx75
-rw-r--r--server/sonar-web/src/main/js/components/upgrade/SystemUpgradeForm.tsx140
-rw-r--r--server/sonar-web/src/main/js/components/upgrade/SystemUpgradeIntermediate.tsx87
-rw-r--r--server/sonar-web/src/main/js/components/upgrade/SystemUpgradeItem.tsx144
-rw-r--r--server/sonar-web/src/main/js/components/upgrade/__tests__/SystemUpgrade-test.tsx91
-rw-r--r--server/sonar-web/src/main/js/components/upgrade/__tests__/utils-test.ts70
-rw-r--r--server/sonar-web/src/main/js/components/upgrade/utils.ts44
-rw-r--r--server/sonar-web/src/main/js/components/workspace/Workspace.tsx206
-rw-r--r--server/sonar-web/src/main/js/components/workspace/WorkspaceComponentTitle.tsx46
-rw-r--r--server/sonar-web/src/main/js/components/workspace/WorkspaceComponentViewer.tsx105
-rw-r--r--server/sonar-web/src/main/js/components/workspace/WorkspaceHeader.tsx143
-rw-r--r--server/sonar-web/src/main/js/components/workspace/WorkspaceNav.tsx58
-rw-r--r--server/sonar-web/src/main/js/components/workspace/WorkspaceNavComponent.tsx48
-rw-r--r--server/sonar-web/src/main/js/components/workspace/WorkspaceNavItem.tsx81
-rw-r--r--server/sonar-web/src/main/js/components/workspace/WorkspacePortal.tsx44
-rw-r--r--server/sonar-web/src/main/js/components/workspace/__tests__/Workspace-test.tsx191
-rw-r--r--server/sonar-web/src/main/js/components/workspace/context.ts46
-rw-r--r--server/sonar-web/src/main/js/components/workspace/styles.css58
-rw-r--r--server/sonar-web/src/main/js/design-system/README.md22
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Accordion.tsx119
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Badge.tsx110
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Banner.tsx130
-rw-r--r--server/sonar-web/src/main/js/design-system/components/BarChart.tsx164
-rw-r--r--server/sonar-web/src/main/js/design-system/components/BorderlessAccordion.tsx68
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Breadcrumbs.tsx186
-rw-r--r--server/sonar-web/src/main/js/design-system/components/BubbleChart.tsx444
-rw-r--r--server/sonar-web/src/main/js/design-system/components/ClickEventBoundary.tsx37
-rw-r--r--server/sonar-web/src/main/js/design-system/components/CodeSnippet.tsx130
-rw-r--r--server/sonar-web/src/main/js/design-system/components/CodeSyntaxHighlighter.tsx262
-rw-r--r--server/sonar-web/src/main/js/design-system/components/ColorsLegend.tsx103
-rw-r--r--server/sonar-web/src/main/js/design-system/components/CoverageIndicator.tsx77
-rw-r--r--server/sonar-web/src/main/js/design-system/components/DonutChart.tsx110
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Dropdown.tsx137
-rw-r--r--server/sonar-web/src/main/js/design-system/components/DropdownMenu.tsx418
-rw-r--r--server/sonar-web/src/main/js/design-system/components/DropdownToggler.tsx66
-rw-r--r--server/sonar-web/src/main/js/design-system/components/DuplicationsIndicator.tsx157
-rw-r--r--server/sonar-web/src/main/js/design-system/components/EscKeydownHandler.tsx49
-rw-r--r--server/sonar-web/src/main/js/design-system/components/ExecutionFlowAccordion.tsx97
-rw-r--r--server/sonar-web/src/main/js/design-system/components/FacetBox.tsx234
-rw-r--r--server/sonar-web/src/main/js/design-system/components/FacetItem.tsx243
-rw-r--r--server/sonar-web/src/main/js/design-system/components/FailedQGConditionLink.tsx52
-rw-r--r--server/sonar-web/src/main/js/design-system/components/FavoriteButton.tsx53
-rw-r--r--server/sonar-web/src/main/js/design-system/components/FlowStep.tsx66
-rw-r--r--server/sonar-web/src/main/js/design-system/components/FocusOutHandler.tsx61
-rw-r--r--server/sonar-web/src/main/js/design-system/components/HighlightRing.tsx32
-rw-r--r--server/sonar-web/src/main/js/design-system/components/HighlightedSection.tsx34
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Histogram.tsx152
-rw-r--r--server/sonar-web/src/main/js/design-system/components/HotspotRating.tsx51
-rw-r--r--server/sonar-web/src/main/js/design-system/components/HtmlFormatter.tsx142
-rw-r--r--server/sonar-web/src/main/js/design-system/components/IlllustredSelectionCard.tsx91
-rw-r--r--server/sonar-web/src/main/js/design-system/components/InteractiveIcon.tsx235
-rw-r--r--server/sonar-web/src/main/js/design-system/components/IssueMessageHighlighting.tsx125
-rw-r--r--server/sonar-web/src/main/js/design-system/components/KeyboardHint.tsx53
-rw-r--r--server/sonar-web/src/main/js/design-system/components/KeyboardHintKeys.tsx74
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Link.tsx307
-rw-r--r--server/sonar-web/src/main/js/design-system/components/LocationMarker.tsx75
-rw-r--r--server/sonar-web/src/main/js/design-system/components/MainAppBar.tsx100
-rw-r--r--server/sonar-web/src/main/js/design-system/components/MainMenu.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/MainMenuItem.tsx63
-rw-r--r--server/sonar-web/src/main/js/design-system/components/MultiSelector.tsx82
-rw-r--r--server/sonar-web/src/main/js/design-system/components/NavBarTabs.tsx145
-rw-r--r--server/sonar-web/src/main/js/design-system/components/NavLink.tsx75
-rw-r--r--server/sonar-web/src/main/js/design-system/components/NewCodeLegend.tsx52
-rw-r--r--server/sonar-web/src/main/js/design-system/components/OutsideClickHandler.tsx70
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Pill.tsx152
-rw-r--r--server/sonar-web/src/main/js/design-system/components/QualityGateIndicator.tsx180
-rw-r--r--server/sonar-web/src/main/js/design-system/components/SearchHighlighter.tsx58
-rw-r--r--server/sonar-web/src/main/js/design-system/components/SelectionCard.tsx188
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Separator.tsx48
-rw-r--r--server/sonar-web/src/main/js/design-system/components/SizeIndicator.tsx77
-rw-r--r--server/sonar-web/src/main/js/design-system/components/SonarCodeColorizer.tsx87
-rw-r--r--server/sonar-web/src/main/js/design-system/components/SonarQubeLogo.tsx50
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Spinner.tsx116
-rw-r--r--server/sonar-web/src/main/js/design-system/components/SpotlightTour.tsx337
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Switch.tsx126
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Tabs.tsx156
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Tags.tsx129
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Text.tsx180
-rw-r--r--server/sonar-web/src/main/js/design-system/components/TextAccordion.tsx115
-rw-r--r--server/sonar-web/src/main/js/design-system/components/Tooltip.tsx555
-rw-r--r--server/sonar-web/src/main/js/design-system/components/TopBar.tsx38
-rw-r--r--server/sonar-web/src/main/js/design-system/components/TreeMap.tsx110
-rw-r--r--server/sonar-web/src/main/js/design-system/components/TreeMapRect.tsx156
-rw-r--r--server/sonar-web/src/main/js/design-system/components/TutorialStep.tsx87
-rw-r--r--server/sonar-web/src/main/js/design-system/components/TutorialStepList.tsx29
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/Badge-test.tsx37
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/Banner-test.tsx51
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/BarChart-test.tsx63
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/BorderlessAccordion-test.tsx54
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/Breadcrumbs-test.tsx79
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/BubbleChart-test.tsx91
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/CodeSnippet-test.tsx52
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/CodeSyntaxHighlighter-test.tsx69
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/ColorsLegend-test.tsx58
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/CoverageIndicator-test.tsx43
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/Dropdown-test.tsx93
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/DropdownMenu-test.tsx79
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/DuplicationsIndicator-test.tsx42
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/ExecutionFlowAccordion-test.tsx44
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/FacetBox-test.tsx77
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/FacetItem-test.tsx75
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/FavoriteButton-test.tsx57
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/FlowStep-test.tsx35
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/HighlightedSection-test.tsx32
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/Histogram-test.tsx53
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/HotspotRating-test.tsx41
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/IssueMessageHighlighting-test.tsx74
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/KeyboardHint-test.tsx65
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/KeyboardHintKeys-test.tsx50
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/LineCoverage-test.tsx61
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/LineFinding-test.tsx52
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/LineNumber-test.tsx52
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/LineToken-test.tsx43
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/LineWrapper-test.tsx61
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/Link-test.tsx131
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/MainAppBar-test.tsx76
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/Menu-test.tsx31
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/MenuItem-test.tsx64
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/NavBarTabs-test.tsx80
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/NavLink-test.tsx117
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/NewCodeLegend-test.tsx33
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/Pill-test.tsx28
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/QualityGateIndicator-test.tsx55
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/SelectionCard-test.tsx80
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/SizeIndicator-test.tsx41
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/Spinner-test.tsx50
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/SpotlightTour-test.tsx172
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/Switch-test.tsx60
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/Tabs-test.tsx50
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/Tags-test.tsx117
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/Text-test.tsx41
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/TextAccordion-test.tsx56
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/Tooltip-test.tsx136
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/TreeMap-test.tsx66
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/TutorialStep-test.tsx38
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/CodeSnippet-test.tsx.snap691
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/CoverageIndicator-test.tsx.snap83
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/DuplicationsIndicator-test.tsx.snap203
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/FavoriteButton-test.tsx.snap167
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/Histogram-test.tsx.snap369
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/HotspotRating-test.tsx.snap118
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/IssueMessageHighlighting-test.tsx.snap148
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/KeyboardHint-test.tsx.snap291
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/KeyboardHintKeys-test.tsx.snap552
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/LineCoverage-test.tsx.snap237
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/LineFinding-test.tsx.snap64
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/LineWrapper-test.tsx.snap21
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/TreeMap-test.tsx.snap194
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/clipboard-test.tsx83
-rw-r--r--server/sonar-web/src/main/js/design-system/components/__tests__/layouts-test.tsx44
-rw-r--r--server/sonar-web/src/main/js/design-system/components/avatar/Avatar.tsx114
-rw-r--r--server/sonar-web/src/main/js/design-system/components/avatar/GenericAvatar.tsx79
-rw-r--r--server/sonar-web/src/main/js/design-system/components/avatar/__tests__/Avatar-test.tsx69
-rw-r--r--server/sonar-web/src/main/js/design-system/components/avatar/__tests__/GenericAvatar-test.tsx52
-rw-r--r--server/sonar-web/src/main/js/design-system/components/avatar/utils.ts35
-rw-r--r--server/sonar-web/src/main/js/design-system/components/buttons/BareButtons.tsx80
-rw-r--r--server/sonar-web/src/main/js/design-system/components/buttons/ButtonLink.tsx56
-rw-r--r--server/sonar-web/src/main/js/design-system/components/buttons/DownloadButton.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/buttons/WrapperButton.tsx31
-rw-r--r--server/sonar-web/src/main/js/design-system/components/buttons/__tests__/BareButtons-test.tsx41
-rw-r--r--server/sonar-web/src/main/js/design-system/components/buttons/__tests__/ButtonLink-test.tsx32
-rw-r--r--server/sonar-web/src/main/js/design-system/components/buttons/index.ts24
-rw-r--r--server/sonar-web/src/main/js/design-system/components/clipboard.tsx136
-rw-r--r--server/sonar-web/src/main/js/design-system/components/code-line/LineCoverage.tsx98
-rw-r--r--server/sonar-web/src/main/js/design-system/components/code-line/LineFinding.tsx104
-rw-r--r--server/sonar-web/src/main/js/design-system/components/code-line/LineIssuePointer.tsx79
-rw-r--r--server/sonar-web/src/main/js/design-system/components/code-line/LineIssuesIndicatorIcon.tsx47
-rw-r--r--server/sonar-web/src/main/js/design-system/components/code-line/LineMarker.tsx100
-rw-r--r--server/sonar-web/src/main/js/design-system/components/code-line/LineNumber.tsx95
-rw-r--r--server/sonar-web/src/main/js/design-system/components/code-line/LineStyles.tsx165
-rw-r--r--server/sonar-web/src/main/js/design-system/components/code-line/LineToken.tsx95
-rw-r--r--server/sonar-web/src/main/js/design-system/components/code-line/LineWrapper.tsx64
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/AddNewIcon.tsx44
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/BranchIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/BugIcon.tsx46
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/CalendarIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/CheckIcon.tsx43
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/ChevronDownIcon.tsx43
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/ChevronLeftIcon.tsx37
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/ChevronRightIcon.tsx37
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/ClockIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/CloseIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/CodeEllipsisIcon.tsx43
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/CodeSmellIcon.tsx42
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/CollapseIcon.tsx43
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/CommentIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/CopyIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/DirectoryIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/DotFillIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/DraggableIcon.tsx45
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/ExecutionFlowIcon.tsx39
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/ExpandIcon.tsx43
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/FileIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/FilterIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/FlagErrorIcon.tsx41
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/FlagInfoIcon.tsx41
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/FlagSuccessIcon.tsx41
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/FlagWarningIcon.tsx42
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/HelperHintIcon.tsx61
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/HomeFillIcon.tsx42
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/HomeIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/Icon.tsx127
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/InProgressVisual.tsx107
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/InheritanceIcon.tsx65
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/IssueLocationIcon.tsx45
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/IssueTypeIcon.tsx65
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/LinkIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/LockIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/LockIllustration.tsx55
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/MailIcon.tsx51
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/MainBranchIcon.tsx43
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/MenuHelpIcon.tsx43
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/MenuIcon.tsx33
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/MenuSearchIcon.tsx44
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/MinimizeIcon.tsx38
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/NoDataIcon.tsx50
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/OpenCloseIndicator.tsx31
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/OpenNewTabIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/OverridenIcon.tsx45
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/OverviewQGNotComputedIcon.tsx136
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/OverviewQGPassedIcon.tsx110
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/PencilIcon.tsx24
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/PinIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/ProjectIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/PullRequestIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/QualifierIcon.tsx92
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/RecommendedIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/RequiredIcon.tsx34
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SearchIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SecurityFindingIcon.tsx44
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SecurityHotspotIcon.tsx42
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SeparatorCircleIcon.tsx33
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SeverityBlockerIcon.tsx34
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SeverityCriticalIcon.tsx37
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SeverityInfoIcon.tsx45
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SeverityMajorIcon.tsx40
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SeverityMinorIcon.tsx40
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SnoozeCircleIcon.tsx46
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityBlockerIcon.tsx45
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityHighIcon.tsx45
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityInfoIcon.tsx47
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityLowIcon.tsx45
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityMediumIcon.tsx45
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SortAscendIcon.tsx24
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/SortDescendIcon.tsx24
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/StarFillIcon.tsx37
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/StarIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/StatusConfirmedIcon.tsx41
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/StatusOpenIcon.tsx39
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/StatusReopenedIcon.tsx46
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/StatusResolvedIcon.tsx48
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/TestFileIcon.tsx51
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/TrashIcon.tsx24
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/TrendDownCircleIcon.tsx40
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/TrendIcon.tsx86
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/TrendUpCircleIcon.tsx47
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/TriangleDownIcon.tsx24
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/TriangleLeftIcon.tsx24
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/TriangleRightIcon.tsx24
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/TriangleUpIcon.tsx24
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/UnfoldDownIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/UnfoldIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/UnfoldUpIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/UserGroupIcon.tsx30
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/VulnerabilityIcon.tsx42
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/__tests__/Icon-test.tsx55
-rw-r--r--server/sonar-web/src/main/js/design-system/components/icons/index.ts107
-rw-r--r--server/sonar-web/src/main/js/design-system/components/index.ts103
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/Checkbox.tsx190
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/DatePicker.tsx296
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/DatePickerCustomCalendarNavigation.tsx149
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/DateRangePicker.tsx132
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/DiscreetSelect.tsx116
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/FileInput.tsx90
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/FormField.tsx90
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/InputField.tsx142
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/InputMultiSelect.tsx72
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/InputSearch.tsx273
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/MultiSelectMenu.tsx380
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/MultiSelectMenuOption.tsx91
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/RadioButton.tsx159
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/SearchSelect.tsx119
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/SearchSelectDropdown.tsx238
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/SearchSelectDropdownControl.tsx171
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/__tests__/DatePicker-test.tsx165
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/__tests__/DateRangePicker-test.tsx96
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/__tests__/DiscreetSelect-test.tsx57
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/__tests__/FileInput-test.tsx51
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/__tests__/FormField-test.tsx46
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/__tests__/InputField-test.tsx37
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/__tests__/InputMultiSelect-test.tsx41
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/__tests__/InputSearch-test.tsx89
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/__tests__/MultiSelectMenu-test.tsx105
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/__tests__/RadioButton-test.tsx63
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/__tests__/SearchSelectDropdown-test.tsx98
-rw-r--r--server/sonar-web/src/main/js/design-system/components/input/index.ts34
-rw-r--r--server/sonar-web/src/main/js/design-system/components/layouts.tsx43
-rw-r--r--server/sonar-web/src/main/js/design-system/components/lists/ListItem.tsx28
-rw-r--r--server/sonar-web/src/main/js/design-system/components/lists/NumberedList.tsx35
-rw-r--r--server/sonar-web/src/main/js/design-system/components/lists/NumberedListItem.tsx46
-rw-r--r--server/sonar-web/src/main/js/design-system/components/lists/OrderedList.tsx41
-rw-r--r--server/sonar-web/src/main/js/design-system/components/lists/UnorderedList.tsx34
-rw-r--r--server/sonar-web/src/main/js/design-system/components/lists/__tests__/NumberedList-test.tsx34
-rw-r--r--server/sonar-web/src/main/js/design-system/components/lists/__tests__/UnorderedList-test.tsx34
-rw-r--r--server/sonar-web/src/main/js/design-system/components/lists/index.ts25
-rw-r--r--server/sonar-web/src/main/js/design-system/components/modal/Modal.tsx190
-rw-r--r--server/sonar-web/src/main/js/design-system/components/modal/ModalBody.tsx59
-rw-r--r--server/sonar-web/src/main/js/design-system/components/modal/ModalFooter.tsx47
-rw-r--r--server/sonar-web/src/main/js/design-system/components/modal/ModalHeader.tsx51
-rw-r--r--server/sonar-web/src/main/js/design-system/components/modal/__tests__/Modal-test.tsx90
-rw-r--r--server/sonar-web/src/main/js/design-system/components/modal/__tests__/ModalBody-test.tsx33
-rw-r--r--server/sonar-web/src/main/js/design-system/components/modal/__tests__/ModalFooter-test.tsx56
-rw-r--r--server/sonar-web/src/main/js/design-system/components/modal/__tests__/ModalHeader-test.tsx45
-rw-r--r--server/sonar-web/src/main/js/design-system/components/modal/__tests__/__snapshots__/ModalBody-test.tsx.snap33
-rw-r--r--server/sonar-web/src/main/js/design-system/components/modal/__tests__/__snapshots__/ModalFooter-test.tsx.snap190
-rw-r--r--server/sonar-web/src/main/js/design-system/components/modal/__tests__/__snapshots__/ModalHeader-test.tsx.snap66
-rw-r--r--server/sonar-web/src/main/js/design-system/components/popups.tsx233
-rw-r--r--server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationAccordion.tsx101
-rw-r--r--server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationGroup.tsx61
-rw-r--r--server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationHeading.tsx35
-rw-r--r--server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationItem.tsx104
-rw-r--r--server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationSubheading.tsx35
-rw-r--r--server/sonar-web/src/main/js/design-system/components/subnavigation/__tests__/SubnavigationAccordion-test.tsx76
-rw-r--r--server/sonar-web/src/main/js/design-system/components/subnavigation/__tests__/SubnavigationItem-test.tsx40
-rw-r--r--server/sonar-web/src/main/js/design-system/components/subnavigation/index.ts25
-rw-r--r--server/sonar-web/src/main/js/design-system/components/toast-message/ToastMessage.tsx208
-rw-r--r--server/sonar-web/src/main/js/design-system/components/toast-message/ToastMessageGlobalStyles.tsx679
-rw-r--r--server/sonar-web/src/main/js/design-system/components/toast-message/__tests__/ToastMessage-test.tsx57
-rw-r--r--server/sonar-web/src/main/js/design-system/components/toast-message/__tests__/toast-utils-test.tsx57
-rw-r--r--server/sonar-web/src/main/js/design-system/components/toast-message/toast-utils.tsx61
-rw-r--r--server/sonar-web/src/main/js/design-system/components/visual-components/FishVisual.tsx96
-rw-r--r--server/sonar-web/src/main/js/design-system/components/visual-components/FlagVisual.tsx79
-rw-r--r--server/sonar-web/src/main/js/design-system/components/visual-components/index.ts22
-rw-r--r--server/sonar-web/src/main/js/design-system/helpers/__tests__/colors-test.ts62
-rw-r--r--server/sonar-web/src/main/js/design-system/helpers/__tests__/dom-test.ts57
-rw-r--r--server/sonar-web/src/main/js/design-system/helpers/__tests__/positioning-test.ts168
-rw-r--r--server/sonar-web/src/main/js/design-system/helpers/__tests__/theme-test.ts149
-rw-r--r--server/sonar-web/src/main/js/design-system/helpers/colors.ts65
-rw-r--r--server/sonar-web/src/main/js/design-system/helpers/constants.ts80
-rw-r--r--server/sonar-web/src/main/js/design-system/helpers/dom.ts76
-rw-r--r--server/sonar-web/src/main/js/design-system/helpers/index.ts25
-rw-r--r--server/sonar-web/src/main/js/design-system/helpers/keyboard.ts62
-rw-r--r--server/sonar-web/src/main/js/design-system/helpers/positioning.ts184
-rw-r--r--server/sonar-web/src/main/js/design-system/helpers/testUtils.tsx146
-rw-r--r--server/sonar-web/src/main/js/design-system/helpers/theme.ts132
-rw-r--r--server/sonar-web/src/main/js/design-system/helpers/types.ts23
-rw-r--r--server/sonar-web/src/main/js/design-system/hooks/__tests__/useResizeObserver-test.tsx58
-rw-r--r--server/sonar-web/src/main/js/design-system/hooks/useResizeObserver.ts57
-rw-r--r--server/sonar-web/src/main/js/design-system/index.ts25
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/Card.tsx101
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/FlagMessage.tsx163
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/FlagMessageV2.tsx203
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/MetricsRatingBadge.tsx112
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/Table.tsx299
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/Text.tsx26
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/ToggleButton.tsx125
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/Card-test.tsx46
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/FlagMessage-test.tsx70
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/FlagMessageV2-test.tsx72
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/MetricsRatingBadge-test.tsx39
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/Table-test.tsx145
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/ToggleButton-test.tsx67
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/BareButton.tsx31
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/Button.tsx198
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/ButtonPrimary.tsx54
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/ButtonSecondary.tsx48
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/DangerButtonPrimary.tsx48
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/DangerButtonSecondary.tsx48
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/ThirdPartyButton.tsx52
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/__tests__/ButtonPrimary-test.tsx37
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/index.ts27
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/index.ts30
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/InputSelect.tsx116
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/SelectCommon.tsx194
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/__tests__/InputSelect-test.tsx102
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/index.ts22
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/typography/Note.tsx28
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/typography/Title.tsx61
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/components/typography/index.ts22
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/__tests__/sanitize-test.tsx294
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/__tests__/tabs-test.ts26
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/index.ts22
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/sanitize.tsx124
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/tabs.ts27
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/HljsIssueIndicatorPlugin.ts144
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/HljsUnderlinePlugin.ts214
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/__tests__/HljsIssueIndicatorPlugin-test.ts127
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/__tests__/HljsUnderlinePlugin-test.ts188
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/index.ts23
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/index.ts24
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/types/index.ts21
-rw-r--r--server/sonar-web/src/main/js/design-system/sonar-aligned/types/measures.ts29
-rw-r--r--server/sonar-web/src/main/js/design-system/theme/colors.ts178
-rw-r--r--server/sonar-web/src/main/js/design-system/theme/index.ts22
-rw-r--r--server/sonar-web/src/main/js/design-system/theme/light.ts1003
-rw-r--r--server/sonar-web/src/main/js/design-system/theme/withTheme.tsx36
-rw-r--r--server/sonar-web/src/main/js/design-system/types/charts.ts33
-rw-r--r--server/sonar-web/src/main/js/design-system/types/index.ts24
-rw-r--r--server/sonar-web/src/main/js/design-system/types/issues.ts21
-rw-r--r--server/sonar-web/src/main/js/design-system/types/measures.ts47
-rw-r--r--server/sonar-web/src/main/js/design-system/types/misc.ts22
-rw-r--r--server/sonar-web/src/main/js/design-system/types/quality-gates.ts21
-rw-r--r--server/sonar-web/src/main/js/design-system/types/theme.ts46
-rw-r--r--server/sonar-web/src/main/js/helpers/UseQuery.tsx36
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/code-difference-test.tsx.snap57
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/extensions-test.ts.snap5
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/query-test.ts.snap11
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/branch-like-test.ts124
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/code-difference-test.tsx154
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/dates-test.ts38
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/error-test.ts92
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/extensions-test.ts94
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/extensionsHandler-test.ts50
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/handleRequiredAuthentication-test.ts51
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/issues-test.ts142
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/l10n-test.ts219
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/l10nBundle-test.ts75
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts107
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/new-code-definition-test.ts85
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/new-code-period-test.ts127
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/path-test.ts129
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/permissions-test.ts40
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/projectLinks-test.ts41
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/projects-test.ts43
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/qualityGates-test.ts70
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/query-test.ts105
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/ratings-test.ts102
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/request-test.ts346
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/security-standard-test.ts146
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/sonarlint-test.ts226
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/stringify-queryparams-test.ts46
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/strings-test.ts52
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/system-test.ts61
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/tokens-test.ts130
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts458
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/users-test.ts83
-rw-r--r--server/sonar-web/src/main/js/helpers/activity-graph.ts100
-rw-r--r--server/sonar-web/src/main/js/helpers/branch-like.ts113
-rw-r--r--server/sonar-web/src/main/js/helpers/browser.ts25
-rw-r--r--server/sonar-web/src/main/js/helpers/code-difference.ts100
-rw-r--r--server/sonar-web/src/main/js/helpers/code-viewer.ts42
-rw-r--r--server/sonar-web/src/main/js/helpers/component.ts27
-rw-r--r--server/sonar-web/src/main/js/helpers/constants.ts293
-rw-r--r--server/sonar-web/src/main/js/helpers/cookies.ts36
-rw-r--r--server/sonar-web/src/main/js/helpers/csv.ts24
-rw-r--r--server/sonar-web/src/main/js/helpers/dates.ts54
-rw-r--r--server/sonar-web/src/main/js/helpers/doc-links.ts139
-rw-r--r--server/sonar-web/src/main/js/helpers/docs.ts46
-rw-r--r--server/sonar-web/src/main/js/helpers/editions.ts80
-rw-r--r--server/sonar-web/src/main/js/helpers/extensions.ts71
-rw-r--r--server/sonar-web/src/main/js/helpers/extensionsHandler.ts53
-rw-r--r--server/sonar-web/src/main/js/helpers/globalMessages.ts36
-rw-r--r--server/sonar-web/src/main/js/helpers/handleRequiredAuthentication.ts27
-rw-r--r--server/sonar-web/src/main/js/helpers/issues.ts232
-rw-r--r--server/sonar-web/src/main/js/helpers/keyboardEventHelpers.ts45
-rw-r--r--server/sonar-web/src/main/js/helpers/keycodes.ts46
-rw-r--r--server/sonar-web/src/main/js/helpers/l10n.ts141
-rw-r--r--server/sonar-web/src/main/js/helpers/l10nBundle.ts136
-rw-r--r--server/sonar-web/src/main/js/helpers/measures.ts178
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/alm-integrations.ts119
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts214
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/application.ts32
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/branch-like.ts81
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/component-report.ts36
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/component.ts102
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/definitions-list.ts2472
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/dom.ts36
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/dop-translation.ts41
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/editions.ts42
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/issues.ts95
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/metrics.ts2003
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/new-code-definition.ts43
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/permissions.ts76
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/plugins.ts85
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/project-activity.ts110
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/projects.ts33
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/quality-gates.ts167
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/quality-profiles.ts31
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/react-select.ts70
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/security-hotspots.ts203
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/settings.ts93
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/sources.ts110
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/system-upgrades.ts32
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/system.ts58
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/tasks.ts46
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/token.ts31
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/users.ts28
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/webapi.ts53
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/webhook.ts43
-rw-r--r--server/sonar-web/src/main/js/helpers/new-code-definition.ts70
-rw-r--r--server/sonar-web/src/main/js/helpers/new-code-period.ts72
-rw-r--r--server/sonar-web/src/main/js/helpers/path.ts108
-rw-r--r--server/sonar-web/src/main/js/helpers/permissions.ts114
-rw-r--r--server/sonar-web/src/main/js/helpers/preferences.ts32
-rw-r--r--server/sonar-web/src/main/js/helpers/projectLinks.ts42
-rw-r--r--server/sonar-web/src/main/js/helpers/projects.ts41
-rw-r--r--server/sonar-web/src/main/js/helpers/qualityGates.ts66
-rw-r--r--server/sonar-web/src/main/js/helpers/query.ts133
-rw-r--r--server/sonar-web/src/main/js/helpers/ratings.ts74
-rw-r--r--server/sonar-web/src/main/js/helpers/react-query.ts52
-rw-r--r--server/sonar-web/src/main/js/helpers/request.ts366
-rw-r--r--server/sonar-web/src/main/js/helpers/search.tsx37
-rw-r--r--server/sonar-web/src/main/js/helpers/security-standard.ts120
-rw-r--r--server/sonar-web/src/main/js/helpers/sonarlint.ts177
-rw-r--r--server/sonar-web/src/main/js/helpers/standards.json7312
-rw-r--r--server/sonar-web/src/main/js/helpers/storage.ts49
-rw-r--r--server/sonar-web/src/main/js/helpers/stringify-queryparams.ts90
-rw-r--r--server/sonar-web/src/main/js/helpers/strings.ts423
-rw-r--r--server/sonar-web/src/main/js/helpers/system.ts62
-rw-r--r--server/sonar-web/src/main/js/helpers/testMocks.ts933
-rw-r--r--server/sonar-web/src/main/js/helpers/testReactTestingUtils.tsx326
-rw-r--r--server/sonar-web/src/main/js/helpers/testUtils.ts57
-rw-r--r--server/sonar-web/src/main/js/helpers/tokens.ts86
-rw-r--r--server/sonar-web/src/main/js/helpers/types.ts23
-rw-r--r--server/sonar-web/src/main/js/helpers/urls.ts420
-rw-r--r--server/sonar-web/src/main/js/helpers/users.ts36
-rw-r--r--server/sonar-web/src/main/js/hooks/__tests__/useLocalStorage-test.tsx79
-rw-r--r--server/sonar-web/src/main/js/hooks/useFollowScroll.ts45
-rw-r--r--server/sonar-web/src/main/js/hooks/useIntersectionObserver.ts53
-rw-r--r--server/sonar-web/src/main/js/hooks/useKeydown.ts42
-rw-r--r--server/sonar-web/src/main/js/hooks/useLocalStorage.ts49
-rw-r--r--server/sonar-web/src/main/js/queries/__tests__/queryClient-test.ts47
-rw-r--r--server/sonar-web/src/main/js/queries/ai-code-assurance.ts35
-rw-r--r--server/sonar-web/src/main/js/queries/applications.ts41
-rw-r--r--server/sonar-web/src/main/js/queries/badges.ts72
-rw-r--r--server/sonar-web/src/main/js/queries/branch.tsx435
-rw-r--r--server/sonar-web/src/main/js/queries/ce.ts31
-rw-r--r--server/sonar-web/src/main/js/queries/common.ts149
-rw-r--r--server/sonar-web/src/main/js/queries/component.ts118
-rw-r--r--server/sonar-web/src/main/js/queries/cves.ts34
-rw-r--r--server/sonar-web/src/main/js/queries/dependencies.ts49
-rw-r--r--server/sonar-web/src/main/js/queries/devops-integration.ts170
-rw-r--r--server/sonar-web/src/main/js/queries/dismissed-messages.ts47
-rw-r--r--server/sonar-web/src/main/js/queries/dop-translation.ts137
-rw-r--r--server/sonar-web/src/main/js/queries/emails.ts37
-rw-r--r--server/sonar-web/src/main/js/queries/favorites.ts82
-rw-r--r--server/sonar-web/src/main/js/queries/fix-suggestions.tsx198
-rw-r--r--server/sonar-web/src/main/js/queries/group-memberships.ts214
-rw-r--r--server/sonar-web/src/main/js/queries/groups.ts75
-rw-r--r--server/sonar-web/src/main/js/queries/hotspots.ts32
-rw-r--r--server/sonar-web/src/main/js/queries/identity-provider/common.ts36
-rw-r--r--server/sonar-web/src/main/js/queries/identity-provider/github.ts150
-rw-r--r--server/sonar-web/src/main/js/queries/identity-provider/gitlab.ts266
-rw-r--r--server/sonar-web/src/main/js/queries/identity-provider/scim.ts49
-rw-r--r--server/sonar-web/src/main/js/queries/import-projects.ts92
-rw-r--r--server/sonar-web/src/main/js/queries/issues.ts58
-rw-r--r--server/sonar-web/src/main/js/queries/measures.ts381
-rw-r--r--server/sonar-web/src/main/js/queries/mode.ts65
-rw-r--r--server/sonar-web/src/main/js/queries/newCodeDefinition.ts76
-rw-r--r--server/sonar-web/src/main/js/queries/notifications.ts82
-rw-r--r--server/sonar-web/src/main/js/queries/portfolios.ts33
-rw-r--r--server/sonar-web/src/main/js/queries/project-analyses.ts170
-rw-r--r--server/sonar-web/src/main/js/queries/project-dump.ts40
-rw-r--r--server/sonar-web/src/main/js/queries/projects.ts116
-rw-r--r--server/sonar-web/src/main/js/queries/quality-gates.ts394
-rw-r--r--server/sonar-web/src/main/js/queries/quality-profiles.ts173
-rw-r--r--server/sonar-web/src/main/js/queries/queryClient.ts42
-rw-r--r--server/sonar-web/src/main/js/queries/rules.ts131
-rw-r--r--server/sonar-web/src/main/js/queries/settings.ts174
-rw-r--r--server/sonar-web/src/main/js/queries/sonarlint.ts75
-rw-r--r--server/sonar-web/src/main/js/queries/sources.ts39
-rw-r--r--server/sonar-web/src/main/js/queries/system.ts85
-rw-r--r--server/sonar-web/src/main/js/queries/users.ts135
-rw-r--r--server/sonar-web/src/main/js/queries/web-api.ts35
-rw-r--r--server/sonar-web/src/main/js/queries/withQueryClientHoc.tsx33
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/SourceViewer/JupyterNotebookViewer.tsx91
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11yContext.tsx38
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11yProvider.tsx63
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11ySkipLinks.css41
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11ySkipLinks.tsx36
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11ySkipTarget.tsx69
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/a11y/__tests__/A11yLinks-test.tsx93
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/common/Image.tsx41
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/common/__tests__/Image-test.tsx54
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/controls/DocHelpTooltip.tsx158
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/controls/HelpTooltip.tsx65
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/controls/__tests__/DocHelpTooltip-test.tsx96
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/hoc/__tests__/utils-test.ts36
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/hoc/utils.ts29
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/hoc/withRouter.tsx91
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/components/measure/Measure.tsx150
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/__snapshots__/component-test.ts.snap15
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/component-test.ts41
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/json-issue-mapper-test.ts157
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/measures-test.ts217
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/request-test.ts59
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/testSelector-test.tsx280
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/urls-test.ts129
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/branch-like.ts54
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/component.ts34
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/error.ts64
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/json-issue-mapper.ts387
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/lazyLoadComponent.tsx72
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/measures.ts310
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/branch.ts31
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/component.ts41
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/00-object-simple.json15
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/01-object-false-flags.json13
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/02-object-jupyter-notebook.json466
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/03-array-simple.json9
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/04-object-jupyter-notebook-oneline.json1
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/request.ts45
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/router.ts38
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/testSelector.ts521
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/helpers/urls.ts88
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/types/branch-like.ts49
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/types/common.ts21
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/types/component.ts66
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/types/metrics.ts222
-rw-r--r--server/sonar-web/src/main/js/sonar-aligned/types/router.ts42
-rw-r--r--server/sonar-web/src/main/js/types/__tests__/__snapshots__/component-test.ts.snap57
-rw-r--r--server/sonar-web/src/main/js/types/__tests__/alm-settings-test.ts37
-rw-r--r--server/sonar-web/src/main/js/types/__tests__/component-test.ts33
-rw-r--r--server/sonar-web/src/main/js/types/admin.ts25
-rw-r--r--server/sonar-web/src/main/js/types/alm-integration.ts85
-rw-r--r--server/sonar-web/src/main/js/types/alm-settings.ts234
-rw-r--r--server/sonar-web/src/main/js/types/application.ts55
-rw-r--r--server/sonar-web/src/main/js/types/appstate.ts41
-rw-r--r--server/sonar-web/src/main/js/types/axios.d.ts49
-rw-r--r--server/sonar-web/src/main/js/types/branch-like.ts58
-rw-r--r--server/sonar-web/src/main/js/types/browser.ts44
-rw-r--r--server/sonar-web/src/main/js/types/clean-code-taxonomy.ts72
-rw-r--r--server/sonar-web/src/main/js/types/coding-rules.ts39
-rw-r--r--server/sonar-web/src/main/js/types/component-report.ts30
-rw-r--r--server/sonar-web/src/main/js/types/component.ts89
-rw-r--r--server/sonar-web/src/main/js/types/cves.ts30
-rw-r--r--server/sonar-web/src/main/js/types/dates.ts21
-rw-r--r--server/sonar-web/src/main/js/types/dependencies.ts44
-rw-r--r--server/sonar-web/src/main/js/types/dop-translation.ts72
-rw-r--r--server/sonar-web/src/main/js/types/editions.ts55
-rw-r--r--server/sonar-web/src/main/js/types/extension.ts68
-rw-r--r--server/sonar-web/src/main/js/types/features.ts35
-rw-r--r--server/sonar-web/src/main/js/types/fix-suggestions.ts38
-rw-r--r--server/sonar-web/src/main/js/types/indexation.ts46
-rw-r--r--server/sonar-web/src/main/js/types/issues.ts248
-rw-r--r--server/sonar-web/src/main/js/types/jest.d.ts27
-rw-r--r--server/sonar-web/src/main/js/types/l10nBundle.ts37
-rw-r--r--server/sonar-web/src/main/js/types/languages.ts28
-rw-r--r--server/sonar-web/src/main/js/types/measures.ts49
-rw-r--r--server/sonar-web/src/main/js/types/misc.ts22
-rw-r--r--server/sonar-web/src/main/js/types/mode.ts29
-rw-r--r--server/sonar-web/src/main/js/types/new-code-definition.ts48
-rw-r--r--server/sonar-web/src/main/js/types/notifications.ts61
-rw-r--r--server/sonar-web/src/main/js/types/permissions.ts33
-rw-r--r--server/sonar-web/src/main/js/types/plugins.ts96
-rw-r--r--server/sonar-web/src/main/js/types/project-activity.ts118
-rw-r--r--server/sonar-web/src/main/js/types/project-dump.ts35
-rw-r--r--server/sonar-web/src/main/js/types/provisioning.ts129
-rw-r--r--server/sonar-web/src/main/js/types/quality-gates.ts126
-rw-r--r--server/sonar-web/src/main/js/types/quality-profiles.ts24
-rw-r--r--server/sonar-web/src/main/js/types/rules.ts75
-rw-r--r--server/sonar-web/src/main/js/types/security-hotspots.ts174
-rw-r--r--server/sonar-web/src/main/js/types/security.ts39
-rw-r--r--server/sonar-web/src/main/js/types/settings.ts118
-rw-r--r--server/sonar-web/src/main/js/types/sonarlint.ts53
-rw-r--r--server/sonar-web/src/main/js/types/system.ts104
-rw-r--r--server/sonar-web/src/main/js/types/tasks.ts88
-rw-r--r--server/sonar-web/src/main/js/types/token.ts47
-rw-r--r--server/sonar-web/src/main/js/types/types.ts856
-rw-r--r--server/sonar-web/src/main/js/types/users.ts135
-rw-r--r--server/sonar-web/src/main/js/types/webhook.ts57
-rw-r--r--server/sonar-web/tailwind-echoes.js81
-rw-r--r--server/sonar-web/tailwind.base.config.js154
-rw-r--r--server/sonar-web/tailwind.config.js24
-rw-r--r--server/sonar-web/tsconfig.json121
1451 files changed, 0 insertions, 163130 deletions
diff --git a/server/sonar-web/.eslintrc b/server/sonar-web/.eslintrc
deleted file mode 100644
index 71a90d503cc..00000000000
--- a/server/sonar-web/.eslintrc
+++ /dev/null
@@ -1,108 +0,0 @@
-{
- "extends": "sonarqube",
- "plugins": [
- "header",
- "typescript-sort-keys",
- "eslint-plugin-local-rules"
- ],
- "ignorePatterns": [
- "babel.config.js",
- "jest.config.js",
- "vite.config.mjs",
- "tailwind*.js",
- "script/**/*",
- "config/**/*",
- "eslint-local-rules/**/*"
- ],
- "root": true,
- "parserOptions": {
- "project": "./tsconfig.json"
- },
- "rules": {
- "camelcase": "off",
- "promise/no-return-wrap": "warn",
- "header/header": [
- "error",
- "block",
- [
- "",
- " * SonarQube",
- " * Copyright (C) 2009-2024 SonarSource SA",
- " * mailto:info AT sonarsource DOT com",
- " *",
- " * This program is free software; you can redistribute it and/or",
- " * modify it under the terms of the GNU Lesser General Public",
- " * License as published by the Free Software Foundation; either",
- " * version 3 of the License, or (at your option) any later version.",
- " *",
- " * This program is distributed in the hope that it will be useful,",
- " * but WITHOUT ANY WARRANTY; without even the implied warranty of",
- " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU",
- " * Lesser General Public License for more details.",
- " *",
- " * You should have received a copy of the GNU Lesser General Public License",
- " * along with this program; if not, write to the Free Software Foundation,",
- " * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.",
- " "
- ],
- 2
- ],
- "react/forbid-component-props": [
- "error",
- {
- "forbid": [
- {
- "propName": "dangerouslySetInnerHTML",
- "message": "Use the SafeHTMLInjection component instead of 'dangerouslySetInnerHTML', to prevent CSS injection along other XSS attacks"
- }
- ]
- }
- ],
- "react/forbid-dom-props": [
- "error",
- {
- "forbid": [
- {
- "propName": "dangerouslySetInnerHTML",
- "message": "Use the SafeHTMLInjection component instead of 'dangerouslySetInnerHTML', to prevent CSS injection along other XSS attacks"
- }
- ]
- }
- ],
- "react/forbid-elements": [
- "warn",
- {
- "forbid": [
- {
- "element": "img",
- "message": "use <Image> from components/common instead"
- }
- ]
- }
- ],
- "react/jsx-curly-brace-presence": "warn",
- "react/react-in-jsx-scope": "off",
- "testing-library/render-result-naming-convention": "off",
- "typescript-sort-keys/interface": "error",
- /* Local rules, defined in ./eslint-local-rules/ */
- "local-rules/use-componentqualifier-enum": "warn",
- "local-rules/use-metrickey-enum": "warn",
- "local-rules/use-metrictype-enum": "warn",
- "local-rules/use-visibility-enum": "warn",
- "local-rules/convert-class-to-function-component": "warn",
- "local-rules/no-conditional-rendering-of-spinner": "warn",
- "local-rules/use-jest-mocked": "warn",
- "local-rules/use-await-expect-async-matcher": "warn",
- "local-rules/no-implicit-coercion": "warn",
- "local-rules/no-api-imports": "warn",
- "local-rules/no-within": "warn",
- "no-restricted-properties": [
- "warn",
- {
- "object": "Math",
- "property": "random",
- "message": "Tests can fail when the same random number is used as a key for several React elements."
- }
- ]
- }
-}
diff --git a/server/sonar-web/.eslintrc-ci b/server/sonar-web/.eslintrc-ci
deleted file mode 100644
index 092580051a8..00000000000
--- a/server/sonar-web/.eslintrc-ci
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "extends": ".eslintrc",
- "rules": {
- "local-rules/no-api-imports": "off",
- "local-rules/no-within": "off"
- }
-}
diff --git a/server/sonar-web/.gitignore b/server/sonar-web/.gitignore
deleted file mode 100644
index f106666ad37..00000000000
--- a/server/sonar-web/.gitignore
+++ /dev/null
@@ -1,23 +0,0 @@
-# webpack
-.awcache/
-
-# tests
-src/test/json/**/*.png
-lcov.info
-coverage/
-.nyc_output
-
-# eslint
-eslint-report.json
-
-# yarn
-.yarn/*
-!.yarn/patches
-!.yarn/releases
-!.yarn/plugins
-!.yarn/sdks
-!.yarn/versions
-.pnp.*
-
-# turborepo
-.turbo/
diff --git a/server/sonar-web/.prettierrc b/server/sonar-web/.prettierrc
deleted file mode 100644
index 7e2d3ccec93..00000000000
--- a/server/sonar-web/.prettierrc
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "printWidth": 100,
- "singleQuote": true,
- "plugins": ["prettier-plugin-organize-imports"],
-
- "overrides": [
- {
- "files": [".eslintrc", "tsconfig.json"],
- "options": {
- "trailingComma": "none"
- }
- }
- ]
-}
diff --git a/server/sonar-web/.vscode/extensions.json b/server/sonar-web/.vscode/extensions.json
deleted file mode 100644
index 70f19772e82..00000000000
--- a/server/sonar-web/.vscode/extensions.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "recommendations": [
- "dbaeumer.vscode-eslint",
- "mgmcdermott.vscode-language-babel",
- "sonarsource.sonarlint-vscode",
- "esbenp.prettier-vscode",
- "eamodio.gitlens"
- ]
-}
diff --git a/server/sonar-web/.yarn/plugins/@yarnpkg/plugin-echo-execute.cjs b/server/sonar-web/.yarn/plugins/@yarnpkg/plugin-echo-execute.cjs
deleted file mode 100644
index f3c74d18a8f..00000000000
--- a/server/sonar-web/.yarn/plugins/@yarnpkg/plugin-echo-execute.cjs
+++ /dev/null
@@ -1,8 +0,0 @@
-/* eslint-disable */
-module.exports = {
-name: "@yarnpkg/plugin-echo-execute",
-factory: function (require) {
-var plugin;(()=>{"use strict";var o={d:(t,e)=>{for(var r in e)o.o(e,r)&&!o.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:e[r]})},o:(o,t)=>Object.prototype.hasOwnProperty.call(o,t),r:o=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(o,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(o,"__esModule",{value:!0})}},t={};o.r(t),o.d(t,{default:()=>r});const e=require("@yarnpkg/core"),r={hooks:{wrapScriptExecution:async(o,t,r,a,n)=>async()=>(await e.StreamReport.start({configuration:t.configuration,json:!1,includeFooter:!1,stdout:n.stdout},async o=>{const r=e.formatUtils.applyColor(t.configuration,a,e.formatUtils.Type.NAME),i=e.formatUtils.applyColor(t.configuration,n.script,e.formatUtils.Type.CODE);o.reportInfo(e.MessageName.UNNAMED,`executing [${r}]: ${i}`)}),o())}};plugin=t})();
-return plugin;
-}
-}; \ No newline at end of file
diff --git a/server/sonar-web/.yarn/releases/yarn-4.2.2.cjs b/server/sonar-web/.yarn/releases/yarn-4.2.2.cjs
deleted file mode 100755
index ea34d01a49a..00000000000
--- a/server/sonar-web/.yarn/releases/yarn-4.2.2.cjs
+++ /dev/null
@@ -1,894 +0,0 @@
-#!/usr/bin/env node
-/* eslint-disable */
-//prettier-ignore
-(()=>{var $3e=Object.create;var LR=Object.defineProperty;var e_e=Object.getOwnPropertyDescriptor;var t_e=Object.getOwnPropertyNames;var r_e=Object.getPrototypeOf,n_e=Object.prototype.hasOwnProperty;var ve=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+t+'" is not supported')});var Et=(t,e)=>()=>(t&&(e=t(t=0)),e);var _=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),zt=(t,e)=>{for(var r in e)LR(t,r,{get:e[r],enumerable:!0})},i_e=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of t_e(e))!n_e.call(t,a)&&a!==r&&LR(t,a,{get:()=>e[a],enumerable:!(o=e_e(e,a))||o.enumerable});return t};var $e=(t,e,r)=>(r=t!=null?$3e(r_e(t)):{},i_e(e||!t||!t.__esModule?LR(r,"default",{value:t,enumerable:!0}):r,t));var vi={};zt(vi,{SAFE_TIME:()=>x7,S_IFDIR:()=>wD,S_IFLNK:()=>ID,S_IFMT:()=>Mu,S_IFREG:()=>qw});var Mu,wD,qw,ID,x7,k7=Et(()=>{Mu=61440,wD=16384,qw=32768,ID=40960,x7=456789e3});var tr={};zt(tr,{EBADF:()=>Io,EBUSY:()=>s_e,EEXIST:()=>A_e,EINVAL:()=>a_e,EISDIR:()=>u_e,ENOENT:()=>l_e,ENOSYS:()=>o_e,ENOTDIR:()=>c_e,ENOTEMPTY:()=>p_e,EOPNOTSUPP:()=>h_e,EROFS:()=>f_e,ERR_DIR_CLOSED:()=>NR});function Ll(t,e){return Object.assign(new Error(`${t}: ${e}`),{code:t})}function s_e(t){return Ll("EBUSY",t)}function o_e(t,e){return Ll("ENOSYS",`${t}, ${e}`)}function a_e(t){return Ll("EINVAL",`invalid argument, ${t}`)}function Io(t){return Ll("EBADF",`bad file descriptor, ${t}`)}function l_e(t){return Ll("ENOENT",`no such file or directory, ${t}`)}function c_e(t){return Ll("ENOTDIR",`not a directory, ${t}`)}function u_e(t){return Ll("EISDIR",`illegal operation on a directory, ${t}`)}function A_e(t){return Ll("EEXIST",`file already exists, ${t}`)}function f_e(t){return Ll("EROFS",`read-only filesystem, ${t}`)}function p_e(t){return Ll("ENOTEMPTY",`directory not empty, ${t}`)}function h_e(t){return Ll("EOPNOTSUPP",`operation not supported, ${t}`)}function NR(){return Ll("ERR_DIR_CLOSED","Directory handle was closed")}var BD=Et(()=>{});var Ea={};zt(Ea,{BigIntStatsEntry:()=>ty,DEFAULT_MODE:()=>UR,DirEntry:()=>OR,StatEntry:()=>ey,areStatsEqual:()=>_R,clearStats:()=>vD,convertToBigIntStats:()=>d_e,makeDefaultStats:()=>Q7,makeEmptyStats:()=>g_e});function Q7(){return new ey}function g_e(){return vD(Q7())}function vD(t){for(let e in t)if(Object.hasOwn(t,e)){let r=t[e];typeof r=="number"?t[e]=0:typeof r=="bigint"?t[e]=BigInt(0):MR.types.isDate(r)&&(t[e]=new Date(0))}return t}function d_e(t){let e=new ty;for(let r in t)if(Object.hasOwn(t,r)){let o=t[r];typeof o=="number"?e[r]=BigInt(o):MR.types.isDate(o)&&(e[r]=new Date(o))}return e.atimeNs=e.atimeMs*BigInt(1e6),e.mtimeNs=e.mtimeMs*BigInt(1e6),e.ctimeNs=e.ctimeMs*BigInt(1e6),e.birthtimeNs=e.birthtimeMs*BigInt(1e6),e}function _R(t,e){if(t.atimeMs!==e.atimeMs||t.birthtimeMs!==e.birthtimeMs||t.blksize!==e.blksize||t.blocks!==e.blocks||t.ctimeMs!==e.ctimeMs||t.dev!==e.dev||t.gid!==e.gid||t.ino!==e.ino||t.isBlockDevice()!==e.isBlockDevice()||t.isCharacterDevice()!==e.isCharacterDevice()||t.isDirectory()!==e.isDirectory()||t.isFIFO()!==e.isFIFO()||t.isFile()!==e.isFile()||t.isSocket()!==e.isSocket()||t.isSymbolicLink()!==e.isSymbolicLink()||t.mode!==e.mode||t.mtimeMs!==e.mtimeMs||t.nlink!==e.nlink||t.rdev!==e.rdev||t.size!==e.size||t.uid!==e.uid)return!1;let r=t,o=e;return!(r.atimeNs!==o.atimeNs||r.mtimeNs!==o.mtimeNs||r.ctimeNs!==o.ctimeNs||r.birthtimeNs!==o.birthtimeNs)}var MR,UR,OR,ey,ty,HR=Et(()=>{MR=$e(ve("util")),UR=33188,OR=class{constructor(){this.name="";this.path="";this.mode=0}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&61440)===16384}isFIFO(){return!1}isFile(){return(this.mode&61440)===32768}isSocket(){return!1}isSymbolicLink(){return(this.mode&61440)===40960}},ey=class{constructor(){this.uid=0;this.gid=0;this.size=0;this.blksize=0;this.atimeMs=0;this.mtimeMs=0;this.ctimeMs=0;this.birthtimeMs=0;this.atime=new Date(0);this.mtime=new Date(0);this.ctime=new Date(0);this.birthtime=new Date(0);this.dev=0;this.ino=0;this.mode=UR;this.nlink=1;this.rdev=0;this.blocks=1}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&61440)===16384}isFIFO(){return!1}isFile(){return(this.mode&61440)===32768}isSocket(){return!1}isSymbolicLink(){return(this.mode&61440)===40960}},ty=class{constructor(){this.uid=BigInt(0);this.gid=BigInt(0);this.size=BigInt(0);this.blksize=BigInt(0);this.atimeMs=BigInt(0);this.mtimeMs=BigInt(0);this.ctimeMs=BigInt(0);this.birthtimeMs=BigInt(0);this.atimeNs=BigInt(0);this.mtimeNs=BigInt(0);this.ctimeNs=BigInt(0);this.birthtimeNs=BigInt(0);this.atime=new Date(0);this.mtime=new Date(0);this.ctime=new Date(0);this.birthtime=new Date(0);this.dev=BigInt(0);this.ino=BigInt(0);this.mode=BigInt(UR);this.nlink=BigInt(1);this.rdev=BigInt(0);this.blocks=BigInt(1)}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&BigInt(61440))===BigInt(16384)}isFIFO(){return!1}isFile(){return(this.mode&BigInt(61440))===BigInt(32768)}isSocket(){return!1}isSymbolicLink(){return(this.mode&BigInt(61440))===BigInt(40960)}}});function w_e(t){let e,r;if(e=t.match(E_e))t=e[1];else if(r=t.match(C_e))t=`\\\\${r[1]?".\\":""}${r[2]}`;else return t;return t.replace(/\//g,"\\")}function I_e(t){t=t.replace(/\\/g,"/");let e,r;return(e=t.match(m_e))?t=`/${e[1]}`:(r=t.match(y_e))&&(t=`/unc/${r[1]?".dot/":""}${r[2]}`),t}function DD(t,e){return t===le?R7(e):qR(e)}var Gw,Bt,dr,le,z,F7,m_e,y_e,E_e,C_e,qR,R7,Ca=Et(()=>{Gw=$e(ve("path")),Bt={root:"/",dot:".",parent:".."},dr={home:"~",nodeModules:"node_modules",manifest:"package.json",lockfile:"yarn.lock",virtual:"__virtual__",pnpJs:".pnp.js",pnpCjs:".pnp.cjs",pnpData:".pnp.data.json",pnpEsmLoader:".pnp.loader.mjs",rc:".yarnrc.yml",env:".env"},le=Object.create(Gw.default),z=Object.create(Gw.default.posix);le.cwd=()=>process.cwd();z.cwd=process.platform==="win32"?()=>qR(process.cwd()):process.cwd;process.platform==="win32"&&(z.resolve=(...t)=>t.length>0&&z.isAbsolute(t[0])?Gw.default.posix.resolve(...t):Gw.default.posix.resolve(z.cwd(),...t));F7=function(t,e,r){return e=t.normalize(e),r=t.normalize(r),e===r?".":(e.endsWith(t.sep)||(e=e+t.sep),r.startsWith(e)?r.slice(e.length):null)};le.contains=(t,e)=>F7(le,t,e);z.contains=(t,e)=>F7(z,t,e);m_e=/^([a-zA-Z]:.*)$/,y_e=/^\/\/(\.\/)?(.*)$/,E_e=/^\/([a-zA-Z]:.*)$/,C_e=/^\/unc\/(\.dot\/)?(.*)$/;qR=process.platform==="win32"?I_e:t=>t,R7=process.platform==="win32"?w_e:t=>t;le.fromPortablePath=R7;le.toPortablePath=qR});async function PD(t,e){let r="0123456789abcdef";await t.mkdirPromise(e.indexPath,{recursive:!0});let o=[];for(let a of r)for(let n of r)o.push(t.mkdirPromise(t.pathUtils.join(e.indexPath,`${a}${n}`),{recursive:!0}));return await Promise.all(o),e.indexPath}async function T7(t,e,r,o,a){let n=t.pathUtils.normalize(e),u=r.pathUtils.normalize(o),A=[],p=[],{atime:h,mtime:E}=a.stableTime?{atime:Mg,mtime:Mg}:await r.lstatPromise(u);await t.mkdirpPromise(t.pathUtils.dirname(e),{utimes:[h,E]}),await GR(A,p,t,n,r,u,{...a,didParentExist:!0});for(let I of A)await I();await Promise.all(p.map(I=>I()))}async function GR(t,e,r,o,a,n,u){let A=u.didParentExist?await L7(r,o):null,p=await a.lstatPromise(n),{atime:h,mtime:E}=u.stableTime?{atime:Mg,mtime:Mg}:p,I;switch(!0){case p.isDirectory():I=await v_e(t,e,r,o,A,a,n,p,u);break;case p.isFile():I=await S_e(t,e,r,o,A,a,n,p,u);break;case p.isSymbolicLink():I=await b_e(t,e,r,o,A,a,n,p,u);break;default:throw new Error(`Unsupported file type (${p.mode})`)}return(u.linkStrategy?.type!=="HardlinkFromIndex"||!p.isFile())&&((I||A?.mtime?.getTime()!==E.getTime()||A?.atime?.getTime()!==h.getTime())&&(e.push(()=>r.lutimesPromise(o,h,E)),I=!0),(A===null||(A.mode&511)!==(p.mode&511))&&(e.push(()=>r.chmodPromise(o,p.mode&511)),I=!0)),I}async function L7(t,e){try{return await t.lstatPromise(e)}catch{return null}}async function v_e(t,e,r,o,a,n,u,A,p){if(a!==null&&!a.isDirectory())if(p.overwrite)t.push(async()=>r.removePromise(o)),a=null;else return!1;let h=!1;a===null&&(t.push(async()=>{try{await r.mkdirPromise(o,{mode:A.mode})}catch(v){if(v.code!=="EEXIST")throw v}}),h=!0);let E=await n.readdirPromise(u),I=p.didParentExist&&!a?{...p,didParentExist:!1}:p;if(p.stableSort)for(let v of E.sort())await GR(t,e,r,r.pathUtils.join(o,v),n,n.pathUtils.join(u,v),I)&&(h=!0);else(await Promise.all(E.map(async x=>{await GR(t,e,r,r.pathUtils.join(o,x),n,n.pathUtils.join(u,x),I)}))).some(x=>x)&&(h=!0);return h}async function D_e(t,e,r,o,a,n,u,A,p,h){let E=await n.checksumFilePromise(u,{algorithm:"sha1"}),I=420,v=A.mode&511,x=`${E}${v!==I?v.toString(8):""}`,C=r.pathUtils.join(h.indexPath,E.slice(0,2),`${x}.dat`),R;(ue=>(ue[ue.Lock=0]="Lock",ue[ue.Rename=1]="Rename"))(R||={});let N=1,U=await L7(r,C);if(a){let ae=U&&a.dev===U.dev&&a.ino===U.ino,fe=U?.mtimeMs!==B_e;if(ae&&fe&&h.autoRepair&&(N=0,U=null),!ae)if(p.overwrite)t.push(async()=>r.removePromise(o)),a=null;else return!1}let V=!U&&N===1?`${C}.${Math.floor(Math.random()*4294967296).toString(16).padStart(8,"0")}`:null,te=!1;return t.push(async()=>{if(!U&&(N===0&&await r.lockPromise(C,async()=>{let ae=await n.readFilePromise(u);await r.writeFilePromise(C,ae)}),N===1&&V)){let ae=await n.readFilePromise(u);await r.writeFilePromise(V,ae);try{await r.linkPromise(V,C)}catch(fe){if(fe.code==="EEXIST")te=!0,await r.unlinkPromise(V);else throw fe}}a||await r.linkPromise(C,o)}),e.push(async()=>{U||(await r.lutimesPromise(C,Mg,Mg),v!==I&&await r.chmodPromise(C,v)),V&&!te&&await r.unlinkPromise(V)}),!1}async function P_e(t,e,r,o,a,n,u,A,p){if(a!==null)if(p.overwrite)t.push(async()=>r.removePromise(o)),a=null;else return!1;return t.push(async()=>{let h=await n.readFilePromise(u);await r.writeFilePromise(o,h)}),!0}async function S_e(t,e,r,o,a,n,u,A,p){return p.linkStrategy?.type==="HardlinkFromIndex"?D_e(t,e,r,o,a,n,u,A,p,p.linkStrategy):P_e(t,e,r,o,a,n,u,A,p)}async function b_e(t,e,r,o,a,n,u,A,p){if(a!==null)if(p.overwrite)t.push(async()=>r.removePromise(o)),a=null;else return!1;return t.push(async()=>{await r.symlinkPromise(DD(r.pathUtils,await n.readlinkPromise(u)),o)}),!0}var Mg,B_e,jR=Et(()=>{Ca();Mg=new Date(456789e3*1e3),B_e=Mg.getTime()});function SD(t,e,r,o){let a=()=>{let n=r.shift();if(typeof n>"u")return null;let u=t.pathUtils.join(e,n);return Object.assign(t.statSync(u),{name:n,path:void 0})};return new jw(e,a,o)}var jw,N7=Et(()=>{BD();jw=class{constructor(e,r,o={}){this.path=e;this.nextDirent=r;this.opts=o;this.closed=!1}throwIfClosed(){if(this.closed)throw NR()}async*[Symbol.asyncIterator](){try{let e;for(;(e=await this.read())!==null;)yield e}finally{await this.close()}}read(e){let r=this.readSync();return typeof e<"u"?e(null,r):Promise.resolve(r)}readSync(){return this.throwIfClosed(),this.nextDirent()}close(e){return this.closeSync(),typeof e<"u"?e(null):Promise.resolve()}closeSync(){this.throwIfClosed(),this.opts.onClose?.(),this.closed=!0}}});function O7(t,e){if(t!==e)throw new Error(`Invalid StatWatcher status: expected '${e}', got '${t}'`)}var M7,ry,U7=Et(()=>{M7=ve("events");HR();ry=class extends M7.EventEmitter{constructor(r,o,{bigint:a=!1}={}){super();this.status="ready";this.changeListeners=new Map;this.startTimeout=null;this.fakeFs=r,this.path=o,this.bigint=a,this.lastStats=this.stat()}static create(r,o,a){let n=new ry(r,o,a);return n.start(),n}start(){O7(this.status,"ready"),this.status="running",this.startTimeout=setTimeout(()=>{this.startTimeout=null,this.fakeFs.existsSync(this.path)||this.emit("change",this.lastStats,this.lastStats)},3)}stop(){O7(this.status,"running"),this.status="stopped",this.startTimeout!==null&&(clearTimeout(this.startTimeout),this.startTimeout=null),this.emit("stop")}stat(){try{return this.fakeFs.statSync(this.path,{bigint:this.bigint})}catch{let o=this.bigint?new ty:new ey;return vD(o)}}makeInterval(r){let o=setInterval(()=>{let a=this.stat(),n=this.lastStats;_R(a,n)||(this.lastStats=a,this.emit("change",a,n))},r.interval);return r.persistent?o:o.unref()}registerChangeListener(r,o){this.addListener("change",r),this.changeListeners.set(r,this.makeInterval(o))}unregisterChangeListener(r){this.removeListener("change",r);let o=this.changeListeners.get(r);typeof o<"u"&&clearInterval(o),this.changeListeners.delete(r)}unregisterAllChangeListeners(){for(let r of this.changeListeners.keys())this.unregisterChangeListener(r)}hasChangeListeners(){return this.changeListeners.size>0}ref(){for(let r of this.changeListeners.values())r.ref();return this}unref(){for(let r of this.changeListeners.values())r.unref();return this}}});function ny(t,e,r,o){let a,n,u,A;switch(typeof r){case"function":a=!1,n=!0,u=5007,A=r;break;default:({bigint:a=!1,persistent:n=!0,interval:u=5007}=r),A=o;break}let p=bD.get(t);typeof p>"u"&&bD.set(t,p=new Map);let h=p.get(e);return typeof h>"u"&&(h=ry.create(t,e,{bigint:a}),p.set(e,h)),h.registerChangeListener(A,{persistent:n,interval:u}),h}function Ug(t,e,r){let o=bD.get(t);if(typeof o>"u")return;let a=o.get(e);typeof a>"u"||(typeof r>"u"?a.unregisterAllChangeListeners():a.unregisterChangeListener(r),a.hasChangeListeners()||(a.stop(),o.delete(e)))}function _g(t){let e=bD.get(t);if(!(typeof e>"u"))for(let r of e.keys())Ug(t,r)}var bD,YR=Et(()=>{U7();bD=new WeakMap});function x_e(t){let e=t.match(/\r?\n/g);if(e===null)return H7.EOL;let r=e.filter(a=>a===`\r
-`).length,o=e.length-r;return r>o?`\r
-`:`
-`}function Hg(t,e){return e.replace(/\r?\n/g,x_e(t))}var _7,H7,gf,Uu,qg=Et(()=>{_7=ve("crypto"),H7=ve("os");jR();Ca();gf=class{constructor(e){this.pathUtils=e}async*genTraversePromise(e,{stableSort:r=!1}={}){let o=[e];for(;o.length>0;){let a=o.shift();if((await this.lstatPromise(a)).isDirectory()){let u=await this.readdirPromise(a);if(r)for(let A of u.sort())o.push(this.pathUtils.join(a,A));else throw new Error("Not supported")}else yield a}}async checksumFilePromise(e,{algorithm:r="sha512"}={}){let o=await this.openPromise(e,"r");try{let n=Buffer.allocUnsafeSlow(65536),u=(0,_7.createHash)(r),A=0;for(;(A=await this.readPromise(o,n,0,65536))!==0;)u.update(A===65536?n:n.slice(0,A));return u.digest("hex")}finally{await this.closePromise(o)}}async removePromise(e,{recursive:r=!0,maxRetries:o=5}={}){let a;try{a=await this.lstatPromise(e)}catch(n){if(n.code==="ENOENT")return;throw n}if(a.isDirectory()){if(r){let n=await this.readdirPromise(e);await Promise.all(n.map(u=>this.removePromise(this.pathUtils.resolve(e,u))))}for(let n=0;n<=o;n++)try{await this.rmdirPromise(e);break}catch(u){if(u.code!=="EBUSY"&&u.code!=="ENOTEMPTY")throw u;n<o&&await new Promise(A=>setTimeout(A,n*100))}}else await this.unlinkPromise(e)}removeSync(e,{recursive:r=!0}={}){let o;try{o=this.lstatSync(e)}catch(a){if(a.code==="ENOENT")return;throw a}if(o.isDirectory()){if(r)for(let a of this.readdirSync(e))this.removeSync(this.pathUtils.resolve(e,a));this.rmdirSync(e)}else this.unlinkSync(e)}async mkdirpPromise(e,{chmod:r,utimes:o}={}){if(e=this.resolve(e),e===this.pathUtils.dirname(e))return;let a=e.split(this.pathUtils.sep),n;for(let u=2;u<=a.length;++u){let A=a.slice(0,u).join(this.pathUtils.sep);if(!this.existsSync(A)){try{await this.mkdirPromise(A)}catch(p){if(p.code==="EEXIST")continue;throw p}if(n??=A,r!=null&&await this.chmodPromise(A,r),o!=null)await this.utimesPromise(A,o[0],o[1]);else{let p=await this.statPromise(this.pathUtils.dirname(A));await this.utimesPromise(A,p.atime,p.mtime)}}}return n}mkdirpSync(e,{chmod:r,utimes:o}={}){if(e=this.resolve(e),e===this.pathUtils.dirname(e))return;let a=e.split(this.pathUtils.sep),n;for(let u=2;u<=a.length;++u){let A=a.slice(0,u).join(this.pathUtils.sep);if(!this.existsSync(A)){try{this.mkdirSync(A)}catch(p){if(p.code==="EEXIST")continue;throw p}if(n??=A,r!=null&&this.chmodSync(A,r),o!=null)this.utimesSync(A,o[0],o[1]);else{let p=this.statSync(this.pathUtils.dirname(A));this.utimesSync(A,p.atime,p.mtime)}}}return n}async copyPromise(e,r,{baseFs:o=this,overwrite:a=!0,stableSort:n=!1,stableTime:u=!1,linkStrategy:A=null}={}){return await T7(this,e,o,r,{overwrite:a,stableSort:n,stableTime:u,linkStrategy:A})}copySync(e,r,{baseFs:o=this,overwrite:a=!0}={}){let n=o.lstatSync(r),u=this.existsSync(e);if(n.isDirectory()){this.mkdirpSync(e);let p=o.readdirSync(r);for(let h of p)this.copySync(this.pathUtils.join(e,h),o.pathUtils.join(r,h),{baseFs:o,overwrite:a})}else if(n.isFile()){if(!u||a){u&&this.removeSync(e);let p=o.readFileSync(r);this.writeFileSync(e,p)}}else if(n.isSymbolicLink()){if(!u||a){u&&this.removeSync(e);let p=o.readlinkSync(r);this.symlinkSync(DD(this.pathUtils,p),e)}}else throw new Error(`Unsupported file type (file: ${r}, mode: 0o${n.mode.toString(8).padStart(6,"0")})`);let A=n.mode&511;this.chmodSync(e,A)}async changeFilePromise(e,r,o={}){return Buffer.isBuffer(r)?this.changeFileBufferPromise(e,r,o):this.changeFileTextPromise(e,r,o)}async changeFileBufferPromise(e,r,{mode:o}={}){let a=Buffer.alloc(0);try{a=await this.readFilePromise(e)}catch{}Buffer.compare(a,r)!==0&&await this.writeFilePromise(e,r,{mode:o})}async changeFileTextPromise(e,r,{automaticNewlines:o,mode:a}={}){let n="";try{n=await this.readFilePromise(e,"utf8")}catch{}let u=o?Hg(n,r):r;n!==u&&await this.writeFilePromise(e,u,{mode:a})}changeFileSync(e,r,o={}){return Buffer.isBuffer(r)?this.changeFileBufferSync(e,r,o):this.changeFileTextSync(e,r,o)}changeFileBufferSync(e,r,{mode:o}={}){let a=Buffer.alloc(0);try{a=this.readFileSync(e)}catch{}Buffer.compare(a,r)!==0&&this.writeFileSync(e,r,{mode:o})}changeFileTextSync(e,r,{automaticNewlines:o=!1,mode:a}={}){let n="";try{n=this.readFileSync(e,"utf8")}catch{}let u=o?Hg(n,r):r;n!==u&&this.writeFileSync(e,u,{mode:a})}async movePromise(e,r){try{await this.renamePromise(e,r)}catch(o){if(o.code==="EXDEV")await this.copyPromise(r,e),await this.removePromise(e);else throw o}}moveSync(e,r){try{this.renameSync(e,r)}catch(o){if(o.code==="EXDEV")this.copySync(r,e),this.removeSync(e);else throw o}}async lockPromise(e,r){let o=`${e}.flock`,a=1e3/60,n=Date.now(),u=null,A=async()=>{let p;try{[p]=await this.readJsonPromise(o)}catch{return Date.now()-n<500}try{return process.kill(p,0),!0}catch{return!1}};for(;u===null;)try{u=await this.openPromise(o,"wx")}catch(p){if(p.code==="EEXIST"){if(!await A())try{await this.unlinkPromise(o);continue}catch{}if(Date.now()-n<60*1e3)await new Promise(h=>setTimeout(h,a));else throw new Error(`Couldn't acquire a lock in a reasonable time (via ${o})`)}else throw p}await this.writePromise(u,JSON.stringify([process.pid]));try{return await r()}finally{try{await this.closePromise(u),await this.unlinkPromise(o)}catch{}}}async readJsonPromise(e){let r=await this.readFilePromise(e,"utf8");try{return JSON.parse(r)}catch(o){throw o.message+=` (in ${e})`,o}}readJsonSync(e){let r=this.readFileSync(e,"utf8");try{return JSON.parse(r)}catch(o){throw o.message+=` (in ${e})`,o}}async writeJsonPromise(e,r,{compact:o=!1}={}){let a=o?0:2;return await this.writeFilePromise(e,`${JSON.stringify(r,null,a)}
-`)}writeJsonSync(e,r,{compact:o=!1}={}){let a=o?0:2;return this.writeFileSync(e,`${JSON.stringify(r,null,a)}
-`)}async preserveTimePromise(e,r){let o=await this.lstatPromise(e),a=await r();typeof a<"u"&&(e=a),await this.lutimesPromise(e,o.atime,o.mtime)}async preserveTimeSync(e,r){let o=this.lstatSync(e),a=r();typeof a<"u"&&(e=a),this.lutimesSync(e,o.atime,o.mtime)}},Uu=class extends gf{constructor(){super(z)}}});var Ps,df=Et(()=>{qg();Ps=class extends gf{getExtractHint(e){return this.baseFs.getExtractHint(e)}resolve(e){return this.mapFromBase(this.baseFs.resolve(this.mapToBase(e)))}getRealPath(){return this.mapFromBase(this.baseFs.getRealPath())}async openPromise(e,r,o){return this.baseFs.openPromise(this.mapToBase(e),r,o)}openSync(e,r,o){return this.baseFs.openSync(this.mapToBase(e),r,o)}async opendirPromise(e,r){return Object.assign(await this.baseFs.opendirPromise(this.mapToBase(e),r),{path:e})}opendirSync(e,r){return Object.assign(this.baseFs.opendirSync(this.mapToBase(e),r),{path:e})}async readPromise(e,r,o,a,n){return await this.baseFs.readPromise(e,r,o,a,n)}readSync(e,r,o,a,n){return this.baseFs.readSync(e,r,o,a,n)}async writePromise(e,r,o,a,n){return typeof r=="string"?await this.baseFs.writePromise(e,r,o):await this.baseFs.writePromise(e,r,o,a,n)}writeSync(e,r,o,a,n){return typeof r=="string"?this.baseFs.writeSync(e,r,o):this.baseFs.writeSync(e,r,o,a,n)}async closePromise(e){return this.baseFs.closePromise(e)}closeSync(e){this.baseFs.closeSync(e)}createReadStream(e,r){return this.baseFs.createReadStream(e!==null?this.mapToBase(e):e,r)}createWriteStream(e,r){return this.baseFs.createWriteStream(e!==null?this.mapToBase(e):e,r)}async realpathPromise(e){return this.mapFromBase(await this.baseFs.realpathPromise(this.mapToBase(e)))}realpathSync(e){return this.mapFromBase(this.baseFs.realpathSync(this.mapToBase(e)))}async existsPromise(e){return this.baseFs.existsPromise(this.mapToBase(e))}existsSync(e){return this.baseFs.existsSync(this.mapToBase(e))}accessSync(e,r){return this.baseFs.accessSync(this.mapToBase(e),r)}async accessPromise(e,r){return this.baseFs.accessPromise(this.mapToBase(e),r)}async statPromise(e,r){return this.baseFs.statPromise(this.mapToBase(e),r)}statSync(e,r){return this.baseFs.statSync(this.mapToBase(e),r)}async fstatPromise(e,r){return this.baseFs.fstatPromise(e,r)}fstatSync(e,r){return this.baseFs.fstatSync(e,r)}lstatPromise(e,r){return this.baseFs.lstatPromise(this.mapToBase(e),r)}lstatSync(e,r){return this.baseFs.lstatSync(this.mapToBase(e),r)}async fchmodPromise(e,r){return this.baseFs.fchmodPromise(e,r)}fchmodSync(e,r){return this.baseFs.fchmodSync(e,r)}async chmodPromise(e,r){return this.baseFs.chmodPromise(this.mapToBase(e),r)}chmodSync(e,r){return this.baseFs.chmodSync(this.mapToBase(e),r)}async fchownPromise(e,r,o){return this.baseFs.fchownPromise(e,r,o)}fchownSync(e,r,o){return this.baseFs.fchownSync(e,r,o)}async chownPromise(e,r,o){return this.baseFs.chownPromise(this.mapToBase(e),r,o)}chownSync(e,r,o){return this.baseFs.chownSync(this.mapToBase(e),r,o)}async renamePromise(e,r){return this.baseFs.renamePromise(this.mapToBase(e),this.mapToBase(r))}renameSync(e,r){return this.baseFs.renameSync(this.mapToBase(e),this.mapToBase(r))}async copyFilePromise(e,r,o=0){return this.baseFs.copyFilePromise(this.mapToBase(e),this.mapToBase(r),o)}copyFileSync(e,r,o=0){return this.baseFs.copyFileSync(this.mapToBase(e),this.mapToBase(r),o)}async appendFilePromise(e,r,o){return this.baseFs.appendFilePromise(this.fsMapToBase(e),r,o)}appendFileSync(e,r,o){return this.baseFs.appendFileSync(this.fsMapToBase(e),r,o)}async writeFilePromise(e,r,o){return this.baseFs.writeFilePromise(this.fsMapToBase(e),r,o)}writeFileSync(e,r,o){return this.baseFs.writeFileSync(this.fsMapToBase(e),r,o)}async unlinkPromise(e){return this.baseFs.unlinkPromise(this.mapToBase(e))}unlinkSync(e){return this.baseFs.unlinkSync(this.mapToBase(e))}async utimesPromise(e,r,o){return this.baseFs.utimesPromise(this.mapToBase(e),r,o)}utimesSync(e,r,o){return this.baseFs.utimesSync(this.mapToBase(e),r,o)}async lutimesPromise(e,r,o){return this.baseFs.lutimesPromise(this.mapToBase(e),r,o)}lutimesSync(e,r,o){return this.baseFs.lutimesSync(this.mapToBase(e),r,o)}async mkdirPromise(e,r){return this.baseFs.mkdirPromise(this.mapToBase(e),r)}mkdirSync(e,r){return this.baseFs.mkdirSync(this.mapToBase(e),r)}async rmdirPromise(e,r){return this.baseFs.rmdirPromise(this.mapToBase(e),r)}rmdirSync(e,r){return this.baseFs.rmdirSync(this.mapToBase(e),r)}async rmPromise(e,r){return this.baseFs.rmPromise(this.mapToBase(e),r)}rmSync(e,r){return this.baseFs.rmSync(this.mapToBase(e),r)}async linkPromise(e,r){return this.baseFs.linkPromise(this.mapToBase(e),this.mapToBase(r))}linkSync(e,r){return this.baseFs.linkSync(this.mapToBase(e),this.mapToBase(r))}async symlinkPromise(e,r,o){let a=this.mapToBase(r);if(this.pathUtils.isAbsolute(e))return this.baseFs.symlinkPromise(this.mapToBase(e),a,o);let n=this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(r),e)),u=this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(a),n);return this.baseFs.symlinkPromise(u,a,o)}symlinkSync(e,r,o){let a=this.mapToBase(r);if(this.pathUtils.isAbsolute(e))return this.baseFs.symlinkSync(this.mapToBase(e),a,o);let n=this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(r),e)),u=this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(a),n);return this.baseFs.symlinkSync(u,a,o)}async readFilePromise(e,r){return this.baseFs.readFilePromise(this.fsMapToBase(e),r)}readFileSync(e,r){return this.baseFs.readFileSync(this.fsMapToBase(e),r)}readdirPromise(e,r){return this.baseFs.readdirPromise(this.mapToBase(e),r)}readdirSync(e,r){return this.baseFs.readdirSync(this.mapToBase(e),r)}async readlinkPromise(e){return this.mapFromBase(await this.baseFs.readlinkPromise(this.mapToBase(e)))}readlinkSync(e){return this.mapFromBase(this.baseFs.readlinkSync(this.mapToBase(e)))}async truncatePromise(e,r){return this.baseFs.truncatePromise(this.mapToBase(e),r)}truncateSync(e,r){return this.baseFs.truncateSync(this.mapToBase(e),r)}async ftruncatePromise(e,r){return this.baseFs.ftruncatePromise(e,r)}ftruncateSync(e,r){return this.baseFs.ftruncateSync(e,r)}watch(e,r,o){return this.baseFs.watch(this.mapToBase(e),r,o)}watchFile(e,r,o){return this.baseFs.watchFile(this.mapToBase(e),r,o)}unwatchFile(e,r){return this.baseFs.unwatchFile(this.mapToBase(e),r)}fsMapToBase(e){return typeof e=="number"?e:this.mapToBase(e)}}});var _u,q7=Et(()=>{df();_u=class extends Ps{constructor(r,{baseFs:o,pathUtils:a}){super(a);this.target=r,this.baseFs=o}getRealPath(){return this.target}getBaseFs(){return this.baseFs}mapFromBase(r){return r}mapToBase(r){return r}}});function G7(t){let e=t;return typeof t.path=="string"&&(e.path=le.toPortablePath(t.path)),e}var j7,Tn,Gg=Et(()=>{j7=$e(ve("fs"));qg();Ca();Tn=class extends Uu{constructor(r=j7.default){super();this.realFs=r}getExtractHint(){return!1}getRealPath(){return Bt.root}resolve(r){return z.resolve(r)}async openPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.open(le.fromPortablePath(r),o,a,this.makeCallback(n,u))})}openSync(r,o,a){return this.realFs.openSync(le.fromPortablePath(r),o,a)}async opendirPromise(r,o){return await new Promise((a,n)=>{typeof o<"u"?this.realFs.opendir(le.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.opendir(le.fromPortablePath(r),this.makeCallback(a,n))}).then(a=>{let n=a;return Object.defineProperty(n,"path",{value:r,configurable:!0,writable:!0}),n})}opendirSync(r,o){let n=typeof o<"u"?this.realFs.opendirSync(le.fromPortablePath(r),o):this.realFs.opendirSync(le.fromPortablePath(r));return Object.defineProperty(n,"path",{value:r,configurable:!0,writable:!0}),n}async readPromise(r,o,a=0,n=0,u=-1){return await new Promise((A,p)=>{this.realFs.read(r,o,a,n,u,(h,E)=>{h?p(h):A(E)})})}readSync(r,o,a,n,u){return this.realFs.readSync(r,o,a,n,u)}async writePromise(r,o,a,n,u){return await new Promise((A,p)=>typeof o=="string"?this.realFs.write(r,o,a,this.makeCallback(A,p)):this.realFs.write(r,o,a,n,u,this.makeCallback(A,p)))}writeSync(r,o,a,n,u){return typeof o=="string"?this.realFs.writeSync(r,o,a):this.realFs.writeSync(r,o,a,n,u)}async closePromise(r){await new Promise((o,a)=>{this.realFs.close(r,this.makeCallback(o,a))})}closeSync(r){this.realFs.closeSync(r)}createReadStream(r,o){let a=r!==null?le.fromPortablePath(r):r;return this.realFs.createReadStream(a,o)}createWriteStream(r,o){let a=r!==null?le.fromPortablePath(r):r;return this.realFs.createWriteStream(a,o)}async realpathPromise(r){return await new Promise((o,a)=>{this.realFs.realpath(le.fromPortablePath(r),{},this.makeCallback(o,a))}).then(o=>le.toPortablePath(o))}realpathSync(r){return le.toPortablePath(this.realFs.realpathSync(le.fromPortablePath(r),{}))}async existsPromise(r){return await new Promise(o=>{this.realFs.exists(le.fromPortablePath(r),o)})}accessSync(r,o){return this.realFs.accessSync(le.fromPortablePath(r),o)}async accessPromise(r,o){return await new Promise((a,n)=>{this.realFs.access(le.fromPortablePath(r),o,this.makeCallback(a,n))})}existsSync(r){return this.realFs.existsSync(le.fromPortablePath(r))}async statPromise(r,o){return await new Promise((a,n)=>{o?this.realFs.stat(le.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.stat(le.fromPortablePath(r),this.makeCallback(a,n))})}statSync(r,o){return o?this.realFs.statSync(le.fromPortablePath(r),o):this.realFs.statSync(le.fromPortablePath(r))}async fstatPromise(r,o){return await new Promise((a,n)=>{o?this.realFs.fstat(r,o,this.makeCallback(a,n)):this.realFs.fstat(r,this.makeCallback(a,n))})}fstatSync(r,o){return o?this.realFs.fstatSync(r,o):this.realFs.fstatSync(r)}async lstatPromise(r,o){return await new Promise((a,n)=>{o?this.realFs.lstat(le.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.lstat(le.fromPortablePath(r),this.makeCallback(a,n))})}lstatSync(r,o){return o?this.realFs.lstatSync(le.fromPortablePath(r),o):this.realFs.lstatSync(le.fromPortablePath(r))}async fchmodPromise(r,o){return await new Promise((a,n)=>{this.realFs.fchmod(r,o,this.makeCallback(a,n))})}fchmodSync(r,o){return this.realFs.fchmodSync(r,o)}async chmodPromise(r,o){return await new Promise((a,n)=>{this.realFs.chmod(le.fromPortablePath(r),o,this.makeCallback(a,n))})}chmodSync(r,o){return this.realFs.chmodSync(le.fromPortablePath(r),o)}async fchownPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.fchown(r,o,a,this.makeCallback(n,u))})}fchownSync(r,o,a){return this.realFs.fchownSync(r,o,a)}async chownPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.chown(le.fromPortablePath(r),o,a,this.makeCallback(n,u))})}chownSync(r,o,a){return this.realFs.chownSync(le.fromPortablePath(r),o,a)}async renamePromise(r,o){return await new Promise((a,n)=>{this.realFs.rename(le.fromPortablePath(r),le.fromPortablePath(o),this.makeCallback(a,n))})}renameSync(r,o){return this.realFs.renameSync(le.fromPortablePath(r),le.fromPortablePath(o))}async copyFilePromise(r,o,a=0){return await new Promise((n,u)=>{this.realFs.copyFile(le.fromPortablePath(r),le.fromPortablePath(o),a,this.makeCallback(n,u))})}copyFileSync(r,o,a=0){return this.realFs.copyFileSync(le.fromPortablePath(r),le.fromPortablePath(o),a)}async appendFilePromise(r,o,a){return await new Promise((n,u)=>{let A=typeof r=="string"?le.fromPortablePath(r):r;a?this.realFs.appendFile(A,o,a,this.makeCallback(n,u)):this.realFs.appendFile(A,o,this.makeCallback(n,u))})}appendFileSync(r,o,a){let n=typeof r=="string"?le.fromPortablePath(r):r;a?this.realFs.appendFileSync(n,o,a):this.realFs.appendFileSync(n,o)}async writeFilePromise(r,o,a){return await new Promise((n,u)=>{let A=typeof r=="string"?le.fromPortablePath(r):r;a?this.realFs.writeFile(A,o,a,this.makeCallback(n,u)):this.realFs.writeFile(A,o,this.makeCallback(n,u))})}writeFileSync(r,o,a){let n=typeof r=="string"?le.fromPortablePath(r):r;a?this.realFs.writeFileSync(n,o,a):this.realFs.writeFileSync(n,o)}async unlinkPromise(r){return await new Promise((o,a)=>{this.realFs.unlink(le.fromPortablePath(r),this.makeCallback(o,a))})}unlinkSync(r){return this.realFs.unlinkSync(le.fromPortablePath(r))}async utimesPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.utimes(le.fromPortablePath(r),o,a,this.makeCallback(n,u))})}utimesSync(r,o,a){this.realFs.utimesSync(le.fromPortablePath(r),o,a)}async lutimesPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.lutimes(le.fromPortablePath(r),o,a,this.makeCallback(n,u))})}lutimesSync(r,o,a){this.realFs.lutimesSync(le.fromPortablePath(r),o,a)}async mkdirPromise(r,o){return await new Promise((a,n)=>{this.realFs.mkdir(le.fromPortablePath(r),o,this.makeCallback(a,n))})}mkdirSync(r,o){return this.realFs.mkdirSync(le.fromPortablePath(r),o)}async rmdirPromise(r,o){return await new Promise((a,n)=>{o?this.realFs.rmdir(le.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.rmdir(le.fromPortablePath(r),this.makeCallback(a,n))})}rmdirSync(r,o){return this.realFs.rmdirSync(le.fromPortablePath(r),o)}async rmPromise(r,o){return await new Promise((a,n)=>{o?this.realFs.rm(le.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.rm(le.fromPortablePath(r),this.makeCallback(a,n))})}rmSync(r,o){return this.realFs.rmSync(le.fromPortablePath(r),o)}async linkPromise(r,o){return await new Promise((a,n)=>{this.realFs.link(le.fromPortablePath(r),le.fromPortablePath(o),this.makeCallback(a,n))})}linkSync(r,o){return this.realFs.linkSync(le.fromPortablePath(r),le.fromPortablePath(o))}async symlinkPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.symlink(le.fromPortablePath(r.replace(/\/+$/,"")),le.fromPortablePath(o),a,this.makeCallback(n,u))})}symlinkSync(r,o,a){return this.realFs.symlinkSync(le.fromPortablePath(r.replace(/\/+$/,"")),le.fromPortablePath(o),a)}async readFilePromise(r,o){return await new Promise((a,n)=>{let u=typeof r=="string"?le.fromPortablePath(r):r;this.realFs.readFile(u,o,this.makeCallback(a,n))})}readFileSync(r,o){let a=typeof r=="string"?le.fromPortablePath(r):r;return this.realFs.readFileSync(a,o)}async readdirPromise(r,o){return await new Promise((a,n)=>{o?o.recursive&&process.platform==="win32"?o.withFileTypes?this.realFs.readdir(le.fromPortablePath(r),o,this.makeCallback(u=>a(u.map(G7)),n)):this.realFs.readdir(le.fromPortablePath(r),o,this.makeCallback(u=>a(u.map(le.toPortablePath)),n)):this.realFs.readdir(le.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.readdir(le.fromPortablePath(r),this.makeCallback(a,n))})}readdirSync(r,o){return o?o.recursive&&process.platform==="win32"?o.withFileTypes?this.realFs.readdirSync(le.fromPortablePath(r),o).map(G7):this.realFs.readdirSync(le.fromPortablePath(r),o).map(le.toPortablePath):this.realFs.readdirSync(le.fromPortablePath(r),o):this.realFs.readdirSync(le.fromPortablePath(r))}async readlinkPromise(r){return await new Promise((o,a)=>{this.realFs.readlink(le.fromPortablePath(r),this.makeCallback(o,a))}).then(o=>le.toPortablePath(o))}readlinkSync(r){return le.toPortablePath(this.realFs.readlinkSync(le.fromPortablePath(r)))}async truncatePromise(r,o){return await new Promise((a,n)=>{this.realFs.truncate(le.fromPortablePath(r),o,this.makeCallback(a,n))})}truncateSync(r,o){return this.realFs.truncateSync(le.fromPortablePath(r),o)}async ftruncatePromise(r,o){return await new Promise((a,n)=>{this.realFs.ftruncate(r,o,this.makeCallback(a,n))})}ftruncateSync(r,o){return this.realFs.ftruncateSync(r,o)}watch(r,o,a){return this.realFs.watch(le.fromPortablePath(r),o,a)}watchFile(r,o,a){return this.realFs.watchFile(le.fromPortablePath(r),o,a)}unwatchFile(r,o){return this.realFs.unwatchFile(le.fromPortablePath(r),o)}makeCallback(r,o){return(a,n)=>{a?o(a):r(n)}}}});var gn,Y7=Et(()=>{Gg();df();Ca();gn=class extends Ps{constructor(r,{baseFs:o=new Tn}={}){super(z);this.target=this.pathUtils.normalize(r),this.baseFs=o}getRealPath(){return this.pathUtils.resolve(this.baseFs.getRealPath(),this.target)}resolve(r){return this.pathUtils.isAbsolute(r)?z.normalize(r):this.baseFs.resolve(z.join(this.target,r))}mapFromBase(r){return r}mapToBase(r){return this.pathUtils.isAbsolute(r)?r:this.pathUtils.join(this.target,r)}}});var W7,Hu,K7=Et(()=>{Gg();df();Ca();W7=Bt.root,Hu=class extends Ps{constructor(r,{baseFs:o=new Tn}={}){super(z);this.target=this.pathUtils.resolve(Bt.root,r),this.baseFs=o}getRealPath(){return this.pathUtils.resolve(this.baseFs.getRealPath(),this.pathUtils.relative(Bt.root,this.target))}getTarget(){return this.target}getBaseFs(){return this.baseFs}mapToBase(r){let o=this.pathUtils.normalize(r);if(this.pathUtils.isAbsolute(r))return this.pathUtils.resolve(this.target,this.pathUtils.relative(W7,r));if(o.match(/^\.\.\/?/))throw new Error(`Resolving this path (${r}) would escape the jail`);return this.pathUtils.resolve(this.target,r)}mapFromBase(r){return this.pathUtils.resolve(W7,this.pathUtils.relative(this.target,r))}}});var iy,z7=Et(()=>{df();iy=class extends Ps{constructor(r,o){super(o);this.instance=null;this.factory=r}get baseFs(){return this.instance||(this.instance=this.factory()),this.instance}set baseFs(r){this.instance=r}mapFromBase(r){return r}mapToBase(r){return r}}});var jg,wa,qp,V7=Et(()=>{jg=ve("fs");qg();Gg();YR();BD();Ca();wa=4278190080,qp=class extends Uu{constructor({baseFs:r=new Tn,filter:o=null,magicByte:a=42,maxOpenFiles:n=1/0,useCache:u=!0,maxAge:A=5e3,typeCheck:p=jg.constants.S_IFREG,getMountPoint:h,factoryPromise:E,factorySync:I}){if(Math.floor(a)!==a||!(a>1&&a<=127))throw new Error("The magic byte must be set to a round value between 1 and 127 included");super();this.fdMap=new Map;this.nextFd=3;this.isMount=new Set;this.notMount=new Set;this.realPaths=new Map;this.limitOpenFilesTimeout=null;this.baseFs=r,this.mountInstances=u?new Map:null,this.factoryPromise=E,this.factorySync=I,this.filter=o,this.getMountPoint=h,this.magic=a<<24,this.maxAge=A,this.maxOpenFiles=n,this.typeCheck=p}getExtractHint(r){return this.baseFs.getExtractHint(r)}getRealPath(){return this.baseFs.getRealPath()}saveAndClose(){if(_g(this),this.mountInstances)for(let[r,{childFs:o}]of this.mountInstances.entries())o.saveAndClose?.(),this.mountInstances.delete(r)}discardAndClose(){if(_g(this),this.mountInstances)for(let[r,{childFs:o}]of this.mountInstances.entries())o.discardAndClose?.(),this.mountInstances.delete(r)}resolve(r){return this.baseFs.resolve(r)}remapFd(r,o){let a=this.nextFd++|this.magic;return this.fdMap.set(a,[r,o]),a}async openPromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.openPromise(r,o,a),async(n,{subPath:u})=>this.remapFd(n,await n.openPromise(u,o,a)))}openSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.openSync(r,o,a),(n,{subPath:u})=>this.remapFd(n,n.openSync(u,o,a)))}async opendirPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.opendirPromise(r,o),async(a,{subPath:n})=>await a.opendirPromise(n,o),{requireSubpath:!1})}opendirSync(r,o){return this.makeCallSync(r,()=>this.baseFs.opendirSync(r,o),(a,{subPath:n})=>a.opendirSync(n,o),{requireSubpath:!1})}async readPromise(r,o,a,n,u){if((r&wa)!==this.magic)return await this.baseFs.readPromise(r,o,a,n,u);let A=this.fdMap.get(r);if(typeof A>"u")throw Io("read");let[p,h]=A;return await p.readPromise(h,o,a,n,u)}readSync(r,o,a,n,u){if((r&wa)!==this.magic)return this.baseFs.readSync(r,o,a,n,u);let A=this.fdMap.get(r);if(typeof A>"u")throw Io("readSync");let[p,h]=A;return p.readSync(h,o,a,n,u)}async writePromise(r,o,a,n,u){if((r&wa)!==this.magic)return typeof o=="string"?await this.baseFs.writePromise(r,o,a):await this.baseFs.writePromise(r,o,a,n,u);let A=this.fdMap.get(r);if(typeof A>"u")throw Io("write");let[p,h]=A;return typeof o=="string"?await p.writePromise(h,o,a):await p.writePromise(h,o,a,n,u)}writeSync(r,o,a,n,u){if((r&wa)!==this.magic)return typeof o=="string"?this.baseFs.writeSync(r,o,a):this.baseFs.writeSync(r,o,a,n,u);let A=this.fdMap.get(r);if(typeof A>"u")throw Io("writeSync");let[p,h]=A;return typeof o=="string"?p.writeSync(h,o,a):p.writeSync(h,o,a,n,u)}async closePromise(r){if((r&wa)!==this.magic)return await this.baseFs.closePromise(r);let o=this.fdMap.get(r);if(typeof o>"u")throw Io("close");this.fdMap.delete(r);let[a,n]=o;return await a.closePromise(n)}closeSync(r){if((r&wa)!==this.magic)return this.baseFs.closeSync(r);let o=this.fdMap.get(r);if(typeof o>"u")throw Io("closeSync");this.fdMap.delete(r);let[a,n]=o;return a.closeSync(n)}createReadStream(r,o){return r===null?this.baseFs.createReadStream(r,o):this.makeCallSync(r,()=>this.baseFs.createReadStream(r,o),(a,{archivePath:n,subPath:u})=>{let A=a.createReadStream(u,o);return A.path=le.fromPortablePath(this.pathUtils.join(n,u)),A})}createWriteStream(r,o){return r===null?this.baseFs.createWriteStream(r,o):this.makeCallSync(r,()=>this.baseFs.createWriteStream(r,o),(a,{subPath:n})=>a.createWriteStream(n,o))}async realpathPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.realpathPromise(r),async(o,{archivePath:a,subPath:n})=>{let u=this.realPaths.get(a);return typeof u>"u"&&(u=await this.baseFs.realpathPromise(a),this.realPaths.set(a,u)),this.pathUtils.join(u,this.pathUtils.relative(Bt.root,await o.realpathPromise(n)))})}realpathSync(r){return this.makeCallSync(r,()=>this.baseFs.realpathSync(r),(o,{archivePath:a,subPath:n})=>{let u=this.realPaths.get(a);return typeof u>"u"&&(u=this.baseFs.realpathSync(a),this.realPaths.set(a,u)),this.pathUtils.join(u,this.pathUtils.relative(Bt.root,o.realpathSync(n)))})}async existsPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.existsPromise(r),async(o,{subPath:a})=>await o.existsPromise(a))}existsSync(r){return this.makeCallSync(r,()=>this.baseFs.existsSync(r),(o,{subPath:a})=>o.existsSync(a))}async accessPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.accessPromise(r,o),async(a,{subPath:n})=>await a.accessPromise(n,o))}accessSync(r,o){return this.makeCallSync(r,()=>this.baseFs.accessSync(r,o),(a,{subPath:n})=>a.accessSync(n,o))}async statPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.statPromise(r,o),async(a,{subPath:n})=>await a.statPromise(n,o))}statSync(r,o){return this.makeCallSync(r,()=>this.baseFs.statSync(r,o),(a,{subPath:n})=>a.statSync(n,o))}async fstatPromise(r,o){if((r&wa)!==this.magic)return this.baseFs.fstatPromise(r,o);let a=this.fdMap.get(r);if(typeof a>"u")throw Io("fstat");let[n,u]=a;return n.fstatPromise(u,o)}fstatSync(r,o){if((r&wa)!==this.magic)return this.baseFs.fstatSync(r,o);let a=this.fdMap.get(r);if(typeof a>"u")throw Io("fstatSync");let[n,u]=a;return n.fstatSync(u,o)}async lstatPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.lstatPromise(r,o),async(a,{subPath:n})=>await a.lstatPromise(n,o))}lstatSync(r,o){return this.makeCallSync(r,()=>this.baseFs.lstatSync(r,o),(a,{subPath:n})=>a.lstatSync(n,o))}async fchmodPromise(r,o){if((r&wa)!==this.magic)return this.baseFs.fchmodPromise(r,o);let a=this.fdMap.get(r);if(typeof a>"u")throw Io("fchmod");let[n,u]=a;return n.fchmodPromise(u,o)}fchmodSync(r,o){if((r&wa)!==this.magic)return this.baseFs.fchmodSync(r,o);let a=this.fdMap.get(r);if(typeof a>"u")throw Io("fchmodSync");let[n,u]=a;return n.fchmodSync(u,o)}async chmodPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.chmodPromise(r,o),async(a,{subPath:n})=>await a.chmodPromise(n,o))}chmodSync(r,o){return this.makeCallSync(r,()=>this.baseFs.chmodSync(r,o),(a,{subPath:n})=>a.chmodSync(n,o))}async fchownPromise(r,o,a){if((r&wa)!==this.magic)return this.baseFs.fchownPromise(r,o,a);let n=this.fdMap.get(r);if(typeof n>"u")throw Io("fchown");let[u,A]=n;return u.fchownPromise(A,o,a)}fchownSync(r,o,a){if((r&wa)!==this.magic)return this.baseFs.fchownSync(r,o,a);let n=this.fdMap.get(r);if(typeof n>"u")throw Io("fchownSync");let[u,A]=n;return u.fchownSync(A,o,a)}async chownPromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.chownPromise(r,o,a),async(n,{subPath:u})=>await n.chownPromise(u,o,a))}chownSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.chownSync(r,o,a),(n,{subPath:u})=>n.chownSync(u,o,a))}async renamePromise(r,o){return await this.makeCallPromise(r,async()=>await this.makeCallPromise(o,async()=>await this.baseFs.renamePromise(r,o),async()=>{throw Object.assign(new Error("EEXDEV: cross-device link not permitted"),{code:"EEXDEV"})}),async(a,{subPath:n})=>await this.makeCallPromise(o,async()=>{throw Object.assign(new Error("EEXDEV: cross-device link not permitted"),{code:"EEXDEV"})},async(u,{subPath:A})=>{if(a!==u)throw Object.assign(new Error("EEXDEV: cross-device link not permitted"),{code:"EEXDEV"});return await a.renamePromise(n,A)}))}renameSync(r,o){return this.makeCallSync(r,()=>this.makeCallSync(o,()=>this.baseFs.renameSync(r,o),()=>{throw Object.assign(new Error("EEXDEV: cross-device link not permitted"),{code:"EEXDEV"})}),(a,{subPath:n})=>this.makeCallSync(o,()=>{throw Object.assign(new Error("EEXDEV: cross-device link not permitted"),{code:"EEXDEV"})},(u,{subPath:A})=>{if(a!==u)throw Object.assign(new Error("EEXDEV: cross-device link not permitted"),{code:"EEXDEV"});return a.renameSync(n,A)}))}async copyFilePromise(r,o,a=0){let n=async(u,A,p,h)=>{if((a&jg.constants.COPYFILE_FICLONE_FORCE)!==0)throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${A}' -> ${h}'`),{code:"EXDEV"});if(a&jg.constants.COPYFILE_EXCL&&await this.existsPromise(A))throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${A}' -> '${h}'`),{code:"EEXIST"});let E;try{E=await u.readFilePromise(A)}catch{throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${A}' -> '${h}'`),{code:"EINVAL"})}await p.writeFilePromise(h,E)};return await this.makeCallPromise(r,async()=>await this.makeCallPromise(o,async()=>await this.baseFs.copyFilePromise(r,o,a),async(u,{subPath:A})=>await n(this.baseFs,r,u,A)),async(u,{subPath:A})=>await this.makeCallPromise(o,async()=>await n(u,A,this.baseFs,o),async(p,{subPath:h})=>u!==p?await n(u,A,p,h):await u.copyFilePromise(A,h,a)))}copyFileSync(r,o,a=0){let n=(u,A,p,h)=>{if((a&jg.constants.COPYFILE_FICLONE_FORCE)!==0)throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${A}' -> ${h}'`),{code:"EXDEV"});if(a&jg.constants.COPYFILE_EXCL&&this.existsSync(A))throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${A}' -> '${h}'`),{code:"EEXIST"});let E;try{E=u.readFileSync(A)}catch{throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${A}' -> '${h}'`),{code:"EINVAL"})}p.writeFileSync(h,E)};return this.makeCallSync(r,()=>this.makeCallSync(o,()=>this.baseFs.copyFileSync(r,o,a),(u,{subPath:A})=>n(this.baseFs,r,u,A)),(u,{subPath:A})=>this.makeCallSync(o,()=>n(u,A,this.baseFs,o),(p,{subPath:h})=>u!==p?n(u,A,p,h):u.copyFileSync(A,h,a)))}async appendFilePromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.appendFilePromise(r,o,a),async(n,{subPath:u})=>await n.appendFilePromise(u,o,a))}appendFileSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.appendFileSync(r,o,a),(n,{subPath:u})=>n.appendFileSync(u,o,a))}async writeFilePromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.writeFilePromise(r,o,a),async(n,{subPath:u})=>await n.writeFilePromise(u,o,a))}writeFileSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.writeFileSync(r,o,a),(n,{subPath:u})=>n.writeFileSync(u,o,a))}async unlinkPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.unlinkPromise(r),async(o,{subPath:a})=>await o.unlinkPromise(a))}unlinkSync(r){return this.makeCallSync(r,()=>this.baseFs.unlinkSync(r),(o,{subPath:a})=>o.unlinkSync(a))}async utimesPromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.utimesPromise(r,o,a),async(n,{subPath:u})=>await n.utimesPromise(u,o,a))}utimesSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.utimesSync(r,o,a),(n,{subPath:u})=>n.utimesSync(u,o,a))}async lutimesPromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.lutimesPromise(r,o,a),async(n,{subPath:u})=>await n.lutimesPromise(u,o,a))}lutimesSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.lutimesSync(r,o,a),(n,{subPath:u})=>n.lutimesSync(u,o,a))}async mkdirPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.mkdirPromise(r,o),async(a,{subPath:n})=>await a.mkdirPromise(n,o))}mkdirSync(r,o){return this.makeCallSync(r,()=>this.baseFs.mkdirSync(r,o),(a,{subPath:n})=>a.mkdirSync(n,o))}async rmdirPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.rmdirPromise(r,o),async(a,{subPath:n})=>await a.rmdirPromise(n,o))}rmdirSync(r,o){return this.makeCallSync(r,()=>this.baseFs.rmdirSync(r,o),(a,{subPath:n})=>a.rmdirSync(n,o))}async rmPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.rmPromise(r,o),async(a,{subPath:n})=>await a.rmPromise(n,o))}rmSync(r,o){return this.makeCallSync(r,()=>this.baseFs.rmSync(r,o),(a,{subPath:n})=>a.rmSync(n,o))}async linkPromise(r,o){return await this.makeCallPromise(o,async()=>await this.baseFs.linkPromise(r,o),async(a,{subPath:n})=>await a.linkPromise(r,n))}linkSync(r,o){return this.makeCallSync(o,()=>this.baseFs.linkSync(r,o),(a,{subPath:n})=>a.linkSync(r,n))}async symlinkPromise(r,o,a){return await this.makeCallPromise(o,async()=>await this.baseFs.symlinkPromise(r,o,a),async(n,{subPath:u})=>await n.symlinkPromise(r,u))}symlinkSync(r,o,a){return this.makeCallSync(o,()=>this.baseFs.symlinkSync(r,o,a),(n,{subPath:u})=>n.symlinkSync(r,u))}async readFilePromise(r,o){return this.makeCallPromise(r,async()=>await this.baseFs.readFilePromise(r,o),async(a,{subPath:n})=>await a.readFilePromise(n,o))}readFileSync(r,o){return this.makeCallSync(r,()=>this.baseFs.readFileSync(r,o),(a,{subPath:n})=>a.readFileSync(n,o))}async readdirPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.readdirPromise(r,o),async(a,{subPath:n})=>await a.readdirPromise(n,o),{requireSubpath:!1})}readdirSync(r,o){return this.makeCallSync(r,()=>this.baseFs.readdirSync(r,o),(a,{subPath:n})=>a.readdirSync(n,o),{requireSubpath:!1})}async readlinkPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.readlinkPromise(r),async(o,{subPath:a})=>await o.readlinkPromise(a))}readlinkSync(r){return this.makeCallSync(r,()=>this.baseFs.readlinkSync(r),(o,{subPath:a})=>o.readlinkSync(a))}async truncatePromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.truncatePromise(r,o),async(a,{subPath:n})=>await a.truncatePromise(n,o))}truncateSync(r,o){return this.makeCallSync(r,()=>this.baseFs.truncateSync(r,o),(a,{subPath:n})=>a.truncateSync(n,o))}async ftruncatePromise(r,o){if((r&wa)!==this.magic)return this.baseFs.ftruncatePromise(r,o);let a=this.fdMap.get(r);if(typeof a>"u")throw Io("ftruncate");let[n,u]=a;return n.ftruncatePromise(u,o)}ftruncateSync(r,o){if((r&wa)!==this.magic)return this.baseFs.ftruncateSync(r,o);let a=this.fdMap.get(r);if(typeof a>"u")throw Io("ftruncateSync");let[n,u]=a;return n.ftruncateSync(u,o)}watch(r,o,a){return this.makeCallSync(r,()=>this.baseFs.watch(r,o,a),(n,{subPath:u})=>n.watch(u,o,a))}watchFile(r,o,a){return this.makeCallSync(r,()=>this.baseFs.watchFile(r,o,a),()=>ny(this,r,o,a))}unwatchFile(r,o){return this.makeCallSync(r,()=>this.baseFs.unwatchFile(r,o),()=>Ug(this,r,o))}async makeCallPromise(r,o,a,{requireSubpath:n=!0}={}){if(typeof r!="string")return await o();let u=this.resolve(r),A=this.findMount(u);return A?n&&A.subPath==="/"?await o():await this.getMountPromise(A.archivePath,async p=>await a(p,A)):await o()}makeCallSync(r,o,a,{requireSubpath:n=!0}={}){if(typeof r!="string")return o();let u=this.resolve(r),A=this.findMount(u);return!A||n&&A.subPath==="/"?o():this.getMountSync(A.archivePath,p=>a(p,A))}findMount(r){if(this.filter&&!this.filter.test(r))return null;let o="";for(;;){let a=r.substring(o.length),n=this.getMountPoint(a,o);if(!n)return null;if(o=this.pathUtils.join(o,n),!this.isMount.has(o)){if(this.notMount.has(o))continue;try{if(this.typeCheck!==null&&(this.baseFs.lstatSync(o).mode&jg.constants.S_IFMT)!==this.typeCheck){this.notMount.add(o);continue}}catch{return null}this.isMount.add(o)}return{archivePath:o,subPath:this.pathUtils.join(Bt.root,r.substring(o.length))}}}limitOpenFiles(r){if(this.mountInstances===null)return;let o=Date.now(),a=o+this.maxAge,n=r===null?0:this.mountInstances.size-r;for(let[u,{childFs:A,expiresAt:p,refCount:h}]of this.mountInstances.entries())if(!(h!==0||A.hasOpenFileHandles?.())){if(o>=p){A.saveAndClose?.(),this.mountInstances.delete(u),n-=1;continue}else if(r===null||n<=0){a=p;break}A.saveAndClose?.(),this.mountInstances.delete(u),n-=1}this.limitOpenFilesTimeout===null&&(r===null&&this.mountInstances.size>0||r!==null)&&isFinite(a)&&(this.limitOpenFilesTimeout=setTimeout(()=>{this.limitOpenFilesTimeout=null,this.limitOpenFiles(null)},a-o).unref())}async getMountPromise(r,o){if(this.mountInstances){let a=this.mountInstances.get(r);if(!a){let n=await this.factoryPromise(this.baseFs,r);a=this.mountInstances.get(r),a||(a={childFs:n(),expiresAt:0,refCount:0})}this.mountInstances.delete(r),this.limitOpenFiles(this.maxOpenFiles-1),this.mountInstances.set(r,a),a.expiresAt=Date.now()+this.maxAge,a.refCount+=1;try{return await o(a.childFs)}finally{a.refCount-=1}}else{let a=(await this.factoryPromise(this.baseFs,r))();try{return await o(a)}finally{a.saveAndClose?.()}}}getMountSync(r,o){if(this.mountInstances){let a=this.mountInstances.get(r);return a||(a={childFs:this.factorySync(this.baseFs,r),expiresAt:0,refCount:0}),this.mountInstances.delete(r),this.limitOpenFiles(this.maxOpenFiles-1),this.mountInstances.set(r,a),a.expiresAt=Date.now()+this.maxAge,o(a.childFs)}else{let a=this.factorySync(this.baseFs,r);try{return o(a)}finally{a.saveAndClose?.()}}}}});var Zt,WR,Yw,J7=Et(()=>{qg();Ca();Zt=()=>Object.assign(new Error("ENOSYS: unsupported filesystem access"),{code:"ENOSYS"}),WR=class extends gf{constructor(){super(z)}getExtractHint(){throw Zt()}getRealPath(){throw Zt()}resolve(){throw Zt()}async openPromise(){throw Zt()}openSync(){throw Zt()}async opendirPromise(){throw Zt()}opendirSync(){throw Zt()}async readPromise(){throw Zt()}readSync(){throw Zt()}async writePromise(){throw Zt()}writeSync(){throw Zt()}async closePromise(){throw Zt()}closeSync(){throw Zt()}createWriteStream(){throw Zt()}createReadStream(){throw Zt()}async realpathPromise(){throw Zt()}realpathSync(){throw Zt()}async readdirPromise(){throw Zt()}readdirSync(){throw Zt()}async existsPromise(e){throw Zt()}existsSync(e){throw Zt()}async accessPromise(){throw Zt()}accessSync(){throw Zt()}async statPromise(){throw Zt()}statSync(){throw Zt()}async fstatPromise(e){throw Zt()}fstatSync(e){throw Zt()}async lstatPromise(e){throw Zt()}lstatSync(e){throw Zt()}async fchmodPromise(){throw Zt()}fchmodSync(){throw Zt()}async chmodPromise(){throw Zt()}chmodSync(){throw Zt()}async fchownPromise(){throw Zt()}fchownSync(){throw Zt()}async chownPromise(){throw Zt()}chownSync(){throw Zt()}async mkdirPromise(){throw Zt()}mkdirSync(){throw Zt()}async rmdirPromise(){throw Zt()}rmdirSync(){throw Zt()}async rmPromise(){throw Zt()}rmSync(){throw Zt()}async linkPromise(){throw Zt()}linkSync(){throw Zt()}async symlinkPromise(){throw Zt()}symlinkSync(){throw Zt()}async renamePromise(){throw Zt()}renameSync(){throw Zt()}async copyFilePromise(){throw Zt()}copyFileSync(){throw Zt()}async appendFilePromise(){throw Zt()}appendFileSync(){throw Zt()}async writeFilePromise(){throw Zt()}writeFileSync(){throw Zt()}async unlinkPromise(){throw Zt()}unlinkSync(){throw Zt()}async utimesPromise(){throw Zt()}utimesSync(){throw Zt()}async lutimesPromise(){throw Zt()}lutimesSync(){throw Zt()}async readFilePromise(){throw Zt()}readFileSync(){throw Zt()}async readlinkPromise(){throw Zt()}readlinkSync(){throw Zt()}async truncatePromise(){throw Zt()}truncateSync(){throw Zt()}async ftruncatePromise(e,r){throw Zt()}ftruncateSync(e,r){throw Zt()}watch(){throw Zt()}watchFile(){throw Zt()}unwatchFile(){throw Zt()}},Yw=WR;Yw.instance=new WR});var Gp,X7=Et(()=>{df();Ca();Gp=class extends Ps{constructor(r){super(le);this.baseFs=r}mapFromBase(r){return le.fromPortablePath(r)}mapToBase(r){return le.toPortablePath(r)}}});var k_e,KR,Q_e,mi,Z7=Et(()=>{Gg();df();Ca();k_e=/^[0-9]+$/,KR=/^(\/(?:[^/]+\/)*?(?:\$\$virtual|__virtual__))((?:\/((?:[^/]+-)?[a-f0-9]+)(?:\/([^/]+))?)?((?:\/.*)?))$/,Q_e=/^([^/]+-)?[a-f0-9]+$/,mi=class extends Ps{constructor({baseFs:r=new Tn}={}){super(z);this.baseFs=r}static makeVirtualPath(r,o,a){if(z.basename(r)!=="__virtual__")throw new Error('Assertion failed: Virtual folders must be named "__virtual__"');if(!z.basename(o).match(Q_e))throw new Error("Assertion failed: Virtual components must be ended by an hexadecimal hash");let u=z.relative(z.dirname(r),a).split("/"),A=0;for(;A<u.length&&u[A]==="..";)A+=1;let p=u.slice(A);return z.join(r,o,String(A),...p)}static resolveVirtual(r){let o=r.match(KR);if(!o||!o[3]&&o[5])return r;let a=z.dirname(o[1]);if(!o[3]||!o[4])return a;if(!k_e.test(o[4]))return r;let u=Number(o[4]),A="../".repeat(u),p=o[5]||".";return mi.resolveVirtual(z.join(a,A,p))}getExtractHint(r){return this.baseFs.getExtractHint(r)}getRealPath(){return this.baseFs.getRealPath()}realpathSync(r){let o=r.match(KR);if(!o)return this.baseFs.realpathSync(r);if(!o[5])return r;let a=this.baseFs.realpathSync(this.mapToBase(r));return mi.makeVirtualPath(o[1],o[3],a)}async realpathPromise(r){let o=r.match(KR);if(!o)return await this.baseFs.realpathPromise(r);if(!o[5])return r;let a=await this.baseFs.realpathPromise(this.mapToBase(r));return mi.makeVirtualPath(o[1],o[3],a)}mapToBase(r){if(r==="")return r;if(this.pathUtils.isAbsolute(r))return mi.resolveVirtual(r);let o=mi.resolveVirtual(this.baseFs.resolve(Bt.dot)),a=mi.resolveVirtual(this.baseFs.resolve(r));return z.relative(o,a)||Bt.dot}mapFromBase(r){return r}}});function F_e(t,e){return typeof zR.default.isUtf8<"u"?zR.default.isUtf8(t):Buffer.byteLength(e)===t.byteLength}var zR,$7,eY,xD,tY=Et(()=>{zR=$e(ve("buffer")),$7=ve("url"),eY=ve("util");df();Ca();xD=class extends Ps{constructor(r){super(le);this.baseFs=r}mapFromBase(r){return r}mapToBase(r){if(typeof r=="string")return r;if(r instanceof URL)return(0,$7.fileURLToPath)(r);if(Buffer.isBuffer(r)){let o=r.toString();if(!F_e(r,o))throw new Error("Non-utf8 buffers are not supported at the moment. Please upvote the following issue if you encounter this error: https://github.com/yarnpkg/berry/issues/4942");return o}throw new Error(`Unsupported path type: ${(0,eY.inspect)(r)}`)}}});var rY,Bo,mf,jp,kD,QD,sy,Lc,Nc,R_e,T_e,L_e,N_e,Ww,nY=Et(()=>{rY=ve("readline"),Bo=Symbol("kBaseFs"),mf=Symbol("kFd"),jp=Symbol("kClosePromise"),kD=Symbol("kCloseResolve"),QD=Symbol("kCloseReject"),sy=Symbol("kRefs"),Lc=Symbol("kRef"),Nc=Symbol("kUnref"),Ww=class{constructor(e,r){this[R_e]=1;this[T_e]=void 0;this[L_e]=void 0;this[N_e]=void 0;this[Bo]=r,this[mf]=e}get fd(){return this[mf]}async appendFile(e,r){try{this[Lc](this.appendFile);let o=(typeof r=="string"?r:r?.encoding)??void 0;return await this[Bo].appendFilePromise(this.fd,e,o?{encoding:o}:void 0)}finally{this[Nc]()}}async chown(e,r){try{return this[Lc](this.chown),await this[Bo].fchownPromise(this.fd,e,r)}finally{this[Nc]()}}async chmod(e){try{return this[Lc](this.chmod),await this[Bo].fchmodPromise(this.fd,e)}finally{this[Nc]()}}createReadStream(e){return this[Bo].createReadStream(null,{...e,fd:this.fd})}createWriteStream(e){return this[Bo].createWriteStream(null,{...e,fd:this.fd})}datasync(){throw new Error("Method not implemented.")}sync(){throw new Error("Method not implemented.")}async read(e,r,o,a){try{this[Lc](this.read);let n;return Buffer.isBuffer(e)?n=e:(e??={},n=e.buffer??Buffer.alloc(16384),r=e.offset||0,o=e.length??n.byteLength,a=e.position??null),r??=0,o??=0,o===0?{bytesRead:o,buffer:n}:{bytesRead:await this[Bo].readPromise(this.fd,n,r,o,a),buffer:n}}finally{this[Nc]()}}async readFile(e){try{this[Lc](this.readFile);let r=(typeof e=="string"?e:e?.encoding)??void 0;return await this[Bo].readFilePromise(this.fd,r)}finally{this[Nc]()}}readLines(e){return(0,rY.createInterface)({input:this.createReadStream(e),crlfDelay:1/0})}async stat(e){try{return this[Lc](this.stat),await this[Bo].fstatPromise(this.fd,e)}finally{this[Nc]()}}async truncate(e){try{return this[Lc](this.truncate),await this[Bo].ftruncatePromise(this.fd,e)}finally{this[Nc]()}}utimes(e,r){throw new Error("Method not implemented.")}async writeFile(e,r){try{this[Lc](this.writeFile);let o=(typeof r=="string"?r:r?.encoding)??void 0;await this[Bo].writeFilePromise(this.fd,e,o)}finally{this[Nc]()}}async write(...e){try{if(this[Lc](this.write),ArrayBuffer.isView(e[0])){let[r,o,a,n]=e;return{bytesWritten:await this[Bo].writePromise(this.fd,r,o??void 0,a??void 0,n??void 0),buffer:r}}else{let[r,o,a]=e;return{bytesWritten:await this[Bo].writePromise(this.fd,r,o,a),buffer:r}}}finally{this[Nc]()}}async writev(e,r){try{this[Lc](this.writev);let o=0;if(typeof r<"u")for(let a of e){let n=await this.write(a,void 0,void 0,r);o+=n.bytesWritten,r+=n.bytesWritten}else for(let a of e){let n=await this.write(a);o+=n.bytesWritten}return{buffers:e,bytesWritten:o}}finally{this[Nc]()}}readv(e,r){throw new Error("Method not implemented.")}close(){if(this[mf]===-1)return Promise.resolve();if(this[jp])return this[jp];if(this[sy]--,this[sy]===0){let e=this[mf];this[mf]=-1,this[jp]=this[Bo].closePromise(e).finally(()=>{this[jp]=void 0})}else this[jp]=new Promise((e,r)=>{this[kD]=e,this[QD]=r}).finally(()=>{this[jp]=void 0,this[QD]=void 0,this[kD]=void 0});return this[jp]}[(Bo,mf,R_e=sy,T_e=jp,L_e=kD,N_e=QD,Lc)](e){if(this[mf]===-1){let r=new Error("file closed");throw r.code="EBADF",r.syscall=e.name,r}this[sy]++}[Nc](){if(this[sy]--,this[sy]===0){let e=this[mf];this[mf]=-1,this[Bo].closePromise(e).then(this[kD],this[QD])}}}});function Kw(t,e){e=new xD(e);let r=(o,a,n)=>{let u=o[a];o[a]=n,typeof u?.[oy.promisify.custom]<"u"&&(n[oy.promisify.custom]=u[oy.promisify.custom])};{r(t,"exists",(o,...a)=>{let u=typeof a[a.length-1]=="function"?a.pop():()=>{};process.nextTick(()=>{e.existsPromise(o).then(A=>{u(A)},()=>{u(!1)})})}),r(t,"read",(...o)=>{let[a,n,u,A,p,h]=o;if(o.length<=3){let E={};o.length<3?h=o[1]:(E=o[1],h=o[2]),{buffer:n=Buffer.alloc(16384),offset:u=0,length:A=n.byteLength,position:p}=E}if(u==null&&(u=0),A|=0,A===0){process.nextTick(()=>{h(null,0,n)});return}p==null&&(p=-1),process.nextTick(()=>{e.readPromise(a,n,u,A,p).then(E=>{h(null,E,n)},E=>{h(E,0,n)})})});for(let o of iY){let a=o.replace(/Promise$/,"");if(typeof t[a]>"u")continue;let n=e[o];if(typeof n>"u")continue;r(t,a,(...A)=>{let h=typeof A[A.length-1]=="function"?A.pop():()=>{};process.nextTick(()=>{n.apply(e,A).then(E=>{h(null,E)},E=>{h(E)})})})}t.realpath.native=t.realpath}{r(t,"existsSync",o=>{try{return e.existsSync(o)}catch{return!1}}),r(t,"readSync",(...o)=>{let[a,n,u,A,p]=o;return o.length<=3&&({offset:u=0,length:A=n.byteLength,position:p}=o[2]||{}),u==null&&(u=0),A|=0,A===0?0:(p==null&&(p=-1),e.readSync(a,n,u,A,p))});for(let o of O_e){let a=o;if(typeof t[a]>"u")continue;let n=e[o];typeof n>"u"||r(t,a,n.bind(e))}t.realpathSync.native=t.realpathSync}{let o=t.promises;for(let a of iY){let n=a.replace(/Promise$/,"");if(typeof o[n]>"u")continue;let u=e[a];typeof u>"u"||a!=="open"&&r(o,n,(A,...p)=>A instanceof Ww?A[n].apply(A,p):u.call(e,A,...p))}r(o,"open",async(...a)=>{let n=await e.openPromise(...a);return new Ww(n,e)})}t.read[oy.promisify.custom]=async(o,a,...n)=>({bytesRead:await e.readPromise(o,a,...n),buffer:a}),t.write[oy.promisify.custom]=async(o,a,...n)=>({bytesWritten:await e.writePromise(o,a,...n),buffer:a})}function FD(t,e){let r=Object.create(t);return Kw(r,e),r}var oy,O_e,iY,sY=Et(()=>{oy=ve("util");tY();nY();O_e=new Set(["accessSync","appendFileSync","createReadStream","createWriteStream","chmodSync","fchmodSync","chownSync","fchownSync","closeSync","copyFileSync","linkSync","lstatSync","fstatSync","lutimesSync","mkdirSync","openSync","opendirSync","readlinkSync","readFileSync","readdirSync","readlinkSync","realpathSync","renameSync","rmdirSync","rmSync","statSync","symlinkSync","truncateSync","ftruncateSync","unlinkSync","unwatchFile","utimesSync","watch","watchFile","writeFileSync","writeSync"]),iY=new Set(["accessPromise","appendFilePromise","fchmodPromise","chmodPromise","fchownPromise","chownPromise","closePromise","copyFilePromise","linkPromise","fstatPromise","lstatPromise","lutimesPromise","mkdirPromise","openPromise","opendirPromise","readdirPromise","realpathPromise","readFilePromise","readdirPromise","readlinkPromise","renamePromise","rmdirPromise","rmPromise","statPromise","symlinkPromise","truncatePromise","ftruncatePromise","unlinkPromise","utimesPromise","writeFilePromise","writeSync"])});function oY(t){let e=Math.ceil(Math.random()*4294967296).toString(16).padStart(8,"0");return`${t}${e}`}function aY(){if(VR)return VR;let t=le.toPortablePath(lY.default.tmpdir()),e=oe.realpathSync(t);return process.once("exit",()=>{oe.rmtempSync()}),VR={tmpdir:t,realTmpdir:e}}var lY,Oc,VR,oe,cY=Et(()=>{lY=$e(ve("os"));Gg();Ca();Oc=new Set,VR=null;oe=Object.assign(new Tn,{detachTemp(t){Oc.delete(t)},mktempSync(t){let{tmpdir:e,realTmpdir:r}=aY();for(;;){let o=oY("xfs-");try{this.mkdirSync(z.join(e,o))}catch(n){if(n.code==="EEXIST")continue;throw n}let a=z.join(r,o);if(Oc.add(a),typeof t>"u")return a;try{return t(a)}finally{if(Oc.has(a)){Oc.delete(a);try{this.removeSync(a)}catch{}}}}},async mktempPromise(t){let{tmpdir:e,realTmpdir:r}=aY();for(;;){let o=oY("xfs-");try{await this.mkdirPromise(z.join(e,o))}catch(n){if(n.code==="EEXIST")continue;throw n}let a=z.join(r,o);if(Oc.add(a),typeof t>"u")return a;try{return await t(a)}finally{if(Oc.has(a)){Oc.delete(a);try{await this.removePromise(a)}catch{}}}}},async rmtempPromise(){await Promise.all(Array.from(Oc.values()).map(async t=>{try{await oe.removePromise(t,{maxRetries:0}),Oc.delete(t)}catch{}}))},rmtempSync(){for(let t of Oc)try{oe.removeSync(t),Oc.delete(t)}catch{}}})});var zw={};zt(zw,{AliasFS:()=>_u,BasePortableFakeFS:()=>Uu,CustomDir:()=>jw,CwdFS:()=>gn,FakeFS:()=>gf,Filename:()=>dr,JailFS:()=>Hu,LazyFS:()=>iy,MountFS:()=>qp,NoFS:()=>Yw,NodeFS:()=>Tn,PortablePath:()=>Bt,PosixFS:()=>Gp,ProxiedFS:()=>Ps,VirtualFS:()=>mi,constants:()=>vi,errors:()=>tr,extendFs:()=>FD,normalizeLineEndings:()=>Hg,npath:()=>le,opendir:()=>SD,patchFs:()=>Kw,ppath:()=>z,setupCopyIndex:()=>PD,statUtils:()=>Ea,unwatchAllFiles:()=>_g,unwatchFile:()=>Ug,watchFile:()=>ny,xfs:()=>oe});var Pt=Et(()=>{k7();BD();HR();jR();N7();YR();qg();Ca();Ca();q7();qg();Y7();K7();z7();V7();J7();Gg();X7();df();Z7();sY();cY()});var hY=_((abt,pY)=>{pY.exports=fY;fY.sync=U_e;var uY=ve("fs");function M_e(t,e){var r=e.pathExt!==void 0?e.pathExt:process.env.PATHEXT;if(!r||(r=r.split(";"),r.indexOf("")!==-1))return!0;for(var o=0;o<r.length;o++){var a=r[o].toLowerCase();if(a&&t.substr(-a.length).toLowerCase()===a)return!0}return!1}function AY(t,e,r){return!t.isSymbolicLink()&&!t.isFile()?!1:M_e(e,r)}function fY(t,e,r){uY.stat(t,function(o,a){r(o,o?!1:AY(a,t,e))})}function U_e(t,e){return AY(uY.statSync(t),t,e)}});var EY=_((lbt,yY)=>{yY.exports=dY;dY.sync=__e;var gY=ve("fs");function dY(t,e,r){gY.stat(t,function(o,a){r(o,o?!1:mY(a,e))})}function __e(t,e){return mY(gY.statSync(t),e)}function mY(t,e){return t.isFile()&&H_e(t,e)}function H_e(t,e){var r=t.mode,o=t.uid,a=t.gid,n=e.uid!==void 0?e.uid:process.getuid&&process.getuid(),u=e.gid!==void 0?e.gid:process.getgid&&process.getgid(),A=parseInt("100",8),p=parseInt("010",8),h=parseInt("001",8),E=A|p,I=r&h||r&p&&a===u||r&A&&o===n||r&E&&n===0;return I}});var wY=_((ubt,CY)=>{var cbt=ve("fs"),RD;process.platform==="win32"||global.TESTING_WINDOWS?RD=hY():RD=EY();CY.exports=JR;JR.sync=q_e;function JR(t,e,r){if(typeof e=="function"&&(r=e,e={}),!r){if(typeof Promise!="function")throw new TypeError("callback not provided");return new Promise(function(o,a){JR(t,e||{},function(n,u){n?a(n):o(u)})})}RD(t,e||{},function(o,a){o&&(o.code==="EACCES"||e&&e.ignoreErrors)&&(o=null,a=!1),r(o,a)})}function q_e(t,e){try{return RD.sync(t,e||{})}catch(r){if(e&&e.ignoreErrors||r.code==="EACCES")return!1;throw r}}});var bY=_((Abt,SY)=>{var ay=process.platform==="win32"||process.env.OSTYPE==="cygwin"||process.env.OSTYPE==="msys",IY=ve("path"),G_e=ay?";":":",BY=wY(),vY=t=>Object.assign(new Error(`not found: ${t}`),{code:"ENOENT"}),DY=(t,e)=>{let r=e.colon||G_e,o=t.match(/\//)||ay&&t.match(/\\/)?[""]:[...ay?[process.cwd()]:[],...(e.path||process.env.PATH||"").split(r)],a=ay?e.pathExt||process.env.PATHEXT||".EXE;.CMD;.BAT;.COM":"",n=ay?a.split(r):[""];return ay&&t.indexOf(".")!==-1&&n[0]!==""&&n.unshift(""),{pathEnv:o,pathExt:n,pathExtExe:a}},PY=(t,e,r)=>{typeof e=="function"&&(r=e,e={}),e||(e={});let{pathEnv:o,pathExt:a,pathExtExe:n}=DY(t,e),u=[],A=h=>new Promise((E,I)=>{if(h===o.length)return e.all&&u.length?E(u):I(vY(t));let v=o[h],x=/^".*"$/.test(v)?v.slice(1,-1):v,C=IY.join(x,t),R=!x&&/^\.[\\\/]/.test(t)?t.slice(0,2)+C:C;E(p(R,h,0))}),p=(h,E,I)=>new Promise((v,x)=>{if(I===a.length)return v(A(E+1));let C=a[I];BY(h+C,{pathExt:n},(R,N)=>{if(!R&&N)if(e.all)u.push(h+C);else return v(h+C);return v(p(h,E,I+1))})});return r?A(0).then(h=>r(null,h),r):A(0)},j_e=(t,e)=>{e=e||{};let{pathEnv:r,pathExt:o,pathExtExe:a}=DY(t,e),n=[];for(let u=0;u<r.length;u++){let A=r[u],p=/^".*"$/.test(A)?A.slice(1,-1):A,h=IY.join(p,t),E=!p&&/^\.[\\\/]/.test(t)?t.slice(0,2)+h:h;for(let I=0;I<o.length;I++){let v=E+o[I];try{if(BY.sync(v,{pathExt:a}))if(e.all)n.push(v);else return v}catch{}}}if(e.all&&n.length)return n;if(e.nothrow)return null;throw vY(t)};SY.exports=PY;PY.sync=j_e});var kY=_((fbt,XR)=>{"use strict";var xY=(t={})=>{let e=t.env||process.env;return(t.platform||process.platform)!=="win32"?"PATH":Object.keys(e).reverse().find(o=>o.toUpperCase()==="PATH")||"Path"};XR.exports=xY;XR.exports.default=xY});var TY=_((pbt,RY)=>{"use strict";var QY=ve("path"),Y_e=bY(),W_e=kY();function FY(t,e){let r=t.options.env||process.env,o=process.cwd(),a=t.options.cwd!=null,n=a&&process.chdir!==void 0&&!process.chdir.disabled;if(n)try{process.chdir(t.options.cwd)}catch{}let u;try{u=Y_e.sync(t.command,{path:r[W_e({env:r})],pathExt:e?QY.delimiter:void 0})}catch{}finally{n&&process.chdir(o)}return u&&(u=QY.resolve(a?t.options.cwd:"",u)),u}function K_e(t){return FY(t)||FY(t,!0)}RY.exports=K_e});var LY=_((hbt,$R)=>{"use strict";var ZR=/([()\][%!^"`<>&|;, *?])/g;function z_e(t){return t=t.replace(ZR,"^$1"),t}function V_e(t,e){return t=`${t}`,t=t.replace(/(\\*)"/g,'$1$1\\"'),t=t.replace(/(\\*)$/,"$1$1"),t=`"${t}"`,t=t.replace(ZR,"^$1"),e&&(t=t.replace(ZR,"^$1")),t}$R.exports.command=z_e;$R.exports.argument=V_e});var OY=_((gbt,NY)=>{"use strict";NY.exports=/^#!(.*)/});var UY=_((dbt,MY)=>{"use strict";var J_e=OY();MY.exports=(t="")=>{let e=t.match(J_e);if(!e)return null;let[r,o]=e[0].replace(/#! ?/,"").split(" "),a=r.split("/").pop();return a==="env"?o:o?`${a} ${o}`:a}});var HY=_((mbt,_Y)=>{"use strict";var eT=ve("fs"),X_e=UY();function Z_e(t){let r=Buffer.alloc(150),o;try{o=eT.openSync(t,"r"),eT.readSync(o,r,0,150,0),eT.closeSync(o)}catch{}return X_e(r.toString())}_Y.exports=Z_e});var YY=_((ybt,jY)=>{"use strict";var $_e=ve("path"),qY=TY(),GY=LY(),e8e=HY(),t8e=process.platform==="win32",r8e=/\.(?:com|exe)$/i,n8e=/node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;function i8e(t){t.file=qY(t);let e=t.file&&e8e(t.file);return e?(t.args.unshift(t.file),t.command=e,qY(t)):t.file}function s8e(t){if(!t8e)return t;let e=i8e(t),r=!r8e.test(e);if(t.options.forceShell||r){let o=n8e.test(e);t.command=$_e.normalize(t.command),t.command=GY.command(t.command),t.args=t.args.map(n=>GY.argument(n,o));let a=[t.command].concat(t.args).join(" ");t.args=["/d","/s","/c",`"${a}"`],t.command=process.env.comspec||"cmd.exe",t.options.windowsVerbatimArguments=!0}return t}function o8e(t,e,r){e&&!Array.isArray(e)&&(r=e,e=null),e=e?e.slice(0):[],r=Object.assign({},r);let o={command:t,args:e,options:r,file:void 0,original:{command:t,args:e}};return r.shell?o:s8e(o)}jY.exports=o8e});var zY=_((Ebt,KY)=>{"use strict";var tT=process.platform==="win32";function rT(t,e){return Object.assign(new Error(`${e} ${t.command} ENOENT`),{code:"ENOENT",errno:"ENOENT",syscall:`${e} ${t.command}`,path:t.command,spawnargs:t.args})}function a8e(t,e){if(!tT)return;let r=t.emit;t.emit=function(o,a){if(o==="exit"){let n=WY(a,e,"spawn");if(n)return r.call(t,"error",n)}return r.apply(t,arguments)}}function WY(t,e){return tT&&t===1&&!e.file?rT(e.original,"spawn"):null}function l8e(t,e){return tT&&t===1&&!e.file?rT(e.original,"spawnSync"):null}KY.exports={hookChildProcess:a8e,verifyENOENT:WY,verifyENOENTSync:l8e,notFoundError:rT}});var sT=_((Cbt,ly)=>{"use strict";var VY=ve("child_process"),nT=YY(),iT=zY();function JY(t,e,r){let o=nT(t,e,r),a=VY.spawn(o.command,o.args,o.options);return iT.hookChildProcess(a,o),a}function c8e(t,e,r){let o=nT(t,e,r),a=VY.spawnSync(o.command,o.args,o.options);return a.error=a.error||iT.verifyENOENTSync(a.status,o),a}ly.exports=JY;ly.exports.spawn=JY;ly.exports.sync=c8e;ly.exports._parse=nT;ly.exports._enoent=iT});var ZY=_((wbt,XY)=>{"use strict";function u8e(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Yg(t,e,r,o){this.message=t,this.expected=e,this.found=r,this.location=o,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,Yg)}u8e(Yg,Error);Yg.buildMessage=function(t,e){var r={literal:function(h){return'"'+a(h.text)+'"'},class:function(h){var E="",I;for(I=0;I<h.parts.length;I++)E+=h.parts[I]instanceof Array?n(h.parts[I][0])+"-"+n(h.parts[I][1]):n(h.parts[I]);return"["+(h.inverted?"^":"")+E+"]"},any:function(h){return"any character"},end:function(h){return"end of input"},other:function(h){return h.description}};function o(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(E){return"\\x0"+o(E)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(E){return"\\x"+o(E)})}function n(h){return h.replace(/\\/g,"\\\\").replace(/\]/g,"\\]").replace(/\^/g,"\\^").replace(/-/g,"\\-").replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(E){return"\\x0"+o(E)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(E){return"\\x"+o(E)})}function u(h){return r[h.type](h)}function A(h){var E=new Array(h.length),I,v;for(I=0;I<h.length;I++)E[I]=u(h[I]);if(E.sort(),E.length>0){for(I=1,v=1;I<E.length;I++)E[I-1]!==E[I]&&(E[v]=E[I],v++);E.length=v}switch(E.length){case 1:return E[0];case 2:return E[0]+" or "+E[1];default:return E.slice(0,-1).join(", ")+", or "+E[E.length-1]}}function p(h){return h?'"'+a(h)+'"':"end of input"}return"Expected "+A(t)+" but "+p(e)+" found."};function A8e(t,e){e=e!==void 0?e:{};var r={},o={Start:gg},a=gg,n=function(L){return L||[]},u=function(L,K,re){return[{command:L,type:K}].concat(re||[])},A=function(L,K){return[{command:L,type:K||";"}]},p=function(L){return L},h=";",E=Br(";",!1),I="&",v=Br("&",!1),x=function(L,K){return K?{chain:L,then:K}:{chain:L}},C=function(L,K){return{type:L,line:K}},R="&&",N=Br("&&",!1),U="||",V=Br("||",!1),te=function(L,K){return K?{...L,then:K}:L},ae=function(L,K){return{type:L,chain:K}},fe="|&",ue=Br("|&",!1),me="|",he=Br("|",!1),Be="=",we=Br("=",!1),g=function(L,K){return{name:L,args:[K]}},Ee=function(L){return{name:L,args:[]}},Pe="(",ce=Br("(",!1),ne=")",ee=Br(")",!1),Ie=function(L,K){return{type:"subshell",subshell:L,args:K}},Fe="{",At=Br("{",!1),H="}",at=Br("}",!1),Re=function(L,K){return{type:"group",group:L,args:K}},ke=function(L,K){return{type:"command",args:K,envs:L}},xe=function(L){return{type:"envs",envs:L}},He=function(L){return L},Te=function(L){return L},Ve=/^[0-9]/,qe=Cs([["0","9"]],!1,!1),b=function(L,K,re){return{type:"redirection",subtype:K,fd:L!==null?parseInt(L):null,args:[re]}},w=">>",S=Br(">>",!1),y=">&",F=Br(">&",!1),J=">",X=Br(">",!1),Z="<<<",ie=Br("<<<",!1),be="<&",Le=Br("<&",!1),ot="<",dt=Br("<",!1),Gt=function(L){return{type:"argument",segments:[].concat(...L)}},$t=function(L){return L},bt="$'",an=Br("$'",!1),Qr="'",mr=Br("'",!1),br=function(L){return[{type:"text",text:L}]},Wr='""',Kn=Br('""',!1),Ls=function(){return{type:"text",text:""}},Ti='"',ps=Br('"',!1),io=function(L){return L},Si=function(L){return{type:"arithmetic",arithmetic:L,quoted:!0}},Ns=function(L){return{type:"shell",shell:L,quoted:!0}},so=function(L){return{type:"variable",...L,quoted:!0}},uc=function(L){return{type:"text",text:L}},uu=function(L){return{type:"arithmetic",arithmetic:L,quoted:!1}},cp=function(L){return{type:"shell",shell:L,quoted:!1}},up=function(L){return{type:"variable",...L,quoted:!1}},Os=function(L){return{type:"glob",pattern:L}},Dn=/^[^']/,oo=Cs(["'"],!0,!1),Ms=function(L){return L.join("")},yl=/^[^$"]/,El=Cs(["$",'"'],!0,!1),ao=`\\
-`,zn=Br(`\\
-`,!1),On=function(){return""},Li="\\",Mn=Br("\\",!1),_i=/^[\\$"`]/,rr=Cs(["\\","$",'"',"`"],!1,!1),Oe=function(L){return L},ii="\\a",Ua=Br("\\a",!1),hr=function(){return"a"},Ac="\\b",Au=Br("\\b",!1),fc=function(){return"\b"},Cl=/^[Ee]/,DA=Cs(["E","e"],!1,!1),fu=function(){return"\x1B"},Ce="\\f",Rt=Br("\\f",!1),pc=function(){return"\f"},Hi="\\n",pu=Br("\\n",!1),Yt=function(){return`
-`},wl="\\r",PA=Br("\\r",!1),Ap=function(){return"\r"},hc="\\t",SA=Br("\\t",!1),Qn=function(){return" "},hi="\\v",gc=Br("\\v",!1),bA=function(){return"\v"},sa=/^[\\'"?]/,Ni=Cs(["\\","'",'"',"?"],!1,!1),_o=function(L){return String.fromCharCode(parseInt(L,16))},Ze="\\x",lo=Br("\\x",!1),dc="\\u",hu=Br("\\u",!1),qi="\\U",gu=Br("\\U",!1),xA=function(L){return String.fromCodePoint(parseInt(L,16))},Ha=/^[0-7]/,mc=Cs([["0","7"]],!1,!1),hs=/^[0-9a-fA-f]/,Ht=Cs([["0","9"],["a","f"],["A","f"]],!1,!1),Fn=Ag(),Ci="{}",oa=Br("{}",!1),co=function(){return"{}"},Us="-",aa=Br("-",!1),la="+",Ho=Br("+",!1),wi=".",gs=Br(".",!1),ds=function(L,K,re){return{type:"number",value:(L==="-"?-1:1)*parseFloat(K.join("")+"."+re.join(""))}},ms=function(L,K){return{type:"number",value:(L==="-"?-1:1)*parseInt(K.join(""))}},_s=function(L){return{type:"variable",...L}},Un=function(L){return{type:"variable",name:L}},Pn=function(L){return L},ys="*",We=Br("*",!1),tt="/",It=Br("/",!1),ir=function(L,K,re){return{type:K==="*"?"multiplication":"division",right:re}},$=function(L,K){return K.reduce((re,pe)=>({left:re,...pe}),L)},ye=function(L,K,re){return{type:K==="+"?"addition":"subtraction",right:re}},Ne="$((",pt=Br("$((",!1),ht="))",Tt=Br("))",!1),er=function(L){return L},$r="$(",Gi=Br("$(",!1),es=function(L){return L},bi="${",qo=Br("${",!1),kA=":-",QA=Br(":-",!1),fp=function(L,K){return{name:L,defaultValue:K}},sg=":-}",du=Br(":-}",!1),og=function(L){return{name:L,defaultValue:[]}},mu=":+",uo=Br(":+",!1),FA=function(L,K){return{name:L,alternativeValue:K}},yc=":+}",ca=Br(":+}",!1),ag=function(L){return{name:L,alternativeValue:[]}},Ec=function(L){return{name:L}},Sm="$",lg=Br("$",!1),ei=function(L){return e.isGlobPattern(L)},pp=function(L){return L},cg=/^[a-zA-Z0-9_]/,RA=Cs([["a","z"],["A","Z"],["0","9"],"_"],!1,!1),Hs=function(){return ug()},yu=/^[$@*?#a-zA-Z0-9_\-]/,qa=Cs(["$","@","*","?","#",["a","z"],["A","Z"],["0","9"],"_","-"],!1,!1),ji=/^[()}<>$|&; \t"']/,ua=Cs(["(",")","}","<",">","$","|","&",";"," "," ",'"',"'"],!1,!1),Eu=/^[<>&; \t"']/,Es=Cs(["<",">","&",";"," "," ",'"',"'"],!1,!1),Cc=/^[ \t]/,wc=Cs([" "," "],!1,!1),j=0,Dt=0,Il=[{line:1,column:1}],xi=0,Ic=[],ct=0,Cu;if("startRule"in e){if(!(e.startRule in o))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');a=o[e.startRule]}function ug(){return t.substring(Dt,j)}function yw(){return Bc(Dt,j)}function TA(L,K){throw K=K!==void 0?K:Bc(Dt,j),hg([pg(L)],t.substring(Dt,j),K)}function hp(L,K){throw K=K!==void 0?K:Bc(Dt,j),bm(L,K)}function Br(L,K){return{type:"literal",text:L,ignoreCase:K}}function Cs(L,K,re){return{type:"class",parts:L,inverted:K,ignoreCase:re}}function Ag(){return{type:"any"}}function fg(){return{type:"end"}}function pg(L){return{type:"other",description:L}}function gp(L){var K=Il[L],re;if(K)return K;for(re=L-1;!Il[re];)re--;for(K=Il[re],K={line:K.line,column:K.column};re<L;)t.charCodeAt(re)===10?(K.line++,K.column=1):K.column++,re++;return Il[L]=K,K}function Bc(L,K){var re=gp(L),pe=gp(K);return{start:{offset:L,line:re.line,column:re.column},end:{offset:K,line:pe.line,column:pe.column}}}function Ct(L){j<xi||(j>xi&&(xi=j,Ic=[]),Ic.push(L))}function bm(L,K){return new Yg(L,null,null,K)}function hg(L,K,re){return new Yg(Yg.buildMessage(L,K),L,K,re)}function gg(){var L,K,re;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();return K!==r?(re=wu(),re===r&&(re=null),re!==r?(Dt=L,K=n(re),L=K):(j=L,L=r)):(j=L,L=r),L}function wu(){var L,K,re,pe,Je;if(L=j,K=Iu(),K!==r){for(re=[],pe=Qt();pe!==r;)re.push(pe),pe=Qt();re!==r?(pe=dg(),pe!==r?(Je=xm(),Je===r&&(Je=null),Je!==r?(Dt=L,K=u(K,pe,Je),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r)}else j=L,L=r;if(L===r)if(L=j,K=Iu(),K!==r){for(re=[],pe=Qt();pe!==r;)re.push(pe),pe=Qt();re!==r?(pe=dg(),pe===r&&(pe=null),pe!==r?(Dt=L,K=A(K,pe),L=K):(j=L,L=r)):(j=L,L=r)}else j=L,L=r;return L}function xm(){var L,K,re,pe,Je;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(re=wu(),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();pe!==r?(Dt=L,K=p(re),L=K):(j=L,L=r)}else j=L,L=r;else j=L,L=r;return L}function dg(){var L;return t.charCodeAt(j)===59?(L=h,j++):(L=r,ct===0&&Ct(E)),L===r&&(t.charCodeAt(j)===38?(L=I,j++):(L=r,ct===0&&Ct(v))),L}function Iu(){var L,K,re;return L=j,K=Aa(),K!==r?(re=Ew(),re===r&&(re=null),re!==r?(Dt=L,K=x(K,re),L=K):(j=L,L=r)):(j=L,L=r),L}function Ew(){var L,K,re,pe,Je,mt,fr;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(re=km(),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r)if(Je=Iu(),Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();mt!==r?(Dt=L,K=C(re,Je),L=K):(j=L,L=r)}else j=L,L=r;else j=L,L=r}else j=L,L=r;else j=L,L=r;return L}function km(){var L;return t.substr(j,2)===R?(L=R,j+=2):(L=r,ct===0&&Ct(N)),L===r&&(t.substr(j,2)===U?(L=U,j+=2):(L=r,ct===0&&Ct(V))),L}function Aa(){var L,K,re;return L=j,K=mg(),K!==r?(re=vc(),re===r&&(re=null),re!==r?(Dt=L,K=te(K,re),L=K):(j=L,L=r)):(j=L,L=r),L}function vc(){var L,K,re,pe,Je,mt,fr;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(re=Bl(),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r)if(Je=Aa(),Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();mt!==r?(Dt=L,K=ae(re,Je),L=K):(j=L,L=r)}else j=L,L=r;else j=L,L=r}else j=L,L=r;else j=L,L=r;return L}function Bl(){var L;return t.substr(j,2)===fe?(L=fe,j+=2):(L=r,ct===0&&Ct(ue)),L===r&&(t.charCodeAt(j)===124?(L=me,j++):(L=r,ct===0&&Ct(he))),L}function Bu(){var L,K,re,pe,Je,mt;if(L=j,K=wg(),K!==r)if(t.charCodeAt(j)===61?(re=Be,j++):(re=r,ct===0&&Ct(we)),re!==r)if(pe=Go(),pe!==r){for(Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();Je!==r?(Dt=L,K=g(K,pe),L=K):(j=L,L=r)}else j=L,L=r;else j=L,L=r;else j=L,L=r;if(L===r)if(L=j,K=wg(),K!==r)if(t.charCodeAt(j)===61?(re=Be,j++):(re=r,ct===0&&Ct(we)),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();pe!==r?(Dt=L,K=Ee(K),L=K):(j=L,L=r)}else j=L,L=r;else j=L,L=r;return L}function mg(){var L,K,re,pe,Je,mt,fr,Cr,yn,oi,Oi;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(t.charCodeAt(j)===40?(re=Pe,j++):(re=r,ct===0&&Ct(ce)),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r)if(Je=wu(),Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();if(mt!==r)if(t.charCodeAt(j)===41?(fr=ne,j++):(fr=r,ct===0&&Ct(ee)),fr!==r){for(Cr=[],yn=Qt();yn!==r;)Cr.push(yn),yn=Qt();if(Cr!==r){for(yn=[],oi=Ga();oi!==r;)yn.push(oi),oi=Ga();if(yn!==r){for(oi=[],Oi=Qt();Oi!==r;)oi.push(Oi),Oi=Qt();oi!==r?(Dt=L,K=Ie(Je,yn),L=K):(j=L,L=r)}else j=L,L=r}else j=L,L=r}else j=L,L=r;else j=L,L=r}else j=L,L=r;else j=L,L=r}else j=L,L=r;else j=L,L=r;if(L===r){for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(t.charCodeAt(j)===123?(re=Fe,j++):(re=r,ct===0&&Ct(At)),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r)if(Je=wu(),Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();if(mt!==r)if(t.charCodeAt(j)===125?(fr=H,j++):(fr=r,ct===0&&Ct(at)),fr!==r){for(Cr=[],yn=Qt();yn!==r;)Cr.push(yn),yn=Qt();if(Cr!==r){for(yn=[],oi=Ga();oi!==r;)yn.push(oi),oi=Ga();if(yn!==r){for(oi=[],Oi=Qt();Oi!==r;)oi.push(Oi),Oi=Qt();oi!==r?(Dt=L,K=Re(Je,yn),L=K):(j=L,L=r)}else j=L,L=r}else j=L,L=r}else j=L,L=r;else j=L,L=r}else j=L,L=r;else j=L,L=r}else j=L,L=r;else j=L,L=r;if(L===r){for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r){for(re=[],pe=Bu();pe!==r;)re.push(pe),pe=Bu();if(re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r){if(Je=[],mt=dp(),mt!==r)for(;mt!==r;)Je.push(mt),mt=dp();else Je=r;if(Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();mt!==r?(Dt=L,K=ke(re,Je),L=K):(j=L,L=r)}else j=L,L=r}else j=L,L=r}else j=L,L=r}else j=L,L=r;if(L===r){for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r){if(re=[],pe=Bu(),pe!==r)for(;pe!==r;)re.push(pe),pe=Bu();else re=r;if(re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();pe!==r?(Dt=L,K=xe(re),L=K):(j=L,L=r)}else j=L,L=r}else j=L,L=r}}}return L}function LA(){var L,K,re,pe,Je;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r){if(re=[],pe=mp(),pe!==r)for(;pe!==r;)re.push(pe),pe=mp();else re=r;if(re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();pe!==r?(Dt=L,K=He(re),L=K):(j=L,L=r)}else j=L,L=r}else j=L,L=r;return L}function dp(){var L,K,re;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r?(re=Ga(),re!==r?(Dt=L,K=Te(re),L=K):(j=L,L=r)):(j=L,L=r),L===r){for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();K!==r?(re=mp(),re!==r?(Dt=L,K=Te(re),L=K):(j=L,L=r)):(j=L,L=r)}return L}function Ga(){var L,K,re,pe,Je;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();return K!==r?(Ve.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(qe)),re===r&&(re=null),re!==r?(pe=yg(),pe!==r?(Je=mp(),Je!==r?(Dt=L,K=b(re,pe,Je),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L}function yg(){var L;return t.substr(j,2)===w?(L=w,j+=2):(L=r,ct===0&&Ct(S)),L===r&&(t.substr(j,2)===y?(L=y,j+=2):(L=r,ct===0&&Ct(F)),L===r&&(t.charCodeAt(j)===62?(L=J,j++):(L=r,ct===0&&Ct(X)),L===r&&(t.substr(j,3)===Z?(L=Z,j+=3):(L=r,ct===0&&Ct(ie)),L===r&&(t.substr(j,2)===be?(L=be,j+=2):(L=r,ct===0&&Ct(Le)),L===r&&(t.charCodeAt(j)===60?(L=ot,j++):(L=r,ct===0&&Ct(dt))))))),L}function mp(){var L,K,re;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();return K!==r?(re=Go(),re!==r?(Dt=L,K=Te(re),L=K):(j=L,L=r)):(j=L,L=r),L}function Go(){var L,K,re;if(L=j,K=[],re=ws(),re!==r)for(;re!==r;)K.push(re),re=ws();else K=r;return K!==r&&(Dt=L,K=Gt(K)),L=K,L}function ws(){var L,K;return L=j,K=Ii(),K!==r&&(Dt=L,K=$t(K)),L=K,L===r&&(L=j,K=Qm(),K!==r&&(Dt=L,K=$t(K)),L=K,L===r&&(L=j,K=Fm(),K!==r&&(Dt=L,K=$t(K)),L=K,L===r&&(L=j,K=jo(),K!==r&&(Dt=L,K=$t(K)),L=K))),L}function Ii(){var L,K,re,pe;return L=j,t.substr(j,2)===bt?(K=bt,j+=2):(K=r,ct===0&&Ct(an)),K!==r?(re=ln(),re!==r?(t.charCodeAt(j)===39?(pe=Qr,j++):(pe=r,ct===0&&Ct(mr)),pe!==r?(Dt=L,K=br(re),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L}function Qm(){var L,K,re,pe;return L=j,t.charCodeAt(j)===39?(K=Qr,j++):(K=r,ct===0&&Ct(mr)),K!==r?(re=Ep(),re!==r?(t.charCodeAt(j)===39?(pe=Qr,j++):(pe=r,ct===0&&Ct(mr)),pe!==r?(Dt=L,K=br(re),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L}function Fm(){var L,K,re,pe;if(L=j,t.substr(j,2)===Wr?(K=Wr,j+=2):(K=r,ct===0&&Ct(Kn)),K!==r&&(Dt=L,K=Ls()),L=K,L===r)if(L=j,t.charCodeAt(j)===34?(K=Ti,j++):(K=r,ct===0&&Ct(ps)),K!==r){for(re=[],pe=NA();pe!==r;)re.push(pe),pe=NA();re!==r?(t.charCodeAt(j)===34?(pe=Ti,j++):(pe=r,ct===0&&Ct(ps)),pe!==r?(Dt=L,K=io(re),L=K):(j=L,L=r)):(j=L,L=r)}else j=L,L=r;return L}function jo(){var L,K,re;if(L=j,K=[],re=yp(),re!==r)for(;re!==r;)K.push(re),re=yp();else K=r;return K!==r&&(Dt=L,K=io(K)),L=K,L}function NA(){var L,K;return L=j,K=jr(),K!==r&&(Dt=L,K=Si(K)),L=K,L===r&&(L=j,K=Cp(),K!==r&&(Dt=L,K=Ns(K)),L=K,L===r&&(L=j,K=Pc(),K!==r&&(Dt=L,K=so(K)),L=K,L===r&&(L=j,K=Eg(),K!==r&&(Dt=L,K=uc(K)),L=K))),L}function yp(){var L,K;return L=j,K=jr(),K!==r&&(Dt=L,K=uu(K)),L=K,L===r&&(L=j,K=Cp(),K!==r&&(Dt=L,K=cp(K)),L=K,L===r&&(L=j,K=Pc(),K!==r&&(Dt=L,K=up(K)),L=K,L===r&&(L=j,K=Cw(),K!==r&&(Dt=L,K=Os(K)),L=K,L===r&&(L=j,K=pa(),K!==r&&(Dt=L,K=uc(K)),L=K)))),L}function Ep(){var L,K,re;for(L=j,K=[],Dn.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(oo));re!==r;)K.push(re),Dn.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(oo));return K!==r&&(Dt=L,K=Ms(K)),L=K,L}function Eg(){var L,K,re;if(L=j,K=[],re=fa(),re===r&&(yl.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(El))),re!==r)for(;re!==r;)K.push(re),re=fa(),re===r&&(yl.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(El)));else K=r;return K!==r&&(Dt=L,K=Ms(K)),L=K,L}function fa(){var L,K,re;return L=j,t.substr(j,2)===ao?(K=ao,j+=2):(K=r,ct===0&&Ct(zn)),K!==r&&(Dt=L,K=On()),L=K,L===r&&(L=j,t.charCodeAt(j)===92?(K=Li,j++):(K=r,ct===0&&Ct(Mn)),K!==r?(_i.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(rr)),re!==r?(Dt=L,K=Oe(re),L=K):(j=L,L=r)):(j=L,L=r)),L}function ln(){var L,K,re;for(L=j,K=[],re=Ao(),re===r&&(Dn.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(oo)));re!==r;)K.push(re),re=Ao(),re===r&&(Dn.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(oo)));return K!==r&&(Dt=L,K=Ms(K)),L=K,L}function Ao(){var L,K,re;return L=j,t.substr(j,2)===ii?(K=ii,j+=2):(K=r,ct===0&&Ct(Ua)),K!==r&&(Dt=L,K=hr()),L=K,L===r&&(L=j,t.substr(j,2)===Ac?(K=Ac,j+=2):(K=r,ct===0&&Ct(Au)),K!==r&&(Dt=L,K=fc()),L=K,L===r&&(L=j,t.charCodeAt(j)===92?(K=Li,j++):(K=r,ct===0&&Ct(Mn)),K!==r?(Cl.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(DA)),re!==r?(Dt=L,K=fu(),L=K):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===Ce?(K=Ce,j+=2):(K=r,ct===0&&Ct(Rt)),K!==r&&(Dt=L,K=pc()),L=K,L===r&&(L=j,t.substr(j,2)===Hi?(K=Hi,j+=2):(K=r,ct===0&&Ct(pu)),K!==r&&(Dt=L,K=Yt()),L=K,L===r&&(L=j,t.substr(j,2)===wl?(K=wl,j+=2):(K=r,ct===0&&Ct(PA)),K!==r&&(Dt=L,K=Ap()),L=K,L===r&&(L=j,t.substr(j,2)===hc?(K=hc,j+=2):(K=r,ct===0&&Ct(SA)),K!==r&&(Dt=L,K=Qn()),L=K,L===r&&(L=j,t.substr(j,2)===hi?(K=hi,j+=2):(K=r,ct===0&&Ct(gc)),K!==r&&(Dt=L,K=bA()),L=K,L===r&&(L=j,t.charCodeAt(j)===92?(K=Li,j++):(K=r,ct===0&&Ct(Mn)),K!==r?(sa.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(Ni)),re!==r?(Dt=L,K=Oe(re),L=K):(j=L,L=r)):(j=L,L=r),L===r&&(L=OA()))))))))),L}function OA(){var L,K,re,pe,Je,mt,fr,Cr,yn,oi,Oi,Bg;return L=j,t.charCodeAt(j)===92?(K=Li,j++):(K=r,ct===0&&Ct(Mn)),K!==r?(re=ja(),re!==r?(Dt=L,K=_o(re),L=K):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===Ze?(K=Ze,j+=2):(K=r,ct===0&&Ct(lo)),K!==r?(re=j,pe=j,Je=ja(),Je!==r?(mt=si(),mt!==r?(Je=[Je,mt],pe=Je):(j=pe,pe=r)):(j=pe,pe=r),pe===r&&(pe=ja()),pe!==r?re=t.substring(re,j):re=pe,re!==r?(Dt=L,K=_o(re),L=K):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===dc?(K=dc,j+=2):(K=r,ct===0&&Ct(hu)),K!==r?(re=j,pe=j,Je=si(),Je!==r?(mt=si(),mt!==r?(fr=si(),fr!==r?(Cr=si(),Cr!==r?(Je=[Je,mt,fr,Cr],pe=Je):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r),pe!==r?re=t.substring(re,j):re=pe,re!==r?(Dt=L,K=_o(re),L=K):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===qi?(K=qi,j+=2):(K=r,ct===0&&Ct(gu)),K!==r?(re=j,pe=j,Je=si(),Je!==r?(mt=si(),mt!==r?(fr=si(),fr!==r?(Cr=si(),Cr!==r?(yn=si(),yn!==r?(oi=si(),oi!==r?(Oi=si(),Oi!==r?(Bg=si(),Bg!==r?(Je=[Je,mt,fr,Cr,yn,oi,Oi,Bg],pe=Je):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r),pe!==r?re=t.substring(re,j):re=pe,re!==r?(Dt=L,K=xA(re),L=K):(j=L,L=r)):(j=L,L=r)))),L}function ja(){var L;return Ha.test(t.charAt(j))?(L=t.charAt(j),j++):(L=r,ct===0&&Ct(mc)),L}function si(){var L;return hs.test(t.charAt(j))?(L=t.charAt(j),j++):(L=r,ct===0&&Ct(Ht)),L}function pa(){var L,K,re,pe,Je;if(L=j,K=[],re=j,t.charCodeAt(j)===92?(pe=Li,j++):(pe=r,ct===0&&Ct(Mn)),pe!==r?(t.length>j?(Je=t.charAt(j),j++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(j=re,re=r)):(j=re,re=r),re===r&&(re=j,t.substr(j,2)===Ci?(pe=Ci,j+=2):(pe=r,ct===0&&Ct(oa)),pe!==r&&(Dt=re,pe=co()),re=pe,re===r&&(re=j,pe=j,ct++,Je=Rm(),ct--,Je===r?pe=void 0:(j=pe,pe=r),pe!==r?(t.length>j?(Je=t.charAt(j),j++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(j=re,re=r)):(j=re,re=r))),re!==r)for(;re!==r;)K.push(re),re=j,t.charCodeAt(j)===92?(pe=Li,j++):(pe=r,ct===0&&Ct(Mn)),pe!==r?(t.length>j?(Je=t.charAt(j),j++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(j=re,re=r)):(j=re,re=r),re===r&&(re=j,t.substr(j,2)===Ci?(pe=Ci,j+=2):(pe=r,ct===0&&Ct(oa)),pe!==r&&(Dt=re,pe=co()),re=pe,re===r&&(re=j,pe=j,ct++,Je=Rm(),ct--,Je===r?pe=void 0:(j=pe,pe=r),pe!==r?(t.length>j?(Je=t.charAt(j),j++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(j=re,re=r)):(j=re,re=r)));else K=r;return K!==r&&(Dt=L,K=Ms(K)),L=K,L}function Dc(){var L,K,re,pe,Je,mt;if(L=j,t.charCodeAt(j)===45?(K=Us,j++):(K=r,ct===0&&Ct(aa)),K===r&&(t.charCodeAt(j)===43?(K=la,j++):(K=r,ct===0&&Ct(Ho))),K===r&&(K=null),K!==r){if(re=[],Ve.test(t.charAt(j))?(pe=t.charAt(j),j++):(pe=r,ct===0&&Ct(qe)),pe!==r)for(;pe!==r;)re.push(pe),Ve.test(t.charAt(j))?(pe=t.charAt(j),j++):(pe=r,ct===0&&Ct(qe));else re=r;if(re!==r)if(t.charCodeAt(j)===46?(pe=wi,j++):(pe=r,ct===0&&Ct(gs)),pe!==r){if(Je=[],Ve.test(t.charAt(j))?(mt=t.charAt(j),j++):(mt=r,ct===0&&Ct(qe)),mt!==r)for(;mt!==r;)Je.push(mt),Ve.test(t.charAt(j))?(mt=t.charAt(j),j++):(mt=r,ct===0&&Ct(qe));else Je=r;Je!==r?(Dt=L,K=ds(K,re,Je),L=K):(j=L,L=r)}else j=L,L=r;else j=L,L=r}else j=L,L=r;if(L===r){if(L=j,t.charCodeAt(j)===45?(K=Us,j++):(K=r,ct===0&&Ct(aa)),K===r&&(t.charCodeAt(j)===43?(K=la,j++):(K=r,ct===0&&Ct(Ho))),K===r&&(K=null),K!==r){if(re=[],Ve.test(t.charAt(j))?(pe=t.charAt(j),j++):(pe=r,ct===0&&Ct(qe)),pe!==r)for(;pe!==r;)re.push(pe),Ve.test(t.charAt(j))?(pe=t.charAt(j),j++):(pe=r,ct===0&&Ct(qe));else re=r;re!==r?(Dt=L,K=ms(K,re),L=K):(j=L,L=r)}else j=L,L=r;if(L===r&&(L=j,K=Pc(),K!==r&&(Dt=L,K=_s(K)),L=K,L===r&&(L=j,K=Ya(),K!==r&&(Dt=L,K=Un(K)),L=K,L===r)))if(L=j,t.charCodeAt(j)===40?(K=Pe,j++):(K=r,ct===0&&Ct(ce)),K!==r){for(re=[],pe=Qt();pe!==r;)re.push(pe),pe=Qt();if(re!==r)if(pe=ts(),pe!==r){for(Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();Je!==r?(t.charCodeAt(j)===41?(mt=ne,j++):(mt=r,ct===0&&Ct(ee)),mt!==r?(Dt=L,K=Pn(pe),L=K):(j=L,L=r)):(j=L,L=r)}else j=L,L=r;else j=L,L=r}else j=L,L=r}return L}function vl(){var L,K,re,pe,Je,mt,fr,Cr;if(L=j,K=Dc(),K!==r){for(re=[],pe=j,Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();if(Je!==r)if(t.charCodeAt(j)===42?(mt=ys,j++):(mt=r,ct===0&&Ct(We)),mt===r&&(t.charCodeAt(j)===47?(mt=tt,j++):(mt=r,ct===0&&Ct(It))),mt!==r){for(fr=[],Cr=Qt();Cr!==r;)fr.push(Cr),Cr=Qt();fr!==r?(Cr=Dc(),Cr!==r?(Dt=pe,Je=ir(K,mt,Cr),pe=Je):(j=pe,pe=r)):(j=pe,pe=r)}else j=pe,pe=r;else j=pe,pe=r;for(;pe!==r;){for(re.push(pe),pe=j,Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();if(Je!==r)if(t.charCodeAt(j)===42?(mt=ys,j++):(mt=r,ct===0&&Ct(We)),mt===r&&(t.charCodeAt(j)===47?(mt=tt,j++):(mt=r,ct===0&&Ct(It))),mt!==r){for(fr=[],Cr=Qt();Cr!==r;)fr.push(Cr),Cr=Qt();fr!==r?(Cr=Dc(),Cr!==r?(Dt=pe,Je=ir(K,mt,Cr),pe=Je):(j=pe,pe=r)):(j=pe,pe=r)}else j=pe,pe=r;else j=pe,pe=r}re!==r?(Dt=L,K=$(K,re),L=K):(j=L,L=r)}else j=L,L=r;return L}function ts(){var L,K,re,pe,Je,mt,fr,Cr;if(L=j,K=vl(),K!==r){for(re=[],pe=j,Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();if(Je!==r)if(t.charCodeAt(j)===43?(mt=la,j++):(mt=r,ct===0&&Ct(Ho)),mt===r&&(t.charCodeAt(j)===45?(mt=Us,j++):(mt=r,ct===0&&Ct(aa))),mt!==r){for(fr=[],Cr=Qt();Cr!==r;)fr.push(Cr),Cr=Qt();fr!==r?(Cr=vl(),Cr!==r?(Dt=pe,Je=ye(K,mt,Cr),pe=Je):(j=pe,pe=r)):(j=pe,pe=r)}else j=pe,pe=r;else j=pe,pe=r;for(;pe!==r;){for(re.push(pe),pe=j,Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();if(Je!==r)if(t.charCodeAt(j)===43?(mt=la,j++):(mt=r,ct===0&&Ct(Ho)),mt===r&&(t.charCodeAt(j)===45?(mt=Us,j++):(mt=r,ct===0&&Ct(aa))),mt!==r){for(fr=[],Cr=Qt();Cr!==r;)fr.push(Cr),Cr=Qt();fr!==r?(Cr=vl(),Cr!==r?(Dt=pe,Je=ye(K,mt,Cr),pe=Je):(j=pe,pe=r)):(j=pe,pe=r)}else j=pe,pe=r;else j=pe,pe=r}re!==r?(Dt=L,K=$(K,re),L=K):(j=L,L=r)}else j=L,L=r;return L}function jr(){var L,K,re,pe,Je,mt;if(L=j,t.substr(j,3)===Ne?(K=Ne,j+=3):(K=r,ct===0&&Ct(pt)),K!==r){for(re=[],pe=Qt();pe!==r;)re.push(pe),pe=Qt();if(re!==r)if(pe=ts(),pe!==r){for(Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();Je!==r?(t.substr(j,2)===ht?(mt=ht,j+=2):(mt=r,ct===0&&Ct(Tt)),mt!==r?(Dt=L,K=er(pe),L=K):(j=L,L=r)):(j=L,L=r)}else j=L,L=r;else j=L,L=r}else j=L,L=r;return L}function Cp(){var L,K,re,pe;return L=j,t.substr(j,2)===$r?(K=$r,j+=2):(K=r,ct===0&&Ct(Gi)),K!==r?(re=wu(),re!==r?(t.charCodeAt(j)===41?(pe=ne,j++):(pe=r,ct===0&&Ct(ee)),pe!==r?(Dt=L,K=es(re),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L}function Pc(){var L,K,re,pe,Je,mt;return L=j,t.substr(j,2)===bi?(K=bi,j+=2):(K=r,ct===0&&Ct(qo)),K!==r?(re=Ya(),re!==r?(t.substr(j,2)===kA?(pe=kA,j+=2):(pe=r,ct===0&&Ct(QA)),pe!==r?(Je=LA(),Je!==r?(t.charCodeAt(j)===125?(mt=H,j++):(mt=r,ct===0&&Ct(at)),mt!==r?(Dt=L,K=fp(re,Je),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===bi?(K=bi,j+=2):(K=r,ct===0&&Ct(qo)),K!==r?(re=Ya(),re!==r?(t.substr(j,3)===sg?(pe=sg,j+=3):(pe=r,ct===0&&Ct(du)),pe!==r?(Dt=L,K=og(re),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===bi?(K=bi,j+=2):(K=r,ct===0&&Ct(qo)),K!==r?(re=Ya(),re!==r?(t.substr(j,2)===mu?(pe=mu,j+=2):(pe=r,ct===0&&Ct(uo)),pe!==r?(Je=LA(),Je!==r?(t.charCodeAt(j)===125?(mt=H,j++):(mt=r,ct===0&&Ct(at)),mt!==r?(Dt=L,K=FA(re,Je),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===bi?(K=bi,j+=2):(K=r,ct===0&&Ct(qo)),K!==r?(re=Ya(),re!==r?(t.substr(j,3)===yc?(pe=yc,j+=3):(pe=r,ct===0&&Ct(ca)),pe!==r?(Dt=L,K=ag(re),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===bi?(K=bi,j+=2):(K=r,ct===0&&Ct(qo)),K!==r?(re=Ya(),re!==r?(t.charCodeAt(j)===125?(pe=H,j++):(pe=r,ct===0&&Ct(at)),pe!==r?(Dt=L,K=Ec(re),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.charCodeAt(j)===36?(K=Sm,j++):(K=r,ct===0&&Ct(lg)),K!==r?(re=Ya(),re!==r?(Dt=L,K=Ec(re),L=K):(j=L,L=r)):(j=L,L=r)))))),L}function Cw(){var L,K,re;return L=j,K=Cg(),K!==r?(Dt=j,re=ei(K),re?re=void 0:re=r,re!==r?(Dt=L,K=pp(K),L=K):(j=L,L=r)):(j=L,L=r),L}function Cg(){var L,K,re,pe,Je;if(L=j,K=[],re=j,pe=j,ct++,Je=Ig(),ct--,Je===r?pe=void 0:(j=pe,pe=r),pe!==r?(t.length>j?(Je=t.charAt(j),j++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(j=re,re=r)):(j=re,re=r),re!==r)for(;re!==r;)K.push(re),re=j,pe=j,ct++,Je=Ig(),ct--,Je===r?pe=void 0:(j=pe,pe=r),pe!==r?(t.length>j?(Je=t.charAt(j),j++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(j=re,re=r)):(j=re,re=r);else K=r;return K!==r&&(Dt=L,K=Ms(K)),L=K,L}function wg(){var L,K,re;if(L=j,K=[],cg.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(RA)),re!==r)for(;re!==r;)K.push(re),cg.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(RA));else K=r;return K!==r&&(Dt=L,K=Hs()),L=K,L}function Ya(){var L,K,re;if(L=j,K=[],yu.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(qa)),re!==r)for(;re!==r;)K.push(re),yu.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(qa));else K=r;return K!==r&&(Dt=L,K=Hs()),L=K,L}function Rm(){var L;return ji.test(t.charAt(j))?(L=t.charAt(j),j++):(L=r,ct===0&&Ct(ua)),L}function Ig(){var L;return Eu.test(t.charAt(j))?(L=t.charAt(j),j++):(L=r,ct===0&&Ct(Es)),L}function Qt(){var L,K;if(L=[],Cc.test(t.charAt(j))?(K=t.charAt(j),j++):(K=r,ct===0&&Ct(wc)),K!==r)for(;K!==r;)L.push(K),Cc.test(t.charAt(j))?(K=t.charAt(j),j++):(K=r,ct===0&&Ct(wc));else L=r;return L}if(Cu=a(),Cu!==r&&j===t.length)return Cu;throw Cu!==r&&j<t.length&&Ct(fg()),hg(Ic,xi<t.length?t.charAt(xi):null,xi<t.length?Bc(xi,xi+1):Bc(xi,xi))}XY.exports={SyntaxError:Yg,parse:A8e}});function LD(t,e={isGlobPattern:()=>!1}){try{return(0,$Y.parse)(t,e)}catch(r){throw r.location&&(r.message=r.message.replace(/(\.)?$/,` (line ${r.location.start.line}, column ${r.location.start.column})$1`)),r}}function cy(t,{endSemicolon:e=!1}={}){return t.map(({command:r,type:o},a)=>`${ND(r)}${o===";"?a!==t.length-1||e?";":"":" &"}`).join(" ")}function ND(t){return`${uy(t.chain)}${t.then?` ${oT(t.then)}`:""}`}function oT(t){return`${t.type} ${ND(t.line)}`}function uy(t){return`${lT(t)}${t.then?` ${aT(t.then)}`:""}`}function aT(t){return`${t.type} ${uy(t.chain)}`}function lT(t){switch(t.type){case"command":return`${t.envs.length>0?`${t.envs.map(e=>TD(e)).join(" ")} `:""}${t.args.map(e=>cT(e)).join(" ")}`;case"subshell":return`(${cy(t.subshell)})${t.args.length>0?` ${t.args.map(e=>Vw(e)).join(" ")}`:""}`;case"group":return`{ ${cy(t.group,{endSemicolon:!0})} }${t.args.length>0?` ${t.args.map(e=>Vw(e)).join(" ")}`:""}`;case"envs":return t.envs.map(e=>TD(e)).join(" ");default:throw new Error(`Unsupported command type: "${t.type}"`)}}function TD(t){return`${t.name}=${t.args[0]?Wg(t.args[0]):""}`}function cT(t){switch(t.type){case"redirection":return Vw(t);case"argument":return Wg(t);default:throw new Error(`Unsupported argument type: "${t.type}"`)}}function Vw(t){return`${t.subtype} ${t.args.map(e=>Wg(e)).join(" ")}`}function Wg(t){return t.segments.map(e=>uT(e)).join("")}function uT(t){let e=(o,a)=>a?`"${o}"`:o,r=o=>o===""?"''":o.match(/[()}<>$|&;"'\n\t ]/)?o.match(/['\t\p{C}]/u)?o.match(/'/)?`"${o.replace(/["$\t\p{C}]/u,p8e)}"`:`$'${o.replace(/[\t\p{C}]/u,tW)}'`:`'${o}'`:o;switch(t.type){case"text":return r(t.text);case"glob":return t.pattern;case"shell":return e(`$(${cy(t.shell)})`,t.quoted);case"variable":return e(typeof t.defaultValue>"u"?typeof t.alternativeValue>"u"?`\${${t.name}}`:t.alternativeValue.length===0?`\${${t.name}:+}`:`\${${t.name}:+${t.alternativeValue.map(o=>Wg(o)).join(" ")}}`:t.defaultValue.length===0?`\${${t.name}:-}`:`\${${t.name}:-${t.defaultValue.map(o=>Wg(o)).join(" ")}}`,t.quoted);case"arithmetic":return`$(( ${OD(t.arithmetic)} ))`;default:throw new Error(`Unsupported argument segment type: "${t.type}"`)}}function OD(t){let e=a=>{switch(a){case"addition":return"+";case"subtraction":return"-";case"multiplication":return"*";case"division":return"/";default:throw new Error(`Can't extract operator from arithmetic expression of type "${a}"`)}},r=(a,n)=>n?`( ${a} )`:a,o=a=>r(OD(a),!["number","variable"].includes(a.type));switch(t.type){case"number":return String(t.value);case"variable":return t.name;default:return`${o(t.left)} ${e(t.type)} ${o(t.right)}`}}var $Y,eW,f8e,tW,p8e,rW=Et(()=>{$Y=$e(ZY());eW=new Map([["\f","\\f"],[`
-`,"\\n"],["\r","\\r"],[" ","\\t"],["\v","\\v"],["\0","\\0"]]),f8e=new Map([["\\","\\\\"],["$","\\$"],['"','\\"'],...Array.from(eW,([t,e])=>[t,`"$'${e}'"`])]),tW=t=>eW.get(t)??`\\x${t.charCodeAt(0).toString(16).padStart(2,"0")}`,p8e=t=>f8e.get(t)??`"$'${tW(t)}'"`});var iW=_((Lbt,nW)=>{"use strict";function h8e(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Kg(t,e,r,o){this.message=t,this.expected=e,this.found=r,this.location=o,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,Kg)}h8e(Kg,Error);Kg.buildMessage=function(t,e){var r={literal:function(h){return'"'+a(h.text)+'"'},class:function(h){var E="",I;for(I=0;I<h.parts.length;I++)E+=h.parts[I]instanceof Array?n(h.parts[I][0])+"-"+n(h.parts[I][1]):n(h.parts[I]);return"["+(h.inverted?"^":"")+E+"]"},any:function(h){return"any character"},end:function(h){return"end of input"},other:function(h){return h.description}};function o(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(E){return"\\x0"+o(E)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(E){return"\\x"+o(E)})}function n(h){return h.replace(/\\/g,"\\\\").replace(/\]/g,"\\]").replace(/\^/g,"\\^").replace(/-/g,"\\-").replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(E){return"\\x0"+o(E)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(E){return"\\x"+o(E)})}function u(h){return r[h.type](h)}function A(h){var E=new Array(h.length),I,v;for(I=0;I<h.length;I++)E[I]=u(h[I]);if(E.sort(),E.length>0){for(I=1,v=1;I<E.length;I++)E[I-1]!==E[I]&&(E[v]=E[I],v++);E.length=v}switch(E.length){case 1:return E[0];case 2:return E[0]+" or "+E[1];default:return E.slice(0,-1).join(", ")+", or "+E[E.length-1]}}function p(h){return h?'"'+a(h)+'"':"end of input"}return"Expected "+A(t)+" but "+p(e)+" found."};function g8e(t,e){e=e!==void 0?e:{};var r={},o={resolution:ke},a=ke,n="/",u=Pe("/",!1),A=function(qe,b){return{from:qe,descriptor:b}},p=function(qe){return{descriptor:qe}},h="@",E=Pe("@",!1),I=function(qe,b){return{fullName:qe,description:b}},v=function(qe){return{fullName:qe}},x=function(){return Be()},C=/^[^\/@]/,R=ce(["/","@"],!0,!1),N=/^[^\/]/,U=ce(["/"],!0,!1),V=0,te=0,ae=[{line:1,column:1}],fe=0,ue=[],me=0,he;if("startRule"in e){if(!(e.startRule in o))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');a=o[e.startRule]}function Be(){return t.substring(te,V)}function we(){return At(te,V)}function g(qe,b){throw b=b!==void 0?b:At(te,V),Re([Ie(qe)],t.substring(te,V),b)}function Ee(qe,b){throw b=b!==void 0?b:At(te,V),at(qe,b)}function Pe(qe,b){return{type:"literal",text:qe,ignoreCase:b}}function ce(qe,b,w){return{type:"class",parts:qe,inverted:b,ignoreCase:w}}function ne(){return{type:"any"}}function ee(){return{type:"end"}}function Ie(qe){return{type:"other",description:qe}}function Fe(qe){var b=ae[qe],w;if(b)return b;for(w=qe-1;!ae[w];)w--;for(b=ae[w],b={line:b.line,column:b.column};w<qe;)t.charCodeAt(w)===10?(b.line++,b.column=1):b.column++,w++;return ae[qe]=b,b}function At(qe,b){var w=Fe(qe),S=Fe(b);return{start:{offset:qe,line:w.line,column:w.column},end:{offset:b,line:S.line,column:S.column}}}function H(qe){V<fe||(V>fe&&(fe=V,ue=[]),ue.push(qe))}function at(qe,b){return new Kg(qe,null,null,b)}function Re(qe,b,w){return new Kg(Kg.buildMessage(qe,b),qe,b,w)}function ke(){var qe,b,w,S;return qe=V,b=xe(),b!==r?(t.charCodeAt(V)===47?(w=n,V++):(w=r,me===0&&H(u)),w!==r?(S=xe(),S!==r?(te=qe,b=A(b,S),qe=b):(V=qe,qe=r)):(V=qe,qe=r)):(V=qe,qe=r),qe===r&&(qe=V,b=xe(),b!==r&&(te=qe,b=p(b)),qe=b),qe}function xe(){var qe,b,w,S;return qe=V,b=He(),b!==r?(t.charCodeAt(V)===64?(w=h,V++):(w=r,me===0&&H(E)),w!==r?(S=Ve(),S!==r?(te=qe,b=I(b,S),qe=b):(V=qe,qe=r)):(V=qe,qe=r)):(V=qe,qe=r),qe===r&&(qe=V,b=He(),b!==r&&(te=qe,b=v(b)),qe=b),qe}function He(){var qe,b,w,S,y;return qe=V,t.charCodeAt(V)===64?(b=h,V++):(b=r,me===0&&H(E)),b!==r?(w=Te(),w!==r?(t.charCodeAt(V)===47?(S=n,V++):(S=r,me===0&&H(u)),S!==r?(y=Te(),y!==r?(te=qe,b=x(),qe=b):(V=qe,qe=r)):(V=qe,qe=r)):(V=qe,qe=r)):(V=qe,qe=r),qe===r&&(qe=V,b=Te(),b!==r&&(te=qe,b=x()),qe=b),qe}function Te(){var qe,b,w;if(qe=V,b=[],C.test(t.charAt(V))?(w=t.charAt(V),V++):(w=r,me===0&&H(R)),w!==r)for(;w!==r;)b.push(w),C.test(t.charAt(V))?(w=t.charAt(V),V++):(w=r,me===0&&H(R));else b=r;return b!==r&&(te=qe,b=x()),qe=b,qe}function Ve(){var qe,b,w;if(qe=V,b=[],N.test(t.charAt(V))?(w=t.charAt(V),V++):(w=r,me===0&&H(U)),w!==r)for(;w!==r;)b.push(w),N.test(t.charAt(V))?(w=t.charAt(V),V++):(w=r,me===0&&H(U));else b=r;return b!==r&&(te=qe,b=x()),qe=b,qe}if(he=a(),he!==r&&V===t.length)return he;throw he!==r&&V<t.length&&H(ee()),Re(ue,fe<t.length?t.charAt(fe):null,fe<t.length?At(fe,fe+1):At(fe,fe))}nW.exports={SyntaxError:Kg,parse:g8e}});function MD(t){let e=t.match(/^\*{1,2}\/(.*)/);if(e)throw new Error(`The override for '${t}' includes a glob pattern. Glob patterns have been removed since their behaviours don't match what you'd expect. Set the override to '${e[1]}' instead.`);try{return(0,sW.parse)(t)}catch(r){throw r.location&&(r.message=r.message.replace(/(\.)?$/,` (line ${r.location.start.line}, column ${r.location.start.column})$1`)),r}}function UD(t){let e="";return t.from&&(e+=t.from.fullName,t.from.description&&(e+=`@${t.from.description}`),e+="/"),e+=t.descriptor.fullName,t.descriptor.description&&(e+=`@${t.descriptor.description}`),e}var sW,oW=Et(()=>{sW=$e(iW())});var Vg=_((Obt,zg)=>{"use strict";function aW(t){return typeof t>"u"||t===null}function d8e(t){return typeof t=="object"&&t!==null}function m8e(t){return Array.isArray(t)?t:aW(t)?[]:[t]}function y8e(t,e){var r,o,a,n;if(e)for(n=Object.keys(e),r=0,o=n.length;r<o;r+=1)a=n[r],t[a]=e[a];return t}function E8e(t,e){var r="",o;for(o=0;o<e;o+=1)r+=t;return r}function C8e(t){return t===0&&Number.NEGATIVE_INFINITY===1/t}zg.exports.isNothing=aW;zg.exports.isObject=d8e;zg.exports.toArray=m8e;zg.exports.repeat=E8e;zg.exports.isNegativeZero=C8e;zg.exports.extend=y8e});var Ay=_((Mbt,lW)=>{"use strict";function Jw(t,e){Error.call(this),this.name="YAMLException",this.reason=t,this.mark=e,this.message=(this.reason||"(unknown reason)")+(this.mark?" "+this.mark.toString():""),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=new Error().stack||""}Jw.prototype=Object.create(Error.prototype);Jw.prototype.constructor=Jw;Jw.prototype.toString=function(e){var r=this.name+": ";return r+=this.reason||"(unknown reason)",!e&&this.mark&&(r+=" "+this.mark.toString()),r};lW.exports=Jw});var AW=_((Ubt,uW)=>{"use strict";var cW=Vg();function AT(t,e,r,o,a){this.name=t,this.buffer=e,this.position=r,this.line=o,this.column=a}AT.prototype.getSnippet=function(e,r){var o,a,n,u,A;if(!this.buffer)return null;for(e=e||4,r=r||75,o="",a=this.position;a>0&&`\0\r
-\x85\u2028\u2029`.indexOf(this.buffer.charAt(a-1))===-1;)if(a-=1,this.position-a>r/2-1){o=" ... ",a+=5;break}for(n="",u=this.position;u<this.buffer.length&&`\0\r
-\x85\u2028\u2029`.indexOf(this.buffer.charAt(u))===-1;)if(u+=1,u-this.position>r/2-1){n=" ... ",u-=5;break}return A=this.buffer.slice(a,u),cW.repeat(" ",e)+o+A+n+`
-`+cW.repeat(" ",e+this.position-a+o.length)+"^"};AT.prototype.toString=function(e){var r,o="";return this.name&&(o+='in "'+this.name+'" '),o+="at line "+(this.line+1)+", column "+(this.column+1),e||(r=this.getSnippet(),r&&(o+=`:
-`+r)),o};uW.exports=AT});var os=_((_bt,pW)=>{"use strict";var fW=Ay(),w8e=["kind","resolve","construct","instanceOf","predicate","represent","defaultStyle","styleAliases"],I8e=["scalar","sequence","mapping"];function B8e(t){var e={};return t!==null&&Object.keys(t).forEach(function(r){t[r].forEach(function(o){e[String(o)]=r})}),e}function v8e(t,e){if(e=e||{},Object.keys(e).forEach(function(r){if(w8e.indexOf(r)===-1)throw new fW('Unknown option "'+r+'" is met in definition of "'+t+'" YAML type.')}),this.tag=t,this.kind=e.kind||null,this.resolve=e.resolve||function(){return!0},this.construct=e.construct||function(r){return r},this.instanceOf=e.instanceOf||null,this.predicate=e.predicate||null,this.represent=e.represent||null,this.defaultStyle=e.defaultStyle||null,this.styleAliases=B8e(e.styleAliases||null),I8e.indexOf(this.kind)===-1)throw new fW('Unknown kind "'+this.kind+'" is specified for "'+t+'" YAML type.')}pW.exports=v8e});var Jg=_((Hbt,gW)=>{"use strict";var hW=Vg(),_D=Ay(),D8e=os();function fT(t,e,r){var o=[];return t.include.forEach(function(a){r=fT(a,e,r)}),t[e].forEach(function(a){r.forEach(function(n,u){n.tag===a.tag&&n.kind===a.kind&&o.push(u)}),r.push(a)}),r.filter(function(a,n){return o.indexOf(n)===-1})}function P8e(){var t={scalar:{},sequence:{},mapping:{},fallback:{}},e,r;function o(a){t[a.kind][a.tag]=t.fallback[a.tag]=a}for(e=0,r=arguments.length;e<r;e+=1)arguments[e].forEach(o);return t}function fy(t){this.include=t.include||[],this.implicit=t.implicit||[],this.explicit=t.explicit||[],this.implicit.forEach(function(e){if(e.loadKind&&e.loadKind!=="scalar")throw new _D("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.")}),this.compiledImplicit=fT(this,"implicit",[]),this.compiledExplicit=fT(this,"explicit",[]),this.compiledTypeMap=P8e(this.compiledImplicit,this.compiledExplicit)}fy.DEFAULT=null;fy.create=function(){var e,r;switch(arguments.length){case 1:e=fy.DEFAULT,r=arguments[0];break;case 2:e=arguments[0],r=arguments[1];break;default:throw new _D("Wrong number of arguments for Schema.create function")}if(e=hW.toArray(e),r=hW.toArray(r),!e.every(function(o){return o instanceof fy}))throw new _D("Specified list of super schemas (or a single Schema object) contains a non-Schema object.");if(!r.every(function(o){return o instanceof D8e}))throw new _D("Specified list of YAML types (or a single Type object) contains a non-Type object.");return new fy({include:e,explicit:r})};gW.exports=fy});var mW=_((qbt,dW)=>{"use strict";var S8e=os();dW.exports=new S8e("tag:yaml.org,2002:str",{kind:"scalar",construct:function(t){return t!==null?t:""}})});var EW=_((Gbt,yW)=>{"use strict";var b8e=os();yW.exports=new b8e("tag:yaml.org,2002:seq",{kind:"sequence",construct:function(t){return t!==null?t:[]}})});var wW=_((jbt,CW)=>{"use strict";var x8e=os();CW.exports=new x8e("tag:yaml.org,2002:map",{kind:"mapping",construct:function(t){return t!==null?t:{}}})});var HD=_((Ybt,IW)=>{"use strict";var k8e=Jg();IW.exports=new k8e({explicit:[mW(),EW(),wW()]})});var vW=_((Wbt,BW)=>{"use strict";var Q8e=os();function F8e(t){if(t===null)return!0;var e=t.length;return e===1&&t==="~"||e===4&&(t==="null"||t==="Null"||t==="NULL")}function R8e(){return null}function T8e(t){return t===null}BW.exports=new Q8e("tag:yaml.org,2002:null",{kind:"scalar",resolve:F8e,construct:R8e,predicate:T8e,represent:{canonical:function(){return"~"},lowercase:function(){return"null"},uppercase:function(){return"NULL"},camelcase:function(){return"Null"}},defaultStyle:"lowercase"})});var PW=_((Kbt,DW)=>{"use strict";var L8e=os();function N8e(t){if(t===null)return!1;var e=t.length;return e===4&&(t==="true"||t==="True"||t==="TRUE")||e===5&&(t==="false"||t==="False"||t==="FALSE")}function O8e(t){return t==="true"||t==="True"||t==="TRUE"}function M8e(t){return Object.prototype.toString.call(t)==="[object Boolean]"}DW.exports=new L8e("tag:yaml.org,2002:bool",{kind:"scalar",resolve:N8e,construct:O8e,predicate:M8e,represent:{lowercase:function(t){return t?"true":"false"},uppercase:function(t){return t?"TRUE":"FALSE"},camelcase:function(t){return t?"True":"False"}},defaultStyle:"lowercase"})});var bW=_((zbt,SW)=>{"use strict";var U8e=Vg(),_8e=os();function H8e(t){return 48<=t&&t<=57||65<=t&&t<=70||97<=t&&t<=102}function q8e(t){return 48<=t&&t<=55}function G8e(t){return 48<=t&&t<=57}function j8e(t){if(t===null)return!1;var e=t.length,r=0,o=!1,a;if(!e)return!1;if(a=t[r],(a==="-"||a==="+")&&(a=t[++r]),a==="0"){if(r+1===e)return!0;if(a=t[++r],a==="b"){for(r++;r<e;r++)if(a=t[r],a!=="_"){if(a!=="0"&&a!=="1")return!1;o=!0}return o&&a!=="_"}if(a==="x"){for(r++;r<e;r++)if(a=t[r],a!=="_"){if(!H8e(t.charCodeAt(r)))return!1;o=!0}return o&&a!=="_"}for(;r<e;r++)if(a=t[r],a!=="_"){if(!q8e(t.charCodeAt(r)))return!1;o=!0}return o&&a!=="_"}if(a==="_")return!1;for(;r<e;r++)if(a=t[r],a!=="_"){if(a===":")break;if(!G8e(t.charCodeAt(r)))return!1;o=!0}return!o||a==="_"?!1:a!==":"?!0:/^(:[0-5]?[0-9])+$/.test(t.slice(r))}function Y8e(t){var e=t,r=1,o,a,n=[];return e.indexOf("_")!==-1&&(e=e.replace(/_/g,"")),o=e[0],(o==="-"||o==="+")&&(o==="-"&&(r=-1),e=e.slice(1),o=e[0]),e==="0"?0:o==="0"?e[1]==="b"?r*parseInt(e.slice(2),2):e[1]==="x"?r*parseInt(e,16):r*parseInt(e,8):e.indexOf(":")!==-1?(e.split(":").forEach(function(u){n.unshift(parseInt(u,10))}),e=0,a=1,n.forEach(function(u){e+=u*a,a*=60}),r*e):r*parseInt(e,10)}function W8e(t){return Object.prototype.toString.call(t)==="[object Number]"&&t%1===0&&!U8e.isNegativeZero(t)}SW.exports=new _8e("tag:yaml.org,2002:int",{kind:"scalar",resolve:j8e,construct:Y8e,predicate:W8e,represent:{binary:function(t){return t>=0?"0b"+t.toString(2):"-0b"+t.toString(2).slice(1)},octal:function(t){return t>=0?"0"+t.toString(8):"-0"+t.toString(8).slice(1)},decimal:function(t){return t.toString(10)},hexadecimal:function(t){return t>=0?"0x"+t.toString(16).toUpperCase():"-0x"+t.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}})});var QW=_((Vbt,kW)=>{"use strict";var xW=Vg(),K8e=os(),z8e=new RegExp("^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");function V8e(t){return!(t===null||!z8e.test(t)||t[t.length-1]==="_")}function J8e(t){var e,r,o,a;return e=t.replace(/_/g,"").toLowerCase(),r=e[0]==="-"?-1:1,a=[],"+-".indexOf(e[0])>=0&&(e=e.slice(1)),e===".inf"?r===1?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:e===".nan"?NaN:e.indexOf(":")>=0?(e.split(":").forEach(function(n){a.unshift(parseFloat(n,10))}),e=0,o=1,a.forEach(function(n){e+=n*o,o*=60}),r*e):r*parseFloat(e,10)}var X8e=/^[-+]?[0-9]+e/;function Z8e(t,e){var r;if(isNaN(t))switch(e){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===t)switch(e){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===t)switch(e){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(xW.isNegativeZero(t))return"-0.0";return r=t.toString(10),X8e.test(r)?r.replace("e",".e"):r}function $8e(t){return Object.prototype.toString.call(t)==="[object Number]"&&(t%1!==0||xW.isNegativeZero(t))}kW.exports=new K8e("tag:yaml.org,2002:float",{kind:"scalar",resolve:V8e,construct:J8e,predicate:$8e,represent:Z8e,defaultStyle:"lowercase"})});var pT=_((Jbt,FW)=>{"use strict";var eHe=Jg();FW.exports=new eHe({include:[HD()],implicit:[vW(),PW(),bW(),QW()]})});var hT=_((Xbt,RW)=>{"use strict";var tHe=Jg();RW.exports=new tHe({include:[pT()]})});var OW=_((Zbt,NW)=>{"use strict";var rHe=os(),TW=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),LW=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");function nHe(t){return t===null?!1:TW.exec(t)!==null||LW.exec(t)!==null}function iHe(t){var e,r,o,a,n,u,A,p=0,h=null,E,I,v;if(e=TW.exec(t),e===null&&(e=LW.exec(t)),e===null)throw new Error("Date resolve error");if(r=+e[1],o=+e[2]-1,a=+e[3],!e[4])return new Date(Date.UTC(r,o,a));if(n=+e[4],u=+e[5],A=+e[6],e[7]){for(p=e[7].slice(0,3);p.length<3;)p+="0";p=+p}return e[9]&&(E=+e[10],I=+(e[11]||0),h=(E*60+I)*6e4,e[9]==="-"&&(h=-h)),v=new Date(Date.UTC(r,o,a,n,u,A,p)),h&&v.setTime(v.getTime()-h),v}function sHe(t){return t.toISOString()}NW.exports=new rHe("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:nHe,construct:iHe,instanceOf:Date,represent:sHe})});var UW=_(($bt,MW)=>{"use strict";var oHe=os();function aHe(t){return t==="<<"||t===null}MW.exports=new oHe("tag:yaml.org,2002:merge",{kind:"scalar",resolve:aHe})});var qW=_((ext,HW)=>{"use strict";var Xg;try{_W=ve,Xg=_W("buffer").Buffer}catch{}var _W,lHe=os(),gT=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
-\r`;function cHe(t){if(t===null)return!1;var e,r,o=0,a=t.length,n=gT;for(r=0;r<a;r++)if(e=n.indexOf(t.charAt(r)),!(e>64)){if(e<0)return!1;o+=6}return o%8===0}function uHe(t){var e,r,o=t.replace(/[\r\n=]/g,""),a=o.length,n=gT,u=0,A=[];for(e=0;e<a;e++)e%4===0&&e&&(A.push(u>>16&255),A.push(u>>8&255),A.push(u&255)),u=u<<6|n.indexOf(o.charAt(e));return r=a%4*6,r===0?(A.push(u>>16&255),A.push(u>>8&255),A.push(u&255)):r===18?(A.push(u>>10&255),A.push(u>>2&255)):r===12&&A.push(u>>4&255),Xg?Xg.from?Xg.from(A):new Xg(A):A}function AHe(t){var e="",r=0,o,a,n=t.length,u=gT;for(o=0;o<n;o++)o%3===0&&o&&(e+=u[r>>18&63],e+=u[r>>12&63],e+=u[r>>6&63],e+=u[r&63]),r=(r<<8)+t[o];return a=n%3,a===0?(e+=u[r>>18&63],e+=u[r>>12&63],e+=u[r>>6&63],e+=u[r&63]):a===2?(e+=u[r>>10&63],e+=u[r>>4&63],e+=u[r<<2&63],e+=u[64]):a===1&&(e+=u[r>>2&63],e+=u[r<<4&63],e+=u[64],e+=u[64]),e}function fHe(t){return Xg&&Xg.isBuffer(t)}HW.exports=new lHe("tag:yaml.org,2002:binary",{kind:"scalar",resolve:cHe,construct:uHe,predicate:fHe,represent:AHe})});var jW=_((rxt,GW)=>{"use strict";var pHe=os(),hHe=Object.prototype.hasOwnProperty,gHe=Object.prototype.toString;function dHe(t){if(t===null)return!0;var e=[],r,o,a,n,u,A=t;for(r=0,o=A.length;r<o;r+=1){if(a=A[r],u=!1,gHe.call(a)!=="[object Object]")return!1;for(n in a)if(hHe.call(a,n))if(!u)u=!0;else return!1;if(!u)return!1;if(e.indexOf(n)===-1)e.push(n);else return!1}return!0}function mHe(t){return t!==null?t:[]}GW.exports=new pHe("tag:yaml.org,2002:omap",{kind:"sequence",resolve:dHe,construct:mHe})});var WW=_((nxt,YW)=>{"use strict";var yHe=os(),EHe=Object.prototype.toString;function CHe(t){if(t===null)return!0;var e,r,o,a,n,u=t;for(n=new Array(u.length),e=0,r=u.length;e<r;e+=1){if(o=u[e],EHe.call(o)!=="[object Object]"||(a=Object.keys(o),a.length!==1))return!1;n[e]=[a[0],o[a[0]]]}return!0}function wHe(t){if(t===null)return[];var e,r,o,a,n,u=t;for(n=new Array(u.length),e=0,r=u.length;e<r;e+=1)o=u[e],a=Object.keys(o),n[e]=[a[0],o[a[0]]];return n}YW.exports=new yHe("tag:yaml.org,2002:pairs",{kind:"sequence",resolve:CHe,construct:wHe})});var zW=_((ixt,KW)=>{"use strict";var IHe=os(),BHe=Object.prototype.hasOwnProperty;function vHe(t){if(t===null)return!0;var e,r=t;for(e in r)if(BHe.call(r,e)&&r[e]!==null)return!1;return!0}function DHe(t){return t!==null?t:{}}KW.exports=new IHe("tag:yaml.org,2002:set",{kind:"mapping",resolve:vHe,construct:DHe})});var py=_((sxt,VW)=>{"use strict";var PHe=Jg();VW.exports=new PHe({include:[hT()],implicit:[OW(),UW()],explicit:[qW(),jW(),WW(),zW()]})});var XW=_((oxt,JW)=>{"use strict";var SHe=os();function bHe(){return!0}function xHe(){}function kHe(){return""}function QHe(t){return typeof t>"u"}JW.exports=new SHe("tag:yaml.org,2002:js/undefined",{kind:"scalar",resolve:bHe,construct:xHe,predicate:QHe,represent:kHe})});var $W=_((axt,ZW)=>{"use strict";var FHe=os();function RHe(t){if(t===null||t.length===0)return!1;var e=t,r=/\/([gim]*)$/.exec(t),o="";return!(e[0]==="/"&&(r&&(o=r[1]),o.length>3||e[e.length-o.length-1]!=="/"))}function THe(t){var e=t,r=/\/([gim]*)$/.exec(t),o="";return e[0]==="/"&&(r&&(o=r[1]),e=e.slice(1,e.length-o.length-1)),new RegExp(e,o)}function LHe(t){var e="/"+t.source+"/";return t.global&&(e+="g"),t.multiline&&(e+="m"),t.ignoreCase&&(e+="i"),e}function NHe(t){return Object.prototype.toString.call(t)==="[object RegExp]"}ZW.exports=new FHe("tag:yaml.org,2002:js/regexp",{kind:"scalar",resolve:RHe,construct:THe,predicate:NHe,represent:LHe})});var rK=_((lxt,tK)=>{"use strict";var qD;try{eK=ve,qD=eK("esprima")}catch{typeof window<"u"&&(qD=window.esprima)}var eK,OHe=os();function MHe(t){if(t===null)return!1;try{var e="("+t+")",r=qD.parse(e,{range:!0});return!(r.type!=="Program"||r.body.length!==1||r.body[0].type!=="ExpressionStatement"||r.body[0].expression.type!=="ArrowFunctionExpression"&&r.body[0].expression.type!=="FunctionExpression")}catch{return!1}}function UHe(t){var e="("+t+")",r=qD.parse(e,{range:!0}),o=[],a;if(r.type!=="Program"||r.body.length!==1||r.body[0].type!=="ExpressionStatement"||r.body[0].expression.type!=="ArrowFunctionExpression"&&r.body[0].expression.type!=="FunctionExpression")throw new Error("Failed to resolve function");return r.body[0].expression.params.forEach(function(n){o.push(n.name)}),a=r.body[0].expression.body.range,r.body[0].expression.body.type==="BlockStatement"?new Function(o,e.slice(a[0]+1,a[1]-1)):new Function(o,"return "+e.slice(a[0],a[1]))}function _He(t){return t.toString()}function HHe(t){return Object.prototype.toString.call(t)==="[object Function]"}tK.exports=new OHe("tag:yaml.org,2002:js/function",{kind:"scalar",resolve:MHe,construct:UHe,predicate:HHe,represent:_He})});var Xw=_((uxt,iK)=>{"use strict";var nK=Jg();iK.exports=nK.DEFAULT=new nK({include:[py()],explicit:[XW(),$W(),rK()]})});var BK=_((Axt,Zw)=>{"use strict";var yf=Vg(),AK=Ay(),qHe=AW(),fK=py(),GHe=Xw(),Wp=Object.prototype.hasOwnProperty,GD=1,pK=2,hK=3,jD=4,dT=1,jHe=2,sK=3,YHe=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,WHe=/[\x85\u2028\u2029]/,KHe=/[,\[\]\{\}]/,gK=/^(?:!|!!|![a-z\-]+!)$/i,dK=/^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i;function oK(t){return Object.prototype.toString.call(t)}function qu(t){return t===10||t===13}function $g(t){return t===9||t===32}function Ia(t){return t===9||t===32||t===10||t===13}function hy(t){return t===44||t===91||t===93||t===123||t===125}function zHe(t){var e;return 48<=t&&t<=57?t-48:(e=t|32,97<=e&&e<=102?e-97+10:-1)}function VHe(t){return t===120?2:t===117?4:t===85?8:0}function JHe(t){return 48<=t&&t<=57?t-48:-1}function aK(t){return t===48?"\0":t===97?"\x07":t===98?"\b":t===116||t===9?" ":t===110?`
-`:t===118?"\v":t===102?"\f":t===114?"\r":t===101?"\x1B":t===32?" ":t===34?'"':t===47?"/":t===92?"\\":t===78?"\x85":t===95?"\xA0":t===76?"\u2028":t===80?"\u2029":""}function XHe(t){return t<=65535?String.fromCharCode(t):String.fromCharCode((t-65536>>10)+55296,(t-65536&1023)+56320)}var mK=new Array(256),yK=new Array(256);for(Zg=0;Zg<256;Zg++)mK[Zg]=aK(Zg)?1:0,yK[Zg]=aK(Zg);var Zg;function ZHe(t,e){this.input=t,this.filename=e.filename||null,this.schema=e.schema||GHe,this.onWarning=e.onWarning||null,this.legacy=e.legacy||!1,this.json=e.json||!1,this.listener=e.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=t.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function EK(t,e){return new AK(e,new qHe(t.filename,t.input,t.position,t.line,t.position-t.lineStart))}function Sr(t,e){throw EK(t,e)}function YD(t,e){t.onWarning&&t.onWarning.call(null,EK(t,e))}var lK={YAML:function(e,r,o){var a,n,u;e.version!==null&&Sr(e,"duplication of %YAML directive"),o.length!==1&&Sr(e,"YAML directive accepts exactly one argument"),a=/^([0-9]+)\.([0-9]+)$/.exec(o[0]),a===null&&Sr(e,"ill-formed argument of the YAML directive"),n=parseInt(a[1],10),u=parseInt(a[2],10),n!==1&&Sr(e,"unacceptable YAML version of the document"),e.version=o[0],e.checkLineBreaks=u<2,u!==1&&u!==2&&YD(e,"unsupported YAML version of the document")},TAG:function(e,r,o){var a,n;o.length!==2&&Sr(e,"TAG directive accepts exactly two arguments"),a=o[0],n=o[1],gK.test(a)||Sr(e,"ill-formed tag handle (first argument) of the TAG directive"),Wp.call(e.tagMap,a)&&Sr(e,'there is a previously declared suffix for "'+a+'" tag handle'),dK.test(n)||Sr(e,"ill-formed tag prefix (second argument) of the TAG directive"),e.tagMap[a]=n}};function Yp(t,e,r,o){var a,n,u,A;if(e<r){if(A=t.input.slice(e,r),o)for(a=0,n=A.length;a<n;a+=1)u=A.charCodeAt(a),u===9||32<=u&&u<=1114111||Sr(t,"expected valid JSON character");else YHe.test(A)&&Sr(t,"the stream contains non-printable characters");t.result+=A}}function cK(t,e,r,o){var a,n,u,A;for(yf.isObject(r)||Sr(t,"cannot merge mappings; the provided source object is unacceptable"),a=Object.keys(r),u=0,A=a.length;u<A;u+=1)n=a[u],Wp.call(e,n)||(e[n]=r[n],o[n]=!0)}function gy(t,e,r,o,a,n,u,A){var p,h;if(Array.isArray(a))for(a=Array.prototype.slice.call(a),p=0,h=a.length;p<h;p+=1)Array.isArray(a[p])&&Sr(t,"nested arrays are not supported inside keys"),typeof a=="object"&&oK(a[p])==="[object Object]"&&(a[p]="[object Object]");if(typeof a=="object"&&oK(a)==="[object Object]"&&(a="[object Object]"),a=String(a),e===null&&(e={}),o==="tag:yaml.org,2002:merge")if(Array.isArray(n))for(p=0,h=n.length;p<h;p+=1)cK(t,e,n[p],r);else cK(t,e,n,r);else!t.json&&!Wp.call(r,a)&&Wp.call(e,a)&&(t.line=u||t.line,t.position=A||t.position,Sr(t,"duplicated mapping key")),e[a]=n,delete r[a];return e}function mT(t){var e;e=t.input.charCodeAt(t.position),e===10?t.position++:e===13?(t.position++,t.input.charCodeAt(t.position)===10&&t.position++):Sr(t,"a line break is expected"),t.line+=1,t.lineStart=t.position}function Wi(t,e,r){for(var o=0,a=t.input.charCodeAt(t.position);a!==0;){for(;$g(a);)a=t.input.charCodeAt(++t.position);if(e&&a===35)do a=t.input.charCodeAt(++t.position);while(a!==10&&a!==13&&a!==0);if(qu(a))for(mT(t),a=t.input.charCodeAt(t.position),o++,t.lineIndent=0;a===32;)t.lineIndent++,a=t.input.charCodeAt(++t.position);else break}return r!==-1&&o!==0&&t.lineIndent<r&&YD(t,"deficient indentation"),o}function WD(t){var e=t.position,r;return r=t.input.charCodeAt(e),!!((r===45||r===46)&&r===t.input.charCodeAt(e+1)&&r===t.input.charCodeAt(e+2)&&(e+=3,r=t.input.charCodeAt(e),r===0||Ia(r)))}function yT(t,e){e===1?t.result+=" ":e>1&&(t.result+=yf.repeat(`
-`,e-1))}function $He(t,e,r){var o,a,n,u,A,p,h,E,I=t.kind,v=t.result,x;if(x=t.input.charCodeAt(t.position),Ia(x)||hy(x)||x===35||x===38||x===42||x===33||x===124||x===62||x===39||x===34||x===37||x===64||x===96||(x===63||x===45)&&(a=t.input.charCodeAt(t.position+1),Ia(a)||r&&hy(a)))return!1;for(t.kind="scalar",t.result="",n=u=t.position,A=!1;x!==0;){if(x===58){if(a=t.input.charCodeAt(t.position+1),Ia(a)||r&&hy(a))break}else if(x===35){if(o=t.input.charCodeAt(t.position-1),Ia(o))break}else{if(t.position===t.lineStart&&WD(t)||r&&hy(x))break;if(qu(x))if(p=t.line,h=t.lineStart,E=t.lineIndent,Wi(t,!1,-1),t.lineIndent>=e){A=!0,x=t.input.charCodeAt(t.position);continue}else{t.position=u,t.line=p,t.lineStart=h,t.lineIndent=E;break}}A&&(Yp(t,n,u,!1),yT(t,t.line-p),n=u=t.position,A=!1),$g(x)||(u=t.position+1),x=t.input.charCodeAt(++t.position)}return Yp(t,n,u,!1),t.result?!0:(t.kind=I,t.result=v,!1)}function e6e(t,e){var r,o,a;if(r=t.input.charCodeAt(t.position),r!==39)return!1;for(t.kind="scalar",t.result="",t.position++,o=a=t.position;(r=t.input.charCodeAt(t.position))!==0;)if(r===39)if(Yp(t,o,t.position,!0),r=t.input.charCodeAt(++t.position),r===39)o=t.position,t.position++,a=t.position;else return!0;else qu(r)?(Yp(t,o,a,!0),yT(t,Wi(t,!1,e)),o=a=t.position):t.position===t.lineStart&&WD(t)?Sr(t,"unexpected end of the document within a single quoted scalar"):(t.position++,a=t.position);Sr(t,"unexpected end of the stream within a single quoted scalar")}function t6e(t,e){var r,o,a,n,u,A;if(A=t.input.charCodeAt(t.position),A!==34)return!1;for(t.kind="scalar",t.result="",t.position++,r=o=t.position;(A=t.input.charCodeAt(t.position))!==0;){if(A===34)return Yp(t,r,t.position,!0),t.position++,!0;if(A===92){if(Yp(t,r,t.position,!0),A=t.input.charCodeAt(++t.position),qu(A))Wi(t,!1,e);else if(A<256&&mK[A])t.result+=yK[A],t.position++;else if((u=VHe(A))>0){for(a=u,n=0;a>0;a--)A=t.input.charCodeAt(++t.position),(u=zHe(A))>=0?n=(n<<4)+u:Sr(t,"expected hexadecimal character");t.result+=XHe(n),t.position++}else Sr(t,"unknown escape sequence");r=o=t.position}else qu(A)?(Yp(t,r,o,!0),yT(t,Wi(t,!1,e)),r=o=t.position):t.position===t.lineStart&&WD(t)?Sr(t,"unexpected end of the document within a double quoted scalar"):(t.position++,o=t.position)}Sr(t,"unexpected end of the stream within a double quoted scalar")}function r6e(t,e){var r=!0,o,a=t.tag,n,u=t.anchor,A,p,h,E,I,v={},x,C,R,N;if(N=t.input.charCodeAt(t.position),N===91)p=93,I=!1,n=[];else if(N===123)p=125,I=!0,n={};else return!1;for(t.anchor!==null&&(t.anchorMap[t.anchor]=n),N=t.input.charCodeAt(++t.position);N!==0;){if(Wi(t,!0,e),N=t.input.charCodeAt(t.position),N===p)return t.position++,t.tag=a,t.anchor=u,t.kind=I?"mapping":"sequence",t.result=n,!0;r||Sr(t,"missed comma between flow collection entries"),C=x=R=null,h=E=!1,N===63&&(A=t.input.charCodeAt(t.position+1),Ia(A)&&(h=E=!0,t.position++,Wi(t,!0,e))),o=t.line,dy(t,e,GD,!1,!0),C=t.tag,x=t.result,Wi(t,!0,e),N=t.input.charCodeAt(t.position),(E||t.line===o)&&N===58&&(h=!0,N=t.input.charCodeAt(++t.position),Wi(t,!0,e),dy(t,e,GD,!1,!0),R=t.result),I?gy(t,n,v,C,x,R):h?n.push(gy(t,null,v,C,x,R)):n.push(x),Wi(t,!0,e),N=t.input.charCodeAt(t.position),N===44?(r=!0,N=t.input.charCodeAt(++t.position)):r=!1}Sr(t,"unexpected end of the stream within a flow collection")}function n6e(t,e){var r,o,a=dT,n=!1,u=!1,A=e,p=0,h=!1,E,I;if(I=t.input.charCodeAt(t.position),I===124)o=!1;else if(I===62)o=!0;else return!1;for(t.kind="scalar",t.result="";I!==0;)if(I=t.input.charCodeAt(++t.position),I===43||I===45)dT===a?a=I===43?sK:jHe:Sr(t,"repeat of a chomping mode identifier");else if((E=JHe(I))>=0)E===0?Sr(t,"bad explicit indentation width of a block scalar; it cannot be less than one"):u?Sr(t,"repeat of an indentation width identifier"):(A=e+E-1,u=!0);else break;if($g(I)){do I=t.input.charCodeAt(++t.position);while($g(I));if(I===35)do I=t.input.charCodeAt(++t.position);while(!qu(I)&&I!==0)}for(;I!==0;){for(mT(t),t.lineIndent=0,I=t.input.charCodeAt(t.position);(!u||t.lineIndent<A)&&I===32;)t.lineIndent++,I=t.input.charCodeAt(++t.position);if(!u&&t.lineIndent>A&&(A=t.lineIndent),qu(I)){p++;continue}if(t.lineIndent<A){a===sK?t.result+=yf.repeat(`
-`,n?1+p:p):a===dT&&n&&(t.result+=`
-`);break}for(o?$g(I)?(h=!0,t.result+=yf.repeat(`
-`,n?1+p:p)):h?(h=!1,t.result+=yf.repeat(`
-`,p+1)):p===0?n&&(t.result+=" "):t.result+=yf.repeat(`
-`,p):t.result+=yf.repeat(`
-`,n?1+p:p),n=!0,u=!0,p=0,r=t.position;!qu(I)&&I!==0;)I=t.input.charCodeAt(++t.position);Yp(t,r,t.position,!1)}return!0}function uK(t,e){var r,o=t.tag,a=t.anchor,n=[],u,A=!1,p;for(t.anchor!==null&&(t.anchorMap[t.anchor]=n),p=t.input.charCodeAt(t.position);p!==0&&!(p!==45||(u=t.input.charCodeAt(t.position+1),!Ia(u)));){if(A=!0,t.position++,Wi(t,!0,-1)&&t.lineIndent<=e){n.push(null),p=t.input.charCodeAt(t.position);continue}if(r=t.line,dy(t,e,hK,!1,!0),n.push(t.result),Wi(t,!0,-1),p=t.input.charCodeAt(t.position),(t.line===r||t.lineIndent>e)&&p!==0)Sr(t,"bad indentation of a sequence entry");else if(t.lineIndent<e)break}return A?(t.tag=o,t.anchor=a,t.kind="sequence",t.result=n,!0):!1}function i6e(t,e,r){var o,a,n,u,A=t.tag,p=t.anchor,h={},E={},I=null,v=null,x=null,C=!1,R=!1,N;for(t.anchor!==null&&(t.anchorMap[t.anchor]=h),N=t.input.charCodeAt(t.position);N!==0;){if(o=t.input.charCodeAt(t.position+1),n=t.line,u=t.position,(N===63||N===58)&&Ia(o))N===63?(C&&(gy(t,h,E,I,v,null),I=v=x=null),R=!0,C=!0,a=!0):C?(C=!1,a=!0):Sr(t,"incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line"),t.position+=1,N=o;else if(dy(t,r,pK,!1,!0))if(t.line===n){for(N=t.input.charCodeAt(t.position);$g(N);)N=t.input.charCodeAt(++t.position);if(N===58)N=t.input.charCodeAt(++t.position),Ia(N)||Sr(t,"a whitespace character is expected after the key-value separator within a block mapping"),C&&(gy(t,h,E,I,v,null),I=v=x=null),R=!0,C=!1,a=!1,I=t.tag,v=t.result;else if(R)Sr(t,"can not read an implicit mapping pair; a colon is missed");else return t.tag=A,t.anchor=p,!0}else if(R)Sr(t,"can not read a block mapping entry; a multiline key may not be an implicit key");else return t.tag=A,t.anchor=p,!0;else break;if((t.line===n||t.lineIndent>e)&&(dy(t,e,jD,!0,a)&&(C?v=t.result:x=t.result),C||(gy(t,h,E,I,v,x,n,u),I=v=x=null),Wi(t,!0,-1),N=t.input.charCodeAt(t.position)),t.lineIndent>e&&N!==0)Sr(t,"bad indentation of a mapping entry");else if(t.lineIndent<e)break}return C&&gy(t,h,E,I,v,null),R&&(t.tag=A,t.anchor=p,t.kind="mapping",t.result=h),R}function s6e(t){var e,r=!1,o=!1,a,n,u;if(u=t.input.charCodeAt(t.position),u!==33)return!1;if(t.tag!==null&&Sr(t,"duplication of a tag property"),u=t.input.charCodeAt(++t.position),u===60?(r=!0,u=t.input.charCodeAt(++t.position)):u===33?(o=!0,a="!!",u=t.input.charCodeAt(++t.position)):a="!",e=t.position,r){do u=t.input.charCodeAt(++t.position);while(u!==0&&u!==62);t.position<t.length?(n=t.input.slice(e,t.position),u=t.input.charCodeAt(++t.position)):Sr(t,"unexpected end of the stream within a verbatim tag")}else{for(;u!==0&&!Ia(u);)u===33&&(o?Sr(t,"tag suffix cannot contain exclamation marks"):(a=t.input.slice(e-1,t.position+1),gK.test(a)||Sr(t,"named tag handle cannot contain such characters"),o=!0,e=t.position+1)),u=t.input.charCodeAt(++t.position);n=t.input.slice(e,t.position),KHe.test(n)&&Sr(t,"tag suffix cannot contain flow indicator characters")}return n&&!dK.test(n)&&Sr(t,"tag name cannot contain such characters: "+n),r?t.tag=n:Wp.call(t.tagMap,a)?t.tag=t.tagMap[a]+n:a==="!"?t.tag="!"+n:a==="!!"?t.tag="tag:yaml.org,2002:"+n:Sr(t,'undeclared tag handle "'+a+'"'),!0}function o6e(t){var e,r;if(r=t.input.charCodeAt(t.position),r!==38)return!1;for(t.anchor!==null&&Sr(t,"duplication of an anchor property"),r=t.input.charCodeAt(++t.position),e=t.position;r!==0&&!Ia(r)&&!hy(r);)r=t.input.charCodeAt(++t.position);return t.position===e&&Sr(t,"name of an anchor node must contain at least one character"),t.anchor=t.input.slice(e,t.position),!0}function a6e(t){var e,r,o;if(o=t.input.charCodeAt(t.position),o!==42)return!1;for(o=t.input.charCodeAt(++t.position),e=t.position;o!==0&&!Ia(o)&&!hy(o);)o=t.input.charCodeAt(++t.position);return t.position===e&&Sr(t,"name of an alias node must contain at least one character"),r=t.input.slice(e,t.position),Wp.call(t.anchorMap,r)||Sr(t,'unidentified alias "'+r+'"'),t.result=t.anchorMap[r],Wi(t,!0,-1),!0}function dy(t,e,r,o,a){var n,u,A,p=1,h=!1,E=!1,I,v,x,C,R;if(t.listener!==null&&t.listener("open",t),t.tag=null,t.anchor=null,t.kind=null,t.result=null,n=u=A=jD===r||hK===r,o&&Wi(t,!0,-1)&&(h=!0,t.lineIndent>e?p=1:t.lineIndent===e?p=0:t.lineIndent<e&&(p=-1)),p===1)for(;s6e(t)||o6e(t);)Wi(t,!0,-1)?(h=!0,A=n,t.lineIndent>e?p=1:t.lineIndent===e?p=0:t.lineIndent<e&&(p=-1)):A=!1;if(A&&(A=h||a),(p===1||jD===r)&&(GD===r||pK===r?C=e:C=e+1,R=t.position-t.lineStart,p===1?A&&(uK(t,R)||i6e(t,R,C))||r6e(t,C)?E=!0:(u&&n6e(t,C)||e6e(t,C)||t6e(t,C)?E=!0:a6e(t)?(E=!0,(t.tag!==null||t.anchor!==null)&&Sr(t,"alias node should not have any properties")):$He(t,C,GD===r)&&(E=!0,t.tag===null&&(t.tag="?")),t.anchor!==null&&(t.anchorMap[t.anchor]=t.result)):p===0&&(E=A&&uK(t,R))),t.tag!==null&&t.tag!=="!")if(t.tag==="?"){for(t.result!==null&&t.kind!=="scalar"&&Sr(t,'unacceptable node kind for !<?> tag; it should be "scalar", not "'+t.kind+'"'),I=0,v=t.implicitTypes.length;I<v;I+=1)if(x=t.implicitTypes[I],x.resolve(t.result)){t.result=x.construct(t.result),t.tag=x.tag,t.anchor!==null&&(t.anchorMap[t.anchor]=t.result);break}}else Wp.call(t.typeMap[t.kind||"fallback"],t.tag)?(x=t.typeMap[t.kind||"fallback"][t.tag],t.result!==null&&x.kind!==t.kind&&Sr(t,"unacceptable node kind for !<"+t.tag+'> tag; it should be "'+x.kind+'", not "'+t.kind+'"'),x.resolve(t.result)?(t.result=x.construct(t.result),t.anchor!==null&&(t.anchorMap[t.anchor]=t.result)):Sr(t,"cannot resolve a node with !<"+t.tag+"> explicit tag")):Sr(t,"unknown tag !<"+t.tag+">");return t.listener!==null&&t.listener("close",t),t.tag!==null||t.anchor!==null||E}function l6e(t){var e=t.position,r,o,a,n=!1,u;for(t.version=null,t.checkLineBreaks=t.legacy,t.tagMap={},t.anchorMap={};(u=t.input.charCodeAt(t.position))!==0&&(Wi(t,!0,-1),u=t.input.charCodeAt(t.position),!(t.lineIndent>0||u!==37));){for(n=!0,u=t.input.charCodeAt(++t.position),r=t.position;u!==0&&!Ia(u);)u=t.input.charCodeAt(++t.position);for(o=t.input.slice(r,t.position),a=[],o.length<1&&Sr(t,"directive name must not be less than one character in length");u!==0;){for(;$g(u);)u=t.input.charCodeAt(++t.position);if(u===35){do u=t.input.charCodeAt(++t.position);while(u!==0&&!qu(u));break}if(qu(u))break;for(r=t.position;u!==0&&!Ia(u);)u=t.input.charCodeAt(++t.position);a.push(t.input.slice(r,t.position))}u!==0&&mT(t),Wp.call(lK,o)?lK[o](t,o,a):YD(t,'unknown document directive "'+o+'"')}if(Wi(t,!0,-1),t.lineIndent===0&&t.input.charCodeAt(t.position)===45&&t.input.charCodeAt(t.position+1)===45&&t.input.charCodeAt(t.position+2)===45?(t.position+=3,Wi(t,!0,-1)):n&&Sr(t,"directives end mark is expected"),dy(t,t.lineIndent-1,jD,!1,!0),Wi(t,!0,-1),t.checkLineBreaks&&WHe.test(t.input.slice(e,t.position))&&YD(t,"non-ASCII line breaks are interpreted as content"),t.documents.push(t.result),t.position===t.lineStart&&WD(t)){t.input.charCodeAt(t.position)===46&&(t.position+=3,Wi(t,!0,-1));return}if(t.position<t.length-1)Sr(t,"end of the stream or a document separator is expected");else return}function CK(t,e){t=String(t),e=e||{},t.length!==0&&(t.charCodeAt(t.length-1)!==10&&t.charCodeAt(t.length-1)!==13&&(t+=`
-`),t.charCodeAt(0)===65279&&(t=t.slice(1)));var r=new ZHe(t,e),o=t.indexOf("\0");for(o!==-1&&(r.position=o,Sr(r,"null byte is not allowed in input")),r.input+="\0";r.input.charCodeAt(r.position)===32;)r.lineIndent+=1,r.position+=1;for(;r.position<r.length-1;)l6e(r);return r.documents}function wK(t,e,r){e!==null&&typeof e=="object"&&typeof r>"u"&&(r=e,e=null);var o=CK(t,r);if(typeof e!="function")return o;for(var a=0,n=o.length;a<n;a+=1)e(o[a])}function IK(t,e){var r=CK(t,e);if(r.length!==0){if(r.length===1)return r[0];throw new AK("expected a single document in the stream, but found more")}}function c6e(t,e,r){return typeof e=="object"&&e!==null&&typeof r>"u"&&(r=e,e=null),wK(t,e,yf.extend({schema:fK},r))}function u6e(t,e){return IK(t,yf.extend({schema:fK},e))}Zw.exports.loadAll=wK;Zw.exports.load=IK;Zw.exports.safeLoadAll=c6e;Zw.exports.safeLoad=u6e});var WK=_((fxt,IT)=>{"use strict";var eI=Vg(),tI=Ay(),A6e=Xw(),f6e=py(),QK=Object.prototype.toString,FK=Object.prototype.hasOwnProperty,p6e=9,$w=10,h6e=13,g6e=32,d6e=33,m6e=34,RK=35,y6e=37,E6e=38,C6e=39,w6e=42,TK=44,I6e=45,LK=58,B6e=61,v6e=62,D6e=63,P6e=64,NK=91,OK=93,S6e=96,MK=123,b6e=124,UK=125,vo={};vo[0]="\\0";vo[7]="\\a";vo[8]="\\b";vo[9]="\\t";vo[10]="\\n";vo[11]="\\v";vo[12]="\\f";vo[13]="\\r";vo[27]="\\e";vo[34]='\\"';vo[92]="\\\\";vo[133]="\\N";vo[160]="\\_";vo[8232]="\\L";vo[8233]="\\P";var x6e=["y","Y","yes","Yes","YES","on","On","ON","n","N","no","No","NO","off","Off","OFF"];function k6e(t,e){var r,o,a,n,u,A,p;if(e===null)return{};for(r={},o=Object.keys(e),a=0,n=o.length;a<n;a+=1)u=o[a],A=String(e[u]),u.slice(0,2)==="!!"&&(u="tag:yaml.org,2002:"+u.slice(2)),p=t.compiledTypeMap.fallback[u],p&&FK.call(p.styleAliases,A)&&(A=p.styleAliases[A]),r[u]=A;return r}function vK(t){var e,r,o;if(e=t.toString(16).toUpperCase(),t<=255)r="x",o=2;else if(t<=65535)r="u",o=4;else if(t<=4294967295)r="U",o=8;else throw new tI("code point within a string may not be greater than 0xFFFFFFFF");return"\\"+r+eI.repeat("0",o-e.length)+e}function Q6e(t){this.schema=t.schema||A6e,this.indent=Math.max(1,t.indent||2),this.noArrayIndent=t.noArrayIndent||!1,this.skipInvalid=t.skipInvalid||!1,this.flowLevel=eI.isNothing(t.flowLevel)?-1:t.flowLevel,this.styleMap=k6e(this.schema,t.styles||null),this.sortKeys=t.sortKeys||!1,this.lineWidth=t.lineWidth||80,this.noRefs=t.noRefs||!1,this.noCompatMode=t.noCompatMode||!1,this.condenseFlow=t.condenseFlow||!1,this.implicitTypes=this.schema.compiledImplicit,this.explicitTypes=this.schema.compiledExplicit,this.tag=null,this.result="",this.duplicates=[],this.usedDuplicates=null}function DK(t,e){for(var r=eI.repeat(" ",e),o=0,a=-1,n="",u,A=t.length;o<A;)a=t.indexOf(`
-`,o),a===-1?(u=t.slice(o),o=A):(u=t.slice(o,a+1),o=a+1),u.length&&u!==`
-`&&(n+=r),n+=u;return n}function ET(t,e){return`
-`+eI.repeat(" ",t.indent*e)}function F6e(t,e){var r,o,a;for(r=0,o=t.implicitTypes.length;r<o;r+=1)if(a=t.implicitTypes[r],a.resolve(e))return!0;return!1}function wT(t){return t===g6e||t===p6e}function my(t){return 32<=t&&t<=126||161<=t&&t<=55295&&t!==8232&&t!==8233||57344<=t&&t<=65533&&t!==65279||65536<=t&&t<=1114111}function R6e(t){return my(t)&&!wT(t)&&t!==65279&&t!==h6e&&t!==$w}function PK(t,e){return my(t)&&t!==65279&&t!==TK&&t!==NK&&t!==OK&&t!==MK&&t!==UK&&t!==LK&&(t!==RK||e&&R6e(e))}function T6e(t){return my(t)&&t!==65279&&!wT(t)&&t!==I6e&&t!==D6e&&t!==LK&&t!==TK&&t!==NK&&t!==OK&&t!==MK&&t!==UK&&t!==RK&&t!==E6e&&t!==w6e&&t!==d6e&&t!==b6e&&t!==B6e&&t!==v6e&&t!==C6e&&t!==m6e&&t!==y6e&&t!==P6e&&t!==S6e}function _K(t){var e=/^\n* /;return e.test(t)}var HK=1,qK=2,GK=3,jK=4,KD=5;function L6e(t,e,r,o,a){var n,u,A,p=!1,h=!1,E=o!==-1,I=-1,v=T6e(t.charCodeAt(0))&&!wT(t.charCodeAt(t.length-1));if(e)for(n=0;n<t.length;n++){if(u=t.charCodeAt(n),!my(u))return KD;A=n>0?t.charCodeAt(n-1):null,v=v&&PK(u,A)}else{for(n=0;n<t.length;n++){if(u=t.charCodeAt(n),u===$w)p=!0,E&&(h=h||n-I-1>o&&t[I+1]!==" ",I=n);else if(!my(u))return KD;A=n>0?t.charCodeAt(n-1):null,v=v&&PK(u,A)}h=h||E&&n-I-1>o&&t[I+1]!==" "}return!p&&!h?v&&!a(t)?HK:qK:r>9&&_K(t)?KD:h?jK:GK}function N6e(t,e,r,o){t.dump=function(){if(e.length===0)return"''";if(!t.noCompatMode&&x6e.indexOf(e)!==-1)return"'"+e+"'";var a=t.indent*Math.max(1,r),n=t.lineWidth===-1?-1:Math.max(Math.min(t.lineWidth,40),t.lineWidth-a),u=o||t.flowLevel>-1&&r>=t.flowLevel;function A(p){return F6e(t,p)}switch(L6e(e,u,t.indent,n,A)){case HK:return e;case qK:return"'"+e.replace(/'/g,"''")+"'";case GK:return"|"+SK(e,t.indent)+bK(DK(e,a));case jK:return">"+SK(e,t.indent)+bK(DK(O6e(e,n),a));case KD:return'"'+M6e(e,n)+'"';default:throw new tI("impossible error: invalid scalar style")}}()}function SK(t,e){var r=_K(t)?String(e):"",o=t[t.length-1]===`
-`,a=o&&(t[t.length-2]===`
-`||t===`
-`),n=a?"+":o?"":"-";return r+n+`
-`}function bK(t){return t[t.length-1]===`
-`?t.slice(0,-1):t}function O6e(t,e){for(var r=/(\n+)([^\n]*)/g,o=function(){var h=t.indexOf(`
-`);return h=h!==-1?h:t.length,r.lastIndex=h,xK(t.slice(0,h),e)}(),a=t[0]===`
-`||t[0]===" ",n,u;u=r.exec(t);){var A=u[1],p=u[2];n=p[0]===" ",o+=A+(!a&&!n&&p!==""?`
-`:"")+xK(p,e),a=n}return o}function xK(t,e){if(t===""||t[0]===" ")return t;for(var r=/ [^ ]/g,o,a=0,n,u=0,A=0,p="";o=r.exec(t);)A=o.index,A-a>e&&(n=u>a?u:A,p+=`
-`+t.slice(a,n),a=n+1),u=A;return p+=`
-`,t.length-a>e&&u>a?p+=t.slice(a,u)+`
-`+t.slice(u+1):p+=t.slice(a),p.slice(1)}function M6e(t){for(var e="",r,o,a,n=0;n<t.length;n++){if(r=t.charCodeAt(n),r>=55296&&r<=56319&&(o=t.charCodeAt(n+1),o>=56320&&o<=57343)){e+=vK((r-55296)*1024+o-56320+65536),n++;continue}a=vo[r],e+=!a&&my(r)?t[n]:a||vK(r)}return e}function U6e(t,e,r){var o="",a=t.tag,n,u;for(n=0,u=r.length;n<u;n+=1)ed(t,e,r[n],!1,!1)&&(n!==0&&(o+=","+(t.condenseFlow?"":" ")),o+=t.dump);t.tag=a,t.dump="["+o+"]"}function _6e(t,e,r,o){var a="",n=t.tag,u,A;for(u=0,A=r.length;u<A;u+=1)ed(t,e+1,r[u],!0,!0)&&((!o||u!==0)&&(a+=ET(t,e)),t.dump&&$w===t.dump.charCodeAt(0)?a+="-":a+="- ",a+=t.dump);t.tag=n,t.dump=a||"[]"}function H6e(t,e,r){var o="",a=t.tag,n=Object.keys(r),u,A,p,h,E;for(u=0,A=n.length;u<A;u+=1)E="",u!==0&&(E+=", "),t.condenseFlow&&(E+='"'),p=n[u],h=r[p],ed(t,e,p,!1,!1)&&(t.dump.length>1024&&(E+="? "),E+=t.dump+(t.condenseFlow?'"':"")+":"+(t.condenseFlow?"":" "),ed(t,e,h,!1,!1)&&(E+=t.dump,o+=E));t.tag=a,t.dump="{"+o+"}"}function q6e(t,e,r,o){var a="",n=t.tag,u=Object.keys(r),A,p,h,E,I,v;if(t.sortKeys===!0)u.sort();else if(typeof t.sortKeys=="function")u.sort(t.sortKeys);else if(t.sortKeys)throw new tI("sortKeys must be a boolean or a function");for(A=0,p=u.length;A<p;A+=1)v="",(!o||A!==0)&&(v+=ET(t,e)),h=u[A],E=r[h],ed(t,e+1,h,!0,!0,!0)&&(I=t.tag!==null&&t.tag!=="?"||t.dump&&t.dump.length>1024,I&&(t.dump&&$w===t.dump.charCodeAt(0)?v+="?":v+="? "),v+=t.dump,I&&(v+=ET(t,e)),ed(t,e+1,E,!0,I)&&(t.dump&&$w===t.dump.charCodeAt(0)?v+=":":v+=": ",v+=t.dump,a+=v));t.tag=n,t.dump=a||"{}"}function kK(t,e,r){var o,a,n,u,A,p;for(a=r?t.explicitTypes:t.implicitTypes,n=0,u=a.length;n<u;n+=1)if(A=a[n],(A.instanceOf||A.predicate)&&(!A.instanceOf||typeof e=="object"&&e instanceof A.instanceOf)&&(!A.predicate||A.predicate(e))){if(t.tag=r?A.tag:"?",A.represent){if(p=t.styleMap[A.tag]||A.defaultStyle,QK.call(A.represent)==="[object Function]")o=A.represent(e,p);else if(FK.call(A.represent,p))o=A.represent[p](e,p);else throw new tI("!<"+A.tag+'> tag resolver accepts not "'+p+'" style');t.dump=o}return!0}return!1}function ed(t,e,r,o,a,n){t.tag=null,t.dump=r,kK(t,r,!1)||kK(t,r,!0);var u=QK.call(t.dump);o&&(o=t.flowLevel<0||t.flowLevel>e);var A=u==="[object Object]"||u==="[object Array]",p,h;if(A&&(p=t.duplicates.indexOf(r),h=p!==-1),(t.tag!==null&&t.tag!=="?"||h||t.indent!==2&&e>0)&&(a=!1),h&&t.usedDuplicates[p])t.dump="*ref_"+p;else{if(A&&h&&!t.usedDuplicates[p]&&(t.usedDuplicates[p]=!0),u==="[object Object]")o&&Object.keys(t.dump).length!==0?(q6e(t,e,t.dump,a),h&&(t.dump="&ref_"+p+t.dump)):(H6e(t,e,t.dump),h&&(t.dump="&ref_"+p+" "+t.dump));else if(u==="[object Array]"){var E=t.noArrayIndent&&e>0?e-1:e;o&&t.dump.length!==0?(_6e(t,E,t.dump,a),h&&(t.dump="&ref_"+p+t.dump)):(U6e(t,E,t.dump),h&&(t.dump="&ref_"+p+" "+t.dump))}else if(u==="[object String]")t.tag!=="?"&&N6e(t,t.dump,e,n);else{if(t.skipInvalid)return!1;throw new tI("unacceptable kind of an object to dump "+u)}t.tag!==null&&t.tag!=="?"&&(t.dump="!<"+t.tag+"> "+t.dump)}return!0}function G6e(t,e){var r=[],o=[],a,n;for(CT(t,r,o),a=0,n=o.length;a<n;a+=1)e.duplicates.push(r[o[a]]);e.usedDuplicates=new Array(n)}function CT(t,e,r){var o,a,n;if(t!==null&&typeof t=="object")if(a=e.indexOf(t),a!==-1)r.indexOf(a)===-1&&r.push(a);else if(e.push(t),Array.isArray(t))for(a=0,n=t.length;a<n;a+=1)CT(t[a],e,r);else for(o=Object.keys(t),a=0,n=o.length;a<n;a+=1)CT(t[o[a]],e,r)}function YK(t,e){e=e||{};var r=new Q6e(e);return r.noRefs||G6e(t,r),ed(r,0,t,!0,!0)?r.dump+`
-`:""}function j6e(t,e){return YK(t,eI.extend({schema:f6e},e))}IT.exports.dump=YK;IT.exports.safeDump=j6e});var zK=_((pxt,ki)=>{"use strict";var zD=BK(),KK=WK();function VD(t){return function(){throw new Error("Function "+t+" is deprecated and cannot be used.")}}ki.exports.Type=os();ki.exports.Schema=Jg();ki.exports.FAILSAFE_SCHEMA=HD();ki.exports.JSON_SCHEMA=pT();ki.exports.CORE_SCHEMA=hT();ki.exports.DEFAULT_SAFE_SCHEMA=py();ki.exports.DEFAULT_FULL_SCHEMA=Xw();ki.exports.load=zD.load;ki.exports.loadAll=zD.loadAll;ki.exports.safeLoad=zD.safeLoad;ki.exports.safeLoadAll=zD.safeLoadAll;ki.exports.dump=KK.dump;ki.exports.safeDump=KK.safeDump;ki.exports.YAMLException=Ay();ki.exports.MINIMAL_SCHEMA=HD();ki.exports.SAFE_SCHEMA=py();ki.exports.DEFAULT_SCHEMA=Xw();ki.exports.scan=VD("scan");ki.exports.parse=VD("parse");ki.exports.compose=VD("compose");ki.exports.addConstructor=VD("addConstructor")});var JK=_((hxt,VK)=>{"use strict";var Y6e=zK();VK.exports=Y6e});var ZK=_((gxt,XK)=>{"use strict";function W6e(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function td(t,e,r,o){this.message=t,this.expected=e,this.found=r,this.location=o,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,td)}W6e(td,Error);td.buildMessage=function(t,e){var r={literal:function(h){return'"'+a(h.text)+'"'},class:function(h){var E="",I;for(I=0;I<h.parts.length;I++)E+=h.parts[I]instanceof Array?n(h.parts[I][0])+"-"+n(h.parts[I][1]):n(h.parts[I]);return"["+(h.inverted?"^":"")+E+"]"},any:function(h){return"any character"},end:function(h){return"end of input"},other:function(h){return h.description}};function o(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(E){return"\\x0"+o(E)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(E){return"\\x"+o(E)})}function n(h){return h.replace(/\\/g,"\\\\").replace(/\]/g,"\\]").replace(/\^/g,"\\^").replace(/-/g,"\\-").replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(E){return"\\x0"+o(E)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(E){return"\\x"+o(E)})}function u(h){return r[h.type](h)}function A(h){var E=new Array(h.length),I,v;for(I=0;I<h.length;I++)E[I]=u(h[I]);if(E.sort(),E.length>0){for(I=1,v=1;I<E.length;I++)E[I-1]!==E[I]&&(E[v]=E[I],v++);E.length=v}switch(E.length){case 1:return E[0];case 2:return E[0]+" or "+E[1];default:return E.slice(0,-1).join(", ")+", or "+E[E.length-1]}}function p(h){return h?'"'+a(h)+'"':"end of input"}return"Expected "+A(t)+" but "+p(e)+" found."};function K6e(t,e){e=e!==void 0?e:{};var r={},o={Start:hu},a=hu,n=function($){return[].concat(...$)},u="-",A=Qn("-",!1),p=function($){return $},h=function($){return Object.assign({},...$)},E="#",I=Qn("#",!1),v=gc(),x=function(){return{}},C=":",R=Qn(":",!1),N=function($,ye){return{[$]:ye}},U=",",V=Qn(",",!1),te=function($,ye){return ye},ae=function($,ye,Ne){return Object.assign({},...[$].concat(ye).map(pt=>({[pt]:Ne})))},fe=function($){return $},ue=function($){return $},me=sa("correct indentation"),he=" ",Be=Qn(" ",!1),we=function($){return $.length===ir*It},g=function($){return $.length===(ir+1)*It},Ee=function(){return ir++,!0},Pe=function(){return ir--,!0},ce=function(){return PA()},ne=sa("pseudostring"),ee=/^[^\r\n\t ?:,\][{}#&*!|>'"%@`\-]/,Ie=hi(["\r",`
-`," "," ","?",":",",","]","[","{","}","#","&","*","!","|",">","'",'"',"%","@","`","-"],!0,!1),Fe=/^[^\r\n\t ,\][{}:#"']/,At=hi(["\r",`
-`," "," ",",","]","[","{","}",":","#",'"',"'"],!0,!1),H=function(){return PA().replace(/^ *| *$/g,"")},at="--",Re=Qn("--",!1),ke=/^[a-zA-Z\/0-9]/,xe=hi([["a","z"],["A","Z"],"/",["0","9"]],!1,!1),He=/^[^\r\n\t :,]/,Te=hi(["\r",`
-`," "," ",":",","],!0,!1),Ve="null",qe=Qn("null",!1),b=function(){return null},w="true",S=Qn("true",!1),y=function(){return!0},F="false",J=Qn("false",!1),X=function(){return!1},Z=sa("string"),ie='"',be=Qn('"',!1),Le=function(){return""},ot=function($){return $},dt=function($){return $.join("")},Gt=/^[^"\\\0-\x1F\x7F]/,$t=hi(['"',"\\",["\0",""],"\x7F"],!0,!1),bt='\\"',an=Qn('\\"',!1),Qr=function(){return'"'},mr="\\\\",br=Qn("\\\\",!1),Wr=function(){return"\\"},Kn="\\/",Ls=Qn("\\/",!1),Ti=function(){return"/"},ps="\\b",io=Qn("\\b",!1),Si=function(){return"\b"},Ns="\\f",so=Qn("\\f",!1),uc=function(){return"\f"},uu="\\n",cp=Qn("\\n",!1),up=function(){return`
-`},Os="\\r",Dn=Qn("\\r",!1),oo=function(){return"\r"},Ms="\\t",yl=Qn("\\t",!1),El=function(){return" "},ao="\\u",zn=Qn("\\u",!1),On=function($,ye,Ne,pt){return String.fromCharCode(parseInt(`0x${$}${ye}${Ne}${pt}`))},Li=/^[0-9a-fA-F]/,Mn=hi([["0","9"],["a","f"],["A","F"]],!1,!1),_i=sa("blank space"),rr=/^[ \t]/,Oe=hi([" "," "],!1,!1),ii=sa("white space"),Ua=/^[ \t\n\r]/,hr=hi([" "," ",`
-`,"\r"],!1,!1),Ac=`\r
-`,Au=Qn(`\r
-`,!1),fc=`
-`,Cl=Qn(`
-`,!1),DA="\r",fu=Qn("\r",!1),Ce=0,Rt=0,pc=[{line:1,column:1}],Hi=0,pu=[],Yt=0,wl;if("startRule"in e){if(!(e.startRule in o))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');a=o[e.startRule]}function PA(){return t.substring(Rt,Ce)}function Ap(){return _o(Rt,Ce)}function hc($,ye){throw ye=ye!==void 0?ye:_o(Rt,Ce),dc([sa($)],t.substring(Rt,Ce),ye)}function SA($,ye){throw ye=ye!==void 0?ye:_o(Rt,Ce),lo($,ye)}function Qn($,ye){return{type:"literal",text:$,ignoreCase:ye}}function hi($,ye,Ne){return{type:"class",parts:$,inverted:ye,ignoreCase:Ne}}function gc(){return{type:"any"}}function bA(){return{type:"end"}}function sa($){return{type:"other",description:$}}function Ni($){var ye=pc[$],Ne;if(ye)return ye;for(Ne=$-1;!pc[Ne];)Ne--;for(ye=pc[Ne],ye={line:ye.line,column:ye.column};Ne<$;)t.charCodeAt(Ne)===10?(ye.line++,ye.column=1):ye.column++,Ne++;return pc[$]=ye,ye}function _o($,ye){var Ne=Ni($),pt=Ni(ye);return{start:{offset:$,line:Ne.line,column:Ne.column},end:{offset:ye,line:pt.line,column:pt.column}}}function Ze($){Ce<Hi||(Ce>Hi&&(Hi=Ce,pu=[]),pu.push($))}function lo($,ye){return new td($,null,null,ye)}function dc($,ye,Ne){return new td(td.buildMessage($,ye),$,ye,Ne)}function hu(){var $;return $=xA(),$}function qi(){var $,ye,Ne;for($=Ce,ye=[],Ne=gu();Ne!==r;)ye.push(Ne),Ne=gu();return ye!==r&&(Rt=$,ye=n(ye)),$=ye,$}function gu(){var $,ye,Ne,pt,ht;return $=Ce,ye=hs(),ye!==r?(t.charCodeAt(Ce)===45?(Ne=u,Ce++):(Ne=r,Yt===0&&Ze(A)),Ne!==r?(pt=Pn(),pt!==r?(ht=mc(),ht!==r?(Rt=$,ye=p(ht),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$}function xA(){var $,ye,Ne;for($=Ce,ye=[],Ne=Ha();Ne!==r;)ye.push(Ne),Ne=Ha();return ye!==r&&(Rt=$,ye=h(ye)),$=ye,$}function Ha(){var $,ye,Ne,pt,ht,Tt,er,$r,Gi;if($=Ce,ye=Pn(),ye===r&&(ye=null),ye!==r){if(Ne=Ce,t.charCodeAt(Ce)===35?(pt=E,Ce++):(pt=r,Yt===0&&Ze(I)),pt!==r){if(ht=[],Tt=Ce,er=Ce,Yt++,$r=tt(),Yt--,$r===r?er=void 0:(Ce=er,er=r),er!==r?(t.length>Ce?($r=t.charAt(Ce),Ce++):($r=r,Yt===0&&Ze(v)),$r!==r?(er=[er,$r],Tt=er):(Ce=Tt,Tt=r)):(Ce=Tt,Tt=r),Tt!==r)for(;Tt!==r;)ht.push(Tt),Tt=Ce,er=Ce,Yt++,$r=tt(),Yt--,$r===r?er=void 0:(Ce=er,er=r),er!==r?(t.length>Ce?($r=t.charAt(Ce),Ce++):($r=r,Yt===0&&Ze(v)),$r!==r?(er=[er,$r],Tt=er):(Ce=Tt,Tt=r)):(Ce=Tt,Tt=r);else ht=r;ht!==r?(pt=[pt,ht],Ne=pt):(Ce=Ne,Ne=r)}else Ce=Ne,Ne=r;if(Ne===r&&(Ne=null),Ne!==r){if(pt=[],ht=We(),ht!==r)for(;ht!==r;)pt.push(ht),ht=We();else pt=r;pt!==r?(Rt=$,ye=x(),$=ye):(Ce=$,$=r)}else Ce=$,$=r}else Ce=$,$=r;if($===r&&($=Ce,ye=hs(),ye!==r?(Ne=oa(),Ne!==r?(pt=Pn(),pt===r&&(pt=null),pt!==r?(t.charCodeAt(Ce)===58?(ht=C,Ce++):(ht=r,Yt===0&&Ze(R)),ht!==r?(Tt=Pn(),Tt===r&&(Tt=null),Tt!==r?(er=mc(),er!==r?(Rt=$,ye=N(Ne,er),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$===r&&($=Ce,ye=hs(),ye!==r?(Ne=co(),Ne!==r?(pt=Pn(),pt===r&&(pt=null),pt!==r?(t.charCodeAt(Ce)===58?(ht=C,Ce++):(ht=r,Yt===0&&Ze(R)),ht!==r?(Tt=Pn(),Tt===r&&(Tt=null),Tt!==r?(er=mc(),er!==r?(Rt=$,ye=N(Ne,er),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$===r))){if($=Ce,ye=hs(),ye!==r)if(Ne=co(),Ne!==r)if(pt=Pn(),pt!==r)if(ht=aa(),ht!==r){if(Tt=[],er=We(),er!==r)for(;er!==r;)Tt.push(er),er=We();else Tt=r;Tt!==r?(Rt=$,ye=N(Ne,ht),$=ye):(Ce=$,$=r)}else Ce=$,$=r;else Ce=$,$=r;else Ce=$,$=r;else Ce=$,$=r;if($===r)if($=Ce,ye=hs(),ye!==r)if(Ne=co(),Ne!==r){if(pt=[],ht=Ce,Tt=Pn(),Tt===r&&(Tt=null),Tt!==r?(t.charCodeAt(Ce)===44?(er=U,Ce++):(er=r,Yt===0&&Ze(V)),er!==r?($r=Pn(),$r===r&&($r=null),$r!==r?(Gi=co(),Gi!==r?(Rt=ht,Tt=te(Ne,Gi),ht=Tt):(Ce=ht,ht=r)):(Ce=ht,ht=r)):(Ce=ht,ht=r)):(Ce=ht,ht=r),ht!==r)for(;ht!==r;)pt.push(ht),ht=Ce,Tt=Pn(),Tt===r&&(Tt=null),Tt!==r?(t.charCodeAt(Ce)===44?(er=U,Ce++):(er=r,Yt===0&&Ze(V)),er!==r?($r=Pn(),$r===r&&($r=null),$r!==r?(Gi=co(),Gi!==r?(Rt=ht,Tt=te(Ne,Gi),ht=Tt):(Ce=ht,ht=r)):(Ce=ht,ht=r)):(Ce=ht,ht=r)):(Ce=ht,ht=r);else pt=r;pt!==r?(ht=Pn(),ht===r&&(ht=null),ht!==r?(t.charCodeAt(Ce)===58?(Tt=C,Ce++):(Tt=r,Yt===0&&Ze(R)),Tt!==r?(er=Pn(),er===r&&(er=null),er!==r?($r=mc(),$r!==r?(Rt=$,ye=ae(Ne,pt,$r),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)}else Ce=$,$=r;else Ce=$,$=r}return $}function mc(){var $,ye,Ne,pt,ht,Tt,er;if($=Ce,ye=Ce,Yt++,Ne=Ce,pt=tt(),pt!==r?(ht=Ht(),ht!==r?(t.charCodeAt(Ce)===45?(Tt=u,Ce++):(Tt=r,Yt===0&&Ze(A)),Tt!==r?(er=Pn(),er!==r?(pt=[pt,ht,Tt,er],Ne=pt):(Ce=Ne,Ne=r)):(Ce=Ne,Ne=r)):(Ce=Ne,Ne=r)):(Ce=Ne,Ne=r),Yt--,Ne!==r?(Ce=ye,ye=void 0):ye=r,ye!==r?(Ne=We(),Ne!==r?(pt=Fn(),pt!==r?(ht=qi(),ht!==r?(Tt=Ci(),Tt!==r?(Rt=$,ye=fe(ht),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$===r&&($=Ce,ye=tt(),ye!==r?(Ne=Fn(),Ne!==r?(pt=xA(),pt!==r?(ht=Ci(),ht!==r?(Rt=$,ye=fe(pt),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$===r))if($=Ce,ye=Us(),ye!==r){if(Ne=[],pt=We(),pt!==r)for(;pt!==r;)Ne.push(pt),pt=We();else Ne=r;Ne!==r?(Rt=$,ye=ue(ye),$=ye):(Ce=$,$=r)}else Ce=$,$=r;return $}function hs(){var $,ye,Ne;for(Yt++,$=Ce,ye=[],t.charCodeAt(Ce)===32?(Ne=he,Ce++):(Ne=r,Yt===0&&Ze(Be));Ne!==r;)ye.push(Ne),t.charCodeAt(Ce)===32?(Ne=he,Ce++):(Ne=r,Yt===0&&Ze(Be));return ye!==r?(Rt=Ce,Ne=we(ye),Ne?Ne=void 0:Ne=r,Ne!==r?(ye=[ye,Ne],$=ye):(Ce=$,$=r)):(Ce=$,$=r),Yt--,$===r&&(ye=r,Yt===0&&Ze(me)),$}function Ht(){var $,ye,Ne;for($=Ce,ye=[],t.charCodeAt(Ce)===32?(Ne=he,Ce++):(Ne=r,Yt===0&&Ze(Be));Ne!==r;)ye.push(Ne),t.charCodeAt(Ce)===32?(Ne=he,Ce++):(Ne=r,Yt===0&&Ze(Be));return ye!==r?(Rt=Ce,Ne=g(ye),Ne?Ne=void 0:Ne=r,Ne!==r?(ye=[ye,Ne],$=ye):(Ce=$,$=r)):(Ce=$,$=r),$}function Fn(){var $;return Rt=Ce,$=Ee(),$?$=void 0:$=r,$}function Ci(){var $;return Rt=Ce,$=Pe(),$?$=void 0:$=r,$}function oa(){var $;return $=ds(),$===r&&($=la()),$}function co(){var $,ye,Ne;if($=ds(),$===r){if($=Ce,ye=[],Ne=Ho(),Ne!==r)for(;Ne!==r;)ye.push(Ne),Ne=Ho();else ye=r;ye!==r&&(Rt=$,ye=ce()),$=ye}return $}function Us(){var $;return $=wi(),$===r&&($=gs(),$===r&&($=ds(),$===r&&($=la()))),$}function aa(){var $;return $=wi(),$===r&&($=ds(),$===r&&($=Ho())),$}function la(){var $,ye,Ne,pt,ht,Tt;if(Yt++,$=Ce,ee.test(t.charAt(Ce))?(ye=t.charAt(Ce),Ce++):(ye=r,Yt===0&&Ze(Ie)),ye!==r){for(Ne=[],pt=Ce,ht=Pn(),ht===r&&(ht=null),ht!==r?(Fe.test(t.charAt(Ce))?(Tt=t.charAt(Ce),Ce++):(Tt=r,Yt===0&&Ze(At)),Tt!==r?(ht=[ht,Tt],pt=ht):(Ce=pt,pt=r)):(Ce=pt,pt=r);pt!==r;)Ne.push(pt),pt=Ce,ht=Pn(),ht===r&&(ht=null),ht!==r?(Fe.test(t.charAt(Ce))?(Tt=t.charAt(Ce),Ce++):(Tt=r,Yt===0&&Ze(At)),Tt!==r?(ht=[ht,Tt],pt=ht):(Ce=pt,pt=r)):(Ce=pt,pt=r);Ne!==r?(Rt=$,ye=H(),$=ye):(Ce=$,$=r)}else Ce=$,$=r;return Yt--,$===r&&(ye=r,Yt===0&&Ze(ne)),$}function Ho(){var $,ye,Ne,pt,ht;if($=Ce,t.substr(Ce,2)===at?(ye=at,Ce+=2):(ye=r,Yt===0&&Ze(Re)),ye===r&&(ye=null),ye!==r)if(ke.test(t.charAt(Ce))?(Ne=t.charAt(Ce),Ce++):(Ne=r,Yt===0&&Ze(xe)),Ne!==r){for(pt=[],He.test(t.charAt(Ce))?(ht=t.charAt(Ce),Ce++):(ht=r,Yt===0&&Ze(Te));ht!==r;)pt.push(ht),He.test(t.charAt(Ce))?(ht=t.charAt(Ce),Ce++):(ht=r,Yt===0&&Ze(Te));pt!==r?(Rt=$,ye=H(),$=ye):(Ce=$,$=r)}else Ce=$,$=r;else Ce=$,$=r;return $}function wi(){var $,ye;return $=Ce,t.substr(Ce,4)===Ve?(ye=Ve,Ce+=4):(ye=r,Yt===0&&Ze(qe)),ye!==r&&(Rt=$,ye=b()),$=ye,$}function gs(){var $,ye;return $=Ce,t.substr(Ce,4)===w?(ye=w,Ce+=4):(ye=r,Yt===0&&Ze(S)),ye!==r&&(Rt=$,ye=y()),$=ye,$===r&&($=Ce,t.substr(Ce,5)===F?(ye=F,Ce+=5):(ye=r,Yt===0&&Ze(J)),ye!==r&&(Rt=$,ye=X()),$=ye),$}function ds(){var $,ye,Ne,pt;return Yt++,$=Ce,t.charCodeAt(Ce)===34?(ye=ie,Ce++):(ye=r,Yt===0&&Ze(be)),ye!==r?(t.charCodeAt(Ce)===34?(Ne=ie,Ce++):(Ne=r,Yt===0&&Ze(be)),Ne!==r?(Rt=$,ye=Le(),$=ye):(Ce=$,$=r)):(Ce=$,$=r),$===r&&($=Ce,t.charCodeAt(Ce)===34?(ye=ie,Ce++):(ye=r,Yt===0&&Ze(be)),ye!==r?(Ne=ms(),Ne!==r?(t.charCodeAt(Ce)===34?(pt=ie,Ce++):(pt=r,Yt===0&&Ze(be)),pt!==r?(Rt=$,ye=ot(Ne),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)),Yt--,$===r&&(ye=r,Yt===0&&Ze(Z)),$}function ms(){var $,ye,Ne;if($=Ce,ye=[],Ne=_s(),Ne!==r)for(;Ne!==r;)ye.push(Ne),Ne=_s();else ye=r;return ye!==r&&(Rt=$,ye=dt(ye)),$=ye,$}function _s(){var $,ye,Ne,pt,ht,Tt;return Gt.test(t.charAt(Ce))?($=t.charAt(Ce),Ce++):($=r,Yt===0&&Ze($t)),$===r&&($=Ce,t.substr(Ce,2)===bt?(ye=bt,Ce+=2):(ye=r,Yt===0&&Ze(an)),ye!==r&&(Rt=$,ye=Qr()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===mr?(ye=mr,Ce+=2):(ye=r,Yt===0&&Ze(br)),ye!==r&&(Rt=$,ye=Wr()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===Kn?(ye=Kn,Ce+=2):(ye=r,Yt===0&&Ze(Ls)),ye!==r&&(Rt=$,ye=Ti()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===ps?(ye=ps,Ce+=2):(ye=r,Yt===0&&Ze(io)),ye!==r&&(Rt=$,ye=Si()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===Ns?(ye=Ns,Ce+=2):(ye=r,Yt===0&&Ze(so)),ye!==r&&(Rt=$,ye=uc()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===uu?(ye=uu,Ce+=2):(ye=r,Yt===0&&Ze(cp)),ye!==r&&(Rt=$,ye=up()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===Os?(ye=Os,Ce+=2):(ye=r,Yt===0&&Ze(Dn)),ye!==r&&(Rt=$,ye=oo()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===Ms?(ye=Ms,Ce+=2):(ye=r,Yt===0&&Ze(yl)),ye!==r&&(Rt=$,ye=El()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===ao?(ye=ao,Ce+=2):(ye=r,Yt===0&&Ze(zn)),ye!==r?(Ne=Un(),Ne!==r?(pt=Un(),pt!==r?(ht=Un(),ht!==r?(Tt=Un(),Tt!==r?(Rt=$,ye=On(Ne,pt,ht,Tt),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)))))))))),$}function Un(){var $;return Li.test(t.charAt(Ce))?($=t.charAt(Ce),Ce++):($=r,Yt===0&&Ze(Mn)),$}function Pn(){var $,ye;if(Yt++,$=[],rr.test(t.charAt(Ce))?(ye=t.charAt(Ce),Ce++):(ye=r,Yt===0&&Ze(Oe)),ye!==r)for(;ye!==r;)$.push(ye),rr.test(t.charAt(Ce))?(ye=t.charAt(Ce),Ce++):(ye=r,Yt===0&&Ze(Oe));else $=r;return Yt--,$===r&&(ye=r,Yt===0&&Ze(_i)),$}function ys(){var $,ye;if(Yt++,$=[],Ua.test(t.charAt(Ce))?(ye=t.charAt(Ce),Ce++):(ye=r,Yt===0&&Ze(hr)),ye!==r)for(;ye!==r;)$.push(ye),Ua.test(t.charAt(Ce))?(ye=t.charAt(Ce),Ce++):(ye=r,Yt===0&&Ze(hr));else $=r;return Yt--,$===r&&(ye=r,Yt===0&&Ze(ii)),$}function We(){var $,ye,Ne,pt,ht,Tt;if($=Ce,ye=tt(),ye!==r){for(Ne=[],pt=Ce,ht=Pn(),ht===r&&(ht=null),ht!==r?(Tt=tt(),Tt!==r?(ht=[ht,Tt],pt=ht):(Ce=pt,pt=r)):(Ce=pt,pt=r);pt!==r;)Ne.push(pt),pt=Ce,ht=Pn(),ht===r&&(ht=null),ht!==r?(Tt=tt(),Tt!==r?(ht=[ht,Tt],pt=ht):(Ce=pt,pt=r)):(Ce=pt,pt=r);Ne!==r?(ye=[ye,Ne],$=ye):(Ce=$,$=r)}else Ce=$,$=r;return $}function tt(){var $;return t.substr(Ce,2)===Ac?($=Ac,Ce+=2):($=r,Yt===0&&Ze(Au)),$===r&&(t.charCodeAt(Ce)===10?($=fc,Ce++):($=r,Yt===0&&Ze(Cl)),$===r&&(t.charCodeAt(Ce)===13?($=DA,Ce++):($=r,Yt===0&&Ze(fu)))),$}let It=2,ir=0;if(wl=a(),wl!==r&&Ce===t.length)return wl;throw wl!==r&&Ce<t.length&&Ze(bA()),dc(pu,Hi<t.length?t.charAt(Hi):null,Hi<t.length?_o(Hi,Hi+1):_o(Hi,Hi))}XK.exports={SyntaxError:td,parse:K6e}});function ez(t){return t.match(z6e)?t:JSON.stringify(t)}function rz(t){return typeof t>"u"?!0:typeof t=="object"&&t!==null&&!Array.isArray(t)?Object.keys(t).every(e=>rz(t[e])):!1}function BT(t,e,r){if(t===null)return`null
-`;if(typeof t=="number"||typeof t=="boolean")return`${t.toString()}
-`;if(typeof t=="string")return`${ez(t)}
-`;if(Array.isArray(t)){if(t.length===0)return`[]
-`;let o=" ".repeat(e);return`
-${t.map(n=>`${o}- ${BT(n,e+1,!1)}`).join("")}`}if(typeof t=="object"&&t){let[o,a]=t instanceof JD?[t.data,!1]:[t,!0],n=" ".repeat(e),u=Object.keys(o);a&&u.sort((p,h)=>{let E=$K.indexOf(p),I=$K.indexOf(h);return E===-1&&I===-1?p<h?-1:p>h?1:0:E!==-1&&I===-1?-1:E===-1&&I!==-1?1:E-I});let A=u.filter(p=>!rz(o[p])).map((p,h)=>{let E=o[p],I=ez(p),v=BT(E,e+1,!0),x=h>0||r?n:"",C=I.length>1024?`? ${I}
-${x}:`:`${I}:`,R=v.startsWith(`
-`)?v:` ${v}`;return`${x}${C}${R}`}).join(e===0?`
-`:"")||`
-`;return r?`
-${A}`:`${A}`}throw new Error(`Unsupported value type (${t})`)}function Ba(t){try{let e=BT(t,0,!1);return e!==`
-`?e:""}catch(e){throw e.location&&(e.message=e.message.replace(/(\.)?$/,` (line ${e.location.start.line}, column ${e.location.start.column})$1`)),e}}function V6e(t){return t.endsWith(`
-`)||(t+=`
-`),(0,tz.parse)(t)}function X6e(t){if(J6e.test(t))return V6e(t);let e=(0,XD.safeLoad)(t,{schema:XD.FAILSAFE_SCHEMA,json:!0});if(e==null)return{};if(typeof e!="object")throw new Error(`Expected an indexed object, got a ${typeof e} instead. Does your file follow Yaml's rules?`);if(Array.isArray(e))throw new Error("Expected an indexed object, got an array instead. Does your file follow Yaml's rules?");return e}function Ki(t){return X6e(t)}var XD,tz,z6e,$K,JD,J6e,nz=Et(()=>{XD=$e(JK()),tz=$e(ZK()),z6e=/^(?![-?:,\][{}#&*!|>'"%@` \t\r\n]).([ \t]*(?![,\][{}:# \t\r\n]).)*$/,$K=["__metadata","version","resolution","dependencies","peerDependencies","dependenciesMeta","peerDependenciesMeta","binaries"],JD=class{constructor(e){this.data=e}};Ba.PreserveOrdering=JD;J6e=/^(#.*(\r?\n))*?#\s+yarn\s+lockfile\s+v1\r?\n/i});var rI={};zt(rI,{parseResolution:()=>MD,parseShell:()=>LD,parseSyml:()=>Ki,stringifyArgument:()=>cT,stringifyArgumentSegment:()=>uT,stringifyArithmeticExpression:()=>OD,stringifyCommand:()=>lT,stringifyCommandChain:()=>uy,stringifyCommandChainThen:()=>aT,stringifyCommandLine:()=>ND,stringifyCommandLineThen:()=>oT,stringifyEnvSegment:()=>TD,stringifyRedirectArgument:()=>Vw,stringifyResolution:()=>UD,stringifyShell:()=>cy,stringifyShellLine:()=>cy,stringifySyml:()=>Ba,stringifyValueArgument:()=>Wg});var Nl=Et(()=>{rW();oW();nz()});var sz=_((Cxt,vT)=>{"use strict";var Z6e=t=>{let e=!1,r=!1,o=!1;for(let a=0;a<t.length;a++){let n=t[a];e&&/[a-zA-Z]/.test(n)&&n.toUpperCase()===n?(t=t.slice(0,a)+"-"+t.slice(a),e=!1,o=r,r=!0,a++):r&&o&&/[a-zA-Z]/.test(n)&&n.toLowerCase()===n?(t=t.slice(0,a-1)+"-"+t.slice(a-1),o=r,r=!1,e=!0):(e=n.toLowerCase()===n&&n.toUpperCase()!==n,o=r,r=n.toUpperCase()===n&&n.toLowerCase()!==n)}return t},iz=(t,e)=>{if(!(typeof t=="string"||Array.isArray(t)))throw new TypeError("Expected the input to be `string | string[]`");e=Object.assign({pascalCase:!1},e);let r=a=>e.pascalCase?a.charAt(0).toUpperCase()+a.slice(1):a;return Array.isArray(t)?t=t.map(a=>a.trim()).filter(a=>a.length).join("-"):t=t.trim(),t.length===0?"":t.length===1?e.pascalCase?t.toUpperCase():t.toLowerCase():(t!==t.toLowerCase()&&(t=Z6e(t)),t=t.replace(/^[_.\- ]+/,"").toLowerCase().replace(/[_.\- ]+(\w|$)/g,(a,n)=>n.toUpperCase()).replace(/\d+(\w|$)/g,a=>a.toUpperCase()),r(t))};vT.exports=iz;vT.exports.default=iz});var oz=_((wxt,$6e)=>{$6e.exports=[{name:"AppVeyor",constant:"APPVEYOR",env:"APPVEYOR",pr:"APPVEYOR_PULL_REQUEST_NUMBER"},{name:"Azure Pipelines",constant:"AZURE_PIPELINES",env:"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI",pr:"SYSTEM_PULLREQUEST_PULLREQUESTID"},{name:"Appcircle",constant:"APPCIRCLE",env:"AC_APPCIRCLE"},{name:"Bamboo",constant:"BAMBOO",env:"bamboo_planKey"},{name:"Bitbucket Pipelines",constant:"BITBUCKET",env:"BITBUCKET_COMMIT",pr:"BITBUCKET_PR_ID"},{name:"Bitrise",constant:"BITRISE",env:"BITRISE_IO",pr:"BITRISE_PULL_REQUEST"},{name:"Buddy",constant:"BUDDY",env:"BUDDY_WORKSPACE_ID",pr:"BUDDY_EXECUTION_PULL_REQUEST_ID"},{name:"Buildkite",constant:"BUILDKITE",env:"BUILDKITE",pr:{env:"BUILDKITE_PULL_REQUEST",ne:"false"}},{name:"CircleCI",constant:"CIRCLE",env:"CIRCLECI",pr:"CIRCLE_PULL_REQUEST"},{name:"Cirrus CI",constant:"CIRRUS",env:"CIRRUS_CI",pr:"CIRRUS_PR"},{name:"AWS CodeBuild",constant:"CODEBUILD",env:"CODEBUILD_BUILD_ARN"},{name:"Codefresh",constant:"CODEFRESH",env:"CF_BUILD_ID",pr:{any:["CF_PULL_REQUEST_NUMBER","CF_PULL_REQUEST_ID"]}},{name:"Codeship",constant:"CODESHIP",env:{CI_NAME:"codeship"}},{name:"Drone",constant:"DRONE",env:"DRONE",pr:{DRONE_BUILD_EVENT:"pull_request"}},{name:"dsari",constant:"DSARI",env:"DSARI"},{name:"GitHub Actions",constant:"GITHUB_ACTIONS",env:"GITHUB_ACTIONS",pr:{GITHUB_EVENT_NAME:"pull_request"}},{name:"GitLab CI",constant:"GITLAB",env:"GITLAB_CI",pr:"CI_MERGE_REQUEST_ID"},{name:"GoCD",constant:"GOCD",env:"GO_PIPELINE_LABEL"},{name:"LayerCI",constant:"LAYERCI",env:"LAYERCI",pr:"LAYERCI_PULL_REQUEST"},{name:"Hudson",constant:"HUDSON",env:"HUDSON_URL"},{name:"Jenkins",constant:"JENKINS",env:["JENKINS_URL","BUILD_ID"],pr:{any:["ghprbPullId","CHANGE_ID"]}},{name:"Magnum CI",constant:"MAGNUM",env:"MAGNUM"},{name:"Netlify CI",constant:"NETLIFY",env:"NETLIFY",pr:{env:"PULL_REQUEST",ne:"false"}},{name:"Nevercode",constant:"NEVERCODE",env:"NEVERCODE",pr:{env:"NEVERCODE_PULL_REQUEST",ne:"false"}},{name:"Render",constant:"RENDER",env:"RENDER",pr:{IS_PULL_REQUEST:"true"}},{name:"Sail CI",constant:"SAIL",env:"SAILCI",pr:"SAIL_PULL_REQUEST_NUMBER"},{name:"Semaphore",constant:"SEMAPHORE",env:"SEMAPHORE",pr:"PULL_REQUEST_NUMBER"},{name:"Screwdriver",constant:"SCREWDRIVER",env:"SCREWDRIVER",pr:{env:"SD_PULL_REQUEST",ne:"false"}},{name:"Shippable",constant:"SHIPPABLE",env:"SHIPPABLE",pr:{IS_PULL_REQUEST:"true"}},{name:"Solano CI",constant:"SOLANO",env:"TDDIUM",pr:"TDDIUM_PR_ID"},{name:"Strider CD",constant:"STRIDER",env:"STRIDER"},{name:"TaskCluster",constant:"TASKCLUSTER",env:["TASK_ID","RUN_ID"]},{name:"TeamCity",constant:"TEAMCITY",env:"TEAMCITY_VERSION"},{name:"Travis CI",constant:"TRAVIS",env:"TRAVIS",pr:{env:"TRAVIS_PULL_REQUEST",ne:"false"}},{name:"Vercel",constant:"VERCEL",env:"NOW_BUILDER"},{name:"Visual Studio App Center",constant:"APPCENTER",env:"APPCENTER_BUILD_ID"}]});var rd=_(Za=>{"use strict";var lz=oz(),Gu=process.env;Object.defineProperty(Za,"_vendors",{value:lz.map(function(t){return t.constant})});Za.name=null;Za.isPR=null;lz.forEach(function(t){let r=(Array.isArray(t.env)?t.env:[t.env]).every(function(o){return az(o)});if(Za[t.constant]=r,r)switch(Za.name=t.name,typeof t.pr){case"string":Za.isPR=!!Gu[t.pr];break;case"object":"env"in t.pr?Za.isPR=t.pr.env in Gu&&Gu[t.pr.env]!==t.pr.ne:"any"in t.pr?Za.isPR=t.pr.any.some(function(o){return!!Gu[o]}):Za.isPR=az(t.pr);break;default:Za.isPR=null}});Za.isCI=!!(Gu.CI||Gu.CONTINUOUS_INTEGRATION||Gu.BUILD_NUMBER||Gu.RUN_ID||Za.name);function az(t){return typeof t=="string"?!!Gu[t]:Object.keys(t).every(function(e){return Gu[e]===t[e]})}});var Hn,cn,nd,DT,ZD,cz,PT,ST,$D=Et(()=>{(function(t){t.StartOfInput="\0",t.EndOfInput="",t.EndOfPartialInput=""})(Hn||(Hn={}));(function(t){t[t.InitialNode=0]="InitialNode",t[t.SuccessNode=1]="SuccessNode",t[t.ErrorNode=2]="ErrorNode",t[t.CustomNode=3]="CustomNode"})(cn||(cn={}));nd=-1,DT=/^(-h|--help)(?:=([0-9]+))?$/,ZD=/^(--[a-z]+(?:-[a-z]+)*|-[a-zA-Z]+)$/,cz=/^-[a-zA-Z]{2,}$/,PT=/^([^=]+)=([\s\S]*)$/,ST=process.env.DEBUG_CLI==="1"});var it,yy,eP,bT,tP=Et(()=>{$D();it=class extends Error{constructor(e){super(e),this.clipanion={type:"usage"},this.name="UsageError"}},yy=class extends Error{constructor(e,r){if(super(),this.input=e,this.candidates=r,this.clipanion={type:"none"},this.name="UnknownSyntaxError",this.candidates.length===0)this.message="Command not found, but we're not sure what's the alternative.";else if(this.candidates.every(o=>o.reason!==null&&o.reason===r[0].reason)){let[{reason:o}]=this.candidates;this.message=`${o}
-
-${this.candidates.map(({usage:a})=>`$ ${a}`).join(`
-`)}`}else if(this.candidates.length===1){let[{usage:o}]=this.candidates;this.message=`Command not found; did you mean:
-
-$ ${o}
-${bT(e)}`}else this.message=`Command not found; did you mean one of:
-
-${this.candidates.map(({usage:o},a)=>`${`${a}.`.padStart(4)} ${o}`).join(`
-`)}
-
-${bT(e)}`}},eP=class extends Error{constructor(e,r){super(),this.input=e,this.usages=r,this.clipanion={type:"none"},this.name="AmbiguousSyntaxError",this.message=`Cannot find which to pick amongst the following alternatives:
-
-${this.usages.map((o,a)=>`${`${a}.`.padStart(4)} ${o}`).join(`
-`)}
-
-${bT(e)}`}},bT=t=>`While running ${t.filter(e=>e!==Hn.EndOfInput&&e!==Hn.EndOfPartialInput).map(e=>{let r=JSON.stringify(e);return e.match(/\s/)||e.length===0||r!==`"${e}"`?r:e}).join(" ")}`});function eqe(t){let e=t.split(`
-`),r=e.filter(a=>a.match(/\S/)),o=r.length>0?r.reduce((a,n)=>Math.min(a,n.length-n.trimStart().length),Number.MAX_VALUE):0;return e.map(a=>a.slice(o).trimRight()).join(`
-`)}function Do(t,{format:e,paragraphs:r}){return t=t.replace(/\r\n?/g,`
-`),t=eqe(t),t=t.replace(/^\n+|\n+$/g,""),t=t.replace(/^(\s*)-([^\n]*?)\n+/gm,`$1-$2
-
-`),t=t.replace(/\n(\n)?\n*/g,(o,a)=>a||" "),r&&(t=t.split(/\n/).map(o=>{let a=o.match(/^\s*[*-][\t ]+(.*)/);if(!a)return o.match(/(.{1,80})(?: |$)/g).join(`
-`);let n=o.length-o.trimStart().length;return a[1].match(new RegExp(`(.{1,${78-n}})(?: |$)`,"g")).map((u,A)=>" ".repeat(n)+(A===0?"- ":" ")+u).join(`
-`)}).join(`
-
-`)),t=t.replace(/(`+)((?:.|[\n])*?)\1/g,(o,a,n)=>e.code(a+n+a)),t=t.replace(/(\*\*)((?:.|[\n])*?)\1/g,(o,a,n)=>e.bold(a+n+a)),t?`${t}
-`:""}var xT,uz,Az,kT=Et(()=>{xT=Array(80).fill("\u2501");for(let t=0;t<=24;++t)xT[xT.length-t]=`\x1B[38;5;${232+t}m\u2501`;uz={header:t=>`\x1B[1m\u2501\u2501\u2501 ${t}${t.length<80-5?` ${xT.slice(t.length+5).join("")}`:":"}\x1B[0m`,bold:t=>`\x1B[1m${t}\x1B[22m`,error:t=>`\x1B[31m\x1B[1m${t}\x1B[22m\x1B[39m`,code:t=>`\x1B[36m${t}\x1B[39m`},Az={header:t=>t,bold:t=>t,error:t=>t,code:t=>t}});function Ko(t){return{...t,[nI]:!0}}function ju(t,e){return typeof t>"u"?[t,e]:typeof t=="object"&&t!==null&&!Array.isArray(t)?[void 0,t]:[t,e]}function rP(t,{mergeName:e=!1}={}){let r=t.match(/^([^:]+): (.*)$/m);if(!r)return"validation failed";let[,o,a]=r;return e&&(a=a[0].toLowerCase()+a.slice(1)),a=o!=="."||!e?`${o.replace(/^\.(\[|$)/,"$1")}: ${a}`:`: ${a}`,a}function iI(t,e){return e.length===1?new it(`${t}${rP(e[0],{mergeName:!0})}`):new it(`${t}:
-${e.map(r=>`
-- ${rP(r)}`).join("")}`)}function id(t,e,r){if(typeof r>"u")return e;let o=[],a=[],n=A=>{let p=e;return e=A,n.bind(null,p)};if(!r(e,{errors:o,coercions:a,coercion:n}))throw iI(`Invalid value for ${t}`,o);for(let[,A]of a)A();return e}var nI,Ef=Et(()=>{tP();nI=Symbol("clipanion/isOption")});var zo={};zt(zo,{KeyRelationship:()=>Yu,TypeAssertionError:()=>zp,applyCascade:()=>aI,as:()=>Eqe,assert:()=>dqe,assertWithErrors:()=>mqe,cascade:()=>oP,fn:()=>Cqe,hasAtLeastOneKey:()=>OT,hasExactLength:()=>dz,hasForbiddenKeys:()=>Uqe,hasKeyRelationship:()=>cI,hasMaxLength:()=>Iqe,hasMinLength:()=>wqe,hasMutuallyExclusiveKeys:()=>_qe,hasRequiredKeys:()=>Mqe,hasUniqueItems:()=>Bqe,isArray:()=>nP,isAtLeast:()=>LT,isAtMost:()=>Pqe,isBase64:()=>Tqe,isBoolean:()=>lqe,isDate:()=>uqe,isDict:()=>pqe,isEnum:()=>Ks,isHexColor:()=>Rqe,isISO8601:()=>Fqe,isInExclusiveRange:()=>bqe,isInInclusiveRange:()=>Sqe,isInstanceOf:()=>gqe,isInteger:()=>NT,isJSON:()=>Lqe,isLiteral:()=>pz,isLowerCase:()=>xqe,isMap:()=>fqe,isNegative:()=>vqe,isNullable:()=>Oqe,isNumber:()=>RT,isObject:()=>hz,isOneOf:()=>TT,isOptional:()=>Nqe,isPartial:()=>hqe,isPayload:()=>cqe,isPositive:()=>Dqe,isRecord:()=>sP,isSet:()=>Aqe,isString:()=>Cy,isTuple:()=>iP,isUUID4:()=>Qqe,isUnknown:()=>FT,isUpperCase:()=>kqe,makeTrait:()=>gz,makeValidator:()=>Hr,matchesRegExp:()=>oI,softAssert:()=>yqe});function qn(t){return t===null?"null":t===void 0?"undefined":t===""?"an empty string":typeof t=="symbol"?`<${t.toString()}>`:Array.isArray(t)?"an array":JSON.stringify(t)}function Ey(t,e){if(t.length===0)return"nothing";if(t.length===1)return qn(t[0]);let r=t.slice(0,-1),o=t[t.length-1],a=t.length>2?`, ${e} `:` ${e} `;return`${r.map(n=>qn(n)).join(", ")}${a}${qn(o)}`}function Kp(t,e){var r,o,a;return typeof e=="number"?`${(r=t?.p)!==null&&r!==void 0?r:"."}[${e}]`:tqe.test(e)?`${(o=t?.p)!==null&&o!==void 0?o:""}.${e}`:`${(a=t?.p)!==null&&a!==void 0?a:"."}[${JSON.stringify(e)}]`}function QT(t,e,r){return t===1?e:r}function pr({errors:t,p:e}={},r){return t?.push(`${e??"."}: ${r}`),!1}function oqe(t,e){return r=>{t[e]=r}}function Wu(t,e){return r=>{let o=t[e];return t[e]=r,Wu(t,e).bind(null,o)}}function sI(t,e,r){let o=()=>(t(r()),a),a=()=>(t(e),o);return o}function FT(){return Hr({test:(t,e)=>!0})}function pz(t){return Hr({test:(e,r)=>e!==t?pr(r,`Expected ${qn(t)} (got ${qn(e)})`):!0})}function Cy(){return Hr({test:(t,e)=>typeof t!="string"?pr(e,`Expected a string (got ${qn(t)})`):!0})}function Ks(t){let e=Array.isArray(t)?t:Object.values(t),r=e.every(a=>typeof a=="string"||typeof a=="number"),o=new Set(e);return o.size===1?pz([...o][0]):Hr({test:(a,n)=>o.has(a)?!0:r?pr(n,`Expected one of ${Ey(e,"or")} (got ${qn(a)})`):pr(n,`Expected a valid enumeration value (got ${qn(a)})`)})}function lqe(){return Hr({test:(t,e)=>{var r;if(typeof t!="boolean"){if(typeof e?.coercions<"u"){if(typeof e?.coercion>"u")return pr(e,"Unbound coercion result");let o=aqe.get(t);if(typeof o<"u")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:".",e.coercion.bind(null,o)]),!0}return pr(e,`Expected a boolean (got ${qn(t)})`)}return!0}})}function RT(){return Hr({test:(t,e)=>{var r;if(typeof t!="number"){if(typeof e?.coercions<"u"){if(typeof e?.coercion>"u")return pr(e,"Unbound coercion result");let o;if(typeof t=="string"){let a;try{a=JSON.parse(t)}catch{}if(typeof a=="number")if(JSON.stringify(a)===t)o=a;else return pr(e,`Received a number that can't be safely represented by the runtime (${t})`)}if(typeof o<"u")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:".",e.coercion.bind(null,o)]),!0}return pr(e,`Expected a number (got ${qn(t)})`)}return!0}})}function cqe(t){return Hr({test:(e,r)=>{var o;if(typeof r?.coercions>"u")return pr(r,"The isPayload predicate can only be used with coercion enabled");if(typeof r.coercion>"u")return pr(r,"Unbound coercion result");if(typeof e!="string")return pr(r,`Expected a string (got ${qn(e)})`);let a;try{a=JSON.parse(e)}catch{return pr(r,`Expected a JSON string (got ${qn(e)})`)}let n={value:a};return t(a,Object.assign(Object.assign({},r),{coercion:Wu(n,"value")}))?(r.coercions.push([(o=r.p)!==null&&o!==void 0?o:".",r.coercion.bind(null,n.value)]),!0):!1}})}function uqe(){return Hr({test:(t,e)=>{var r;if(!(t instanceof Date)){if(typeof e?.coercions<"u"){if(typeof e?.coercion>"u")return pr(e,"Unbound coercion result");let o;if(typeof t=="string"&&fz.test(t))o=new Date(t);else{let a;if(typeof t=="string"){let n;try{n=JSON.parse(t)}catch{}typeof n=="number"&&(a=n)}else typeof t=="number"&&(a=t);if(typeof a<"u")if(Number.isSafeInteger(a)||!Number.isSafeInteger(a*1e3))o=new Date(a*1e3);else return pr(e,`Received a timestamp that can't be safely represented by the runtime (${t})`)}if(typeof o<"u")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:".",e.coercion.bind(null,o)]),!0}return pr(e,`Expected a date (got ${qn(t)})`)}return!0}})}function nP(t,{delimiter:e}={}){return Hr({test:(r,o)=>{var a;let n=r;if(typeof r=="string"&&typeof e<"u"&&typeof o?.coercions<"u"){if(typeof o?.coercion>"u")return pr(o,"Unbound coercion result");r=r.split(e)}if(!Array.isArray(r))return pr(o,`Expected an array (got ${qn(r)})`);let u=!0;for(let A=0,p=r.length;A<p&&(u=t(r[A],Object.assign(Object.assign({},o),{p:Kp(o,A),coercion:Wu(r,A)}))&&u,!(!u&&o?.errors==null));++A);return r!==n&&o.coercions.push([(a=o.p)!==null&&a!==void 0?a:".",o.coercion.bind(null,r)]),u}})}function Aqe(t,{delimiter:e}={}){let r=nP(t,{delimiter:e});return Hr({test:(o,a)=>{var n,u;if(Object.getPrototypeOf(o).toString()==="[object Set]")if(typeof a?.coercions<"u"){if(typeof a?.coercion>"u")return pr(a,"Unbound coercion result");let A=[...o],p=[...o];if(!r(p,Object.assign(Object.assign({},a),{coercion:void 0})))return!1;let h=()=>p.some((E,I)=>E!==A[I])?new Set(p):o;return a.coercions.push([(n=a.p)!==null&&n!==void 0?n:".",sI(a.coercion,o,h)]),!0}else{let A=!0;for(let p of o)if(A=t(p,Object.assign({},a))&&A,!A&&a?.errors==null)break;return A}if(typeof a?.coercions<"u"){if(typeof a?.coercion>"u")return pr(a,"Unbound coercion result");let A={value:o};return r(o,Object.assign(Object.assign({},a),{coercion:Wu(A,"value")}))?(a.coercions.push([(u=a.p)!==null&&u!==void 0?u:".",sI(a.coercion,o,()=>new Set(A.value))]),!0):!1}return pr(a,`Expected a set (got ${qn(o)})`)}})}function fqe(t,e){let r=nP(iP([t,e])),o=sP(e,{keys:t});return Hr({test:(a,n)=>{var u,A,p;if(Object.getPrototypeOf(a).toString()==="[object Map]")if(typeof n?.coercions<"u"){if(typeof n?.coercion>"u")return pr(n,"Unbound coercion result");let h=[...a],E=[...a];if(!r(E,Object.assign(Object.assign({},n),{coercion:void 0})))return!1;let I=()=>E.some((v,x)=>v[0]!==h[x][0]||v[1]!==h[x][1])?new Map(E):a;return n.coercions.push([(u=n.p)!==null&&u!==void 0?u:".",sI(n.coercion,a,I)]),!0}else{let h=!0;for(let[E,I]of a)if(h=t(E,Object.assign({},n))&&h,!h&&n?.errors==null||(h=e(I,Object.assign(Object.assign({},n),{p:Kp(n,E)}))&&h,!h&&n?.errors==null))break;return h}if(typeof n?.coercions<"u"){if(typeof n?.coercion>"u")return pr(n,"Unbound coercion result");let h={value:a};return Array.isArray(a)?r(a,Object.assign(Object.assign({},n),{coercion:void 0}))?(n.coercions.push([(A=n.p)!==null&&A!==void 0?A:".",sI(n.coercion,a,()=>new Map(h.value))]),!0):!1:o(a,Object.assign(Object.assign({},n),{coercion:Wu(h,"value")}))?(n.coercions.push([(p=n.p)!==null&&p!==void 0?p:".",sI(n.coercion,a,()=>new Map(Object.entries(h.value)))]),!0):!1}return pr(n,`Expected a map (got ${qn(a)})`)}})}function iP(t,{delimiter:e}={}){let r=dz(t.length);return Hr({test:(o,a)=>{var n;if(typeof o=="string"&&typeof e<"u"&&typeof a?.coercions<"u"){if(typeof a?.coercion>"u")return pr(a,"Unbound coercion result");o=o.split(e),a.coercions.push([(n=a.p)!==null&&n!==void 0?n:".",a.coercion.bind(null,o)])}if(!Array.isArray(o))return pr(a,`Expected a tuple (got ${qn(o)})`);let u=r(o,Object.assign({},a));for(let A=0,p=o.length;A<p&&A<t.length&&(u=t[A](o[A],Object.assign(Object.assign({},a),{p:Kp(a,A),coercion:Wu(o,A)}))&&u,!(!u&&a?.errors==null));++A);return u}})}function sP(t,{keys:e=null}={}){let r=nP(iP([e??Cy(),t]));return Hr({test:(o,a)=>{var n;if(Array.isArray(o)&&typeof a?.coercions<"u")return typeof a?.coercion>"u"?pr(a,"Unbound coercion result"):r(o,Object.assign(Object.assign({},a),{coercion:void 0}))?(o=Object.fromEntries(o),a.coercions.push([(n=a.p)!==null&&n!==void 0?n:".",a.coercion.bind(null,o)]),!0):!1;if(typeof o!="object"||o===null)return pr(a,`Expected an object (got ${qn(o)})`);let u=Object.keys(o),A=!0;for(let p=0,h=u.length;p<h&&(A||a?.errors!=null);++p){let E=u[p],I=o[E];if(E==="__proto__"||E==="constructor"){A=pr(Object.assign(Object.assign({},a),{p:Kp(a,E)}),"Unsafe property name");continue}if(e!==null&&!e(E,a)){A=!1;continue}if(!t(I,Object.assign(Object.assign({},a),{p:Kp(a,E),coercion:Wu(o,E)}))){A=!1;continue}}return A}})}function pqe(t,e={}){return sP(t,e)}function hz(t,{extra:e=null}={}){let r=Object.keys(t),o=Hr({test:(a,n)=>{if(typeof a!="object"||a===null)return pr(n,`Expected an object (got ${qn(a)})`);let u=new Set([...r,...Object.keys(a)]),A={},p=!0;for(let h of u){if(h==="constructor"||h==="__proto__")p=pr(Object.assign(Object.assign({},n),{p:Kp(n,h)}),"Unsafe property name");else{let E=Object.prototype.hasOwnProperty.call(t,h)?t[h]:void 0,I=Object.prototype.hasOwnProperty.call(a,h)?a[h]:void 0;typeof E<"u"?p=E(I,Object.assign(Object.assign({},n),{p:Kp(n,h),coercion:Wu(a,h)}))&&p:e===null?p=pr(Object.assign(Object.assign({},n),{p:Kp(n,h)}),`Extraneous property (got ${qn(I)})`):Object.defineProperty(A,h,{enumerable:!0,get:()=>I,set:oqe(a,h)})}if(!p&&n?.errors==null)break}return e!==null&&(p||n?.errors!=null)&&(p=e(A,n)&&p),p}});return Object.assign(o,{properties:t})}function hqe(t){return hz(t,{extra:sP(FT())})}function gz(t){return()=>t}function Hr({test:t}){return gz(t)()}function dqe(t,e){if(!e(t))throw new zp}function mqe(t,e){let r=[];if(!e(t,{errors:r}))throw new zp({errors:r})}function yqe(t,e){}function Eqe(t,e,{coerce:r=!1,errors:o,throw:a}={}){let n=o?[]:void 0;if(!r){if(e(t,{errors:n}))return a?t:{value:t,errors:void 0};if(a)throw new zp({errors:n});return{value:void 0,errors:n??!0}}let u={value:t},A=Wu(u,"value"),p=[];if(!e(t,{errors:n,coercion:A,coercions:p})){if(a)throw new zp({errors:n});return{value:void 0,errors:n??!0}}for(let[,h]of p)h();return a?u.value:{value:u.value,errors:void 0}}function Cqe(t,e){let r=iP(t);return(...o)=>{if(!r(o))throw new zp;return e(...o)}}function wqe(t){return Hr({test:(e,r)=>e.length>=t?!0:pr(r,`Expected to have a length of at least ${t} elements (got ${e.length})`)})}function Iqe(t){return Hr({test:(e,r)=>e.length<=t?!0:pr(r,`Expected to have a length of at most ${t} elements (got ${e.length})`)})}function dz(t){return Hr({test:(e,r)=>e.length!==t?pr(r,`Expected to have a length of exactly ${t} elements (got ${e.length})`):!0})}function Bqe({map:t}={}){return Hr({test:(e,r)=>{let o=new Set,a=new Set;for(let n=0,u=e.length;n<u;++n){let A=e[n],p=typeof t<"u"?t(A):A;if(o.has(p)){if(a.has(p))continue;pr(r,`Expected to contain unique elements; got a duplicate with ${qn(e)}`),a.add(p)}else o.add(p)}return a.size===0}})}function vqe(){return Hr({test:(t,e)=>t<=0?!0:pr(e,`Expected to be negative (got ${t})`)})}function Dqe(){return Hr({test:(t,e)=>t>=0?!0:pr(e,`Expected to be positive (got ${t})`)})}function LT(t){return Hr({test:(e,r)=>e>=t?!0:pr(r,`Expected to be at least ${t} (got ${e})`)})}function Pqe(t){return Hr({test:(e,r)=>e<=t?!0:pr(r,`Expected to be at most ${t} (got ${e})`)})}function Sqe(t,e){return Hr({test:(r,o)=>r>=t&&r<=e?!0:pr(o,`Expected to be in the [${t}; ${e}] range (got ${r})`)})}function bqe(t,e){return Hr({test:(r,o)=>r>=t&&r<e?!0:pr(o,`Expected to be in the [${t}; ${e}[ range (got ${r})`)})}function NT({unsafe:t=!1}={}){return Hr({test:(e,r)=>e!==Math.round(e)?pr(r,`Expected to be an integer (got ${e})`):!t&&!Number.isSafeInteger(e)?pr(r,`Expected to be a safe integer (got ${e})`):!0})}function oI(t){return Hr({test:(e,r)=>t.test(e)?!0:pr(r,`Expected to match the pattern ${t.toString()} (got ${qn(e)})`)})}function xqe(){return Hr({test:(t,e)=>t!==t.toLowerCase()?pr(e,`Expected to be all-lowercase (got ${t})`):!0})}function kqe(){return Hr({test:(t,e)=>t!==t.toUpperCase()?pr(e,`Expected to be all-uppercase (got ${t})`):!0})}function Qqe(){return Hr({test:(t,e)=>sqe.test(t)?!0:pr(e,`Expected to be a valid UUID v4 (got ${qn(t)})`)})}function Fqe(){return Hr({test:(t,e)=>fz.test(t)?!0:pr(e,`Expected to be a valid ISO 8601 date string (got ${qn(t)})`)})}function Rqe({alpha:t=!1}){return Hr({test:(e,r)=>(t?rqe.test(e):nqe.test(e))?!0:pr(r,`Expected to be a valid hexadecimal color string (got ${qn(e)})`)})}function Tqe(){return Hr({test:(t,e)=>iqe.test(t)?!0:pr(e,`Expected to be a valid base 64 string (got ${qn(t)})`)})}function Lqe(t=FT()){return Hr({test:(e,r)=>{let o;try{o=JSON.parse(e)}catch{return pr(r,`Expected to be a valid JSON string (got ${qn(e)})`)}return t(o,r)}})}function oP(t,...e){let r=Array.isArray(e[0])?e[0]:e;return Hr({test:(o,a)=>{var n,u;let A={value:o},p=typeof a?.coercions<"u"?Wu(A,"value"):void 0,h=typeof a?.coercions<"u"?[]:void 0;if(!t(o,Object.assign(Object.assign({},a),{coercion:p,coercions:h})))return!1;let E=[];if(typeof h<"u")for(let[,I]of h)E.push(I());try{if(typeof a?.coercions<"u"){if(A.value!==o){if(typeof a?.coercion>"u")return pr(a,"Unbound coercion result");a.coercions.push([(n=a.p)!==null&&n!==void 0?n:".",a.coercion.bind(null,A.value)])}(u=a?.coercions)===null||u===void 0||u.push(...h)}return r.every(I=>I(A.value,a))}finally{for(let I of E)I()}}})}function aI(t,...e){let r=Array.isArray(e[0])?e[0]:e;return oP(t,r)}function Nqe(t){return Hr({test:(e,r)=>typeof e>"u"?!0:t(e,r)})}function Oqe(t){return Hr({test:(e,r)=>e===null?!0:t(e,r)})}function Mqe(t,e){var r;let o=new Set(t),a=lI[(r=e?.missingIf)!==null&&r!==void 0?r:"missing"];return Hr({test:(n,u)=>{let A=new Set(Object.keys(n)),p=[];for(let h of o)a(A,h,n)||p.push(h);return p.length>0?pr(u,`Missing required ${QT(p.length,"property","properties")} ${Ey(p,"and")}`):!0}})}function OT(t,e){var r;let o=new Set(t),a=lI[(r=e?.missingIf)!==null&&r!==void 0?r:"missing"];return Hr({test:(n,u)=>Object.keys(n).some(h=>a(o,h,n))?!0:pr(u,`Missing at least one property from ${Ey(Array.from(o),"or")}`)})}function Uqe(t,e){var r;let o=new Set(t),a=lI[(r=e?.missingIf)!==null&&r!==void 0?r:"missing"];return Hr({test:(n,u)=>{let A=new Set(Object.keys(n)),p=[];for(let h of o)a(A,h,n)&&p.push(h);return p.length>0?pr(u,`Forbidden ${QT(p.length,"property","properties")} ${Ey(p,"and")}`):!0}})}function _qe(t,e){var r;let o=new Set(t),a=lI[(r=e?.missingIf)!==null&&r!==void 0?r:"missing"];return Hr({test:(n,u)=>{let A=new Set(Object.keys(n)),p=[];for(let h of o)a(A,h,n)&&p.push(h);return p.length>1?pr(u,`Mutually exclusive properties ${Ey(p,"and")}`):!0}})}function cI(t,e,r,o){var a,n;let u=new Set((a=o?.ignore)!==null&&a!==void 0?a:[]),A=lI[(n=o?.missingIf)!==null&&n!==void 0?n:"missing"],p=new Set(r),h=Hqe[e],E=e===Yu.Forbids?"or":"and";return Hr({test:(I,v)=>{let x=new Set(Object.keys(I));if(!A(x,t,I)||u.has(I[t]))return!0;let C=[];for(let R of p)(A(x,R,I)&&!u.has(I[R]))!==h.expect&&C.push(R);return C.length>=1?pr(v,`Property "${t}" ${h.message} ${QT(C.length,"property","properties")} ${Ey(C,E)}`):!0}})}var tqe,rqe,nqe,iqe,sqe,fz,aqe,gqe,TT,zp,lI,Yu,Hqe,$a=Et(()=>{tqe=/^[a-zA-Z_][a-zA-Z0-9_]*$/;rqe=/^#[0-9a-f]{6}$/i,nqe=/^#[0-9a-f]{6}([0-9a-f]{2})?$/i,iqe=/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/,sqe=/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}$/i,fz=/^(?:[1-9]\d{3}(-?)(?:(?:0[1-9]|1[0-2])\1(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])\1(?:29|30)|(?:0[13578]|1[02])(?:\1)31|00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[0-5]))|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)(?:(-?)02(?:\2)29|-?366))T(?:[01]\d|2[0-3])(:?)[0-5]\d(?:\3[0-5]\d)?(?:Z|[+-][01]\d(?:\3[0-5]\d)?)$/;aqe=new Map([["true",!0],["True",!0],["1",!0],[1,!0],["false",!1],["False",!1],["0",!1],[0,!1]]);gqe=t=>Hr({test:(e,r)=>e instanceof t?!0:pr(r,`Expected an instance of ${t.name} (got ${qn(e)})`)}),TT=(t,{exclusive:e=!1}={})=>Hr({test:(r,o)=>{var a,n,u;let A=[],p=typeof o?.errors<"u"?[]:void 0;for(let h=0,E=t.length;h<E;++h){let I=typeof o?.errors<"u"?[]:void 0,v=typeof o?.coercions<"u"?[]:void 0;if(t[h](r,Object.assign(Object.assign({},o),{errors:I,coercions:v,p:`${(a=o?.p)!==null&&a!==void 0?a:"."}#${h+1}`}))){if(A.push([`#${h+1}`,v]),!e)break}else p?.push(I[0])}if(A.length===1){let[,h]=A[0];return typeof h<"u"&&((n=o?.coercions)===null||n===void 0||n.push(...h)),!0}return A.length>1?pr(o,`Expected to match exactly a single predicate (matched ${A.join(", ")})`):(u=o?.errors)===null||u===void 0||u.push(...p),!1}});zp=class extends Error{constructor({errors:e}={}){let r="Type mismatch";if(e&&e.length>0){r+=`
-`;for(let o of e)r+=`
-- ${o}`}super(r)}};lI={missing:(t,e)=>t.has(e),undefined:(t,e,r)=>t.has(e)&&typeof r[e]<"u",nil:(t,e,r)=>t.has(e)&&r[e]!=null,falsy:(t,e,r)=>t.has(e)&&!!r[e]};(function(t){t.Forbids="Forbids",t.Requires="Requires"})(Yu||(Yu={}));Hqe={[Yu.Forbids]:{expect:!1,message:"forbids using"},[Yu.Requires]:{expect:!0,message:"requires using"}}});var nt,Vp=Et(()=>{Ef();nt=class{constructor(){this.help=!1}static Usage(e){return e}async catch(e){throw e}async validateAndExecute(){let r=this.constructor.schema;if(Array.isArray(r)){let{isDict:a,isUnknown:n,applyCascade:u}=await Promise.resolve().then(()=>($a(),zo)),A=u(a(n()),r),p=[],h=[];if(!A(this,{errors:p,coercions:h}))throw iI("Invalid option schema",p);for(let[,I]of h)I()}else if(r!=null)throw new Error("Invalid command schema");let o=await this.execute();return typeof o<"u"?o:0}};nt.isOption=nI;nt.Default=[]});function va(t){ST&&console.log(t)}function yz(){let t={nodes:[]};for(let e=0;e<cn.CustomNode;++e)t.nodes.push(el());return t}function qqe(t){let e=yz(),r=[],o=e.nodes.length;for(let a of t){r.push(o);for(let n=0;n<a.nodes.length;++n)Cz(n)||e.nodes.push(Jqe(a.nodes[n],o));o+=a.nodes.length-cn.CustomNode+1}for(let a of r)wy(e,cn.InitialNode,a);return e}function Mc(t,e){return t.nodes.push(e),t.nodes.length-1}function Gqe(t){let e=new Set,r=o=>{if(e.has(o))return;e.add(o);let a=t.nodes[o];for(let u of Object.values(a.statics))for(let{to:A}of u)r(A);for(let[,{to:u}]of a.dynamics)r(u);for(let{to:u}of a.shortcuts)r(u);let n=new Set(a.shortcuts.map(({to:u})=>u));for(;a.shortcuts.length>0;){let{to:u}=a.shortcuts.shift(),A=t.nodes[u];for(let[p,h]of Object.entries(A.statics)){let E=Object.prototype.hasOwnProperty.call(a.statics,p)?a.statics[p]:a.statics[p]=[];for(let I of h)E.some(({to:v})=>I.to===v)||E.push(I)}for(let[p,h]of A.dynamics)a.dynamics.some(([E,{to:I}])=>p===E&&h.to===I)||a.dynamics.push([p,h]);for(let p of A.shortcuts)n.has(p.to)||(a.shortcuts.push(p),n.add(p.to))}};r(cn.InitialNode)}function jqe(t,{prefix:e=""}={}){if(ST){va(`${e}Nodes are:`);for(let r=0;r<t.nodes.length;++r)va(`${e} ${r}: ${JSON.stringify(t.nodes[r])}`)}}function Yqe(t,e,r=!1){va(`Running a vm on ${JSON.stringify(e)}`);let o=[{node:cn.InitialNode,state:{candidateUsage:null,requiredOptions:[],errorMessage:null,ignoreOptions:!1,options:[],path:[],positionals:[],remainder:null,selectedIndex:null,partial:!1,tokens:[]}}];jqe(t,{prefix:" "});let a=[Hn.StartOfInput,...e];for(let n=0;n<a.length;++n){let u=a[n],A=u===Hn.EndOfInput||u===Hn.EndOfPartialInput,p=n-1;va(` Processing ${JSON.stringify(u)}`);let h=[];for(let{node:E,state:I}of o){va(` Current node is ${E}`);let v=t.nodes[E];if(E===cn.ErrorNode){h.push({node:E,state:I});continue}console.assert(v.shortcuts.length===0,"Shortcuts should have been eliminated by now");let x=Object.prototype.hasOwnProperty.call(v.statics,u);if(!r||n<a.length-1||x)if(x){let C=v.statics[u];for(let{to:R,reducer:N}of C)h.push({node:R,state:typeof N<"u"?aP(UT,N,I,u,p):I}),va(` Static transition to ${R} found`)}else va(" No static transition found");else{let C=!1;for(let R of Object.keys(v.statics))if(!!R.startsWith(u)){if(u===R)for(let{to:N,reducer:U}of v.statics[R])h.push({node:N,state:typeof U<"u"?aP(UT,U,I,u,p):I}),va(` Static transition to ${N} found`);else for(let{to:N}of v.statics[R])h.push({node:N,state:{...I,remainder:R.slice(u.length)}}),va(` Static transition to ${N} found (partial match)`);C=!0}C||va(" No partial static transition found")}if(!A)for(let[C,{to:R,reducer:N}]of v.dynamics)aP(Xqe,C,I,u,p)&&(h.push({node:R,state:typeof N<"u"?aP(UT,N,I,u,p):I}),va(` Dynamic transition to ${R} found (via ${C})`))}if(h.length===0&&A&&e.length===1)return[{node:cn.InitialNode,state:mz}];if(h.length===0)throw new yy(e,o.filter(({node:E})=>E!==cn.ErrorNode).map(({state:E})=>({usage:E.candidateUsage,reason:null})));if(h.every(({node:E})=>E===cn.ErrorNode))throw new yy(e,h.map(({state:E})=>({usage:E.candidateUsage,reason:E.errorMessage})));o=Kqe(h)}if(o.length>0){va(" Results:");for(let n of o)va(` - ${n.node} -> ${JSON.stringify(n.state)}`)}else va(" No results");return o}function Wqe(t,e,{endToken:r=Hn.EndOfInput}={}){let o=Yqe(t,[...e,r]);return zqe(e,o.map(({state:a})=>a))}function Kqe(t){let e=0;for(let{state:r}of t)r.path.length>e&&(e=r.path.length);return t.filter(({state:r})=>r.path.length===e)}function zqe(t,e){let r=e.filter(v=>v.selectedIndex!==null),o=r.filter(v=>!v.partial);if(o.length>0&&(r=o),r.length===0)throw new Error;let a=r.filter(v=>v.selectedIndex===nd||v.requiredOptions.every(x=>x.some(C=>v.options.find(R=>R.name===C))));if(a.length===0)throw new yy(t,r.map(v=>({usage:v.candidateUsage,reason:null})));let n=0;for(let v of a)v.path.length>n&&(n=v.path.length);let u=a.filter(v=>v.path.length===n),A=v=>v.positionals.filter(({extra:x})=>!x).length+v.options.length,p=u.map(v=>({state:v,positionalCount:A(v)})),h=0;for(let{positionalCount:v}of p)v>h&&(h=v);let E=p.filter(({positionalCount:v})=>v===h).map(({state:v})=>v),I=Vqe(E);if(I.length>1)throw new eP(t,I.map(v=>v.candidateUsage));return I[0]}function Vqe(t){let e=[],r=[];for(let o of t)o.selectedIndex===nd?r.push(o):e.push(o);return r.length>0&&e.push({...mz,path:Ez(...r.map(o=>o.path)),options:r.reduce((o,a)=>o.concat(a.options),[])}),e}function Ez(t,e,...r){return e===void 0?Array.from(t):Ez(t.filter((o,a)=>o===e[a]),...r)}function el(){return{dynamics:[],shortcuts:[],statics:{}}}function Cz(t){return t===cn.SuccessNode||t===cn.ErrorNode}function MT(t,e=0){return{to:Cz(t.to)?t.to:t.to>=cn.CustomNode?t.to+e-cn.CustomNode+1:t.to+e,reducer:t.reducer}}function Jqe(t,e=0){let r=el();for(let[o,a]of t.dynamics)r.dynamics.push([o,MT(a,e)]);for(let o of t.shortcuts)r.shortcuts.push(MT(o,e));for(let[o,a]of Object.entries(t.statics))r.statics[o]=a.map(n=>MT(n,e));return r}function Ss(t,e,r,o,a){t.nodes[e].dynamics.push([r,{to:o,reducer:a}])}function wy(t,e,r,o){t.nodes[e].shortcuts.push({to:r,reducer:o})}function Vo(t,e,r,o,a){(Object.prototype.hasOwnProperty.call(t.nodes[e].statics,r)?t.nodes[e].statics[r]:t.nodes[e].statics[r]=[]).push({to:o,reducer:a})}function aP(t,e,r,o,a){if(Array.isArray(e)){let[n,...u]=e;return t[n](r,o,a,...u)}else return t[e](r,o,a)}var mz,Xqe,UT,tl,_T,Iy,lP=Et(()=>{$D();tP();mz={candidateUsage:null,requiredOptions:[],errorMessage:null,ignoreOptions:!1,path:[],positionals:[],options:[],remainder:null,selectedIndex:nd,partial:!1,tokens:[]};Xqe={always:()=>!0,isOptionLike:(t,e)=>!t.ignoreOptions&&e!=="-"&&e.startsWith("-"),isNotOptionLike:(t,e)=>t.ignoreOptions||e==="-"||!e.startsWith("-"),isOption:(t,e,r,o)=>!t.ignoreOptions&&e===o,isBatchOption:(t,e,r,o)=>!t.ignoreOptions&&cz.test(e)&&[...e.slice(1)].every(a=>o.has(`-${a}`)),isBoundOption:(t,e,r,o,a)=>{let n=e.match(PT);return!t.ignoreOptions&&!!n&&ZD.test(n[1])&&o.has(n[1])&&a.filter(u=>u.nameSet.includes(n[1])).every(u=>u.allowBinding)},isNegatedOption:(t,e,r,o)=>!t.ignoreOptions&&e===`--no-${o.slice(2)}`,isHelp:(t,e)=>!t.ignoreOptions&&DT.test(e),isUnsupportedOption:(t,e,r,o)=>!t.ignoreOptions&&e.startsWith("-")&&ZD.test(e)&&!o.has(e),isInvalidOption:(t,e)=>!t.ignoreOptions&&e.startsWith("-")&&!ZD.test(e)},UT={setCandidateState:(t,e,r,o)=>({...t,...o}),setSelectedIndex:(t,e,r,o)=>({...t,selectedIndex:o}),setPartialIndex:(t,e,r,o)=>({...t,selectedIndex:o,partial:!0}),pushBatch:(t,e,r,o)=>{let a=t.options.slice(),n=t.tokens.slice();for(let u=1;u<e.length;++u){let A=o.get(`-${e[u]}`),p=u===1?[0,2]:[u,u+1];a.push({name:A,value:!0}),n.push({segmentIndex:r,type:"option",option:A,slice:p})}return{...t,options:a,tokens:n}},pushBound:(t,e,r)=>{let[,o,a]=e.match(PT),n=t.options.concat({name:o,value:a}),u=t.tokens.concat([{segmentIndex:r,type:"option",slice:[0,o.length],option:o},{segmentIndex:r,type:"assign",slice:[o.length,o.length+1]},{segmentIndex:r,type:"value",slice:[o.length+1,o.length+a.length+1]}]);return{...t,options:n,tokens:u}},pushPath:(t,e,r)=>{let o=t.path.concat(e),a=t.tokens.concat({segmentIndex:r,type:"path"});return{...t,path:o,tokens:a}},pushPositional:(t,e,r)=>{let o=t.positionals.concat({value:e,extra:!1}),a=t.tokens.concat({segmentIndex:r,type:"positional"});return{...t,positionals:o,tokens:a}},pushExtra:(t,e,r)=>{let o=t.positionals.concat({value:e,extra:!0}),a=t.tokens.concat({segmentIndex:r,type:"positional"});return{...t,positionals:o,tokens:a}},pushExtraNoLimits:(t,e,r)=>{let o=t.positionals.concat({value:e,extra:tl}),a=t.tokens.concat({segmentIndex:r,type:"positional"});return{...t,positionals:o,tokens:a}},pushTrue:(t,e,r,o)=>{let a=t.options.concat({name:o,value:!0}),n=t.tokens.concat({segmentIndex:r,type:"option",option:o});return{...t,options:a,tokens:n}},pushFalse:(t,e,r,o)=>{let a=t.options.concat({name:o,value:!1}),n=t.tokens.concat({segmentIndex:r,type:"option",option:o});return{...t,options:a,tokens:n}},pushUndefined:(t,e,r,o)=>{let a=t.options.concat({name:e,value:void 0}),n=t.tokens.concat({segmentIndex:r,type:"option",option:e});return{...t,options:a,tokens:n}},pushStringValue:(t,e,r)=>{var o;let a=t.options[t.options.length-1],n=t.options.slice(),u=t.tokens.concat({segmentIndex:r,type:"value"});return a.value=((o=a.value)!==null&&o!==void 0?o:[]).concat([e]),{...t,options:n,tokens:u}},setStringValue:(t,e,r)=>{let o=t.options[t.options.length-1],a=t.options.slice(),n=t.tokens.concat({segmentIndex:r,type:"value"});return o.value=e,{...t,options:a,tokens:n}},inhibateOptions:t=>({...t,ignoreOptions:!0}),useHelp:(t,e,r,o)=>{let[,,a]=e.match(DT);return typeof a<"u"?{...t,options:[{name:"-c",value:String(o)},{name:"-i",value:a}]}:{...t,options:[{name:"-c",value:String(o)}]}},setError:(t,e,r,o)=>e===Hn.EndOfInput||e===Hn.EndOfPartialInput?{...t,errorMessage:`${o}.`}:{...t,errorMessage:`${o} ("${e}").`},setOptionArityError:(t,e)=>{let r=t.options[t.options.length-1];return{...t,errorMessage:`Not enough arguments to option ${r.name}.`}}},tl=Symbol(),_T=class{constructor(e,r){this.allOptionNames=new Map,this.arity={leading:[],trailing:[],extra:[],proxy:!1},this.options=[],this.paths=[],this.cliIndex=e,this.cliOpts=r}addPath(e){this.paths.push(e)}setArity({leading:e=this.arity.leading,trailing:r=this.arity.trailing,extra:o=this.arity.extra,proxy:a=this.arity.proxy}){Object.assign(this.arity,{leading:e,trailing:r,extra:o,proxy:a})}addPositional({name:e="arg",required:r=!0}={}){if(!r&&this.arity.extra===tl)throw new Error("Optional parameters cannot be declared when using .rest() or .proxy()");if(!r&&this.arity.trailing.length>0)throw new Error("Optional parameters cannot be declared after the required trailing positional arguments");!r&&this.arity.extra!==tl?this.arity.extra.push(e):this.arity.extra!==tl&&this.arity.extra.length===0?this.arity.leading.push(e):this.arity.trailing.push(e)}addRest({name:e="arg",required:r=0}={}){if(this.arity.extra===tl)throw new Error("Infinite lists cannot be declared multiple times in the same command");if(this.arity.trailing.length>0)throw new Error("Infinite lists cannot be declared after the required trailing positional arguments");for(let o=0;o<r;++o)this.addPositional({name:e});this.arity.extra=tl}addProxy({required:e=0}={}){this.addRest({required:e}),this.arity.proxy=!0}addOption({names:e,description:r,arity:o=0,hidden:a=!1,required:n=!1,allowBinding:u=!0}){if(!u&&o>1)throw new Error("The arity cannot be higher than 1 when the option only supports the --arg=value syntax");if(!Number.isInteger(o))throw new Error(`The arity must be an integer, got ${o}`);if(o<0)throw new Error(`The arity must be positive, got ${o}`);let A=e.reduce((p,h)=>h.length>p.length?h:p,"");for(let p of e)this.allOptionNames.set(p,A);this.options.push({preferredName:A,nameSet:e,description:r,arity:o,hidden:a,required:n,allowBinding:u})}setContext(e){this.context=e}usage({detailed:e=!0,inlineOptions:r=!0}={}){let o=[this.cliOpts.binaryName],a=[];if(this.paths.length>0&&o.push(...this.paths[0]),e){for(let{preferredName:u,nameSet:A,arity:p,hidden:h,description:E,required:I}of this.options){if(h)continue;let v=[];for(let C=0;C<p;++C)v.push(` #${C}`);let x=`${A.join(",")}${v.join("")}`;!r&&E?a.push({preferredName:u,nameSet:A,definition:x,description:E,required:I}):o.push(I?`<${x}>`:`[${x}]`)}o.push(...this.arity.leading.map(u=>`<${u}>`)),this.arity.extra===tl?o.push("..."):o.push(...this.arity.extra.map(u=>`[${u}]`)),o.push(...this.arity.trailing.map(u=>`<${u}>`))}return{usage:o.join(" "),options:a}}compile(){if(typeof this.context>"u")throw new Error("Assertion failed: No context attached");let e=yz(),r=cn.InitialNode,o=this.usage().usage,a=this.options.filter(A=>A.required).map(A=>A.nameSet);r=Mc(e,el()),Vo(e,cn.InitialNode,Hn.StartOfInput,r,["setCandidateState",{candidateUsage:o,requiredOptions:a}]);let n=this.arity.proxy?"always":"isNotOptionLike",u=this.paths.length>0?this.paths:[[]];for(let A of u){let p=r;if(A.length>0){let v=Mc(e,el());wy(e,p,v),this.registerOptions(e,v),p=v}for(let v=0;v<A.length;++v){let x=Mc(e,el());Vo(e,p,A[v],x,"pushPath"),p=x}if(this.arity.leading.length>0||!this.arity.proxy){let v=Mc(e,el());Ss(e,p,"isHelp",v,["useHelp",this.cliIndex]),Ss(e,v,"always",v,"pushExtra"),Vo(e,v,Hn.EndOfInput,cn.SuccessNode,["setSelectedIndex",nd]),this.registerOptions(e,p)}this.arity.leading.length>0&&(Vo(e,p,Hn.EndOfInput,cn.ErrorNode,["setError","Not enough positional arguments"]),Vo(e,p,Hn.EndOfPartialInput,cn.SuccessNode,["setPartialIndex",this.cliIndex]));let h=p;for(let v=0;v<this.arity.leading.length;++v){let x=Mc(e,el());(!this.arity.proxy||v+1!==this.arity.leading.length)&&this.registerOptions(e,x),(this.arity.trailing.length>0||v+1!==this.arity.leading.length)&&(Vo(e,x,Hn.EndOfInput,cn.ErrorNode,["setError","Not enough positional arguments"]),Vo(e,x,Hn.EndOfPartialInput,cn.SuccessNode,["setPartialIndex",this.cliIndex])),Ss(e,h,"isNotOptionLike",x,"pushPositional"),h=x}let E=h;if(this.arity.extra===tl||this.arity.extra.length>0){let v=Mc(e,el());if(wy(e,h,v),this.arity.extra===tl){let x=Mc(e,el());this.arity.proxy||this.registerOptions(e,x),Ss(e,h,n,x,"pushExtraNoLimits"),Ss(e,x,n,x,"pushExtraNoLimits"),wy(e,x,v)}else for(let x=0;x<this.arity.extra.length;++x){let C=Mc(e,el());(!this.arity.proxy||x>0)&&this.registerOptions(e,C),Ss(e,E,n,C,"pushExtra"),wy(e,C,v),E=C}E=v}this.arity.trailing.length>0&&(Vo(e,E,Hn.EndOfInput,cn.ErrorNode,["setError","Not enough positional arguments"]),Vo(e,E,Hn.EndOfPartialInput,cn.SuccessNode,["setPartialIndex",this.cliIndex]));let I=E;for(let v=0;v<this.arity.trailing.length;++v){let x=Mc(e,el());this.arity.proxy||this.registerOptions(e,x),v+1<this.arity.trailing.length&&(Vo(e,x,Hn.EndOfInput,cn.ErrorNode,["setError","Not enough positional arguments"]),Vo(e,x,Hn.EndOfPartialInput,cn.SuccessNode,["setPartialIndex",this.cliIndex])),Ss(e,I,"isNotOptionLike",x,"pushPositional"),I=x}Ss(e,I,n,cn.ErrorNode,["setError","Extraneous positional argument"]),Vo(e,I,Hn.EndOfInput,cn.SuccessNode,["setSelectedIndex",this.cliIndex]),Vo(e,I,Hn.EndOfPartialInput,cn.SuccessNode,["setSelectedIndex",this.cliIndex])}return{machine:e,context:this.context}}registerOptions(e,r){Ss(e,r,["isOption","--"],r,"inhibateOptions"),Ss(e,r,["isBatchOption",this.allOptionNames],r,["pushBatch",this.allOptionNames]),Ss(e,r,["isBoundOption",this.allOptionNames,this.options],r,"pushBound"),Ss(e,r,["isUnsupportedOption",this.allOptionNames],cn.ErrorNode,["setError","Unsupported option name"]),Ss(e,r,["isInvalidOption"],cn.ErrorNode,["setError","Invalid option name"]);for(let o of this.options)if(o.arity===0)for(let a of o.nameSet)Ss(e,r,["isOption",a],r,["pushTrue",o.preferredName]),a.startsWith("--")&&!a.startsWith("--no-")&&Ss(e,r,["isNegatedOption",a],r,["pushFalse",o.preferredName]);else{let a=Mc(e,el());for(let n of o.nameSet)Ss(e,r,["isOption",n],a,["pushUndefined",o.preferredName]);for(let n=0;n<o.arity;++n){let u=Mc(e,el());Vo(e,a,Hn.EndOfInput,cn.ErrorNode,"setOptionArityError"),Vo(e,a,Hn.EndOfPartialInput,cn.ErrorNode,"setOptionArityError"),Ss(e,a,"isOptionLike",cn.ErrorNode,"setOptionArityError");let A=o.arity===1?"setStringValue":"pushStringValue";Ss(e,a,"isNotOptionLike",u,A),a=u}wy(e,a,r)}}},Iy=class{constructor({binaryName:e="..."}={}){this.builders=[],this.opts={binaryName:e}}static build(e,r={}){return new Iy(r).commands(e).compile()}getBuilderByIndex(e){if(!(e>=0&&e<this.builders.length))throw new Error(`Assertion failed: Out-of-bound command index (${e})`);return this.builders[e]}commands(e){for(let r of e)r(this.command());return this}command(){let e=new _T(this.builders.length,this.opts);return this.builders.push(e),e}compile(){let e=[],r=[];for(let a of this.builders){let{machine:n,context:u}=a.compile();e.push(n),r.push(u)}let o=qqe(e);return Gqe(o),{machine:o,contexts:r,process:(a,{partial:n}={})=>{let u=n?Hn.EndOfPartialInput:Hn.EndOfInput;return Wqe(o,a,{endToken:u})}}}}});function Iz(){return cP.default&&"getColorDepth"in cP.default.WriteStream.prototype?cP.default.WriteStream.prototype.getColorDepth():process.env.FORCE_COLOR==="0"?1:process.env.FORCE_COLOR==="1"||typeof process.stdout<"u"&&process.stdout.isTTY?8:1}function Bz(t){let e=wz;if(typeof e>"u"){if(t.stdout===process.stdout&&t.stderr===process.stderr)return null;let{AsyncLocalStorage:r}=ve("async_hooks");e=wz=new r;let o=process.stdout._write;process.stdout._write=function(n,u,A){let p=e.getStore();return typeof p>"u"?o.call(this,n,u,A):p.stdout.write(n,u,A)};let a=process.stderr._write;process.stderr._write=function(n,u,A){let p=e.getStore();return typeof p>"u"?a.call(this,n,u,A):p.stderr.write(n,u,A)}}return r=>e.run(t,r)}var cP,wz,vz=Et(()=>{cP=$e(ve("tty"),1)});var By,Dz=Et(()=>{Vp();By=class extends nt{constructor(e){super(),this.contexts=e,this.commands=[]}static from(e,r){let o=new By(r);o.path=e.path;for(let a of e.options)switch(a.name){case"-c":o.commands.push(Number(a.value));break;case"-i":o.index=Number(a.value);break}return o}async execute(){let e=this.commands;if(typeof this.index<"u"&&this.index>=0&&this.index<e.length&&(e=[e[this.index]]),e.length===0)this.context.stdout.write(this.cli.usage());else if(e.length===1)this.context.stdout.write(this.cli.usage(this.contexts[e[0]].commandClass,{detailed:!0}));else if(e.length>1){this.context.stdout.write(`Multiple commands match your selection:
-`),this.context.stdout.write(`
-`);let r=0;for(let o of this.commands)this.context.stdout.write(this.cli.usage(this.contexts[o].commandClass,{prefix:`${r++}. `.padStart(5)}));this.context.stdout.write(`
-`),this.context.stdout.write(`Run again with -h=<index> to see the longer details of any of those commands.
-`)}}}});async function bz(...t){let{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:o,resolvedContext:a}=kz(t);return as.from(r,e).runExit(o,a)}async function xz(...t){let{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:o,resolvedContext:a}=kz(t);return as.from(r,e).run(o,a)}function kz(t){let e,r,o,a;switch(typeof process<"u"&&typeof process.argv<"u"&&(o=process.argv.slice(2)),t.length){case 1:r=t[0];break;case 2:t[0]&&t[0].prototype instanceof nt||Array.isArray(t[0])?(r=t[0],Array.isArray(t[1])?o=t[1]:a=t[1]):(e=t[0],r=t[1]);break;case 3:Array.isArray(t[2])?(e=t[0],r=t[1],o=t[2]):t[0]&&t[0].prototype instanceof nt||Array.isArray(t[0])?(r=t[0],o=t[1],a=t[2]):(e=t[0],r=t[1],a=t[2]);break;default:e=t[0],r=t[1],o=t[2],a=t[3];break}if(typeof o>"u")throw new Error("The argv parameter must be provided when running Clipanion outside of a Node context");return{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:o,resolvedContext:a}}function Sz(t){return t()}var Pz,as,Qz=Et(()=>{$D();lP();kT();vz();Vp();Dz();Pz=Symbol("clipanion/errorCommand");as=class{constructor({binaryLabel:e,binaryName:r="...",binaryVersion:o,enableCapture:a=!1,enableColors:n}={}){this.registrations=new Map,this.builder=new Iy({binaryName:r}),this.binaryLabel=e,this.binaryName=r,this.binaryVersion=o,this.enableCapture=a,this.enableColors=n}static from(e,r={}){let o=new as(r),a=Array.isArray(e)?e:[e];for(let n of a)o.register(n);return o}register(e){var r;let o=new Map,a=new e;for(let p in a){let h=a[p];typeof h=="object"&&h!==null&&h[nt.isOption]&&o.set(p,h)}let n=this.builder.command(),u=n.cliIndex,A=(r=e.paths)!==null&&r!==void 0?r:a.paths;if(typeof A<"u")for(let p of A)n.addPath(p);this.registrations.set(e,{specs:o,builder:n,index:u});for(let[p,{definition:h}]of o.entries())h(n,p);n.setContext({commandClass:e})}process(e,r){let{input:o,context:a,partial:n}=typeof e=="object"&&Array.isArray(e)?{input:e,context:r}:e,{contexts:u,process:A}=this.builder.compile(),p=A(o,{partial:n}),h={...as.defaultContext,...a};switch(p.selectedIndex){case nd:{let E=By.from(p,u);return E.context=h,E.tokens=p.tokens,E}default:{let{commandClass:E}=u[p.selectedIndex],I=this.registrations.get(E);if(typeof I>"u")throw new Error("Assertion failed: Expected the command class to have been registered.");let v=new E;v.context=h,v.tokens=p.tokens,v.path=p.path;try{for(let[x,{transformer:C}]of I.specs.entries())v[x]=C(I.builder,x,p,h);return v}catch(x){throw x[Pz]=v,x}}break}}async run(e,r){var o,a;let n,u={...as.defaultContext,...r},A=(o=this.enableColors)!==null&&o!==void 0?o:u.colorDepth>1;if(!Array.isArray(e))n=e;else try{n=this.process(e,u)}catch(E){return u.stdout.write(this.error(E,{colored:A})),1}if(n.help)return u.stdout.write(this.usage(n,{colored:A,detailed:!0})),0;n.context=u,n.cli={binaryLabel:this.binaryLabel,binaryName:this.binaryName,binaryVersion:this.binaryVersion,enableCapture:this.enableCapture,enableColors:this.enableColors,definitions:()=>this.definitions(),definition:E=>this.definition(E),error:(E,I)=>this.error(E,I),format:E=>this.format(E),process:(E,I)=>this.process(E,{...u,...I}),run:(E,I)=>this.run(E,{...u,...I}),usage:(E,I)=>this.usage(E,I)};let p=this.enableCapture&&(a=Bz(u))!==null&&a!==void 0?a:Sz,h;try{h=await p(()=>n.validateAndExecute().catch(E=>n.catch(E).then(()=>0)))}catch(E){return u.stdout.write(this.error(E,{colored:A,command:n})),1}return h}async runExit(e,r){process.exitCode=await this.run(e,r)}definition(e,{colored:r=!1}={}){if(!e.usage)return null;let{usage:o}=this.getUsageByRegistration(e,{detailed:!1}),{usage:a,options:n}=this.getUsageByRegistration(e,{detailed:!0,inlineOptions:!1}),u=typeof e.usage.category<"u"?Do(e.usage.category,{format:this.format(r),paragraphs:!1}):void 0,A=typeof e.usage.description<"u"?Do(e.usage.description,{format:this.format(r),paragraphs:!1}):void 0,p=typeof e.usage.details<"u"?Do(e.usage.details,{format:this.format(r),paragraphs:!0}):void 0,h=typeof e.usage.examples<"u"?e.usage.examples.map(([E,I])=>[Do(E,{format:this.format(r),paragraphs:!1}),I.replace(/\$0/g,this.binaryName)]):void 0;return{path:o,usage:a,category:u,description:A,details:p,examples:h,options:n}}definitions({colored:e=!1}={}){let r=[];for(let o of this.registrations.keys()){let a=this.definition(o,{colored:e});!a||r.push(a)}return r}usage(e=null,{colored:r,detailed:o=!1,prefix:a="$ "}={}){var n;if(e===null){for(let p of this.registrations.keys()){let h=p.paths,E=typeof p.usage<"u";if(!h||h.length===0||h.length===1&&h[0].length===0||((n=h?.some(x=>x.length===0))!==null&&n!==void 0?n:!1))if(e){e=null;break}else e=p;else if(E){e=null;continue}}e&&(o=!0)}let u=e!==null&&e instanceof nt?e.constructor:e,A="";if(u)if(o){let{description:p="",details:h="",examples:E=[]}=u.usage||{};p!==""&&(A+=Do(p,{format:this.format(r),paragraphs:!1}).replace(/^./,x=>x.toUpperCase()),A+=`
-`),(h!==""||E.length>0)&&(A+=`${this.format(r).header("Usage")}
-`,A+=`
-`);let{usage:I,options:v}=this.getUsageByRegistration(u,{inlineOptions:!1});if(A+=`${this.format(r).bold(a)}${I}
-`,v.length>0){A+=`
-`,A+=`${this.format(r).header("Options")}
-`;let x=v.reduce((C,R)=>Math.max(C,R.definition.length),0);A+=`
-`;for(let{definition:C,description:R}of v)A+=` ${this.format(r).bold(C.padEnd(x))} ${Do(R,{format:this.format(r),paragraphs:!1})}`}if(h!==""&&(A+=`
-`,A+=`${this.format(r).header("Details")}
-`,A+=`
-`,A+=Do(h,{format:this.format(r),paragraphs:!0})),E.length>0){A+=`
-`,A+=`${this.format(r).header("Examples")}
-`;for(let[x,C]of E)A+=`
-`,A+=Do(x,{format:this.format(r),paragraphs:!1}),A+=`${C.replace(/^/m,` ${this.format(r).bold(a)}`).replace(/\$0/g,this.binaryName)}
-`}}else{let{usage:p}=this.getUsageByRegistration(u);A+=`${this.format(r).bold(a)}${p}
-`}else{let p=new Map;for(let[v,{index:x}]of this.registrations.entries()){if(typeof v.usage>"u")continue;let C=typeof v.usage.category<"u"?Do(v.usage.category,{format:this.format(r),paragraphs:!1}):null,R=p.get(C);typeof R>"u"&&p.set(C,R=[]);let{usage:N}=this.getUsageByIndex(x);R.push({commandClass:v,usage:N})}let h=Array.from(p.keys()).sort((v,x)=>v===null?-1:x===null?1:v.localeCompare(x,"en",{usage:"sort",caseFirst:"upper"})),E=typeof this.binaryLabel<"u",I=typeof this.binaryVersion<"u";E||I?(E&&I?A+=`${this.format(r).header(`${this.binaryLabel} - ${this.binaryVersion}`)}
-
-`:E?A+=`${this.format(r).header(`${this.binaryLabel}`)}
-`:A+=`${this.format(r).header(`${this.binaryVersion}`)}
-`,A+=` ${this.format(r).bold(a)}${this.binaryName} <command>
-`):A+=`${this.format(r).bold(a)}${this.binaryName} <command>
-`;for(let v of h){let x=p.get(v).slice().sort((R,N)=>R.usage.localeCompare(N.usage,"en",{usage:"sort",caseFirst:"upper"})),C=v!==null?v.trim():"General commands";A+=`
-`,A+=`${this.format(r).header(`${C}`)}
-`;for(let{commandClass:R,usage:N}of x){let U=R.usage.description||"undocumented";A+=`
-`,A+=` ${this.format(r).bold(N)}
-`,A+=` ${Do(U,{format:this.format(r),paragraphs:!1})}`}}A+=`
-`,A+=Do("You can also print more details about any of these commands by calling them with the `-h,--help` flag right after the command name.",{format:this.format(r),paragraphs:!0})}return A}error(e,r){var o,{colored:a,command:n=(o=e[Pz])!==null&&o!==void 0?o:null}=r===void 0?{}:r;(!e||typeof e!="object"||!("stack"in e))&&(e=new Error(`Execution failed with a non-error rejection (rejected value: ${JSON.stringify(e)})`));let u="",A=e.name.replace(/([a-z])([A-Z])/g,"$1 $2");A==="Error"&&(A="Internal Error"),u+=`${this.format(a).error(A)}: ${e.message}
-`;let p=e.clipanion;return typeof p<"u"?p.type==="usage"&&(u+=`
-`,u+=this.usage(n)):e.stack&&(u+=`${e.stack.replace(/^.*\n/,"")}
-`),u}format(e){var r;return((r=e??this.enableColors)!==null&&r!==void 0?r:as.defaultContext.colorDepth>1)?uz:Az}getUsageByRegistration(e,r){let o=this.registrations.get(e);if(typeof o>"u")throw new Error("Assertion failed: Unregistered command");return this.getUsageByIndex(o.index,r)}getUsageByIndex(e,r){return this.builder.getBuilderByIndex(e).usage(r)}};as.defaultContext={env:process.env,stdin:process.stdin,stdout:process.stdout,stderr:process.stderr,colorDepth:Iz()}});var uI,Fz=Et(()=>{Vp();uI=class extends nt{async execute(){this.context.stdout.write(`${JSON.stringify(this.cli.definitions(),null,2)}
-`)}};uI.paths=[["--clipanion=definitions"]]});var AI,Rz=Et(()=>{Vp();AI=class extends nt{async execute(){this.context.stdout.write(this.cli.usage())}};AI.paths=[["-h"],["--help"]]});function uP(t={}){return Ko({definition(e,r){var o;e.addProxy({name:(o=t.name)!==null&&o!==void 0?o:r,required:t.required})},transformer(e,r,o){return o.positionals.map(({value:a})=>a)}})}var HT=Et(()=>{Ef()});var fI,Tz=Et(()=>{Vp();HT();fI=class extends nt{constructor(){super(...arguments),this.args=uP()}async execute(){this.context.stdout.write(`${JSON.stringify(this.cli.process(this.args).tokens,null,2)}
-`)}};fI.paths=[["--clipanion=tokens"]]});var pI,Lz=Et(()=>{Vp();pI=class extends nt{async execute(){var e;this.context.stdout.write(`${(e=this.cli.binaryVersion)!==null&&e!==void 0?e:"<unknown>"}
-`)}};pI.paths=[["-v"],["--version"]]});var qT={};zt(qT,{DefinitionsCommand:()=>uI,HelpCommand:()=>AI,TokensCommand:()=>fI,VersionCommand:()=>pI});var Nz=Et(()=>{Fz();Rz();Tz();Lz()});function Oz(t,e,r){let[o,a]=ju(e,r??{}),{arity:n=1}=a,u=t.split(","),A=new Set(u);return Ko({definition(p){p.addOption({names:u,arity:n,hidden:a?.hidden,description:a?.description,required:a.required})},transformer(p,h,E){let I,v=typeof o<"u"?[...o]:void 0;for(let{name:x,value:C}of E.options)!A.has(x)||(I=x,v=v??[],v.push(C));return typeof v<"u"?id(I??h,v,a.validator):v}})}var Mz=Et(()=>{Ef()});function Uz(t,e,r){let[o,a]=ju(e,r??{}),n=t.split(","),u=new Set(n);return Ko({definition(A){A.addOption({names:n,allowBinding:!1,arity:0,hidden:a.hidden,description:a.description,required:a.required})},transformer(A,p,h){let E=o;for(let{name:I,value:v}of h.options)!u.has(I)||(E=v);return E}})}var _z=Et(()=>{Ef()});function Hz(t,e,r){let[o,a]=ju(e,r??{}),n=t.split(","),u=new Set(n);return Ko({definition(A){A.addOption({names:n,allowBinding:!1,arity:0,hidden:a.hidden,description:a.description,required:a.required})},transformer(A,p,h){let E=o;for(let{name:I,value:v}of h.options)!u.has(I)||(E??(E=0),v?E+=1:E=0);return E}})}var qz=Et(()=>{Ef()});function Gz(t={}){return Ko({definition(e,r){var o;e.addRest({name:(o=t.name)!==null&&o!==void 0?o:r,required:t.required})},transformer(e,r,o){let a=u=>{let A=o.positionals[u];return A.extra===tl||A.extra===!1&&u<e.arity.leading.length},n=0;for(;n<o.positionals.length&&a(n);)n+=1;return o.positionals.splice(0,n).map(({value:u})=>u)}})}var jz=Et(()=>{lP();Ef()});function Zqe(t,e,r){let[o,a]=ju(e,r??{}),{arity:n=1}=a,u=t.split(","),A=new Set(u);return Ko({definition(p){p.addOption({names:u,arity:a.tolerateBoolean?0:n,hidden:a.hidden,description:a.description,required:a.required})},transformer(p,h,E,I){let v,x=o;typeof a.env<"u"&&I.env[a.env]&&(v=a.env,x=I.env[a.env]);for(let{name:C,value:R}of E.options)!A.has(C)||(v=C,x=R);return typeof x=="string"?id(v??h,x,a.validator):x}})}function $qe(t={}){let{required:e=!0}=t;return Ko({definition(r,o){var a;r.addPositional({name:(a=t.name)!==null&&a!==void 0?a:o,required:t.required})},transformer(r,o,a){var n;for(let u=0;u<a.positionals.length;++u){if(a.positionals[u].extra===tl||e&&a.positionals[u].extra===!0||!e&&a.positionals[u].extra===!1)continue;let[A]=a.positionals.splice(u,1);return id((n=t.name)!==null&&n!==void 0?n:o,A.value,t.validator)}}})}function Yz(t,...e){return typeof t=="string"?Zqe(t,...e):$qe(t)}var Wz=Et(()=>{lP();Ef()});var ge={};zt(ge,{Array:()=>Oz,Boolean:()=>Uz,Counter:()=>Hz,Proxy:()=>uP,Rest:()=>Gz,String:()=>Yz,applyValidator:()=>id,cleanValidationError:()=>rP,formatError:()=>iI,isOptionSymbol:()=>nI,makeCommandOption:()=>Ko,rerouteArguments:()=>ju});var Kz=Et(()=>{Ef();HT();Mz();_z();qz();jz();Wz()});var hI={};zt(hI,{Builtins:()=>qT,Cli:()=>as,Command:()=>nt,Option:()=>ge,UsageError:()=>it,formatMarkdownish:()=>Do,run:()=>xz,runExit:()=>bz});var qt=Et(()=>{tP();kT();Vp();Qz();Nz();Kz()});var zz=_((bkt,eGe)=>{eGe.exports={name:"dotenv",version:"16.3.1",description:"Loads environment variables from .env file",main:"lib/main.js",types:"lib/main.d.ts",exports:{".":{types:"./lib/main.d.ts",require:"./lib/main.js",default:"./lib/main.js"},"./config":"./config.js","./config.js":"./config.js","./lib/env-options":"./lib/env-options.js","./lib/env-options.js":"./lib/env-options.js","./lib/cli-options":"./lib/cli-options.js","./lib/cli-options.js":"./lib/cli-options.js","./package.json":"./package.json"},scripts:{"dts-check":"tsc --project tests/types/tsconfig.json",lint:"standard","lint-readme":"standard-markdown",pretest:"npm run lint && npm run dts-check",test:"tap tests/*.js --100 -Rspec",prerelease:"npm test",release:"standard-version"},repository:{type:"git",url:"git://github.com/motdotla/dotenv.git"},funding:"https://github.com/motdotla/dotenv?sponsor=1",keywords:["dotenv","env",".env","environment","variables","config","settings"],readmeFilename:"README.md",license:"BSD-2-Clause",devDependencies:{"@definitelytyped/dtslint":"^0.0.133","@types/node":"^18.11.3",decache:"^4.6.1",sinon:"^14.0.1",standard:"^17.0.0","standard-markdown":"^7.1.0","standard-version":"^9.5.0",tap:"^16.3.0",tar:"^6.1.11",typescript:"^4.8.4"},engines:{node:">=12"},browser:{fs:!1}}});var Zz=_((xkt,Cf)=>{var Vz=ve("fs"),jT=ve("path"),tGe=ve("os"),rGe=ve("crypto"),nGe=zz(),YT=nGe.version,iGe=/(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;function sGe(t){let e={},r=t.toString();r=r.replace(/\r\n?/mg,`
-`);let o;for(;(o=iGe.exec(r))!=null;){let a=o[1],n=o[2]||"";n=n.trim();let u=n[0];n=n.replace(/^(['"`])([\s\S]*)\1$/mg,"$2"),u==='"'&&(n=n.replace(/\\n/g,`
-`),n=n.replace(/\\r/g,"\r")),e[a]=n}return e}function oGe(t){let e=Xz(t),r=bs.configDotenv({path:e});if(!r.parsed)throw new Error(`MISSING_DATA: Cannot parse ${e} for an unknown reason`);let o=Jz(t).split(","),a=o.length,n;for(let u=0;u<a;u++)try{let A=o[u].trim(),p=cGe(r,A);n=bs.decrypt(p.ciphertext,p.key);break}catch(A){if(u+1>=a)throw A}return bs.parse(n)}function aGe(t){console.log(`[dotenv@${YT}][INFO] ${t}`)}function lGe(t){console.log(`[dotenv@${YT}][WARN] ${t}`)}function GT(t){console.log(`[dotenv@${YT}][DEBUG] ${t}`)}function Jz(t){return t&&t.DOTENV_KEY&&t.DOTENV_KEY.length>0?t.DOTENV_KEY:process.env.DOTENV_KEY&&process.env.DOTENV_KEY.length>0?process.env.DOTENV_KEY:""}function cGe(t,e){let r;try{r=new URL(e)}catch(A){throw A.code==="ERR_INVALID_URL"?new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenv.org/vault/.env.vault?environment=development"):A}let o=r.password;if(!o)throw new Error("INVALID_DOTENV_KEY: Missing key part");let a=r.searchParams.get("environment");if(!a)throw new Error("INVALID_DOTENV_KEY: Missing environment part");let n=`DOTENV_VAULT_${a.toUpperCase()}`,u=t.parsed[n];if(!u)throw new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${n} in your .env.vault file.`);return{ciphertext:u,key:o}}function Xz(t){let e=jT.resolve(process.cwd(),".env");return t&&t.path&&t.path.length>0&&(e=t.path),e.endsWith(".vault")?e:`${e}.vault`}function uGe(t){return t[0]==="~"?jT.join(tGe.homedir(),t.slice(1)):t}function AGe(t){aGe("Loading env from encrypted .env.vault");let e=bs._parseVault(t),r=process.env;return t&&t.processEnv!=null&&(r=t.processEnv),bs.populate(r,e,t),{parsed:e}}function fGe(t){let e=jT.resolve(process.cwd(),".env"),r="utf8",o=Boolean(t&&t.debug);t&&(t.path!=null&&(e=uGe(t.path)),t.encoding!=null&&(r=t.encoding));try{let a=bs.parse(Vz.readFileSync(e,{encoding:r})),n=process.env;return t&&t.processEnv!=null&&(n=t.processEnv),bs.populate(n,a,t),{parsed:a}}catch(a){return o&&GT(`Failed to load ${e} ${a.message}`),{error:a}}}function pGe(t){let e=Xz(t);return Jz(t).length===0?bs.configDotenv(t):Vz.existsSync(e)?bs._configVault(t):(lGe(`You set DOTENV_KEY but you are missing a .env.vault file at ${e}. Did you forget to build it?`),bs.configDotenv(t))}function hGe(t,e){let r=Buffer.from(e.slice(-64),"hex"),o=Buffer.from(t,"base64"),a=o.slice(0,12),n=o.slice(-16);o=o.slice(12,-16);try{let u=rGe.createDecipheriv("aes-256-gcm",r,a);return u.setAuthTag(n),`${u.update(o)}${u.final()}`}catch(u){let A=u instanceof RangeError,p=u.message==="Invalid key length",h=u.message==="Unsupported state or unable to authenticate data";if(A||p){let E="INVALID_DOTENV_KEY: It must be 64 characters long (or more)";throw new Error(E)}else if(h){let E="DECRYPTION_FAILED: Please check your DOTENV_KEY";throw new Error(E)}else throw console.error("Error: ",u.code),console.error("Error: ",u.message),u}}function gGe(t,e,r={}){let o=Boolean(r&&r.debug),a=Boolean(r&&r.override);if(typeof e!="object")throw new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");for(let n of Object.keys(e))Object.prototype.hasOwnProperty.call(t,n)?(a===!0&&(t[n]=e[n]),o&&GT(a===!0?`"${n}" is already defined and WAS overwritten`:`"${n}" is already defined and was NOT overwritten`)):t[n]=e[n]}var bs={configDotenv:fGe,_configVault:AGe,_parseVault:oGe,config:pGe,decrypt:hGe,parse:sGe,populate:gGe};Cf.exports.configDotenv=bs.configDotenv;Cf.exports._configVault=bs._configVault;Cf.exports._parseVault=bs._parseVault;Cf.exports.config=bs.config;Cf.exports.decrypt=bs.decrypt;Cf.exports.parse=bs.parse;Cf.exports.populate=bs.populate;Cf.exports=bs});var eV=_((kkt,$z)=>{"use strict";$z.exports=(t,...e)=>new Promise(r=>{r(t(...e))})});var sd=_((Qkt,WT)=>{"use strict";var dGe=eV(),tV=t=>{if(t<1)throw new TypeError("Expected `concurrency` to be a number from 1 and up");let e=[],r=0,o=()=>{r--,e.length>0&&e.shift()()},a=(A,p,...h)=>{r++;let E=dGe(A,...h);p(E),E.then(o,o)},n=(A,p,...h)=>{r<t?a(A,p,...h):e.push(a.bind(null,A,p,...h))},u=(A,...p)=>new Promise(h=>n(A,h,...p));return Object.defineProperties(u,{activeCount:{get:()=>r},pendingCount:{get:()=>e.length}}),u};WT.exports=tV;WT.exports.default=tV});function Ku(t){return`YN${t.toString(10).padStart(4,"0")}`}function AP(t){let e=Number(t.slice(2));if(typeof wr[e]>"u")throw new Error(`Unknown message name: "${t}"`);return e}var wr,fP=Et(()=>{wr=(Oe=>(Oe[Oe.UNNAMED=0]="UNNAMED",Oe[Oe.EXCEPTION=1]="EXCEPTION",Oe[Oe.MISSING_PEER_DEPENDENCY=2]="MISSING_PEER_DEPENDENCY",Oe[Oe.CYCLIC_DEPENDENCIES=3]="CYCLIC_DEPENDENCIES",Oe[Oe.DISABLED_BUILD_SCRIPTS=4]="DISABLED_BUILD_SCRIPTS",Oe[Oe.BUILD_DISABLED=5]="BUILD_DISABLED",Oe[Oe.SOFT_LINK_BUILD=6]="SOFT_LINK_BUILD",Oe[Oe.MUST_BUILD=7]="MUST_BUILD",Oe[Oe.MUST_REBUILD=8]="MUST_REBUILD",Oe[Oe.BUILD_FAILED=9]="BUILD_FAILED",Oe[Oe.RESOLVER_NOT_FOUND=10]="RESOLVER_NOT_FOUND",Oe[Oe.FETCHER_NOT_FOUND=11]="FETCHER_NOT_FOUND",Oe[Oe.LINKER_NOT_FOUND=12]="LINKER_NOT_FOUND",Oe[Oe.FETCH_NOT_CACHED=13]="FETCH_NOT_CACHED",Oe[Oe.YARN_IMPORT_FAILED=14]="YARN_IMPORT_FAILED",Oe[Oe.REMOTE_INVALID=15]="REMOTE_INVALID",Oe[Oe.REMOTE_NOT_FOUND=16]="REMOTE_NOT_FOUND",Oe[Oe.RESOLUTION_PACK=17]="RESOLUTION_PACK",Oe[Oe.CACHE_CHECKSUM_MISMATCH=18]="CACHE_CHECKSUM_MISMATCH",Oe[Oe.UNUSED_CACHE_ENTRY=19]="UNUSED_CACHE_ENTRY",Oe[Oe.MISSING_LOCKFILE_ENTRY=20]="MISSING_LOCKFILE_ENTRY",Oe[Oe.WORKSPACE_NOT_FOUND=21]="WORKSPACE_NOT_FOUND",Oe[Oe.TOO_MANY_MATCHING_WORKSPACES=22]="TOO_MANY_MATCHING_WORKSPACES",Oe[Oe.CONSTRAINTS_MISSING_DEPENDENCY=23]="CONSTRAINTS_MISSING_DEPENDENCY",Oe[Oe.CONSTRAINTS_INCOMPATIBLE_DEPENDENCY=24]="CONSTRAINTS_INCOMPATIBLE_DEPENDENCY",Oe[Oe.CONSTRAINTS_EXTRANEOUS_DEPENDENCY=25]="CONSTRAINTS_EXTRANEOUS_DEPENDENCY",Oe[Oe.CONSTRAINTS_INVALID_DEPENDENCY=26]="CONSTRAINTS_INVALID_DEPENDENCY",Oe[Oe.CANT_SUGGEST_RESOLUTIONS=27]="CANT_SUGGEST_RESOLUTIONS",Oe[Oe.FROZEN_LOCKFILE_EXCEPTION=28]="FROZEN_LOCKFILE_EXCEPTION",Oe[Oe.CROSS_DRIVE_VIRTUAL_LOCAL=29]="CROSS_DRIVE_VIRTUAL_LOCAL",Oe[Oe.FETCH_FAILED=30]="FETCH_FAILED",Oe[Oe.DANGEROUS_NODE_MODULES=31]="DANGEROUS_NODE_MODULES",Oe[Oe.NODE_GYP_INJECTED=32]="NODE_GYP_INJECTED",Oe[Oe.AUTHENTICATION_NOT_FOUND=33]="AUTHENTICATION_NOT_FOUND",Oe[Oe.INVALID_CONFIGURATION_KEY=34]="INVALID_CONFIGURATION_KEY",Oe[Oe.NETWORK_ERROR=35]="NETWORK_ERROR",Oe[Oe.LIFECYCLE_SCRIPT=36]="LIFECYCLE_SCRIPT",Oe[Oe.CONSTRAINTS_MISSING_FIELD=37]="CONSTRAINTS_MISSING_FIELD",Oe[Oe.CONSTRAINTS_INCOMPATIBLE_FIELD=38]="CONSTRAINTS_INCOMPATIBLE_FIELD",Oe[Oe.CONSTRAINTS_EXTRANEOUS_FIELD=39]="CONSTRAINTS_EXTRANEOUS_FIELD",Oe[Oe.CONSTRAINTS_INVALID_FIELD=40]="CONSTRAINTS_INVALID_FIELD",Oe[Oe.AUTHENTICATION_INVALID=41]="AUTHENTICATION_INVALID",Oe[Oe.PROLOG_UNKNOWN_ERROR=42]="PROLOG_UNKNOWN_ERROR",Oe[Oe.PROLOG_SYNTAX_ERROR=43]="PROLOG_SYNTAX_ERROR",Oe[Oe.PROLOG_EXISTENCE_ERROR=44]="PROLOG_EXISTENCE_ERROR",Oe[Oe.STACK_OVERFLOW_RESOLUTION=45]="STACK_OVERFLOW_RESOLUTION",Oe[Oe.AUTOMERGE_FAILED_TO_PARSE=46]="AUTOMERGE_FAILED_TO_PARSE",Oe[Oe.AUTOMERGE_IMMUTABLE=47]="AUTOMERGE_IMMUTABLE",Oe[Oe.AUTOMERGE_SUCCESS=48]="AUTOMERGE_SUCCESS",Oe[Oe.AUTOMERGE_REQUIRED=49]="AUTOMERGE_REQUIRED",Oe[Oe.DEPRECATED_CLI_SETTINGS=50]="DEPRECATED_CLI_SETTINGS",Oe[Oe.PLUGIN_NAME_NOT_FOUND=51]="PLUGIN_NAME_NOT_FOUND",Oe[Oe.INVALID_PLUGIN_REFERENCE=52]="INVALID_PLUGIN_REFERENCE",Oe[Oe.CONSTRAINTS_AMBIGUITY=53]="CONSTRAINTS_AMBIGUITY",Oe[Oe.CACHE_OUTSIDE_PROJECT=54]="CACHE_OUTSIDE_PROJECT",Oe[Oe.IMMUTABLE_INSTALL=55]="IMMUTABLE_INSTALL",Oe[Oe.IMMUTABLE_CACHE=56]="IMMUTABLE_CACHE",Oe[Oe.INVALID_MANIFEST=57]="INVALID_MANIFEST",Oe[Oe.PACKAGE_PREPARATION_FAILED=58]="PACKAGE_PREPARATION_FAILED",Oe[Oe.INVALID_RANGE_PEER_DEPENDENCY=59]="INVALID_RANGE_PEER_DEPENDENCY",Oe[Oe.INCOMPATIBLE_PEER_DEPENDENCY=60]="INCOMPATIBLE_PEER_DEPENDENCY",Oe[Oe.DEPRECATED_PACKAGE=61]="DEPRECATED_PACKAGE",Oe[Oe.INCOMPATIBLE_OS=62]="INCOMPATIBLE_OS",Oe[Oe.INCOMPATIBLE_CPU=63]="INCOMPATIBLE_CPU",Oe[Oe.FROZEN_ARTIFACT_EXCEPTION=64]="FROZEN_ARTIFACT_EXCEPTION",Oe[Oe.TELEMETRY_NOTICE=65]="TELEMETRY_NOTICE",Oe[Oe.PATCH_HUNK_FAILED=66]="PATCH_HUNK_FAILED",Oe[Oe.INVALID_CONFIGURATION_VALUE=67]="INVALID_CONFIGURATION_VALUE",Oe[Oe.UNUSED_PACKAGE_EXTENSION=68]="UNUSED_PACKAGE_EXTENSION",Oe[Oe.REDUNDANT_PACKAGE_EXTENSION=69]="REDUNDANT_PACKAGE_EXTENSION",Oe[Oe.AUTO_NM_SUCCESS=70]="AUTO_NM_SUCCESS",Oe[Oe.NM_CANT_INSTALL_EXTERNAL_SOFT_LINK=71]="NM_CANT_INSTALL_EXTERNAL_SOFT_LINK",Oe[Oe.NM_PRESERVE_SYMLINKS_REQUIRED=72]="NM_PRESERVE_SYMLINKS_REQUIRED",Oe[Oe.UPDATE_LOCKFILE_ONLY_SKIP_LINK=73]="UPDATE_LOCKFILE_ONLY_SKIP_LINK",Oe[Oe.NM_HARDLINKS_MODE_DOWNGRADED=74]="NM_HARDLINKS_MODE_DOWNGRADED",Oe[Oe.PROLOG_INSTANTIATION_ERROR=75]="PROLOG_INSTANTIATION_ERROR",Oe[Oe.INCOMPATIBLE_ARCHITECTURE=76]="INCOMPATIBLE_ARCHITECTURE",Oe[Oe.GHOST_ARCHITECTURE=77]="GHOST_ARCHITECTURE",Oe[Oe.RESOLUTION_MISMATCH=78]="RESOLUTION_MISMATCH",Oe[Oe.PROLOG_LIMIT_EXCEEDED=79]="PROLOG_LIMIT_EXCEEDED",Oe[Oe.NETWORK_DISABLED=80]="NETWORK_DISABLED",Oe[Oe.NETWORK_UNSAFE_HTTP=81]="NETWORK_UNSAFE_HTTP",Oe[Oe.RESOLUTION_FAILED=82]="RESOLUTION_FAILED",Oe[Oe.AUTOMERGE_GIT_ERROR=83]="AUTOMERGE_GIT_ERROR",Oe[Oe.CONSTRAINTS_CHECK_FAILED=84]="CONSTRAINTS_CHECK_FAILED",Oe[Oe.UPDATED_RESOLUTION_RECORD=85]="UPDATED_RESOLUTION_RECORD",Oe[Oe.EXPLAIN_PEER_DEPENDENCIES_CTA=86]="EXPLAIN_PEER_DEPENDENCIES_CTA",Oe[Oe.MIGRATION_SUCCESS=87]="MIGRATION_SUCCESS",Oe[Oe.VERSION_NOTICE=88]="VERSION_NOTICE",Oe[Oe.TIPS_NOTICE=89]="TIPS_NOTICE",Oe[Oe.OFFLINE_MODE_ENABLED=90]="OFFLINE_MODE_ENABLED",Oe))(wr||{})});var gI=_((Rkt,rV)=>{var mGe="2.0.0",yGe=Number.MAX_SAFE_INTEGER||9007199254740991,EGe=16,CGe=256-6,wGe=["major","premajor","minor","preminor","patch","prepatch","prerelease"];rV.exports={MAX_LENGTH:256,MAX_SAFE_COMPONENT_LENGTH:EGe,MAX_SAFE_BUILD_LENGTH:CGe,MAX_SAFE_INTEGER:yGe,RELEASE_TYPES:wGe,SEMVER_SPEC_VERSION:mGe,FLAG_INCLUDE_PRERELEASE:1,FLAG_LOOSE:2}});var dI=_((Tkt,nV)=>{var IGe=typeof process=="object"&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?(...t)=>console.error("SEMVER",...t):()=>{};nV.exports=IGe});var vy=_((wf,iV)=>{var{MAX_SAFE_COMPONENT_LENGTH:KT,MAX_SAFE_BUILD_LENGTH:BGe,MAX_LENGTH:vGe}=gI(),DGe=dI();wf=iV.exports={};var PGe=wf.re=[],SGe=wf.safeRe=[],lr=wf.src=[],cr=wf.t={},bGe=0,zT="[a-zA-Z0-9-]",xGe=[["\\s",1],["\\d",vGe],[zT,BGe]],kGe=t=>{for(let[e,r]of xGe)t=t.split(`${e}*`).join(`${e}{0,${r}}`).split(`${e}+`).join(`${e}{1,${r}}`);return t},Vr=(t,e,r)=>{let o=kGe(e),a=bGe++;DGe(t,a,e),cr[t]=a,lr[a]=e,PGe[a]=new RegExp(e,r?"g":void 0),SGe[a]=new RegExp(o,r?"g":void 0)};Vr("NUMERICIDENTIFIER","0|[1-9]\\d*");Vr("NUMERICIDENTIFIERLOOSE","\\d+");Vr("NONNUMERICIDENTIFIER",`\\d*[a-zA-Z-]${zT}*`);Vr("MAINVERSION",`(${lr[cr.NUMERICIDENTIFIER]})\\.(${lr[cr.NUMERICIDENTIFIER]})\\.(${lr[cr.NUMERICIDENTIFIER]})`);Vr("MAINVERSIONLOOSE",`(${lr[cr.NUMERICIDENTIFIERLOOSE]})\\.(${lr[cr.NUMERICIDENTIFIERLOOSE]})\\.(${lr[cr.NUMERICIDENTIFIERLOOSE]})`);Vr("PRERELEASEIDENTIFIER",`(?:${lr[cr.NUMERICIDENTIFIER]}|${lr[cr.NONNUMERICIDENTIFIER]})`);Vr("PRERELEASEIDENTIFIERLOOSE",`(?:${lr[cr.NUMERICIDENTIFIERLOOSE]}|${lr[cr.NONNUMERICIDENTIFIER]})`);Vr("PRERELEASE",`(?:-(${lr[cr.PRERELEASEIDENTIFIER]}(?:\\.${lr[cr.PRERELEASEIDENTIFIER]})*))`);Vr("PRERELEASELOOSE",`(?:-?(${lr[cr.PRERELEASEIDENTIFIERLOOSE]}(?:\\.${lr[cr.PRERELEASEIDENTIFIERLOOSE]})*))`);Vr("BUILDIDENTIFIER",`${zT}+`);Vr("BUILD",`(?:\\+(${lr[cr.BUILDIDENTIFIER]}(?:\\.${lr[cr.BUILDIDENTIFIER]})*))`);Vr("FULLPLAIN",`v?${lr[cr.MAINVERSION]}${lr[cr.PRERELEASE]}?${lr[cr.BUILD]}?`);Vr("FULL",`^${lr[cr.FULLPLAIN]}$`);Vr("LOOSEPLAIN",`[v=\\s]*${lr[cr.MAINVERSIONLOOSE]}${lr[cr.PRERELEASELOOSE]}?${lr[cr.BUILD]}?`);Vr("LOOSE",`^${lr[cr.LOOSEPLAIN]}$`);Vr("GTLT","((?:<|>)?=?)");Vr("XRANGEIDENTIFIERLOOSE",`${lr[cr.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`);Vr("XRANGEIDENTIFIER",`${lr[cr.NUMERICIDENTIFIER]}|x|X|\\*`);Vr("XRANGEPLAIN",`[v=\\s]*(${lr[cr.XRANGEIDENTIFIER]})(?:\\.(${lr[cr.XRANGEIDENTIFIER]})(?:\\.(${lr[cr.XRANGEIDENTIFIER]})(?:${lr[cr.PRERELEASE]})?${lr[cr.BUILD]}?)?)?`);Vr("XRANGEPLAINLOOSE",`[v=\\s]*(${lr[cr.XRANGEIDENTIFIERLOOSE]})(?:\\.(${lr[cr.XRANGEIDENTIFIERLOOSE]})(?:\\.(${lr[cr.XRANGEIDENTIFIERLOOSE]})(?:${lr[cr.PRERELEASELOOSE]})?${lr[cr.BUILD]}?)?)?`);Vr("XRANGE",`^${lr[cr.GTLT]}\\s*${lr[cr.XRANGEPLAIN]}$`);Vr("XRANGELOOSE",`^${lr[cr.GTLT]}\\s*${lr[cr.XRANGEPLAINLOOSE]}$`);Vr("COERCE",`(^|[^\\d])(\\d{1,${KT}})(?:\\.(\\d{1,${KT}}))?(?:\\.(\\d{1,${KT}}))?(?:$|[^\\d])`);Vr("COERCERTL",lr[cr.COERCE],!0);Vr("LONETILDE","(?:~>?)");Vr("TILDETRIM",`(\\s*)${lr[cr.LONETILDE]}\\s+`,!0);wf.tildeTrimReplace="$1~";Vr("TILDE",`^${lr[cr.LONETILDE]}${lr[cr.XRANGEPLAIN]}$`);Vr("TILDELOOSE",`^${lr[cr.LONETILDE]}${lr[cr.XRANGEPLAINLOOSE]}$`);Vr("LONECARET","(?:\\^)");Vr("CARETTRIM",`(\\s*)${lr[cr.LONECARET]}\\s+`,!0);wf.caretTrimReplace="$1^";Vr("CARET",`^${lr[cr.LONECARET]}${lr[cr.XRANGEPLAIN]}$`);Vr("CARETLOOSE",`^${lr[cr.LONECARET]}${lr[cr.XRANGEPLAINLOOSE]}$`);Vr("COMPARATORLOOSE",`^${lr[cr.GTLT]}\\s*(${lr[cr.LOOSEPLAIN]})$|^$`);Vr("COMPARATOR",`^${lr[cr.GTLT]}\\s*(${lr[cr.FULLPLAIN]})$|^$`);Vr("COMPARATORTRIM",`(\\s*)${lr[cr.GTLT]}\\s*(${lr[cr.LOOSEPLAIN]}|${lr[cr.XRANGEPLAIN]})`,!0);wf.comparatorTrimReplace="$1$2$3";Vr("HYPHENRANGE",`^\\s*(${lr[cr.XRANGEPLAIN]})\\s+-\\s+(${lr[cr.XRANGEPLAIN]})\\s*$`);Vr("HYPHENRANGELOOSE",`^\\s*(${lr[cr.XRANGEPLAINLOOSE]})\\s+-\\s+(${lr[cr.XRANGEPLAINLOOSE]})\\s*$`);Vr("STAR","(<|>)?=?\\s*\\*");Vr("GTE0","^\\s*>=\\s*0\\.0\\.0\\s*$");Vr("GTE0PRE","^\\s*>=\\s*0\\.0\\.0-0\\s*$")});var pP=_((Lkt,sV)=>{var QGe=Object.freeze({loose:!0}),FGe=Object.freeze({}),RGe=t=>t?typeof t!="object"?QGe:t:FGe;sV.exports=RGe});var VT=_((Nkt,lV)=>{var oV=/^[0-9]+$/,aV=(t,e)=>{let r=oV.test(t),o=oV.test(e);return r&&o&&(t=+t,e=+e),t===e?0:r&&!o?-1:o&&!r?1:t<e?-1:1},TGe=(t,e)=>aV(e,t);lV.exports={compareIdentifiers:aV,rcompareIdentifiers:TGe}});var Po=_((Okt,fV)=>{var hP=dI(),{MAX_LENGTH:cV,MAX_SAFE_INTEGER:gP}=gI(),{safeRe:uV,t:AV}=vy(),LGe=pP(),{compareIdentifiers:Dy}=VT(),rl=class{constructor(e,r){if(r=LGe(r),e instanceof rl){if(e.loose===!!r.loose&&e.includePrerelease===!!r.includePrerelease)return e;e=e.version}else if(typeof e!="string")throw new TypeError(`Invalid version. Must be a string. Got type "${typeof e}".`);if(e.length>cV)throw new TypeError(`version is longer than ${cV} characters`);hP("SemVer",e,r),this.options=r,this.loose=!!r.loose,this.includePrerelease=!!r.includePrerelease;let o=e.trim().match(r.loose?uV[AV.LOOSE]:uV[AV.FULL]);if(!o)throw new TypeError(`Invalid Version: ${e}`);if(this.raw=e,this.major=+o[1],this.minor=+o[2],this.patch=+o[3],this.major>gP||this.major<0)throw new TypeError("Invalid major version");if(this.minor>gP||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>gP||this.patch<0)throw new TypeError("Invalid patch version");o[4]?this.prerelease=o[4].split(".").map(a=>{if(/^[0-9]+$/.test(a)){let n=+a;if(n>=0&&n<gP)return n}return a}):this.prerelease=[],this.build=o[5]?o[5].split("."):[],this.format()}format(){return this.version=`${this.major}.${this.minor}.${this.patch}`,this.prerelease.length&&(this.version+=`-${this.prerelease.join(".")}`),this.version}toString(){return this.version}compare(e){if(hP("SemVer.compare",this.version,this.options,e),!(e instanceof rl)){if(typeof e=="string"&&e===this.version)return 0;e=new rl(e,this.options)}return e.version===this.version?0:this.compareMain(e)||this.comparePre(e)}compareMain(e){return e instanceof rl||(e=new rl(e,this.options)),Dy(this.major,e.major)||Dy(this.minor,e.minor)||Dy(this.patch,e.patch)}comparePre(e){if(e instanceof rl||(e=new rl(e,this.options)),this.prerelease.length&&!e.prerelease.length)return-1;if(!this.prerelease.length&&e.prerelease.length)return 1;if(!this.prerelease.length&&!e.prerelease.length)return 0;let r=0;do{let o=this.prerelease[r],a=e.prerelease[r];if(hP("prerelease compare",r,o,a),o===void 0&&a===void 0)return 0;if(a===void 0)return 1;if(o===void 0)return-1;if(o===a)continue;return Dy(o,a)}while(++r)}compareBuild(e){e instanceof rl||(e=new rl(e,this.options));let r=0;do{let o=this.build[r],a=e.build[r];if(hP("prerelease compare",r,o,a),o===void 0&&a===void 0)return 0;if(a===void 0)return 1;if(o===void 0)return-1;if(o===a)continue;return Dy(o,a)}while(++r)}inc(e,r,o){switch(e){case"premajor":this.prerelease.length=0,this.patch=0,this.minor=0,this.major++,this.inc("pre",r,o);break;case"preminor":this.prerelease.length=0,this.patch=0,this.minor++,this.inc("pre",r,o);break;case"prepatch":this.prerelease.length=0,this.inc("patch",r,o),this.inc("pre",r,o);break;case"prerelease":this.prerelease.length===0&&this.inc("patch",r,o),this.inc("pre",r,o);break;case"major":(this.minor!==0||this.patch!==0||this.prerelease.length===0)&&this.major++,this.minor=0,this.patch=0,this.prerelease=[];break;case"minor":(this.patch!==0||this.prerelease.length===0)&&this.minor++,this.patch=0,this.prerelease=[];break;case"patch":this.prerelease.length===0&&this.patch++,this.prerelease=[];break;case"pre":{let a=Number(o)?1:0;if(!r&&o===!1)throw new Error("invalid increment argument: identifier is empty");if(this.prerelease.length===0)this.prerelease=[a];else{let n=this.prerelease.length;for(;--n>=0;)typeof this.prerelease[n]=="number"&&(this.prerelease[n]++,n=-2);if(n===-1){if(r===this.prerelease.join(".")&&o===!1)throw new Error("invalid increment argument: identifier already exists");this.prerelease.push(a)}}if(r){let n=[r,a];o===!1&&(n=[r]),Dy(this.prerelease[0],r)===0?isNaN(this.prerelease[1])&&(this.prerelease=n):this.prerelease=n}break}default:throw new Error(`invalid increment argument: ${e}`)}return this.raw=this.format(),this.build.length&&(this.raw+=`+${this.build.join(".")}`),this}};fV.exports=rl});var od=_((Mkt,hV)=>{var pV=Po(),NGe=(t,e,r=!1)=>{if(t instanceof pV)return t;try{return new pV(t,e)}catch(o){if(!r)return null;throw o}};hV.exports=NGe});var dV=_((Ukt,gV)=>{var OGe=od(),MGe=(t,e)=>{let r=OGe(t,e);return r?r.version:null};gV.exports=MGe});var yV=_((_kt,mV)=>{var UGe=od(),_Ge=(t,e)=>{let r=UGe(t.trim().replace(/^[=v]+/,""),e);return r?r.version:null};mV.exports=_Ge});var wV=_((Hkt,CV)=>{var EV=Po(),HGe=(t,e,r,o,a)=>{typeof r=="string"&&(a=o,o=r,r=void 0);try{return new EV(t instanceof EV?t.version:t,r).inc(e,o,a).version}catch{return null}};CV.exports=HGe});var vV=_((qkt,BV)=>{var IV=od(),qGe=(t,e)=>{let r=IV(t,null,!0),o=IV(e,null,!0),a=r.compare(o);if(a===0)return null;let n=a>0,u=n?r:o,A=n?o:r,p=!!u.prerelease.length;if(!!A.prerelease.length&&!p)return!A.patch&&!A.minor?"major":u.patch?"patch":u.minor?"minor":"major";let E=p?"pre":"";return r.major!==o.major?E+"major":r.minor!==o.minor?E+"minor":r.patch!==o.patch?E+"patch":"prerelease"};BV.exports=qGe});var PV=_((Gkt,DV)=>{var GGe=Po(),jGe=(t,e)=>new GGe(t,e).major;DV.exports=jGe});var bV=_((jkt,SV)=>{var YGe=Po(),WGe=(t,e)=>new YGe(t,e).minor;SV.exports=WGe});var kV=_((Ykt,xV)=>{var KGe=Po(),zGe=(t,e)=>new KGe(t,e).patch;xV.exports=zGe});var FV=_((Wkt,QV)=>{var VGe=od(),JGe=(t,e)=>{let r=VGe(t,e);return r&&r.prerelease.length?r.prerelease:null};QV.exports=JGe});var Ol=_((Kkt,TV)=>{var RV=Po(),XGe=(t,e,r)=>new RV(t,r).compare(new RV(e,r));TV.exports=XGe});var NV=_((zkt,LV)=>{var ZGe=Ol(),$Ge=(t,e,r)=>ZGe(e,t,r);LV.exports=$Ge});var MV=_((Vkt,OV)=>{var eje=Ol(),tje=(t,e)=>eje(t,e,!0);OV.exports=tje});var dP=_((Jkt,_V)=>{var UV=Po(),rje=(t,e,r)=>{let o=new UV(t,r),a=new UV(e,r);return o.compare(a)||o.compareBuild(a)};_V.exports=rje});var qV=_((Xkt,HV)=>{var nje=dP(),ije=(t,e)=>t.sort((r,o)=>nje(r,o,e));HV.exports=ije});var jV=_((Zkt,GV)=>{var sje=dP(),oje=(t,e)=>t.sort((r,o)=>sje(o,r,e));GV.exports=oje});var mI=_(($kt,YV)=>{var aje=Ol(),lje=(t,e,r)=>aje(t,e,r)>0;YV.exports=lje});var mP=_((eQt,WV)=>{var cje=Ol(),uje=(t,e,r)=>cje(t,e,r)<0;WV.exports=uje});var JT=_((tQt,KV)=>{var Aje=Ol(),fje=(t,e,r)=>Aje(t,e,r)===0;KV.exports=fje});var XT=_((rQt,zV)=>{var pje=Ol(),hje=(t,e,r)=>pje(t,e,r)!==0;zV.exports=hje});var yP=_((nQt,VV)=>{var gje=Ol(),dje=(t,e,r)=>gje(t,e,r)>=0;VV.exports=dje});var EP=_((iQt,JV)=>{var mje=Ol(),yje=(t,e,r)=>mje(t,e,r)<=0;JV.exports=yje});var ZT=_((sQt,XV)=>{var Eje=JT(),Cje=XT(),wje=mI(),Ije=yP(),Bje=mP(),vje=EP(),Dje=(t,e,r,o)=>{switch(e){case"===":return typeof t=="object"&&(t=t.version),typeof r=="object"&&(r=r.version),t===r;case"!==":return typeof t=="object"&&(t=t.version),typeof r=="object"&&(r=r.version),t!==r;case"":case"=":case"==":return Eje(t,r,o);case"!=":return Cje(t,r,o);case">":return wje(t,r,o);case">=":return Ije(t,r,o);case"<":return Bje(t,r,o);case"<=":return vje(t,r,o);default:throw new TypeError(`Invalid operator: ${e}`)}};XV.exports=Dje});var $V=_((oQt,ZV)=>{var Pje=Po(),Sje=od(),{safeRe:CP,t:wP}=vy(),bje=(t,e)=>{if(t instanceof Pje)return t;if(typeof t=="number"&&(t=String(t)),typeof t!="string")return null;e=e||{};let r=null;if(!e.rtl)r=t.match(CP[wP.COERCE]);else{let o;for(;(o=CP[wP.COERCERTL].exec(t))&&(!r||r.index+r[0].length!==t.length);)(!r||o.index+o[0].length!==r.index+r[0].length)&&(r=o),CP[wP.COERCERTL].lastIndex=o.index+o[1].length+o[2].length;CP[wP.COERCERTL].lastIndex=-1}return r===null?null:Sje(`${r[2]}.${r[3]||"0"}.${r[4]||"0"}`,e)};ZV.exports=bje});var tJ=_((aQt,eJ)=>{"use strict";eJ.exports=function(t){t.prototype[Symbol.iterator]=function*(){for(let e=this.head;e;e=e.next)yield e.value}}});var IP=_((lQt,rJ)=>{"use strict";rJ.exports=Cn;Cn.Node=ad;Cn.create=Cn;function Cn(t){var e=this;if(e instanceof Cn||(e=new Cn),e.tail=null,e.head=null,e.length=0,t&&typeof t.forEach=="function")t.forEach(function(a){e.push(a)});else if(arguments.length>0)for(var r=0,o=arguments.length;r<o;r++)e.push(arguments[r]);return e}Cn.prototype.removeNode=function(t){if(t.list!==this)throw new Error("removing node which does not belong to this list");var e=t.next,r=t.prev;return e&&(e.prev=r),r&&(r.next=e),t===this.head&&(this.head=e),t===this.tail&&(this.tail=r),t.list.length--,t.next=null,t.prev=null,t.list=null,e};Cn.prototype.unshiftNode=function(t){if(t!==this.head){t.list&&t.list.removeNode(t);var e=this.head;t.list=this,t.next=e,e&&(e.prev=t),this.head=t,this.tail||(this.tail=t),this.length++}};Cn.prototype.pushNode=function(t){if(t!==this.tail){t.list&&t.list.removeNode(t);var e=this.tail;t.list=this,t.prev=e,e&&(e.next=t),this.tail=t,this.head||(this.head=t),this.length++}};Cn.prototype.push=function(){for(var t=0,e=arguments.length;t<e;t++)kje(this,arguments[t]);return this.length};Cn.prototype.unshift=function(){for(var t=0,e=arguments.length;t<e;t++)Qje(this,arguments[t]);return this.length};Cn.prototype.pop=function(){if(!!this.tail){var t=this.tail.value;return this.tail=this.tail.prev,this.tail?this.tail.next=null:this.head=null,this.length--,t}};Cn.prototype.shift=function(){if(!!this.head){var t=this.head.value;return this.head=this.head.next,this.head?this.head.prev=null:this.tail=null,this.length--,t}};Cn.prototype.forEach=function(t,e){e=e||this;for(var r=this.head,o=0;r!==null;o++)t.call(e,r.value,o,this),r=r.next};Cn.prototype.forEachReverse=function(t,e){e=e||this;for(var r=this.tail,o=this.length-1;r!==null;o--)t.call(e,r.value,o,this),r=r.prev};Cn.prototype.get=function(t){for(var e=0,r=this.head;r!==null&&e<t;e++)r=r.next;if(e===t&&r!==null)return r.value};Cn.prototype.getReverse=function(t){for(var e=0,r=this.tail;r!==null&&e<t;e++)r=r.prev;if(e===t&&r!==null)return r.value};Cn.prototype.map=function(t,e){e=e||this;for(var r=new Cn,o=this.head;o!==null;)r.push(t.call(e,o.value,this)),o=o.next;return r};Cn.prototype.mapReverse=function(t,e){e=e||this;for(var r=new Cn,o=this.tail;o!==null;)r.push(t.call(e,o.value,this)),o=o.prev;return r};Cn.prototype.reduce=function(t,e){var r,o=this.head;if(arguments.length>1)r=e;else if(this.head)o=this.head.next,r=this.head.value;else throw new TypeError("Reduce of empty list with no initial value");for(var a=0;o!==null;a++)r=t(r,o.value,a),o=o.next;return r};Cn.prototype.reduceReverse=function(t,e){var r,o=this.tail;if(arguments.length>1)r=e;else if(this.tail)o=this.tail.prev,r=this.tail.value;else throw new TypeError("Reduce of empty list with no initial value");for(var a=this.length-1;o!==null;a--)r=t(r,o.value,a),o=o.prev;return r};Cn.prototype.toArray=function(){for(var t=new Array(this.length),e=0,r=this.head;r!==null;e++)t[e]=r.value,r=r.next;return t};Cn.prototype.toArrayReverse=function(){for(var t=new Array(this.length),e=0,r=this.tail;r!==null;e++)t[e]=r.value,r=r.prev;return t};Cn.prototype.slice=function(t,e){e=e||this.length,e<0&&(e+=this.length),t=t||0,t<0&&(t+=this.length);var r=new Cn;if(e<t||e<0)return r;t<0&&(t=0),e>this.length&&(e=this.length);for(var o=0,a=this.head;a!==null&&o<t;o++)a=a.next;for(;a!==null&&o<e;o++,a=a.next)r.push(a.value);return r};Cn.prototype.sliceReverse=function(t,e){e=e||this.length,e<0&&(e+=this.length),t=t||0,t<0&&(t+=this.length);var r=new Cn;if(e<t||e<0)return r;t<0&&(t=0),e>this.length&&(e=this.length);for(var o=this.length,a=this.tail;a!==null&&o>e;o--)a=a.prev;for(;a!==null&&o>t;o--,a=a.prev)r.push(a.value);return r};Cn.prototype.splice=function(t,e,...r){t>this.length&&(t=this.length-1),t<0&&(t=this.length+t);for(var o=0,a=this.head;a!==null&&o<t;o++)a=a.next;for(var n=[],o=0;a&&o<e;o++)n.push(a.value),a=this.removeNode(a);a===null&&(a=this.tail),a!==this.head&&a!==this.tail&&(a=a.prev);for(var o=0;o<r.length;o++)a=xje(this,a,r[o]);return n};Cn.prototype.reverse=function(){for(var t=this.head,e=this.tail,r=t;r!==null;r=r.prev){var o=r.prev;r.prev=r.next,r.next=o}return this.head=e,this.tail=t,this};function xje(t,e,r){var o=e===t.head?new ad(r,null,e,t):new ad(r,e,e.next,t);return o.next===null&&(t.tail=o),o.prev===null&&(t.head=o),t.length++,o}function kje(t,e){t.tail=new ad(e,t.tail,null,t),t.head||(t.head=t.tail),t.length++}function Qje(t,e){t.head=new ad(e,null,t.head,t),t.tail||(t.tail=t.head),t.length++}function ad(t,e,r,o){if(!(this instanceof ad))return new ad(t,e,r,o);this.list=o,this.value=t,e?(e.next=this,this.prev=e):this.prev=null,r?(r.prev=this,this.next=r):this.next=null}try{tJ()(Cn)}catch{}});var aJ=_((cQt,oJ)=>{"use strict";var Fje=IP(),ld=Symbol("max"),Bf=Symbol("length"),Py=Symbol("lengthCalculator"),EI=Symbol("allowStale"),cd=Symbol("maxAge"),If=Symbol("dispose"),nJ=Symbol("noDisposeOnSet"),xs=Symbol("lruList"),Uc=Symbol("cache"),sJ=Symbol("updateAgeOnGet"),$T=()=>1,tL=class{constructor(e){if(typeof e=="number"&&(e={max:e}),e||(e={}),e.max&&(typeof e.max!="number"||e.max<0))throw new TypeError("max must be a non-negative number");let r=this[ld]=e.max||1/0,o=e.length||$T;if(this[Py]=typeof o!="function"?$T:o,this[EI]=e.stale||!1,e.maxAge&&typeof e.maxAge!="number")throw new TypeError("maxAge must be a number");this[cd]=e.maxAge||0,this[If]=e.dispose,this[nJ]=e.noDisposeOnSet||!1,this[sJ]=e.updateAgeOnGet||!1,this.reset()}set max(e){if(typeof e!="number"||e<0)throw new TypeError("max must be a non-negative number");this[ld]=e||1/0,yI(this)}get max(){return this[ld]}set allowStale(e){this[EI]=!!e}get allowStale(){return this[EI]}set maxAge(e){if(typeof e!="number")throw new TypeError("maxAge must be a non-negative number");this[cd]=e,yI(this)}get maxAge(){return this[cd]}set lengthCalculator(e){typeof e!="function"&&(e=$T),e!==this[Py]&&(this[Py]=e,this[Bf]=0,this[xs].forEach(r=>{r.length=this[Py](r.value,r.key),this[Bf]+=r.length})),yI(this)}get lengthCalculator(){return this[Py]}get length(){return this[Bf]}get itemCount(){return this[xs].length}rforEach(e,r){r=r||this;for(let o=this[xs].tail;o!==null;){let a=o.prev;iJ(this,e,o,r),o=a}}forEach(e,r){r=r||this;for(let o=this[xs].head;o!==null;){let a=o.next;iJ(this,e,o,r),o=a}}keys(){return this[xs].toArray().map(e=>e.key)}values(){return this[xs].toArray().map(e=>e.value)}reset(){this[If]&&this[xs]&&this[xs].length&&this[xs].forEach(e=>this[If](e.key,e.value)),this[Uc]=new Map,this[xs]=new Fje,this[Bf]=0}dump(){return this[xs].map(e=>BP(this,e)?!1:{k:e.key,v:e.value,e:e.now+(e.maxAge||0)}).toArray().filter(e=>e)}dumpLru(){return this[xs]}set(e,r,o){if(o=o||this[cd],o&&typeof o!="number")throw new TypeError("maxAge must be a number");let a=o?Date.now():0,n=this[Py](r,e);if(this[Uc].has(e)){if(n>this[ld])return Sy(this,this[Uc].get(e)),!1;let p=this[Uc].get(e).value;return this[If]&&(this[nJ]||this[If](e,p.value)),p.now=a,p.maxAge=o,p.value=r,this[Bf]+=n-p.length,p.length=n,this.get(e),yI(this),!0}let u=new rL(e,r,n,a,o);return u.length>this[ld]?(this[If]&&this[If](e,r),!1):(this[Bf]+=u.length,this[xs].unshift(u),this[Uc].set(e,this[xs].head),yI(this),!0)}has(e){if(!this[Uc].has(e))return!1;let r=this[Uc].get(e).value;return!BP(this,r)}get(e){return eL(this,e,!0)}peek(e){return eL(this,e,!1)}pop(){let e=this[xs].tail;return e?(Sy(this,e),e.value):null}del(e){Sy(this,this[Uc].get(e))}load(e){this.reset();let r=Date.now();for(let o=e.length-1;o>=0;o--){let a=e[o],n=a.e||0;if(n===0)this.set(a.k,a.v);else{let u=n-r;u>0&&this.set(a.k,a.v,u)}}}prune(){this[Uc].forEach((e,r)=>eL(this,r,!1))}},eL=(t,e,r)=>{let o=t[Uc].get(e);if(o){let a=o.value;if(BP(t,a)){if(Sy(t,o),!t[EI])return}else r&&(t[sJ]&&(o.value.now=Date.now()),t[xs].unshiftNode(o));return a.value}},BP=(t,e)=>{if(!e||!e.maxAge&&!t[cd])return!1;let r=Date.now()-e.now;return e.maxAge?r>e.maxAge:t[cd]&&r>t[cd]},yI=t=>{if(t[Bf]>t[ld])for(let e=t[xs].tail;t[Bf]>t[ld]&&e!==null;){let r=e.prev;Sy(t,e),e=r}},Sy=(t,e)=>{if(e){let r=e.value;t[If]&&t[If](r.key,r.value),t[Bf]-=r.length,t[Uc].delete(r.key),t[xs].removeNode(e)}},rL=class{constructor(e,r,o,a,n){this.key=e,this.value=r,this.length=o,this.now=a,this.maxAge=n||0}},iJ=(t,e,r,o)=>{let a=r.value;BP(t,a)&&(Sy(t,r),t[EI]||(a=void 0)),a&&e.call(o,a.value,a.key,t)};oJ.exports=tL});var Ml=_((uQt,AJ)=>{var ud=class{constructor(e,r){if(r=Tje(r),e instanceof ud)return e.loose===!!r.loose&&e.includePrerelease===!!r.includePrerelease?e:new ud(e.raw,r);if(e instanceof nL)return this.raw=e.value,this.set=[[e]],this.format(),this;if(this.options=r,this.loose=!!r.loose,this.includePrerelease=!!r.includePrerelease,this.raw=e.trim().split(/\s+/).join(" "),this.set=this.raw.split("||").map(o=>this.parseRange(o.trim())).filter(o=>o.length),!this.set.length)throw new TypeError(`Invalid SemVer Range: ${this.raw}`);if(this.set.length>1){let o=this.set[0];if(this.set=this.set.filter(a=>!cJ(a[0])),this.set.length===0)this.set=[o];else if(this.set.length>1){for(let a of this.set)if(a.length===1&&Hje(a[0])){this.set=[a];break}}}this.format()}format(){return this.range=this.set.map(e=>e.join(" ").trim()).join("||").trim(),this.range}toString(){return this.range}parseRange(e){let o=((this.options.includePrerelease&&Uje)|(this.options.loose&&_je))+":"+e,a=lJ.get(o);if(a)return a;let n=this.options.loose,u=n?Da[Jo.HYPHENRANGELOOSE]:Da[Jo.HYPHENRANGE];e=e.replace(u,Xje(this.options.includePrerelease)),ci("hyphen replace",e),e=e.replace(Da[Jo.COMPARATORTRIM],Nje),ci("comparator trim",e),e=e.replace(Da[Jo.TILDETRIM],Oje),ci("tilde trim",e),e=e.replace(Da[Jo.CARETTRIM],Mje),ci("caret trim",e);let A=e.split(" ").map(I=>qje(I,this.options)).join(" ").split(/\s+/).map(I=>Jje(I,this.options));n&&(A=A.filter(I=>(ci("loose invalid filter",I,this.options),!!I.match(Da[Jo.COMPARATORLOOSE])))),ci("range list",A);let p=new Map,h=A.map(I=>new nL(I,this.options));for(let I of h){if(cJ(I))return[I];p.set(I.value,I)}p.size>1&&p.has("")&&p.delete("");let E=[...p.values()];return lJ.set(o,E),E}intersects(e,r){if(!(e instanceof ud))throw new TypeError("a Range is required");return this.set.some(o=>uJ(o,r)&&e.set.some(a=>uJ(a,r)&&o.every(n=>a.every(u=>n.intersects(u,r)))))}test(e){if(!e)return!1;if(typeof e=="string")try{e=new Lje(e,this.options)}catch{return!1}for(let r=0;r<this.set.length;r++)if(Zje(this.set[r],e,this.options))return!0;return!1}};AJ.exports=ud;var Rje=aJ(),lJ=new Rje({max:1e3}),Tje=pP(),nL=CI(),ci=dI(),Lje=Po(),{safeRe:Da,t:Jo,comparatorTrimReplace:Nje,tildeTrimReplace:Oje,caretTrimReplace:Mje}=vy(),{FLAG_INCLUDE_PRERELEASE:Uje,FLAG_LOOSE:_je}=gI(),cJ=t=>t.value==="<0.0.0-0",Hje=t=>t.value==="",uJ=(t,e)=>{let r=!0,o=t.slice(),a=o.pop();for(;r&&o.length;)r=o.every(n=>a.intersects(n,e)),a=o.pop();return r},qje=(t,e)=>(ci("comp",t,e),t=Yje(t,e),ci("caret",t),t=Gje(t,e),ci("tildes",t),t=Kje(t,e),ci("xrange",t),t=Vje(t,e),ci("stars",t),t),Xo=t=>!t||t.toLowerCase()==="x"||t==="*",Gje=(t,e)=>t.trim().split(/\s+/).map(r=>jje(r,e)).join(" "),jje=(t,e)=>{let r=e.loose?Da[Jo.TILDELOOSE]:Da[Jo.TILDE];return t.replace(r,(o,a,n,u,A)=>{ci("tilde",t,o,a,n,u,A);let p;return Xo(a)?p="":Xo(n)?p=`>=${a}.0.0 <${+a+1}.0.0-0`:Xo(u)?p=`>=${a}.${n}.0 <${a}.${+n+1}.0-0`:A?(ci("replaceTilde pr",A),p=`>=${a}.${n}.${u}-${A} <${a}.${+n+1}.0-0`):p=`>=${a}.${n}.${u} <${a}.${+n+1}.0-0`,ci("tilde return",p),p})},Yje=(t,e)=>t.trim().split(/\s+/).map(r=>Wje(r,e)).join(" "),Wje=(t,e)=>{ci("caret",t,e);let r=e.loose?Da[Jo.CARETLOOSE]:Da[Jo.CARET],o=e.includePrerelease?"-0":"";return t.replace(r,(a,n,u,A,p)=>{ci("caret",t,a,n,u,A,p);let h;return Xo(n)?h="":Xo(u)?h=`>=${n}.0.0${o} <${+n+1}.0.0-0`:Xo(A)?n==="0"?h=`>=${n}.${u}.0${o} <${n}.${+u+1}.0-0`:h=`>=${n}.${u}.0${o} <${+n+1}.0.0-0`:p?(ci("replaceCaret pr",p),n==="0"?u==="0"?h=`>=${n}.${u}.${A}-${p} <${n}.${u}.${+A+1}-0`:h=`>=${n}.${u}.${A}-${p} <${n}.${+u+1}.0-0`:h=`>=${n}.${u}.${A}-${p} <${+n+1}.0.0-0`):(ci("no pr"),n==="0"?u==="0"?h=`>=${n}.${u}.${A}${o} <${n}.${u}.${+A+1}-0`:h=`>=${n}.${u}.${A}${o} <${n}.${+u+1}.0-0`:h=`>=${n}.${u}.${A} <${+n+1}.0.0-0`),ci("caret return",h),h})},Kje=(t,e)=>(ci("replaceXRanges",t,e),t.split(/\s+/).map(r=>zje(r,e)).join(" ")),zje=(t,e)=>{t=t.trim();let r=e.loose?Da[Jo.XRANGELOOSE]:Da[Jo.XRANGE];return t.replace(r,(o,a,n,u,A,p)=>{ci("xRange",t,o,a,n,u,A,p);let h=Xo(n),E=h||Xo(u),I=E||Xo(A),v=I;return a==="="&&v&&(a=""),p=e.includePrerelease?"-0":"",h?a===">"||a==="<"?o="<0.0.0-0":o="*":a&&v?(E&&(u=0),A=0,a===">"?(a=">=",E?(n=+n+1,u=0,A=0):(u=+u+1,A=0)):a==="<="&&(a="<",E?n=+n+1:u=+u+1),a==="<"&&(p="-0"),o=`${a+n}.${u}.${A}${p}`):E?o=`>=${n}.0.0${p} <${+n+1}.0.0-0`:I&&(o=`>=${n}.${u}.0${p} <${n}.${+u+1}.0-0`),ci("xRange return",o),o})},Vje=(t,e)=>(ci("replaceStars",t,e),t.trim().replace(Da[Jo.STAR],"")),Jje=(t,e)=>(ci("replaceGTE0",t,e),t.trim().replace(Da[e.includePrerelease?Jo.GTE0PRE:Jo.GTE0],"")),Xje=t=>(e,r,o,a,n,u,A,p,h,E,I,v,x)=>(Xo(o)?r="":Xo(a)?r=`>=${o}.0.0${t?"-0":""}`:Xo(n)?r=`>=${o}.${a}.0${t?"-0":""}`:u?r=`>=${r}`:r=`>=${r}${t?"-0":""}`,Xo(h)?p="":Xo(E)?p=`<${+h+1}.0.0-0`:Xo(I)?p=`<${h}.${+E+1}.0-0`:v?p=`<=${h}.${E}.${I}-${v}`:t?p=`<${h}.${E}.${+I+1}-0`:p=`<=${p}`,`${r} ${p}`.trim()),Zje=(t,e,r)=>{for(let o=0;o<t.length;o++)if(!t[o].test(e))return!1;if(e.prerelease.length&&!r.includePrerelease){for(let o=0;o<t.length;o++)if(ci(t[o].semver),t[o].semver!==nL.ANY&&t[o].semver.prerelease.length>0){let a=t[o].semver;if(a.major===e.major&&a.minor===e.minor&&a.patch===e.patch)return!0}return!1}return!0}});var CI=_((AQt,mJ)=>{var wI=Symbol("SemVer ANY"),by=class{static get ANY(){return wI}constructor(e,r){if(r=fJ(r),e instanceof by){if(e.loose===!!r.loose)return e;e=e.value}e=e.trim().split(/\s+/).join(" "),sL("comparator",e,r),this.options=r,this.loose=!!r.loose,this.parse(e),this.semver===wI?this.value="":this.value=this.operator+this.semver.version,sL("comp",this)}parse(e){let r=this.options.loose?pJ[hJ.COMPARATORLOOSE]:pJ[hJ.COMPARATOR],o=e.match(r);if(!o)throw new TypeError(`Invalid comparator: ${e}`);this.operator=o[1]!==void 0?o[1]:"",this.operator==="="&&(this.operator=""),o[2]?this.semver=new gJ(o[2],this.options.loose):this.semver=wI}toString(){return this.value}test(e){if(sL("Comparator.test",e,this.options.loose),this.semver===wI||e===wI)return!0;if(typeof e=="string")try{e=new gJ(e,this.options)}catch{return!1}return iL(e,this.operator,this.semver,this.options)}intersects(e,r){if(!(e instanceof by))throw new TypeError("a Comparator is required");return this.operator===""?this.value===""?!0:new dJ(e.value,r).test(this.value):e.operator===""?e.value===""?!0:new dJ(this.value,r).test(e.semver):(r=fJ(r),r.includePrerelease&&(this.value==="<0.0.0-0"||e.value==="<0.0.0-0")||!r.includePrerelease&&(this.value.startsWith("<0.0.0")||e.value.startsWith("<0.0.0"))?!1:!!(this.operator.startsWith(">")&&e.operator.startsWith(">")||this.operator.startsWith("<")&&e.operator.startsWith("<")||this.semver.version===e.semver.version&&this.operator.includes("=")&&e.operator.includes("=")||iL(this.semver,"<",e.semver,r)&&this.operator.startsWith(">")&&e.operator.startsWith("<")||iL(this.semver,">",e.semver,r)&&this.operator.startsWith("<")&&e.operator.startsWith(">")))}};mJ.exports=by;var fJ=pP(),{safeRe:pJ,t:hJ}=vy(),iL=ZT(),sL=dI(),gJ=Po(),dJ=Ml()});var II=_((fQt,yJ)=>{var $je=Ml(),e9e=(t,e,r)=>{try{e=new $je(e,r)}catch{return!1}return e.test(t)};yJ.exports=e9e});var CJ=_((pQt,EJ)=>{var t9e=Ml(),r9e=(t,e)=>new t9e(t,e).set.map(r=>r.map(o=>o.value).join(" ").trim().split(" "));EJ.exports=r9e});var IJ=_((hQt,wJ)=>{var n9e=Po(),i9e=Ml(),s9e=(t,e,r)=>{let o=null,a=null,n=null;try{n=new i9e(e,r)}catch{return null}return t.forEach(u=>{n.test(u)&&(!o||a.compare(u)===-1)&&(o=u,a=new n9e(o,r))}),o};wJ.exports=s9e});var vJ=_((gQt,BJ)=>{var o9e=Po(),a9e=Ml(),l9e=(t,e,r)=>{let o=null,a=null,n=null;try{n=new a9e(e,r)}catch{return null}return t.forEach(u=>{n.test(u)&&(!o||a.compare(u)===1)&&(o=u,a=new o9e(o,r))}),o};BJ.exports=l9e});var SJ=_((dQt,PJ)=>{var oL=Po(),c9e=Ml(),DJ=mI(),u9e=(t,e)=>{t=new c9e(t,e);let r=new oL("0.0.0");if(t.test(r)||(r=new oL("0.0.0-0"),t.test(r)))return r;r=null;for(let o=0;o<t.set.length;++o){let a=t.set[o],n=null;a.forEach(u=>{let A=new oL(u.semver.version);switch(u.operator){case">":A.prerelease.length===0?A.patch++:A.prerelease.push(0),A.raw=A.format();case"":case">=":(!n||DJ(A,n))&&(n=A);break;case"<":case"<=":break;default:throw new Error(`Unexpected operation: ${u.operator}`)}}),n&&(!r||DJ(r,n))&&(r=n)}return r&&t.test(r)?r:null};PJ.exports=u9e});var xJ=_((mQt,bJ)=>{var A9e=Ml(),f9e=(t,e)=>{try{return new A9e(t,e).range||"*"}catch{return null}};bJ.exports=f9e});var vP=_((yQt,RJ)=>{var p9e=Po(),FJ=CI(),{ANY:h9e}=FJ,g9e=Ml(),d9e=II(),kJ=mI(),QJ=mP(),m9e=EP(),y9e=yP(),E9e=(t,e,r,o)=>{t=new p9e(t,o),e=new g9e(e,o);let a,n,u,A,p;switch(r){case">":a=kJ,n=m9e,u=QJ,A=">",p=">=";break;case"<":a=QJ,n=y9e,u=kJ,A="<",p="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(d9e(t,e,o))return!1;for(let h=0;h<e.set.length;++h){let E=e.set[h],I=null,v=null;if(E.forEach(x=>{x.semver===h9e&&(x=new FJ(">=0.0.0")),I=I||x,v=v||x,a(x.semver,I.semver,o)?I=x:u(x.semver,v.semver,o)&&(v=x)}),I.operator===A||I.operator===p||(!v.operator||v.operator===A)&&n(t,v.semver))return!1;if(v.operator===p&&u(t,v.semver))return!1}return!0};RJ.exports=E9e});var LJ=_((EQt,TJ)=>{var C9e=vP(),w9e=(t,e,r)=>C9e(t,e,">",r);TJ.exports=w9e});var OJ=_((CQt,NJ)=>{var I9e=vP(),B9e=(t,e,r)=>I9e(t,e,"<",r);NJ.exports=B9e});var _J=_((wQt,UJ)=>{var MJ=Ml(),v9e=(t,e,r)=>(t=new MJ(t,r),e=new MJ(e,r),t.intersects(e,r));UJ.exports=v9e});var qJ=_((IQt,HJ)=>{var D9e=II(),P9e=Ol();HJ.exports=(t,e,r)=>{let o=[],a=null,n=null,u=t.sort((E,I)=>P9e(E,I,r));for(let E of u)D9e(E,e,r)?(n=E,a||(a=E)):(n&&o.push([a,n]),n=null,a=null);a&&o.push([a,null]);let A=[];for(let[E,I]of o)E===I?A.push(E):!I&&E===u[0]?A.push("*"):I?E===u[0]?A.push(`<=${I}`):A.push(`${E} - ${I}`):A.push(`>=${E}`);let p=A.join(" || "),h=typeof e.raw=="string"?e.raw:String(e);return p.length<h.length?p:e}});var zJ=_((BQt,KJ)=>{var GJ=Ml(),lL=CI(),{ANY:aL}=lL,BI=II(),cL=Ol(),S9e=(t,e,r={})=>{if(t===e)return!0;t=new GJ(t,r),e=new GJ(e,r);let o=!1;e:for(let a of t.set){for(let n of e.set){let u=x9e(a,n,r);if(o=o||u!==null,u)continue e}if(o)return!1}return!0},b9e=[new lL(">=0.0.0-0")],jJ=[new lL(">=0.0.0")],x9e=(t,e,r)=>{if(t===e)return!0;if(t.length===1&&t[0].semver===aL){if(e.length===1&&e[0].semver===aL)return!0;r.includePrerelease?t=b9e:t=jJ}if(e.length===1&&e[0].semver===aL){if(r.includePrerelease)return!0;e=jJ}let o=new Set,a,n;for(let x of t)x.operator===">"||x.operator===">="?a=YJ(a,x,r):x.operator==="<"||x.operator==="<="?n=WJ(n,x,r):o.add(x.semver);if(o.size>1)return null;let u;if(a&&n){if(u=cL(a.semver,n.semver,r),u>0)return null;if(u===0&&(a.operator!==">="||n.operator!=="<="))return null}for(let x of o){if(a&&!BI(x,String(a),r)||n&&!BI(x,String(n),r))return null;for(let C of e)if(!BI(x,String(C),r))return!1;return!0}let A,p,h,E,I=n&&!r.includePrerelease&&n.semver.prerelease.length?n.semver:!1,v=a&&!r.includePrerelease&&a.semver.prerelease.length?a.semver:!1;I&&I.prerelease.length===1&&n.operator==="<"&&I.prerelease[0]===0&&(I=!1);for(let x of e){if(E=E||x.operator===">"||x.operator===">=",h=h||x.operator==="<"||x.operator==="<=",a){if(v&&x.semver.prerelease&&x.semver.prerelease.length&&x.semver.major===v.major&&x.semver.minor===v.minor&&x.semver.patch===v.patch&&(v=!1),x.operator===">"||x.operator===">="){if(A=YJ(a,x,r),A===x&&A!==a)return!1}else if(a.operator===">="&&!BI(a.semver,String(x),r))return!1}if(n){if(I&&x.semver.prerelease&&x.semver.prerelease.length&&x.semver.major===I.major&&x.semver.minor===I.minor&&x.semver.patch===I.patch&&(I=!1),x.operator==="<"||x.operator==="<="){if(p=WJ(n,x,r),p===x&&p!==n)return!1}else if(n.operator==="<="&&!BI(n.semver,String(x),r))return!1}if(!x.operator&&(n||a)&&u!==0)return!1}return!(a&&h&&!n&&u!==0||n&&E&&!a&&u!==0||v||I)},YJ=(t,e,r)=>{if(!t)return e;let o=cL(t.semver,e.semver,r);return o>0?t:o<0||e.operator===">"&&t.operator===">="?e:t},WJ=(t,e,r)=>{if(!t)return e;let o=cL(t.semver,e.semver,r);return o<0?t:o>0||e.operator==="<"&&t.operator==="<="?e:t};KJ.exports=S9e});var Jn=_((vQt,XJ)=>{var uL=vy(),VJ=gI(),k9e=Po(),JJ=VT(),Q9e=od(),F9e=dV(),R9e=yV(),T9e=wV(),L9e=vV(),N9e=PV(),O9e=bV(),M9e=kV(),U9e=FV(),_9e=Ol(),H9e=NV(),q9e=MV(),G9e=dP(),j9e=qV(),Y9e=jV(),W9e=mI(),K9e=mP(),z9e=JT(),V9e=XT(),J9e=yP(),X9e=EP(),Z9e=ZT(),$9e=$V(),e5e=CI(),t5e=Ml(),r5e=II(),n5e=CJ(),i5e=IJ(),s5e=vJ(),o5e=SJ(),a5e=xJ(),l5e=vP(),c5e=LJ(),u5e=OJ(),A5e=_J(),f5e=qJ(),p5e=zJ();XJ.exports={parse:Q9e,valid:F9e,clean:R9e,inc:T9e,diff:L9e,major:N9e,minor:O9e,patch:M9e,prerelease:U9e,compare:_9e,rcompare:H9e,compareLoose:q9e,compareBuild:G9e,sort:j9e,rsort:Y9e,gt:W9e,lt:K9e,eq:z9e,neq:V9e,gte:J9e,lte:X9e,cmp:Z9e,coerce:$9e,Comparator:e5e,Range:t5e,satisfies:r5e,toComparators:n5e,maxSatisfying:i5e,minSatisfying:s5e,minVersion:o5e,validRange:a5e,outside:l5e,gtr:c5e,ltr:u5e,intersects:A5e,simplifyRange:f5e,subset:p5e,SemVer:k9e,re:uL.re,src:uL.src,tokens:uL.t,SEMVER_SPEC_VERSION:VJ.SEMVER_SPEC_VERSION,RELEASE_TYPES:VJ.RELEASE_TYPES,compareIdentifiers:JJ.compareIdentifiers,rcompareIdentifiers:JJ.rcompareIdentifiers}});var $J=_((DQt,ZJ)=>{"use strict";function h5e(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Ad(t,e,r,o){this.message=t,this.expected=e,this.found=r,this.location=o,this.name="SyntaxError",typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(this,Ad)}h5e(Ad,Error);Ad.buildMessage=function(t,e){var r={literal:function(h){return'"'+a(h.text)+'"'},class:function(h){var E="",I;for(I=0;I<h.parts.length;I++)E+=h.parts[I]instanceof Array?n(h.parts[I][0])+"-"+n(h.parts[I][1]):n(h.parts[I]);return"["+(h.inverted?"^":"")+E+"]"},any:function(h){return"any character"},end:function(h){return"end of input"},other:function(h){return h.description}};function o(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(E){return"\\x0"+o(E)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(E){return"\\x"+o(E)})}function n(h){return h.replace(/\\/g,"\\\\").replace(/\]/g,"\\]").replace(/\^/g,"\\^").replace(/-/g,"\\-").replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(E){return"\\x0"+o(E)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(E){return"\\x"+o(E)})}function u(h){return r[h.type](h)}function A(h){var E=new Array(h.length),I,v;for(I=0;I<h.length;I++)E[I]=u(h[I]);if(E.sort(),E.length>0){for(I=1,v=1;I<E.length;I++)E[I-1]!==E[I]&&(E[v]=E[I],v++);E.length=v}switch(E.length){case 1:return E[0];case 2:return E[0]+" or "+E[1];default:return E.slice(0,-1).join(", ")+", or "+E[E.length-1]}}function p(h){return h?'"'+a(h)+'"':"end of input"}return"Expected "+A(t)+" but "+p(e)+" found."};function g5e(t,e){e=e!==void 0?e:{};var r={},o={Expression:y},a=y,n="|",u=Re("|",!1),A="&",p=Re("&",!1),h="^",E=Re("^",!1),I=function(Z,ie){return!!ie.reduce((be,Le)=>{switch(Le[1]){case"|":return be|Le[3];case"&":return be&Le[3];case"^":return be^Le[3]}},Z)},v="!",x=Re("!",!1),C=function(Z){return!Z},R="(",N=Re("(",!1),U=")",V=Re(")",!1),te=function(Z){return Z},ae=/^[^ \t\n\r()!|&\^]/,fe=ke([" "," ",`
-`,"\r","(",")","!","|","&","^"],!0,!1),ue=function(Z){return e.queryPattern.test(Z)},me=function(Z){return e.checkFn(Z)},he=Te("whitespace"),Be=/^[ \t\n\r]/,we=ke([" "," ",`
-`,"\r"],!1,!1),g=0,Ee=0,Pe=[{line:1,column:1}],ce=0,ne=[],ee=0,Ie;if("startRule"in e){if(!(e.startRule in o))throw new Error(`Can't start parsing from rule "`+e.startRule+'".');a=o[e.startRule]}function Fe(){return t.substring(Ee,g)}function At(){return qe(Ee,g)}function H(Z,ie){throw ie=ie!==void 0?ie:qe(Ee,g),S([Te(Z)],t.substring(Ee,g),ie)}function at(Z,ie){throw ie=ie!==void 0?ie:qe(Ee,g),w(Z,ie)}function Re(Z,ie){return{type:"literal",text:Z,ignoreCase:ie}}function ke(Z,ie,be){return{type:"class",parts:Z,inverted:ie,ignoreCase:be}}function xe(){return{type:"any"}}function He(){return{type:"end"}}function Te(Z){return{type:"other",description:Z}}function Ve(Z){var ie=Pe[Z],be;if(ie)return ie;for(be=Z-1;!Pe[be];)be--;for(ie=Pe[be],ie={line:ie.line,column:ie.column};be<Z;)t.charCodeAt(be)===10?(ie.line++,ie.column=1):ie.column++,be++;return Pe[Z]=ie,ie}function qe(Z,ie){var be=Ve(Z),Le=Ve(ie);return{start:{offset:Z,line:be.line,column:be.column},end:{offset:ie,line:Le.line,column:Le.column}}}function b(Z){g<ce||(g>ce&&(ce=g,ne=[]),ne.push(Z))}function w(Z,ie){return new Ad(Z,null,null,ie)}function S(Z,ie,be){return new Ad(Ad.buildMessage(Z,ie),Z,ie,be)}function y(){var Z,ie,be,Le,ot,dt,Gt,$t;if(Z=g,ie=F(),ie!==r){for(be=[],Le=g,ot=X(),ot!==r?(t.charCodeAt(g)===124?(dt=n,g++):(dt=r,ee===0&&b(u)),dt===r&&(t.charCodeAt(g)===38?(dt=A,g++):(dt=r,ee===0&&b(p)),dt===r&&(t.charCodeAt(g)===94?(dt=h,g++):(dt=r,ee===0&&b(E)))),dt!==r?(Gt=X(),Gt!==r?($t=F(),$t!==r?(ot=[ot,dt,Gt,$t],Le=ot):(g=Le,Le=r)):(g=Le,Le=r)):(g=Le,Le=r)):(g=Le,Le=r);Le!==r;)be.push(Le),Le=g,ot=X(),ot!==r?(t.charCodeAt(g)===124?(dt=n,g++):(dt=r,ee===0&&b(u)),dt===r&&(t.charCodeAt(g)===38?(dt=A,g++):(dt=r,ee===0&&b(p)),dt===r&&(t.charCodeAt(g)===94?(dt=h,g++):(dt=r,ee===0&&b(E)))),dt!==r?(Gt=X(),Gt!==r?($t=F(),$t!==r?(ot=[ot,dt,Gt,$t],Le=ot):(g=Le,Le=r)):(g=Le,Le=r)):(g=Le,Le=r)):(g=Le,Le=r);be!==r?(Ee=Z,ie=I(ie,be),Z=ie):(g=Z,Z=r)}else g=Z,Z=r;return Z}function F(){var Z,ie,be,Le,ot,dt;return Z=g,t.charCodeAt(g)===33?(ie=v,g++):(ie=r,ee===0&&b(x)),ie!==r?(be=F(),be!==r?(Ee=Z,ie=C(be),Z=ie):(g=Z,Z=r)):(g=Z,Z=r),Z===r&&(Z=g,t.charCodeAt(g)===40?(ie=R,g++):(ie=r,ee===0&&b(N)),ie!==r?(be=X(),be!==r?(Le=y(),Le!==r?(ot=X(),ot!==r?(t.charCodeAt(g)===41?(dt=U,g++):(dt=r,ee===0&&b(V)),dt!==r?(Ee=Z,ie=te(Le),Z=ie):(g=Z,Z=r)):(g=Z,Z=r)):(g=Z,Z=r)):(g=Z,Z=r)):(g=Z,Z=r),Z===r&&(Z=J())),Z}function J(){var Z,ie,be,Le,ot;if(Z=g,ie=X(),ie!==r){if(be=g,Le=[],ae.test(t.charAt(g))?(ot=t.charAt(g),g++):(ot=r,ee===0&&b(fe)),ot!==r)for(;ot!==r;)Le.push(ot),ae.test(t.charAt(g))?(ot=t.charAt(g),g++):(ot=r,ee===0&&b(fe));else Le=r;Le!==r?be=t.substring(be,g):be=Le,be!==r?(Ee=g,Le=ue(be),Le?Le=void 0:Le=r,Le!==r?(Ee=Z,ie=me(be),Z=ie):(g=Z,Z=r)):(g=Z,Z=r)}else g=Z,Z=r;return Z}function X(){var Z,ie;for(ee++,Z=[],Be.test(t.charAt(g))?(ie=t.charAt(g),g++):(ie=r,ee===0&&b(we));ie!==r;)Z.push(ie),Be.test(t.charAt(g))?(ie=t.charAt(g),g++):(ie=r,ee===0&&b(we));return ee--,Z===r&&(ie=r,ee===0&&b(he)),Z}if(Ie=a(),Ie!==r&&g===t.length)return Ie;throw Ie!==r&&g<t.length&&b(He()),S(ne,ce<t.length?t.charAt(ce):null,ce<t.length?qe(ce,ce+1):qe(ce,ce))}ZJ.exports={SyntaxError:Ad,parse:g5e}});var eX=_(DP=>{var{parse:d5e}=$J();DP.makeParser=(t=/[a-z]+/)=>(e,r)=>d5e(e,{queryPattern:t,checkFn:r});DP.parse=DP.makeParser()});var rX=_((SQt,tX)=>{"use strict";tX.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}});var AL=_((bQt,iX)=>{var vI=rX(),nX={};for(let t of Object.keys(vI))nX[vI[t]]=t;var Ar={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};iX.exports=Ar;for(let t of Object.keys(Ar)){if(!("channels"in Ar[t]))throw new Error("missing channels property: "+t);if(!("labels"in Ar[t]))throw new Error("missing channel labels property: "+t);if(Ar[t].labels.length!==Ar[t].channels)throw new Error("channel and label counts mismatch: "+t);let{channels:e,labels:r}=Ar[t];delete Ar[t].channels,delete Ar[t].labels,Object.defineProperty(Ar[t],"channels",{value:e}),Object.defineProperty(Ar[t],"labels",{value:r})}Ar.rgb.hsl=function(t){let e=t[0]/255,r=t[1]/255,o=t[2]/255,a=Math.min(e,r,o),n=Math.max(e,r,o),u=n-a,A,p;n===a?A=0:e===n?A=(r-o)/u:r===n?A=2+(o-e)/u:o===n&&(A=4+(e-r)/u),A=Math.min(A*60,360),A<0&&(A+=360);let h=(a+n)/2;return n===a?p=0:h<=.5?p=u/(n+a):p=u/(2-n-a),[A,p*100,h*100]};Ar.rgb.hsv=function(t){let e,r,o,a,n,u=t[0]/255,A=t[1]/255,p=t[2]/255,h=Math.max(u,A,p),E=h-Math.min(u,A,p),I=function(v){return(h-v)/6/E+1/2};return E===0?(a=0,n=0):(n=E/h,e=I(u),r=I(A),o=I(p),u===h?a=o-r:A===h?a=1/3+e-o:p===h&&(a=2/3+r-e),a<0?a+=1:a>1&&(a-=1)),[a*360,n*100,h*100]};Ar.rgb.hwb=function(t){let e=t[0],r=t[1],o=t[2],a=Ar.rgb.hsl(t)[0],n=1/255*Math.min(e,Math.min(r,o));return o=1-1/255*Math.max(e,Math.max(r,o)),[a,n*100,o*100]};Ar.rgb.cmyk=function(t){let e=t[0]/255,r=t[1]/255,o=t[2]/255,a=Math.min(1-e,1-r,1-o),n=(1-e-a)/(1-a)||0,u=(1-r-a)/(1-a)||0,A=(1-o-a)/(1-a)||0;return[n*100,u*100,A*100,a*100]};function m5e(t,e){return(t[0]-e[0])**2+(t[1]-e[1])**2+(t[2]-e[2])**2}Ar.rgb.keyword=function(t){let e=nX[t];if(e)return e;let r=1/0,o;for(let a of Object.keys(vI)){let n=vI[a],u=m5e(t,n);u<r&&(r=u,o=a)}return o};Ar.keyword.rgb=function(t){return vI[t]};Ar.rgb.xyz=function(t){let e=t[0]/255,r=t[1]/255,o=t[2]/255;e=e>.04045?((e+.055)/1.055)**2.4:e/12.92,r=r>.04045?((r+.055)/1.055)**2.4:r/12.92,o=o>.04045?((o+.055)/1.055)**2.4:o/12.92;let a=e*.4124+r*.3576+o*.1805,n=e*.2126+r*.7152+o*.0722,u=e*.0193+r*.1192+o*.9505;return[a*100,n*100,u*100]};Ar.rgb.lab=function(t){let e=Ar.rgb.xyz(t),r=e[0],o=e[1],a=e[2];r/=95.047,o/=100,a/=108.883,r=r>.008856?r**(1/3):7.787*r+16/116,o=o>.008856?o**(1/3):7.787*o+16/116,a=a>.008856?a**(1/3):7.787*a+16/116;let n=116*o-16,u=500*(r-o),A=200*(o-a);return[n,u,A]};Ar.hsl.rgb=function(t){let e=t[0]/360,r=t[1]/100,o=t[2]/100,a,n,u;if(r===0)return u=o*255,[u,u,u];o<.5?a=o*(1+r):a=o+r-o*r;let A=2*o-a,p=[0,0,0];for(let h=0;h<3;h++)n=e+1/3*-(h-1),n<0&&n++,n>1&&n--,6*n<1?u=A+(a-A)*6*n:2*n<1?u=a:3*n<2?u=A+(a-A)*(2/3-n)*6:u=A,p[h]=u*255;return p};Ar.hsl.hsv=function(t){let e=t[0],r=t[1]/100,o=t[2]/100,a=r,n=Math.max(o,.01);o*=2,r*=o<=1?o:2-o,a*=n<=1?n:2-n;let u=(o+r)/2,A=o===0?2*a/(n+a):2*r/(o+r);return[e,A*100,u*100]};Ar.hsv.rgb=function(t){let e=t[0]/60,r=t[1]/100,o=t[2]/100,a=Math.floor(e)%6,n=e-Math.floor(e),u=255*o*(1-r),A=255*o*(1-r*n),p=255*o*(1-r*(1-n));switch(o*=255,a){case 0:return[o,p,u];case 1:return[A,o,u];case 2:return[u,o,p];case 3:return[u,A,o];case 4:return[p,u,o];case 5:return[o,u,A]}};Ar.hsv.hsl=function(t){let e=t[0],r=t[1]/100,o=t[2]/100,a=Math.max(o,.01),n,u;u=(2-r)*o;let A=(2-r)*a;return n=r*a,n/=A<=1?A:2-A,n=n||0,u/=2,[e,n*100,u*100]};Ar.hwb.rgb=function(t){let e=t[0]/360,r=t[1]/100,o=t[2]/100,a=r+o,n;a>1&&(r/=a,o/=a);let u=Math.floor(6*e),A=1-o;n=6*e-u,(u&1)!==0&&(n=1-n);let p=r+n*(A-r),h,E,I;switch(u){default:case 6:case 0:h=A,E=p,I=r;break;case 1:h=p,E=A,I=r;break;case 2:h=r,E=A,I=p;break;case 3:h=r,E=p,I=A;break;case 4:h=p,E=r,I=A;break;case 5:h=A,E=r,I=p;break}return[h*255,E*255,I*255]};Ar.cmyk.rgb=function(t){let e=t[0]/100,r=t[1]/100,o=t[2]/100,a=t[3]/100,n=1-Math.min(1,e*(1-a)+a),u=1-Math.min(1,r*(1-a)+a),A=1-Math.min(1,o*(1-a)+a);return[n*255,u*255,A*255]};Ar.xyz.rgb=function(t){let e=t[0]/100,r=t[1]/100,o=t[2]/100,a,n,u;return a=e*3.2406+r*-1.5372+o*-.4986,n=e*-.9689+r*1.8758+o*.0415,u=e*.0557+r*-.204+o*1.057,a=a>.0031308?1.055*a**(1/2.4)-.055:a*12.92,n=n>.0031308?1.055*n**(1/2.4)-.055:n*12.92,u=u>.0031308?1.055*u**(1/2.4)-.055:u*12.92,a=Math.min(Math.max(0,a),1),n=Math.min(Math.max(0,n),1),u=Math.min(Math.max(0,u),1),[a*255,n*255,u*255]};Ar.xyz.lab=function(t){let e=t[0],r=t[1],o=t[2];e/=95.047,r/=100,o/=108.883,e=e>.008856?e**(1/3):7.787*e+16/116,r=r>.008856?r**(1/3):7.787*r+16/116,o=o>.008856?o**(1/3):7.787*o+16/116;let a=116*r-16,n=500*(e-r),u=200*(r-o);return[a,n,u]};Ar.lab.xyz=function(t){let e=t[0],r=t[1],o=t[2],a,n,u;n=(e+16)/116,a=r/500+n,u=n-o/200;let A=n**3,p=a**3,h=u**3;return n=A>.008856?A:(n-16/116)/7.787,a=p>.008856?p:(a-16/116)/7.787,u=h>.008856?h:(u-16/116)/7.787,a*=95.047,n*=100,u*=108.883,[a,n,u]};Ar.lab.lch=function(t){let e=t[0],r=t[1],o=t[2],a;a=Math.atan2(o,r)*360/2/Math.PI,a<0&&(a+=360);let u=Math.sqrt(r*r+o*o);return[e,u,a]};Ar.lch.lab=function(t){let e=t[0],r=t[1],a=t[2]/360*2*Math.PI,n=r*Math.cos(a),u=r*Math.sin(a);return[e,n,u]};Ar.rgb.ansi16=function(t,e=null){let[r,o,a]=t,n=e===null?Ar.rgb.hsv(t)[2]:e;if(n=Math.round(n/50),n===0)return 30;let u=30+(Math.round(a/255)<<2|Math.round(o/255)<<1|Math.round(r/255));return n===2&&(u+=60),u};Ar.hsv.ansi16=function(t){return Ar.rgb.ansi16(Ar.hsv.rgb(t),t[2])};Ar.rgb.ansi256=function(t){let e=t[0],r=t[1],o=t[2];return e===r&&r===o?e<8?16:e>248?231:Math.round((e-8)/247*24)+232:16+36*Math.round(e/255*5)+6*Math.round(r/255*5)+Math.round(o/255*5)};Ar.ansi16.rgb=function(t){let e=t%10;if(e===0||e===7)return t>50&&(e+=3.5),e=e/10.5*255,[e,e,e];let r=(~~(t>50)+1)*.5,o=(e&1)*r*255,a=(e>>1&1)*r*255,n=(e>>2&1)*r*255;return[o,a,n]};Ar.ansi256.rgb=function(t){if(t>=232){let n=(t-232)*10+8;return[n,n,n]}t-=16;let e,r=Math.floor(t/36)/5*255,o=Math.floor((e=t%36)/6)/5*255,a=e%6/5*255;return[r,o,a]};Ar.rgb.hex=function(t){let r=(((Math.round(t[0])&255)<<16)+((Math.round(t[1])&255)<<8)+(Math.round(t[2])&255)).toString(16).toUpperCase();return"000000".substring(r.length)+r};Ar.hex.rgb=function(t){let e=t.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!e)return[0,0,0];let r=e[0];e[0].length===3&&(r=r.split("").map(A=>A+A).join(""));let o=parseInt(r,16),a=o>>16&255,n=o>>8&255,u=o&255;return[a,n,u]};Ar.rgb.hcg=function(t){let e=t[0]/255,r=t[1]/255,o=t[2]/255,a=Math.max(Math.max(e,r),o),n=Math.min(Math.min(e,r),o),u=a-n,A,p;return u<1?A=n/(1-u):A=0,u<=0?p=0:a===e?p=(r-o)/u%6:a===r?p=2+(o-e)/u:p=4+(e-r)/u,p/=6,p%=1,[p*360,u*100,A*100]};Ar.hsl.hcg=function(t){let e=t[1]/100,r=t[2]/100,o=r<.5?2*e*r:2*e*(1-r),a=0;return o<1&&(a=(r-.5*o)/(1-o)),[t[0],o*100,a*100]};Ar.hsv.hcg=function(t){let e=t[1]/100,r=t[2]/100,o=e*r,a=0;return o<1&&(a=(r-o)/(1-o)),[t[0],o*100,a*100]};Ar.hcg.rgb=function(t){let e=t[0]/360,r=t[1]/100,o=t[2]/100;if(r===0)return[o*255,o*255,o*255];let a=[0,0,0],n=e%1*6,u=n%1,A=1-u,p=0;switch(Math.floor(n)){case 0:a[0]=1,a[1]=u,a[2]=0;break;case 1:a[0]=A,a[1]=1,a[2]=0;break;case 2:a[0]=0,a[1]=1,a[2]=u;break;case 3:a[0]=0,a[1]=A,a[2]=1;break;case 4:a[0]=u,a[1]=0,a[2]=1;break;default:a[0]=1,a[1]=0,a[2]=A}return p=(1-r)*o,[(r*a[0]+p)*255,(r*a[1]+p)*255,(r*a[2]+p)*255]};Ar.hcg.hsv=function(t){let e=t[1]/100,r=t[2]/100,o=e+r*(1-e),a=0;return o>0&&(a=e/o),[t[0],a*100,o*100]};Ar.hcg.hsl=function(t){let e=t[1]/100,o=t[2]/100*(1-e)+.5*e,a=0;return o>0&&o<.5?a=e/(2*o):o>=.5&&o<1&&(a=e/(2*(1-o))),[t[0],a*100,o*100]};Ar.hcg.hwb=function(t){let e=t[1]/100,r=t[2]/100,o=e+r*(1-e);return[t[0],(o-e)*100,(1-o)*100]};Ar.hwb.hcg=function(t){let e=t[1]/100,o=1-t[2]/100,a=o-e,n=0;return a<1&&(n=(o-a)/(1-a)),[t[0],a*100,n*100]};Ar.apple.rgb=function(t){return[t[0]/65535*255,t[1]/65535*255,t[2]/65535*255]};Ar.rgb.apple=function(t){return[t[0]/255*65535,t[1]/255*65535,t[2]/255*65535]};Ar.gray.rgb=function(t){return[t[0]/100*255,t[0]/100*255,t[0]/100*255]};Ar.gray.hsl=function(t){return[0,0,t[0]]};Ar.gray.hsv=Ar.gray.hsl;Ar.gray.hwb=function(t){return[0,100,t[0]]};Ar.gray.cmyk=function(t){return[0,0,0,t[0]]};Ar.gray.lab=function(t){return[t[0],0,0]};Ar.gray.hex=function(t){let e=Math.round(t[0]/100*255)&255,o=((e<<16)+(e<<8)+e).toString(16).toUpperCase();return"000000".substring(o.length)+o};Ar.rgb.gray=function(t){return[(t[0]+t[1]+t[2])/3/255*100]}});var oX=_((xQt,sX)=>{var PP=AL();function y5e(){let t={},e=Object.keys(PP);for(let r=e.length,o=0;o<r;o++)t[e[o]]={distance:-1,parent:null};return t}function E5e(t){let e=y5e(),r=[t];for(e[t].distance=0;r.length;){let o=r.pop(),a=Object.keys(PP[o]);for(let n=a.length,u=0;u<n;u++){let A=a[u],p=e[A];p.distance===-1&&(p.distance=e[o].distance+1,p.parent=o,r.unshift(A))}}return e}function C5e(t,e){return function(r){return e(t(r))}}function w5e(t,e){let r=[e[t].parent,t],o=PP[e[t].parent][t],a=e[t].parent;for(;e[a].parent;)r.unshift(e[a].parent),o=C5e(PP[e[a].parent][a],o),a=e[a].parent;return o.conversion=r,o}sX.exports=function(t){let e=E5e(t),r={},o=Object.keys(e);for(let a=o.length,n=0;n<a;n++){let u=o[n];e[u].parent!==null&&(r[u]=w5e(u,e))}return r}});var lX=_((kQt,aX)=>{var fL=AL(),I5e=oX(),xy={},B5e=Object.keys(fL);function v5e(t){let e=function(...r){let o=r[0];return o==null?o:(o.length>1&&(r=o),t(r))};return"conversion"in t&&(e.conversion=t.conversion),e}function D5e(t){let e=function(...r){let o=r[0];if(o==null)return o;o.length>1&&(r=o);let a=t(r);if(typeof a=="object")for(let n=a.length,u=0;u<n;u++)a[u]=Math.round(a[u]);return a};return"conversion"in t&&(e.conversion=t.conversion),e}B5e.forEach(t=>{xy[t]={},Object.defineProperty(xy[t],"channels",{value:fL[t].channels}),Object.defineProperty(xy[t],"labels",{value:fL[t].labels});let e=I5e(t);Object.keys(e).forEach(o=>{let a=e[o];xy[t][o]=D5e(a),xy[t][o].raw=v5e(a)})});aX.exports=xy});var DI=_((QQt,pX)=>{"use strict";var cX=(t,e)=>(...r)=>`\x1B[${t(...r)+e}m`,uX=(t,e)=>(...r)=>{let o=t(...r);return`\x1B[${38+e};5;${o}m`},AX=(t,e)=>(...r)=>{let o=t(...r);return`\x1B[${38+e};2;${o[0]};${o[1]};${o[2]}m`},SP=t=>t,fX=(t,e,r)=>[t,e,r],ky=(t,e,r)=>{Object.defineProperty(t,e,{get:()=>{let o=r();return Object.defineProperty(t,e,{value:o,enumerable:!0,configurable:!0}),o},enumerable:!0,configurable:!0})},pL,Qy=(t,e,r,o)=>{pL===void 0&&(pL=lX());let a=o?10:0,n={};for(let[u,A]of Object.entries(pL)){let p=u==="ansi16"?"ansi":u;u===e?n[p]=t(r,a):typeof A=="object"&&(n[p]=t(A[e],a))}return n};function P5e(){let t=new Map,e={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}};e.color.gray=e.color.blackBright,e.bgColor.bgGray=e.bgColor.bgBlackBright,e.color.grey=e.color.blackBright,e.bgColor.bgGrey=e.bgColor.bgBlackBright;for(let[r,o]of Object.entries(e)){for(let[a,n]of Object.entries(o))e[a]={open:`\x1B[${n[0]}m`,close:`\x1B[${n[1]}m`},o[a]=e[a],t.set(n[0],n[1]);Object.defineProperty(e,r,{value:o,enumerable:!1})}return Object.defineProperty(e,"codes",{value:t,enumerable:!1}),e.color.close="\x1B[39m",e.bgColor.close="\x1B[49m",ky(e.color,"ansi",()=>Qy(cX,"ansi16",SP,!1)),ky(e.color,"ansi256",()=>Qy(uX,"ansi256",SP,!1)),ky(e.color,"ansi16m",()=>Qy(AX,"rgb",fX,!1)),ky(e.bgColor,"ansi",()=>Qy(cX,"ansi16",SP,!0)),ky(e.bgColor,"ansi256",()=>Qy(uX,"ansi256",SP,!0)),ky(e.bgColor,"ansi16m",()=>Qy(AX,"rgb",fX,!0)),e}Object.defineProperty(pX,"exports",{enumerable:!0,get:P5e})});var gX=_((FQt,hX)=>{"use strict";hX.exports=(t,e=process.argv)=>{let r=t.startsWith("-")?"":t.length===1?"-":"--",o=e.indexOf(r+t),a=e.indexOf("--");return o!==-1&&(a===-1||o<a)}});var dL=_((RQt,mX)=>{"use strict";var S5e=ve("os"),dX=ve("tty"),Ul=gX(),{env:ls}=process,Jp;Ul("no-color")||Ul("no-colors")||Ul("color=false")||Ul("color=never")?Jp=0:(Ul("color")||Ul("colors")||Ul("color=true")||Ul("color=always"))&&(Jp=1);"FORCE_COLOR"in ls&&(ls.FORCE_COLOR==="true"?Jp=1:ls.FORCE_COLOR==="false"?Jp=0:Jp=ls.FORCE_COLOR.length===0?1:Math.min(parseInt(ls.FORCE_COLOR,10),3));function hL(t){return t===0?!1:{level:t,hasBasic:!0,has256:t>=2,has16m:t>=3}}function gL(t,e){if(Jp===0)return 0;if(Ul("color=16m")||Ul("color=full")||Ul("color=truecolor"))return 3;if(Ul("color=256"))return 2;if(t&&!e&&Jp===void 0)return 0;let r=Jp||0;if(ls.TERM==="dumb")return r;if(process.platform==="win32"){let o=S5e.release().split(".");return Number(o[0])>=10&&Number(o[2])>=10586?Number(o[2])>=14931?3:2:1}if("CI"in ls)return["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI"].some(o=>o in ls)||ls.CI_NAME==="codeship"?1:r;if("TEAMCITY_VERSION"in ls)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(ls.TEAMCITY_VERSION)?1:0;if("GITHUB_ACTIONS"in ls)return 1;if(ls.COLORTERM==="truecolor")return 3;if("TERM_PROGRAM"in ls){let o=parseInt((ls.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(ls.TERM_PROGRAM){case"iTerm.app":return o>=3?3:2;case"Apple_Terminal":return 2}}return/-256(color)?$/i.test(ls.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(ls.TERM)||"COLORTERM"in ls?1:r}function b5e(t){let e=gL(t,t&&t.isTTY);return hL(e)}mX.exports={supportsColor:b5e,stdout:hL(gL(!0,dX.isatty(1))),stderr:hL(gL(!0,dX.isatty(2)))}});var EX=_((TQt,yX)=>{"use strict";var x5e=(t,e,r)=>{let o=t.indexOf(e);if(o===-1)return t;let a=e.length,n=0,u="";do u+=t.substr(n,o-n)+e+r,n=o+a,o=t.indexOf(e,n);while(o!==-1);return u+=t.substr(n),u},k5e=(t,e,r,o)=>{let a=0,n="";do{let u=t[o-1]==="\r";n+=t.substr(a,(u?o-1:o)-a)+e+(u?`\r
-`:`
-`)+r,a=o+1,o=t.indexOf(`
-`,a)}while(o!==-1);return n+=t.substr(a),n};yX.exports={stringReplaceAll:x5e,stringEncaseCRLFWithFirstIndex:k5e}});var vX=_((LQt,BX)=>{"use strict";var Q5e=/(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi,CX=/(?:^|\.)(\w+)(?:\(([^)]*)\))?/g,F5e=/^(['"])((?:\\.|(?!\1)[^\\])*)\1$/,R5e=/\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.)|([^\\])/gi,T5e=new Map([["n",`
-`],["r","\r"],["t"," "],["b","\b"],["f","\f"],["v","\v"],["0","\0"],["\\","\\"],["e","\x1B"],["a","\x07"]]);function IX(t){let e=t[0]==="u",r=t[1]==="{";return e&&!r&&t.length===5||t[0]==="x"&&t.length===3?String.fromCharCode(parseInt(t.slice(1),16)):e&&r?String.fromCodePoint(parseInt(t.slice(2,-1),16)):T5e.get(t)||t}function L5e(t,e){let r=[],o=e.trim().split(/\s*,\s*/g),a;for(let n of o){let u=Number(n);if(!Number.isNaN(u))r.push(u);else if(a=n.match(F5e))r.push(a[2].replace(R5e,(A,p,h)=>p?IX(p):h));else throw new Error(`Invalid Chalk template style argument: ${n} (in style '${t}')`)}return r}function N5e(t){CX.lastIndex=0;let e=[],r;for(;(r=CX.exec(t))!==null;){let o=r[1];if(r[2]){let a=L5e(o,r[2]);e.push([o].concat(a))}else e.push([o])}return e}function wX(t,e){let r={};for(let a of e)for(let n of a.styles)r[n[0]]=a.inverse?null:n.slice(1);let o=t;for(let[a,n]of Object.entries(r))if(!!Array.isArray(n)){if(!(a in o))throw new Error(`Unknown Chalk style: ${a}`);o=n.length>0?o[a](...n):o[a]}return o}BX.exports=(t,e)=>{let r=[],o=[],a=[];if(e.replace(Q5e,(n,u,A,p,h,E)=>{if(u)a.push(IX(u));else if(p){let I=a.join("");a=[],o.push(r.length===0?I:wX(t,r)(I)),r.push({inverse:A,styles:N5e(p)})}else if(h){if(r.length===0)throw new Error("Found extraneous } in Chalk template literal");o.push(wX(t,r)(a.join(""))),a=[],r.pop()}else a.push(E)}),o.push(a.join("")),r.length>0){let n=`Chalk template literal is missing ${r.length} closing bracket${r.length===1?"":"s"} (\`}\`)`;throw new Error(n)}return o.join("")}});var IL=_((NQt,bX)=>{"use strict";var PI=DI(),{stdout:yL,stderr:EL}=dL(),{stringReplaceAll:O5e,stringEncaseCRLFWithFirstIndex:M5e}=EX(),DX=["ansi","ansi","ansi256","ansi16m"],Fy=Object.create(null),U5e=(t,e={})=>{if(e.level>3||e.level<0)throw new Error("The `level` option should be an integer from 0 to 3");let r=yL?yL.level:0;t.level=e.level===void 0?r:e.level},CL=class{constructor(e){return PX(e)}},PX=t=>{let e={};return U5e(e,t),e.template=(...r)=>q5e(e.template,...r),Object.setPrototypeOf(e,bP.prototype),Object.setPrototypeOf(e.template,e),e.template.constructor=()=>{throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.")},e.template.Instance=CL,e.template};function bP(t){return PX(t)}for(let[t,e]of Object.entries(PI))Fy[t]={get(){let r=xP(this,wL(e.open,e.close,this._styler),this._isEmpty);return Object.defineProperty(this,t,{value:r}),r}};Fy.visible={get(){let t=xP(this,this._styler,!0);return Object.defineProperty(this,"visible",{value:t}),t}};var SX=["rgb","hex","keyword","hsl","hsv","hwb","ansi","ansi256"];for(let t of SX)Fy[t]={get(){let{level:e}=this;return function(...r){let o=wL(PI.color[DX[e]][t](...r),PI.color.close,this._styler);return xP(this,o,this._isEmpty)}}};for(let t of SX){let e="bg"+t[0].toUpperCase()+t.slice(1);Fy[e]={get(){let{level:r}=this;return function(...o){let a=wL(PI.bgColor[DX[r]][t](...o),PI.bgColor.close,this._styler);return xP(this,a,this._isEmpty)}}}}var _5e=Object.defineProperties(()=>{},{...Fy,level:{enumerable:!0,get(){return this._generator.level},set(t){this._generator.level=t}}}),wL=(t,e,r)=>{let o,a;return r===void 0?(o=t,a=e):(o=r.openAll+t,a=e+r.closeAll),{open:t,close:e,openAll:o,closeAll:a,parent:r}},xP=(t,e,r)=>{let o=(...a)=>H5e(o,a.length===1?""+a[0]:a.join(" "));return o.__proto__=_5e,o._generator=t,o._styler=e,o._isEmpty=r,o},H5e=(t,e)=>{if(t.level<=0||!e)return t._isEmpty?"":e;let r=t._styler;if(r===void 0)return e;let{openAll:o,closeAll:a}=r;if(e.indexOf("\x1B")!==-1)for(;r!==void 0;)e=O5e(e,r.close,r.open),r=r.parent;let n=e.indexOf(`
-`);return n!==-1&&(e=M5e(e,a,o,n)),o+e+a},mL,q5e=(t,...e)=>{let[r]=e;if(!Array.isArray(r))return e.join(" ");let o=e.slice(1),a=[r.raw[0]];for(let n=1;n<r.length;n++)a.push(String(o[n-1]).replace(/[{}\\]/g,"\\$&"),String(r.raw[n]));return mL===void 0&&(mL=vX()),mL(t,a.join(""))};Object.defineProperties(bP.prototype,Fy);var SI=bP();SI.supportsColor=yL;SI.stderr=bP({level:EL?EL.level:0});SI.stderr.supportsColor=EL;SI.Level={None:0,Basic:1,Ansi256:2,TrueColor:3,0:"None",1:"Basic",2:"Ansi256",3:"TrueColor"};bX.exports=SI});var kP=_(_l=>{"use strict";_l.isInteger=t=>typeof t=="number"?Number.isInteger(t):typeof t=="string"&&t.trim()!==""?Number.isInteger(Number(t)):!1;_l.find=(t,e)=>t.nodes.find(r=>r.type===e);_l.exceedsLimit=(t,e,r=1,o)=>o===!1||!_l.isInteger(t)||!_l.isInteger(e)?!1:(Number(e)-Number(t))/Number(r)>=o;_l.escapeNode=(t,e=0,r)=>{let o=t.nodes[e];!o||(r&&o.type===r||o.type==="open"||o.type==="close")&&o.escaped!==!0&&(o.value="\\"+o.value,o.escaped=!0)};_l.encloseBrace=t=>t.type!=="brace"?!1:t.commas>>0+t.ranges>>0===0?(t.invalid=!0,!0):!1;_l.isInvalidBrace=t=>t.type!=="brace"?!1:t.invalid===!0||t.dollar?!0:t.commas>>0+t.ranges>>0===0||t.open!==!0||t.close!==!0?(t.invalid=!0,!0):!1;_l.isOpenOrClose=t=>t.type==="open"||t.type==="close"?!0:t.open===!0||t.close===!0;_l.reduce=t=>t.reduce((e,r)=>(r.type==="text"&&e.push(r.value),r.type==="range"&&(r.type="text"),e),[]);_l.flatten=(...t)=>{let e=[],r=o=>{for(let a=0;a<o.length;a++){let n=o[a];Array.isArray(n)?r(n,e):n!==void 0&&e.push(n)}return e};return r(t),e}});var QP=_((MQt,kX)=>{"use strict";var xX=kP();kX.exports=(t,e={})=>{let r=(o,a={})=>{let n=e.escapeInvalid&&xX.isInvalidBrace(a),u=o.invalid===!0&&e.escapeInvalid===!0,A="";if(o.value)return(n||u)&&xX.isOpenOrClose(o)?"\\"+o.value:o.value;if(o.value)return o.value;if(o.nodes)for(let p of o.nodes)A+=r(p);return A};return r(t)}});var FX=_((UQt,QX)=>{"use strict";QX.exports=function(t){return typeof t=="number"?t-t===0:typeof t=="string"&&t.trim()!==""?Number.isFinite?Number.isFinite(+t):isFinite(+t):!1}});var HX=_((_Qt,_X)=>{"use strict";var RX=FX(),fd=(t,e,r)=>{if(RX(t)===!1)throw new TypeError("toRegexRange: expected the first argument to be a number");if(e===void 0||t===e)return String(t);if(RX(e)===!1)throw new TypeError("toRegexRange: expected the second argument to be a number.");let o={relaxZeros:!0,...r};typeof o.strictZeros=="boolean"&&(o.relaxZeros=o.strictZeros===!1);let a=String(o.relaxZeros),n=String(o.shorthand),u=String(o.capture),A=String(o.wrap),p=t+":"+e+"="+a+n+u+A;if(fd.cache.hasOwnProperty(p))return fd.cache[p].result;let h=Math.min(t,e),E=Math.max(t,e);if(Math.abs(h-E)===1){let R=t+"|"+e;return o.capture?`(${R})`:o.wrap===!1?R:`(?:${R})`}let I=UX(t)||UX(e),v={min:t,max:e,a:h,b:E},x=[],C=[];if(I&&(v.isPadded=I,v.maxLen=String(v.max).length),h<0){let R=E<0?Math.abs(E):1;C=TX(R,Math.abs(h),v,o),h=v.a=0}return E>=0&&(x=TX(h,E,v,o)),v.negatives=C,v.positives=x,v.result=G5e(C,x,o),o.capture===!0?v.result=`(${v.result})`:o.wrap!==!1&&x.length+C.length>1&&(v.result=`(?:${v.result})`),fd.cache[p]=v,v.result};function G5e(t,e,r){let o=BL(t,e,"-",!1,r)||[],a=BL(e,t,"",!1,r)||[],n=BL(t,e,"-?",!0,r)||[];return o.concat(n).concat(a).join("|")}function j5e(t,e){let r=1,o=1,a=NX(t,r),n=new Set([e]);for(;t<=a&&a<=e;)n.add(a),r+=1,a=NX(t,r);for(a=OX(e+1,o)-1;t<a&&a<=e;)n.add(a),o+=1,a=OX(e+1,o)-1;return n=[...n],n.sort(K5e),n}function Y5e(t,e,r){if(t===e)return{pattern:t,count:[],digits:0};let o=W5e(t,e),a=o.length,n="",u=0;for(let A=0;A<a;A++){let[p,h]=o[A];p===h?n+=p:p!=="0"||h!=="9"?n+=z5e(p,h,r):u++}return u&&(n+=r.shorthand===!0?"\\d":"[0-9]"),{pattern:n,count:[u],digits:a}}function TX(t,e,r,o){let a=j5e(t,e),n=[],u=t,A;for(let p=0;p<a.length;p++){let h=a[p],E=Y5e(String(u),String(h),o),I="";if(!r.isPadded&&A&&A.pattern===E.pattern){A.count.length>1&&A.count.pop(),A.count.push(E.count[0]),A.string=A.pattern+MX(A.count),u=h+1;continue}r.isPadded&&(I=V5e(h,r,o)),E.string=I+E.pattern+MX(E.count),n.push(E),u=h+1,A=E}return n}function BL(t,e,r,o,a){let n=[];for(let u of t){let{string:A}=u;!o&&!LX(e,"string",A)&&n.push(r+A),o&&LX(e,"string",A)&&n.push(r+A)}return n}function W5e(t,e){let r=[];for(let o=0;o<t.length;o++)r.push([t[o],e[o]]);return r}function K5e(t,e){return t>e?1:e>t?-1:0}function LX(t,e,r){return t.some(o=>o[e]===r)}function NX(t,e){return Number(String(t).slice(0,-e)+"9".repeat(e))}function OX(t,e){return t-t%Math.pow(10,e)}function MX(t){let[e=0,r=""]=t;return r||e>1?`{${e+(r?","+r:"")}}`:""}function z5e(t,e,r){return`[${t}${e-t===1?"":"-"}${e}]`}function UX(t){return/^-?(0+)\d/.test(t)}function V5e(t,e,r){if(!e.isPadded)return t;let o=Math.abs(e.maxLen-String(t).length),a=r.relaxZeros!==!1;switch(o){case 0:return"";case 1:return a?"0?":"0";case 2:return a?"0{0,2}":"00";default:return a?`0{0,${o}}`:`0{${o}}`}}fd.cache={};fd.clearCache=()=>fd.cache={};_X.exports=fd});var PL=_((HQt,VX)=>{"use strict";var J5e=ve("util"),jX=HX(),qX=t=>t!==null&&typeof t=="object"&&!Array.isArray(t),X5e=t=>e=>t===!0?Number(e):String(e),vL=t=>typeof t=="number"||typeof t=="string"&&t!=="",bI=t=>Number.isInteger(+t),DL=t=>{let e=`${t}`,r=-1;if(e[0]==="-"&&(e=e.slice(1)),e==="0")return!1;for(;e[++r]==="0";);return r>0},Z5e=(t,e,r)=>typeof t=="string"||typeof e=="string"?!0:r.stringify===!0,$5e=(t,e,r)=>{if(e>0){let o=t[0]==="-"?"-":"";o&&(t=t.slice(1)),t=o+t.padStart(o?e-1:e,"0")}return r===!1?String(t):t},GX=(t,e)=>{let r=t[0]==="-"?"-":"";for(r&&(t=t.slice(1),e--);t.length<e;)t="0"+t;return r?"-"+t:t},e7e=(t,e)=>{t.negatives.sort((u,A)=>u<A?-1:u>A?1:0),t.positives.sort((u,A)=>u<A?-1:u>A?1:0);let r=e.capture?"":"?:",o="",a="",n;return t.positives.length&&(o=t.positives.join("|")),t.negatives.length&&(a=`-(${r}${t.negatives.join("|")})`),o&&a?n=`${o}|${a}`:n=o||a,e.wrap?`(${r}${n})`:n},YX=(t,e,r,o)=>{if(r)return jX(t,e,{wrap:!1,...o});let a=String.fromCharCode(t);if(t===e)return a;let n=String.fromCharCode(e);return`[${a}-${n}]`},WX=(t,e,r)=>{if(Array.isArray(t)){let o=r.wrap===!0,a=r.capture?"":"?:";return o?`(${a}${t.join("|")})`:t.join("|")}return jX(t,e,r)},KX=(...t)=>new RangeError("Invalid range arguments: "+J5e.inspect(...t)),zX=(t,e,r)=>{if(r.strictRanges===!0)throw KX([t,e]);return[]},t7e=(t,e)=>{if(e.strictRanges===!0)throw new TypeError(`Expected step "${t}" to be a number`);return[]},r7e=(t,e,r=1,o={})=>{let a=Number(t),n=Number(e);if(!Number.isInteger(a)||!Number.isInteger(n)){if(o.strictRanges===!0)throw KX([t,e]);return[]}a===0&&(a=0),n===0&&(n=0);let u=a>n,A=String(t),p=String(e),h=String(r);r=Math.max(Math.abs(r),1);let E=DL(A)||DL(p)||DL(h),I=E?Math.max(A.length,p.length,h.length):0,v=E===!1&&Z5e(t,e,o)===!1,x=o.transform||X5e(v);if(o.toRegex&&r===1)return YX(GX(t,I),GX(e,I),!0,o);let C={negatives:[],positives:[]},R=V=>C[V<0?"negatives":"positives"].push(Math.abs(V)),N=[],U=0;for(;u?a>=n:a<=n;)o.toRegex===!0&&r>1?R(a):N.push($5e(x(a,U),I,v)),a=u?a-r:a+r,U++;return o.toRegex===!0?r>1?e7e(C,o):WX(N,null,{wrap:!1,...o}):N},n7e=(t,e,r=1,o={})=>{if(!bI(t)&&t.length>1||!bI(e)&&e.length>1)return zX(t,e,o);let a=o.transform||(v=>String.fromCharCode(v)),n=`${t}`.charCodeAt(0),u=`${e}`.charCodeAt(0),A=n>u,p=Math.min(n,u),h=Math.max(n,u);if(o.toRegex&&r===1)return YX(p,h,!1,o);let E=[],I=0;for(;A?n>=u:n<=u;)E.push(a(n,I)),n=A?n-r:n+r,I++;return o.toRegex===!0?WX(E,null,{wrap:!1,options:o}):E},FP=(t,e,r,o={})=>{if(e==null&&vL(t))return[t];if(!vL(t)||!vL(e))return zX(t,e,o);if(typeof r=="function")return FP(t,e,1,{transform:r});if(qX(r))return FP(t,e,0,r);let a={...o};return a.capture===!0&&(a.wrap=!0),r=r||a.step||1,bI(r)?bI(t)&&bI(e)?r7e(t,e,r,a):n7e(t,e,Math.max(Math.abs(r),1),a):r!=null&&!qX(r)?t7e(r,a):FP(t,e,1,r)};VX.exports=FP});var ZX=_((qQt,XX)=>{"use strict";var i7e=PL(),JX=kP(),s7e=(t,e={})=>{let r=(o,a={})=>{let n=JX.isInvalidBrace(a),u=o.invalid===!0&&e.escapeInvalid===!0,A=n===!0||u===!0,p=e.escapeInvalid===!0?"\\":"",h="";if(o.isOpen===!0||o.isClose===!0)return p+o.value;if(o.type==="open")return A?p+o.value:"(";if(o.type==="close")return A?p+o.value:")";if(o.type==="comma")return o.prev.type==="comma"?"":A?o.value:"|";if(o.value)return o.value;if(o.nodes&&o.ranges>0){let E=JX.reduce(o.nodes),I=i7e(...E,{...e,wrap:!1,toRegex:!0});if(I.length!==0)return E.length>1&&I.length>1?`(${I})`:I}if(o.nodes)for(let E of o.nodes)h+=r(E,o);return h};return r(t)};XX.exports=s7e});var tZ=_((GQt,eZ)=>{"use strict";var o7e=PL(),$X=QP(),Ry=kP(),pd=(t="",e="",r=!1)=>{let o=[];if(t=[].concat(t),e=[].concat(e),!e.length)return t;if(!t.length)return r?Ry.flatten(e).map(a=>`{${a}}`):e;for(let a of t)if(Array.isArray(a))for(let n of a)o.push(pd(n,e,r));else for(let n of e)r===!0&&typeof n=="string"&&(n=`{${n}}`),o.push(Array.isArray(n)?pd(a,n,r):a+n);return Ry.flatten(o)},a7e=(t,e={})=>{let r=e.rangeLimit===void 0?1e3:e.rangeLimit,o=(a,n={})=>{a.queue=[];let u=n,A=n.queue;for(;u.type!=="brace"&&u.type!=="root"&&u.parent;)u=u.parent,A=u.queue;if(a.invalid||a.dollar){A.push(pd(A.pop(),$X(a,e)));return}if(a.type==="brace"&&a.invalid!==!0&&a.nodes.length===2){A.push(pd(A.pop(),["{}"]));return}if(a.nodes&&a.ranges>0){let I=Ry.reduce(a.nodes);if(Ry.exceedsLimit(...I,e.step,r))throw new RangeError("expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.");let v=o7e(...I,e);v.length===0&&(v=$X(a,e)),A.push(pd(A.pop(),v)),a.nodes=[];return}let p=Ry.encloseBrace(a),h=a.queue,E=a;for(;E.type!=="brace"&&E.type!=="root"&&E.parent;)E=E.parent,h=E.queue;for(let I=0;I<a.nodes.length;I++){let v=a.nodes[I];if(v.type==="comma"&&a.type==="brace"){I===1&&h.push(""),h.push("");continue}if(v.type==="close"){A.push(pd(A.pop(),h,p));continue}if(v.value&&v.type!=="open"){h.push(pd(h.pop(),v.value));continue}v.nodes&&o(v,a)}return h};return Ry.flatten(o(t))};eZ.exports=a7e});var nZ=_((jQt,rZ)=>{"use strict";rZ.exports={MAX_LENGTH:1024*64,CHAR_0:"0",CHAR_9:"9",CHAR_UPPERCASE_A:"A",CHAR_LOWERCASE_A:"a",CHAR_UPPERCASE_Z:"Z",CHAR_LOWERCASE_Z:"z",CHAR_LEFT_PARENTHESES:"(",CHAR_RIGHT_PARENTHESES:")",CHAR_ASTERISK:"*",CHAR_AMPERSAND:"&",CHAR_AT:"@",CHAR_BACKSLASH:"\\",CHAR_BACKTICK:"`",CHAR_CARRIAGE_RETURN:"\r",CHAR_CIRCUMFLEX_ACCENT:"^",CHAR_COLON:":",CHAR_COMMA:",",CHAR_DOLLAR:"$",CHAR_DOT:".",CHAR_DOUBLE_QUOTE:'"',CHAR_EQUAL:"=",CHAR_EXCLAMATION_MARK:"!",CHAR_FORM_FEED:"\f",CHAR_FORWARD_SLASH:"/",CHAR_HASH:"#",CHAR_HYPHEN_MINUS:"-",CHAR_LEFT_ANGLE_BRACKET:"<",CHAR_LEFT_CURLY_BRACE:"{",CHAR_LEFT_SQUARE_BRACKET:"[",CHAR_LINE_FEED:`
-`,CHAR_NO_BREAK_SPACE:"\xA0",CHAR_PERCENT:"%",CHAR_PLUS:"+",CHAR_QUESTION_MARK:"?",CHAR_RIGHT_ANGLE_BRACKET:">",CHAR_RIGHT_CURLY_BRACE:"}",CHAR_RIGHT_SQUARE_BRACKET:"]",CHAR_SEMICOLON:";",CHAR_SINGLE_QUOTE:"'",CHAR_SPACE:" ",CHAR_TAB:" ",CHAR_UNDERSCORE:"_",CHAR_VERTICAL_LINE:"|",CHAR_ZERO_WIDTH_NOBREAK_SPACE:"\uFEFF"}});var lZ=_((YQt,aZ)=>{"use strict";var l7e=QP(),{MAX_LENGTH:iZ,CHAR_BACKSLASH:SL,CHAR_BACKTICK:c7e,CHAR_COMMA:u7e,CHAR_DOT:A7e,CHAR_LEFT_PARENTHESES:f7e,CHAR_RIGHT_PARENTHESES:p7e,CHAR_LEFT_CURLY_BRACE:h7e,CHAR_RIGHT_CURLY_BRACE:g7e,CHAR_LEFT_SQUARE_BRACKET:sZ,CHAR_RIGHT_SQUARE_BRACKET:oZ,CHAR_DOUBLE_QUOTE:d7e,CHAR_SINGLE_QUOTE:m7e,CHAR_NO_BREAK_SPACE:y7e,CHAR_ZERO_WIDTH_NOBREAK_SPACE:E7e}=nZ(),C7e=(t,e={})=>{if(typeof t!="string")throw new TypeError("Expected a string");let r=e||{},o=typeof r.maxLength=="number"?Math.min(iZ,r.maxLength):iZ;if(t.length>o)throw new SyntaxError(`Input length (${t.length}), exceeds max characters (${o})`);let a={type:"root",input:t,nodes:[]},n=[a],u=a,A=a,p=0,h=t.length,E=0,I=0,v,x={},C=()=>t[E++],R=N=>{if(N.type==="text"&&A.type==="dot"&&(A.type="text"),A&&A.type==="text"&&N.type==="text"){A.value+=N.value;return}return u.nodes.push(N),N.parent=u,N.prev=A,A=N,N};for(R({type:"bos"});E<h;)if(u=n[n.length-1],v=C(),!(v===E7e||v===y7e)){if(v===SL){R({type:"text",value:(e.keepEscaping?v:"")+C()});continue}if(v===oZ){R({type:"text",value:"\\"+v});continue}if(v===sZ){p++;let N=!0,U;for(;E<h&&(U=C());){if(v+=U,U===sZ){p++;continue}if(U===SL){v+=C();continue}if(U===oZ&&(p--,p===0))break}R({type:"text",value:v});continue}if(v===f7e){u=R({type:"paren",nodes:[]}),n.push(u),R({type:"text",value:v});continue}if(v===p7e){if(u.type!=="paren"){R({type:"text",value:v});continue}u=n.pop(),R({type:"text",value:v}),u=n[n.length-1];continue}if(v===d7e||v===m7e||v===c7e){let N=v,U;for(e.keepQuotes!==!0&&(v="");E<h&&(U=C());){if(U===SL){v+=U+C();continue}if(U===N){e.keepQuotes===!0&&(v+=U);break}v+=U}R({type:"text",value:v});continue}if(v===h7e){I++;let U={type:"brace",open:!0,close:!1,dollar:A.value&&A.value.slice(-1)==="$"||u.dollar===!0,depth:I,commas:0,ranges:0,nodes:[]};u=R(U),n.push(u),R({type:"open",value:v});continue}if(v===g7e){if(u.type!=="brace"){R({type:"text",value:v});continue}let N="close";u=n.pop(),u.close=!0,R({type:N,value:v}),I--,u=n[n.length-1];continue}if(v===u7e&&I>0){if(u.ranges>0){u.ranges=0;let N=u.nodes.shift();u.nodes=[N,{type:"text",value:l7e(u)}]}R({type:"comma",value:v}),u.commas++;continue}if(v===A7e&&I>0&&u.commas===0){let N=u.nodes;if(I===0||N.length===0){R({type:"text",value:v});continue}if(A.type==="dot"){if(u.range=[],A.value+=v,A.type="range",u.nodes.length!==3&&u.nodes.length!==5){u.invalid=!0,u.ranges=0,A.type="text";continue}u.ranges++,u.args=[];continue}if(A.type==="range"){N.pop();let U=N[N.length-1];U.value+=A.value+v,A=U,u.ranges--;continue}R({type:"dot",value:v});continue}R({type:"text",value:v})}do if(u=n.pop(),u.type!=="root"){u.nodes.forEach(V=>{V.nodes||(V.type==="open"&&(V.isOpen=!0),V.type==="close"&&(V.isClose=!0),V.nodes||(V.type="text"),V.invalid=!0)});let N=n[n.length-1],U=N.nodes.indexOf(u);N.nodes.splice(U,1,...u.nodes)}while(n.length>0);return R({type:"eos"}),a};aZ.exports=C7e});var AZ=_((WQt,uZ)=>{"use strict";var cZ=QP(),w7e=ZX(),I7e=tZ(),B7e=lZ(),nl=(t,e={})=>{let r=[];if(Array.isArray(t))for(let o of t){let a=nl.create(o,e);Array.isArray(a)?r.push(...a):r.push(a)}else r=[].concat(nl.create(t,e));return e&&e.expand===!0&&e.nodupes===!0&&(r=[...new Set(r)]),r};nl.parse=(t,e={})=>B7e(t,e);nl.stringify=(t,e={})=>cZ(typeof t=="string"?nl.parse(t,e):t,e);nl.compile=(t,e={})=>(typeof t=="string"&&(t=nl.parse(t,e)),w7e(t,e));nl.expand=(t,e={})=>{typeof t=="string"&&(t=nl.parse(t,e));let r=I7e(t,e);return e.noempty===!0&&(r=r.filter(Boolean)),e.nodupes===!0&&(r=[...new Set(r)]),r};nl.create=(t,e={})=>t===""||t.length<3?[t]:e.expand!==!0?nl.compile(t,e):nl.expand(t,e);uZ.exports=nl});var xI=_((KQt,dZ)=>{"use strict";var v7e=ve("path"),zu="\\\\/",fZ=`[^${zu}]`,vf="\\.",D7e="\\+",P7e="\\?",RP="\\/",S7e="(?=.)",pZ="[^/]",bL=`(?:${RP}|$)`,hZ=`(?:^|${RP})`,xL=`${vf}{1,2}${bL}`,b7e=`(?!${vf})`,x7e=`(?!${hZ}${xL})`,k7e=`(?!${vf}{0,1}${bL})`,Q7e=`(?!${xL})`,F7e=`[^.${RP}]`,R7e=`${pZ}*?`,gZ={DOT_LITERAL:vf,PLUS_LITERAL:D7e,QMARK_LITERAL:P7e,SLASH_LITERAL:RP,ONE_CHAR:S7e,QMARK:pZ,END_ANCHOR:bL,DOTS_SLASH:xL,NO_DOT:b7e,NO_DOTS:x7e,NO_DOT_SLASH:k7e,NO_DOTS_SLASH:Q7e,QMARK_NO_DOT:F7e,STAR:R7e,START_ANCHOR:hZ},T7e={...gZ,SLASH_LITERAL:`[${zu}]`,QMARK:fZ,STAR:`${fZ}*?`,DOTS_SLASH:`${vf}{1,2}(?:[${zu}]|$)`,NO_DOT:`(?!${vf})`,NO_DOTS:`(?!(?:^|[${zu}])${vf}{1,2}(?:[${zu}]|$))`,NO_DOT_SLASH:`(?!${vf}{0,1}(?:[${zu}]|$))`,NO_DOTS_SLASH:`(?!${vf}{1,2}(?:[${zu}]|$))`,QMARK_NO_DOT:`[^.${zu}]`,START_ANCHOR:`(?:^|[${zu}])`,END_ANCHOR:`(?:[${zu}]|$)`},L7e={alnum:"a-zA-Z0-9",alpha:"a-zA-Z",ascii:"\\x00-\\x7F",blank:" \\t",cntrl:"\\x00-\\x1F\\x7F",digit:"0-9",graph:"\\x21-\\x7E",lower:"a-z",print:"\\x20-\\x7E ",punct:"\\-!\"#$%&'()\\*+,./:;<=>?@[\\]^_`{|}~",space:" \\t\\r\\n\\v\\f",upper:"A-Z",word:"A-Za-z0-9_",xdigit:"A-Fa-f0-9"};dZ.exports={MAX_LENGTH:1024*64,POSIX_REGEX_SOURCE:L7e,REGEX_BACKSLASH:/\\(?![*+?^${}(|)[\]])/g,REGEX_NON_SPECIAL_CHARS:/^[^@![\].,$*+?^{}()|\\/]+/,REGEX_SPECIAL_CHARS:/[-*+?.^${}(|)[\]]/,REGEX_SPECIAL_CHARS_BACKREF:/(\\?)((\W)(\3*))/g,REGEX_SPECIAL_CHARS_GLOBAL:/([-*+?.^${}(|)[\]])/g,REGEX_REMOVE_BACKSLASH:/(?:\[.*?[^\\]\]|\\(?=.))/g,REPLACEMENTS:{"***":"*","**/**":"**","**/**/**":"**"},CHAR_0:48,CHAR_9:57,CHAR_UPPERCASE_A:65,CHAR_LOWERCASE_A:97,CHAR_UPPERCASE_Z:90,CHAR_LOWERCASE_Z:122,CHAR_LEFT_PARENTHESES:40,CHAR_RIGHT_PARENTHESES:41,CHAR_ASTERISK:42,CHAR_AMPERSAND:38,CHAR_AT:64,CHAR_BACKWARD_SLASH:92,CHAR_CARRIAGE_RETURN:13,CHAR_CIRCUMFLEX_ACCENT:94,CHAR_COLON:58,CHAR_COMMA:44,CHAR_DOT:46,CHAR_DOUBLE_QUOTE:34,CHAR_EQUAL:61,CHAR_EXCLAMATION_MARK:33,CHAR_FORM_FEED:12,CHAR_FORWARD_SLASH:47,CHAR_GRAVE_ACCENT:96,CHAR_HASH:35,CHAR_HYPHEN_MINUS:45,CHAR_LEFT_ANGLE_BRACKET:60,CHAR_LEFT_CURLY_BRACE:123,CHAR_LEFT_SQUARE_BRACKET:91,CHAR_LINE_FEED:10,CHAR_NO_BREAK_SPACE:160,CHAR_PERCENT:37,CHAR_PLUS:43,CHAR_QUESTION_MARK:63,CHAR_RIGHT_ANGLE_BRACKET:62,CHAR_RIGHT_CURLY_BRACE:125,CHAR_RIGHT_SQUARE_BRACKET:93,CHAR_SEMICOLON:59,CHAR_SINGLE_QUOTE:39,CHAR_SPACE:32,CHAR_TAB:9,CHAR_UNDERSCORE:95,CHAR_VERTICAL_LINE:124,CHAR_ZERO_WIDTH_NOBREAK_SPACE:65279,SEP:v7e.sep,extglobChars(t){return{"!":{type:"negate",open:"(?:(?!(?:",close:`))${t.STAR})`},"?":{type:"qmark",open:"(?:",close:")?"},"+":{type:"plus",open:"(?:",close:")+"},"*":{type:"star",open:"(?:",close:")*"},"@":{type:"at",open:"(?:",close:")"}}},globChars(t){return t===!0?T7e:gZ}}});var kI=_(Pa=>{"use strict";var N7e=ve("path"),O7e=process.platform==="win32",{REGEX_BACKSLASH:M7e,REGEX_REMOVE_BACKSLASH:U7e,REGEX_SPECIAL_CHARS:_7e,REGEX_SPECIAL_CHARS_GLOBAL:H7e}=xI();Pa.isObject=t=>t!==null&&typeof t=="object"&&!Array.isArray(t);Pa.hasRegexChars=t=>_7e.test(t);Pa.isRegexChar=t=>t.length===1&&Pa.hasRegexChars(t);Pa.escapeRegex=t=>t.replace(H7e,"\\$1");Pa.toPosixSlashes=t=>t.replace(M7e,"/");Pa.removeBackslashes=t=>t.replace(U7e,e=>e==="\\"?"":e);Pa.supportsLookbehinds=()=>{let t=process.version.slice(1).split(".").map(Number);return t.length===3&&t[0]>=9||t[0]===8&&t[1]>=10};Pa.isWindows=t=>t&&typeof t.windows=="boolean"?t.windows:O7e===!0||N7e.sep==="\\";Pa.escapeLast=(t,e,r)=>{let o=t.lastIndexOf(e,r);return o===-1?t:t[o-1]==="\\"?Pa.escapeLast(t,e,o-1):`${t.slice(0,o)}\\${t.slice(o)}`};Pa.removePrefix=(t,e={})=>{let r=t;return r.startsWith("./")&&(r=r.slice(2),e.prefix="./"),r};Pa.wrapOutput=(t,e={},r={})=>{let o=r.contains?"":"^",a=r.contains?"":"$",n=`${o}(?:${t})${a}`;return e.negated===!0&&(n=`(?:^(?!${n}).*$)`),n}});var vZ=_((VQt,BZ)=>{"use strict";var mZ=kI(),{CHAR_ASTERISK:kL,CHAR_AT:q7e,CHAR_BACKWARD_SLASH:QI,CHAR_COMMA:G7e,CHAR_DOT:QL,CHAR_EXCLAMATION_MARK:FL,CHAR_FORWARD_SLASH:IZ,CHAR_LEFT_CURLY_BRACE:RL,CHAR_LEFT_PARENTHESES:TL,CHAR_LEFT_SQUARE_BRACKET:j7e,CHAR_PLUS:Y7e,CHAR_QUESTION_MARK:yZ,CHAR_RIGHT_CURLY_BRACE:W7e,CHAR_RIGHT_PARENTHESES:EZ,CHAR_RIGHT_SQUARE_BRACKET:K7e}=xI(),CZ=t=>t===IZ||t===QI,wZ=t=>{t.isPrefix!==!0&&(t.depth=t.isGlobstar?1/0:1)},z7e=(t,e)=>{let r=e||{},o=t.length-1,a=r.parts===!0||r.scanToEnd===!0,n=[],u=[],A=[],p=t,h=-1,E=0,I=0,v=!1,x=!1,C=!1,R=!1,N=!1,U=!1,V=!1,te=!1,ae=!1,fe=!1,ue=0,me,he,Be={value:"",depth:0,isGlob:!1},we=()=>h>=o,g=()=>p.charCodeAt(h+1),Ee=()=>(me=he,p.charCodeAt(++h));for(;h<o;){he=Ee();let Ie;if(he===QI){V=Be.backslashes=!0,he=Ee(),he===RL&&(U=!0);continue}if(U===!0||he===RL){for(ue++;we()!==!0&&(he=Ee());){if(he===QI){V=Be.backslashes=!0,Ee();continue}if(he===RL){ue++;continue}if(U!==!0&&he===QL&&(he=Ee())===QL){if(v=Be.isBrace=!0,C=Be.isGlob=!0,fe=!0,a===!0)continue;break}if(U!==!0&&he===G7e){if(v=Be.isBrace=!0,C=Be.isGlob=!0,fe=!0,a===!0)continue;break}if(he===W7e&&(ue--,ue===0)){U=!1,v=Be.isBrace=!0,fe=!0;break}}if(a===!0)continue;break}if(he===IZ){if(n.push(h),u.push(Be),Be={value:"",depth:0,isGlob:!1},fe===!0)continue;if(me===QL&&h===E+1){E+=2;continue}I=h+1;continue}if(r.noext!==!0&&(he===Y7e||he===q7e||he===kL||he===yZ||he===FL)===!0&&g()===TL){if(C=Be.isGlob=!0,R=Be.isExtglob=!0,fe=!0,he===FL&&h===E&&(ae=!0),a===!0){for(;we()!==!0&&(he=Ee());){if(he===QI){V=Be.backslashes=!0,he=Ee();continue}if(he===EZ){C=Be.isGlob=!0,fe=!0;break}}continue}break}if(he===kL){if(me===kL&&(N=Be.isGlobstar=!0),C=Be.isGlob=!0,fe=!0,a===!0)continue;break}if(he===yZ){if(C=Be.isGlob=!0,fe=!0,a===!0)continue;break}if(he===j7e){for(;we()!==!0&&(Ie=Ee());){if(Ie===QI){V=Be.backslashes=!0,Ee();continue}if(Ie===K7e){x=Be.isBracket=!0,C=Be.isGlob=!0,fe=!0;break}}if(a===!0)continue;break}if(r.nonegate!==!0&&he===FL&&h===E){te=Be.negated=!0,E++;continue}if(r.noparen!==!0&&he===TL){if(C=Be.isGlob=!0,a===!0){for(;we()!==!0&&(he=Ee());){if(he===TL){V=Be.backslashes=!0,he=Ee();continue}if(he===EZ){fe=!0;break}}continue}break}if(C===!0){if(fe=!0,a===!0)continue;break}}r.noext===!0&&(R=!1,C=!1);let Pe=p,ce="",ne="";E>0&&(ce=p.slice(0,E),p=p.slice(E),I-=E),Pe&&C===!0&&I>0?(Pe=p.slice(0,I),ne=p.slice(I)):C===!0?(Pe="",ne=p):Pe=p,Pe&&Pe!==""&&Pe!=="/"&&Pe!==p&&CZ(Pe.charCodeAt(Pe.length-1))&&(Pe=Pe.slice(0,-1)),r.unescape===!0&&(ne&&(ne=mZ.removeBackslashes(ne)),Pe&&V===!0&&(Pe=mZ.removeBackslashes(Pe)));let ee={prefix:ce,input:t,start:E,base:Pe,glob:ne,isBrace:v,isBracket:x,isGlob:C,isExtglob:R,isGlobstar:N,negated:te,negatedExtglob:ae};if(r.tokens===!0&&(ee.maxDepth=0,CZ(he)||u.push(Be),ee.tokens=u),r.parts===!0||r.tokens===!0){let Ie;for(let Fe=0;Fe<n.length;Fe++){let At=Ie?Ie+1:E,H=n[Fe],at=t.slice(At,H);r.tokens&&(Fe===0&&E!==0?(u[Fe].isPrefix=!0,u[Fe].value=ce):u[Fe].value=at,wZ(u[Fe]),ee.maxDepth+=u[Fe].depth),(Fe!==0||at!=="")&&A.push(at),Ie=H}if(Ie&&Ie+1<t.length){let Fe=t.slice(Ie+1);A.push(Fe),r.tokens&&(u[u.length-1].value=Fe,wZ(u[u.length-1]),ee.maxDepth+=u[u.length-1].depth)}ee.slashes=n,ee.parts=A}return ee};BZ.exports=z7e});var SZ=_((JQt,PZ)=>{"use strict";var TP=xI(),il=kI(),{MAX_LENGTH:LP,POSIX_REGEX_SOURCE:V7e,REGEX_NON_SPECIAL_CHARS:J7e,REGEX_SPECIAL_CHARS_BACKREF:X7e,REPLACEMENTS:DZ}=TP,Z7e=(t,e)=>{if(typeof e.expandRange=="function")return e.expandRange(...t,e);t.sort();let r=`[${t.join("-")}]`;try{new RegExp(r)}catch{return t.map(a=>il.escapeRegex(a)).join("..")}return r},Ty=(t,e)=>`Missing ${t}: "${e}" - use "\\\\${e}" to match literal characters`,LL=(t,e)=>{if(typeof t!="string")throw new TypeError("Expected a string");t=DZ[t]||t;let r={...e},o=typeof r.maxLength=="number"?Math.min(LP,r.maxLength):LP,a=t.length;if(a>o)throw new SyntaxError(`Input length: ${a}, exceeds maximum allowed length: ${o}`);let n={type:"bos",value:"",output:r.prepend||""},u=[n],A=r.capture?"":"?:",p=il.isWindows(e),h=TP.globChars(p),E=TP.extglobChars(h),{DOT_LITERAL:I,PLUS_LITERAL:v,SLASH_LITERAL:x,ONE_CHAR:C,DOTS_SLASH:R,NO_DOT:N,NO_DOT_SLASH:U,NO_DOTS_SLASH:V,QMARK:te,QMARK_NO_DOT:ae,STAR:fe,START_ANCHOR:ue}=h,me=b=>`(${A}(?:(?!${ue}${b.dot?R:I}).)*?)`,he=r.dot?"":N,Be=r.dot?te:ae,we=r.bash===!0?me(r):fe;r.capture&&(we=`(${we})`),typeof r.noext=="boolean"&&(r.noextglob=r.noext);let g={input:t,index:-1,start:0,dot:r.dot===!0,consumed:"",output:"",prefix:"",backtrack:!1,negated:!1,brackets:0,braces:0,parens:0,quotes:0,globstar:!1,tokens:u};t=il.removePrefix(t,g),a=t.length;let Ee=[],Pe=[],ce=[],ne=n,ee,Ie=()=>g.index===a-1,Fe=g.peek=(b=1)=>t[g.index+b],At=g.advance=()=>t[++g.index]||"",H=()=>t.slice(g.index+1),at=(b="",w=0)=>{g.consumed+=b,g.index+=w},Re=b=>{g.output+=b.output!=null?b.output:b.value,at(b.value)},ke=()=>{let b=1;for(;Fe()==="!"&&(Fe(2)!=="("||Fe(3)==="?");)At(),g.start++,b++;return b%2===0?!1:(g.negated=!0,g.start++,!0)},xe=b=>{g[b]++,ce.push(b)},He=b=>{g[b]--,ce.pop()},Te=b=>{if(ne.type==="globstar"){let w=g.braces>0&&(b.type==="comma"||b.type==="brace"),S=b.extglob===!0||Ee.length&&(b.type==="pipe"||b.type==="paren");b.type!=="slash"&&b.type!=="paren"&&!w&&!S&&(g.output=g.output.slice(0,-ne.output.length),ne.type="star",ne.value="*",ne.output=we,g.output+=ne.output)}if(Ee.length&&b.type!=="paren"&&(Ee[Ee.length-1].inner+=b.value),(b.value||b.output)&&Re(b),ne&&ne.type==="text"&&b.type==="text"){ne.value+=b.value,ne.output=(ne.output||"")+b.value;return}b.prev=ne,u.push(b),ne=b},Ve=(b,w)=>{let S={...E[w],conditions:1,inner:""};S.prev=ne,S.parens=g.parens,S.output=g.output;let y=(r.capture?"(":"")+S.open;xe("parens"),Te({type:b,value:w,output:g.output?"":C}),Te({type:"paren",extglob:!0,value:At(),output:y}),Ee.push(S)},qe=b=>{let w=b.close+(r.capture?")":""),S;if(b.type==="negate"){let y=we;if(b.inner&&b.inner.length>1&&b.inner.includes("/")&&(y=me(r)),(y!==we||Ie()||/^\)+$/.test(H()))&&(w=b.close=`)$))${y}`),b.inner.includes("*")&&(S=H())&&/^\.[^\\/.]+$/.test(S)){let F=LL(S,{...e,fastpaths:!1}).output;w=b.close=`)${F})${y})`}b.prev.type==="bos"&&(g.negatedExtglob=!0)}Te({type:"paren",extglob:!0,value:ee,output:w}),He("parens")};if(r.fastpaths!==!1&&!/(^[*!]|[/()[\]{}"])/.test(t)){let b=!1,w=t.replace(X7e,(S,y,F,J,X,Z)=>J==="\\"?(b=!0,S):J==="?"?y?y+J+(X?te.repeat(X.length):""):Z===0?Be+(X?te.repeat(X.length):""):te.repeat(F.length):J==="."?I.repeat(F.length):J==="*"?y?y+J+(X?we:""):we:y?S:`\\${S}`);return b===!0&&(r.unescape===!0?w=w.replace(/\\/g,""):w=w.replace(/\\+/g,S=>S.length%2===0?"\\\\":S?"\\":"")),w===t&&r.contains===!0?(g.output=t,g):(g.output=il.wrapOutput(w,g,e),g)}for(;!Ie();){if(ee=At(),ee==="\0")continue;if(ee==="\\"){let S=Fe();if(S==="/"&&r.bash!==!0||S==="."||S===";")continue;if(!S){ee+="\\",Te({type:"text",value:ee});continue}let y=/^\\+/.exec(H()),F=0;if(y&&y[0].length>2&&(F=y[0].length,g.index+=F,F%2!==0&&(ee+="\\")),r.unescape===!0?ee=At():ee+=At(),g.brackets===0){Te({type:"text",value:ee});continue}}if(g.brackets>0&&(ee!=="]"||ne.value==="["||ne.value==="[^")){if(r.posix!==!1&&ee===":"){let S=ne.value.slice(1);if(S.includes("[")&&(ne.posix=!0,S.includes(":"))){let y=ne.value.lastIndexOf("["),F=ne.value.slice(0,y),J=ne.value.slice(y+2),X=V7e[J];if(X){ne.value=F+X,g.backtrack=!0,At(),!n.output&&u.indexOf(ne)===1&&(n.output=C);continue}}}(ee==="["&&Fe()!==":"||ee==="-"&&Fe()==="]")&&(ee=`\\${ee}`),ee==="]"&&(ne.value==="["||ne.value==="[^")&&(ee=`\\${ee}`),r.posix===!0&&ee==="!"&&ne.value==="["&&(ee="^"),ne.value+=ee,Re({value:ee});continue}if(g.quotes===1&&ee!=='"'){ee=il.escapeRegex(ee),ne.value+=ee,Re({value:ee});continue}if(ee==='"'){g.quotes=g.quotes===1?0:1,r.keepQuotes===!0&&Te({type:"text",value:ee});continue}if(ee==="("){xe("parens"),Te({type:"paren",value:ee});continue}if(ee===")"){if(g.parens===0&&r.strictBrackets===!0)throw new SyntaxError(Ty("opening","("));let S=Ee[Ee.length-1];if(S&&g.parens===S.parens+1){qe(Ee.pop());continue}Te({type:"paren",value:ee,output:g.parens?")":"\\)"}),He("parens");continue}if(ee==="["){if(r.nobracket===!0||!H().includes("]")){if(r.nobracket!==!0&&r.strictBrackets===!0)throw new SyntaxError(Ty("closing","]"));ee=`\\${ee}`}else xe("brackets");Te({type:"bracket",value:ee});continue}if(ee==="]"){if(r.nobracket===!0||ne&&ne.type==="bracket"&&ne.value.length===1){Te({type:"text",value:ee,output:`\\${ee}`});continue}if(g.brackets===0){if(r.strictBrackets===!0)throw new SyntaxError(Ty("opening","["));Te({type:"text",value:ee,output:`\\${ee}`});continue}He("brackets");let S=ne.value.slice(1);if(ne.posix!==!0&&S[0]==="^"&&!S.includes("/")&&(ee=`/${ee}`),ne.value+=ee,Re({value:ee}),r.literalBrackets===!1||il.hasRegexChars(S))continue;let y=il.escapeRegex(ne.value);if(g.output=g.output.slice(0,-ne.value.length),r.literalBrackets===!0){g.output+=y,ne.value=y;continue}ne.value=`(${A}${y}|${ne.value})`,g.output+=ne.value;continue}if(ee==="{"&&r.nobrace!==!0){xe("braces");let S={type:"brace",value:ee,output:"(",outputIndex:g.output.length,tokensIndex:g.tokens.length};Pe.push(S),Te(S);continue}if(ee==="}"){let S=Pe[Pe.length-1];if(r.nobrace===!0||!S){Te({type:"text",value:ee,output:ee});continue}let y=")";if(S.dots===!0){let F=u.slice(),J=[];for(let X=F.length-1;X>=0&&(u.pop(),F[X].type!=="brace");X--)F[X].type!=="dots"&&J.unshift(F[X].value);y=Z7e(J,r),g.backtrack=!0}if(S.comma!==!0&&S.dots!==!0){let F=g.output.slice(0,S.outputIndex),J=g.tokens.slice(S.tokensIndex);S.value=S.output="\\{",ee=y="\\}",g.output=F;for(let X of J)g.output+=X.output||X.value}Te({type:"brace",value:ee,output:y}),He("braces"),Pe.pop();continue}if(ee==="|"){Ee.length>0&&Ee[Ee.length-1].conditions++,Te({type:"text",value:ee});continue}if(ee===","){let S=ee,y=Pe[Pe.length-1];y&&ce[ce.length-1]==="braces"&&(y.comma=!0,S="|"),Te({type:"comma",value:ee,output:S});continue}if(ee==="/"){if(ne.type==="dot"&&g.index===g.start+1){g.start=g.index+1,g.consumed="",g.output="",u.pop(),ne=n;continue}Te({type:"slash",value:ee,output:x});continue}if(ee==="."){if(g.braces>0&&ne.type==="dot"){ne.value==="."&&(ne.output=I);let S=Pe[Pe.length-1];ne.type="dots",ne.output+=ee,ne.value+=ee,S.dots=!0;continue}if(g.braces+g.parens===0&&ne.type!=="bos"&&ne.type!=="slash"){Te({type:"text",value:ee,output:I});continue}Te({type:"dot",value:ee,output:I});continue}if(ee==="?"){if(!(ne&&ne.value==="(")&&r.noextglob!==!0&&Fe()==="("&&Fe(2)!=="?"){Ve("qmark",ee);continue}if(ne&&ne.type==="paren"){let y=Fe(),F=ee;if(y==="<"&&!il.supportsLookbehinds())throw new Error("Node.js v10 or higher is required for regex lookbehinds");(ne.value==="("&&!/[!=<:]/.test(y)||y==="<"&&!/<([!=]|\w+>)/.test(H()))&&(F=`\\${ee}`),Te({type:"text",value:ee,output:F});continue}if(r.dot!==!0&&(ne.type==="slash"||ne.type==="bos")){Te({type:"qmark",value:ee,output:ae});continue}Te({type:"qmark",value:ee,output:te});continue}if(ee==="!"){if(r.noextglob!==!0&&Fe()==="("&&(Fe(2)!=="?"||!/[!=<:]/.test(Fe(3)))){Ve("negate",ee);continue}if(r.nonegate!==!0&&g.index===0){ke();continue}}if(ee==="+"){if(r.noextglob!==!0&&Fe()==="("&&Fe(2)!=="?"){Ve("plus",ee);continue}if(ne&&ne.value==="("||r.regex===!1){Te({type:"plus",value:ee,output:v});continue}if(ne&&(ne.type==="bracket"||ne.type==="paren"||ne.type==="brace")||g.parens>0){Te({type:"plus",value:ee});continue}Te({type:"plus",value:v});continue}if(ee==="@"){if(r.noextglob!==!0&&Fe()==="("&&Fe(2)!=="?"){Te({type:"at",extglob:!0,value:ee,output:""});continue}Te({type:"text",value:ee});continue}if(ee!=="*"){(ee==="$"||ee==="^")&&(ee=`\\${ee}`);let S=J7e.exec(H());S&&(ee+=S[0],g.index+=S[0].length),Te({type:"text",value:ee});continue}if(ne&&(ne.type==="globstar"||ne.star===!0)){ne.type="star",ne.star=!0,ne.value+=ee,ne.output=we,g.backtrack=!0,g.globstar=!0,at(ee);continue}let b=H();if(r.noextglob!==!0&&/^\([^?]/.test(b)){Ve("star",ee);continue}if(ne.type==="star"){if(r.noglobstar===!0){at(ee);continue}let S=ne.prev,y=S.prev,F=S.type==="slash"||S.type==="bos",J=y&&(y.type==="star"||y.type==="globstar");if(r.bash===!0&&(!F||b[0]&&b[0]!=="/")){Te({type:"star",value:ee,output:""});continue}let X=g.braces>0&&(S.type==="comma"||S.type==="brace"),Z=Ee.length&&(S.type==="pipe"||S.type==="paren");if(!F&&S.type!=="paren"&&!X&&!Z){Te({type:"star",value:ee,output:""});continue}for(;b.slice(0,3)==="/**";){let ie=t[g.index+4];if(ie&&ie!=="/")break;b=b.slice(3),at("/**",3)}if(S.type==="bos"&&Ie()){ne.type="globstar",ne.value+=ee,ne.output=me(r),g.output=ne.output,g.globstar=!0,at(ee);continue}if(S.type==="slash"&&S.prev.type!=="bos"&&!J&&Ie()){g.output=g.output.slice(0,-(S.output+ne.output).length),S.output=`(?:${S.output}`,ne.type="globstar",ne.output=me(r)+(r.strictSlashes?")":"|$)"),ne.value+=ee,g.globstar=!0,g.output+=S.output+ne.output,at(ee);continue}if(S.type==="slash"&&S.prev.type!=="bos"&&b[0]==="/"){let ie=b[1]!==void 0?"|$":"";g.output=g.output.slice(0,-(S.output+ne.output).length),S.output=`(?:${S.output}`,ne.type="globstar",ne.output=`${me(r)}${x}|${x}${ie})`,ne.value+=ee,g.output+=S.output+ne.output,g.globstar=!0,at(ee+At()),Te({type:"slash",value:"/",output:""});continue}if(S.type==="bos"&&b[0]==="/"){ne.type="globstar",ne.value+=ee,ne.output=`(?:^|${x}|${me(r)}${x})`,g.output=ne.output,g.globstar=!0,at(ee+At()),Te({type:"slash",value:"/",output:""});continue}g.output=g.output.slice(0,-ne.output.length),ne.type="globstar",ne.output=me(r),ne.value+=ee,g.output+=ne.output,g.globstar=!0,at(ee);continue}let w={type:"star",value:ee,output:we};if(r.bash===!0){w.output=".*?",(ne.type==="bos"||ne.type==="slash")&&(w.output=he+w.output),Te(w);continue}if(ne&&(ne.type==="bracket"||ne.type==="paren")&&r.regex===!0){w.output=ee,Te(w);continue}(g.index===g.start||ne.type==="slash"||ne.type==="dot")&&(ne.type==="dot"?(g.output+=U,ne.output+=U):r.dot===!0?(g.output+=V,ne.output+=V):(g.output+=he,ne.output+=he),Fe()!=="*"&&(g.output+=C,ne.output+=C)),Te(w)}for(;g.brackets>0;){if(r.strictBrackets===!0)throw new SyntaxError(Ty("closing","]"));g.output=il.escapeLast(g.output,"["),He("brackets")}for(;g.parens>0;){if(r.strictBrackets===!0)throw new SyntaxError(Ty("closing",")"));g.output=il.escapeLast(g.output,"("),He("parens")}for(;g.braces>0;){if(r.strictBrackets===!0)throw new SyntaxError(Ty("closing","}"));g.output=il.escapeLast(g.output,"{"),He("braces")}if(r.strictSlashes!==!0&&(ne.type==="star"||ne.type==="bracket")&&Te({type:"maybe_slash",value:"",output:`${x}?`}),g.backtrack===!0){g.output="";for(let b of g.tokens)g.output+=b.output!=null?b.output:b.value,b.suffix&&(g.output+=b.suffix)}return g};LL.fastpaths=(t,e)=>{let r={...e},o=typeof r.maxLength=="number"?Math.min(LP,r.maxLength):LP,a=t.length;if(a>o)throw new SyntaxError(`Input length: ${a}, exceeds maximum allowed length: ${o}`);t=DZ[t]||t;let n=il.isWindows(e),{DOT_LITERAL:u,SLASH_LITERAL:A,ONE_CHAR:p,DOTS_SLASH:h,NO_DOT:E,NO_DOTS:I,NO_DOTS_SLASH:v,STAR:x,START_ANCHOR:C}=TP.globChars(n),R=r.dot?I:E,N=r.dot?v:E,U=r.capture?"":"?:",V={negated:!1,prefix:""},te=r.bash===!0?".*?":x;r.capture&&(te=`(${te})`);let ae=he=>he.noglobstar===!0?te:`(${U}(?:(?!${C}${he.dot?h:u}).)*?)`,fe=he=>{switch(he){case"*":return`${R}${p}${te}`;case".*":return`${u}${p}${te}`;case"*.*":return`${R}${te}${u}${p}${te}`;case"*/*":return`${R}${te}${A}${p}${N}${te}`;case"**":return R+ae(r);case"**/*":return`(?:${R}${ae(r)}${A})?${N}${p}${te}`;case"**/*.*":return`(?:${R}${ae(r)}${A})?${N}${te}${u}${p}${te}`;case"**/.*":return`(?:${R}${ae(r)}${A})?${u}${p}${te}`;default:{let Be=/^(.*?)\.(\w+)$/.exec(he);if(!Be)return;let we=fe(Be[1]);return we?we+u+Be[2]:void 0}}},ue=il.removePrefix(t,V),me=fe(ue);return me&&r.strictSlashes!==!0&&(me+=`${A}?`),me};PZ.exports=LL});var xZ=_((XQt,bZ)=>{"use strict";var $7e=ve("path"),eYe=vZ(),NL=SZ(),OL=kI(),tYe=xI(),rYe=t=>t&&typeof t=="object"&&!Array.isArray(t),Mi=(t,e,r=!1)=>{if(Array.isArray(t)){let E=t.map(v=>Mi(v,e,r));return v=>{for(let x of E){let C=x(v);if(C)return C}return!1}}let o=rYe(t)&&t.tokens&&t.input;if(t===""||typeof t!="string"&&!o)throw new TypeError("Expected pattern to be a non-empty string");let a=e||{},n=OL.isWindows(e),u=o?Mi.compileRe(t,e):Mi.makeRe(t,e,!1,!0),A=u.state;delete u.state;let p=()=>!1;if(a.ignore){let E={...e,ignore:null,onMatch:null,onResult:null};p=Mi(a.ignore,E,r)}let h=(E,I=!1)=>{let{isMatch:v,match:x,output:C}=Mi.test(E,u,e,{glob:t,posix:n}),R={glob:t,state:A,regex:u,posix:n,input:E,output:C,match:x,isMatch:v};return typeof a.onResult=="function"&&a.onResult(R),v===!1?(R.isMatch=!1,I?R:!1):p(E)?(typeof a.onIgnore=="function"&&a.onIgnore(R),R.isMatch=!1,I?R:!1):(typeof a.onMatch=="function"&&a.onMatch(R),I?R:!0)};return r&&(h.state=A),h};Mi.test=(t,e,r,{glob:o,posix:a}={})=>{if(typeof t!="string")throw new TypeError("Expected input to be a string");if(t==="")return{isMatch:!1,output:""};let n=r||{},u=n.format||(a?OL.toPosixSlashes:null),A=t===o,p=A&&u?u(t):t;return A===!1&&(p=u?u(t):t,A=p===o),(A===!1||n.capture===!0)&&(n.matchBase===!0||n.basename===!0?A=Mi.matchBase(t,e,r,a):A=e.exec(p)),{isMatch:Boolean(A),match:A,output:p}};Mi.matchBase=(t,e,r,o=OL.isWindows(r))=>(e instanceof RegExp?e:Mi.makeRe(e,r)).test($7e.basename(t));Mi.isMatch=(t,e,r)=>Mi(e,r)(t);Mi.parse=(t,e)=>Array.isArray(t)?t.map(r=>Mi.parse(r,e)):NL(t,{...e,fastpaths:!1});Mi.scan=(t,e)=>eYe(t,e);Mi.compileRe=(t,e,r=!1,o=!1)=>{if(r===!0)return t.output;let a=e||{},n=a.contains?"":"^",u=a.contains?"":"$",A=`${n}(?:${t.output})${u}`;t&&t.negated===!0&&(A=`^(?!${A}).*$`);let p=Mi.toRegex(A,e);return o===!0&&(p.state=t),p};Mi.makeRe=(t,e={},r=!1,o=!1)=>{if(!t||typeof t!="string")throw new TypeError("Expected a non-empty string");let a={negated:!1,fastpaths:!0};return e.fastpaths!==!1&&(t[0]==="."||t[0]==="*")&&(a.output=NL.fastpaths(t,e)),a.output||(a=NL(t,e)),Mi.compileRe(a,e,r,o)};Mi.toRegex=(t,e)=>{try{let r=e||{};return new RegExp(t,r.flags||(r.nocase?"i":""))}catch(r){if(e&&e.debug===!0)throw r;return/$^/}};Mi.constants=tYe;bZ.exports=Mi});var QZ=_((ZQt,kZ)=>{"use strict";kZ.exports=xZ()});var Zo=_(($Qt,LZ)=>{"use strict";var RZ=ve("util"),TZ=AZ(),Vu=QZ(),ML=kI(),FZ=t=>t===""||t==="./",yi=(t,e,r)=>{e=[].concat(e),t=[].concat(t);let o=new Set,a=new Set,n=new Set,u=0,A=E=>{n.add(E.output),r&&r.onResult&&r.onResult(E)};for(let E=0;E<e.length;E++){let I=Vu(String(e[E]),{...r,onResult:A},!0),v=I.state.negated||I.state.negatedExtglob;v&&u++;for(let x of t){let C=I(x,!0);!(v?!C.isMatch:C.isMatch)||(v?o.add(C.output):(o.delete(C.output),a.add(C.output)))}}let h=(u===e.length?[...n]:[...a]).filter(E=>!o.has(E));if(r&&h.length===0){if(r.failglob===!0)throw new Error(`No matches found for "${e.join(", ")}"`);if(r.nonull===!0||r.nullglob===!0)return r.unescape?e.map(E=>E.replace(/\\/g,"")):e}return h};yi.match=yi;yi.matcher=(t,e)=>Vu(t,e);yi.isMatch=(t,e,r)=>Vu(e,r)(t);yi.any=yi.isMatch;yi.not=(t,e,r={})=>{e=[].concat(e).map(String);let o=new Set,a=[],n=A=>{r.onResult&&r.onResult(A),a.push(A.output)},u=new Set(yi(t,e,{...r,onResult:n}));for(let A of a)u.has(A)||o.add(A);return[...o]};yi.contains=(t,e,r)=>{if(typeof t!="string")throw new TypeError(`Expected a string: "${RZ.inspect(t)}"`);if(Array.isArray(e))return e.some(o=>yi.contains(t,o,r));if(typeof e=="string"){if(FZ(t)||FZ(e))return!1;if(t.includes(e)||t.startsWith("./")&&t.slice(2).includes(e))return!0}return yi.isMatch(t,e,{...r,contains:!0})};yi.matchKeys=(t,e,r)=>{if(!ML.isObject(t))throw new TypeError("Expected the first argument to be an object");let o=yi(Object.keys(t),e,r),a={};for(let n of o)a[n]=t[n];return a};yi.some=(t,e,r)=>{let o=[].concat(t);for(let a of[].concat(e)){let n=Vu(String(a),r);if(o.some(u=>n(u)))return!0}return!1};yi.every=(t,e,r)=>{let o=[].concat(t);for(let a of[].concat(e)){let n=Vu(String(a),r);if(!o.every(u=>n(u)))return!1}return!0};yi.all=(t,e,r)=>{if(typeof t!="string")throw new TypeError(`Expected a string: "${RZ.inspect(t)}"`);return[].concat(e).every(o=>Vu(o,r)(t))};yi.capture=(t,e,r)=>{let o=ML.isWindows(r),n=Vu.makeRe(String(t),{...r,capture:!0}).exec(o?ML.toPosixSlashes(e):e);if(n)return n.slice(1).map(u=>u===void 0?"":u)};yi.makeRe=(...t)=>Vu.makeRe(...t);yi.scan=(...t)=>Vu.scan(...t);yi.parse=(t,e)=>{let r=[];for(let o of[].concat(t||[]))for(let a of TZ(String(o),e))r.push(Vu.parse(a,e));return r};yi.braces=(t,e)=>{if(typeof t!="string")throw new TypeError("Expected a string");return e&&e.nobrace===!0||!/\{.*\}/.test(t)?[t]:TZ(t,e)};yi.braceExpand=(t,e)=>{if(typeof t!="string")throw new TypeError("Expected a string");return yi.braces(t,{...e,expand:!0})};LZ.exports=yi});var OZ=_((eFt,NZ)=>{"use strict";NZ.exports=({onlyFirst:t=!1}={})=>{let e=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(e,t?void 0:"g")}});var NP=_((tFt,MZ)=>{"use strict";var nYe=OZ();MZ.exports=t=>typeof t=="string"?t.replace(nYe(),""):t});var _Z=_((rFt,UZ)=>{function iYe(){this.__data__=[],this.size=0}UZ.exports=iYe});var Ly=_((nFt,HZ)=>{function sYe(t,e){return t===e||t!==t&&e!==e}HZ.exports=sYe});var FI=_((iFt,qZ)=>{var oYe=Ly();function aYe(t,e){for(var r=t.length;r--;)if(oYe(t[r][0],e))return r;return-1}qZ.exports=aYe});var jZ=_((sFt,GZ)=>{var lYe=FI(),cYe=Array.prototype,uYe=cYe.splice;function AYe(t){var e=this.__data__,r=lYe(e,t);if(r<0)return!1;var o=e.length-1;return r==o?e.pop():uYe.call(e,r,1),--this.size,!0}GZ.exports=AYe});var WZ=_((oFt,YZ)=>{var fYe=FI();function pYe(t){var e=this.__data__,r=fYe(e,t);return r<0?void 0:e[r][1]}YZ.exports=pYe});var zZ=_((aFt,KZ)=>{var hYe=FI();function gYe(t){return hYe(this.__data__,t)>-1}KZ.exports=gYe});var JZ=_((lFt,VZ)=>{var dYe=FI();function mYe(t,e){var r=this.__data__,o=dYe(r,t);return o<0?(++this.size,r.push([t,e])):r[o][1]=e,this}VZ.exports=mYe});var RI=_((cFt,XZ)=>{var yYe=_Z(),EYe=jZ(),CYe=WZ(),wYe=zZ(),IYe=JZ();function Ny(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e<r;){var o=t[e];this.set(o[0],o[1])}}Ny.prototype.clear=yYe;Ny.prototype.delete=EYe;Ny.prototype.get=CYe;Ny.prototype.has=wYe;Ny.prototype.set=IYe;XZ.exports=Ny});var $Z=_((uFt,ZZ)=>{var BYe=RI();function vYe(){this.__data__=new BYe,this.size=0}ZZ.exports=vYe});var t$=_((AFt,e$)=>{function DYe(t){var e=this.__data__,r=e.delete(t);return this.size=e.size,r}e$.exports=DYe});var n$=_((fFt,r$)=>{function PYe(t){return this.__data__.get(t)}r$.exports=PYe});var s$=_((pFt,i$)=>{function SYe(t){return this.__data__.has(t)}i$.exports=SYe});var UL=_((hFt,o$)=>{var bYe=typeof global=="object"&&global&&global.Object===Object&&global;o$.exports=bYe});var Hl=_((gFt,a$)=>{var xYe=UL(),kYe=typeof self=="object"&&self&&self.Object===Object&&self,QYe=xYe||kYe||Function("return this")();a$.exports=QYe});var hd=_((dFt,l$)=>{var FYe=Hl(),RYe=FYe.Symbol;l$.exports=RYe});var f$=_((mFt,A$)=>{var c$=hd(),u$=Object.prototype,TYe=u$.hasOwnProperty,LYe=u$.toString,TI=c$?c$.toStringTag:void 0;function NYe(t){var e=TYe.call(t,TI),r=t[TI];try{t[TI]=void 0;var o=!0}catch{}var a=LYe.call(t);return o&&(e?t[TI]=r:delete t[TI]),a}A$.exports=NYe});var h$=_((yFt,p$)=>{var OYe=Object.prototype,MYe=OYe.toString;function UYe(t){return MYe.call(t)}p$.exports=UYe});var gd=_((EFt,m$)=>{var g$=hd(),_Ye=f$(),HYe=h$(),qYe="[object Null]",GYe="[object Undefined]",d$=g$?g$.toStringTag:void 0;function jYe(t){return t==null?t===void 0?GYe:qYe:d$&&d$ in Object(t)?_Ye(t):HYe(t)}m$.exports=jYe});var sl=_((CFt,y$)=>{function YYe(t){var e=typeof t;return t!=null&&(e=="object"||e=="function")}y$.exports=YYe});var OP=_((wFt,E$)=>{var WYe=gd(),KYe=sl(),zYe="[object AsyncFunction]",VYe="[object Function]",JYe="[object GeneratorFunction]",XYe="[object Proxy]";function ZYe(t){if(!KYe(t))return!1;var e=WYe(t);return e==VYe||e==JYe||e==zYe||e==XYe}E$.exports=ZYe});var w$=_((IFt,C$)=>{var $Ye=Hl(),eWe=$Ye["__core-js_shared__"];C$.exports=eWe});var v$=_((BFt,B$)=>{var _L=w$(),I$=function(){var t=/[^.]+$/.exec(_L&&_L.keys&&_L.keys.IE_PROTO||"");return t?"Symbol(src)_1."+t:""}();function tWe(t){return!!I$&&I$ in t}B$.exports=tWe});var HL=_((vFt,D$)=>{var rWe=Function.prototype,nWe=rWe.toString;function iWe(t){if(t!=null){try{return nWe.call(t)}catch{}try{return t+""}catch{}}return""}D$.exports=iWe});var S$=_((DFt,P$)=>{var sWe=OP(),oWe=v$(),aWe=sl(),lWe=HL(),cWe=/[\\^$.*+?()[\]{}|]/g,uWe=/^\[object .+?Constructor\]$/,AWe=Function.prototype,fWe=Object.prototype,pWe=AWe.toString,hWe=fWe.hasOwnProperty,gWe=RegExp("^"+pWe.call(hWe).replace(cWe,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");function dWe(t){if(!aWe(t)||oWe(t))return!1;var e=sWe(t)?gWe:uWe;return e.test(lWe(t))}P$.exports=dWe});var x$=_((PFt,b$)=>{function mWe(t,e){return t?.[e]}b$.exports=mWe});var Xp=_((SFt,k$)=>{var yWe=S$(),EWe=x$();function CWe(t,e){var r=EWe(t,e);return yWe(r)?r:void 0}k$.exports=CWe});var MP=_((bFt,Q$)=>{var wWe=Xp(),IWe=Hl(),BWe=wWe(IWe,"Map");Q$.exports=BWe});var LI=_((xFt,F$)=>{var vWe=Xp(),DWe=vWe(Object,"create");F$.exports=DWe});var L$=_((kFt,T$)=>{var R$=LI();function PWe(){this.__data__=R$?R$(null):{},this.size=0}T$.exports=PWe});var O$=_((QFt,N$)=>{function SWe(t){var e=this.has(t)&&delete this.__data__[t];return this.size-=e?1:0,e}N$.exports=SWe});var U$=_((FFt,M$)=>{var bWe=LI(),xWe="__lodash_hash_undefined__",kWe=Object.prototype,QWe=kWe.hasOwnProperty;function FWe(t){var e=this.__data__;if(bWe){var r=e[t];return r===xWe?void 0:r}return QWe.call(e,t)?e[t]:void 0}M$.exports=FWe});var H$=_((RFt,_$)=>{var RWe=LI(),TWe=Object.prototype,LWe=TWe.hasOwnProperty;function NWe(t){var e=this.__data__;return RWe?e[t]!==void 0:LWe.call(e,t)}_$.exports=NWe});var G$=_((TFt,q$)=>{var OWe=LI(),MWe="__lodash_hash_undefined__";function UWe(t,e){var r=this.__data__;return this.size+=this.has(t)?0:1,r[t]=OWe&&e===void 0?MWe:e,this}q$.exports=UWe});var Y$=_((LFt,j$)=>{var _We=L$(),HWe=O$(),qWe=U$(),GWe=H$(),jWe=G$();function Oy(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e<r;){var o=t[e];this.set(o[0],o[1])}}Oy.prototype.clear=_We;Oy.prototype.delete=HWe;Oy.prototype.get=qWe;Oy.prototype.has=GWe;Oy.prototype.set=jWe;j$.exports=Oy});var z$=_((NFt,K$)=>{var W$=Y$(),YWe=RI(),WWe=MP();function KWe(){this.size=0,this.__data__={hash:new W$,map:new(WWe||YWe),string:new W$}}K$.exports=KWe});var J$=_((OFt,V$)=>{function zWe(t){var e=typeof t;return e=="string"||e=="number"||e=="symbol"||e=="boolean"?t!=="__proto__":t===null}V$.exports=zWe});var NI=_((MFt,X$)=>{var VWe=J$();function JWe(t,e){var r=t.__data__;return VWe(e)?r[typeof e=="string"?"string":"hash"]:r.map}X$.exports=JWe});var $$=_((UFt,Z$)=>{var XWe=NI();function ZWe(t){var e=XWe(this,t).delete(t);return this.size-=e?1:0,e}Z$.exports=ZWe});var tee=_((_Ft,eee)=>{var $We=NI();function eKe(t){return $We(this,t).get(t)}eee.exports=eKe});var nee=_((HFt,ree)=>{var tKe=NI();function rKe(t){return tKe(this,t).has(t)}ree.exports=rKe});var see=_((qFt,iee)=>{var nKe=NI();function iKe(t,e){var r=nKe(this,t),o=r.size;return r.set(t,e),this.size+=r.size==o?0:1,this}iee.exports=iKe});var UP=_((GFt,oee)=>{var sKe=z$(),oKe=$$(),aKe=tee(),lKe=nee(),cKe=see();function My(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e<r;){var o=t[e];this.set(o[0],o[1])}}My.prototype.clear=sKe;My.prototype.delete=oKe;My.prototype.get=aKe;My.prototype.has=lKe;My.prototype.set=cKe;oee.exports=My});var lee=_((jFt,aee)=>{var uKe=RI(),AKe=MP(),fKe=UP(),pKe=200;function hKe(t,e){var r=this.__data__;if(r instanceof uKe){var o=r.__data__;if(!AKe||o.length<pKe-1)return o.push([t,e]),this.size=++r.size,this;r=this.__data__=new fKe(o)}return r.set(t,e),this.size=r.size,this}aee.exports=hKe});var _P=_((YFt,cee)=>{var gKe=RI(),dKe=$Z(),mKe=t$(),yKe=n$(),EKe=s$(),CKe=lee();function Uy(t){var e=this.__data__=new gKe(t);this.size=e.size}Uy.prototype.clear=dKe;Uy.prototype.delete=mKe;Uy.prototype.get=yKe;Uy.prototype.has=EKe;Uy.prototype.set=CKe;cee.exports=Uy});var Aee=_((WFt,uee)=>{var wKe="__lodash_hash_undefined__";function IKe(t){return this.__data__.set(t,wKe),this}uee.exports=IKe});var pee=_((KFt,fee)=>{function BKe(t){return this.__data__.has(t)}fee.exports=BKe});var gee=_((zFt,hee)=>{var vKe=UP(),DKe=Aee(),PKe=pee();function HP(t){var e=-1,r=t==null?0:t.length;for(this.__data__=new vKe;++e<r;)this.add(t[e])}HP.prototype.add=HP.prototype.push=DKe;HP.prototype.has=PKe;hee.exports=HP});var mee=_((VFt,dee)=>{function SKe(t,e){for(var r=-1,o=t==null?0:t.length;++r<o;)if(e(t[r],r,t))return!0;return!1}dee.exports=SKe});var Eee=_((JFt,yee)=>{function bKe(t,e){return t.has(e)}yee.exports=bKe});var qL=_((XFt,Cee)=>{var xKe=gee(),kKe=mee(),QKe=Eee(),FKe=1,RKe=2;function TKe(t,e,r,o,a,n){var u=r&FKe,A=t.length,p=e.length;if(A!=p&&!(u&&p>A))return!1;var h=n.get(t),E=n.get(e);if(h&&E)return h==e&&E==t;var I=-1,v=!0,x=r&RKe?new xKe:void 0;for(n.set(t,e),n.set(e,t);++I<A;){var C=t[I],R=e[I];if(o)var N=u?o(R,C,I,e,t,n):o(C,R,I,t,e,n);if(N!==void 0){if(N)continue;v=!1;break}if(x){if(!kKe(e,function(U,V){if(!QKe(x,V)&&(C===U||a(C,U,r,o,n)))return x.push(V)})){v=!1;break}}else if(!(C===R||a(C,R,r,o,n))){v=!1;break}}return n.delete(t),n.delete(e),v}Cee.exports=TKe});var jL=_((ZFt,wee)=>{var LKe=Hl(),NKe=LKe.Uint8Array;wee.exports=NKe});var Bee=_(($Ft,Iee)=>{function OKe(t){var e=-1,r=Array(t.size);return t.forEach(function(o,a){r[++e]=[a,o]}),r}Iee.exports=OKe});var Dee=_((eRt,vee)=>{function MKe(t){var e=-1,r=Array(t.size);return t.forEach(function(o){r[++e]=o}),r}vee.exports=MKe});var kee=_((tRt,xee)=>{var Pee=hd(),See=jL(),UKe=Ly(),_Ke=qL(),HKe=Bee(),qKe=Dee(),GKe=1,jKe=2,YKe="[object Boolean]",WKe="[object Date]",KKe="[object Error]",zKe="[object Map]",VKe="[object Number]",JKe="[object RegExp]",XKe="[object Set]",ZKe="[object String]",$Ke="[object Symbol]",eze="[object ArrayBuffer]",tze="[object DataView]",bee=Pee?Pee.prototype:void 0,YL=bee?bee.valueOf:void 0;function rze(t,e,r,o,a,n,u){switch(r){case tze:if(t.byteLength!=e.byteLength||t.byteOffset!=e.byteOffset)return!1;t=t.buffer,e=e.buffer;case eze:return!(t.byteLength!=e.byteLength||!n(new See(t),new See(e)));case YKe:case WKe:case VKe:return UKe(+t,+e);case KKe:return t.name==e.name&&t.message==e.message;case JKe:case ZKe:return t==e+"";case zKe:var A=HKe;case XKe:var p=o&GKe;if(A||(A=qKe),t.size!=e.size&&!p)return!1;var h=u.get(t);if(h)return h==e;o|=jKe,u.set(t,e);var E=_Ke(A(t),A(e),o,a,n,u);return u.delete(t),E;case $Ke:if(YL)return YL.call(t)==YL.call(e)}return!1}xee.exports=rze});var qP=_((rRt,Qee)=>{function nze(t,e){for(var r=-1,o=e.length,a=t.length;++r<o;)t[a+r]=e[r];return t}Qee.exports=nze});var ql=_((nRt,Fee)=>{var ize=Array.isArray;Fee.exports=ize});var WL=_((iRt,Ree)=>{var sze=qP(),oze=ql();function aze(t,e,r){var o=e(t);return oze(t)?o:sze(o,r(t))}Ree.exports=aze});var Lee=_((sRt,Tee)=>{function lze(t,e){for(var r=-1,o=t==null?0:t.length,a=0,n=[];++r<o;){var u=t[r];e(u,r,t)&&(n[a++]=u)}return n}Tee.exports=lze});var KL=_((oRt,Nee)=>{function cze(){return[]}Nee.exports=cze});var GP=_((aRt,Mee)=>{var uze=Lee(),Aze=KL(),fze=Object.prototype,pze=fze.propertyIsEnumerable,Oee=Object.getOwnPropertySymbols,hze=Oee?function(t){return t==null?[]:(t=Object(t),uze(Oee(t),function(e){return pze.call(t,e)}))}:Aze;Mee.exports=hze});var _ee=_((lRt,Uee)=>{function gze(t,e){for(var r=-1,o=Array(t);++r<t;)o[r]=e(r);return o}Uee.exports=gze});var Ju=_((cRt,Hee)=>{function dze(t){return t!=null&&typeof t=="object"}Hee.exports=dze});var Gee=_((uRt,qee)=>{var mze=gd(),yze=Ju(),Eze="[object Arguments]";function Cze(t){return yze(t)&&mze(t)==Eze}qee.exports=Cze});var OI=_((ARt,Wee)=>{var jee=Gee(),wze=Ju(),Yee=Object.prototype,Ize=Yee.hasOwnProperty,Bze=Yee.propertyIsEnumerable,vze=jee(function(){return arguments}())?jee:function(t){return wze(t)&&Ize.call(t,"callee")&&!Bze.call(t,"callee")};Wee.exports=vze});var zee=_((fRt,Kee)=>{function Dze(){return!1}Kee.exports=Dze});var UI=_((MI,_y)=>{var Pze=Hl(),Sze=zee(),Xee=typeof MI=="object"&&MI&&!MI.nodeType&&MI,Vee=Xee&&typeof _y=="object"&&_y&&!_y.nodeType&&_y,bze=Vee&&Vee.exports===Xee,Jee=bze?Pze.Buffer:void 0,xze=Jee?Jee.isBuffer:void 0,kze=xze||Sze;_y.exports=kze});var _I=_((pRt,Zee)=>{var Qze=9007199254740991,Fze=/^(?:0|[1-9]\d*)$/;function Rze(t,e){var r=typeof t;return e=e??Qze,!!e&&(r=="number"||r!="symbol"&&Fze.test(t))&&t>-1&&t%1==0&&t<e}Zee.exports=Rze});var jP=_((hRt,$ee)=>{var Tze=9007199254740991;function Lze(t){return typeof t=="number"&&t>-1&&t%1==0&&t<=Tze}$ee.exports=Lze});var tte=_((gRt,ete)=>{var Nze=gd(),Oze=jP(),Mze=Ju(),Uze="[object Arguments]",_ze="[object Array]",Hze="[object Boolean]",qze="[object Date]",Gze="[object Error]",jze="[object Function]",Yze="[object Map]",Wze="[object Number]",Kze="[object Object]",zze="[object RegExp]",Vze="[object Set]",Jze="[object String]",Xze="[object WeakMap]",Zze="[object ArrayBuffer]",$ze="[object DataView]",eVe="[object Float32Array]",tVe="[object Float64Array]",rVe="[object Int8Array]",nVe="[object Int16Array]",iVe="[object Int32Array]",sVe="[object Uint8Array]",oVe="[object Uint8ClampedArray]",aVe="[object Uint16Array]",lVe="[object Uint32Array]",ui={};ui[eVe]=ui[tVe]=ui[rVe]=ui[nVe]=ui[iVe]=ui[sVe]=ui[oVe]=ui[aVe]=ui[lVe]=!0;ui[Uze]=ui[_ze]=ui[Zze]=ui[Hze]=ui[$ze]=ui[qze]=ui[Gze]=ui[jze]=ui[Yze]=ui[Wze]=ui[Kze]=ui[zze]=ui[Vze]=ui[Jze]=ui[Xze]=!1;function cVe(t){return Mze(t)&&Oze(t.length)&&!!ui[Nze(t)]}ete.exports=cVe});var YP=_((dRt,rte)=>{function uVe(t){return function(e){return t(e)}}rte.exports=uVe});var WP=_((HI,Hy)=>{var AVe=UL(),nte=typeof HI=="object"&&HI&&!HI.nodeType&&HI,qI=nte&&typeof Hy=="object"&&Hy&&!Hy.nodeType&&Hy,fVe=qI&&qI.exports===nte,zL=fVe&&AVe.process,pVe=function(){try{var t=qI&&qI.require&&qI.require("util").types;return t||zL&&zL.binding&&zL.binding("util")}catch{}}();Hy.exports=pVe});var KP=_((mRt,ote)=>{var hVe=tte(),gVe=YP(),ite=WP(),ste=ite&&ite.isTypedArray,dVe=ste?gVe(ste):hVe;ote.exports=dVe});var VL=_((yRt,ate)=>{var mVe=_ee(),yVe=OI(),EVe=ql(),CVe=UI(),wVe=_I(),IVe=KP(),BVe=Object.prototype,vVe=BVe.hasOwnProperty;function DVe(t,e){var r=EVe(t),o=!r&&yVe(t),a=!r&&!o&&CVe(t),n=!r&&!o&&!a&&IVe(t),u=r||o||a||n,A=u?mVe(t.length,String):[],p=A.length;for(var h in t)(e||vVe.call(t,h))&&!(u&&(h=="length"||a&&(h=="offset"||h=="parent")||n&&(h=="buffer"||h=="byteLength"||h=="byteOffset")||wVe(h,p)))&&A.push(h);return A}ate.exports=DVe});var zP=_((ERt,lte)=>{var PVe=Object.prototype;function SVe(t){var e=t&&t.constructor,r=typeof e=="function"&&e.prototype||PVe;return t===r}lte.exports=SVe});var JL=_((CRt,cte)=>{function bVe(t,e){return function(r){return t(e(r))}}cte.exports=bVe});var Ate=_((wRt,ute)=>{var xVe=JL(),kVe=xVe(Object.keys,Object);ute.exports=kVe});var pte=_((IRt,fte)=>{var QVe=zP(),FVe=Ate(),RVe=Object.prototype,TVe=RVe.hasOwnProperty;function LVe(t){if(!QVe(t))return FVe(t);var e=[];for(var r in Object(t))TVe.call(t,r)&&r!="constructor"&&e.push(r);return e}fte.exports=LVe});var GI=_((BRt,hte)=>{var NVe=OP(),OVe=jP();function MVe(t){return t!=null&&OVe(t.length)&&!NVe(t)}hte.exports=MVe});var VP=_((vRt,gte)=>{var UVe=VL(),_Ve=pte(),HVe=GI();function qVe(t){return HVe(t)?UVe(t):_Ve(t)}gte.exports=qVe});var XL=_((DRt,dte)=>{var GVe=WL(),jVe=GP(),YVe=VP();function WVe(t){return GVe(t,YVe,jVe)}dte.exports=WVe});var Ete=_((PRt,yte)=>{var mte=XL(),KVe=1,zVe=Object.prototype,VVe=zVe.hasOwnProperty;function JVe(t,e,r,o,a,n){var u=r&KVe,A=mte(t),p=A.length,h=mte(e),E=h.length;if(p!=E&&!u)return!1;for(var I=p;I--;){var v=A[I];if(!(u?v in e:VVe.call(e,v)))return!1}var x=n.get(t),C=n.get(e);if(x&&C)return x==e&&C==t;var R=!0;n.set(t,e),n.set(e,t);for(var N=u;++I<p;){v=A[I];var U=t[v],V=e[v];if(o)var te=u?o(V,U,v,e,t,n):o(U,V,v,t,e,n);if(!(te===void 0?U===V||a(U,V,r,o,n):te)){R=!1;break}N||(N=v=="constructor")}if(R&&!N){var ae=t.constructor,fe=e.constructor;ae!=fe&&"constructor"in t&&"constructor"in e&&!(typeof ae=="function"&&ae instanceof ae&&typeof fe=="function"&&fe instanceof fe)&&(R=!1)}return n.delete(t),n.delete(e),R}yte.exports=JVe});var wte=_((SRt,Cte)=>{var XVe=Xp(),ZVe=Hl(),$Ve=XVe(ZVe,"DataView");Cte.exports=$Ve});var Bte=_((bRt,Ite)=>{var eJe=Xp(),tJe=Hl(),rJe=eJe(tJe,"Promise");Ite.exports=rJe});var Dte=_((xRt,vte)=>{var nJe=Xp(),iJe=Hl(),sJe=nJe(iJe,"Set");vte.exports=sJe});var Ste=_((kRt,Pte)=>{var oJe=Xp(),aJe=Hl(),lJe=oJe(aJe,"WeakMap");Pte.exports=lJe});var jI=_((QRt,Tte)=>{var ZL=wte(),$L=MP(),eN=Bte(),tN=Dte(),rN=Ste(),Rte=gd(),qy=HL(),bte="[object Map]",cJe="[object Object]",xte="[object Promise]",kte="[object Set]",Qte="[object WeakMap]",Fte="[object DataView]",uJe=qy(ZL),AJe=qy($L),fJe=qy(eN),pJe=qy(tN),hJe=qy(rN),dd=Rte;(ZL&&dd(new ZL(new ArrayBuffer(1)))!=Fte||$L&&dd(new $L)!=bte||eN&&dd(eN.resolve())!=xte||tN&&dd(new tN)!=kte||rN&&dd(new rN)!=Qte)&&(dd=function(t){var e=Rte(t),r=e==cJe?t.constructor:void 0,o=r?qy(r):"";if(o)switch(o){case uJe:return Fte;case AJe:return bte;case fJe:return xte;case pJe:return kte;case hJe:return Qte}return e});Tte.exports=dd});var qte=_((FRt,Hte)=>{var nN=_P(),gJe=qL(),dJe=kee(),mJe=Ete(),Lte=jI(),Nte=ql(),Ote=UI(),yJe=KP(),EJe=1,Mte="[object Arguments]",Ute="[object Array]",JP="[object Object]",CJe=Object.prototype,_te=CJe.hasOwnProperty;function wJe(t,e,r,o,a,n){var u=Nte(t),A=Nte(e),p=u?Ute:Lte(t),h=A?Ute:Lte(e);p=p==Mte?JP:p,h=h==Mte?JP:h;var E=p==JP,I=h==JP,v=p==h;if(v&&Ote(t)){if(!Ote(e))return!1;u=!0,E=!1}if(v&&!E)return n||(n=new nN),u||yJe(t)?gJe(t,e,r,o,a,n):dJe(t,e,p,r,o,a,n);if(!(r&EJe)){var x=E&&_te.call(t,"__wrapped__"),C=I&&_te.call(e,"__wrapped__");if(x||C){var R=x?t.value():t,N=C?e.value():e;return n||(n=new nN),a(R,N,r,o,n)}}return v?(n||(n=new nN),mJe(t,e,r,o,a,n)):!1}Hte.exports=wJe});var Wte=_((RRt,Yte)=>{var IJe=qte(),Gte=Ju();function jte(t,e,r,o,a){return t===e?!0:t==null||e==null||!Gte(t)&&!Gte(e)?t!==t&&e!==e:IJe(t,e,r,o,jte,a)}Yte.exports=jte});var zte=_((TRt,Kte)=>{var BJe=Wte();function vJe(t,e){return BJe(t,e)}Kte.exports=vJe});var iN=_((LRt,Vte)=>{var DJe=Xp(),PJe=function(){try{var t=DJe(Object,"defineProperty");return t({},"",{}),t}catch{}}();Vte.exports=PJe});var XP=_((NRt,Xte)=>{var Jte=iN();function SJe(t,e,r){e=="__proto__"&&Jte?Jte(t,e,{configurable:!0,enumerable:!0,value:r,writable:!0}):t[e]=r}Xte.exports=SJe});var sN=_((ORt,Zte)=>{var bJe=XP(),xJe=Ly();function kJe(t,e,r){(r!==void 0&&!xJe(t[e],r)||r===void 0&&!(e in t))&&bJe(t,e,r)}Zte.exports=kJe});var ere=_((MRt,$te)=>{function QJe(t){return function(e,r,o){for(var a=-1,n=Object(e),u=o(e),A=u.length;A--;){var p=u[t?A:++a];if(r(n[p],p,n)===!1)break}return e}}$te.exports=QJe});var rre=_((URt,tre)=>{var FJe=ere(),RJe=FJe();tre.exports=RJe});var oN=_((YI,Gy)=>{var TJe=Hl(),ore=typeof YI=="object"&&YI&&!YI.nodeType&&YI,nre=ore&&typeof Gy=="object"&&Gy&&!Gy.nodeType&&Gy,LJe=nre&&nre.exports===ore,ire=LJe?TJe.Buffer:void 0,sre=ire?ire.allocUnsafe:void 0;function NJe(t,e){if(e)return t.slice();var r=t.length,o=sre?sre(r):new t.constructor(r);return t.copy(o),o}Gy.exports=NJe});var ZP=_((_Rt,lre)=>{var are=jL();function OJe(t){var e=new t.constructor(t.byteLength);return new are(e).set(new are(t)),e}lre.exports=OJe});var aN=_((HRt,cre)=>{var MJe=ZP();function UJe(t,e){var r=e?MJe(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.length)}cre.exports=UJe});var $P=_((qRt,ure)=>{function _Je(t,e){var r=-1,o=t.length;for(e||(e=Array(o));++r<o;)e[r]=t[r];return e}ure.exports=_Je});var pre=_((GRt,fre)=>{var HJe=sl(),Are=Object.create,qJe=function(){function t(){}return function(e){if(!HJe(e))return{};if(Are)return Are(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();fre.exports=qJe});var eS=_((jRt,hre)=>{var GJe=JL(),jJe=GJe(Object.getPrototypeOf,Object);hre.exports=jJe});var lN=_((YRt,gre)=>{var YJe=pre(),WJe=eS(),KJe=zP();function zJe(t){return typeof t.constructor=="function"&&!KJe(t)?YJe(WJe(t)):{}}gre.exports=zJe});var mre=_((WRt,dre)=>{var VJe=GI(),JJe=Ju();function XJe(t){return JJe(t)&&VJe(t)}dre.exports=XJe});var cN=_((KRt,Ere)=>{var ZJe=gd(),$Je=eS(),eXe=Ju(),tXe="[object Object]",rXe=Function.prototype,nXe=Object.prototype,yre=rXe.toString,iXe=nXe.hasOwnProperty,sXe=yre.call(Object);function oXe(t){if(!eXe(t)||ZJe(t)!=tXe)return!1;var e=$Je(t);if(e===null)return!0;var r=iXe.call(e,"constructor")&&e.constructor;return typeof r=="function"&&r instanceof r&&yre.call(r)==sXe}Ere.exports=oXe});var uN=_((zRt,Cre)=>{function aXe(t,e){if(!(e==="constructor"&&typeof t[e]=="function")&&e!="__proto__")return t[e]}Cre.exports=aXe});var tS=_((VRt,wre)=>{var lXe=XP(),cXe=Ly(),uXe=Object.prototype,AXe=uXe.hasOwnProperty;function fXe(t,e,r){var o=t[e];(!(AXe.call(t,e)&&cXe(o,r))||r===void 0&&!(e in t))&&lXe(t,e,r)}wre.exports=fXe});var md=_((JRt,Ire)=>{var pXe=tS(),hXe=XP();function gXe(t,e,r,o){var a=!r;r||(r={});for(var n=-1,u=e.length;++n<u;){var A=e[n],p=o?o(r[A],t[A],A,r,t):void 0;p===void 0&&(p=t[A]),a?hXe(r,A,p):pXe(r,A,p)}return r}Ire.exports=gXe});var vre=_((XRt,Bre)=>{function dXe(t){var e=[];if(t!=null)for(var r in Object(t))e.push(r);return e}Bre.exports=dXe});var Pre=_((ZRt,Dre)=>{var mXe=sl(),yXe=zP(),EXe=vre(),CXe=Object.prototype,wXe=CXe.hasOwnProperty;function IXe(t){if(!mXe(t))return EXe(t);var e=yXe(t),r=[];for(var o in t)o=="constructor"&&(e||!wXe.call(t,o))||r.push(o);return r}Dre.exports=IXe});var jy=_(($Rt,Sre)=>{var BXe=VL(),vXe=Pre(),DXe=GI();function PXe(t){return DXe(t)?BXe(t,!0):vXe(t)}Sre.exports=PXe});var xre=_((eTt,bre)=>{var SXe=md(),bXe=jy();function xXe(t){return SXe(t,bXe(t))}bre.exports=xXe});var Lre=_((tTt,Tre)=>{var kre=sN(),kXe=oN(),QXe=aN(),FXe=$P(),RXe=lN(),Qre=OI(),Fre=ql(),TXe=mre(),LXe=UI(),NXe=OP(),OXe=sl(),MXe=cN(),UXe=KP(),Rre=uN(),_Xe=xre();function HXe(t,e,r,o,a,n,u){var A=Rre(t,r),p=Rre(e,r),h=u.get(p);if(h){kre(t,r,h);return}var E=n?n(A,p,r+"",t,e,u):void 0,I=E===void 0;if(I){var v=Fre(p),x=!v&&LXe(p),C=!v&&!x&&UXe(p);E=p,v||x||C?Fre(A)?E=A:TXe(A)?E=FXe(A):x?(I=!1,E=kXe(p,!0)):C?(I=!1,E=QXe(p,!0)):E=[]:MXe(p)||Qre(p)?(E=A,Qre(A)?E=_Xe(A):(!OXe(A)||NXe(A))&&(E=RXe(p))):I=!1}I&&(u.set(p,E),a(E,p,o,n,u),u.delete(p)),kre(t,r,E)}Tre.exports=HXe});var Mre=_((rTt,Ore)=>{var qXe=_P(),GXe=sN(),jXe=rre(),YXe=Lre(),WXe=sl(),KXe=jy(),zXe=uN();function Nre(t,e,r,o,a){t!==e&&jXe(e,function(n,u){if(a||(a=new qXe),WXe(n))YXe(t,e,u,r,Nre,o,a);else{var A=o?o(zXe(t,u),n,u+"",t,e,a):void 0;A===void 0&&(A=n),GXe(t,u,A)}},KXe)}Ore.exports=Nre});var AN=_((nTt,Ure)=>{function VXe(t){return t}Ure.exports=VXe});var Hre=_((iTt,_re)=>{function JXe(t,e,r){switch(r.length){case 0:return t.call(e);case 1:return t.call(e,r[0]);case 2:return t.call(e,r[0],r[1]);case 3:return t.call(e,r[0],r[1],r[2])}return t.apply(e,r)}_re.exports=JXe});var fN=_((sTt,Gre)=>{var XXe=Hre(),qre=Math.max;function ZXe(t,e,r){return e=qre(e===void 0?t.length-1:e,0),function(){for(var o=arguments,a=-1,n=qre(o.length-e,0),u=Array(n);++a<n;)u[a]=o[e+a];a=-1;for(var A=Array(e+1);++a<e;)A[a]=o[a];return A[e]=r(u),XXe(t,this,A)}}Gre.exports=ZXe});var Yre=_((oTt,jre)=>{function $Xe(t){return function(){return t}}jre.exports=$Xe});var zre=_((aTt,Kre)=>{var eZe=Yre(),Wre=iN(),tZe=AN(),rZe=Wre?function(t,e){return Wre(t,"toString",{configurable:!0,enumerable:!1,value:eZe(e),writable:!0})}:tZe;Kre.exports=rZe});var Jre=_((lTt,Vre)=>{var nZe=800,iZe=16,sZe=Date.now;function oZe(t){var e=0,r=0;return function(){var o=sZe(),a=iZe-(o-r);if(r=o,a>0){if(++e>=nZe)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}Vre.exports=oZe});var pN=_((cTt,Xre)=>{var aZe=zre(),lZe=Jre(),cZe=lZe(aZe);Xre.exports=cZe});var $re=_((uTt,Zre)=>{var uZe=AN(),AZe=fN(),fZe=pN();function pZe(t,e){return fZe(AZe(t,e,uZe),t+"")}Zre.exports=pZe});var tne=_((ATt,ene)=>{var hZe=Ly(),gZe=GI(),dZe=_I(),mZe=sl();function yZe(t,e,r){if(!mZe(r))return!1;var o=typeof e;return(o=="number"?gZe(r)&&dZe(e,r.length):o=="string"&&e in r)?hZe(r[e],t):!1}ene.exports=yZe});var nne=_((fTt,rne)=>{var EZe=$re(),CZe=tne();function wZe(t){return EZe(function(e,r){var o=-1,a=r.length,n=a>1?r[a-1]:void 0,u=a>2?r[2]:void 0;for(n=t.length>3&&typeof n=="function"?(a--,n):void 0,u&&CZe(r[0],r[1],u)&&(n=a<3?void 0:n,a=1),e=Object(e);++o<a;){var A=r[o];A&&t(e,A,o,n)}return e})}rne.exports=wZe});var sne=_((pTt,ine)=>{var IZe=Mre(),BZe=nne(),vZe=BZe(function(t,e,r,o){IZe(t,e,r,o)});ine.exports=vZe});var _e={};zt(_e,{AsyncActions:()=>dN,BufferStream:()=>gN,CachingStrategy:()=>mne,DefaultStream:()=>mN,allSettledSafe:()=>_c,assertNever:()=>EN,bufferStream:()=>zy,buildIgnorePattern:()=>QZe,convertMapsToIndexableObjects:()=>nS,dynamicRequire:()=>Df,escapeRegExp:()=>PZe,getArrayWithDefault:()=>Yy,getFactoryWithDefault:()=>al,getMapWithDefault:()=>Wy,getSetWithDefault:()=>yd,groupBy:()=>IN,isIndexableObject:()=>hN,isPathLike:()=>FZe,isTaggedYarnVersion:()=>DZe,makeDeferred:()=>hne,mapAndFilter:()=>ol,mapAndFind:()=>KI,mergeIntoTarget:()=>Ene,overrideType:()=>SZe,parseBoolean:()=>zI,parseInt:()=>Vy,parseOptionalBoolean:()=>yne,plural:()=>rS,prettifyAsyncErrors:()=>Ky,prettifySyncErrors:()=>CN,releaseAfterUseAsync:()=>xZe,replaceEnvVariables:()=>iS,sortMap:()=>ks,toMerged:()=>RZe,tryParseOptionalBoolean:()=>wN,validateEnum:()=>bZe});function DZe(t){return!!(Ane.default.valid(t)&&t.match(/^[^-]+(-rc\.[0-9]+)?$/))}function rS(t,{one:e,more:r,zero:o=r}){return t===0?o:t===1?e:r}function PZe(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function SZe(t){}function EN(t){throw new Error(`Assertion failed: Unexpected object '${t}'`)}function bZe(t,e){let r=Object.values(t);if(!r.includes(e))throw new it(`Invalid value for enumeration: ${JSON.stringify(e)} (expected one of ${r.map(o=>JSON.stringify(o)).join(", ")})`);return e}function ol(t,e){let r=[];for(let o of t){let a=e(o);a!==fne&&r.push(a)}return r}function KI(t,e){for(let r of t){let o=e(r);if(o!==pne)return o}}function hN(t){return typeof t=="object"&&t!==null}async function _c(t){let e=await Promise.allSettled(t),r=[];for(let o of e){if(o.status==="rejected")throw o.reason;r.push(o.value)}return r}function nS(t){if(t instanceof Map&&(t=Object.fromEntries(t)),hN(t))for(let e of Object.keys(t)){let r=t[e];hN(r)&&(t[e]=nS(r))}return t}function al(t,e,r){let o=t.get(e);return typeof o>"u"&&t.set(e,o=r()),o}function Yy(t,e){let r=t.get(e);return typeof r>"u"&&t.set(e,r=[]),r}function yd(t,e){let r=t.get(e);return typeof r>"u"&&t.set(e,r=new Set),r}function Wy(t,e){let r=t.get(e);return typeof r>"u"&&t.set(e,r=new Map),r}async function xZe(t,e){if(e==null)return await t();try{return await t()}finally{await e()}}async function Ky(t,e){try{return await t()}catch(r){throw r.message=e(r.message),r}}function CN(t,e){try{return t()}catch(r){throw r.message=e(r.message),r}}async function zy(t){return await new Promise((e,r)=>{let o=[];t.on("error",a=>{r(a)}),t.on("data",a=>{o.push(a)}),t.on("end",()=>{e(Buffer.concat(o))})})}function hne(){let t,e;return{promise:new Promise((o,a)=>{t=o,e=a}),resolve:t,reject:e}}function gne(t){return WI(le.fromPortablePath(t))}function dne(path){let physicalPath=le.fromPortablePath(path),currentCacheEntry=WI.cache[physicalPath];delete WI.cache[physicalPath];let result;try{result=gne(physicalPath);let freshCacheEntry=WI.cache[physicalPath],dynamicModule=eval("module"),freshCacheIndex=dynamicModule.children.indexOf(freshCacheEntry);freshCacheIndex!==-1&&dynamicModule.children.splice(freshCacheIndex,1)}finally{WI.cache[physicalPath]=currentCacheEntry}return result}function kZe(t){let e=one.get(t),r=oe.statSync(t);if(e?.mtime===r.mtimeMs)return e.instance;let o=dne(t);return one.set(t,{mtime:r.mtimeMs,instance:o}),o}function Df(t,{cachingStrategy:e=2}={}){switch(e){case 0:return dne(t);case 1:return kZe(t);case 2:return gne(t);default:throw new Error("Unsupported caching strategy")}}function ks(t,e){let r=Array.from(t);Array.isArray(e)||(e=[e]);let o=[];for(let n of e)o.push(r.map(u=>n(u)));let a=r.map((n,u)=>u);return a.sort((n,u)=>{for(let A of o){let p=A[n]<A[u]?-1:A[n]>A[u]?1:0;if(p!==0)return p}return 0}),a.map(n=>r[n])}function QZe(t){return t.length===0?null:t.map(e=>`(${cne.default.makeRe(e,{windows:!1,dot:!0}).source})`).join("|")}function iS(t,{env:e}){let r=/\${(?<variableName>[\d\w_]+)(?<colon>:)?(?:-(?<fallback>[^}]*))?}/g;return t.replace(r,(...o)=>{let{variableName:a,colon:n,fallback:u}=o[o.length-1],A=Object.hasOwn(e,a),p=e[a];if(p||A&&!n)return p;if(u!=null)return u;throw new it(`Environment variable not found (${a})`)})}function zI(t){switch(t){case"true":case"1":case 1:case!0:return!0;case"false":case"0":case 0:case!1:return!1;default:throw new Error(`Couldn't parse "${t}" as a boolean`)}}function yne(t){return typeof t>"u"?t:zI(t)}function wN(t){try{return yne(t)}catch{return null}}function FZe(t){return!!(le.isAbsolute(t)||t.match(/^(\.{1,2}|~)\//))}function Ene(t,...e){let r=u=>({value:u}),o=r(t),a=e.map(u=>r(u)),{value:n}=(0,lne.default)(o,...a,(u,A)=>{if(Array.isArray(u)&&Array.isArray(A)){for(let p of A)u.find(h=>(0,ane.default)(h,p))||u.push(p);return u}});return n}function RZe(...t){return Ene({},...t)}function IN(t,e){let r=Object.create(null);for(let o of t){let a=o[e];r[a]??=[],r[a].push(o)}return r}function Vy(t){return typeof t=="string"?Number.parseInt(t,10):t}var ane,lne,cne,une,Ane,yN,fne,pne,gN,dN,mN,WI,one,mne,Gl=Et(()=>{Pt();qt();ane=$e(zte()),lne=$e(sne()),cne=$e(Zo()),une=$e(sd()),Ane=$e(Jn()),yN=ve("stream");fne=Symbol();ol.skip=fne;pne=Symbol();KI.skip=pne;gN=class extends yN.Transform{constructor(){super(...arguments);this.chunks=[]}_transform(r,o,a){if(o!=="buffer"||!Buffer.isBuffer(r))throw new Error("Assertion failed: BufferStream only accept buffers");this.chunks.push(r),a(null,null)}_flush(r){r(null,Buffer.concat(this.chunks))}};dN=class{constructor(e){this.deferred=new Map;this.promises=new Map;this.limit=(0,une.default)(e)}set(e,r){let o=this.deferred.get(e);typeof o>"u"&&this.deferred.set(e,o=hne());let a=this.limit(()=>r());return this.promises.set(e,a),a.then(()=>{this.promises.get(e)===a&&o.resolve()},n=>{this.promises.get(e)===a&&o.reject(n)}),o.promise}reduce(e,r){let o=this.promises.get(e)??Promise.resolve();this.set(e,()=>r(o))}async wait(){await Promise.all(this.promises.values())}},mN=class extends yN.Transform{constructor(r=Buffer.alloc(0)){super();this.active=!0;this.ifEmpty=r}_transform(r,o,a){if(o!=="buffer"||!Buffer.isBuffer(r))throw new Error("Assertion failed: DefaultStream only accept buffers");this.active=!1,a(null,r)}_flush(r){this.active&&this.ifEmpty.length>0?r(null,this.ifEmpty):r(null)}},WI=eval("require");one=new Map;mne=(o=>(o[o.NoCache=0]="NoCache",o[o.FsTime=1]="FsTime",o[o.Node=2]="Node",o))(mne||{})});var Jy,BN,vN,Cne=Et(()=>{Jy=(r=>(r.HARD="HARD",r.SOFT="SOFT",r))(Jy||{}),BN=(o=>(o.Dependency="Dependency",o.PeerDependency="PeerDependency",o.PeerDependencyMeta="PeerDependencyMeta",o))(BN||{}),vN=(o=>(o.Inactive="inactive",o.Redundant="redundant",o.Active="active",o))(vN||{})});var de={};zt(de,{LogLevel:()=>cS,Style:()=>oS,Type:()=>yt,addLogFilterSupport:()=>XI,applyColor:()=>zs,applyHyperlink:()=>Zy,applyStyle:()=>Ed,json:()=>Cd,jsonOrPretty:()=>NZe,mark:()=>xN,pretty:()=>Ut,prettyField:()=>Xu,prettyList:()=>bN,prettyTruncatedLocatorList:()=>lS,stripAnsi:()=>Xy.default,supportsColor:()=>aS,supportsHyperlinks:()=>SN,tuple:()=>Hc});function wne(t){let e=["KiB","MiB","GiB","TiB"],r=e.length;for(;r>1&&t<1024**r;)r-=1;let o=1024**r;return`${Math.floor(t*100/o)/100} ${e[r-1]}`}function Hc(t,e){return[e,t]}function Ed(t,e,r){return t.get("enableColors")&&r&2&&(e=JI.default.bold(e)),e}function zs(t,e,r){if(!t.get("enableColors"))return e;let o=TZe.get(r);if(o===null)return e;let a=typeof o>"u"?r:PN.level>=3?o[0]:o[1],n=typeof a=="number"?DN.ansi256(a):a.startsWith("#")?DN.hex(a):DN[a];if(typeof n!="function")throw new Error(`Invalid format type ${a}`);return n(e)}function Zy(t,e,r){return t.get("enableHyperlinks")?LZe?`\x1B]8;;${r}\x1B\\${e}\x1B]8;;\x1B\\`:`\x1B]8;;${r}\x07${e}\x1B]8;;\x07`:e}function Ut(t,e,r){if(e===null)return zs(t,"null",yt.NULL);if(Object.hasOwn(sS,r))return sS[r].pretty(t,e);if(typeof e!="string")throw new Error(`Assertion failed: Expected the value to be a string, got ${typeof e}`);return zs(t,e,r)}function bN(t,e,r,{separator:o=", "}={}){return[...e].map(a=>Ut(t,a,r)).join(o)}function Cd(t,e){if(t===null)return null;if(Object.hasOwn(sS,e))return sS[e].json(t);if(typeof t!="string")throw new Error(`Assertion failed: Expected the value to be a string, got ${typeof t}`);return t}function NZe(t,e,[r,o]){return t?Cd(r,o):Ut(e,r,o)}function xN(t){return{Check:zs(t,"\u2713","green"),Cross:zs(t,"\u2718","red"),Question:zs(t,"?","cyan")}}function Xu(t,{label:e,value:[r,o]}){return`${Ut(t,e,yt.CODE)}: ${Ut(t,r,o)}`}function lS(t,e,r){let o=[],a=[...e],n=r;for(;a.length>0;){let h=a[0],E=`${qr(t,h)}, `,I=kN(h).length+2;if(o.length>0&&n<I)break;o.push([E,I]),n-=I,a.shift()}if(a.length===0)return o.map(([h])=>h).join("").slice(0,-2);let u="X".repeat(a.length.toString().length),A=`and ${u} more.`,p=a.length;for(;o.length>1&&n<A.length;)n+=o[o.length-1][1],p+=1,o.pop();return[o.map(([h])=>h).join(""),A.replace(u,Ut(t,p,yt.NUMBER))].join("")}function XI(t,{configuration:e}){let r=e.get("logFilters"),o=new Map,a=new Map,n=[];for(let I of r){let v=I.get("level");if(typeof v>"u")continue;let x=I.get("code");typeof x<"u"&&o.set(x,v);let C=I.get("text");typeof C<"u"&&a.set(C,v);let R=I.get("pattern");typeof R<"u"&&n.push([Ine.default.matcher(R,{contains:!0}),v])}n.reverse();let u=(I,v,x)=>{if(I===null||I===0)return x;let C=a.size>0||n.length>0?(0,Xy.default)(v):v;if(a.size>0){let R=a.get(C);if(typeof R<"u")return R??x}if(n.length>0){for(let[R,N]of n)if(R(C))return N??x}if(o.size>0){let R=o.get(Ku(I));if(typeof R<"u")return R??x}return x},A=t.reportInfo,p=t.reportWarning,h=t.reportError,E=function(I,v,x,C){switch(u(v,x,C)){case"info":A.call(I,v,x);break;case"warning":p.call(I,v??0,x);break;case"error":h.call(I,v??0,x);break}};t.reportInfo=function(...I){return E(this,...I,"info")},t.reportWarning=function(...I){return E(this,...I,"warning")},t.reportError=function(...I){return E(this,...I,"error")}}var JI,VI,Ine,Xy,Bne,yt,oS,PN,aS,SN,DN,TZe,So,sS,LZe,cS,jl=Et(()=>{Pt();JI=$e(IL()),VI=$e(rd());qt();Ine=$e(Zo()),Xy=$e(NP()),Bne=ve("util");fP();bo();yt={NO_HINT:"NO_HINT",ID:"ID",NULL:"NULL",SCOPE:"SCOPE",NAME:"NAME",RANGE:"RANGE",REFERENCE:"REFERENCE",NUMBER:"NUMBER",PATH:"PATH",URL:"URL",ADDED:"ADDED",REMOVED:"REMOVED",CODE:"CODE",INSPECT:"INSPECT",DURATION:"DURATION",SIZE:"SIZE",SIZE_DIFF:"SIZE_DIFF",IDENT:"IDENT",DESCRIPTOR:"DESCRIPTOR",LOCATOR:"LOCATOR",RESOLUTION:"RESOLUTION",DEPENDENT:"DEPENDENT",PACKAGE_EXTENSION:"PACKAGE_EXTENSION",SETTING:"SETTING",MARKDOWN:"MARKDOWN",MARKDOWN_INLINE:"MARKDOWN_INLINE"},oS=(e=>(e[e.BOLD=2]="BOLD",e))(oS||{}),PN=VI.default.GITHUB_ACTIONS?{level:2}:JI.default.supportsColor?{level:JI.default.supportsColor.level}:{level:0},aS=PN.level!==0,SN=aS&&!VI.default.GITHUB_ACTIONS&&!VI.default.CIRCLE&&!VI.default.GITLAB,DN=new JI.default.Instance(PN),TZe=new Map([[yt.NO_HINT,null],[yt.NULL,["#a853b5",129]],[yt.SCOPE,["#d75f00",166]],[yt.NAME,["#d7875f",173]],[yt.RANGE,["#00afaf",37]],[yt.REFERENCE,["#87afff",111]],[yt.NUMBER,["#ffd700",220]],[yt.PATH,["#d75fd7",170]],[yt.URL,["#d75fd7",170]],[yt.ADDED,["#5faf00",70]],[yt.REMOVED,["#ff3131",160]],[yt.CODE,["#87afff",111]],[yt.SIZE,["#ffd700",220]]]),So=t=>t;sS={[yt.ID]:So({pretty:(t,e)=>typeof e=="number"?zs(t,`${e}`,yt.NUMBER):zs(t,e,yt.CODE),json:t=>t}),[yt.INSPECT]:So({pretty:(t,e)=>(0,Bne.inspect)(e,{depth:1/0,colors:t.get("enableColors"),compact:!0,breakLength:1/0}),json:t=>t}),[yt.NUMBER]:So({pretty:(t,e)=>zs(t,`${e}`,yt.NUMBER),json:t=>t}),[yt.IDENT]:So({pretty:(t,e)=>cs(t,e),json:t=>fn(t)}),[yt.LOCATOR]:So({pretty:(t,e)=>qr(t,e),json:t=>ba(t)}),[yt.DESCRIPTOR]:So({pretty:(t,e)=>Gn(t,e),json:t=>Sa(t)}),[yt.RESOLUTION]:So({pretty:(t,{descriptor:e,locator:r})=>ZI(t,e,r),json:({descriptor:t,locator:e})=>({descriptor:Sa(t),locator:e!==null?ba(e):null})}),[yt.DEPENDENT]:So({pretty:(t,{locator:e,descriptor:r})=>QN(t,e,r),json:({locator:t,descriptor:e})=>({locator:ba(t),descriptor:Sa(e)})}),[yt.PACKAGE_EXTENSION]:So({pretty:(t,e)=>{switch(e.type){case"Dependency":return`${cs(t,e.parentDescriptor)} \u27A4 ${zs(t,"dependencies",yt.CODE)} \u27A4 ${cs(t,e.descriptor)}`;case"PeerDependency":return`${cs(t,e.parentDescriptor)} \u27A4 ${zs(t,"peerDependencies",yt.CODE)} \u27A4 ${cs(t,e.descriptor)}`;case"PeerDependencyMeta":return`${cs(t,e.parentDescriptor)} \u27A4 ${zs(t,"peerDependenciesMeta",yt.CODE)} \u27A4 ${cs(t,Vs(e.selector))} \u27A4 ${zs(t,e.key,yt.CODE)}`;default:throw new Error(`Assertion failed: Unsupported package extension type: ${e.type}`)}},json:t=>{switch(t.type){case"Dependency":return`${fn(t.parentDescriptor)} > ${fn(t.descriptor)}`;case"PeerDependency":return`${fn(t.parentDescriptor)} >> ${fn(t.descriptor)}`;case"PeerDependencyMeta":return`${fn(t.parentDescriptor)} >> ${t.selector} / ${t.key}`;default:throw new Error(`Assertion failed: Unsupported package extension type: ${t.type}`)}}}),[yt.SETTING]:So({pretty:(t,e)=>(t.get(e),Zy(t,zs(t,e,yt.CODE),`https://yarnpkg.com/configuration/yarnrc#${e}`)),json:t=>t}),[yt.DURATION]:So({pretty:(t,e)=>{if(e>1e3*60){let r=Math.floor(e/1e3/60),o=Math.ceil((e-r*60*1e3)/1e3);return o===0?`${r}m`:`${r}m ${o}s`}else{let r=Math.floor(e/1e3),o=e-r*1e3;return o===0?`${r}s`:`${r}s ${o}ms`}},json:t=>t}),[yt.SIZE]:So({pretty:(t,e)=>zs(t,wne(e),yt.NUMBER),json:t=>t}),[yt.SIZE_DIFF]:So({pretty:(t,e)=>{let r=e>=0?"+":"-",o=r==="+"?yt.REMOVED:yt.ADDED;return zs(t,`${r} ${wne(Math.max(Math.abs(e),1))}`,o)},json:t=>t}),[yt.PATH]:So({pretty:(t,e)=>zs(t,le.fromPortablePath(e),yt.PATH),json:t=>le.fromPortablePath(t)}),[yt.MARKDOWN]:So({pretty:(t,{text:e,format:r,paragraphs:o})=>Do(e,{format:r,paragraphs:o}),json:({text:t})=>t}),[yt.MARKDOWN_INLINE]:So({pretty:(t,e)=>(e=e.replace(/(`+)((?:.|[\n])*?)\1/g,(r,o,a)=>Ut(t,o+a+o,yt.CODE)),e=e.replace(/(\*\*)((?:.|[\n])*?)\1/g,(r,o,a)=>Ed(t,a,2)),e),json:t=>t})};LZe=!!process.env.KONSOLE_VERSION;cS=(a=>(a.Error="error",a.Warning="warning",a.Info="info",a.Discard="discard",a))(cS||{})});var vne=_($y=>{"use strict";Object.defineProperty($y,"__esModule",{value:!0});$y.splitWhen=$y.flatten=void 0;function OZe(t){return t.reduce((e,r)=>[].concat(e,r),[])}$y.flatten=OZe;function MZe(t,e){let r=[[]],o=0;for(let a of t)e(a)?(o++,r[o]=[]):r[o].push(a);return r}$y.splitWhen=MZe});var Dne=_(uS=>{"use strict";Object.defineProperty(uS,"__esModule",{value:!0});uS.isEnoentCodeError=void 0;function UZe(t){return t.code==="ENOENT"}uS.isEnoentCodeError=UZe});var Pne=_(AS=>{"use strict";Object.defineProperty(AS,"__esModule",{value:!0});AS.createDirentFromStats=void 0;var FN=class{constructor(e,r){this.name=e,this.isBlockDevice=r.isBlockDevice.bind(r),this.isCharacterDevice=r.isCharacterDevice.bind(r),this.isDirectory=r.isDirectory.bind(r),this.isFIFO=r.isFIFO.bind(r),this.isFile=r.isFile.bind(r),this.isSocket=r.isSocket.bind(r),this.isSymbolicLink=r.isSymbolicLink.bind(r)}};function _Ze(t,e){return new FN(t,e)}AS.createDirentFromStats=_Ze});var Sne=_(Zu=>{"use strict";Object.defineProperty(Zu,"__esModule",{value:!0});Zu.removeLeadingDotSegment=Zu.escape=Zu.makeAbsolute=Zu.unixify=void 0;var HZe=ve("path"),qZe=2,GZe=/(\\?)([()*?[\]{|}]|^!|[!+@](?=\())/g;function jZe(t){return t.replace(/\\/g,"/")}Zu.unixify=jZe;function YZe(t,e){return HZe.resolve(t,e)}Zu.makeAbsolute=YZe;function WZe(t){return t.replace(GZe,"\\$2")}Zu.escape=WZe;function KZe(t){if(t.charAt(0)==="."){let e=t.charAt(1);if(e==="/"||e==="\\")return t.slice(qZe)}return t}Zu.removeLeadingDotSegment=KZe});var xne=_((bTt,bne)=>{bne.exports=function(e){if(typeof e!="string"||e==="")return!1;for(var r;r=/(\\).|([@?!+*]\(.*\))/g.exec(e);){if(r[2])return!0;e=e.slice(r.index+r[0].length)}return!1}});var Fne=_((xTt,Qne)=>{var zZe=xne(),kne={"{":"}","(":")","[":"]"},VZe=function(t){if(t[0]==="!")return!0;for(var e=0,r=-2,o=-2,a=-2,n=-2,u=-2;e<t.length;){if(t[e]==="*"||t[e+1]==="?"&&/[\].+)]/.test(t[e])||o!==-1&&t[e]==="["&&t[e+1]!=="]"&&(o<e&&(o=t.indexOf("]",e)),o>e&&(u===-1||u>o||(u=t.indexOf("\\",e),u===-1||u>o)))||a!==-1&&t[e]==="{"&&t[e+1]!=="}"&&(a=t.indexOf("}",e),a>e&&(u=t.indexOf("\\",e),u===-1||u>a))||n!==-1&&t[e]==="("&&t[e+1]==="?"&&/[:!=]/.test(t[e+2])&&t[e+3]!==")"&&(n=t.indexOf(")",e),n>e&&(u=t.indexOf("\\",e),u===-1||u>n))||r!==-1&&t[e]==="("&&t[e+1]!=="|"&&(r<e&&(r=t.indexOf("|",e)),r!==-1&&t[r+1]!==")"&&(n=t.indexOf(")",r),n>r&&(u=t.indexOf("\\",r),u===-1||u>n))))return!0;if(t[e]==="\\"){var A=t[e+1];e+=2;var p=kne[A];if(p){var h=t.indexOf(p,e);h!==-1&&(e=h+1)}if(t[e]==="!")return!0}else e++}return!1},JZe=function(t){if(t[0]==="!")return!0;for(var e=0;e<t.length;){if(/[*?{}()[\]]/.test(t[e]))return!0;if(t[e]==="\\"){var r=t[e+1];e+=2;var o=kne[r];if(o){var a=t.indexOf(o,e);a!==-1&&(e=a+1)}if(t[e]==="!")return!0}else e++}return!1};Qne.exports=function(e,r){if(typeof e!="string"||e==="")return!1;if(zZe(e))return!0;var o=VZe;return r&&r.strict===!1&&(o=JZe),o(e)}});var Tne=_((kTt,Rne)=>{"use strict";var XZe=Fne(),ZZe=ve("path").posix.dirname,$Ze=ve("os").platform()==="win32",RN="/",e$e=/\\/g,t$e=/[\{\[].*[\}\]]$/,r$e=/(^|[^\\])([\{\[]|\([^\)]+$)/,n$e=/\\([\!\*\?\|\[\]\(\)\{\}])/g;Rne.exports=function(e,r){var o=Object.assign({flipBackslashes:!0},r);o.flipBackslashes&&$Ze&&e.indexOf(RN)<0&&(e=e.replace(e$e,RN)),t$e.test(e)&&(e+=RN),e+="a";do e=ZZe(e);while(XZe(e)||r$e.test(e));return e.replace(n$e,"$1")}});var qne=_(Gr=>{"use strict";Object.defineProperty(Gr,"__esModule",{value:!0});Gr.matchAny=Gr.convertPatternsToRe=Gr.makeRe=Gr.getPatternParts=Gr.expandBraceExpansion=Gr.expandPatternsWithBraceExpansion=Gr.isAffectDepthOfReadingPattern=Gr.endsWithSlashGlobStar=Gr.hasGlobStar=Gr.getBaseDirectory=Gr.isPatternRelatedToParentDirectory=Gr.getPatternsOutsideCurrentDirectory=Gr.getPatternsInsideCurrentDirectory=Gr.getPositivePatterns=Gr.getNegativePatterns=Gr.isPositivePattern=Gr.isNegativePattern=Gr.convertToNegativePattern=Gr.convertToPositivePattern=Gr.isDynamicPattern=Gr.isStaticPattern=void 0;var i$e=ve("path"),s$e=Tne(),TN=Zo(),Lne="**",o$e="\\",a$e=/[*?]|^!/,l$e=/\[[^[]*]/,c$e=/(?:^|[^!*+?@])\([^(]*\|[^|]*\)/,u$e=/[!*+?@]\([^(]*\)/,A$e=/,|\.\./;function Nne(t,e={}){return!One(t,e)}Gr.isStaticPattern=Nne;function One(t,e={}){return t===""?!1:!!(e.caseSensitiveMatch===!1||t.includes(o$e)||a$e.test(t)||l$e.test(t)||c$e.test(t)||e.extglob!==!1&&u$e.test(t)||e.braceExpansion!==!1&&f$e(t))}Gr.isDynamicPattern=One;function f$e(t){let e=t.indexOf("{");if(e===-1)return!1;let r=t.indexOf("}",e+1);if(r===-1)return!1;let o=t.slice(e,r);return A$e.test(o)}function p$e(t){return fS(t)?t.slice(1):t}Gr.convertToPositivePattern=p$e;function h$e(t){return"!"+t}Gr.convertToNegativePattern=h$e;function fS(t){return t.startsWith("!")&&t[1]!=="("}Gr.isNegativePattern=fS;function Mne(t){return!fS(t)}Gr.isPositivePattern=Mne;function g$e(t){return t.filter(fS)}Gr.getNegativePatterns=g$e;function d$e(t){return t.filter(Mne)}Gr.getPositivePatterns=d$e;function m$e(t){return t.filter(e=>!LN(e))}Gr.getPatternsInsideCurrentDirectory=m$e;function y$e(t){return t.filter(LN)}Gr.getPatternsOutsideCurrentDirectory=y$e;function LN(t){return t.startsWith("..")||t.startsWith("./..")}Gr.isPatternRelatedToParentDirectory=LN;function E$e(t){return s$e(t,{flipBackslashes:!1})}Gr.getBaseDirectory=E$e;function C$e(t){return t.includes(Lne)}Gr.hasGlobStar=C$e;function Une(t){return t.endsWith("/"+Lne)}Gr.endsWithSlashGlobStar=Une;function w$e(t){let e=i$e.basename(t);return Une(t)||Nne(e)}Gr.isAffectDepthOfReadingPattern=w$e;function I$e(t){return t.reduce((e,r)=>e.concat(_ne(r)),[])}Gr.expandPatternsWithBraceExpansion=I$e;function _ne(t){return TN.braces(t,{expand:!0,nodupes:!0})}Gr.expandBraceExpansion=_ne;function B$e(t,e){let{parts:r}=TN.scan(t,Object.assign(Object.assign({},e),{parts:!0}));return r.length===0&&(r=[t]),r[0].startsWith("/")&&(r[0]=r[0].slice(1),r.unshift("")),r}Gr.getPatternParts=B$e;function Hne(t,e){return TN.makeRe(t,e)}Gr.makeRe=Hne;function v$e(t,e){return t.map(r=>Hne(r,e))}Gr.convertPatternsToRe=v$e;function D$e(t,e){return e.some(r=>r.test(t))}Gr.matchAny=D$e});var Wne=_((FTt,Yne)=>{"use strict";var P$e=ve("stream"),Gne=P$e.PassThrough,S$e=Array.prototype.slice;Yne.exports=b$e;function b$e(){let t=[],e=S$e.call(arguments),r=!1,o=e[e.length-1];o&&!Array.isArray(o)&&o.pipe==null?e.pop():o={};let a=o.end!==!1,n=o.pipeError===!0;o.objectMode==null&&(o.objectMode=!0),o.highWaterMark==null&&(o.highWaterMark=64*1024);let u=Gne(o);function A(){for(let E=0,I=arguments.length;E<I;E++)t.push(jne(arguments[E],o));return p(),this}function p(){if(r)return;r=!0;let E=t.shift();if(!E){process.nextTick(h);return}Array.isArray(E)||(E=[E]);let I=E.length+1;function v(){--I>0||(r=!1,p())}function x(C){function R(){C.removeListener("merge2UnpipeEnd",R),C.removeListener("end",R),n&&C.removeListener("error",N),v()}function N(U){u.emit("error",U)}if(C._readableState.endEmitted)return v();C.on("merge2UnpipeEnd",R),C.on("end",R),n&&C.on("error",N),C.pipe(u,{end:!1}),C.resume()}for(let C=0;C<E.length;C++)x(E[C]);v()}function h(){r=!1,u.emit("queueDrain"),a&&u.end()}return u.setMaxListeners(0),u.add=A,u.on("unpipe",function(E){E.emit("merge2UnpipeEnd")}),e.length&&A.apply(null,e),u}function jne(t,e){if(Array.isArray(t))for(let r=0,o=t.length;r<o;r++)t[r]=jne(t[r],e);else{if(!t._readableState&&t.pipe&&(t=t.pipe(Gne(e))),!t._readableState||!t.pause||!t.pipe)throw new Error("Only readable stream can be merged.");t.pause()}return t}});var zne=_(pS=>{"use strict";Object.defineProperty(pS,"__esModule",{value:!0});pS.merge=void 0;var x$e=Wne();function k$e(t){let e=x$e(t);return t.forEach(r=>{r.once("error",o=>e.emit("error",o))}),e.once("close",()=>Kne(t)),e.once("end",()=>Kne(t)),e}pS.merge=k$e;function Kne(t){t.forEach(e=>e.emit("close"))}});var Vne=_(eE=>{"use strict";Object.defineProperty(eE,"__esModule",{value:!0});eE.isEmpty=eE.isString=void 0;function Q$e(t){return typeof t=="string"}eE.isString=Q$e;function F$e(t){return t===""}eE.isEmpty=F$e});var Pf=_(xo=>{"use strict";Object.defineProperty(xo,"__esModule",{value:!0});xo.string=xo.stream=xo.pattern=xo.path=xo.fs=xo.errno=xo.array=void 0;var R$e=vne();xo.array=R$e;var T$e=Dne();xo.errno=T$e;var L$e=Pne();xo.fs=L$e;var N$e=Sne();xo.path=N$e;var O$e=qne();xo.pattern=O$e;var M$e=zne();xo.stream=M$e;var U$e=Vne();xo.string=U$e});var Zne=_(ko=>{"use strict";Object.defineProperty(ko,"__esModule",{value:!0});ko.convertPatternGroupToTask=ko.convertPatternGroupsToTasks=ko.groupPatternsByBaseDirectory=ko.getNegativePatternsAsPositive=ko.getPositivePatterns=ko.convertPatternsToTasks=ko.generate=void 0;var Sf=Pf();function _$e(t,e){let r=Jne(t),o=Xne(t,e.ignore),a=r.filter(p=>Sf.pattern.isStaticPattern(p,e)),n=r.filter(p=>Sf.pattern.isDynamicPattern(p,e)),u=NN(a,o,!1),A=NN(n,o,!0);return u.concat(A)}ko.generate=_$e;function NN(t,e,r){let o=[],a=Sf.pattern.getPatternsOutsideCurrentDirectory(t),n=Sf.pattern.getPatternsInsideCurrentDirectory(t),u=ON(a),A=ON(n);return o.push(...MN(u,e,r)),"."in A?o.push(UN(".",n,e,r)):o.push(...MN(A,e,r)),o}ko.convertPatternsToTasks=NN;function Jne(t){return Sf.pattern.getPositivePatterns(t)}ko.getPositivePatterns=Jne;function Xne(t,e){return Sf.pattern.getNegativePatterns(t).concat(e).map(Sf.pattern.convertToPositivePattern)}ko.getNegativePatternsAsPositive=Xne;function ON(t){let e={};return t.reduce((r,o)=>{let a=Sf.pattern.getBaseDirectory(o);return a in r?r[a].push(o):r[a]=[o],r},e)}ko.groupPatternsByBaseDirectory=ON;function MN(t,e,r){return Object.keys(t).map(o=>UN(o,t[o],e,r))}ko.convertPatternGroupsToTasks=MN;function UN(t,e,r,o){return{dynamic:o,positive:e,negative:r,base:t,patterns:[].concat(e,r.map(Sf.pattern.convertToNegativePattern))}}ko.convertPatternGroupToTask=UN});var eie=_(tE=>{"use strict";Object.defineProperty(tE,"__esModule",{value:!0});tE.removeDuplicateSlashes=tE.transform=void 0;var H$e=/(?!^)\/{2,}/g;function q$e(t){return t.map(e=>$ne(e))}tE.transform=q$e;function $ne(t){return t.replace(H$e,"/")}tE.removeDuplicateSlashes=$ne});var rie=_(hS=>{"use strict";Object.defineProperty(hS,"__esModule",{value:!0});hS.read=void 0;function G$e(t,e,r){e.fs.lstat(t,(o,a)=>{if(o!==null){tie(r,o);return}if(!a.isSymbolicLink()||!e.followSymbolicLink){_N(r,a);return}e.fs.stat(t,(n,u)=>{if(n!==null){if(e.throwErrorOnBrokenSymbolicLink){tie(r,n);return}_N(r,a);return}e.markSymbolicLink&&(u.isSymbolicLink=()=>!0),_N(r,u)})})}hS.read=G$e;function tie(t,e){t(e)}function _N(t,e){t(null,e)}});var nie=_(gS=>{"use strict";Object.defineProperty(gS,"__esModule",{value:!0});gS.read=void 0;function j$e(t,e){let r=e.fs.lstatSync(t);if(!r.isSymbolicLink()||!e.followSymbolicLink)return r;try{let o=e.fs.statSync(t);return e.markSymbolicLink&&(o.isSymbolicLink=()=>!0),o}catch(o){if(!e.throwErrorOnBrokenSymbolicLink)return r;throw o}}gS.read=j$e});var iie=_(Zp=>{"use strict";Object.defineProperty(Zp,"__esModule",{value:!0});Zp.createFileSystemAdapter=Zp.FILE_SYSTEM_ADAPTER=void 0;var dS=ve("fs");Zp.FILE_SYSTEM_ADAPTER={lstat:dS.lstat,stat:dS.stat,lstatSync:dS.lstatSync,statSync:dS.statSync};function Y$e(t){return t===void 0?Zp.FILE_SYSTEM_ADAPTER:Object.assign(Object.assign({},Zp.FILE_SYSTEM_ADAPTER),t)}Zp.createFileSystemAdapter=Y$e});var sie=_(qN=>{"use strict";Object.defineProperty(qN,"__esModule",{value:!0});var W$e=iie(),HN=class{constructor(e={}){this._options=e,this.followSymbolicLink=this._getValue(this._options.followSymbolicLink,!0),this.fs=W$e.createFileSystemAdapter(this._options.fs),this.markSymbolicLink=this._getValue(this._options.markSymbolicLink,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!0)}_getValue(e,r){return e??r}};qN.default=HN});var wd=_($p=>{"use strict";Object.defineProperty($p,"__esModule",{value:!0});$p.statSync=$p.stat=$p.Settings=void 0;var oie=rie(),K$e=nie(),GN=sie();$p.Settings=GN.default;function z$e(t,e,r){if(typeof e=="function"){oie.read(t,jN(),e);return}oie.read(t,jN(e),r)}$p.stat=z$e;function V$e(t,e){let r=jN(e);return K$e.read(t,r)}$p.statSync=V$e;function jN(t={}){return t instanceof GN.default?t:new GN.default(t)}});var lie=_((GTt,aie)=>{aie.exports=J$e;function J$e(t,e){var r,o,a,n=!0;Array.isArray(t)?(r=[],o=t.length):(a=Object.keys(t),r={},o=a.length);function u(p){function h(){e&&e(p,r),e=null}n?process.nextTick(h):h()}function A(p,h,E){r[p]=E,(--o===0||h)&&u(h)}o?a?a.forEach(function(p){t[p](function(h,E){A(p,h,E)})}):t.forEach(function(p,h){p(function(E,I){A(h,E,I)})}):u(null),n=!1}});var YN=_(yS=>{"use strict";Object.defineProperty(yS,"__esModule",{value:!0});yS.IS_SUPPORT_READDIR_WITH_FILE_TYPES=void 0;var mS=process.versions.node.split(".");if(mS[0]===void 0||mS[1]===void 0)throw new Error(`Unexpected behavior. The 'process.versions.node' variable has invalid value: ${process.versions.node}`);var cie=Number.parseInt(mS[0],10),X$e=Number.parseInt(mS[1],10),uie=10,Z$e=10,$$e=cie>uie,eet=cie===uie&&X$e>=Z$e;yS.IS_SUPPORT_READDIR_WITH_FILE_TYPES=$$e||eet});var Aie=_(ES=>{"use strict";Object.defineProperty(ES,"__esModule",{value:!0});ES.createDirentFromStats=void 0;var WN=class{constructor(e,r){this.name=e,this.isBlockDevice=r.isBlockDevice.bind(r),this.isCharacterDevice=r.isCharacterDevice.bind(r),this.isDirectory=r.isDirectory.bind(r),this.isFIFO=r.isFIFO.bind(r),this.isFile=r.isFile.bind(r),this.isSocket=r.isSocket.bind(r),this.isSymbolicLink=r.isSymbolicLink.bind(r)}};function tet(t,e){return new WN(t,e)}ES.createDirentFromStats=tet});var KN=_(CS=>{"use strict";Object.defineProperty(CS,"__esModule",{value:!0});CS.fs=void 0;var ret=Aie();CS.fs=ret});var zN=_(wS=>{"use strict";Object.defineProperty(wS,"__esModule",{value:!0});wS.joinPathSegments=void 0;function net(t,e,r){return t.endsWith(r)?t+e:t+r+e}wS.joinPathSegments=net});var mie=_(eh=>{"use strict";Object.defineProperty(eh,"__esModule",{value:!0});eh.readdir=eh.readdirWithFileTypes=eh.read=void 0;var iet=wd(),fie=lie(),set=YN(),pie=KN(),hie=zN();function oet(t,e,r){if(!e.stats&&set.IS_SUPPORT_READDIR_WITH_FILE_TYPES){gie(t,e,r);return}die(t,e,r)}eh.read=oet;function gie(t,e,r){e.fs.readdir(t,{withFileTypes:!0},(o,a)=>{if(o!==null){IS(r,o);return}let n=a.map(A=>({dirent:A,name:A.name,path:hie.joinPathSegments(t,A.name,e.pathSegmentSeparator)}));if(!e.followSymbolicLinks){VN(r,n);return}let u=n.map(A=>aet(A,e));fie(u,(A,p)=>{if(A!==null){IS(r,A);return}VN(r,p)})})}eh.readdirWithFileTypes=gie;function aet(t,e){return r=>{if(!t.dirent.isSymbolicLink()){r(null,t);return}e.fs.stat(t.path,(o,a)=>{if(o!==null){if(e.throwErrorOnBrokenSymbolicLink){r(o);return}r(null,t);return}t.dirent=pie.fs.createDirentFromStats(t.name,a),r(null,t)})}}function die(t,e,r){e.fs.readdir(t,(o,a)=>{if(o!==null){IS(r,o);return}let n=a.map(u=>{let A=hie.joinPathSegments(t,u,e.pathSegmentSeparator);return p=>{iet.stat(A,e.fsStatSettings,(h,E)=>{if(h!==null){p(h);return}let I={name:u,path:A,dirent:pie.fs.createDirentFromStats(u,E)};e.stats&&(I.stats=E),p(null,I)})}});fie(n,(u,A)=>{if(u!==null){IS(r,u);return}VN(r,A)})})}eh.readdir=die;function IS(t,e){t(e)}function VN(t,e){t(null,e)}});var Iie=_(th=>{"use strict";Object.defineProperty(th,"__esModule",{value:!0});th.readdir=th.readdirWithFileTypes=th.read=void 0;var cet=wd(),uet=YN(),yie=KN(),Eie=zN();function Aet(t,e){return!e.stats&&uet.IS_SUPPORT_READDIR_WITH_FILE_TYPES?Cie(t,e):wie(t,e)}th.read=Aet;function Cie(t,e){return e.fs.readdirSync(t,{withFileTypes:!0}).map(o=>{let a={dirent:o,name:o.name,path:Eie.joinPathSegments(t,o.name,e.pathSegmentSeparator)};if(a.dirent.isSymbolicLink()&&e.followSymbolicLinks)try{let n=e.fs.statSync(a.path);a.dirent=yie.fs.createDirentFromStats(a.name,n)}catch(n){if(e.throwErrorOnBrokenSymbolicLink)throw n}return a})}th.readdirWithFileTypes=Cie;function wie(t,e){return e.fs.readdirSync(t).map(o=>{let a=Eie.joinPathSegments(t,o,e.pathSegmentSeparator),n=cet.statSync(a,e.fsStatSettings),u={name:o,path:a,dirent:yie.fs.createDirentFromStats(o,n)};return e.stats&&(u.stats=n),u})}th.readdir=wie});var Bie=_(rh=>{"use strict";Object.defineProperty(rh,"__esModule",{value:!0});rh.createFileSystemAdapter=rh.FILE_SYSTEM_ADAPTER=void 0;var rE=ve("fs");rh.FILE_SYSTEM_ADAPTER={lstat:rE.lstat,stat:rE.stat,lstatSync:rE.lstatSync,statSync:rE.statSync,readdir:rE.readdir,readdirSync:rE.readdirSync};function fet(t){return t===void 0?rh.FILE_SYSTEM_ADAPTER:Object.assign(Object.assign({},rh.FILE_SYSTEM_ADAPTER),t)}rh.createFileSystemAdapter=fet});var vie=_(XN=>{"use strict";Object.defineProperty(XN,"__esModule",{value:!0});var pet=ve("path"),het=wd(),get=Bie(),JN=class{constructor(e={}){this._options=e,this.followSymbolicLinks=this._getValue(this._options.followSymbolicLinks,!1),this.fs=get.createFileSystemAdapter(this._options.fs),this.pathSegmentSeparator=this._getValue(this._options.pathSegmentSeparator,pet.sep),this.stats=this._getValue(this._options.stats,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!0),this.fsStatSettings=new het.Settings({followSymbolicLink:this.followSymbolicLinks,fs:this.fs,throwErrorOnBrokenSymbolicLink:this.throwErrorOnBrokenSymbolicLink})}_getValue(e,r){return e??r}};XN.default=JN});var BS=_(nh=>{"use strict";Object.defineProperty(nh,"__esModule",{value:!0});nh.Settings=nh.scandirSync=nh.scandir=void 0;var Die=mie(),det=Iie(),ZN=vie();nh.Settings=ZN.default;function met(t,e,r){if(typeof e=="function"){Die.read(t,$N(),e);return}Die.read(t,$N(e),r)}nh.scandir=met;function yet(t,e){let r=$N(e);return det.read(t,r)}nh.scandirSync=yet;function $N(t={}){return t instanceof ZN.default?t:new ZN.default(t)}});var Sie=_(($Tt,Pie)=>{"use strict";function Eet(t){var e=new t,r=e;function o(){var n=e;return n.next?e=n.next:(e=new t,r=e),n.next=null,n}function a(n){r.next=n,r=n}return{get:o,release:a}}Pie.exports=Eet});var xie=_((eLt,eO)=>{"use strict";var Cet=Sie();function bie(t,e,r){if(typeof t=="function"&&(r=e,e=t,t=null),r<1)throw new Error("fastqueue concurrency must be greater than 1");var o=Cet(wet),a=null,n=null,u=0,A=null,p={push:R,drain:Yl,saturated:Yl,pause:E,paused:!1,concurrency:r,running:h,resume:x,idle:C,length:I,getQueue:v,unshift:N,empty:Yl,kill:V,killAndDrain:te,error:ae};return p;function h(){return u}function E(){p.paused=!0}function I(){for(var fe=a,ue=0;fe;)fe=fe.next,ue++;return ue}function v(){for(var fe=a,ue=[];fe;)ue.push(fe.value),fe=fe.next;return ue}function x(){if(!!p.paused){p.paused=!1;for(var fe=0;fe<p.concurrency;fe++)u++,U()}}function C(){return u===0&&p.length()===0}function R(fe,ue){var me=o.get();me.context=t,me.release=U,me.value=fe,me.callback=ue||Yl,me.errorHandler=A,u===p.concurrency||p.paused?n?(n.next=me,n=me):(a=me,n=me,p.saturated()):(u++,e.call(t,me.value,me.worked))}function N(fe,ue){var me=o.get();me.context=t,me.release=U,me.value=fe,me.callback=ue||Yl,u===p.concurrency||p.paused?a?(me.next=a,a=me):(a=me,n=me,p.saturated()):(u++,e.call(t,me.value,me.worked))}function U(fe){fe&&o.release(fe);var ue=a;ue?p.paused?u--:(n===a&&(n=null),a=ue.next,ue.next=null,e.call(t,ue.value,ue.worked),n===null&&p.empty()):--u===0&&p.drain()}function V(){a=null,n=null,p.drain=Yl}function te(){a=null,n=null,p.drain(),p.drain=Yl}function ae(fe){A=fe}}function Yl(){}function wet(){this.value=null,this.callback=Yl,this.next=null,this.release=Yl,this.context=null,this.errorHandler=null;var t=this;this.worked=function(r,o){var a=t.callback,n=t.errorHandler,u=t.value;t.value=null,t.callback=Yl,t.errorHandler&&n(r,u),a.call(t.context,r,o),t.release(t)}}function Iet(t,e,r){typeof t=="function"&&(r=e,e=t,t=null);function o(E,I){e.call(this,E).then(function(v){I(null,v)},I)}var a=bie(t,o,r),n=a.push,u=a.unshift;return a.push=A,a.unshift=p,a.drained=h,a;function A(E){var I=new Promise(function(v,x){n(E,function(C,R){if(C){x(C);return}v(R)})});return I.catch(Yl),I}function p(E){var I=new Promise(function(v,x){u(E,function(C,R){if(C){x(C);return}v(R)})});return I.catch(Yl),I}function h(){var E=a.drain,I=new Promise(function(v){a.drain=function(){E(),v()}});return I}}eO.exports=bie;eO.exports.promise=Iet});var vS=_($u=>{"use strict";Object.defineProperty($u,"__esModule",{value:!0});$u.joinPathSegments=$u.replacePathSegmentSeparator=$u.isAppliedFilter=$u.isFatalError=void 0;function Bet(t,e){return t.errorFilter===null?!0:!t.errorFilter(e)}$u.isFatalError=Bet;function vet(t,e){return t===null||t(e)}$u.isAppliedFilter=vet;function Det(t,e){return t.split(/[/\\]/).join(e)}$u.replacePathSegmentSeparator=Det;function Pet(t,e,r){return t===""?e:t.endsWith(r)?t+e:t+r+e}$u.joinPathSegments=Pet});var nO=_(rO=>{"use strict";Object.defineProperty(rO,"__esModule",{value:!0});var bet=vS(),tO=class{constructor(e,r){this._root=e,this._settings=r,this._root=bet.replacePathSegmentSeparator(e,r.pathSegmentSeparator)}};rO.default=tO});var oO=_(sO=>{"use strict";Object.defineProperty(sO,"__esModule",{value:!0});var xet=ve("events"),ket=BS(),Qet=xie(),DS=vS(),Fet=nO(),iO=class extends Fet.default{constructor(e,r){super(e,r),this._settings=r,this._scandir=ket.scandir,this._emitter=new xet.EventEmitter,this._queue=Qet(this._worker.bind(this),this._settings.concurrency),this._isFatalError=!1,this._isDestroyed=!1,this._queue.drain=()=>{this._isFatalError||this._emitter.emit("end")}}read(){return this._isFatalError=!1,this._isDestroyed=!1,setImmediate(()=>{this._pushToQueue(this._root,this._settings.basePath)}),this._emitter}get isDestroyed(){return this._isDestroyed}destroy(){if(this._isDestroyed)throw new Error("The reader is already destroyed");this._isDestroyed=!0,this._queue.killAndDrain()}onEntry(e){this._emitter.on("entry",e)}onError(e){this._emitter.once("error",e)}onEnd(e){this._emitter.once("end",e)}_pushToQueue(e,r){let o={directory:e,base:r};this._queue.push(o,a=>{a!==null&&this._handleError(a)})}_worker(e,r){this._scandir(e.directory,this._settings.fsScandirSettings,(o,a)=>{if(o!==null){r(o,void 0);return}for(let n of a)this._handleEntry(n,e.base);r(null,void 0)})}_handleError(e){this._isDestroyed||!DS.isFatalError(this._settings,e)||(this._isFatalError=!0,this._isDestroyed=!0,this._emitter.emit("error",e))}_handleEntry(e,r){if(this._isDestroyed||this._isFatalError)return;let o=e.path;r!==void 0&&(e.path=DS.joinPathSegments(r,e.name,this._settings.pathSegmentSeparator)),DS.isAppliedFilter(this._settings.entryFilter,e)&&this._emitEntry(e),e.dirent.isDirectory()&&DS.isAppliedFilter(this._settings.deepFilter,e)&&this._pushToQueue(o,r===void 0?void 0:e.path)}_emitEntry(e){this._emitter.emit("entry",e)}};sO.default=iO});var kie=_(lO=>{"use strict";Object.defineProperty(lO,"__esModule",{value:!0});var Ret=oO(),aO=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new Ret.default(this._root,this._settings),this._storage=[]}read(e){this._reader.onError(r=>{Tet(e,r)}),this._reader.onEntry(r=>{this._storage.push(r)}),this._reader.onEnd(()=>{Let(e,this._storage)}),this._reader.read()}};lO.default=aO;function Tet(t,e){t(e)}function Let(t,e){t(null,e)}});var Qie=_(uO=>{"use strict";Object.defineProperty(uO,"__esModule",{value:!0});var Net=ve("stream"),Oet=oO(),cO=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new Oet.default(this._root,this._settings),this._stream=new Net.Readable({objectMode:!0,read:()=>{},destroy:()=>{this._reader.isDestroyed||this._reader.destroy()}})}read(){return this._reader.onError(e=>{this._stream.emit("error",e)}),this._reader.onEntry(e=>{this._stream.push(e)}),this._reader.onEnd(()=>{this._stream.push(null)}),this._reader.read(),this._stream}};uO.default=cO});var Fie=_(fO=>{"use strict";Object.defineProperty(fO,"__esModule",{value:!0});var Met=BS(),PS=vS(),Uet=nO(),AO=class extends Uet.default{constructor(){super(...arguments),this._scandir=Met.scandirSync,this._storage=[],this._queue=new Set}read(){return this._pushToQueue(this._root,this._settings.basePath),this._handleQueue(),this._storage}_pushToQueue(e,r){this._queue.add({directory:e,base:r})}_handleQueue(){for(let e of this._queue.values())this._handleDirectory(e.directory,e.base)}_handleDirectory(e,r){try{let o=this._scandir(e,this._settings.fsScandirSettings);for(let a of o)this._handleEntry(a,r)}catch(o){this._handleError(o)}}_handleError(e){if(!!PS.isFatalError(this._settings,e))throw e}_handleEntry(e,r){let o=e.path;r!==void 0&&(e.path=PS.joinPathSegments(r,e.name,this._settings.pathSegmentSeparator)),PS.isAppliedFilter(this._settings.entryFilter,e)&&this._pushToStorage(e),e.dirent.isDirectory()&&PS.isAppliedFilter(this._settings.deepFilter,e)&&this._pushToQueue(o,r===void 0?void 0:e.path)}_pushToStorage(e){this._storage.push(e)}};fO.default=AO});var Rie=_(hO=>{"use strict";Object.defineProperty(hO,"__esModule",{value:!0});var _et=Fie(),pO=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new _et.default(this._root,this._settings)}read(){return this._reader.read()}};hO.default=pO});var Tie=_(dO=>{"use strict";Object.defineProperty(dO,"__esModule",{value:!0});var Het=ve("path"),qet=BS(),gO=class{constructor(e={}){this._options=e,this.basePath=this._getValue(this._options.basePath,void 0),this.concurrency=this._getValue(this._options.concurrency,Number.POSITIVE_INFINITY),this.deepFilter=this._getValue(this._options.deepFilter,null),this.entryFilter=this._getValue(this._options.entryFilter,null),this.errorFilter=this._getValue(this._options.errorFilter,null),this.pathSegmentSeparator=this._getValue(this._options.pathSegmentSeparator,Het.sep),this.fsScandirSettings=new qet.Settings({followSymbolicLinks:this._options.followSymbolicLinks,fs:this._options.fs,pathSegmentSeparator:this._options.pathSegmentSeparator,stats:this._options.stats,throwErrorOnBrokenSymbolicLink:this._options.throwErrorOnBrokenSymbolicLink})}_getValue(e,r){return e??r}};dO.default=gO});var bS=_(eA=>{"use strict";Object.defineProperty(eA,"__esModule",{value:!0});eA.Settings=eA.walkStream=eA.walkSync=eA.walk=void 0;var Lie=kie(),Get=Qie(),jet=Rie(),mO=Tie();eA.Settings=mO.default;function Yet(t,e,r){if(typeof e=="function"){new Lie.default(t,SS()).read(e);return}new Lie.default(t,SS(e)).read(r)}eA.walk=Yet;function Wet(t,e){let r=SS(e);return new jet.default(t,r).read()}eA.walkSync=Wet;function Ket(t,e){let r=SS(e);return new Get.default(t,r).read()}eA.walkStream=Ket;function SS(t={}){return t instanceof mO.default?t:new mO.default(t)}});var xS=_(EO=>{"use strict";Object.defineProperty(EO,"__esModule",{value:!0});var zet=ve("path"),Vet=wd(),Nie=Pf(),yO=class{constructor(e){this._settings=e,this._fsStatSettings=new Vet.Settings({followSymbolicLink:this._settings.followSymbolicLinks,fs:this._settings.fs,throwErrorOnBrokenSymbolicLink:this._settings.followSymbolicLinks})}_getFullEntryPath(e){return zet.resolve(this._settings.cwd,e)}_makeEntry(e,r){let o={name:r,path:r,dirent:Nie.fs.createDirentFromStats(r,e)};return this._settings.stats&&(o.stats=e),o}_isFatalError(e){return!Nie.errno.isEnoentCodeError(e)&&!this._settings.suppressErrors}};EO.default=yO});var IO=_(wO=>{"use strict";Object.defineProperty(wO,"__esModule",{value:!0});var Jet=ve("stream"),Xet=wd(),Zet=bS(),$et=xS(),CO=class extends $et.default{constructor(){super(...arguments),this._walkStream=Zet.walkStream,this._stat=Xet.stat}dynamic(e,r){return this._walkStream(e,r)}static(e,r){let o=e.map(this._getFullEntryPath,this),a=new Jet.PassThrough({objectMode:!0});a._write=(n,u,A)=>this._getEntry(o[n],e[n],r).then(p=>{p!==null&&r.entryFilter(p)&&a.push(p),n===o.length-1&&a.end(),A()}).catch(A);for(let n=0;n<o.length;n++)a.write(n);return a}_getEntry(e,r,o){return this._getStat(e).then(a=>this._makeEntry(a,r)).catch(a=>{if(o.errorFilter(a))return null;throw a})}_getStat(e){return new Promise((r,o)=>{this._stat(e,this._fsStatSettings,(a,n)=>a===null?r(n):o(a))})}};wO.default=CO});var Oie=_(vO=>{"use strict";Object.defineProperty(vO,"__esModule",{value:!0});var ett=bS(),ttt=xS(),rtt=IO(),BO=class extends ttt.default{constructor(){super(...arguments),this._walkAsync=ett.walk,this._readerStream=new rtt.default(this._settings)}dynamic(e,r){return new Promise((o,a)=>{this._walkAsync(e,r,(n,u)=>{n===null?o(u):a(n)})})}async static(e,r){let o=[],a=this._readerStream.static(e,r);return new Promise((n,u)=>{a.once("error",u),a.on("data",A=>o.push(A)),a.once("end",()=>n(o))})}};vO.default=BO});var Mie=_(PO=>{"use strict";Object.defineProperty(PO,"__esModule",{value:!0});var nE=Pf(),DO=class{constructor(e,r,o){this._patterns=e,this._settings=r,this._micromatchOptions=o,this._storage=[],this._fillStorage()}_fillStorage(){let e=nE.pattern.expandPatternsWithBraceExpansion(this._patterns);for(let r of e){let o=this._getPatternSegments(r),a=this._splitSegmentsIntoSections(o);this._storage.push({complete:a.length<=1,pattern:r,segments:o,sections:a})}}_getPatternSegments(e){return nE.pattern.getPatternParts(e,this._micromatchOptions).map(o=>nE.pattern.isDynamicPattern(o,this._settings)?{dynamic:!0,pattern:o,patternRe:nE.pattern.makeRe(o,this._micromatchOptions)}:{dynamic:!1,pattern:o})}_splitSegmentsIntoSections(e){return nE.array.splitWhen(e,r=>r.dynamic&&nE.pattern.hasGlobStar(r.pattern))}};PO.default=DO});var Uie=_(bO=>{"use strict";Object.defineProperty(bO,"__esModule",{value:!0});var ntt=Mie(),SO=class extends ntt.default{match(e){let r=e.split("/"),o=r.length,a=this._storage.filter(n=>!n.complete||n.segments.length>o);for(let n of a){let u=n.sections[0];if(!n.complete&&o>u.length||r.every((p,h)=>{let E=n.segments[h];return!!(E.dynamic&&E.patternRe.test(p)||!E.dynamic&&E.pattern===p)}))return!0}return!1}};bO.default=SO});var _ie=_(kO=>{"use strict";Object.defineProperty(kO,"__esModule",{value:!0});var kS=Pf(),itt=Uie(),xO=class{constructor(e,r){this._settings=e,this._micromatchOptions=r}getFilter(e,r,o){let a=this._getMatcher(r),n=this._getNegativePatternsRe(o);return u=>this._filter(e,u,a,n)}_getMatcher(e){return new itt.default(e,this._settings,this._micromatchOptions)}_getNegativePatternsRe(e){let r=e.filter(kS.pattern.isAffectDepthOfReadingPattern);return kS.pattern.convertPatternsToRe(r,this._micromatchOptions)}_filter(e,r,o,a){if(this._isSkippedByDeep(e,r.path)||this._isSkippedSymbolicLink(r))return!1;let n=kS.path.removeLeadingDotSegment(r.path);return this._isSkippedByPositivePatterns(n,o)?!1:this._isSkippedByNegativePatterns(n,a)}_isSkippedByDeep(e,r){return this._settings.deep===1/0?!1:this._getEntryLevel(e,r)>=this._settings.deep}_getEntryLevel(e,r){let o=r.split("/").length;if(e==="")return o;let a=e.split("/").length;return o-a}_isSkippedSymbolicLink(e){return!this._settings.followSymbolicLinks&&e.dirent.isSymbolicLink()}_isSkippedByPositivePatterns(e,r){return!this._settings.baseNameMatch&&!r.match(e)}_isSkippedByNegativePatterns(e,r){return!kS.pattern.matchAny(e,r)}};kO.default=xO});var Hie=_(FO=>{"use strict";Object.defineProperty(FO,"__esModule",{value:!0});var Id=Pf(),QO=class{constructor(e,r){this._settings=e,this._micromatchOptions=r,this.index=new Map}getFilter(e,r){let o=Id.pattern.convertPatternsToRe(e,this._micromatchOptions),a=Id.pattern.convertPatternsToRe(r,this._micromatchOptions);return n=>this._filter(n,o,a)}_filter(e,r,o){if(this._settings.unique&&this._isDuplicateEntry(e)||this._onlyFileFilter(e)||this._onlyDirectoryFilter(e)||this._isSkippedByAbsoluteNegativePatterns(e.path,o))return!1;let a=this._settings.baseNameMatch?e.name:e.path,n=e.dirent.isDirectory(),u=this._isMatchToPatterns(a,r,n)&&!this._isMatchToPatterns(e.path,o,n);return this._settings.unique&&u&&this._createIndexRecord(e),u}_isDuplicateEntry(e){return this.index.has(e.path)}_createIndexRecord(e){this.index.set(e.path,void 0)}_onlyFileFilter(e){return this._settings.onlyFiles&&!e.dirent.isFile()}_onlyDirectoryFilter(e){return this._settings.onlyDirectories&&!e.dirent.isDirectory()}_isSkippedByAbsoluteNegativePatterns(e,r){if(!this._settings.absolute)return!1;let o=Id.path.makeAbsolute(this._settings.cwd,e);return Id.pattern.matchAny(o,r)}_isMatchToPatterns(e,r,o){let a=Id.path.removeLeadingDotSegment(e),n=Id.pattern.matchAny(a,r);return!n&&o?Id.pattern.matchAny(a+"/",r):n}};FO.default=QO});var qie=_(TO=>{"use strict";Object.defineProperty(TO,"__esModule",{value:!0});var stt=Pf(),RO=class{constructor(e){this._settings=e}getFilter(){return e=>this._isNonFatalError(e)}_isNonFatalError(e){return stt.errno.isEnoentCodeError(e)||this._settings.suppressErrors}};TO.default=RO});var jie=_(NO=>{"use strict";Object.defineProperty(NO,"__esModule",{value:!0});var Gie=Pf(),LO=class{constructor(e){this._settings=e}getTransformer(){return e=>this._transform(e)}_transform(e){let r=e.path;return this._settings.absolute&&(r=Gie.path.makeAbsolute(this._settings.cwd,r),r=Gie.path.unixify(r)),this._settings.markDirectories&&e.dirent.isDirectory()&&(r+="/"),this._settings.objectMode?Object.assign(Object.assign({},e),{path:r}):r}};NO.default=LO});var QS=_(MO=>{"use strict";Object.defineProperty(MO,"__esModule",{value:!0});var ott=ve("path"),att=_ie(),ltt=Hie(),ctt=qie(),utt=jie(),OO=class{constructor(e){this._settings=e,this.errorFilter=new ctt.default(this._settings),this.entryFilter=new ltt.default(this._settings,this._getMicromatchOptions()),this.deepFilter=new att.default(this._settings,this._getMicromatchOptions()),this.entryTransformer=new utt.default(this._settings)}_getRootDirectory(e){return ott.resolve(this._settings.cwd,e.base)}_getReaderOptions(e){let r=e.base==="."?"":e.base;return{basePath:r,pathSegmentSeparator:"/",concurrency:this._settings.concurrency,deepFilter:this.deepFilter.getFilter(r,e.positive,e.negative),entryFilter:this.entryFilter.getFilter(e.positive,e.negative),errorFilter:this.errorFilter.getFilter(),followSymbolicLinks:this._settings.followSymbolicLinks,fs:this._settings.fs,stats:this._settings.stats,throwErrorOnBrokenSymbolicLink:this._settings.throwErrorOnBrokenSymbolicLink,transform:this.entryTransformer.getTransformer()}}_getMicromatchOptions(){return{dot:this._settings.dot,matchBase:this._settings.baseNameMatch,nobrace:!this._settings.braceExpansion,nocase:!this._settings.caseSensitiveMatch,noext:!this._settings.extglob,noglobstar:!this._settings.globstar,posix:!0,strictSlashes:!1}}};MO.default=OO});var Yie=_(_O=>{"use strict";Object.defineProperty(_O,"__esModule",{value:!0});var Att=Oie(),ftt=QS(),UO=class extends ftt.default{constructor(){super(...arguments),this._reader=new Att.default(this._settings)}async read(e){let r=this._getRootDirectory(e),o=this._getReaderOptions(e);return(await this.api(r,e,o)).map(n=>o.transform(n))}api(e,r,o){return r.dynamic?this._reader.dynamic(e,o):this._reader.static(r.patterns,o)}};_O.default=UO});var Wie=_(qO=>{"use strict";Object.defineProperty(qO,"__esModule",{value:!0});var ptt=ve("stream"),htt=IO(),gtt=QS(),HO=class extends gtt.default{constructor(){super(...arguments),this._reader=new htt.default(this._settings)}read(e){let r=this._getRootDirectory(e),o=this._getReaderOptions(e),a=this.api(r,e,o),n=new ptt.Readable({objectMode:!0,read:()=>{}});return a.once("error",u=>n.emit("error",u)).on("data",u=>n.emit("data",o.transform(u))).once("end",()=>n.emit("end")),n.once("close",()=>a.destroy()),n}api(e,r,o){return r.dynamic?this._reader.dynamic(e,o):this._reader.static(r.patterns,o)}};qO.default=HO});var Kie=_(jO=>{"use strict";Object.defineProperty(jO,"__esModule",{value:!0});var dtt=wd(),mtt=bS(),ytt=xS(),GO=class extends ytt.default{constructor(){super(...arguments),this._walkSync=mtt.walkSync,this._statSync=dtt.statSync}dynamic(e,r){return this._walkSync(e,r)}static(e,r){let o=[];for(let a of e){let n=this._getFullEntryPath(a),u=this._getEntry(n,a,r);u===null||!r.entryFilter(u)||o.push(u)}return o}_getEntry(e,r,o){try{let a=this._getStat(e);return this._makeEntry(a,r)}catch(a){if(o.errorFilter(a))return null;throw a}}_getStat(e){return this._statSync(e,this._fsStatSettings)}};jO.default=GO});var zie=_(WO=>{"use strict";Object.defineProperty(WO,"__esModule",{value:!0});var Ett=Kie(),Ctt=QS(),YO=class extends Ctt.default{constructor(){super(...arguments),this._reader=new Ett.default(this._settings)}read(e){let r=this._getRootDirectory(e),o=this._getReaderOptions(e);return this.api(r,e,o).map(o.transform)}api(e,r,o){return r.dynamic?this._reader.dynamic(e,o):this._reader.static(r.patterns,o)}};WO.default=YO});var Vie=_(sE=>{"use strict";Object.defineProperty(sE,"__esModule",{value:!0});sE.DEFAULT_FILE_SYSTEM_ADAPTER=void 0;var iE=ve("fs"),wtt=ve("os"),Itt=Math.max(wtt.cpus().length,1);sE.DEFAULT_FILE_SYSTEM_ADAPTER={lstat:iE.lstat,lstatSync:iE.lstatSync,stat:iE.stat,statSync:iE.statSync,readdir:iE.readdir,readdirSync:iE.readdirSync};var KO=class{constructor(e={}){this._options=e,this.absolute=this._getValue(this._options.absolute,!1),this.baseNameMatch=this._getValue(this._options.baseNameMatch,!1),this.braceExpansion=this._getValue(this._options.braceExpansion,!0),this.caseSensitiveMatch=this._getValue(this._options.caseSensitiveMatch,!0),this.concurrency=this._getValue(this._options.concurrency,Itt),this.cwd=this._getValue(this._options.cwd,process.cwd()),this.deep=this._getValue(this._options.deep,1/0),this.dot=this._getValue(this._options.dot,!1),this.extglob=this._getValue(this._options.extglob,!0),this.followSymbolicLinks=this._getValue(this._options.followSymbolicLinks,!0),this.fs=this._getFileSystemMethods(this._options.fs),this.globstar=this._getValue(this._options.globstar,!0),this.ignore=this._getValue(this._options.ignore,[]),this.markDirectories=this._getValue(this._options.markDirectories,!1),this.objectMode=this._getValue(this._options.objectMode,!1),this.onlyDirectories=this._getValue(this._options.onlyDirectories,!1),this.onlyFiles=this._getValue(this._options.onlyFiles,!0),this.stats=this._getValue(this._options.stats,!1),this.suppressErrors=this._getValue(this._options.suppressErrors,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!1),this.unique=this._getValue(this._options.unique,!0),this.onlyDirectories&&(this.onlyFiles=!1),this.stats&&(this.objectMode=!0)}_getValue(e,r){return e===void 0?r:e}_getFileSystemMethods(e={}){return Object.assign(Object.assign({},sE.DEFAULT_FILE_SYSTEM_ADAPTER),e)}};sE.default=KO});var RS=_((DLt,Zie)=>{"use strict";var Jie=Zne(),Xie=eie(),Btt=Yie(),vtt=Wie(),Dtt=zie(),zO=Vie(),Bd=Pf();async function VO(t,e){oE(t);let r=JO(t,Btt.default,e),o=await Promise.all(r);return Bd.array.flatten(o)}(function(t){function e(u,A){oE(u);let p=JO(u,Dtt.default,A);return Bd.array.flatten(p)}t.sync=e;function r(u,A){oE(u);let p=JO(u,vtt.default,A);return Bd.stream.merge(p)}t.stream=r;function o(u,A){oE(u);let p=Xie.transform([].concat(u)),h=new zO.default(A);return Jie.generate(p,h)}t.generateTasks=o;function a(u,A){oE(u);let p=new zO.default(A);return Bd.pattern.isDynamicPattern(u,p)}t.isDynamicPattern=a;function n(u){return oE(u),Bd.path.escape(u)}t.escapePath=n})(VO||(VO={}));function JO(t,e,r){let o=Xie.transform([].concat(t)),a=new zO.default(r),n=Jie.generate(o,a),u=new e(a);return n.map(u.read,u)}function oE(t){if(![].concat(t).every(o=>Bd.string.isString(o)&&!Bd.string.isEmpty(o)))throw new TypeError("Patterns must be a string (non empty) or an array of strings")}Zie.exports=VO});var wn={};zt(wn,{checksumFile:()=>LS,checksumPattern:()=>NS,makeHash:()=>Js});function Js(...t){let e=(0,TS.createHash)("sha512"),r="";for(let o of t)typeof o=="string"?r+=o:o&&(r&&(e.update(r),r=""),e.update(o));return r&&e.update(r),e.digest("hex")}async function LS(t,{baseFs:e,algorithm:r}={baseFs:oe,algorithm:"sha512"}){let o=await e.openPromise(t,"r");try{let n=Buffer.allocUnsafeSlow(65536),u=(0,TS.createHash)(r),A=0;for(;(A=await e.readPromise(o,n,0,65536))!==0;)u.update(A===65536?n:n.slice(0,A));return u.digest("hex")}finally{await e.closePromise(o)}}async function NS(t,{cwd:e}){let o=(await(0,XO.default)(t,{cwd:le.fromPortablePath(e),onlyDirectories:!0})).map(A=>`${A}/**/*`),a=await(0,XO.default)([t,...o],{cwd:le.fromPortablePath(e),onlyFiles:!1});a.sort();let n=await Promise.all(a.map(async A=>{let p=[Buffer.from(A)],h=le.toPortablePath(A),E=await oe.lstatPromise(h);return E.isSymbolicLink()?p.push(Buffer.from(await oe.readlinkPromise(h))):E.isFile()&&p.push(await oe.readFilePromise(h)),p.join("\0")})),u=(0,TS.createHash)("sha512");for(let A of n)u.update(A);return u.digest("hex")}var TS,XO,ih=Et(()=>{Pt();TS=ve("crypto"),XO=$e(RS())});var W={};zt(W,{areDescriptorsEqual:()=>nse,areIdentsEqual:()=>n1,areLocatorsEqual:()=>i1,areVirtualPackagesEquivalent:()=>Ttt,bindDescriptor:()=>Ftt,bindLocator:()=>Rtt,convertDescriptorToLocator:()=>OS,convertLocatorToDescriptor:()=>$O,convertPackageToLocator:()=>xtt,convertToIdent:()=>btt,convertToManifestRange:()=>jtt,copyPackage:()=>e1,devirtualizeDescriptor:()=>t1,devirtualizeLocator:()=>r1,ensureDevirtualizedDescriptor:()=>ktt,ensureDevirtualizedLocator:()=>Qtt,getIdentVendorPath:()=>nM,isPackageCompatible:()=>qS,isVirtualDescriptor:()=>bf,isVirtualLocator:()=>qc,makeDescriptor:()=>In,makeIdent:()=>tA,makeLocator:()=>Qs,makeRange:()=>_S,parseDescriptor:()=>sh,parseFileStyleRange:()=>qtt,parseIdent:()=>Vs,parseLocator:()=>xf,parseRange:()=>vd,prettyDependent:()=>QN,prettyDescriptor:()=>Gn,prettyIdent:()=>cs,prettyLocator:()=>qr,prettyLocatorNoColors:()=>kN,prettyRange:()=>cE,prettyReference:()=>o1,prettyResolution:()=>ZI,prettyWorkspace:()=>a1,renamePackage:()=>eM,slugifyIdent:()=>ZO,slugifyLocator:()=>lE,sortDescriptors:()=>uE,stringifyDescriptor:()=>Sa,stringifyIdent:()=>fn,stringifyLocator:()=>ba,tryParseDescriptor:()=>s1,tryParseIdent:()=>ise,tryParseLocator:()=>US,tryParseRange:()=>Htt,virtualizeDescriptor:()=>tM,virtualizePackage:()=>rM});function tA(t,e){if(t?.startsWith("@"))throw new Error("Invalid scope: don't prefix it with '@'");return{identHash:Js(t,e),scope:t,name:e}}function In(t,e){return{identHash:t.identHash,scope:t.scope,name:t.name,descriptorHash:Js(t.identHash,e),range:e}}function Qs(t,e){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:Js(t.identHash,e),reference:e}}function btt(t){return{identHash:t.identHash,scope:t.scope,name:t.name}}function OS(t){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:t.descriptorHash,reference:t.range}}function $O(t){return{identHash:t.identHash,scope:t.scope,name:t.name,descriptorHash:t.locatorHash,range:t.reference}}function xtt(t){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:t.locatorHash,reference:t.reference}}function eM(t,e){return{identHash:e.identHash,scope:e.scope,name:e.name,locatorHash:e.locatorHash,reference:e.reference,version:t.version,languageName:t.languageName,linkType:t.linkType,conditions:t.conditions,dependencies:new Map(t.dependencies),peerDependencies:new Map(t.peerDependencies),dependenciesMeta:new Map(t.dependenciesMeta),peerDependenciesMeta:new Map(t.peerDependenciesMeta),bin:new Map(t.bin)}}function e1(t){return eM(t,t)}function tM(t,e){if(e.includes("#"))throw new Error("Invalid entropy");return In(t,`virtual:${e}#${t.range}`)}function rM(t,e){if(e.includes("#"))throw new Error("Invalid entropy");return eM(t,Qs(t,`virtual:${e}#${t.reference}`))}function bf(t){return t.range.startsWith($I)}function qc(t){return t.reference.startsWith($I)}function t1(t){if(!bf(t))throw new Error("Not a virtual descriptor");return In(t,t.range.replace(MS,""))}function r1(t){if(!qc(t))throw new Error("Not a virtual descriptor");return Qs(t,t.reference.replace(MS,""))}function ktt(t){return bf(t)?In(t,t.range.replace(MS,"")):t}function Qtt(t){return qc(t)?Qs(t,t.reference.replace(MS,"")):t}function Ftt(t,e){return t.range.includes("::")?t:In(t,`${t.range}::${aE.default.stringify(e)}`)}function Rtt(t,e){return t.reference.includes("::")?t:Qs(t,`${t.reference}::${aE.default.stringify(e)}`)}function n1(t,e){return t.identHash===e.identHash}function nse(t,e){return t.descriptorHash===e.descriptorHash}function i1(t,e){return t.locatorHash===e.locatorHash}function Ttt(t,e){if(!qc(t))throw new Error("Invalid package type");if(!qc(e))throw new Error("Invalid package type");if(!n1(t,e)||t.dependencies.size!==e.dependencies.size)return!1;for(let r of t.dependencies.values()){let o=e.dependencies.get(r.identHash);if(!o||!nse(r,o))return!1}return!0}function Vs(t){let e=ise(t);if(!e)throw new Error(`Invalid ident (${t})`);return e}function ise(t){let e=t.match(Ltt);if(!e)return null;let[,r,o]=e;return tA(typeof r<"u"?r:null,o)}function sh(t,e=!1){let r=s1(t,e);if(!r)throw new Error(`Invalid descriptor (${t})`);return r}function s1(t,e=!1){let r=e?t.match(Ntt):t.match(Ott);if(!r)return null;let[,o,a,n]=r;if(n==="unknown")throw new Error(`Invalid range (${t})`);let u=typeof o<"u"?o:null,A=typeof n<"u"?n:"unknown";return In(tA(u,a),A)}function xf(t,e=!1){let r=US(t,e);if(!r)throw new Error(`Invalid locator (${t})`);return r}function US(t,e=!1){let r=e?t.match(Mtt):t.match(Utt);if(!r)return null;let[,o,a,n]=r;if(n==="unknown")throw new Error(`Invalid reference (${t})`);let u=typeof o<"u"?o:null,A=typeof n<"u"?n:"unknown";return Qs(tA(u,a),A)}function vd(t,e){let r=t.match(_tt);if(r===null)throw new Error(`Invalid range (${t})`);let o=typeof r[1]<"u"?r[1]:null;if(typeof e?.requireProtocol=="string"&&o!==e.requireProtocol)throw new Error(`Invalid protocol (${o})`);if(e?.requireProtocol&&o===null)throw new Error(`Missing protocol (${o})`);let a=typeof r[3]<"u"?decodeURIComponent(r[2]):null;if(e?.requireSource&&a===null)throw new Error(`Missing source (${t})`);let n=typeof r[3]<"u"?decodeURIComponent(r[3]):decodeURIComponent(r[2]),u=e?.parseSelector?aE.default.parse(n):n,A=typeof r[4]<"u"?aE.default.parse(r[4]):null;return{protocol:o,source:a,selector:u,params:A}}function Htt(t,e){try{return vd(t,e)}catch{return null}}function qtt(t,{protocol:e}){let{selector:r,params:o}=vd(t,{requireProtocol:e,requireBindings:!0});if(typeof o.locator!="string")throw new Error(`Assertion failed: Invalid bindings for ${t}`);return{parentLocator:xf(o.locator,!0),path:r}}function $ie(t){return t=t.replaceAll("%","%25"),t=t.replaceAll(":","%3A"),t=t.replaceAll("#","%23"),t}function Gtt(t){return t===null?!1:Object.entries(t).length>0}function _S({protocol:t,source:e,selector:r,params:o}){let a="";return t!==null&&(a+=`${t}`),e!==null&&(a+=`${$ie(e)}#`),a+=$ie(r),Gtt(o)&&(a+=`::${aE.default.stringify(o)}`),a}function jtt(t){let{params:e,protocol:r,source:o,selector:a}=vd(t);for(let n in e)n.startsWith("__")&&delete e[n];return _S({protocol:r,source:o,params:e,selector:a})}function fn(t){return t.scope?`@${t.scope}/${t.name}`:`${t.name}`}function Sa(t){return t.scope?`@${t.scope}/${t.name}@${t.range}`:`${t.name}@${t.range}`}function ba(t){return t.scope?`@${t.scope}/${t.name}@${t.reference}`:`${t.name}@${t.reference}`}function ZO(t){return t.scope!==null?`@${t.scope}-${t.name}`:t.name}function lE(t){let{protocol:e,selector:r}=vd(t.reference),o=e!==null?e.replace(Ytt,""):"exotic",a=ese.default.valid(r),n=a!==null?`${o}-${a}`:`${o}`,u=10;return t.scope?`${ZO(t)}-${n}-${t.locatorHash.slice(0,u)}`:`${ZO(t)}-${n}-${t.locatorHash.slice(0,u)}`}function cs(t,e){return e.scope?`${Ut(t,`@${e.scope}/`,yt.SCOPE)}${Ut(t,e.name,yt.NAME)}`:`${Ut(t,e.name,yt.NAME)}`}function HS(t){if(t.startsWith($I)){let e=HS(t.substring(t.indexOf("#")+1)),r=t.substring($I.length,$I.length+Ptt);return`${e} [${r}]`}else return t.replace(Wtt,"?[...]")}function cE(t,e){return`${Ut(t,HS(e),yt.RANGE)}`}function Gn(t,e){return`${cs(t,e)}${Ut(t,"@",yt.RANGE)}${cE(t,e.range)}`}function o1(t,e){return`${Ut(t,HS(e),yt.REFERENCE)}`}function qr(t,e){return`${cs(t,e)}${Ut(t,"@",yt.REFERENCE)}${o1(t,e.reference)}`}function kN(t){return`${fn(t)}@${HS(t.reference)}`}function uE(t){return ks(t,[e=>fn(e),e=>e.range])}function a1(t,e){return cs(t,e.anchoredLocator)}function ZI(t,e,r){let o=bf(e)?t1(e):e;return r===null?`${Gn(t,o)} \u2192 ${xN(t).Cross}`:o.identHash===r.identHash?`${Gn(t,o)} \u2192 ${o1(t,r.reference)}`:`${Gn(t,o)} \u2192 ${qr(t,r)}`}function QN(t,e,r){return r===null?`${qr(t,e)}`:`${qr(t,e)} (via ${cE(t,r.range)})`}function nM(t){return`node_modules/${fn(t)}`}function qS(t,e){return t.conditions?Stt(t.conditions,r=>{let[,o,a]=r.match(rse),n=e[o];return n?n.includes(a):!0}):!0}var aE,ese,tse,$I,Ptt,rse,Stt,MS,Ltt,Ntt,Ott,Mtt,Utt,_tt,Ytt,Wtt,bo=Et(()=>{aE=$e(ve("querystring")),ese=$e(Jn()),tse=$e(eX());jl();ih();Gl();bo();$I="virtual:",Ptt=5,rse=/(os|cpu|libc)=([a-z0-9_-]+)/,Stt=(0,tse.makeParser)(rse);MS=/^[^#]*#/;Ltt=/^(?:@([^/]+?)\/)?([^@/]+)$/;Ntt=/^(?:@([^/]+?)\/)?([^@/]+?)(?:@(.+))$/,Ott=/^(?:@([^/]+?)\/)?([^@/]+?)(?:@(.+))?$/;Mtt=/^(?:@([^/]+?)\/)?([^@/]+?)(?:@(.+))$/,Utt=/^(?:@([^/]+?)\/)?([^@/]+?)(?:@(.+))?$/;_tt=/^([^#:]*:)?((?:(?!::)[^#])*)(?:#((?:(?!::).)*))?(?:::(.*))?$/;Ytt=/:$/;Wtt=/\?.*/});var sse,ose=Et(()=>{bo();sse={hooks:{reduceDependency:(t,e,r,o,{resolver:a,resolveOptions:n})=>{for(let{pattern:u,reference:A}of e.topLevelWorkspace.manifest.resolutions){if(u.from&&(u.from.fullName!==fn(r)||e.configuration.normalizeLocator(Qs(Vs(u.from.fullName),u.from.description??r.reference)).locatorHash!==r.locatorHash)||u.descriptor.fullName!==fn(t)||e.configuration.normalizeDependency(In(xf(u.descriptor.fullName),u.descriptor.description??t.range)).descriptorHash!==t.descriptorHash)continue;return a.bindDescriptor(e.configuration.normalizeDependency(In(t,A)),e.topLevelWorkspace.anchoredLocator,n)}return t},validateProject:async(t,e)=>{for(let r of t.workspaces){let o=a1(t.configuration,r);await t.configuration.triggerHook(a=>a.validateWorkspace,r,{reportWarning:(a,n)=>e.reportWarning(a,`${o}: ${n}`),reportError:(a,n)=>e.reportError(a,`${o}: ${n}`)})}},validateWorkspace:async(t,e)=>{let{manifest:r}=t;r.resolutions.length&&t.cwd!==t.project.cwd&&r.errors.push(new Error("Resolutions field will be ignored"));for(let o of r.errors)e.reportWarning(57,o.message)}}}});var l1,Xn,Dd=Et(()=>{l1=class{supportsDescriptor(e,r){return!!(e.range.startsWith(l1.protocol)||r.project.tryWorkspaceByDescriptor(e)!==null)}supportsLocator(e,r){return!!e.reference.startsWith(l1.protocol)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){return[o.project.getWorkspaceByDescriptor(e).anchoredLocator]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let o=r.project.getWorkspaceByCwd(e.reference.slice(l1.protocol.length));return{...e,version:o.manifest.version||"0.0.0",languageName:"unknown",linkType:"SOFT",conditions:null,dependencies:r.project.configuration.normalizeDependencyMap(new Map([...o.manifest.dependencies,...o.manifest.devDependencies])),peerDependencies:new Map([...o.manifest.peerDependencies]),dependenciesMeta:o.manifest.dependenciesMeta,peerDependenciesMeta:o.manifest.peerDependenciesMeta,bin:o.manifest.bin}}},Xn=l1;Xn.protocol="workspace:"});var kr={};zt(kr,{SemVer:()=>Ase.SemVer,clean:()=>ztt,getComparator:()=>cse,mergeComparators:()=>iM,satisfiesWithPrereleases:()=>kf,simplifyRanges:()=>sM,stringifyComparator:()=>use,validRange:()=>xa});function kf(t,e,r=!1){if(!t)return!1;let o=`${e}${r}`,a=ase.get(o);if(typeof a>"u")try{a=new oh.default.Range(e,{includePrerelease:!0,loose:r})}catch{return!1}finally{ase.set(o,a||null)}else if(a===null)return!1;let n;try{n=new oh.default.SemVer(t,a)}catch{return!1}return a.test(n)?!0:(n.prerelease&&(n.prerelease=[]),a.set.some(u=>{for(let A of u)A.semver.prerelease&&(A.semver.prerelease=[]);return u.every(A=>A.test(n))}))}function xa(t){if(t.indexOf(":")!==-1)return null;let e=lse.get(t);if(typeof e<"u")return e;try{e=new oh.default.Range(t)}catch{e=null}return lse.set(t,e),e}function ztt(t){let e=Ktt.exec(t);return e?e[1]:null}function cse(t){if(t.semver===oh.default.Comparator.ANY)return{gt:null,lt:null};switch(t.operator){case"":return{gt:[">=",t.semver],lt:["<=",t.semver]};case">":case">=":return{gt:[t.operator,t.semver],lt:null};case"<":case"<=":return{gt:null,lt:[t.operator,t.semver]};default:throw new Error(`Assertion failed: Unexpected comparator operator (${t.operator})`)}}function iM(t){if(t.length===0)return null;let e=null,r=null;for(let o of t){if(o.gt){let a=e!==null?oh.default.compare(o.gt[1],e[1]):null;(a===null||a>0||a===0&&o.gt[0]===">")&&(e=o.gt)}if(o.lt){let a=r!==null?oh.default.compare(o.lt[1],r[1]):null;(a===null||a<0||a===0&&o.lt[0]==="<")&&(r=o.lt)}}if(e&&r){let o=oh.default.compare(e[1],r[1]);if(o===0&&(e[0]===">"||r[0]==="<")||o>0)return null}return{gt:e,lt:r}}function use(t){if(t.gt&&t.lt){if(t.gt[0]===">="&&t.lt[0]==="<="&&t.gt[1].version===t.lt[1].version)return t.gt[1].version;if(t.gt[0]===">="&&t.lt[0]==="<"){if(t.lt[1].version===`${t.gt[1].major+1}.0.0-0`)return`^${t.gt[1].version}`;if(t.lt[1].version===`${t.gt[1].major}.${t.gt[1].minor+1}.0-0`)return`~${t.gt[1].version}`}}let e=[];return t.gt&&e.push(t.gt[0]+t.gt[1].version),t.lt&&e.push(t.lt[0]+t.lt[1].version),e.length?e.join(" "):"*"}function sM(t){let e=t.map(o=>xa(o).set.map(a=>a.map(n=>cse(n)))),r=e.shift().map(o=>iM(o)).filter(o=>o!==null);for(let o of e){let a=[];for(let n of r)for(let u of o){let A=iM([n,...u]);A!==null&&a.push(A)}r=a}return r.length===0?null:r.map(o=>use(o)).join(" || ")}var oh,Ase,ase,lse,Ktt,Qf=Et(()=>{oh=$e(Jn()),Ase=$e(Jn()),ase=new Map;lse=new Map;Ktt=/^(?:[\sv=]*?)((0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)(?:\s*)$/});function fse(t){let e=t.match(/^[ \t]+/m);return e?e[0]:" "}function pse(t){return t.charCodeAt(0)===65279?t.slice(1):t}function $o(t){return t.replace(/\\/g,"/")}function GS(t,{yamlCompatibilityMode:e}){return e?wN(t):typeof t>"u"||typeof t=="boolean"?t:null}function hse(t,e){let r=e.search(/[^!]/);if(r===-1)return"invalid";let o=r%2===0?"":"!",a=e.slice(r);return`${o}${t}=${a}`}function oM(t,e){return e.length===1?hse(t,e[0]):`(${e.map(r=>hse(t,r)).join(" | ")})`}var gse,AE,Ot,fE=Et(()=>{Pt();Nl();gse=$e(Jn());Dd();Gl();Qf();bo();AE=class{constructor(){this.indent=" ";this.name=null;this.version=null;this.os=null;this.cpu=null;this.libc=null;this.type=null;this.packageManager=null;this.private=!1;this.license=null;this.main=null;this.module=null;this.browser=null;this.languageName=null;this.bin=new Map;this.scripts=new Map;this.dependencies=new Map;this.devDependencies=new Map;this.peerDependencies=new Map;this.workspaceDefinitions=[];this.dependenciesMeta=new Map;this.peerDependenciesMeta=new Map;this.resolutions=[];this.files=null;this.publishConfig=null;this.installConfig=null;this.preferUnplugged=null;this.raw={};this.errors=[]}static async tryFind(e,{baseFs:r=new Tn}={}){let o=z.join(e,"package.json");try{return await AE.fromFile(o,{baseFs:r})}catch(a){if(a.code==="ENOENT")return null;throw a}}static async find(e,{baseFs:r}={}){let o=await AE.tryFind(e,{baseFs:r});if(o===null)throw new Error("Manifest not found");return o}static async fromFile(e,{baseFs:r=new Tn}={}){let o=new AE;return await o.loadFile(e,{baseFs:r}),o}static fromText(e){let r=new AE;return r.loadFromText(e),r}loadFromText(e){let r;try{r=JSON.parse(pse(e)||"{}")}catch(o){throw o.message+=` (when parsing ${e})`,o}this.load(r),this.indent=fse(e)}async loadFile(e,{baseFs:r=new Tn}){let o=await r.readFilePromise(e,"utf8"),a;try{a=JSON.parse(pse(o)||"{}")}catch(n){throw n.message+=` (when parsing ${e})`,n}this.load(a),this.indent=fse(o)}load(e,{yamlCompatibilityMode:r=!1}={}){if(typeof e!="object"||e===null)throw new Error(`Utterly invalid manifest data (${e})`);this.raw=e;let o=[];if(this.name=null,typeof e.name=="string")try{this.name=Vs(e.name)}catch{o.push(new Error("Parsing failed for the 'name' field"))}if(typeof e.version=="string"?this.version=e.version:this.version=null,Array.isArray(e.os)){let n=[];this.os=n;for(let u of e.os)typeof u!="string"?o.push(new Error("Parsing failed for the 'os' field")):n.push(u)}else this.os=null;if(Array.isArray(e.cpu)){let n=[];this.cpu=n;for(let u of e.cpu)typeof u!="string"?o.push(new Error("Parsing failed for the 'cpu' field")):n.push(u)}else this.cpu=null;if(Array.isArray(e.libc)){let n=[];this.libc=n;for(let u of e.libc)typeof u!="string"?o.push(new Error("Parsing failed for the 'libc' field")):n.push(u)}else this.libc=null;if(typeof e.type=="string"?this.type=e.type:this.type=null,typeof e.packageManager=="string"?this.packageManager=e.packageManager:this.packageManager=null,typeof e.private=="boolean"?this.private=e.private:this.private=!1,typeof e.license=="string"?this.license=e.license:this.license=null,typeof e.languageName=="string"?this.languageName=e.languageName:this.languageName=null,typeof e.main=="string"?this.main=$o(e.main):this.main=null,typeof e.module=="string"?this.module=$o(e.module):this.module=null,e.browser!=null)if(typeof e.browser=="string")this.browser=$o(e.browser);else{this.browser=new Map;for(let[n,u]of Object.entries(e.browser))this.browser.set($o(n),typeof u=="string"?$o(u):u)}else this.browser=null;if(this.bin=new Map,typeof e.bin=="string")e.bin.trim()===""?o.push(new Error("Invalid bin field")):this.name!==null?this.bin.set(this.name.name,$o(e.bin)):o.push(new Error("String bin field, but no attached package name"));else if(typeof e.bin=="object"&&e.bin!==null)for(let[n,u]of Object.entries(e.bin)){if(typeof u!="string"||u.trim()===""){o.push(new Error(`Invalid bin definition for '${n}'`));continue}let A=Vs(n);this.bin.set(A.name,$o(u))}if(this.scripts=new Map,typeof e.scripts=="object"&&e.scripts!==null)for(let[n,u]of Object.entries(e.scripts)){if(typeof u!="string"){o.push(new Error(`Invalid script definition for '${n}'`));continue}this.scripts.set(n,u)}if(this.dependencies=new Map,typeof e.dependencies=="object"&&e.dependencies!==null)for(let[n,u]of Object.entries(e.dependencies)){if(typeof u!="string"){o.push(new Error(`Invalid dependency range for '${n}'`));continue}let A;try{A=Vs(n)}catch{o.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=In(A,u);this.dependencies.set(p.identHash,p)}if(this.devDependencies=new Map,typeof e.devDependencies=="object"&&e.devDependencies!==null)for(let[n,u]of Object.entries(e.devDependencies)){if(typeof u!="string"){o.push(new Error(`Invalid dependency range for '${n}'`));continue}let A;try{A=Vs(n)}catch{o.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=In(A,u);this.devDependencies.set(p.identHash,p)}if(this.peerDependencies=new Map,typeof e.peerDependencies=="object"&&e.peerDependencies!==null)for(let[n,u]of Object.entries(e.peerDependencies)){let A;try{A=Vs(n)}catch{o.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}(typeof u!="string"||!u.startsWith(Xn.protocol)&&!xa(u))&&(o.push(new Error(`Invalid dependency range for '${n}'`)),u="*");let p=In(A,u);this.peerDependencies.set(p.identHash,p)}typeof e.workspaces=="object"&&e.workspaces!==null&&e.workspaces.nohoist&&o.push(new Error("'nohoist' is deprecated, please use 'installConfig.hoistingLimits' instead"));let a=Array.isArray(e.workspaces)?e.workspaces:typeof e.workspaces=="object"&&e.workspaces!==null&&Array.isArray(e.workspaces.packages)?e.workspaces.packages:[];this.workspaceDefinitions=[];for(let n of a){if(typeof n!="string"){o.push(new Error(`Invalid workspace definition for '${n}'`));continue}this.workspaceDefinitions.push({pattern:n})}if(this.dependenciesMeta=new Map,typeof e.dependenciesMeta=="object"&&e.dependenciesMeta!==null)for(let[n,u]of Object.entries(e.dependenciesMeta)){if(typeof u!="object"||u===null){o.push(new Error(`Invalid meta field for '${n}`));continue}let A=sh(n),p=this.ensureDependencyMeta(A),h=GS(u.built,{yamlCompatibilityMode:r});if(h===null){o.push(new Error(`Invalid built meta field for '${n}'`));continue}let E=GS(u.optional,{yamlCompatibilityMode:r});if(E===null){o.push(new Error(`Invalid optional meta field for '${n}'`));continue}let I=GS(u.unplugged,{yamlCompatibilityMode:r});if(I===null){o.push(new Error(`Invalid unplugged meta field for '${n}'`));continue}Object.assign(p,{built:h,optional:E,unplugged:I})}if(this.peerDependenciesMeta=new Map,typeof e.peerDependenciesMeta=="object"&&e.peerDependenciesMeta!==null)for(let[n,u]of Object.entries(e.peerDependenciesMeta)){if(typeof u!="object"||u===null){o.push(new Error(`Invalid meta field for '${n}'`));continue}let A=sh(n),p=this.ensurePeerDependencyMeta(A),h=GS(u.optional,{yamlCompatibilityMode:r});if(h===null){o.push(new Error(`Invalid optional meta field for '${n}'`));continue}Object.assign(p,{optional:h})}if(this.resolutions=[],typeof e.resolutions=="object"&&e.resolutions!==null)for(let[n,u]of Object.entries(e.resolutions)){if(typeof u!="string"){o.push(new Error(`Invalid resolution entry for '${n}'`));continue}try{this.resolutions.push({pattern:MD(n),reference:u})}catch(A){o.push(A);continue}}if(Array.isArray(e.files)){this.files=new Set;for(let n of e.files){if(typeof n!="string"){o.push(new Error(`Invalid files entry for '${n}'`));continue}this.files.add(n)}}else this.files=null;if(typeof e.publishConfig=="object"&&e.publishConfig!==null){if(this.publishConfig={},typeof e.publishConfig.access=="string"&&(this.publishConfig.access=e.publishConfig.access),typeof e.publishConfig.main=="string"&&(this.publishConfig.main=$o(e.publishConfig.main)),typeof e.publishConfig.module=="string"&&(this.publishConfig.module=$o(e.publishConfig.module)),e.publishConfig.browser!=null)if(typeof e.publishConfig.browser=="string")this.publishConfig.browser=$o(e.publishConfig.browser);else{this.publishConfig.browser=new Map;for(let[n,u]of Object.entries(e.publishConfig.browser))this.publishConfig.browser.set($o(n),typeof u=="string"?$o(u):u)}if(typeof e.publishConfig.registry=="string"&&(this.publishConfig.registry=e.publishConfig.registry),typeof e.publishConfig.bin=="string")this.name!==null?this.publishConfig.bin=new Map([[this.name.name,$o(e.publishConfig.bin)]]):o.push(new Error("String bin field, but no attached package name"));else if(typeof e.publishConfig.bin=="object"&&e.publishConfig.bin!==null){this.publishConfig.bin=new Map;for(let[n,u]of Object.entries(e.publishConfig.bin)){if(typeof u!="string"){o.push(new Error(`Invalid bin definition for '${n}'`));continue}this.publishConfig.bin.set(n,$o(u))}}if(Array.isArray(e.publishConfig.executableFiles)){this.publishConfig.executableFiles=new Set;for(let n of e.publishConfig.executableFiles){if(typeof n!="string"){o.push(new Error("Invalid executable file definition"));continue}this.publishConfig.executableFiles.add($o(n))}}}else this.publishConfig=null;if(typeof e.installConfig=="object"&&e.installConfig!==null){this.installConfig={};for(let n of Object.keys(e.installConfig))n==="hoistingLimits"?typeof e.installConfig.hoistingLimits=="string"?this.installConfig.hoistingLimits=e.installConfig.hoistingLimits:o.push(new Error("Invalid hoisting limits definition")):n=="selfReferences"?typeof e.installConfig.selfReferences=="boolean"?this.installConfig.selfReferences=e.installConfig.selfReferences:o.push(new Error("Invalid selfReferences definition, must be a boolean value")):o.push(new Error(`Unrecognized installConfig key: ${n}`))}else this.installConfig=null;if(typeof e.optionalDependencies=="object"&&e.optionalDependencies!==null)for(let[n,u]of Object.entries(e.optionalDependencies)){if(typeof u!="string"){o.push(new Error(`Invalid dependency range for '${n}'`));continue}let A;try{A=Vs(n)}catch{o.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=In(A,u);this.dependencies.set(p.identHash,p);let h=In(A,"unknown"),E=this.ensureDependencyMeta(h);Object.assign(E,{optional:!0})}typeof e.preferUnplugged=="boolean"?this.preferUnplugged=e.preferUnplugged:this.preferUnplugged=null,this.errors=o}getForScope(e){switch(e){case"dependencies":return this.dependencies;case"devDependencies":return this.devDependencies;case"peerDependencies":return this.peerDependencies;default:throw new Error(`Unsupported value ("${e}")`)}}hasConsumerDependency(e){return!!(this.dependencies.has(e.identHash)||this.peerDependencies.has(e.identHash))}hasHardDependency(e){return!!(this.dependencies.has(e.identHash)||this.devDependencies.has(e.identHash))}hasSoftDependency(e){return!!this.peerDependencies.has(e.identHash)}hasDependency(e){return!!(this.hasHardDependency(e)||this.hasSoftDependency(e))}getConditions(){let e=[];return this.os&&this.os.length>0&&e.push(oM("os",this.os)),this.cpu&&this.cpu.length>0&&e.push(oM("cpu",this.cpu)),this.libc&&this.libc.length>0&&e.push(oM("libc",this.libc)),e.length>0?e.join(" & "):null}ensureDependencyMeta(e){if(e.range!=="unknown"&&!gse.default.valid(e.range))throw new Error(`Invalid meta field range for '${Sa(e)}'`);let r=fn(e),o=e.range!=="unknown"?e.range:null,a=this.dependenciesMeta.get(r);a||this.dependenciesMeta.set(r,a=new Map);let n=a.get(o);return n||a.set(o,n={}),n}ensurePeerDependencyMeta(e){if(e.range!=="unknown")throw new Error(`Invalid meta field range for '${Sa(e)}'`);let r=fn(e),o=this.peerDependenciesMeta.get(r);return o||this.peerDependenciesMeta.set(r,o={}),o}setRawField(e,r,{after:o=[]}={}){let a=new Set(o.filter(n=>Object.hasOwn(this.raw,n)));if(a.size===0||Object.hasOwn(this.raw,e))this.raw[e]=r;else{let n=this.raw,u=this.raw={},A=!1;for(let p of Object.keys(n))u[p]=n[p],A||(a.delete(p),a.size===0&&(u[e]=r,A=!0))}}exportTo(e,{compatibilityMode:r=!0}={}){if(Object.assign(e,this.raw),this.name!==null?e.name=fn(this.name):delete e.name,this.version!==null?e.version=this.version:delete e.version,this.os!==null?e.os=this.os:delete e.os,this.cpu!==null?e.cpu=this.cpu:delete e.cpu,this.type!==null?e.type=this.type:delete e.type,this.packageManager!==null?e.packageManager=this.packageManager:delete e.packageManager,this.private?e.private=!0:delete e.private,this.license!==null?e.license=this.license:delete e.license,this.languageName!==null?e.languageName=this.languageName:delete e.languageName,this.main!==null?e.main=this.main:delete e.main,this.module!==null?e.module=this.module:delete e.module,this.browser!==null){let n=this.browser;typeof n=="string"?e.browser=n:n instanceof Map&&(e.browser=Object.assign({},...Array.from(n.keys()).sort().map(u=>({[u]:n.get(u)}))))}else delete e.browser;this.bin.size===1&&this.name!==null&&this.bin.has(this.name.name)?e.bin=this.bin.get(this.name.name):this.bin.size>0?e.bin=Object.assign({},...Array.from(this.bin.keys()).sort().map(n=>({[n]:this.bin.get(n)}))):delete e.bin,this.workspaceDefinitions.length>0?this.raw.workspaces&&!Array.isArray(this.raw.workspaces)?e.workspaces={...this.raw.workspaces,packages:this.workspaceDefinitions.map(({pattern:n})=>n)}:e.workspaces=this.workspaceDefinitions.map(({pattern:n})=>n):this.raw.workspaces&&!Array.isArray(this.raw.workspaces)&&Object.keys(this.raw.workspaces).length>0?e.workspaces=this.raw.workspaces:delete e.workspaces;let o=[],a=[];for(let n of this.dependencies.values()){let u=this.dependenciesMeta.get(fn(n)),A=!1;if(r&&u){let p=u.get(null);p&&p.optional&&(A=!0)}A?a.push(n):o.push(n)}o.length>0?e.dependencies=Object.assign({},...uE(o).map(n=>({[fn(n)]:n.range}))):delete e.dependencies,a.length>0?e.optionalDependencies=Object.assign({},...uE(a).map(n=>({[fn(n)]:n.range}))):delete e.optionalDependencies,this.devDependencies.size>0?e.devDependencies=Object.assign({},...uE(this.devDependencies.values()).map(n=>({[fn(n)]:n.range}))):delete e.devDependencies,this.peerDependencies.size>0?e.peerDependencies=Object.assign({},...uE(this.peerDependencies.values()).map(n=>({[fn(n)]:n.range}))):delete e.peerDependencies,e.dependenciesMeta={};for(let[n,u]of ks(this.dependenciesMeta.entries(),([A,p])=>A))for(let[A,p]of ks(u.entries(),([h,E])=>h!==null?`0${h}`:"1")){let h=A!==null?Sa(In(Vs(n),A)):n,E={...p};r&&A===null&&delete E.optional,Object.keys(E).length!==0&&(e.dependenciesMeta[h]=E)}if(Object.keys(e.dependenciesMeta).length===0&&delete e.dependenciesMeta,this.peerDependenciesMeta.size>0?e.peerDependenciesMeta=Object.assign({},...ks(this.peerDependenciesMeta.entries(),([n,u])=>n).map(([n,u])=>({[n]:u}))):delete e.peerDependenciesMeta,this.resolutions.length>0?e.resolutions=Object.assign({},...this.resolutions.map(({pattern:n,reference:u})=>({[UD(n)]:u}))):delete e.resolutions,this.files!==null?e.files=Array.from(this.files):delete e.files,this.preferUnplugged!==null?e.preferUnplugged=this.preferUnplugged:delete e.preferUnplugged,this.scripts!==null&&this.scripts.size>0){e.scripts??={};for(let n of Object.keys(e.scripts))this.scripts.has(n)||delete e.scripts[n];for(let[n,u]of this.scripts.entries())e.scripts[n]=u}else delete e.scripts;return e}},Ot=AE;Ot.fileName="package.json",Ot.allDependencies=["dependencies","devDependencies","peerDependencies"],Ot.hardDependencies=["dependencies","devDependencies"]});var mse=_((_Lt,dse)=>{var Vtt=Hl(),Jtt=function(){return Vtt.Date.now()};dse.exports=Jtt});var Ese=_((HLt,yse)=>{var Xtt=/\s/;function Ztt(t){for(var e=t.length;e--&&Xtt.test(t.charAt(e)););return e}yse.exports=Ztt});var wse=_((qLt,Cse)=>{var $tt=Ese(),ert=/^\s+/;function trt(t){return t&&t.slice(0,$tt(t)+1).replace(ert,"")}Cse.exports=trt});var pE=_((GLt,Ise)=>{var rrt=gd(),nrt=Ju(),irt="[object Symbol]";function srt(t){return typeof t=="symbol"||nrt(t)&&rrt(t)==irt}Ise.exports=srt});var Pse=_((jLt,Dse)=>{var ort=wse(),Bse=sl(),art=pE(),vse=0/0,lrt=/^[-+]0x[0-9a-f]+$/i,crt=/^0b[01]+$/i,urt=/^0o[0-7]+$/i,Art=parseInt;function frt(t){if(typeof t=="number")return t;if(art(t))return vse;if(Bse(t)){var e=typeof t.valueOf=="function"?t.valueOf():t;t=Bse(e)?e+"":e}if(typeof t!="string")return t===0?t:+t;t=ort(t);var r=crt.test(t);return r||urt.test(t)?Art(t.slice(2),r?2:8):lrt.test(t)?vse:+t}Dse.exports=frt});var xse=_((YLt,bse)=>{var prt=sl(),aM=mse(),Sse=Pse(),hrt="Expected a function",grt=Math.max,drt=Math.min;function mrt(t,e,r){var o,a,n,u,A,p,h=0,E=!1,I=!1,v=!0;if(typeof t!="function")throw new TypeError(hrt);e=Sse(e)||0,prt(r)&&(E=!!r.leading,I="maxWait"in r,n=I?grt(Sse(r.maxWait)||0,e):n,v="trailing"in r?!!r.trailing:v);function x(ue){var me=o,he=a;return o=a=void 0,h=ue,u=t.apply(he,me),u}function C(ue){return h=ue,A=setTimeout(U,e),E?x(ue):u}function R(ue){var me=ue-p,he=ue-h,Be=e-me;return I?drt(Be,n-he):Be}function N(ue){var me=ue-p,he=ue-h;return p===void 0||me>=e||me<0||I&&he>=n}function U(){var ue=aM();if(N(ue))return V(ue);A=setTimeout(U,R(ue))}function V(ue){return A=void 0,v&&o?x(ue):(o=a=void 0,u)}function te(){A!==void 0&&clearTimeout(A),h=0,o=p=a=A=void 0}function ae(){return A===void 0?u:V(aM())}function fe(){var ue=aM(),me=N(ue);if(o=arguments,a=this,p=ue,me){if(A===void 0)return C(p);if(I)return clearTimeout(A),A=setTimeout(U,e),x(p)}return A===void 0&&(A=setTimeout(U,e)),u}return fe.cancel=te,fe.flush=ae,fe}bse.exports=mrt});var lM=_((WLt,kse)=>{var yrt=xse(),Ert=sl(),Crt="Expected a function";function wrt(t,e,r){var o=!0,a=!0;if(typeof t!="function")throw new TypeError(Crt);return Ert(r)&&(o="leading"in r?!!r.leading:o,a="trailing"in r?!!r.trailing:a),yrt(t,e,{leading:o,maxWait:e,trailing:a})}kse.exports=wrt});function Brt(t){return typeof t.reportCode<"u"}var Qse,Fse,Rse,Irt,Jt,Xs,Wl=Et(()=>{Qse=$e(lM()),Fse=ve("stream"),Rse=ve("string_decoder"),Irt=15,Jt=class extends Error{constructor(r,o,a){super(o);this.reportExtra=a;this.reportCode=r}};Xs=class{constructor(){this.cacheHits=new Set;this.cacheMisses=new Set;this.reportedInfos=new Set;this.reportedWarnings=new Set;this.reportedErrors=new Set}getRecommendedLength(){return 180}reportCacheHit(e){this.cacheHits.add(e.locatorHash)}reportCacheMiss(e,r){this.cacheMisses.add(e.locatorHash)}static progressViaCounter(e){let r=0,o,a=new Promise(p=>{o=p}),n=p=>{let h=o;a=new Promise(E=>{o=E}),r=p,h()},u=(p=0)=>{n(r+1)},A=async function*(){for(;r<e;)await a,yield{progress:r/e}}();return{[Symbol.asyncIterator](){return A},hasProgress:!0,hasTitle:!1,set:n,tick:u}}static progressViaTitle(){let e,r,o=new Promise(u=>{r=u}),a=(0,Qse.default)(u=>{let A=r;o=new Promise(p=>{r=p}),e=u,A()},1e3/Irt),n=async function*(){for(;;)await o,yield{title:e}}();return{[Symbol.asyncIterator](){return n},hasProgress:!1,hasTitle:!0,setTitle:a}}async startProgressPromise(e,r){let o=this.reportProgress(e);try{return await r(e)}finally{o.stop()}}startProgressSync(e,r){let o=this.reportProgress(e);try{return r(e)}finally{o.stop()}}reportInfoOnce(e,r,o){let a=o&&o.key?o.key:r;this.reportedInfos.has(a)||(this.reportedInfos.add(a),this.reportInfo(e,r),o?.reportExtra?.(this))}reportWarningOnce(e,r,o){let a=o&&o.key?o.key:r;this.reportedWarnings.has(a)||(this.reportedWarnings.add(a),this.reportWarning(e,r),o?.reportExtra?.(this))}reportErrorOnce(e,r,o){let a=o&&o.key?o.key:r;this.reportedErrors.has(a)||(this.reportedErrors.add(a),this.reportError(e,r),o?.reportExtra?.(this))}reportExceptionOnce(e){Brt(e)?this.reportErrorOnce(e.reportCode,e.message,{key:e,reportExtra:e.reportExtra}):this.reportErrorOnce(1,e.stack||e.message,{key:e})}createStreamReporter(e=null){let r=new Fse.PassThrough,o=new Rse.StringDecoder,a="";return r.on("data",n=>{let u=o.write(n),A;do if(A=u.indexOf(`
-`),A!==-1){let p=a+u.substring(0,A);u=u.substring(A+1),a="",e!==null?this.reportInfo(null,`${e} ${p}`):this.reportInfo(null,p)}while(A!==-1);a+=u}),r.on("end",()=>{let n=o.end();n!==""&&(e!==null?this.reportInfo(null,`${e} ${n}`):this.reportInfo(null,n))}),r}}});var hE,cM=Et(()=>{Wl();bo();hE=class{constructor(e){this.fetchers=e}supports(e,r){return!!this.tryFetcher(e,r)}getLocalPath(e,r){return this.getFetcher(e,r).getLocalPath(e,r)}async fetch(e,r){return await this.getFetcher(e,r).fetch(e,r)}tryFetcher(e,r){let o=this.fetchers.find(a=>a.supports(e,r));return o||null}getFetcher(e,r){let o=this.fetchers.find(a=>a.supports(e,r));if(!o)throw new Jt(11,`${qr(r.project.configuration,e)} isn't supported by any available fetcher`);return o}}});var Pd,uM=Et(()=>{bo();Pd=class{constructor(e){this.resolvers=e.filter(r=>r)}supportsDescriptor(e,r){return!!this.tryResolverByDescriptor(e,r)}supportsLocator(e,r){return!!this.tryResolverByLocator(e,r)}shouldPersistResolution(e,r){return this.getResolverByLocator(e,r).shouldPersistResolution(e,r)}bindDescriptor(e,r,o){return this.getResolverByDescriptor(e,o).bindDescriptor(e,r,o)}getResolutionDependencies(e,r){return this.getResolverByDescriptor(e,r).getResolutionDependencies(e,r)}async getCandidates(e,r,o){return await this.getResolverByDescriptor(e,o).getCandidates(e,r,o)}async getSatisfying(e,r,o,a){return this.getResolverByDescriptor(e,a).getSatisfying(e,r,o,a)}async resolve(e,r){return await this.getResolverByLocator(e,r).resolve(e,r)}tryResolverByDescriptor(e,r){let o=this.resolvers.find(a=>a.supportsDescriptor(e,r));return o||null}getResolverByDescriptor(e,r){let o=this.resolvers.find(a=>a.supportsDescriptor(e,r));if(!o)throw new Error(`${Gn(r.project.configuration,e)} isn't supported by any available resolver`);return o}tryResolverByLocator(e,r){let o=this.resolvers.find(a=>a.supportsLocator(e,r));return o||null}getResolverByLocator(e,r){let o=this.resolvers.find(a=>a.supportsLocator(e,r));if(!o)throw new Error(`${qr(r.project.configuration,e)} isn't supported by any available resolver`);return o}}});var gE,AM=Et(()=>{Pt();bo();gE=class{supports(e){return!!e.reference.startsWith("virtual:")}getLocalPath(e,r){let o=e.reference.indexOf("#");if(o===-1)throw new Error("Invalid virtual package reference");let a=e.reference.slice(o+1),n=Qs(e,a);return r.fetcher.getLocalPath(n,r)}async fetch(e,r){let o=e.reference.indexOf("#");if(o===-1)throw new Error("Invalid virtual package reference");let a=e.reference.slice(o+1),n=Qs(e,a),u=await r.fetcher.fetch(n,r);return await this.ensureVirtualLink(e,u,r)}getLocatorFilename(e){return lE(e)}async ensureVirtualLink(e,r,o){let a=r.packageFs.getRealPath(),n=o.project.configuration.get("virtualFolder"),u=this.getLocatorFilename(e),A=mi.makeVirtualPath(n,u,a),p=new _u(A,{baseFs:r.packageFs,pathUtils:z});return{...r,packageFs:p}}}});var dE,c1,Tse=Et(()=>{dE=class{static isVirtualDescriptor(e){return!!e.range.startsWith(dE.protocol)}static isVirtualLocator(e){return!!e.reference.startsWith(dE.protocol)}supportsDescriptor(e,r){return dE.isVirtualDescriptor(e)}supportsLocator(e,r){return dE.isVirtualLocator(e)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){throw new Error('Assertion failed: calling "bindDescriptor" on a virtual descriptor is unsupported')}getResolutionDependencies(e,r){throw new Error('Assertion failed: calling "getResolutionDependencies" on a virtual descriptor is unsupported')}async getCandidates(e,r,o){throw new Error('Assertion failed: calling "getCandidates" on a virtual descriptor is unsupported')}async getSatisfying(e,r,o,a){throw new Error('Assertion failed: calling "getSatisfying" on a virtual descriptor is unsupported')}async resolve(e,r){throw new Error('Assertion failed: calling "resolve" on a virtual locator is unsupported')}},c1=dE;c1.protocol="virtual:"});var mE,fM=Et(()=>{Pt();Dd();mE=class{supports(e){return!!e.reference.startsWith(Xn.protocol)}getLocalPath(e,r){return this.getWorkspace(e,r).cwd}async fetch(e,r){let o=this.getWorkspace(e,r).cwd;return{packageFs:new gn(o),prefixPath:Bt.dot,localPath:o}}getWorkspace(e,r){return r.project.getWorkspaceByCwd(e.reference.slice(Xn.protocol.length))}}});function u1(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function Lse(t){return typeof t>"u"?3:u1(t)?0:Array.isArray(t)?1:2}function gM(t,e){return Object.hasOwn(t,e)}function Drt(t){return u1(t)&&gM(t,"onConflict")&&typeof t.onConflict=="string"}function Prt(t){if(typeof t>"u")return{onConflict:"default",value:t};if(!Drt(t))return{onConflict:"default",value:t};if(gM(t,"value"))return t;let{onConflict:e,...r}=t;return{onConflict:e,value:r}}function Nse(t,e){let r=u1(t)&&gM(t,e)?t[e]:void 0;return Prt(r)}function yE(t,e){return[t,e,Ose]}function dM(t){return Array.isArray(t)?t[2]===Ose:!1}function pM(t,e){if(u1(t)){let r={};for(let o of Object.keys(t))r[o]=pM(t[o],e);return yE(e,r)}return Array.isArray(t)?yE(e,t.map(r=>pM(r,e))):yE(e,t)}function hM(t,e,r,o,a){let n,u=[],A=a,p=0;for(let E=a-1;E>=o;--E){let[I,v]=t[E],{onConflict:x,value:C}=Nse(v,r),R=Lse(C);if(R!==3){if(n??=R,R!==n||x==="hardReset"){p=A;break}if(R===2)return yE(I,C);if(u.unshift([I,C]),x==="reset"){p=E;break}x==="extend"&&E===o&&(o=0),A=E}}if(typeof n>"u")return null;let h=u.map(([E])=>E).join(", ");switch(n){case 1:return yE(h,new Array().concat(...u.map(([E,I])=>I.map(v=>pM(v,E)))));case 0:{let E=Object.assign({},...u.map(([,R])=>R)),I=Object.keys(E),v={},x=t.map(([R,N])=>[R,Nse(N,r).value]),C=vrt(x,([R,N])=>{let U=Lse(N);return U!==0&&U!==3});if(C!==-1){let R=x.slice(C+1);for(let N of I)v[N]=hM(R,e,N,0,R.length)}else for(let R of I)v[R]=hM(x,e,R,p,x.length);return yE(h,v)}default:throw new Error("Assertion failed: Non-extendable value type")}}function Mse(t){return hM(t.map(([e,r])=>[e,{["."]:r}]),[],".",0,t.length)}function A1(t){return dM(t)?t[1]:t}function jS(t){let e=dM(t)?t[1]:t;if(Array.isArray(e))return e.map(r=>jS(r));if(u1(e)){let r={};for(let[o,a]of Object.entries(e))r[o]=jS(a);return r}return e}function mM(t){return dM(t)?t[0]:null}var vrt,Ose,Use=Et(()=>{vrt=(t,e,r)=>{let o=[...t];return o.reverse(),o.findIndex(e,r)};Ose=Symbol()});var YS={};zt(YS,{getDefaultGlobalFolder:()=>EM,getHomeFolder:()=>EE,isFolderInside:()=>CM});function EM(){if(process.platform==="win32"){let t=le.toPortablePath(process.env.LOCALAPPDATA||le.join((0,yM.homedir)(),"AppData","Local"));return z.resolve(t,"Yarn/Berry")}if(process.env.XDG_DATA_HOME){let t=le.toPortablePath(process.env.XDG_DATA_HOME);return z.resolve(t,"yarn/berry")}return z.resolve(EE(),".yarn/berry")}function EE(){return le.toPortablePath((0,yM.homedir)()||"/usr/local/share")}function CM(t,e){let r=z.relative(e,t);return r&&!r.startsWith("..")&&!z.isAbsolute(r)}var yM,WS=Et(()=>{Pt();yM=ve("os")});var Gse=_(CE=>{"use strict";var sNt=ve("net"),brt=ve("tls"),wM=ve("http"),_se=ve("https"),xrt=ve("events"),oNt=ve("assert"),krt=ve("util");CE.httpOverHttp=Qrt;CE.httpsOverHttp=Frt;CE.httpOverHttps=Rrt;CE.httpsOverHttps=Trt;function Qrt(t){var e=new Ff(t);return e.request=wM.request,e}function Frt(t){var e=new Ff(t);return e.request=wM.request,e.createSocket=Hse,e.defaultPort=443,e}function Rrt(t){var e=new Ff(t);return e.request=_se.request,e}function Trt(t){var e=new Ff(t);return e.request=_se.request,e.createSocket=Hse,e.defaultPort=443,e}function Ff(t){var e=this;e.options=t||{},e.proxyOptions=e.options.proxy||{},e.maxSockets=e.options.maxSockets||wM.Agent.defaultMaxSockets,e.requests=[],e.sockets=[],e.on("free",function(o,a,n,u){for(var A=qse(a,n,u),p=0,h=e.requests.length;p<h;++p){var E=e.requests[p];if(E.host===A.host&&E.port===A.port){e.requests.splice(p,1),E.request.onSocket(o);return}}o.destroy(),e.removeSocket(o)})}krt.inherits(Ff,xrt.EventEmitter);Ff.prototype.addRequest=function(e,r,o,a){var n=this,u=IM({request:e},n.options,qse(r,o,a));if(n.sockets.length>=this.maxSockets){n.requests.push(u);return}n.createSocket(u,function(A){A.on("free",p),A.on("close",h),A.on("agentRemove",h),e.onSocket(A);function p(){n.emit("free",A,u)}function h(E){n.removeSocket(A),A.removeListener("free",p),A.removeListener("close",h),A.removeListener("agentRemove",h)}})};Ff.prototype.createSocket=function(e,r){var o=this,a={};o.sockets.push(a);var n=IM({},o.proxyOptions,{method:"CONNECT",path:e.host+":"+e.port,agent:!1,headers:{host:e.host+":"+e.port}});e.localAddress&&(n.localAddress=e.localAddress),n.proxyAuth&&(n.headers=n.headers||{},n.headers["Proxy-Authorization"]="Basic "+new Buffer(n.proxyAuth).toString("base64")),ah("making CONNECT request");var u=o.request(n);u.useChunkedEncodingByDefault=!1,u.once("response",A),u.once("upgrade",p),u.once("connect",h),u.once("error",E),u.end();function A(I){I.upgrade=!0}function p(I,v,x){process.nextTick(function(){h(I,v,x)})}function h(I,v,x){if(u.removeAllListeners(),v.removeAllListeners(),I.statusCode!==200){ah("tunneling socket could not be established, statusCode=%d",I.statusCode),v.destroy();var C=new Error("tunneling socket could not be established, statusCode="+I.statusCode);C.code="ECONNRESET",e.request.emit("error",C),o.removeSocket(a);return}if(x.length>0){ah("got illegal response body from proxy"),v.destroy();var C=new Error("got illegal response body from proxy");C.code="ECONNRESET",e.request.emit("error",C),o.removeSocket(a);return}return ah("tunneling connection has established"),o.sockets[o.sockets.indexOf(a)]=v,r(v)}function E(I){u.removeAllListeners(),ah(`tunneling socket could not be established, cause=%s
-`,I.message,I.stack);var v=new Error("tunneling socket could not be established, cause="+I.message);v.code="ECONNRESET",e.request.emit("error",v),o.removeSocket(a)}};Ff.prototype.removeSocket=function(e){var r=this.sockets.indexOf(e);if(r!==-1){this.sockets.splice(r,1);var o=this.requests.shift();o&&this.createSocket(o,function(a){o.request.onSocket(a)})}};function Hse(t,e){var r=this;Ff.prototype.createSocket.call(r,t,function(o){var a=t.request.getHeader("host"),n=IM({},r.options,{socket:o,servername:a?a.replace(/:.*$/,""):t.host}),u=brt.connect(0,n);r.sockets[r.sockets.indexOf(o)]=u,e(u)})}function qse(t,e,r){return typeof t=="string"?{host:t,port:e,localAddress:r}:t}function IM(t){for(var e=1,r=arguments.length;e<r;++e){var o=arguments[e];if(typeof o=="object")for(var a=Object.keys(o),n=0,u=a.length;n<u;++n){var A=a[n];o[A]!==void 0&&(t[A]=o[A])}}return t}var ah;process.env.NODE_DEBUG&&/\btunnel\b/.test(process.env.NODE_DEBUG)?ah=function(){var t=Array.prototype.slice.call(arguments);typeof t[0]=="string"?t[0]="TUNNEL: "+t[0]:t.unshift("TUNNEL:"),console.error.apply(console,t)}:ah=function(){};CE.debug=ah});var Yse=_((lNt,jse)=>{jse.exports=Gse()});var Tf=_((Rf,KS)=>{"use strict";Object.defineProperty(Rf,"__esModule",{value:!0});var Wse=["Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Uint16Array","Int32Array","Uint32Array","Float32Array","Float64Array","BigInt64Array","BigUint64Array"];function Lrt(t){return Wse.includes(t)}var Nrt=["Function","Generator","AsyncGenerator","GeneratorFunction","AsyncGeneratorFunction","AsyncFunction","Observable","Array","Buffer","Blob","Object","RegExp","Date","Error","Map","Set","WeakMap","WeakSet","ArrayBuffer","SharedArrayBuffer","DataView","Promise","URL","FormData","URLSearchParams","HTMLElement",...Wse];function Ort(t){return Nrt.includes(t)}var Mrt=["null","undefined","string","number","bigint","boolean","symbol"];function Urt(t){return Mrt.includes(t)}function wE(t){return e=>typeof e===t}var{toString:Kse}=Object.prototype,f1=t=>{let e=Kse.call(t).slice(8,-1);if(/HTML\w+Element/.test(e)&&Se.domElement(t))return"HTMLElement";if(Ort(e))return e},Zn=t=>e=>f1(e)===t;function Se(t){if(t===null)return"null";switch(typeof t){case"undefined":return"undefined";case"string":return"string";case"number":return"number";case"boolean":return"boolean";case"function":return"Function";case"bigint":return"bigint";case"symbol":return"symbol";default:}if(Se.observable(t))return"Observable";if(Se.array(t))return"Array";if(Se.buffer(t))return"Buffer";let e=f1(t);if(e)return e;if(t instanceof String||t instanceof Boolean||t instanceof Number)throw new TypeError("Please don't use object wrappers for primitive types");return"Object"}Se.undefined=wE("undefined");Se.string=wE("string");var _rt=wE("number");Se.number=t=>_rt(t)&&!Se.nan(t);Se.bigint=wE("bigint");Se.function_=wE("function");Se.null_=t=>t===null;Se.class_=t=>Se.function_(t)&&t.toString().startsWith("class ");Se.boolean=t=>t===!0||t===!1;Se.symbol=wE("symbol");Se.numericString=t=>Se.string(t)&&!Se.emptyStringOrWhitespace(t)&&!Number.isNaN(Number(t));Se.array=(t,e)=>Array.isArray(t)?Se.function_(e)?t.every(e):!0:!1;Se.buffer=t=>{var e,r,o,a;return(a=(o=(r=(e=t)===null||e===void 0?void 0:e.constructor)===null||r===void 0?void 0:r.isBuffer)===null||o===void 0?void 0:o.call(r,t))!==null&&a!==void 0?a:!1};Se.blob=t=>Zn("Blob")(t);Se.nullOrUndefined=t=>Se.null_(t)||Se.undefined(t);Se.object=t=>!Se.null_(t)&&(typeof t=="object"||Se.function_(t));Se.iterable=t=>{var e;return Se.function_((e=t)===null||e===void 0?void 0:e[Symbol.iterator])};Se.asyncIterable=t=>{var e;return Se.function_((e=t)===null||e===void 0?void 0:e[Symbol.asyncIterator])};Se.generator=t=>{var e,r;return Se.iterable(t)&&Se.function_((e=t)===null||e===void 0?void 0:e.next)&&Se.function_((r=t)===null||r===void 0?void 0:r.throw)};Se.asyncGenerator=t=>Se.asyncIterable(t)&&Se.function_(t.next)&&Se.function_(t.throw);Se.nativePromise=t=>Zn("Promise")(t);var Hrt=t=>{var e,r;return Se.function_((e=t)===null||e===void 0?void 0:e.then)&&Se.function_((r=t)===null||r===void 0?void 0:r.catch)};Se.promise=t=>Se.nativePromise(t)||Hrt(t);Se.generatorFunction=Zn("GeneratorFunction");Se.asyncGeneratorFunction=t=>f1(t)==="AsyncGeneratorFunction";Se.asyncFunction=t=>f1(t)==="AsyncFunction";Se.boundFunction=t=>Se.function_(t)&&!t.hasOwnProperty("prototype");Se.regExp=Zn("RegExp");Se.date=Zn("Date");Se.error=Zn("Error");Se.map=t=>Zn("Map")(t);Se.set=t=>Zn("Set")(t);Se.weakMap=t=>Zn("WeakMap")(t);Se.weakSet=t=>Zn("WeakSet")(t);Se.int8Array=Zn("Int8Array");Se.uint8Array=Zn("Uint8Array");Se.uint8ClampedArray=Zn("Uint8ClampedArray");Se.int16Array=Zn("Int16Array");Se.uint16Array=Zn("Uint16Array");Se.int32Array=Zn("Int32Array");Se.uint32Array=Zn("Uint32Array");Se.float32Array=Zn("Float32Array");Se.float64Array=Zn("Float64Array");Se.bigInt64Array=Zn("BigInt64Array");Se.bigUint64Array=Zn("BigUint64Array");Se.arrayBuffer=Zn("ArrayBuffer");Se.sharedArrayBuffer=Zn("SharedArrayBuffer");Se.dataView=Zn("DataView");Se.enumCase=(t,e)=>Object.values(e).includes(t);Se.directInstanceOf=(t,e)=>Object.getPrototypeOf(t)===e.prototype;Se.urlInstance=t=>Zn("URL")(t);Se.urlString=t=>{if(!Se.string(t))return!1;try{return new URL(t),!0}catch{return!1}};Se.truthy=t=>Boolean(t);Se.falsy=t=>!t;Se.nan=t=>Number.isNaN(t);Se.primitive=t=>Se.null_(t)||Urt(typeof t);Se.integer=t=>Number.isInteger(t);Se.safeInteger=t=>Number.isSafeInteger(t);Se.plainObject=t=>{if(Kse.call(t)!=="[object Object]")return!1;let e=Object.getPrototypeOf(t);return e===null||e===Object.getPrototypeOf({})};Se.typedArray=t=>Lrt(f1(t));var qrt=t=>Se.safeInteger(t)&&t>=0;Se.arrayLike=t=>!Se.nullOrUndefined(t)&&!Se.function_(t)&&qrt(t.length);Se.inRange=(t,e)=>{if(Se.number(e))return t>=Math.min(0,e)&&t<=Math.max(e,0);if(Se.array(e)&&e.length===2)return t>=Math.min(...e)&&t<=Math.max(...e);throw new TypeError(`Invalid range: ${JSON.stringify(e)}`)};var Grt=1,jrt=["innerHTML","ownerDocument","style","attributes","nodeValue"];Se.domElement=t=>Se.object(t)&&t.nodeType===Grt&&Se.string(t.nodeName)&&!Se.plainObject(t)&&jrt.every(e=>e in t);Se.observable=t=>{var e,r,o,a;return t?t===((r=(e=t)[Symbol.observable])===null||r===void 0?void 0:r.call(e))||t===((a=(o=t)["@@observable"])===null||a===void 0?void 0:a.call(o)):!1};Se.nodeStream=t=>Se.object(t)&&Se.function_(t.pipe)&&!Se.observable(t);Se.infinite=t=>t===1/0||t===-1/0;var zse=t=>e=>Se.integer(e)&&Math.abs(e%2)===t;Se.evenInteger=zse(0);Se.oddInteger=zse(1);Se.emptyArray=t=>Se.array(t)&&t.length===0;Se.nonEmptyArray=t=>Se.array(t)&&t.length>0;Se.emptyString=t=>Se.string(t)&&t.length===0;var Yrt=t=>Se.string(t)&&!/\S/.test(t);Se.emptyStringOrWhitespace=t=>Se.emptyString(t)||Yrt(t);Se.nonEmptyString=t=>Se.string(t)&&t.length>0;Se.nonEmptyStringAndNotWhitespace=t=>Se.string(t)&&!Se.emptyStringOrWhitespace(t);Se.emptyObject=t=>Se.object(t)&&!Se.map(t)&&!Se.set(t)&&Object.keys(t).length===0;Se.nonEmptyObject=t=>Se.object(t)&&!Se.map(t)&&!Se.set(t)&&Object.keys(t).length>0;Se.emptySet=t=>Se.set(t)&&t.size===0;Se.nonEmptySet=t=>Se.set(t)&&t.size>0;Se.emptyMap=t=>Se.map(t)&&t.size===0;Se.nonEmptyMap=t=>Se.map(t)&&t.size>0;Se.propertyKey=t=>Se.any([Se.string,Se.number,Se.symbol],t);Se.formData=t=>Zn("FormData")(t);Se.urlSearchParams=t=>Zn("URLSearchParams")(t);var Vse=(t,e,r)=>{if(!Se.function_(e))throw new TypeError(`Invalid predicate: ${JSON.stringify(e)}`);if(r.length===0)throw new TypeError("Invalid number of values");return t.call(r,e)};Se.any=(t,...e)=>(Se.array(t)?t:[t]).some(o=>Vse(Array.prototype.some,o,e));Se.all=(t,...e)=>Vse(Array.prototype.every,t,e);var Mt=(t,e,r,o={})=>{if(!t){let{multipleValues:a}=o,n=a?`received values of types ${[...new Set(r.map(u=>`\`${Se(u)}\``))].join(", ")}`:`received value of type \`${Se(r)}\``;throw new TypeError(`Expected value which is \`${e}\`, ${n}.`)}};Rf.assert={undefined:t=>Mt(Se.undefined(t),"undefined",t),string:t=>Mt(Se.string(t),"string",t),number:t=>Mt(Se.number(t),"number",t),bigint:t=>Mt(Se.bigint(t),"bigint",t),function_:t=>Mt(Se.function_(t),"Function",t),null_:t=>Mt(Se.null_(t),"null",t),class_:t=>Mt(Se.class_(t),"Class",t),boolean:t=>Mt(Se.boolean(t),"boolean",t),symbol:t=>Mt(Se.symbol(t),"symbol",t),numericString:t=>Mt(Se.numericString(t),"string with a number",t),array:(t,e)=>{Mt(Se.array(t),"Array",t),e&&t.forEach(e)},buffer:t=>Mt(Se.buffer(t),"Buffer",t),blob:t=>Mt(Se.blob(t),"Blob",t),nullOrUndefined:t=>Mt(Se.nullOrUndefined(t),"null or undefined",t),object:t=>Mt(Se.object(t),"Object",t),iterable:t=>Mt(Se.iterable(t),"Iterable",t),asyncIterable:t=>Mt(Se.asyncIterable(t),"AsyncIterable",t),generator:t=>Mt(Se.generator(t),"Generator",t),asyncGenerator:t=>Mt(Se.asyncGenerator(t),"AsyncGenerator",t),nativePromise:t=>Mt(Se.nativePromise(t),"native Promise",t),promise:t=>Mt(Se.promise(t),"Promise",t),generatorFunction:t=>Mt(Se.generatorFunction(t),"GeneratorFunction",t),asyncGeneratorFunction:t=>Mt(Se.asyncGeneratorFunction(t),"AsyncGeneratorFunction",t),asyncFunction:t=>Mt(Se.asyncFunction(t),"AsyncFunction",t),boundFunction:t=>Mt(Se.boundFunction(t),"Function",t),regExp:t=>Mt(Se.regExp(t),"RegExp",t),date:t=>Mt(Se.date(t),"Date",t),error:t=>Mt(Se.error(t),"Error",t),map:t=>Mt(Se.map(t),"Map",t),set:t=>Mt(Se.set(t),"Set",t),weakMap:t=>Mt(Se.weakMap(t),"WeakMap",t),weakSet:t=>Mt(Se.weakSet(t),"WeakSet",t),int8Array:t=>Mt(Se.int8Array(t),"Int8Array",t),uint8Array:t=>Mt(Se.uint8Array(t),"Uint8Array",t),uint8ClampedArray:t=>Mt(Se.uint8ClampedArray(t),"Uint8ClampedArray",t),int16Array:t=>Mt(Se.int16Array(t),"Int16Array",t),uint16Array:t=>Mt(Se.uint16Array(t),"Uint16Array",t),int32Array:t=>Mt(Se.int32Array(t),"Int32Array",t),uint32Array:t=>Mt(Se.uint32Array(t),"Uint32Array",t),float32Array:t=>Mt(Se.float32Array(t),"Float32Array",t),float64Array:t=>Mt(Se.float64Array(t),"Float64Array",t),bigInt64Array:t=>Mt(Se.bigInt64Array(t),"BigInt64Array",t),bigUint64Array:t=>Mt(Se.bigUint64Array(t),"BigUint64Array",t),arrayBuffer:t=>Mt(Se.arrayBuffer(t),"ArrayBuffer",t),sharedArrayBuffer:t=>Mt(Se.sharedArrayBuffer(t),"SharedArrayBuffer",t),dataView:t=>Mt(Se.dataView(t),"DataView",t),enumCase:(t,e)=>Mt(Se.enumCase(t,e),"EnumCase",t),urlInstance:t=>Mt(Se.urlInstance(t),"URL",t),urlString:t=>Mt(Se.urlString(t),"string with a URL",t),truthy:t=>Mt(Se.truthy(t),"truthy",t),falsy:t=>Mt(Se.falsy(t),"falsy",t),nan:t=>Mt(Se.nan(t),"NaN",t),primitive:t=>Mt(Se.primitive(t),"primitive",t),integer:t=>Mt(Se.integer(t),"integer",t),safeInteger:t=>Mt(Se.safeInteger(t),"integer",t),plainObject:t=>Mt(Se.plainObject(t),"plain object",t),typedArray:t=>Mt(Se.typedArray(t),"TypedArray",t),arrayLike:t=>Mt(Se.arrayLike(t),"array-like",t),domElement:t=>Mt(Se.domElement(t),"HTMLElement",t),observable:t=>Mt(Se.observable(t),"Observable",t),nodeStream:t=>Mt(Se.nodeStream(t),"Node.js Stream",t),infinite:t=>Mt(Se.infinite(t),"infinite number",t),emptyArray:t=>Mt(Se.emptyArray(t),"empty array",t),nonEmptyArray:t=>Mt(Se.nonEmptyArray(t),"non-empty array",t),emptyString:t=>Mt(Se.emptyString(t),"empty string",t),emptyStringOrWhitespace:t=>Mt(Se.emptyStringOrWhitespace(t),"empty string or whitespace",t),nonEmptyString:t=>Mt(Se.nonEmptyString(t),"non-empty string",t),nonEmptyStringAndNotWhitespace:t=>Mt(Se.nonEmptyStringAndNotWhitespace(t),"non-empty string and not whitespace",t),emptyObject:t=>Mt(Se.emptyObject(t),"empty object",t),nonEmptyObject:t=>Mt(Se.nonEmptyObject(t),"non-empty object",t),emptySet:t=>Mt(Se.emptySet(t),"empty set",t),nonEmptySet:t=>Mt(Se.nonEmptySet(t),"non-empty set",t),emptyMap:t=>Mt(Se.emptyMap(t),"empty map",t),nonEmptyMap:t=>Mt(Se.nonEmptyMap(t),"non-empty map",t),propertyKey:t=>Mt(Se.propertyKey(t),"PropertyKey",t),formData:t=>Mt(Se.formData(t),"FormData",t),urlSearchParams:t=>Mt(Se.urlSearchParams(t),"URLSearchParams",t),evenInteger:t=>Mt(Se.evenInteger(t),"even integer",t),oddInteger:t=>Mt(Se.oddInteger(t),"odd integer",t),directInstanceOf:(t,e)=>Mt(Se.directInstanceOf(t,e),"T",t),inRange:(t,e)=>Mt(Se.inRange(t,e),"in range",t),any:(t,...e)=>Mt(Se.any(t,...e),"predicate returns truthy for any value",e,{multipleValues:!0}),all:(t,...e)=>Mt(Se.all(t,...e),"predicate returns truthy for all values",e,{multipleValues:!0})};Object.defineProperties(Se,{class:{value:Se.class_},function:{value:Se.function_},null:{value:Se.null_}});Object.defineProperties(Rf.assert,{class:{value:Rf.assert.class_},function:{value:Rf.assert.function_},null:{value:Rf.assert.null_}});Rf.default=Se;KS.exports=Se;KS.exports.default=Se;KS.exports.assert=Rf.assert});var Jse=_((cNt,BM)=>{"use strict";var zS=class extends Error{constructor(e){super(e||"Promise was canceled"),this.name="CancelError"}get isCanceled(){return!0}},IE=class{static fn(e){return(...r)=>new IE((o,a,n)=>{r.push(n),e(...r).then(o,a)})}constructor(e){this._cancelHandlers=[],this._isPending=!0,this._isCanceled=!1,this._rejectOnCancel=!0,this._promise=new Promise((r,o)=>{this._reject=o;let a=A=>{this._isPending=!1,r(A)},n=A=>{this._isPending=!1,o(A)},u=A=>{if(!this._isPending)throw new Error("The `onCancel` handler was attached after the promise settled.");this._cancelHandlers.push(A)};return Object.defineProperties(u,{shouldReject:{get:()=>this._rejectOnCancel,set:A=>{this._rejectOnCancel=A}}}),e(a,n,u)})}then(e,r){return this._promise.then(e,r)}catch(e){return this._promise.catch(e)}finally(e){return this._promise.finally(e)}cancel(e){if(!(!this._isPending||this._isCanceled)){if(this._cancelHandlers.length>0)try{for(let r of this._cancelHandlers)r()}catch(r){this._reject(r)}this._isCanceled=!0,this._rejectOnCancel&&this._reject(new zS(e))}}get isCanceled(){return this._isCanceled}};Object.setPrototypeOf(IE.prototype,Promise.prototype);BM.exports=IE;BM.exports.CancelError=zS});var Xse=_((DM,PM)=>{"use strict";Object.defineProperty(DM,"__esModule",{value:!0});function Wrt(t){return t.encrypted}var vM=(t,e)=>{let r;typeof e=="function"?r={connect:e}:r=e;let o=typeof r.connect=="function",a=typeof r.secureConnect=="function",n=typeof r.close=="function",u=()=>{o&&r.connect(),Wrt(t)&&a&&(t.authorized?r.secureConnect():t.authorizationError||t.once("secureConnect",r.secureConnect)),n&&t.once("close",r.close)};t.writable&&!t.connecting?u():t.connecting?t.once("connect",u):t.destroyed&&n&&r.close(t._hadError)};DM.default=vM;PM.exports=vM;PM.exports.default=vM});var Zse=_((bM,xM)=>{"use strict";Object.defineProperty(bM,"__esModule",{value:!0});var Krt=Xse(),zrt=Number(process.versions.node.split(".")[0]),SM=t=>{let e={start:Date.now(),socket:void 0,lookup:void 0,connect:void 0,secureConnect:void 0,upload:void 0,response:void 0,end:void 0,error:void 0,abort:void 0,phases:{wait:void 0,dns:void 0,tcp:void 0,tls:void 0,request:void 0,firstByte:void 0,download:void 0,total:void 0}};t.timings=e;let r=u=>{let A=u.emit.bind(u);u.emit=(p,...h)=>(p==="error"&&(e.error=Date.now(),e.phases.total=e.error-e.start,u.emit=A),A(p,...h))};r(t),t.prependOnceListener("abort",()=>{e.abort=Date.now(),(!e.response||zrt>=13)&&(e.phases.total=Date.now()-e.start)});let o=u=>{e.socket=Date.now(),e.phases.wait=e.socket-e.start;let A=()=>{e.lookup=Date.now(),e.phases.dns=e.lookup-e.socket};u.prependOnceListener("lookup",A),Krt.default(u,{connect:()=>{e.connect=Date.now(),e.lookup===void 0&&(u.removeListener("lookup",A),e.lookup=e.connect,e.phases.dns=e.lookup-e.socket),e.phases.tcp=e.connect-e.lookup},secureConnect:()=>{e.secureConnect=Date.now(),e.phases.tls=e.secureConnect-e.connect}})};t.socket?o(t.socket):t.prependOnceListener("socket",o);let a=()=>{var u;e.upload=Date.now(),e.phases.request=e.upload-(u=e.secureConnect,u??e.connect)};return(()=>typeof t.writableFinished=="boolean"?t.writableFinished:t.finished&&t.outputSize===0&&(!t.socket||t.socket.writableLength===0))()?a():t.prependOnceListener("finish",a),t.prependOnceListener("response",u=>{e.response=Date.now(),e.phases.firstByte=e.response-e.upload,u.timings=e,r(u),u.prependOnceListener("end",()=>{e.end=Date.now(),e.phases.download=e.end-e.response,e.phases.total=e.end-e.start})}),e};bM.default=SM;xM.exports=SM;xM.exports.default=SM});var soe=_((uNt,FM)=>{"use strict";var{V4MAPPED:Vrt,ADDRCONFIG:Jrt,ALL:ioe,promises:{Resolver:$se},lookup:Xrt}=ve("dns"),{promisify:kM}=ve("util"),Zrt=ve("os"),BE=Symbol("cacheableLookupCreateConnection"),QM=Symbol("cacheableLookupInstance"),eoe=Symbol("expires"),$rt=typeof ioe=="number",toe=t=>{if(!(t&&typeof t.createConnection=="function"))throw new Error("Expected an Agent instance as the first argument")},ent=t=>{for(let e of t)e.family!==6&&(e.address=`::ffff:${e.address}`,e.family=6)},roe=()=>{let t=!1,e=!1;for(let r of Object.values(Zrt.networkInterfaces()))for(let o of r)if(!o.internal&&(o.family==="IPv6"?e=!0:t=!0,t&&e))return{has4:t,has6:e};return{has4:t,has6:e}},tnt=t=>Symbol.iterator in t,noe={ttl:!0},rnt={all:!0},VS=class{constructor({cache:e=new Map,maxTtl:r=1/0,fallbackDuration:o=3600,errorTtl:a=.15,resolver:n=new $se,lookup:u=Xrt}={}){if(this.maxTtl=r,this.errorTtl=a,this._cache=e,this._resolver=n,this._dnsLookup=kM(u),this._resolver instanceof $se?(this._resolve4=this._resolver.resolve4.bind(this._resolver),this._resolve6=this._resolver.resolve6.bind(this._resolver)):(this._resolve4=kM(this._resolver.resolve4.bind(this._resolver)),this._resolve6=kM(this._resolver.resolve6.bind(this._resolver))),this._iface=roe(),this._pending={},this._nextRemovalTime=!1,this._hostnamesToFallback=new Set,o<1)this._fallback=!1;else{this._fallback=!0;let A=setInterval(()=>{this._hostnamesToFallback.clear()},o*1e3);A.unref&&A.unref()}this.lookup=this.lookup.bind(this),this.lookupAsync=this.lookupAsync.bind(this)}set servers(e){this.clear(),this._resolver.setServers(e)}get servers(){return this._resolver.getServers()}lookup(e,r,o){if(typeof r=="function"?(o=r,r={}):typeof r=="number"&&(r={family:r}),!o)throw new Error("Callback must be a function.");this.lookupAsync(e,r).then(a=>{r.all?o(null,a):o(null,a.address,a.family,a.expires,a.ttl)},o)}async lookupAsync(e,r={}){typeof r=="number"&&(r={family:r});let o=await this.query(e);if(r.family===6){let a=o.filter(n=>n.family===6);r.hints&Vrt&&($rt&&r.hints&ioe||a.length===0)?ent(o):o=a}else r.family===4&&(o=o.filter(a=>a.family===4));if(r.hints&Jrt){let{_iface:a}=this;o=o.filter(n=>n.family===6?a.has6:a.has4)}if(o.length===0){let a=new Error(`cacheableLookup ENOTFOUND ${e}`);throw a.code="ENOTFOUND",a.hostname=e,a}return r.all?o:o[0]}async query(e){let r=await this._cache.get(e);if(!r){let o=this._pending[e];if(o)r=await o;else{let a=this.queryAndCache(e);this._pending[e]=a,r=await a}}return r=r.map(o=>({...o})),r}async _resolve(e){let r=async h=>{try{return await h}catch(E){if(E.code==="ENODATA"||E.code==="ENOTFOUND")return[];throw E}},[o,a]=await Promise.all([this._resolve4(e,noe),this._resolve6(e,noe)].map(h=>r(h))),n=0,u=0,A=0,p=Date.now();for(let h of o)h.family=4,h.expires=p+h.ttl*1e3,n=Math.max(n,h.ttl);for(let h of a)h.family=6,h.expires=p+h.ttl*1e3,u=Math.max(u,h.ttl);return o.length>0?a.length>0?A=Math.min(n,u):A=n:A=u,{entries:[...o,...a],cacheTtl:A}}async _lookup(e){try{return{entries:await this._dnsLookup(e,{all:!0}),cacheTtl:0}}catch{return{entries:[],cacheTtl:0}}}async _set(e,r,o){if(this.maxTtl>0&&o>0){o=Math.min(o,this.maxTtl)*1e3,r[eoe]=Date.now()+o;try{await this._cache.set(e,r,o)}catch(a){this.lookupAsync=async()=>{let n=new Error("Cache Error. Please recreate the CacheableLookup instance.");throw n.cause=a,n}}tnt(this._cache)&&this._tick(o)}}async queryAndCache(e){if(this._hostnamesToFallback.has(e))return this._dnsLookup(e,rnt);try{let r=await this._resolve(e);r.entries.length===0&&this._fallback&&(r=await this._lookup(e),r.entries.length!==0&&this._hostnamesToFallback.add(e));let o=r.entries.length===0?this.errorTtl:r.cacheTtl;return await this._set(e,r.entries,o),delete this._pending[e],r.entries}catch(r){throw delete this._pending[e],r}}_tick(e){let r=this._nextRemovalTime;(!r||e<r)&&(clearTimeout(this._removalTimeout),this._nextRemovalTime=e,this._removalTimeout=setTimeout(()=>{this._nextRemovalTime=!1;let o=1/0,a=Date.now();for(let[n,u]of this._cache){let A=u[eoe];a>=A?this._cache.delete(n):A<o&&(o=A)}o!==1/0&&this._tick(o-a)},e),this._removalTimeout.unref&&this._removalTimeout.unref())}install(e){if(toe(e),BE in e)throw new Error("CacheableLookup has been already installed");e[BE]=e.createConnection,e[QM]=this,e.createConnection=(r,o)=>("lookup"in r||(r.lookup=this.lookup),e[BE](r,o))}uninstall(e){if(toe(e),e[BE]){if(e[QM]!==this)throw new Error("The agent is not owned by this CacheableLookup instance");e.createConnection=e[BE],delete e[BE],delete e[QM]}}updateInterfaceInfo(){let{_iface:e}=this;this._iface=roe(),(e.has4&&!this._iface.has4||e.has6&&!this._iface.has6)&&this._cache.clear()}clear(e){if(e){this._cache.delete(e);return}this._cache.clear()}};FM.exports=VS;FM.exports.default=VS});var loe=_((ANt,RM)=>{"use strict";var nnt=typeof URL>"u"?ve("url").URL:URL,int="text/plain",snt="us-ascii",ooe=(t,e)=>e.some(r=>r instanceof RegExp?r.test(t):r===t),ont=(t,{stripHash:e})=>{let r=t.match(/^data:([^,]*?),([^#]*?)(?:#(.*))?$/);if(!r)throw new Error(`Invalid URL: ${t}`);let o=r[1].split(";"),a=r[2],n=e?"":r[3],u=!1;o[o.length-1]==="base64"&&(o.pop(),u=!0);let A=(o.shift()||"").toLowerCase(),h=[...o.map(E=>{let[I,v=""]=E.split("=").map(x=>x.trim());return I==="charset"&&(v=v.toLowerCase(),v===snt)?"":`${I}${v?`=${v}`:""}`}).filter(Boolean)];return u&&h.push("base64"),(h.length!==0||A&&A!==int)&&h.unshift(A),`data:${h.join(";")},${u?a.trim():a}${n?`#${n}`:""}`},aoe=(t,e)=>{if(e={defaultProtocol:"http:",normalizeProtocol:!0,forceHttp:!1,forceHttps:!1,stripAuthentication:!0,stripHash:!1,stripWWW:!0,removeQueryParameters:[/^utm_\w+/i],removeTrailingSlash:!0,removeDirectoryIndex:!1,sortQueryParameters:!0,...e},Reflect.has(e,"normalizeHttps"))throw new Error("options.normalizeHttps is renamed to options.forceHttp");if(Reflect.has(e,"normalizeHttp"))throw new Error("options.normalizeHttp is renamed to options.forceHttps");if(Reflect.has(e,"stripFragment"))throw new Error("options.stripFragment is renamed to options.stripHash");if(t=t.trim(),/^data:/i.test(t))return ont(t,e);let r=t.startsWith("//");!r&&/^\.*\//.test(t)||(t=t.replace(/^(?!(?:\w+:)?\/\/)|^\/\//,e.defaultProtocol));let a=new nnt(t);if(e.forceHttp&&e.forceHttps)throw new Error("The `forceHttp` and `forceHttps` options cannot be used together");if(e.forceHttp&&a.protocol==="https:"&&(a.protocol="http:"),e.forceHttps&&a.protocol==="http:"&&(a.protocol="https:"),e.stripAuthentication&&(a.username="",a.password=""),e.stripHash&&(a.hash=""),a.pathname&&(a.pathname=a.pathname.replace(/((?!:).|^)\/{2,}/g,(n,u)=>/^(?!\/)/g.test(u)?`${u}/`:"/")),a.pathname&&(a.pathname=decodeURI(a.pathname)),e.removeDirectoryIndex===!0&&(e.removeDirectoryIndex=[/^index\.[a-z]+$/]),Array.isArray(e.removeDirectoryIndex)&&e.removeDirectoryIndex.length>0){let n=a.pathname.split("/"),u=n[n.length-1];ooe(u,e.removeDirectoryIndex)&&(n=n.slice(0,n.length-1),a.pathname=n.slice(1).join("/")+"/")}if(a.hostname&&(a.hostname=a.hostname.replace(/\.$/,""),e.stripWWW&&/^www\.([a-z\-\d]{2,63})\.([a-z.]{2,5})$/.test(a.hostname)&&(a.hostname=a.hostname.replace(/^www\./,""))),Array.isArray(e.removeQueryParameters))for(let n of[...a.searchParams.keys()])ooe(n,e.removeQueryParameters)&&a.searchParams.delete(n);return e.sortQueryParameters&&a.searchParams.sort(),e.removeTrailingSlash&&(a.pathname=a.pathname.replace(/\/$/,"")),t=a.toString(),(e.removeTrailingSlash||a.pathname==="/")&&a.hash===""&&(t=t.replace(/\/$/,"")),r&&!e.normalizeProtocol&&(t=t.replace(/^http:\/\//,"//")),e.stripProtocol&&(t=t.replace(/^(?:https?:)?\/\//,"")),t};RM.exports=aoe;RM.exports.default=aoe});var Aoe=_((fNt,uoe)=>{uoe.exports=coe;function coe(t,e){if(t&&e)return coe(t)(e);if(typeof t!="function")throw new TypeError("need wrapper function");return Object.keys(t).forEach(function(o){r[o]=t[o]}),r;function r(){for(var o=new Array(arguments.length),a=0;a<o.length;a++)o[a]=arguments[a];var n=t.apply(this,o),u=o[o.length-1];return typeof n=="function"&&n!==u&&Object.keys(u).forEach(function(A){n[A]=u[A]}),n}}});var LM=_((pNt,TM)=>{var foe=Aoe();TM.exports=foe(JS);TM.exports.strict=foe(poe);JS.proto=JS(function(){Object.defineProperty(Function.prototype,"once",{value:function(){return JS(this)},configurable:!0}),Object.defineProperty(Function.prototype,"onceStrict",{value:function(){return poe(this)},configurable:!0})});function JS(t){var e=function(){return e.called?e.value:(e.called=!0,e.value=t.apply(this,arguments))};return e.called=!1,e}function poe(t){var e=function(){if(e.called)throw new Error(e.onceError);return e.called=!0,e.value=t.apply(this,arguments)},r=t.name||"Function wrapped with `once`";return e.onceError=r+" shouldn't be called more than once",e.called=!1,e}});var NM=_((hNt,goe)=>{var ant=LM(),lnt=function(){},cnt=function(t){return t.setHeader&&typeof t.abort=="function"},unt=function(t){return t.stdio&&Array.isArray(t.stdio)&&t.stdio.length===3},hoe=function(t,e,r){if(typeof e=="function")return hoe(t,null,e);e||(e={}),r=ant(r||lnt);var o=t._writableState,a=t._readableState,n=e.readable||e.readable!==!1&&t.readable,u=e.writable||e.writable!==!1&&t.writable,A=function(){t.writable||p()},p=function(){u=!1,n||r.call(t)},h=function(){n=!1,u||r.call(t)},E=function(C){r.call(t,C?new Error("exited with error code: "+C):null)},I=function(C){r.call(t,C)},v=function(){if(n&&!(a&&a.ended))return r.call(t,new Error("premature close"));if(u&&!(o&&o.ended))return r.call(t,new Error("premature close"))},x=function(){t.req.on("finish",p)};return cnt(t)?(t.on("complete",p),t.on("abort",v),t.req?x():t.on("request",x)):u&&!o&&(t.on("end",A),t.on("close",A)),unt(t)&&t.on("exit",E),t.on("end",h),t.on("finish",p),e.error!==!1&&t.on("error",I),t.on("close",v),function(){t.removeListener("complete",p),t.removeListener("abort",v),t.removeListener("request",x),t.req&&t.req.removeListener("finish",p),t.removeListener("end",A),t.removeListener("close",A),t.removeListener("finish",p),t.removeListener("exit",E),t.removeListener("end",h),t.removeListener("error",I),t.removeListener("close",v)}};goe.exports=hoe});var yoe=_((gNt,moe)=>{var Ant=LM(),fnt=NM(),OM=ve("fs"),p1=function(){},pnt=/^v?\.0/.test(process.version),XS=function(t){return typeof t=="function"},hnt=function(t){return!pnt||!OM?!1:(t instanceof(OM.ReadStream||p1)||t instanceof(OM.WriteStream||p1))&&XS(t.close)},gnt=function(t){return t.setHeader&&XS(t.abort)},dnt=function(t,e,r,o){o=Ant(o);var a=!1;t.on("close",function(){a=!0}),fnt(t,{readable:e,writable:r},function(u){if(u)return o(u);a=!0,o()});var n=!1;return function(u){if(!a&&!n){if(n=!0,hnt(t))return t.close(p1);if(gnt(t))return t.abort();if(XS(t.destroy))return t.destroy();o(u||new Error("stream was destroyed"))}}},doe=function(t){t()},mnt=function(t,e){return t.pipe(e)},ynt=function(){var t=Array.prototype.slice.call(arguments),e=XS(t[t.length-1]||p1)&&t.pop()||p1;if(Array.isArray(t[0])&&(t=t[0]),t.length<2)throw new Error("pump requires two streams per minimum");var r,o=t.map(function(a,n){var u=n<t.length-1,A=n>0;return dnt(a,u,A,function(p){r||(r=p),p&&o.forEach(doe),!u&&(o.forEach(doe),e(r))})});return t.reduce(mnt)};moe.exports=ynt});var Coe=_((dNt,Eoe)=>{"use strict";var{PassThrough:Ent}=ve("stream");Eoe.exports=t=>{t={...t};let{array:e}=t,{encoding:r}=t,o=r==="buffer",a=!1;e?a=!(r||o):r=r||"utf8",o&&(r=null);let n=new Ent({objectMode:a});r&&n.setEncoding(r);let u=0,A=[];return n.on("data",p=>{A.push(p),a?u=A.length:u+=p.length}),n.getBufferedValue=()=>e?A:o?Buffer.concat(A,u):A.join(""),n.getBufferedLength=()=>u,n}});var woe=_((mNt,vE)=>{"use strict";var Cnt=yoe(),wnt=Coe(),ZS=class extends Error{constructor(){super("maxBuffer exceeded"),this.name="MaxBufferError"}};async function $S(t,e){if(!t)return Promise.reject(new Error("Expected a stream"));e={maxBuffer:1/0,...e};let{maxBuffer:r}=e,o;return await new Promise((a,n)=>{let u=A=>{A&&(A.bufferedData=o.getBufferedValue()),n(A)};o=Cnt(t,wnt(e),A=>{if(A){u(A);return}a()}),o.on("data",()=>{o.getBufferedLength()>r&&u(new ZS)})}),o.getBufferedValue()}vE.exports=$S;vE.exports.default=$S;vE.exports.buffer=(t,e)=>$S(t,{...e,encoding:"buffer"});vE.exports.array=(t,e)=>$S(t,{...e,array:!0});vE.exports.MaxBufferError=ZS});var Boe=_((ENt,Ioe)=>{"use strict";var Int=new Set([200,203,204,206,300,301,308,404,405,410,414,501]),Bnt=new Set([200,203,204,300,301,302,303,307,308,404,405,410,414,501]),vnt=new Set([500,502,503,504]),Dnt={date:!0,connection:!0,"keep-alive":!0,"proxy-authenticate":!0,"proxy-authorization":!0,te:!0,trailer:!0,"transfer-encoding":!0,upgrade:!0},Pnt={"content-length":!0,"content-encoding":!0,"transfer-encoding":!0,"content-range":!0};function Sd(t){let e=parseInt(t,10);return isFinite(e)?e:0}function Snt(t){return t?vnt.has(t.status):!0}function MM(t){let e={};if(!t)return e;let r=t.trim().split(/,/);for(let o of r){let[a,n]=o.split(/=/,2);e[a.trim()]=n===void 0?!0:n.trim().replace(/^"|"$/g,"")}return e}function bnt(t){let e=[];for(let r in t){let o=t[r];e.push(o===!0?r:r+"="+o)}if(!!e.length)return e.join(", ")}Ioe.exports=class{constructor(e,r,{shared:o,cacheHeuristic:a,immutableMinTimeToLive:n,ignoreCargoCult:u,_fromObject:A}={}){if(A){this._fromObject(A);return}if(!r||!r.headers)throw Error("Response headers missing");this._assertRequestHasHeaders(e),this._responseTime=this.now(),this._isShared=o!==!1,this._cacheHeuristic=a!==void 0?a:.1,this._immutableMinTtl=n!==void 0?n:24*3600*1e3,this._status="status"in r?r.status:200,this._resHeaders=r.headers,this._rescc=MM(r.headers["cache-control"]),this._method="method"in e?e.method:"GET",this._url=e.url,this._host=e.headers.host,this._noAuthorization=!e.headers.authorization,this._reqHeaders=r.headers.vary?e.headers:null,this._reqcc=MM(e.headers["cache-control"]),u&&"pre-check"in this._rescc&&"post-check"in this._rescc&&(delete this._rescc["pre-check"],delete this._rescc["post-check"],delete this._rescc["no-cache"],delete this._rescc["no-store"],delete this._rescc["must-revalidate"],this._resHeaders=Object.assign({},this._resHeaders,{"cache-control":bnt(this._rescc)}),delete this._resHeaders.expires,delete this._resHeaders.pragma),r.headers["cache-control"]==null&&/no-cache/.test(r.headers.pragma)&&(this._rescc["no-cache"]=!0)}now(){return Date.now()}storable(){return!!(!this._reqcc["no-store"]&&(this._method==="GET"||this._method==="HEAD"||this._method==="POST"&&this._hasExplicitExpiration())&&Bnt.has(this._status)&&!this._rescc["no-store"]&&(!this._isShared||!this._rescc.private)&&(!this._isShared||this._noAuthorization||this._allowsStoringAuthenticated())&&(this._resHeaders.expires||this._rescc["max-age"]||this._isShared&&this._rescc["s-maxage"]||this._rescc.public||Int.has(this._status)))}_hasExplicitExpiration(){return this._isShared&&this._rescc["s-maxage"]||this._rescc["max-age"]||this._resHeaders.expires}_assertRequestHasHeaders(e){if(!e||!e.headers)throw Error("Request headers missing")}satisfiesWithoutRevalidation(e){this._assertRequestHasHeaders(e);let r=MM(e.headers["cache-control"]);return r["no-cache"]||/no-cache/.test(e.headers.pragma)||r["max-age"]&&this.age()>r["max-age"]||r["min-fresh"]&&this.timeToLive()<1e3*r["min-fresh"]||this.stale()&&!(r["max-stale"]&&!this._rescc["must-revalidate"]&&(r["max-stale"]===!0||r["max-stale"]>this.age()-this.maxAge()))?!1:this._requestMatches(e,!1)}_requestMatches(e,r){return(!this._url||this._url===e.url)&&this._host===e.headers.host&&(!e.method||this._method===e.method||r&&e.method==="HEAD")&&this._varyMatches(e)}_allowsStoringAuthenticated(){return this._rescc["must-revalidate"]||this._rescc.public||this._rescc["s-maxage"]}_varyMatches(e){if(!this._resHeaders.vary)return!0;if(this._resHeaders.vary==="*")return!1;let r=this._resHeaders.vary.trim().toLowerCase().split(/\s*,\s*/);for(let o of r)if(e.headers[o]!==this._reqHeaders[o])return!1;return!0}_copyWithoutHopByHopHeaders(e){let r={};for(let o in e)Dnt[o]||(r[o]=e[o]);if(e.connection){let o=e.connection.trim().split(/\s*,\s*/);for(let a of o)delete r[a]}if(r.warning){let o=r.warning.split(/,/).filter(a=>!/^\s*1[0-9][0-9]/.test(a));o.length?r.warning=o.join(",").trim():delete r.warning}return r}responseHeaders(){let e=this._copyWithoutHopByHopHeaders(this._resHeaders),r=this.age();return r>3600*24&&!this._hasExplicitExpiration()&&this.maxAge()>3600*24&&(e.warning=(e.warning?`${e.warning}, `:"")+'113 - "rfc7234 5.5.4"'),e.age=`${Math.round(r)}`,e.date=new Date(this.now()).toUTCString(),e}date(){let e=Date.parse(this._resHeaders.date);return isFinite(e)?e:this._responseTime}age(){let e=this._ageValue(),r=(this.now()-this._responseTime)/1e3;return e+r}_ageValue(){return Sd(this._resHeaders.age)}maxAge(){if(!this.storable()||this._rescc["no-cache"]||this._isShared&&this._resHeaders["set-cookie"]&&!this._rescc.public&&!this._rescc.immutable||this._resHeaders.vary==="*")return 0;if(this._isShared){if(this._rescc["proxy-revalidate"])return 0;if(this._rescc["s-maxage"])return Sd(this._rescc["s-maxage"])}if(this._rescc["max-age"])return Sd(this._rescc["max-age"]);let e=this._rescc.immutable?this._immutableMinTtl:0,r=this.date();if(this._resHeaders.expires){let o=Date.parse(this._resHeaders.expires);return Number.isNaN(o)||o<r?0:Math.max(e,(o-r)/1e3)}if(this._resHeaders["last-modified"]){let o=Date.parse(this._resHeaders["last-modified"]);if(isFinite(o)&&r>o)return Math.max(e,(r-o)/1e3*this._cacheHeuristic)}return e}timeToLive(){let e=this.maxAge()-this.age(),r=e+Sd(this._rescc["stale-if-error"]),o=e+Sd(this._rescc["stale-while-revalidate"]);return Math.max(0,e,r,o)*1e3}stale(){return this.maxAge()<=this.age()}_useStaleIfError(){return this.maxAge()+Sd(this._rescc["stale-if-error"])>this.age()}useStaleWhileRevalidate(){return this.maxAge()+Sd(this._rescc["stale-while-revalidate"])>this.age()}static fromObject(e){return new this(void 0,void 0,{_fromObject:e})}_fromObject(e){if(this._responseTime)throw Error("Reinitialized");if(!e||e.v!==1)throw Error("Invalid serialization");this._responseTime=e.t,this._isShared=e.sh,this._cacheHeuristic=e.ch,this._immutableMinTtl=e.imm!==void 0?e.imm:24*3600*1e3,this._status=e.st,this._resHeaders=e.resh,this._rescc=e.rescc,this._method=e.m,this._url=e.u,this._host=e.h,this._noAuthorization=e.a,this._reqHeaders=e.reqh,this._reqcc=e.reqcc}toObject(){return{v:1,t:this._responseTime,sh:this._isShared,ch:this._cacheHeuristic,imm:this._immutableMinTtl,st:this._status,resh:this._resHeaders,rescc:this._rescc,m:this._method,u:this._url,h:this._host,a:this._noAuthorization,reqh:this._reqHeaders,reqcc:this._reqcc}}revalidationHeaders(e){this._assertRequestHasHeaders(e);let r=this._copyWithoutHopByHopHeaders(e.headers);if(delete r["if-range"],!this._requestMatches(e,!0)||!this.storable())return delete r["if-none-match"],delete r["if-modified-since"],r;if(this._resHeaders.etag&&(r["if-none-match"]=r["if-none-match"]?`${r["if-none-match"]}, ${this._resHeaders.etag}`:this._resHeaders.etag),r["accept-ranges"]||r["if-match"]||r["if-unmodified-since"]||this._method&&this._method!="GET"){if(delete r["if-modified-since"],r["if-none-match"]){let a=r["if-none-match"].split(/,/).filter(n=>!/^\s*W\//.test(n));a.length?r["if-none-match"]=a.join(",").trim():delete r["if-none-match"]}}else this._resHeaders["last-modified"]&&!r["if-modified-since"]&&(r["if-modified-since"]=this._resHeaders["last-modified"]);return r}revalidatedPolicy(e,r){if(this._assertRequestHasHeaders(e),this._useStaleIfError()&&Snt(r))return{modified:!1,matches:!1,policy:this};if(!r||!r.headers)throw Error("Response headers missing");let o=!1;if(r.status!==void 0&&r.status!=304?o=!1:r.headers.etag&&!/^\s*W\//.test(r.headers.etag)?o=this._resHeaders.etag&&this._resHeaders.etag.replace(/^\s*W\//,"")===r.headers.etag:this._resHeaders.etag&&r.headers.etag?o=this._resHeaders.etag.replace(/^\s*W\//,"")===r.headers.etag.replace(/^\s*W\//,""):this._resHeaders["last-modified"]?o=this._resHeaders["last-modified"]===r.headers["last-modified"]:!this._resHeaders.etag&&!this._resHeaders["last-modified"]&&!r.headers.etag&&!r.headers["last-modified"]&&(o=!0),!o)return{policy:new this.constructor(e,r),modified:r.status!=304,matches:!1};let a={};for(let u in this._resHeaders)a[u]=u in r.headers&&!Pnt[u]?r.headers[u]:this._resHeaders[u];let n=Object.assign({},r,{status:this._status,method:this._method,headers:a});return{policy:new this.constructor(e,n,{shared:this._isShared,cacheHeuristic:this._cacheHeuristic,immutableMinTimeToLive:this._immutableMinTtl}),modified:!1,matches:!0}}}});var eb=_((CNt,voe)=>{"use strict";voe.exports=t=>{let e={};for(let[r,o]of Object.entries(t))e[r.toLowerCase()]=o;return e}});var Poe=_((wNt,Doe)=>{"use strict";var xnt=ve("stream").Readable,knt=eb(),UM=class extends xnt{constructor(e,r,o,a){if(typeof e!="number")throw new TypeError("Argument `statusCode` should be a number");if(typeof r!="object")throw new TypeError("Argument `headers` should be an object");if(!(o instanceof Buffer))throw new TypeError("Argument `body` should be a buffer");if(typeof a!="string")throw new TypeError("Argument `url` should be a string");super(),this.statusCode=e,this.headers=knt(r),this.body=o,this.url=a}_read(){this.push(this.body),this.push(null)}};Doe.exports=UM});var boe=_((INt,Soe)=>{"use strict";var Qnt=["destroy","setTimeout","socket","headers","trailers","rawHeaders","statusCode","httpVersion","httpVersionMinor","httpVersionMajor","rawTrailers","statusMessage"];Soe.exports=(t,e)=>{let r=new Set(Object.keys(t).concat(Qnt));for(let o of r)o in e||(e[o]=typeof t[o]=="function"?t[o].bind(t):t[o])}});var koe=_((BNt,xoe)=>{"use strict";var Fnt=ve("stream").PassThrough,Rnt=boe(),Tnt=t=>{if(!(t&&t.pipe))throw new TypeError("Parameter `response` must be a response stream.");let e=new Fnt;return Rnt(t,e),t.pipe(e)};xoe.exports=Tnt});var Qoe=_(_M=>{_M.stringify=function t(e){if(typeof e>"u")return e;if(e&&Buffer.isBuffer(e))return JSON.stringify(":base64:"+e.toString("base64"));if(e&&e.toJSON&&(e=e.toJSON()),e&&typeof e=="object"){var r="",o=Array.isArray(e);r=o?"[":"{";var a=!0;for(var n in e){var u=typeof e[n]=="function"||!o&&typeof e[n]>"u";Object.hasOwnProperty.call(e,n)&&!u&&(a||(r+=","),a=!1,o?e[n]==null?r+="null":r+=t(e[n]):e[n]!==void 0&&(r+=t(n)+":"+t(e[n])))}return r+=o?"]":"}",r}else return typeof e=="string"?JSON.stringify(/^:/.test(e)?":"+e:e):typeof e>"u"?"null":JSON.stringify(e)};_M.parse=function(t){return JSON.parse(t,function(e,r){return typeof r=="string"?/^:base64:/.test(r)?Buffer.from(r.substring(8),"base64"):/^:/.test(r)?r.substring(1):r:r})}});var Loe=_((DNt,Toe)=>{"use strict";var Lnt=ve("events"),Foe=Qoe(),Nnt=t=>{let e={redis:"@keyv/redis",rediss:"@keyv/redis",mongodb:"@keyv/mongo",mongo:"@keyv/mongo",sqlite:"@keyv/sqlite",postgresql:"@keyv/postgres",postgres:"@keyv/postgres",mysql:"@keyv/mysql",etcd:"@keyv/etcd",offline:"@keyv/offline",tiered:"@keyv/tiered"};if(t.adapter||t.uri){let r=t.adapter||/^[^:+]*/.exec(t.uri)[0];return new(ve(e[r]))(t)}return new Map},Roe=["sqlite","postgres","mysql","mongo","redis","tiered"],HM=class extends Lnt{constructor(e,{emitErrors:r=!0,...o}={}){if(super(),this.opts={namespace:"keyv",serialize:Foe.stringify,deserialize:Foe.parse,...typeof e=="string"?{uri:e}:e,...o},!this.opts.store){let n={...this.opts};this.opts.store=Nnt(n)}if(this.opts.compression){let n=this.opts.compression;this.opts.serialize=n.serialize.bind(n),this.opts.deserialize=n.deserialize.bind(n)}typeof this.opts.store.on=="function"&&r&&this.opts.store.on("error",n=>this.emit("error",n)),this.opts.store.namespace=this.opts.namespace;let a=n=>async function*(){for await(let[u,A]of typeof n=="function"?n(this.opts.store.namespace):n){let p=await this.opts.deserialize(A);if(!(this.opts.store.namespace&&!u.includes(this.opts.store.namespace))){if(typeof p.expires=="number"&&Date.now()>p.expires){this.delete(u);continue}yield[this._getKeyUnprefix(u),p.value]}}};typeof this.opts.store[Symbol.iterator]=="function"&&this.opts.store instanceof Map?this.iterator=a(this.opts.store):typeof this.opts.store.iterator=="function"&&this.opts.store.opts&&this._checkIterableAdaptar()&&(this.iterator=a(this.opts.store.iterator.bind(this.opts.store)))}_checkIterableAdaptar(){return Roe.includes(this.opts.store.opts.dialect)||Roe.findIndex(e=>this.opts.store.opts.url.includes(e))>=0}_getKeyPrefix(e){return`${this.opts.namespace}:${e}`}_getKeyPrefixArray(e){return e.map(r=>`${this.opts.namespace}:${r}`)}_getKeyUnprefix(e){return e.split(":").splice(1).join(":")}get(e,r){let{store:o}=this.opts,a=Array.isArray(e),n=a?this._getKeyPrefixArray(e):this._getKeyPrefix(e);if(a&&o.getMany===void 0){let u=[];for(let A of n)u.push(Promise.resolve().then(()=>o.get(A)).then(p=>typeof p=="string"?this.opts.deserialize(p):this.opts.compression?this.opts.deserialize(p):p).then(p=>{if(p!=null)return typeof p.expires=="number"&&Date.now()>p.expires?this.delete(A).then(()=>{}):r&&r.raw?p:p.value}));return Promise.allSettled(u).then(A=>{let p=[];for(let h of A)p.push(h.value);return p})}return Promise.resolve().then(()=>a?o.getMany(n):o.get(n)).then(u=>typeof u=="string"?this.opts.deserialize(u):this.opts.compression?this.opts.deserialize(u):u).then(u=>{if(u!=null)return a?u.map((A,p)=>{if(typeof A=="string"&&(A=this.opts.deserialize(A)),A!=null){if(typeof A.expires=="number"&&Date.now()>A.expires){this.delete(e[p]).then(()=>{});return}return r&&r.raw?A:A.value}}):typeof u.expires=="number"&&Date.now()>u.expires?this.delete(e).then(()=>{}):r&&r.raw?u:u.value})}set(e,r,o){let a=this._getKeyPrefix(e);typeof o>"u"&&(o=this.opts.ttl),o===0&&(o=void 0);let{store:n}=this.opts;return Promise.resolve().then(()=>{let u=typeof o=="number"?Date.now()+o:null;return typeof r=="symbol"&&this.emit("error","symbol cannot be serialized"),r={value:r,expires:u},this.opts.serialize(r)}).then(u=>n.set(a,u,o)).then(()=>!0)}delete(e){let{store:r}=this.opts;if(Array.isArray(e)){let a=this._getKeyPrefixArray(e);if(r.deleteMany===void 0){let n=[];for(let u of a)n.push(r.delete(u));return Promise.allSettled(n).then(u=>u.every(A=>A.value===!0))}return Promise.resolve().then(()=>r.deleteMany(a))}let o=this._getKeyPrefix(e);return Promise.resolve().then(()=>r.delete(o))}clear(){let{store:e}=this.opts;return Promise.resolve().then(()=>e.clear())}has(e){let r=this._getKeyPrefix(e),{store:o}=this.opts;return Promise.resolve().then(async()=>typeof o.has=="function"?o.has(r):await o.get(r)!==void 0)}disconnect(){let{store:e}=this.opts;if(typeof e.disconnect=="function")return e.disconnect()}};Toe.exports=HM});var Moe=_((SNt,Ooe)=>{"use strict";var Ont=ve("events"),tb=ve("url"),Mnt=loe(),Unt=woe(),qM=Boe(),Noe=Poe(),_nt=eb(),Hnt=koe(),qnt=Loe(),Gc=class{constructor(e,r){if(typeof e!="function")throw new TypeError("Parameter `request` must be a function");return this.cache=new qnt({uri:typeof r=="string"&&r,store:typeof r!="string"&&r,namespace:"cacheable-request"}),this.createCacheableRequest(e)}createCacheableRequest(e){return(r,o)=>{let a;if(typeof r=="string")a=GM(tb.parse(r)),r={};else if(r instanceof tb.URL)a=GM(tb.parse(r.toString())),r={};else{let[I,...v]=(r.path||"").split("?"),x=v.length>0?`?${v.join("?")}`:"";a=GM({...r,pathname:I,search:x})}r={headers:{},method:"GET",cache:!0,strictTtl:!1,automaticFailover:!1,...r,...Gnt(a)},r.headers=_nt(r.headers);let n=new Ont,u=Mnt(tb.format(a),{stripWWW:!1,removeTrailingSlash:!1,stripAuthentication:!1}),A=`${r.method}:${u}`,p=!1,h=!1,E=I=>{h=!0;let v=!1,x,C=new Promise(N=>{x=()=>{v||(v=!0,N())}}),R=N=>{if(p&&!I.forceRefresh){N.status=N.statusCode;let V=qM.fromObject(p.cachePolicy).revalidatedPolicy(I,N);if(!V.modified){let te=V.policy.responseHeaders();N=new Noe(p.statusCode,te,p.body,p.url),N.cachePolicy=V.policy,N.fromCache=!0}}N.fromCache||(N.cachePolicy=new qM(I,N,I),N.fromCache=!1);let U;I.cache&&N.cachePolicy.storable()?(U=Hnt(N),(async()=>{try{let V=Unt.buffer(N);if(await Promise.race([C,new Promise(ue=>N.once("end",ue))]),v)return;let te=await V,ae={cachePolicy:N.cachePolicy.toObject(),url:N.url,statusCode:N.fromCache?p.statusCode:N.statusCode,body:te},fe=I.strictTtl?N.cachePolicy.timeToLive():void 0;I.maxTtl&&(fe=fe?Math.min(fe,I.maxTtl):I.maxTtl),await this.cache.set(A,ae,fe)}catch(V){n.emit("error",new Gc.CacheError(V))}})()):I.cache&&p&&(async()=>{try{await this.cache.delete(A)}catch(V){n.emit("error",new Gc.CacheError(V))}})(),n.emit("response",U||N),typeof o=="function"&&o(U||N)};try{let N=e(I,R);N.once("error",x),N.once("abort",x),n.emit("request",N)}catch(N){n.emit("error",new Gc.RequestError(N))}};return(async()=>{let I=async x=>{await Promise.resolve();let C=x.cache?await this.cache.get(A):void 0;if(typeof C>"u")return E(x);let R=qM.fromObject(C.cachePolicy);if(R.satisfiesWithoutRevalidation(x)&&!x.forceRefresh){let N=R.responseHeaders(),U=new Noe(C.statusCode,N,C.body,C.url);U.cachePolicy=R,U.fromCache=!0,n.emit("response",U),typeof o=="function"&&o(U)}else p=C,x.headers=R.revalidationHeaders(x),E(x)},v=x=>n.emit("error",new Gc.CacheError(x));this.cache.once("error",v),n.on("response",()=>this.cache.removeListener("error",v));try{await I(r)}catch(x){r.automaticFailover&&!h&&E(r),n.emit("error",new Gc.CacheError(x))}})(),n}}};function Gnt(t){let e={...t};return e.path=`${t.pathname||"/"}${t.search||""}`,delete e.pathname,delete e.search,e}function GM(t){return{protocol:t.protocol,auth:t.auth,hostname:t.hostname||t.host||"localhost",port:t.port,pathname:t.pathname,search:t.search}}Gc.RequestError=class extends Error{constructor(t){super(t.message),this.name="RequestError",Object.assign(this,t)}};Gc.CacheError=class extends Error{constructor(t){super(t.message),this.name="CacheError",Object.assign(this,t)}};Ooe.exports=Gc});var _oe=_((kNt,Uoe)=>{"use strict";var jnt=["aborted","complete","headers","httpVersion","httpVersionMinor","httpVersionMajor","method","rawHeaders","rawTrailers","setTimeout","socket","statusCode","statusMessage","trailers","url"];Uoe.exports=(t,e)=>{if(e._readableState.autoDestroy)throw new Error("The second stream must have the `autoDestroy` option set to `false`");let r=new Set(Object.keys(t).concat(jnt)),o={};for(let a of r)a in e||(o[a]={get(){let n=t[a];return typeof n=="function"?n.bind(t):n},set(n){t[a]=n},enumerable:!0,configurable:!1});return Object.defineProperties(e,o),t.once("aborted",()=>{e.destroy(),e.emit("aborted")}),t.once("close",()=>{t.complete&&e.readable?e.once("end",()=>{e.emit("close")}):e.emit("close")}),e}});var qoe=_((QNt,Hoe)=>{"use strict";var{Transform:Ynt,PassThrough:Wnt}=ve("stream"),jM=ve("zlib"),Knt=_oe();Hoe.exports=t=>{let e=(t.headers["content-encoding"]||"").toLowerCase();if(!["gzip","deflate","br"].includes(e))return t;let r=e==="br";if(r&&typeof jM.createBrotliDecompress!="function")return t.destroy(new Error("Brotli is not supported on Node.js < 12")),t;let o=!0,a=new Ynt({transform(A,p,h){o=!1,h(null,A)},flush(A){A()}}),n=new Wnt({autoDestroy:!1,destroy(A,p){t.destroy(),p(A)}}),u=r?jM.createBrotliDecompress():jM.createUnzip();return u.once("error",A=>{if(o&&!t.readable){n.end();return}n.destroy(A)}),Knt(t,n),t.pipe(a).pipe(u).pipe(n),n}});var WM=_((FNt,Goe)=>{"use strict";var YM=class{constructor(e={}){if(!(e.maxSize&&e.maxSize>0))throw new TypeError("`maxSize` must be a number greater than 0");this.maxSize=e.maxSize,this.onEviction=e.onEviction,this.cache=new Map,this.oldCache=new Map,this._size=0}_set(e,r){if(this.cache.set(e,r),this._size++,this._size>=this.maxSize){if(this._size=0,typeof this.onEviction=="function")for(let[o,a]of this.oldCache.entries())this.onEviction(o,a);this.oldCache=this.cache,this.cache=new Map}}get(e){if(this.cache.has(e))return this.cache.get(e);if(this.oldCache.has(e)){let r=this.oldCache.get(e);return this.oldCache.delete(e),this._set(e,r),r}}set(e,r){return this.cache.has(e)?this.cache.set(e,r):this._set(e,r),this}has(e){return this.cache.has(e)||this.oldCache.has(e)}peek(e){if(this.cache.has(e))return this.cache.get(e);if(this.oldCache.has(e))return this.oldCache.get(e)}delete(e){let r=this.cache.delete(e);return r&&this._size--,this.oldCache.delete(e)||r}clear(){this.cache.clear(),this.oldCache.clear(),this._size=0}*keys(){for(let[e]of this)yield e}*values(){for(let[,e]of this)yield e}*[Symbol.iterator](){for(let e of this.cache)yield e;for(let e of this.oldCache){let[r]=e;this.cache.has(r)||(yield e)}}get size(){let e=0;for(let r of this.oldCache.keys())this.cache.has(r)||e++;return Math.min(this._size+e,this.maxSize)}};Goe.exports=YM});var zM=_((RNt,Koe)=>{"use strict";var znt=ve("events"),Vnt=ve("tls"),Jnt=ve("http2"),Xnt=WM(),ea=Symbol("currentStreamsCount"),joe=Symbol("request"),Kl=Symbol("cachedOriginSet"),DE=Symbol("gracefullyClosing"),Znt=["maxDeflateDynamicTableSize","maxSessionMemory","maxHeaderListPairs","maxOutstandingPings","maxReservedRemoteStreams","maxSendHeaderBlockLength","paddingStrategy","localAddress","path","rejectUnauthorized","minDHSize","ca","cert","clientCertEngine","ciphers","key","pfx","servername","minVersion","maxVersion","secureProtocol","crl","honorCipherOrder","ecdhCurve","dhparam","secureOptions","sessionIdContext"],$nt=(t,e,r)=>{let o=0,a=t.length;for(;o<a;){let n=o+a>>>1;r(t[n],e)?o=n+1:a=n}return o},eit=(t,e)=>t.remoteSettings.maxConcurrentStreams>e.remoteSettings.maxConcurrentStreams,KM=(t,e)=>{for(let r of t)r[Kl].length<e[Kl].length&&r[Kl].every(o=>e[Kl].includes(o))&&r[ea]+e[ea]<=e.remoteSettings.maxConcurrentStreams&&Woe(r)},tit=(t,e)=>{for(let r of t)e[Kl].length<r[Kl].length&&e[Kl].every(o=>r[Kl].includes(o))&&e[ea]+r[ea]<=r.remoteSettings.maxConcurrentStreams&&Woe(e)},Yoe=({agent:t,isFree:e})=>{let r={};for(let o in t.sessions){let n=t.sessions[o].filter(u=>{let A=u[rA.kCurrentStreamsCount]<u.remoteSettings.maxConcurrentStreams;return e?A:!A});n.length!==0&&(r[o]=n)}return r},Woe=t=>{t[DE]=!0,t[ea]===0&&t.close()},rA=class extends znt{constructor({timeout:e=6e4,maxSessions:r=1/0,maxFreeSessions:o=10,maxCachedTlsSessions:a=100}={}){super(),this.sessions={},this.queue={},this.timeout=e,this.maxSessions=r,this.maxFreeSessions=o,this._freeSessionsCount=0,this._sessionsCount=0,this.settings={enablePush:!1},this.tlsSessionCache=new Xnt({maxSize:a})}static normalizeOrigin(e,r){return typeof e=="string"&&(e=new URL(e)),r&&e.hostname!==r&&(e.hostname=r),e.origin}normalizeOptions(e){let r="";if(e)for(let o of Znt)e[o]&&(r+=`:${e[o]}`);return r}_tryToCreateNewSession(e,r){if(!(e in this.queue)||!(r in this.queue[e]))return;let o=this.queue[e][r];this._sessionsCount<this.maxSessions&&!o.completed&&(o.completed=!0,o())}getSession(e,r,o){return new Promise((a,n)=>{Array.isArray(o)?(o=[...o],a()):o=[{resolve:a,reject:n}];let u=this.normalizeOptions(r),A=rA.normalizeOrigin(e,r&&r.servername);if(A===void 0){for(let{reject:E}of o)E(new TypeError("The `origin` argument needs to be a string or an URL object"));return}if(u in this.sessions){let E=this.sessions[u],I=-1,v=-1,x;for(let C of E){let R=C.remoteSettings.maxConcurrentStreams;if(R<I)break;if(C[Kl].includes(A)){let N=C[ea];if(N>=R||C[DE]||C.destroyed)continue;x||(I=R),N>v&&(x=C,v=N)}}if(x){if(o.length!==1){for(let{reject:C}of o){let R=new Error(`Expected the length of listeners to be 1, got ${o.length}.
-Please report this to https://github.com/szmarczak/http2-wrapper/`);C(R)}return}o[0].resolve(x);return}}if(u in this.queue){if(A in this.queue[u]){this.queue[u][A].listeners.push(...o),this._tryToCreateNewSession(u,A);return}}else this.queue[u]={};let p=()=>{u in this.queue&&this.queue[u][A]===h&&(delete this.queue[u][A],Object.keys(this.queue[u]).length===0&&delete this.queue[u])},h=()=>{let E=`${A}:${u}`,I=!1;try{let v=Jnt.connect(e,{createConnection:this.createConnection,settings:this.settings,session:this.tlsSessionCache.get(E),...r});v[ea]=0,v[DE]=!1;let x=()=>v[ea]<v.remoteSettings.maxConcurrentStreams,C=!0;v.socket.once("session",N=>{this.tlsSessionCache.set(E,N)}),v.once("error",N=>{for(let{reject:U}of o)U(N);this.tlsSessionCache.delete(E)}),v.setTimeout(this.timeout,()=>{v.destroy()}),v.once("close",()=>{if(I){C&&this._freeSessionsCount--,this._sessionsCount--;let N=this.sessions[u];N.splice(N.indexOf(v),1),N.length===0&&delete this.sessions[u]}else{let N=new Error("Session closed without receiving a SETTINGS frame");N.code="HTTP2WRAPPER_NOSETTINGS";for(let{reject:U}of o)U(N);p()}this._tryToCreateNewSession(u,A)});let R=()=>{if(!(!(u in this.queue)||!x())){for(let N of v[Kl])if(N in this.queue[u]){let{listeners:U}=this.queue[u][N];for(;U.length!==0&&x();)U.shift().resolve(v);let V=this.queue[u];if(V[N].listeners.length===0&&(delete V[N],Object.keys(V).length===0)){delete this.queue[u];break}if(!x())break}}};v.on("origin",()=>{v[Kl]=v.originSet,x()&&(R(),KM(this.sessions[u],v))}),v.once("remoteSettings",()=>{if(v.ref(),v.unref(),this._sessionsCount++,h.destroyed){let N=new Error("Agent has been destroyed");for(let U of o)U.reject(N);v.destroy();return}v[Kl]=v.originSet;{let N=this.sessions;if(u in N){let U=N[u];U.splice($nt(U,v,eit),0,v)}else N[u]=[v]}this._freeSessionsCount+=1,I=!0,this.emit("session",v),R(),p(),v[ea]===0&&this._freeSessionsCount>this.maxFreeSessions&&v.close(),o.length!==0&&(this.getSession(A,r,o),o.length=0),v.on("remoteSettings",()=>{R(),KM(this.sessions[u],v)})}),v[joe]=v.request,v.request=(N,U)=>{if(v[DE])throw new Error("The session is gracefully closing. No new streams are allowed.");let V=v[joe](N,U);return v.ref(),++v[ea],v[ea]===v.remoteSettings.maxConcurrentStreams&&this._freeSessionsCount--,V.once("close",()=>{if(C=x(),--v[ea],!v.destroyed&&!v.closed&&(tit(this.sessions[u],v),x()&&!v.closed)){C||(this._freeSessionsCount++,C=!0);let te=v[ea]===0;te&&v.unref(),te&&(this._freeSessionsCount>this.maxFreeSessions||v[DE])?v.close():(KM(this.sessions[u],v),R())}}),V}}catch(v){for(let x of o)x.reject(v);p()}};h.listeners=o,h.completed=!1,h.destroyed=!1,this.queue[u][A]=h,this._tryToCreateNewSession(u,A)})}request(e,r,o,a){return new Promise((n,u)=>{this.getSession(e,r,[{reject:u,resolve:A=>{try{n(A.request(o,a))}catch(p){u(p)}}}])})}createConnection(e,r){return rA.connect(e,r)}static connect(e,r){r.ALPNProtocols=["h2"];let o=e.port||443,a=e.hostname||e.host;return typeof r.servername>"u"&&(r.servername=a),Vnt.connect(o,a,r)}closeFreeSessions(){for(let e of Object.values(this.sessions))for(let r of e)r[ea]===0&&r.close()}destroy(e){for(let r of Object.values(this.sessions))for(let o of r)o.destroy(e);for(let r of Object.values(this.queue))for(let o of Object.values(r))o.destroyed=!0;this.queue={}}get freeSessions(){return Yoe({agent:this,isFree:!0})}get busySessions(){return Yoe({agent:this,isFree:!1})}};rA.kCurrentStreamsCount=ea;rA.kGracefullyClosing=DE;Koe.exports={Agent:rA,globalAgent:new rA}});var JM=_((TNt,zoe)=>{"use strict";var{Readable:rit}=ve("stream"),VM=class extends rit{constructor(e,r){super({highWaterMark:r,autoDestroy:!1}),this.statusCode=null,this.statusMessage="",this.httpVersion="2.0",this.httpVersionMajor=2,this.httpVersionMinor=0,this.headers={},this.trailers={},this.req=null,this.aborted=!1,this.complete=!1,this.upgrade=null,this.rawHeaders=[],this.rawTrailers=[],this.socket=e,this.connection=e,this._dumped=!1}_destroy(e){this.req._request.destroy(e)}setTimeout(e,r){return this.req.setTimeout(e,r),this}_dump(){this._dumped||(this._dumped=!0,this.removeAllListeners("data"),this.resume())}_read(){this.req&&this.req._request.resume()}};zoe.exports=VM});var XM=_((LNt,Voe)=>{"use strict";Voe.exports=t=>{let e={protocol:t.protocol,hostname:typeof t.hostname=="string"&&t.hostname.startsWith("[")?t.hostname.slice(1,-1):t.hostname,host:t.host,hash:t.hash,search:t.search,pathname:t.pathname,href:t.href,path:`${t.pathname||""}${t.search||""}`};return typeof t.port=="string"&&t.port.length!==0&&(e.port=Number(t.port)),(t.username||t.password)&&(e.auth=`${t.username||""}:${t.password||""}`),e}});var Xoe=_((NNt,Joe)=>{"use strict";Joe.exports=(t,e,r)=>{for(let o of r)t.on(o,(...a)=>e.emit(o,...a))}});var $oe=_((ONt,Zoe)=>{"use strict";Zoe.exports=t=>{switch(t){case":method":case":scheme":case":authority":case":path":return!0;default:return!1}}});var tae=_((UNt,eae)=>{"use strict";var PE=(t,e,r)=>{eae.exports[e]=class extends t{constructor(...a){super(typeof r=="string"?r:r(a)),this.name=`${super.name} [${e}]`,this.code=e}}};PE(TypeError,"ERR_INVALID_ARG_TYPE",t=>{let e=t[0].includes(".")?"property":"argument",r=t[1],o=Array.isArray(r);return o&&(r=`${r.slice(0,-1).join(", ")} or ${r.slice(-1)}`),`The "${t[0]}" ${e} must be ${o?"one of":"of"} type ${r}. Received ${typeof t[2]}`});PE(TypeError,"ERR_INVALID_PROTOCOL",t=>`Protocol "${t[0]}" not supported. Expected "${t[1]}"`);PE(Error,"ERR_HTTP_HEADERS_SENT",t=>`Cannot ${t[0]} headers after they are sent to the client`);PE(TypeError,"ERR_INVALID_HTTP_TOKEN",t=>`${t[0]} must be a valid HTTP token [${t[1]}]`);PE(TypeError,"ERR_HTTP_INVALID_HEADER_VALUE",t=>`Invalid value "${t[0]} for header "${t[1]}"`);PE(TypeError,"ERR_INVALID_CHAR",t=>`Invalid character in ${t[0]} [${t[1]}]`)});var r4=_((_Nt,lae)=>{"use strict";var nit=ve("http2"),{Writable:iit}=ve("stream"),{Agent:rae,globalAgent:sit}=zM(),oit=JM(),ait=XM(),lit=Xoe(),cit=$oe(),{ERR_INVALID_ARG_TYPE:ZM,ERR_INVALID_PROTOCOL:uit,ERR_HTTP_HEADERS_SENT:nae,ERR_INVALID_HTTP_TOKEN:Ait,ERR_HTTP_INVALID_HEADER_VALUE:fit,ERR_INVALID_CHAR:pit}=tae(),{HTTP2_HEADER_STATUS:iae,HTTP2_HEADER_METHOD:sae,HTTP2_HEADER_PATH:oae,HTTP2_METHOD_CONNECT:hit}=nit.constants,Qo=Symbol("headers"),$M=Symbol("origin"),e4=Symbol("session"),aae=Symbol("options"),rb=Symbol("flushedHeaders"),h1=Symbol("jobs"),git=/^[\^`\-\w!#$%&*+.|~]+$/,dit=/[^\t\u0020-\u007E\u0080-\u00FF]/,t4=class extends iit{constructor(e,r,o){super({autoDestroy:!1});let a=typeof e=="string"||e instanceof URL;if(a&&(e=ait(e instanceof URL?e:new URL(e))),typeof r=="function"||r===void 0?(o=r,r=a?e:{...e}):r={...e,...r},r.h2session)this[e4]=r.h2session;else if(r.agent===!1)this.agent=new rae({maxFreeSessions:0});else if(typeof r.agent>"u"||r.agent===null)typeof r.createConnection=="function"?(this.agent=new rae({maxFreeSessions:0}),this.agent.createConnection=r.createConnection):this.agent=sit;else if(typeof r.agent.request=="function")this.agent=r.agent;else throw new ZM("options.agent",["Agent-like Object","undefined","false"],r.agent);if(r.protocol&&r.protocol!=="https:")throw new uit(r.protocol,"https:");let n=r.port||r.defaultPort||this.agent&&this.agent.defaultPort||443,u=r.hostname||r.host||"localhost";delete r.hostname,delete r.host,delete r.port;let{timeout:A}=r;if(r.timeout=void 0,this[Qo]=Object.create(null),this[h1]=[],this.socket=null,this.connection=null,this.method=r.method||"GET",this.path=r.path,this.res=null,this.aborted=!1,this.reusedSocket=!1,r.headers)for(let[p,h]of Object.entries(r.headers))this.setHeader(p,h);r.auth&&!("authorization"in this[Qo])&&(this[Qo].authorization="Basic "+Buffer.from(r.auth).toString("base64")),r.session=r.tlsSession,r.path=r.socketPath,this[aae]=r,n===443?(this[$M]=`https://${u}`,":authority"in this[Qo]||(this[Qo][":authority"]=u)):(this[$M]=`https://${u}:${n}`,":authority"in this[Qo]||(this[Qo][":authority"]=`${u}:${n}`)),A&&this.setTimeout(A),o&&this.once("response",o),this[rb]=!1}get method(){return this[Qo][sae]}set method(e){e&&(this[Qo][sae]=e.toUpperCase())}get path(){return this[Qo][oae]}set path(e){e&&(this[Qo][oae]=e)}get _mustNotHaveABody(){return this.method==="GET"||this.method==="HEAD"||this.method==="DELETE"}_write(e,r,o){if(this._mustNotHaveABody){o(new Error("The GET, HEAD and DELETE methods must NOT have a body"));return}this.flushHeaders();let a=()=>this._request.write(e,r,o);this._request?a():this[h1].push(a)}_final(e){if(this.destroyed)return;this.flushHeaders();let r=()=>{if(this._mustNotHaveABody){e();return}this._request.end(e)};this._request?r():this[h1].push(r)}abort(){this.res&&this.res.complete||(this.aborted||process.nextTick(()=>this.emit("abort")),this.aborted=!0,this.destroy())}_destroy(e,r){this.res&&this.res._dump(),this._request&&this._request.destroy(),r(e)}async flushHeaders(){if(this[rb]||this.destroyed)return;this[rb]=!0;let e=this.method===hit,r=o=>{if(this._request=o,this.destroyed){o.destroy();return}e||lit(o,this,["timeout","continue","close","error"]);let a=u=>(...A)=>{!this.writable&&!this.destroyed?u(...A):this.once("finish",()=>{u(...A)})};o.once("response",a((u,A,p)=>{let h=new oit(this.socket,o.readableHighWaterMark);this.res=h,h.req=this,h.statusCode=u[iae],h.headers=u,h.rawHeaders=p,h.once("end",()=>{this.aborted?(h.aborted=!0,h.emit("aborted")):(h.complete=!0,h.socket=null,h.connection=null)}),e?(h.upgrade=!0,this.emit("connect",h,o,Buffer.alloc(0))?this.emit("close"):o.destroy()):(o.on("data",E=>{!h._dumped&&!h.push(E)&&o.pause()}),o.once("end",()=>{h.push(null)}),this.emit("response",h)||h._dump())})),o.once("headers",a(u=>this.emit("information",{statusCode:u[iae]}))),o.once("trailers",a((u,A,p)=>{let{res:h}=this;h.trailers=u,h.rawTrailers=p}));let{socket:n}=o.session;this.socket=n,this.connection=n;for(let u of this[h1])u();this.emit("socket",this.socket)};if(this[e4])try{r(this[e4].request(this[Qo]))}catch(o){this.emit("error",o)}else{this.reusedSocket=!0;try{r(await this.agent.request(this[$M],this[aae],this[Qo]))}catch(o){this.emit("error",o)}}}getHeader(e){if(typeof e!="string")throw new ZM("name","string",e);return this[Qo][e.toLowerCase()]}get headersSent(){return this[rb]}removeHeader(e){if(typeof e!="string")throw new ZM("name","string",e);if(this.headersSent)throw new nae("remove");delete this[Qo][e.toLowerCase()]}setHeader(e,r){if(this.headersSent)throw new nae("set");if(typeof e!="string"||!git.test(e)&&!cit(e))throw new Ait("Header name",e);if(typeof r>"u")throw new fit(r,e);if(dit.test(r))throw new pit("header content",e);this[Qo][e.toLowerCase()]=r}setNoDelay(){}setSocketKeepAlive(){}setTimeout(e,r){let o=()=>this._request.setTimeout(e,r);return this._request?o():this[h1].push(o),this}get maxHeadersCount(){if(!this.destroyed&&this._request)return this._request.session.localSettings.maxHeaderListSize}set maxHeadersCount(e){}};lae.exports=t4});var uae=_((HNt,cae)=>{"use strict";var mit=ve("tls");cae.exports=(t={},e=mit.connect)=>new Promise((r,o)=>{let a=!1,n,u=async()=>{await p,n.off("timeout",A),n.off("error",o),t.resolveSocket?(r({alpnProtocol:n.alpnProtocol,socket:n,timeout:a}),a&&(await Promise.resolve(),n.emit("timeout"))):(n.destroy(),r({alpnProtocol:n.alpnProtocol,timeout:a}))},A=async()=>{a=!0,u()},p=(async()=>{try{n=await e(t,u),n.on("error",o),n.once("timeout",A)}catch(h){o(h)}})()})});var fae=_((qNt,Aae)=>{"use strict";var yit=ve("net");Aae.exports=t=>{let e=t.host,r=t.headers&&t.headers.host;return r&&(r.startsWith("[")?r.indexOf("]")===-1?e=r:e=r.slice(1,-1):e=r.split(":",1)[0]),yit.isIP(e)?"":e}});var gae=_((GNt,i4)=>{"use strict";var pae=ve("http"),n4=ve("https"),Eit=uae(),Cit=WM(),wit=r4(),Iit=fae(),Bit=XM(),nb=new Cit({maxSize:100}),g1=new Map,hae=(t,e,r)=>{e._httpMessage={shouldKeepAlive:!0};let o=()=>{t.emit("free",e,r)};e.on("free",o);let a=()=>{t.removeSocket(e,r)};e.on("close",a);let n=()=>{t.removeSocket(e,r),e.off("close",a),e.off("free",o),e.off("agentRemove",n)};e.on("agentRemove",n),t.emit("free",e,r)},vit=async t=>{let e=`${t.host}:${t.port}:${t.ALPNProtocols.sort()}`;if(!nb.has(e)){if(g1.has(e))return(await g1.get(e)).alpnProtocol;let{path:r,agent:o}=t;t.path=t.socketPath;let a=Eit(t);g1.set(e,a);try{let{socket:n,alpnProtocol:u}=await a;if(nb.set(e,u),t.path=r,u==="h2")n.destroy();else{let{globalAgent:A}=n4,p=n4.Agent.prototype.createConnection;o?o.createConnection===p?hae(o,n,t):n.destroy():A.createConnection===p?hae(A,n,t):n.destroy()}return g1.delete(e),u}catch(n){throw g1.delete(e),n}}return nb.get(e)};i4.exports=async(t,e,r)=>{if((typeof t=="string"||t instanceof URL)&&(t=Bit(new URL(t))),typeof e=="function"&&(r=e,e=void 0),e={ALPNProtocols:["h2","http/1.1"],...t,...e,resolveSocket:!0},!Array.isArray(e.ALPNProtocols)||e.ALPNProtocols.length===0)throw new Error("The `ALPNProtocols` option must be an Array with at least one entry");e.protocol=e.protocol||"https:";let o=e.protocol==="https:";e.host=e.hostname||e.host||"localhost",e.session=e.tlsSession,e.servername=e.servername||Iit(e),e.port=e.port||(o?443:80),e._defaultAgent=o?n4.globalAgent:pae.globalAgent;let a=e.agent;if(a){if(a.addRequest)throw new Error("The `options.agent` object can contain only `http`, `https` or `http2` properties");e.agent=a[o?"https":"http"]}return o&&await vit(e)==="h2"?(a&&(e.agent=a.http2),new wit(e,r)):pae.request(e,r)};i4.exports.protocolCache=nb});var mae=_((jNt,dae)=>{"use strict";var Dit=ve("http2"),Pit=zM(),s4=r4(),Sit=JM(),bit=gae(),xit=(t,e,r)=>new s4(t,e,r),kit=(t,e,r)=>{let o=new s4(t,e,r);return o.end(),o};dae.exports={...Dit,ClientRequest:s4,IncomingMessage:Sit,...Pit,request:xit,get:kit,auto:bit}});var a4=_(o4=>{"use strict";Object.defineProperty(o4,"__esModule",{value:!0});var yae=Tf();o4.default=t=>yae.default.nodeStream(t)&&yae.default.function_(t.getBoundary)});var Iae=_(l4=>{"use strict";Object.defineProperty(l4,"__esModule",{value:!0});var Cae=ve("fs"),wae=ve("util"),Eae=Tf(),Qit=a4(),Fit=wae.promisify(Cae.stat);l4.default=async(t,e)=>{if(e&&"content-length"in e)return Number(e["content-length"]);if(!t)return 0;if(Eae.default.string(t))return Buffer.byteLength(t);if(Eae.default.buffer(t))return t.length;if(Qit.default(t))return wae.promisify(t.getLength.bind(t))();if(t instanceof Cae.ReadStream){let{size:r}=await Fit(t.path);return r===0?void 0:r}}});var u4=_(c4=>{"use strict";Object.defineProperty(c4,"__esModule",{value:!0});function Rit(t,e,r){let o={};for(let a of r)o[a]=(...n)=>{e.emit(a,...n)},t.on(a,o[a]);return()=>{for(let a of r)t.off(a,o[a])}}c4.default=Rit});var Bae=_(A4=>{"use strict";Object.defineProperty(A4,"__esModule",{value:!0});A4.default=()=>{let t=[];return{once(e,r,o){e.once(r,o),t.push({origin:e,event:r,fn:o})},unhandleAll(){for(let e of t){let{origin:r,event:o,fn:a}=e;r.removeListener(o,a)}t.length=0}}}});var Dae=_(d1=>{"use strict";Object.defineProperty(d1,"__esModule",{value:!0});d1.TimeoutError=void 0;var Tit=ve("net"),Lit=Bae(),vae=Symbol("reentry"),Nit=()=>{},ib=class extends Error{constructor(e,r){super(`Timeout awaiting '${r}' for ${e}ms`),this.event=r,this.name="TimeoutError",this.code="ETIMEDOUT"}};d1.TimeoutError=ib;d1.default=(t,e,r)=>{if(vae in t)return Nit;t[vae]=!0;let o=[],{once:a,unhandleAll:n}=Lit.default(),u=(I,v,x)=>{var C;let R=setTimeout(v,I,I,x);(C=R.unref)===null||C===void 0||C.call(R);let N=()=>{clearTimeout(R)};return o.push(N),N},{host:A,hostname:p}=r,h=(I,v)=>{t.destroy(new ib(I,v))},E=()=>{for(let I of o)I();n()};if(t.once("error",I=>{if(E(),t.listenerCount("error")===0)throw I}),t.once("close",E),a(t,"response",I=>{a(I,"end",E)}),typeof e.request<"u"&&u(e.request,h,"request"),typeof e.socket<"u"){let I=()=>{h(e.socket,"socket")};t.setTimeout(e.socket,I),o.push(()=>{t.removeListener("timeout",I)})}return a(t,"socket",I=>{var v;let{socketPath:x}=t;if(I.connecting){let C=Boolean(x??Tit.isIP((v=p??A)!==null&&v!==void 0?v:"")!==0);if(typeof e.lookup<"u"&&!C&&typeof I.address().address>"u"){let R=u(e.lookup,h,"lookup");a(I,"lookup",R)}if(typeof e.connect<"u"){let R=()=>u(e.connect,h,"connect");C?a(I,"connect",R()):a(I,"lookup",N=>{N===null&&a(I,"connect",R())})}typeof e.secureConnect<"u"&&r.protocol==="https:"&&a(I,"connect",()=>{let R=u(e.secureConnect,h,"secureConnect");a(I,"secureConnect",R)})}if(typeof e.send<"u"){let C=()=>u(e.send,h,"send");I.connecting?a(I,"connect",()=>{a(t,"upload-complete",C())}):a(t,"upload-complete",C())}}),typeof e.response<"u"&&a(t,"upload-complete",()=>{let I=u(e.response,h,"response");a(t,"response",I)}),E}});var Sae=_(f4=>{"use strict";Object.defineProperty(f4,"__esModule",{value:!0});var Pae=Tf();f4.default=t=>{t=t;let e={protocol:t.protocol,hostname:Pae.default.string(t.hostname)&&t.hostname.startsWith("[")?t.hostname.slice(1,-1):t.hostname,host:t.host,hash:t.hash,search:t.search,pathname:t.pathname,href:t.href,path:`${t.pathname||""}${t.search||""}`};return Pae.default.string(t.port)&&t.port.length>0&&(e.port=Number(t.port)),(t.username||t.password)&&(e.auth=`${t.username||""}:${t.password||""}`),e}});var bae=_(p4=>{"use strict";Object.defineProperty(p4,"__esModule",{value:!0});var Oit=ve("url"),Mit=["protocol","host","hostname","port","pathname","search"];p4.default=(t,e)=>{var r,o;if(e.path){if(e.pathname)throw new TypeError("Parameters `path` and `pathname` are mutually exclusive.");if(e.search)throw new TypeError("Parameters `path` and `search` are mutually exclusive.");if(e.searchParams)throw new TypeError("Parameters `path` and `searchParams` are mutually exclusive.")}if(e.search&&e.searchParams)throw new TypeError("Parameters `search` and `searchParams` are mutually exclusive.");if(!t){if(!e.protocol)throw new TypeError("No URL protocol specified");t=`${e.protocol}//${(o=(r=e.hostname)!==null&&r!==void 0?r:e.host)!==null&&o!==void 0?o:""}`}let a=new Oit.URL(t);if(e.path){let n=e.path.indexOf("?");n===-1?e.pathname=e.path:(e.pathname=e.path.slice(0,n),e.search=e.path.slice(n+1)),delete e.path}for(let n of Mit)e[n]&&(a[n]=e[n].toString());return a}});var xae=_(g4=>{"use strict";Object.defineProperty(g4,"__esModule",{value:!0});var h4=class{constructor(){this.weakMap=new WeakMap,this.map=new Map}set(e,r){typeof e=="object"?this.weakMap.set(e,r):this.map.set(e,r)}get(e){return typeof e=="object"?this.weakMap.get(e):this.map.get(e)}has(e){return typeof e=="object"?this.weakMap.has(e):this.map.has(e)}};g4.default=h4});var m4=_(d4=>{"use strict";Object.defineProperty(d4,"__esModule",{value:!0});var Uit=async t=>{let e=[],r=0;for await(let o of t)e.push(o),r+=Buffer.byteLength(o);return Buffer.isBuffer(e[0])?Buffer.concat(e,r):Buffer.from(e.join(""))};d4.default=Uit});var Qae=_(bd=>{"use strict";Object.defineProperty(bd,"__esModule",{value:!0});bd.dnsLookupIpVersionToFamily=bd.isDnsLookupIpVersion=void 0;var kae={auto:0,ipv4:4,ipv6:6};bd.isDnsLookupIpVersion=t=>t in kae;bd.dnsLookupIpVersionToFamily=t=>{if(bd.isDnsLookupIpVersion(t))return kae[t];throw new Error("Invalid DNS lookup IP version")}});var y4=_(sb=>{"use strict";Object.defineProperty(sb,"__esModule",{value:!0});sb.isResponseOk=void 0;sb.isResponseOk=t=>{let{statusCode:e}=t,r=t.request.options.followRedirect?299:399;return e>=200&&e<=r||e===304}});var Rae=_(E4=>{"use strict";Object.defineProperty(E4,"__esModule",{value:!0});var Fae=new Set;E4.default=t=>{Fae.has(t)||(Fae.add(t),process.emitWarning(`Got: ${t}`,{type:"DeprecationWarning"}))}});var Tae=_(C4=>{"use strict";Object.defineProperty(C4,"__esModule",{value:!0});var Ai=Tf(),_it=(t,e)=>{if(Ai.default.null_(t.encoding))throw new TypeError("To get a Buffer, set `options.responseType` to `buffer` instead");Ai.assert.any([Ai.default.string,Ai.default.undefined],t.encoding),Ai.assert.any([Ai.default.boolean,Ai.default.undefined],t.resolveBodyOnly),Ai.assert.any([Ai.default.boolean,Ai.default.undefined],t.methodRewriting),Ai.assert.any([Ai.default.boolean,Ai.default.undefined],t.isStream),Ai.assert.any([Ai.default.string,Ai.default.undefined],t.responseType),t.responseType===void 0&&(t.responseType="text");let{retry:r}=t;if(e?t.retry={...e.retry}:t.retry={calculateDelay:o=>o.computedValue,limit:0,methods:[],statusCodes:[],errorCodes:[],maxRetryAfter:void 0},Ai.default.object(r)?(t.retry={...t.retry,...r},t.retry.methods=[...new Set(t.retry.methods.map(o=>o.toUpperCase()))],t.retry.statusCodes=[...new Set(t.retry.statusCodes)],t.retry.errorCodes=[...new Set(t.retry.errorCodes)]):Ai.default.number(r)&&(t.retry.limit=r),Ai.default.undefined(t.retry.maxRetryAfter)&&(t.retry.maxRetryAfter=Math.min(...[t.timeout.request,t.timeout.connect].filter(Ai.default.number))),Ai.default.object(t.pagination)){e&&(t.pagination={...e.pagination,...t.pagination});let{pagination:o}=t;if(!Ai.default.function_(o.transform))throw new Error("`options.pagination.transform` must be implemented");if(!Ai.default.function_(o.shouldContinue))throw new Error("`options.pagination.shouldContinue` must be implemented");if(!Ai.default.function_(o.filter))throw new TypeError("`options.pagination.filter` must be implemented");if(!Ai.default.function_(o.paginate))throw new Error("`options.pagination.paginate` must be implemented")}return t.responseType==="json"&&t.headers.accept===void 0&&(t.headers.accept="application/json"),t};C4.default=_it});var Lae=_(m1=>{"use strict";Object.defineProperty(m1,"__esModule",{value:!0});m1.retryAfterStatusCodes=void 0;m1.retryAfterStatusCodes=new Set([413,429,503]);var Hit=({attemptCount:t,retryOptions:e,error:r,retryAfter:o})=>{if(t>e.limit)return 0;let a=e.methods.includes(r.options.method),n=e.errorCodes.includes(r.code),u=r.response&&e.statusCodes.includes(r.response.statusCode);if(!a||!n&&!u)return 0;if(r.response){if(o)return e.maxRetryAfter===void 0||o>e.maxRetryAfter?0:o;if(r.response.statusCode===413)return 0}let A=Math.random()*100;return 2**(t-1)*1e3+A};m1.default=Hit});var C1=_(Bn=>{"use strict";Object.defineProperty(Bn,"__esModule",{value:!0});Bn.UnsupportedProtocolError=Bn.ReadError=Bn.TimeoutError=Bn.UploadError=Bn.CacheError=Bn.HTTPError=Bn.MaxRedirectsError=Bn.RequestError=Bn.setNonEnumerableProperties=Bn.knownHookEvents=Bn.withoutBody=Bn.kIsNormalizedAlready=void 0;var Nae=ve("util"),Oae=ve("stream"),qit=ve("fs"),lh=ve("url"),Mae=ve("http"),w4=ve("http"),Git=ve("https"),jit=Zse(),Yit=soe(),Uae=Moe(),Wit=qoe(),Kit=mae(),zit=eb(),st=Tf(),Vit=Iae(),_ae=a4(),Jit=u4(),Hae=Dae(),Xit=Sae(),qae=bae(),Zit=xae(),$it=m4(),Gae=Qae(),est=y4(),ch=Rae(),tst=Tae(),rst=Lae(),I4,Zs=Symbol("request"),lb=Symbol("response"),SE=Symbol("responseSize"),bE=Symbol("downloadedSize"),xE=Symbol("bodySize"),kE=Symbol("uploadedSize"),ob=Symbol("serverResponsesPiped"),jae=Symbol("unproxyEvents"),Yae=Symbol("isFromCache"),B4=Symbol("cancelTimeouts"),Wae=Symbol("startedReading"),QE=Symbol("stopReading"),ab=Symbol("triggerRead"),uh=Symbol("body"),y1=Symbol("jobs"),Kae=Symbol("originalResponse"),zae=Symbol("retryTimeout");Bn.kIsNormalizedAlready=Symbol("isNormalizedAlready");var nst=st.default.string(process.versions.brotli);Bn.withoutBody=new Set(["GET","HEAD"]);Bn.knownHookEvents=["init","beforeRequest","beforeRedirect","beforeError","beforeRetry","afterResponse"];function ist(t){for(let e in t){let r=t[e];if(!st.default.string(r)&&!st.default.number(r)&&!st.default.boolean(r)&&!st.default.null_(r)&&!st.default.undefined(r))throw new TypeError(`The \`searchParams\` value '${String(r)}' must be a string, number, boolean or null`)}}function sst(t){return st.default.object(t)&&!("statusCode"in t)}var v4=new Zit.default,ost=async t=>new Promise((e,r)=>{let o=a=>{r(a)};t.pending||e(),t.once("error",o),t.once("ready",()=>{t.off("error",o),e()})}),ast=new Set([300,301,302,303,304,307,308]),lst=["context","body","json","form"];Bn.setNonEnumerableProperties=(t,e)=>{let r={};for(let o of t)if(!!o)for(let a of lst)a in o&&(r[a]={writable:!0,configurable:!0,enumerable:!1,value:o[a]});Object.defineProperties(e,r)};var zi=class extends Error{constructor(e,r,o){var a;if(super(e),Error.captureStackTrace(this,this.constructor),this.name="RequestError",this.code=r.code,o instanceof db?(Object.defineProperty(this,"request",{enumerable:!1,value:o}),Object.defineProperty(this,"response",{enumerable:!1,value:o[lb]}),Object.defineProperty(this,"options",{enumerable:!1,value:o.options})):Object.defineProperty(this,"options",{enumerable:!1,value:o}),this.timings=(a=this.request)===null||a===void 0?void 0:a.timings,st.default.string(r.stack)&&st.default.string(this.stack)){let n=this.stack.indexOf(this.message)+this.message.length,u=this.stack.slice(n).split(`
-`).reverse(),A=r.stack.slice(r.stack.indexOf(r.message)+r.message.length).split(`
-`).reverse();for(;A.length!==0&&A[0]===u[0];)u.shift();this.stack=`${this.stack.slice(0,n)}${u.reverse().join(`
-`)}${A.reverse().join(`
-`)}`}}};Bn.RequestError=zi;var ub=class extends zi{constructor(e){super(`Redirected ${e.options.maxRedirects} times. Aborting.`,{},e),this.name="MaxRedirectsError"}};Bn.MaxRedirectsError=ub;var Ab=class extends zi{constructor(e){super(`Response code ${e.statusCode} (${e.statusMessage})`,{},e.request),this.name="HTTPError"}};Bn.HTTPError=Ab;var fb=class extends zi{constructor(e,r){super(e.message,e,r),this.name="CacheError"}};Bn.CacheError=fb;var pb=class extends zi{constructor(e,r){super(e.message,e,r),this.name="UploadError"}};Bn.UploadError=pb;var hb=class extends zi{constructor(e,r,o){super(e.message,e,o),this.name="TimeoutError",this.event=e.event,this.timings=r}};Bn.TimeoutError=hb;var E1=class extends zi{constructor(e,r){super(e.message,e,r),this.name="ReadError"}};Bn.ReadError=E1;var gb=class extends zi{constructor(e){super(`Unsupported protocol "${e.url.protocol}"`,{},e),this.name="UnsupportedProtocolError"}};Bn.UnsupportedProtocolError=gb;var cst=["socket","connect","continue","information","upgrade","timeout"],db=class extends Oae.Duplex{constructor(e,r={},o){super({autoDestroy:!1,highWaterMark:0}),this[bE]=0,this[kE]=0,this.requestInitialized=!1,this[ob]=new Set,this.redirects=[],this[QE]=!1,this[ab]=!1,this[y1]=[],this.retryCount=0,this._progressCallbacks=[];let a=()=>this._unlockWrite(),n=()=>this._lockWrite();this.on("pipe",h=>{h.prependListener("data",a),h.on("data",n),h.prependListener("end",a),h.on("end",n)}),this.on("unpipe",h=>{h.off("data",a),h.off("data",n),h.off("end",a),h.off("end",n)}),this.on("pipe",h=>{h instanceof w4.IncomingMessage&&(this.options.headers={...h.headers,...this.options.headers})});let{json:u,body:A,form:p}=r;if((u||A||p)&&this._lockWrite(),Bn.kIsNormalizedAlready in r)this.options=r;else try{this.options=this.constructor.normalizeArguments(e,r,o)}catch(h){st.default.nodeStream(r.body)&&r.body.destroy(),this.destroy(h);return}(async()=>{var h;try{this.options.body instanceof qit.ReadStream&&await ost(this.options.body);let{url:E}=this.options;if(!E)throw new TypeError("Missing `url` property");if(this.requestUrl=E.toString(),decodeURI(this.requestUrl),await this._finalizeBody(),await this._makeRequest(),this.destroyed){(h=this[Zs])===null||h===void 0||h.destroy();return}for(let I of this[y1])I();this[y1].length=0,this.requestInitialized=!0}catch(E){if(E instanceof zi){this._beforeError(E);return}this.destroyed||this.destroy(E)}})()}static normalizeArguments(e,r,o){var a,n,u,A,p;let h=r;if(st.default.object(e)&&!st.default.urlInstance(e))r={...o,...e,...r};else{if(e&&r&&r.url!==void 0)throw new TypeError("The `url` option is mutually exclusive with the `input` argument");r={...o,...r},e!==void 0&&(r.url=e),st.default.urlInstance(r.url)&&(r.url=new lh.URL(r.url.toString()))}if(r.cache===!1&&(r.cache=void 0),r.dnsCache===!1&&(r.dnsCache=void 0),st.assert.any([st.default.string,st.default.undefined],r.method),st.assert.any([st.default.object,st.default.undefined],r.headers),st.assert.any([st.default.string,st.default.urlInstance,st.default.undefined],r.prefixUrl),st.assert.any([st.default.object,st.default.undefined],r.cookieJar),st.assert.any([st.default.object,st.default.string,st.default.undefined],r.searchParams),st.assert.any([st.default.object,st.default.string,st.default.undefined],r.cache),st.assert.any([st.default.object,st.default.number,st.default.undefined],r.timeout),st.assert.any([st.default.object,st.default.undefined],r.context),st.assert.any([st.default.object,st.default.undefined],r.hooks),st.assert.any([st.default.boolean,st.default.undefined],r.decompress),st.assert.any([st.default.boolean,st.default.undefined],r.ignoreInvalidCookies),st.assert.any([st.default.boolean,st.default.undefined],r.followRedirect),st.assert.any([st.default.number,st.default.undefined],r.maxRedirects),st.assert.any([st.default.boolean,st.default.undefined],r.throwHttpErrors),st.assert.any([st.default.boolean,st.default.undefined],r.http2),st.assert.any([st.default.boolean,st.default.undefined],r.allowGetBody),st.assert.any([st.default.string,st.default.undefined],r.localAddress),st.assert.any([Gae.isDnsLookupIpVersion,st.default.undefined],r.dnsLookupIpVersion),st.assert.any([st.default.object,st.default.undefined],r.https),st.assert.any([st.default.boolean,st.default.undefined],r.rejectUnauthorized),r.https&&(st.assert.any([st.default.boolean,st.default.undefined],r.https.rejectUnauthorized),st.assert.any([st.default.function_,st.default.undefined],r.https.checkServerIdentity),st.assert.any([st.default.string,st.default.object,st.default.array,st.default.undefined],r.https.certificateAuthority),st.assert.any([st.default.string,st.default.object,st.default.array,st.default.undefined],r.https.key),st.assert.any([st.default.string,st.default.object,st.default.array,st.default.undefined],r.https.certificate),st.assert.any([st.default.string,st.default.undefined],r.https.passphrase),st.assert.any([st.default.string,st.default.buffer,st.default.array,st.default.undefined],r.https.pfx)),st.assert.any([st.default.object,st.default.undefined],r.cacheOptions),st.default.string(r.method)?r.method=r.method.toUpperCase():r.method="GET",r.headers===o?.headers?r.headers={...r.headers}:r.headers=zit({...o?.headers,...r.headers}),"slashes"in r)throw new TypeError("The legacy `url.Url` has been deprecated. Use `URL` instead.");if("auth"in r)throw new TypeError("Parameter `auth` is deprecated. Use `username` / `password` instead.");if("searchParams"in r&&r.searchParams&&r.searchParams!==o?.searchParams){let x;if(st.default.string(r.searchParams)||r.searchParams instanceof lh.URLSearchParams)x=new lh.URLSearchParams(r.searchParams);else{ist(r.searchParams),x=new lh.URLSearchParams;for(let C in r.searchParams){let R=r.searchParams[C];R===null?x.append(C,""):R!==void 0&&x.append(C,R)}}(a=o?.searchParams)===null||a===void 0||a.forEach((C,R)=>{x.has(R)||x.append(R,C)}),r.searchParams=x}if(r.username=(n=r.username)!==null&&n!==void 0?n:"",r.password=(u=r.password)!==null&&u!==void 0?u:"",st.default.undefined(r.prefixUrl)?r.prefixUrl=(A=o?.prefixUrl)!==null&&A!==void 0?A:"":(r.prefixUrl=r.prefixUrl.toString(),r.prefixUrl!==""&&!r.prefixUrl.endsWith("/")&&(r.prefixUrl+="/")),st.default.string(r.url)){if(r.url.startsWith("/"))throw new Error("`input` must not start with a slash when using `prefixUrl`");r.url=qae.default(r.prefixUrl+r.url,r)}else(st.default.undefined(r.url)&&r.prefixUrl!==""||r.protocol)&&(r.url=qae.default(r.prefixUrl,r));if(r.url){"port"in r&&delete r.port;let{prefixUrl:x}=r;Object.defineProperty(r,"prefixUrl",{set:R=>{let N=r.url;if(!N.href.startsWith(R))throw new Error(`Cannot change \`prefixUrl\` from ${x} to ${R}: ${N.href}`);r.url=new lh.URL(R+N.href.slice(x.length)),x=R},get:()=>x});let{protocol:C}=r.url;if(C==="unix:"&&(C="http:",r.url=new lh.URL(`http://unix${r.url.pathname}${r.url.search}`)),r.searchParams&&(r.url.search=r.searchParams.toString()),C!=="http:"&&C!=="https:")throw new gb(r);r.username===""?r.username=r.url.username:r.url.username=r.username,r.password===""?r.password=r.url.password:r.url.password=r.password}let{cookieJar:E}=r;if(E){let{setCookie:x,getCookieString:C}=E;st.assert.function_(x),st.assert.function_(C),x.length===4&&C.length===0&&(x=Nae.promisify(x.bind(r.cookieJar)),C=Nae.promisify(C.bind(r.cookieJar)),r.cookieJar={setCookie:x,getCookieString:C})}let{cache:I}=r;if(I&&(v4.has(I)||v4.set(I,new Uae((x,C)=>{let R=x[Zs](x,C);return st.default.promise(R)&&(R.once=(N,U)=>{if(N==="error")R.catch(U);else if(N==="abort")(async()=>{try{(await R).once("abort",U)}catch{}})();else throw new Error(`Unknown HTTP2 promise event: ${N}`);return R}),R},I))),r.cacheOptions={...r.cacheOptions},r.dnsCache===!0)I4||(I4=new Yit.default),r.dnsCache=I4;else if(!st.default.undefined(r.dnsCache)&&!r.dnsCache.lookup)throw new TypeError(`Parameter \`dnsCache\` must be a CacheableLookup instance or a boolean, got ${st.default(r.dnsCache)}`);st.default.number(r.timeout)?r.timeout={request:r.timeout}:o&&r.timeout!==o.timeout?r.timeout={...o.timeout,...r.timeout}:r.timeout={...r.timeout},r.context||(r.context={});let v=r.hooks===o?.hooks;r.hooks={...r.hooks};for(let x of Bn.knownHookEvents)if(x in r.hooks)if(st.default.array(r.hooks[x]))r.hooks[x]=[...r.hooks[x]];else throw new TypeError(`Parameter \`${x}\` must be an Array, got ${st.default(r.hooks[x])}`);else r.hooks[x]=[];if(o&&!v)for(let x of Bn.knownHookEvents)o.hooks[x].length>0&&(r.hooks[x]=[...o.hooks[x],...r.hooks[x]]);if("family"in r&&ch.default('"options.family" was never documented, please use "options.dnsLookupIpVersion"'),o?.https&&(r.https={...o.https,...r.https}),"rejectUnauthorized"in r&&ch.default('"options.rejectUnauthorized" is now deprecated, please use "options.https.rejectUnauthorized"'),"checkServerIdentity"in r&&ch.default('"options.checkServerIdentity" was never documented, please use "options.https.checkServerIdentity"'),"ca"in r&&ch.default('"options.ca" was never documented, please use "options.https.certificateAuthority"'),"key"in r&&ch.default('"options.key" was never documented, please use "options.https.key"'),"cert"in r&&ch.default('"options.cert" was never documented, please use "options.https.certificate"'),"passphrase"in r&&ch.default('"options.passphrase" was never documented, please use "options.https.passphrase"'),"pfx"in r&&ch.default('"options.pfx" was never documented, please use "options.https.pfx"'),"followRedirects"in r)throw new TypeError("The `followRedirects` option does not exist. Use `followRedirect` instead.");if(r.agent){for(let x in r.agent)if(x!=="http"&&x!=="https"&&x!=="http2")throw new TypeError(`Expected the \`options.agent\` properties to be \`http\`, \`https\` or \`http2\`, got \`${x}\``)}return r.maxRedirects=(p=r.maxRedirects)!==null&&p!==void 0?p:0,Bn.setNonEnumerableProperties([o,h],r),tst.default(r,o)}_lockWrite(){let e=()=>{throw new TypeError("The payload has been already provided")};this.write=e,this.end=e}_unlockWrite(){this.write=super.write,this.end=super.end}async _finalizeBody(){let{options:e}=this,{headers:r}=e,o=!st.default.undefined(e.form),a=!st.default.undefined(e.json),n=!st.default.undefined(e.body),u=o||a||n,A=Bn.withoutBody.has(e.method)&&!(e.method==="GET"&&e.allowGetBody);if(this._cannotHaveBody=A,u){if(A)throw new TypeError(`The \`${e.method}\` method cannot be used with a body`);if([n,o,a].filter(p=>p).length>1)throw new TypeError("The `body`, `json` and `form` options are mutually exclusive");if(n&&!(e.body instanceof Oae.Readable)&&!st.default.string(e.body)&&!st.default.buffer(e.body)&&!_ae.default(e.body))throw new TypeError("The `body` option must be a stream.Readable, string or Buffer");if(o&&!st.default.object(e.form))throw new TypeError("The `form` option must be an Object");{let p=!st.default.string(r["content-type"]);n?(_ae.default(e.body)&&p&&(r["content-type"]=`multipart/form-data; boundary=${e.body.getBoundary()}`),this[uh]=e.body):o?(p&&(r["content-type"]="application/x-www-form-urlencoded"),this[uh]=new lh.URLSearchParams(e.form).toString()):(p&&(r["content-type"]="application/json"),this[uh]=e.stringifyJson(e.json));let h=await Vit.default(this[uh],e.headers);st.default.undefined(r["content-length"])&&st.default.undefined(r["transfer-encoding"])&&!A&&!st.default.undefined(h)&&(r["content-length"]=String(h))}}else A?this._lockWrite():this._unlockWrite();this[xE]=Number(r["content-length"])||void 0}async _onResponseBase(e){let{options:r}=this,{url:o}=r;this[Kae]=e,r.decompress&&(e=Wit(e));let a=e.statusCode,n=e;n.statusMessage=n.statusMessage?n.statusMessage:Mae.STATUS_CODES[a],n.url=r.url.toString(),n.requestUrl=this.requestUrl,n.redirectUrls=this.redirects,n.request=this,n.isFromCache=e.fromCache||!1,n.ip=this.ip,n.retryCount=this.retryCount,this[Yae]=n.isFromCache,this[SE]=Number(e.headers["content-length"])||void 0,this[lb]=e,e.once("end",()=>{this[SE]=this[bE],this.emit("downloadProgress",this.downloadProgress)}),e.once("error",A=>{e.destroy(),this._beforeError(new E1(A,this))}),e.once("aborted",()=>{this._beforeError(new E1({name:"Error",message:"The server aborted pending request",code:"ECONNRESET"},this))}),this.emit("downloadProgress",this.downloadProgress);let u=e.headers["set-cookie"];if(st.default.object(r.cookieJar)&&u){let A=u.map(async p=>r.cookieJar.setCookie(p,o.toString()));r.ignoreInvalidCookies&&(A=A.map(async p=>p.catch(()=>{})));try{await Promise.all(A)}catch(p){this._beforeError(p);return}}if(r.followRedirect&&e.headers.location&&ast.has(a)){if(e.resume(),this[Zs]&&(this[B4](),delete this[Zs],this[jae]()),(a===303&&r.method!=="GET"&&r.method!=="HEAD"||!r.methodRewriting)&&(r.method="GET","body"in r&&delete r.body,"json"in r&&delete r.json,"form"in r&&delete r.form,this[uh]=void 0,delete r.headers["content-length"]),this.redirects.length>=r.maxRedirects){this._beforeError(new ub(this));return}try{let p=Buffer.from(e.headers.location,"binary").toString(),h=new lh.URL(p,o),E=h.toString();decodeURI(E),h.hostname!==o.hostname||h.port!==o.port?("host"in r.headers&&delete r.headers.host,"cookie"in r.headers&&delete r.headers.cookie,"authorization"in r.headers&&delete r.headers.authorization,(r.username||r.password)&&(r.username="",r.password="")):(h.username=r.username,h.password=r.password),this.redirects.push(E),r.url=h;for(let I of r.hooks.beforeRedirect)await I(r,n);this.emit("redirect",n,r),await this._makeRequest()}catch(p){this._beforeError(p);return}return}if(r.isStream&&r.throwHttpErrors&&!est.isResponseOk(n)){this._beforeError(new Ab(n));return}e.on("readable",()=>{this[ab]&&this._read()}),this.on("resume",()=>{e.resume()}),this.on("pause",()=>{e.pause()}),e.once("end",()=>{this.push(null)}),this.emit("response",e);for(let A of this[ob])if(!A.headersSent){for(let p in e.headers){let h=r.decompress?p!=="content-encoding":!0,E=e.headers[p];h&&A.setHeader(p,E)}A.statusCode=a}}async _onResponse(e){try{await this._onResponseBase(e)}catch(r){this._beforeError(r)}}_onRequest(e){let{options:r}=this,{timeout:o,url:a}=r;jit.default(e),this[B4]=Hae.default(e,o,a);let n=r.cache?"cacheableResponse":"response";e.once(n,p=>{this._onResponse(p)}),e.once("error",p=>{var h;e.destroy(),(h=e.res)===null||h===void 0||h.removeAllListeners("end"),p=p instanceof Hae.TimeoutError?new hb(p,this.timings,this):new zi(p.message,p,this),this._beforeError(p)}),this[jae]=Jit.default(e,this,cst),this[Zs]=e,this.emit("uploadProgress",this.uploadProgress);let u=this[uh],A=this.redirects.length===0?this:e;st.default.nodeStream(u)?(u.pipe(A),u.once("error",p=>{this._beforeError(new pb(p,this))})):(this._unlockWrite(),st.default.undefined(u)?(this._cannotHaveBody||this._noPipe)&&(A.end(),this._lockWrite()):(this._writeRequest(u,void 0,()=>{}),A.end(),this._lockWrite())),this.emit("request",e)}async _createCacheableRequest(e,r){return new Promise((o,a)=>{Object.assign(r,Xit.default(e)),delete r.url;let n,u=v4.get(r.cache)(r,async A=>{A._readableState.autoDestroy=!1,n&&(await n).emit("cacheableResponse",A),o(A)});r.url=e,u.once("error",a),u.once("request",async A=>{n=A,o(n)})})}async _makeRequest(){var e,r,o,a,n;let{options:u}=this,{headers:A}=u;for(let U in A)if(st.default.undefined(A[U]))delete A[U];else if(st.default.null_(A[U]))throw new TypeError(`Use \`undefined\` instead of \`null\` to delete the \`${U}\` header`);if(u.decompress&&st.default.undefined(A["accept-encoding"])&&(A["accept-encoding"]=nst?"gzip, deflate, br":"gzip, deflate"),u.cookieJar){let U=await u.cookieJar.getCookieString(u.url.toString());st.default.nonEmptyString(U)&&(u.headers.cookie=U)}for(let U of u.hooks.beforeRequest){let V=await U(u);if(!st.default.undefined(V)){u.request=()=>V;break}}u.body&&this[uh]!==u.body&&(this[uh]=u.body);let{agent:p,request:h,timeout:E,url:I}=u;if(u.dnsCache&&!("lookup"in u)&&(u.lookup=u.dnsCache.lookup),I.hostname==="unix"){let U=/(?<socketPath>.+?):(?<path>.+)/.exec(`${I.pathname}${I.search}`);if(U?.groups){let{socketPath:V,path:te}=U.groups;Object.assign(u,{socketPath:V,path:te,host:""})}}let v=I.protocol==="https:",x;u.http2?x=Kit.auto:x=v?Git.request:Mae.request;let C=(e=u.request)!==null&&e!==void 0?e:x,R=u.cache?this._createCacheableRequest:C;p&&!u.http2&&(u.agent=p[v?"https":"http"]),u[Zs]=C,delete u.request,delete u.timeout;let N=u;if(N.shared=(r=u.cacheOptions)===null||r===void 0?void 0:r.shared,N.cacheHeuristic=(o=u.cacheOptions)===null||o===void 0?void 0:o.cacheHeuristic,N.immutableMinTimeToLive=(a=u.cacheOptions)===null||a===void 0?void 0:a.immutableMinTimeToLive,N.ignoreCargoCult=(n=u.cacheOptions)===null||n===void 0?void 0:n.ignoreCargoCult,u.dnsLookupIpVersion!==void 0)try{N.family=Gae.dnsLookupIpVersionToFamily(u.dnsLookupIpVersion)}catch{throw new Error("Invalid `dnsLookupIpVersion` option value")}u.https&&("rejectUnauthorized"in u.https&&(N.rejectUnauthorized=u.https.rejectUnauthorized),u.https.checkServerIdentity&&(N.checkServerIdentity=u.https.checkServerIdentity),u.https.certificateAuthority&&(N.ca=u.https.certificateAuthority),u.https.certificate&&(N.cert=u.https.certificate),u.https.key&&(N.key=u.https.key),u.https.passphrase&&(N.passphrase=u.https.passphrase),u.https.pfx&&(N.pfx=u.https.pfx));try{let U=await R(I,N);st.default.undefined(U)&&(U=x(I,N)),u.request=h,u.timeout=E,u.agent=p,u.https&&("rejectUnauthorized"in u.https&&delete N.rejectUnauthorized,u.https.checkServerIdentity&&delete N.checkServerIdentity,u.https.certificateAuthority&&delete N.ca,u.https.certificate&&delete N.cert,u.https.key&&delete N.key,u.https.passphrase&&delete N.passphrase,u.https.pfx&&delete N.pfx),sst(U)?this._onRequest(U):this.writable?(this.once("finish",()=>{this._onResponse(U)}),this._unlockWrite(),this.end(),this._lockWrite()):this._onResponse(U)}catch(U){throw U instanceof Uae.CacheError?new fb(U,this):new zi(U.message,U,this)}}async _error(e){try{for(let r of this.options.hooks.beforeError)e=await r(e)}catch(r){e=new zi(r.message,r,this)}this.destroy(e)}_beforeError(e){if(this[QE])return;let{options:r}=this,o=this.retryCount+1;this[QE]=!0,e instanceof zi||(e=new zi(e.message,e,this));let a=e,{response:n}=a;(async()=>{if(n&&!n.body){n.setEncoding(this._readableState.encoding);try{n.rawBody=await $it.default(n),n.body=n.rawBody.toString()}catch{}}if(this.listenerCount("retry")!==0){let u;try{let A;n&&"retry-after"in n.headers&&(A=Number(n.headers["retry-after"]),Number.isNaN(A)?(A=Date.parse(n.headers["retry-after"])-Date.now(),A<=0&&(A=1)):A*=1e3),u=await r.retry.calculateDelay({attemptCount:o,retryOptions:r.retry,error:a,retryAfter:A,computedValue:rst.default({attemptCount:o,retryOptions:r.retry,error:a,retryAfter:A,computedValue:0})})}catch(A){this._error(new zi(A.message,A,this));return}if(u){let A=async()=>{try{for(let p of this.options.hooks.beforeRetry)await p(this.options,a,o)}catch(p){this._error(new zi(p.message,e,this));return}this.destroyed||(this.destroy(),this.emit("retry",o,e))};this[zae]=setTimeout(A,u);return}}this._error(a)})()}_read(){this[ab]=!0;let e=this[lb];if(e&&!this[QE]){e.readableLength&&(this[ab]=!1);let r;for(;(r=e.read())!==null;){this[bE]+=r.length,this[Wae]=!0;let o=this.downloadProgress;o.percent<1&&this.emit("downloadProgress",o),this.push(r)}}}_write(e,r,o){let a=()=>{this._writeRequest(e,r,o)};this.requestInitialized?a():this[y1].push(a)}_writeRequest(e,r,o){this[Zs].destroyed||(this._progressCallbacks.push(()=>{this[kE]+=Buffer.byteLength(e,r);let a=this.uploadProgress;a.percent<1&&this.emit("uploadProgress",a)}),this[Zs].write(e,r,a=>{!a&&this._progressCallbacks.length>0&&this._progressCallbacks.shift()(),o(a)}))}_final(e){let r=()=>{for(;this._progressCallbacks.length!==0;)this._progressCallbacks.shift()();if(!(Zs in this)){e();return}if(this[Zs].destroyed){e();return}this[Zs].end(o=>{o||(this[xE]=this[kE],this.emit("uploadProgress",this.uploadProgress),this[Zs].emit("upload-complete")),e(o)})};this.requestInitialized?r():this[y1].push(r)}_destroy(e,r){var o;this[QE]=!0,clearTimeout(this[zae]),Zs in this&&(this[B4](),!((o=this[lb])===null||o===void 0)&&o.complete||this[Zs].destroy()),e!==null&&!st.default.undefined(e)&&!(e instanceof zi)&&(e=new zi(e.message,e,this)),r(e)}get _isAboutToError(){return this[QE]}get ip(){var e;return(e=this.socket)===null||e===void 0?void 0:e.remoteAddress}get aborted(){var e,r,o;return((r=(e=this[Zs])===null||e===void 0?void 0:e.destroyed)!==null&&r!==void 0?r:this.destroyed)&&!(!((o=this[Kae])===null||o===void 0)&&o.complete)}get socket(){var e,r;return(r=(e=this[Zs])===null||e===void 0?void 0:e.socket)!==null&&r!==void 0?r:void 0}get downloadProgress(){let e;return this[SE]?e=this[bE]/this[SE]:this[SE]===this[bE]?e=1:e=0,{percent:e,transferred:this[bE],total:this[SE]}}get uploadProgress(){let e;return this[xE]?e=this[kE]/this[xE]:this[xE]===this[kE]?e=1:e=0,{percent:e,transferred:this[kE],total:this[xE]}}get timings(){var e;return(e=this[Zs])===null||e===void 0?void 0:e.timings}get isFromCache(){return this[Yae]}pipe(e,r){if(this[Wae])throw new Error("Failed to pipe. The response has been emitted already.");return e instanceof w4.ServerResponse&&this[ob].add(e),super.pipe(e,r)}unpipe(e){return e instanceof w4.ServerResponse&&this[ob].delete(e),super.unpipe(e),this}};Bn.default=db});var w1=_(jc=>{"use strict";var ust=jc&&jc.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),Ast=jc&&jc.__exportStar||function(t,e){for(var r in t)r!=="default"&&!Object.prototype.hasOwnProperty.call(e,r)&&ust(e,t,r)};Object.defineProperty(jc,"__esModule",{value:!0});jc.CancelError=jc.ParseError=void 0;var Vae=C1(),D4=class extends Vae.RequestError{constructor(e,r){let{options:o}=r.request;super(`${e.message} in "${o.url.toString()}"`,e,r.request),this.name="ParseError"}};jc.ParseError=D4;var P4=class extends Vae.RequestError{constructor(e){super("Promise was canceled",{},e),this.name="CancelError"}get isCanceled(){return!0}};jc.CancelError=P4;Ast(C1(),jc)});var Xae=_(S4=>{"use strict";Object.defineProperty(S4,"__esModule",{value:!0});var Jae=w1(),fst=(t,e,r,o)=>{let{rawBody:a}=t;try{if(e==="text")return a.toString(o);if(e==="json")return a.length===0?"":r(a.toString());if(e==="buffer")return a;throw new Jae.ParseError({message:`Unknown body type '${e}'`,name:"Error"},t)}catch(n){throw new Jae.ParseError(n,t)}};S4.default=fst});var b4=_(Ah=>{"use strict";var pst=Ah&&Ah.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),hst=Ah&&Ah.__exportStar||function(t,e){for(var r in t)r!=="default"&&!Object.prototype.hasOwnProperty.call(e,r)&&pst(e,t,r)};Object.defineProperty(Ah,"__esModule",{value:!0});var gst=ve("events"),dst=Tf(),mst=Jse(),mb=w1(),Zae=Xae(),$ae=C1(),yst=u4(),Est=m4(),ele=y4(),Cst=["request","response","redirect","uploadProgress","downloadProgress"];function tle(t){let e,r,o=new gst.EventEmitter,a=new mst((u,A,p)=>{let h=E=>{let I=new $ae.default(void 0,t);I.retryCount=E,I._noPipe=!0,p(()=>I.destroy()),p.shouldReject=!1,p(()=>A(new mb.CancelError(I))),e=I,I.once("response",async C=>{var R;if(C.retryCount=E,C.request.aborted)return;let N;try{N=await Est.default(I),C.rawBody=N}catch{return}if(I._isAboutToError)return;let U=((R=C.headers["content-encoding"])!==null&&R!==void 0?R:"").toLowerCase(),V=["gzip","deflate","br"].includes(U),{options:te}=I;if(V&&!te.decompress)C.body=N;else try{C.body=Zae.default(C,te.responseType,te.parseJson,te.encoding)}catch(ae){if(C.body=N.toString(),ele.isResponseOk(C)){I._beforeError(ae);return}}try{for(let[ae,fe]of te.hooks.afterResponse.entries())C=await fe(C,async ue=>{let me=$ae.default.normalizeArguments(void 0,{...ue,retry:{calculateDelay:()=>0},throwHttpErrors:!1,resolveBodyOnly:!1},te);me.hooks.afterResponse=me.hooks.afterResponse.slice(0,ae);for(let Be of me.hooks.beforeRetry)await Be(me);let he=tle(me);return p(()=>{he.catch(()=>{}),he.cancel()}),he})}catch(ae){I._beforeError(new mb.RequestError(ae.message,ae,I));return}if(!ele.isResponseOk(C)){I._beforeError(new mb.HTTPError(C));return}r=C,u(I.options.resolveBodyOnly?C.body:C)});let v=C=>{if(a.isCanceled)return;let{options:R}=I;if(C instanceof mb.HTTPError&&!R.throwHttpErrors){let{response:N}=C;u(I.options.resolveBodyOnly?N.body:N);return}A(C)};I.once("error",v);let x=I.options.body;I.once("retry",(C,R)=>{var N,U;if(x===((N=R.request)===null||N===void 0?void 0:N.options.body)&&dst.default.nodeStream((U=R.request)===null||U===void 0?void 0:U.options.body)){v(R);return}h(C)}),yst.default(I,o,Cst)};h(0)});a.on=(u,A)=>(o.on(u,A),a);let n=u=>{let A=(async()=>{await a;let{options:p}=r.request;return Zae.default(r,u,p.parseJson,p.encoding)})();return Object.defineProperties(A,Object.getOwnPropertyDescriptors(a)),A};return a.json=()=>{let{headers:u}=e.options;return!e.writableFinished&&u.accept===void 0&&(u.accept="application/json"),n("json")},a.buffer=()=>n("buffer"),a.text=()=>n("text"),a}Ah.default=tle;hst(w1(),Ah)});var rle=_(x4=>{"use strict";Object.defineProperty(x4,"__esModule",{value:!0});var wst=w1();function Ist(t,...e){let r=(async()=>{if(t instanceof wst.RequestError)try{for(let a of e)if(a)for(let n of a)t=await n(t)}catch(a){t=a}throw t})(),o=()=>r;return r.json=o,r.text=o,r.buffer=o,r.on=o,r}x4.default=Ist});var sle=_(k4=>{"use strict";Object.defineProperty(k4,"__esModule",{value:!0});var nle=Tf();function ile(t){for(let e of Object.values(t))(nle.default.plainObject(e)||nle.default.array(e))&&ile(e);return Object.freeze(t)}k4.default=ile});var ale=_(ole=>{"use strict";Object.defineProperty(ole,"__esModule",{value:!0})});var Q4=_(Vl=>{"use strict";var Bst=Vl&&Vl.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),vst=Vl&&Vl.__exportStar||function(t,e){for(var r in t)r!=="default"&&!Object.prototype.hasOwnProperty.call(e,r)&&Bst(e,t,r)};Object.defineProperty(Vl,"__esModule",{value:!0});Vl.defaultHandler=void 0;var lle=Tf(),zl=b4(),Dst=rle(),Eb=C1(),Pst=sle(),Sst={RequestError:zl.RequestError,CacheError:zl.CacheError,ReadError:zl.ReadError,HTTPError:zl.HTTPError,MaxRedirectsError:zl.MaxRedirectsError,TimeoutError:zl.TimeoutError,ParseError:zl.ParseError,CancelError:zl.CancelError,UnsupportedProtocolError:zl.UnsupportedProtocolError,UploadError:zl.UploadError},bst=async t=>new Promise(e=>{setTimeout(e,t)}),{normalizeArguments:yb}=Eb.default,cle=(...t)=>{let e;for(let r of t)e=yb(void 0,r,e);return e},xst=t=>t.isStream?new Eb.default(void 0,t):zl.default(t),kst=t=>"defaults"in t&&"options"in t.defaults,Qst=["get","post","put","patch","head","delete"];Vl.defaultHandler=(t,e)=>e(t);var ule=(t,e)=>{if(t)for(let r of t)r(e)},Ale=t=>{t._rawHandlers=t.handlers,t.handlers=t.handlers.map(o=>(a,n)=>{let u,A=o(a,p=>(u=n(p),u));if(A!==u&&!a.isStream&&u){let p=A,{then:h,catch:E,finally:I}=p;Object.setPrototypeOf(p,Object.getPrototypeOf(u)),Object.defineProperties(p,Object.getOwnPropertyDescriptors(u)),p.then=h,p.catch=E,p.finally=I}return A});let e=(o,a={},n)=>{var u,A;let p=0,h=E=>t.handlers[p++](E,p===t.handlers.length?xst:h);if(lle.default.plainObject(o)){let E={...o,...a};Eb.setNonEnumerableProperties([o,a],E),a=E,o=void 0}try{let E;try{ule(t.options.hooks.init,a),ule((u=a.hooks)===null||u===void 0?void 0:u.init,a)}catch(v){E=v}let I=yb(o,a,n??t.options);if(I[Eb.kIsNormalizedAlready]=!0,E)throw new zl.RequestError(E.message,E,I);return h(I)}catch(E){if(a.isStream)throw E;return Dst.default(E,t.options.hooks.beforeError,(A=a.hooks)===null||A===void 0?void 0:A.beforeError)}};e.extend=(...o)=>{let a=[t.options],n=[...t._rawHandlers],u;for(let A of o)kst(A)?(a.push(A.defaults.options),n.push(...A.defaults._rawHandlers),u=A.defaults.mutableDefaults):(a.push(A),"handlers"in A&&n.push(...A.handlers),u=A.mutableDefaults);return n=n.filter(A=>A!==Vl.defaultHandler),n.length===0&&n.push(Vl.defaultHandler),Ale({options:cle(...a),handlers:n,mutableDefaults:Boolean(u)})};let r=async function*(o,a){let n=yb(o,a,t.options);n.resolveBodyOnly=!1;let u=n.pagination;if(!lle.default.object(u))throw new TypeError("`options.pagination` must be implemented");let A=[],{countLimit:p}=u,h=0;for(;h<u.requestLimit;){h!==0&&await bst(u.backoff);let E=await e(void 0,void 0,n),I=await u.transform(E),v=[];for(let C of I)if(u.filter(C,A,v)&&(!u.shouldContinue(C,A,v)||(yield C,u.stackAllItems&&A.push(C),v.push(C),--p<=0)))return;let x=u.paginate(E,A,v);if(x===!1)return;x===E.request.options?n=E.request.options:x!==void 0&&(n=yb(void 0,x,n)),h++}};e.paginate=r,e.paginate.all=async(o,a)=>{let n=[];for await(let u of r(o,a))n.push(u);return n},e.paginate.each=r,e.stream=(o,a)=>e(o,{...a,isStream:!0});for(let o of Qst)e[o]=(a,n)=>e(a,{...n,method:o}),e.stream[o]=(a,n)=>e(a,{...n,method:o,isStream:!0});return Object.assign(e,Sst),Object.defineProperty(e,"defaults",{value:t.mutableDefaults?t:Pst.default(t),writable:t.mutableDefaults,configurable:t.mutableDefaults,enumerable:!0}),e.mergeOptions=cle,e};Vl.default=Ale;vst(ale(),Vl)});var hle=_((Lf,Cb)=>{"use strict";var Fst=Lf&&Lf.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),fle=Lf&&Lf.__exportStar||function(t,e){for(var r in t)r!=="default"&&!Object.prototype.hasOwnProperty.call(e,r)&&Fst(e,t,r)};Object.defineProperty(Lf,"__esModule",{value:!0});var Rst=ve("url"),ple=Q4(),Tst={options:{method:"GET",retry:{limit:2,methods:["GET","PUT","HEAD","DELETE","OPTIONS","TRACE"],statusCodes:[408,413,429,500,502,503,504,521,522,524],errorCodes:["ETIMEDOUT","ECONNRESET","EADDRINUSE","ECONNREFUSED","EPIPE","ENOTFOUND","ENETUNREACH","EAI_AGAIN"],maxRetryAfter:void 0,calculateDelay:({computedValue:t})=>t},timeout:{},headers:{"user-agent":"got (https://github.com/sindresorhus/got)"},hooks:{init:[],beforeRequest:[],beforeRedirect:[],beforeRetry:[],beforeError:[],afterResponse:[]},cache:void 0,dnsCache:void 0,decompress:!0,throwHttpErrors:!0,followRedirect:!0,isStream:!1,responseType:"text",resolveBodyOnly:!1,maxRedirects:10,prefixUrl:"",methodRewriting:!0,ignoreInvalidCookies:!1,context:{},http2:!1,allowGetBody:!1,https:void 0,pagination:{transform:t=>t.request.options.responseType==="json"?t.body:JSON.parse(t.body),paginate:t=>{if(!Reflect.has(t.headers,"link"))return!1;let e=t.headers.link.split(","),r;for(let o of e){let a=o.split(";");if(a[1].includes("next")){r=a[0].trimStart().trim(),r=r.slice(1,-1);break}}return r?{url:new Rst.URL(r)}:!1},filter:()=>!0,shouldContinue:()=>!0,countLimit:1/0,backoff:0,requestLimit:1e4,stackAllItems:!0},parseJson:t=>JSON.parse(t),stringifyJson:t=>JSON.stringify(t),cacheOptions:{}},handlers:[ple.defaultHandler],mutableDefaults:!1},F4=ple.default(Tst);Lf.default=F4;Cb.exports=F4;Cb.exports.default=F4;Cb.exports.__esModule=!0;fle(Q4(),Lf);fle(b4(),Lf)});var nn={};zt(nn,{Method:()=>wle,del:()=>Ust,get:()=>N4,getNetworkSettings:()=>Cle,post:()=>O4,put:()=>Mst,request:()=>I1});function mle(t){let e=new URL(t),r={host:e.hostname,headers:{}};return e.port&&(r.port=Number(e.port)),e.username&&e.password&&(r.proxyAuth=`${e.username}:${e.password}`),{proxy:r}}async function R4(t){return al(dle,t,()=>oe.readFilePromise(t).then(e=>(dle.set(t,e),e)))}function Ost({statusCode:t,statusMessage:e},r){let o=Ut(r,t,yt.NUMBER),a=`https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/${t}`;return Zy(r,`${o}${e?` (${e})`:""}`,a)}async function wb(t,{configuration:e,customErrorMessage:r}){try{return await t}catch(o){if(o.name!=="HTTPError")throw o;let a=r?.(o,e)??o.response.body?.error;a==null&&(o.message.startsWith("Response code")?a="The remote server failed to provide the requested resource":a=o.message),o.code==="ETIMEDOUT"&&o.event==="socket"&&(a+=`(can be increased via ${Ut(e,"httpTimeout",yt.SETTING)})`);let n=new Jt(35,a,u=>{o.response&&u.reportError(35,` ${Xu(e,{label:"Response Code",value:Hc(yt.NO_HINT,Ost(o.response,e))})}`),o.request&&(u.reportError(35,` ${Xu(e,{label:"Request Method",value:Hc(yt.NO_HINT,o.request.options.method)})}`),u.reportError(35,` ${Xu(e,{label:"Request URL",value:Hc(yt.URL,o.request.requestUrl)})}`)),o.request.redirects.length>0&&u.reportError(35,` ${Xu(e,{label:"Request Redirects",value:Hc(yt.NO_HINT,bN(e,o.request.redirects,yt.URL))})}`),o.request.retryCount===o.request.options.retry.limit&&u.reportError(35,` ${Xu(e,{label:"Request Retry Count",value:Hc(yt.NO_HINT,`${Ut(e,o.request.retryCount,yt.NUMBER)} (can be increased via ${Ut(e,"httpRetry",yt.SETTING)})`)})}`)});throw n.originalError=o,n}}function Cle(t,e){let r=[...e.configuration.get("networkSettings")].sort(([u],[A])=>A.length-u.length),o={enableNetwork:void 0,httpsCaFilePath:void 0,httpProxy:void 0,httpsProxy:void 0,httpsKeyFilePath:void 0,httpsCertFilePath:void 0},a=Object.keys(o),n=typeof t=="string"?new URL(t):t;for(let[u,A]of r)if(L4.default.isMatch(n.hostname,u))for(let p of a){let h=A.get(p);h!==null&&typeof o[p]>"u"&&(o[p]=h)}for(let u of a)typeof o[u]>"u"&&(o[u]=e.configuration.get(u));return o}async function I1(t,e,{configuration:r,headers:o,jsonRequest:a,jsonResponse:n,method:u="GET",wrapNetworkRequest:A}){let p={target:t,body:e,configuration:r,headers:o,jsonRequest:a,jsonResponse:n,method:u},h=async()=>await _st(t,e,p),E=typeof A<"u"?await A(h,p):h;return await(await r.reduceHook(v=>v.wrapNetworkRequest,E,p))()}async function N4(t,{configuration:e,jsonResponse:r,customErrorMessage:o,wrapNetworkRequest:a,...n}){let u=()=>wb(I1(t,null,{configuration:e,wrapNetworkRequest:a,...n}),{configuration:e,customErrorMessage:o}).then(p=>p.body),A=await(typeof a<"u"?u():al(gle,t,()=>u().then(p=>(gle.set(t,p),p))));return r?JSON.parse(A.toString()):A}async function Mst(t,e,{customErrorMessage:r,...o}){return(await wb(I1(t,e,{...o,method:"PUT"}),{customErrorMessage:r,configuration:o.configuration})).body}async function O4(t,e,{customErrorMessage:r,...o}){return(await wb(I1(t,e,{...o,method:"POST"}),{customErrorMessage:r,configuration:o.configuration})).body}async function Ust(t,{customErrorMessage:e,...r}){return(await wb(I1(t,null,{...r,method:"DELETE"}),{customErrorMessage:e,configuration:r.configuration})).body}async function _st(t,e,{configuration:r,headers:o,jsonRequest:a,jsonResponse:n,method:u="GET"}){let A=typeof t=="string"?new URL(t):t,p=Cle(A,{configuration:r});if(p.enableNetwork===!1)throw new Jt(80,`Request to '${A.href}' has been blocked because of your configuration settings`);if(A.protocol==="http:"&&!L4.default.isMatch(A.hostname,r.get("unsafeHttpWhitelist")))throw new Jt(81,`Unsafe http requests must be explicitly whitelisted in your configuration (${A.hostname})`);let E={agent:{http:p.httpProxy?T4.default.httpOverHttp(mle(p.httpProxy)):Lst,https:p.httpsProxy?T4.default.httpsOverHttp(mle(p.httpsProxy)):Nst},headers:o,method:u};E.responseType=n?"json":"buffer",e!==null&&(Buffer.isBuffer(e)||!a&&typeof e=="string"?E.body=e:E.json=e);let I=r.get("httpTimeout"),v=r.get("httpRetry"),x=r.get("enableStrictSsl"),C=p.httpsCaFilePath,R=p.httpsCertFilePath,N=p.httpsKeyFilePath,{default:U}=await Promise.resolve().then(()=>$e(hle())),V=C?await R4(C):void 0,te=R?await R4(R):void 0,ae=N?await R4(N):void 0,fe=U.extend({timeout:{socket:I},retry:v,https:{rejectUnauthorized:x,certificateAuthority:V,certificate:te,key:ae},...E});return r.getLimit("networkConcurrency")(()=>fe(A))}var yle,Ele,L4,T4,gle,dle,Lst,Nst,wle,Ib=Et(()=>{Pt();yle=ve("https"),Ele=ve("http"),L4=$e(Zo()),T4=$e(Yse());Wl();jl();Gl();gle=new Map,dle=new Map,Lst=new Ele.Agent({keepAlive:!0}),Nst=new yle.Agent({keepAlive:!0});wle=(a=>(a.GET="GET",a.PUT="PUT",a.POST="POST",a.DELETE="DELETE",a))(wle||{})});var Vi={};zt(Vi,{availableParallelism:()=>U4,getArchitecture:()=>B1,getArchitectureName:()=>Yst,getArchitectureSet:()=>M4,getCaller:()=>Vst,major:()=>Hst,openUrl:()=>qst});function jst(){if(process.platform==="darwin"||process.platform==="win32")return null;let t;try{t=oe.readFileSync(Gst)}catch{}if(typeof t<"u"){if(t&&(t.includes("GLIBC")||t.includes("libc")))return"glibc";if(t&&t.includes("musl"))return"musl"}let r=(process.report?.getReport()??{}).sharedObjects??[],o=/\/(?:(ld-linux-|[^/]+-linux-gnu\/)|(libc.musl-|ld-musl-))/;return KI(r,a=>{let n=a.match(o);if(!n)return KI.skip;if(n[1])return"glibc";if(n[2])return"musl";throw new Error("Assertion failed: Expected the libc variant to have been detected")})??null}function B1(){return Ble=Ble??{os:process.platform,cpu:process.arch,libc:jst()}}function Yst(t=B1()){return t.libc?`${t.os}-${t.cpu}-${t.libc}`:`${t.os}-${t.cpu}`}function M4(){let t=B1();return vle=vle??{os:[t.os],cpu:[t.cpu],libc:t.libc?[t.libc]:[]}}function zst(t){let e=Wst.exec(t);if(!e)return null;let r=e[2]&&e[2].indexOf("native")===0,o=e[2]&&e[2].indexOf("eval")===0,a=Kst.exec(e[2]);return o&&a!=null&&(e[2]=a[1],e[3]=a[2],e[4]=a[3]),{file:r?null:e[2],methodName:e[1]||"<unknown>",arguments:r?[e[2]]:[],line:e[3]?+e[3]:null,column:e[4]?+e[4]:null}}function Vst(){let e=new Error().stack.split(`
-`)[3];return zst(e)}function U4(){return typeof Bb.default.availableParallelism<"u"?Bb.default.availableParallelism():Math.max(1,Bb.default.cpus().length)}var Bb,Hst,Ile,qst,Gst,Ble,vle,Wst,Kst,vb=Et(()=>{Pt();Bb=$e(ve("os"));Db();Gl();Hst=Number(process.versions.node.split(".")[0]),Ile=new Map([["darwin","open"],["linux","xdg-open"],["win32","explorer.exe"]]).get(process.platform),qst=typeof Ile<"u"?async t=>{try{return await _4(Ile,[t],{cwd:z.cwd()}),!0}catch{return!1}}:void 0,Gst="/usr/bin/ldd";Wst=/^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|\/|[a-z]:\\|\\\\).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,Kst=/\((\S*)(?::(\d+))(?::(\d+))\)/});function Y4(t,e,r,o,a){let n=A1(r);if(o.isArray||o.type==="ANY"&&Array.isArray(n))return Array.isArray(n)?n.map((u,A)=>H4(t,`${e}[${A}]`,u,o,a)):String(n).split(/,/).map(u=>H4(t,e,u,o,a));if(Array.isArray(n))throw new Error(`Non-array configuration settings "${e}" cannot be an array`);return H4(t,e,r,o,a)}function H4(t,e,r,o,a){let n=A1(r);switch(o.type){case"ANY":return jS(n);case"SHAPE":return $st(t,e,r,o,a);case"MAP":return eot(t,e,r,o,a)}if(n===null&&!o.isNullable&&o.default!==null)throw new Error(`Non-nullable configuration settings "${e}" cannot be set to null`);if(o.values?.includes(n))return n;let A=(()=>{if(o.type==="BOOLEAN"&&typeof n!="string")return zI(n);if(typeof n!="string")throw new Error(`Expected configuration setting "${e}" to be a string, got ${typeof n}`);let p=iS(n,{env:t.env});switch(o.type){case"ABSOLUTE_PATH":{let h=a,E=mM(r);return E&&E[0]!=="<"&&(h=z.dirname(E)),z.resolve(h,le.toPortablePath(p))}case"LOCATOR_LOOSE":return xf(p,!1);case"NUMBER":return parseInt(p);case"LOCATOR":return xf(p);case"BOOLEAN":return zI(p);default:return p}})();if(o.values&&!o.values.includes(A))throw new Error(`Invalid value, expected one of ${o.values.join(", ")}`);return A}function $st(t,e,r,o,a){let n=A1(r);if(typeof n!="object"||Array.isArray(n))throw new it(`Object configuration settings "${e}" must be an object`);let u=W4(t,o,{ignoreArrays:!0});if(n===null)return u;for(let[A,p]of Object.entries(n)){let h=`${e}.${A}`;if(!o.properties[A])throw new it(`Unrecognized configuration settings found: ${e}.${A} - run "yarn config -v" to see the list of settings supported in Yarn`);u.set(A,Y4(t,h,p,o.properties[A],a))}return u}function eot(t,e,r,o,a){let n=A1(r),u=new Map;if(typeof n!="object"||Array.isArray(n))throw new it(`Map configuration settings "${e}" must be an object`);if(n===null)return u;for(let[A,p]of Object.entries(n)){let h=o.normalizeKeys?o.normalizeKeys(A):A,E=`${e}['${h}']`,I=o.valueDefinition;u.set(h,Y4(t,E,p,I,a))}return u}function W4(t,e,{ignoreArrays:r=!1}={}){switch(e.type){case"SHAPE":{if(e.isArray&&!r)return[];let o=new Map;for(let[a,n]of Object.entries(e.properties))o.set(a,W4(t,n));return o}case"MAP":return e.isArray&&!r?[]:new Map;case"ABSOLUTE_PATH":return e.default===null?null:t.projectCwd===null?Array.isArray(e.default)?e.default.map(o=>z.normalize(o)):z.isAbsolute(e.default)?z.normalize(e.default):e.isNullable?null:void 0:Array.isArray(e.default)?e.default.map(o=>z.resolve(t.projectCwd,o)):z.resolve(t.projectCwd,e.default);default:return e.default}}function Sb(t,e,r){if(e.type==="SECRET"&&typeof t=="string"&&r.hideSecrets)return Zst;if(e.type==="ABSOLUTE_PATH"&&typeof t=="string"&&r.getNativePaths)return le.fromPortablePath(t);if(e.isArray&&Array.isArray(t)){let o=[];for(let a of t)o.push(Sb(a,e,r));return o}if(e.type==="MAP"&&t instanceof Map){if(t.size===0)return;let o=new Map;for(let[a,n]of t.entries()){let u=Sb(n,e.valueDefinition,r);typeof u<"u"&&o.set(a,u)}return o}if(e.type==="SHAPE"&&t instanceof Map){if(t.size===0)return;let o=new Map;for(let[a,n]of t.entries()){let u=e.properties[a],A=Sb(n,u,r);typeof A<"u"&&o.set(a,A)}return o}return t}function tot(){let t={};for(let[e,r]of Object.entries(process.env))e=e.toLowerCase(),e.startsWith(bb)&&(e=(0,Ple.default)(e.slice(bb.length)),t[e]=r);return t}function G4(){let t=`${bb}rc_filename`;for(let[e,r]of Object.entries(process.env))if(e.toLowerCase()===t&&typeof r=="string")return r;return j4}async function Dle(t){try{return await oe.readFilePromise(t)}catch{return Buffer.of()}}async function rot(t,e){return Buffer.compare(...await Promise.all([Dle(t),Dle(e)]))===0}async function not(t,e){let[r,o]=await Promise.all([oe.statPromise(t),oe.statPromise(e)]);return r.dev===o.dev&&r.ino===o.ino}async function sot({configuration:t,selfPath:e}){let r=t.get("yarnPath");return t.get("ignorePath")||r===null||r===e||await iot(r,e)?null:r}var Ple,Nf,Sle,ble,xle,q4,Jst,v1,Xst,FE,bb,j4,Zst,D1,kle,xb,Pb,iot,nA,Ke,P1=Et(()=>{Pt();Nl();Ple=$e(sz()),Nf=$e(rd());qt();Sle=$e(Zz()),ble=ve("module"),xle=$e(sd()),q4=ve("stream");ose();fE();cM();uM();AM();Tse();fM();Dd();Use();WS();jl();ih();Ib();Gl();vb();Qf();bo();Jst=function(){if(!Nf.GITHUB_ACTIONS||!process.env.GITHUB_EVENT_PATH)return!1;let t=le.toPortablePath(process.env.GITHUB_EVENT_PATH),e;try{e=oe.readJsonSync(t)}catch{return!1}return!(!("repository"in e)||!e.repository||(e.repository.private??!0))}(),v1=new Set(["@yarnpkg/plugin-constraints","@yarnpkg/plugin-exec","@yarnpkg/plugin-interactive-tools","@yarnpkg/plugin-stage","@yarnpkg/plugin-typescript","@yarnpkg/plugin-version","@yarnpkg/plugin-workspace-tools"]),Xst=new Set(["isTestEnv","injectNpmUser","injectNpmPassword","injectNpm2FaToken","zipDataEpilogue","cacheCheckpointOverride","cacheVersionOverride","lockfileVersionOverride","binFolder","version","flags","profile","gpg","ignoreNode","wrapOutput","home","confDir","registry","ignoreCwd"]),FE=/^(?!v)[a-z0-9._-]+$/i,bb="yarn_",j4=".yarnrc.yml",Zst="********",D1=(E=>(E.ANY="ANY",E.BOOLEAN="BOOLEAN",E.ABSOLUTE_PATH="ABSOLUTE_PATH",E.LOCATOR="LOCATOR",E.LOCATOR_LOOSE="LOCATOR_LOOSE",E.NUMBER="NUMBER",E.STRING="STRING",E.SECRET="SECRET",E.SHAPE="SHAPE",E.MAP="MAP",E))(D1||{}),kle=yt,xb=(r=>(r.JUNCTIONS="junctions",r.SYMLINKS="symlinks",r))(xb||{}),Pb={lastUpdateCheck:{description:"Last timestamp we checked whether new Yarn versions were available",type:"STRING",default:null},yarnPath:{description:"Path to the local executable that must be used over the global one",type:"ABSOLUTE_PATH",default:null},ignorePath:{description:"If true, the local executable will be ignored when using the global one",type:"BOOLEAN",default:!1},globalFolder:{description:"Folder where all system-global files are stored",type:"ABSOLUTE_PATH",default:EM()},cacheFolder:{description:"Folder where the cache files must be written",type:"ABSOLUTE_PATH",default:"./.yarn/cache"},compressionLevel:{description:"Zip files compression level, from 0 to 9 or mixed (a variant of 9, which stores some files uncompressed, when compression doesn't yield good results)",type:"NUMBER",values:["mixed",0,1,2,3,4,5,6,7,8,9],default:0},virtualFolder:{description:"Folder where the virtual packages (cf doc) will be mapped on the disk (must be named __virtual__)",type:"ABSOLUTE_PATH",default:"./.yarn/__virtual__"},installStatePath:{description:"Path of the file where the install state will be persisted",type:"ABSOLUTE_PATH",default:"./.yarn/install-state.gz"},immutablePatterns:{description:"Array of glob patterns; files matching them won't be allowed to change during immutable installs",type:"STRING",default:[],isArray:!0},rcFilename:{description:"Name of the files where the configuration can be found",type:"STRING",default:G4()},enableGlobalCache:{description:"If true, the system-wide cache folder will be used regardless of `cache-folder`",type:"BOOLEAN",default:!0},cacheMigrationMode:{description:"Defines the conditions under which Yarn upgrades should cause the cache archives to be regenerated.",type:"STRING",values:["always","match-spec","required-only"],default:"always"},enableColors:{description:"If true, the CLI is allowed to use colors in its output",type:"BOOLEAN",default:aS,defaultText:"<dynamic>"},enableHyperlinks:{description:"If true, the CLI is allowed to use hyperlinks in its output",type:"BOOLEAN",default:SN,defaultText:"<dynamic>"},enableInlineBuilds:{description:"If true, the CLI will print the build output on the command line",type:"BOOLEAN",default:Nf.isCI,defaultText:"<dynamic>"},enableMessageNames:{description:"If true, the CLI will prefix most messages with codes suitable for search engines",type:"BOOLEAN",default:!0},enableProgressBars:{description:"If true, the CLI is allowed to show a progress bar for long-running events",type:"BOOLEAN",default:!Nf.isCI,defaultText:"<dynamic>"},enableTimers:{description:"If true, the CLI is allowed to print the time spent executing commands",type:"BOOLEAN",default:!0},enableTips:{description:"If true, installs will print a helpful message every day of the week",type:"BOOLEAN",default:!Nf.isCI,defaultText:"<dynamic>"},preferInteractive:{description:"If true, the CLI will automatically use the interactive mode when called from a TTY",type:"BOOLEAN",default:!1},preferTruncatedLines:{description:"If true, the CLI will truncate lines that would go beyond the size of the terminal",type:"BOOLEAN",default:!1},progressBarStyle:{description:"Which style of progress bar should be used (only when progress bars are enabled)",type:"STRING",default:void 0,defaultText:"<dynamic>"},defaultLanguageName:{description:"Default language mode that should be used when a package doesn't offer any insight",type:"STRING",default:"node"},defaultProtocol:{description:"Default resolution protocol used when resolving pure semver and tag ranges",type:"STRING",default:"npm:"},enableTransparentWorkspaces:{description:"If false, Yarn won't automatically resolve workspace dependencies unless they use the `workspace:` protocol",type:"BOOLEAN",default:!0},supportedArchitectures:{description:"Architectures that Yarn will fetch and inject into the resolver",type:"SHAPE",properties:{os:{description:"Array of supported process.platform strings, or null to target them all",type:"STRING",isArray:!0,isNullable:!0,default:["current"]},cpu:{description:"Array of supported process.arch strings, or null to target them all",type:"STRING",isArray:!0,isNullable:!0,default:["current"]},libc:{description:"Array of supported libc libraries, or null to target them all",type:"STRING",isArray:!0,isNullable:!0,default:["current"]}}},enableMirror:{description:"If true, the downloaded packages will be retrieved and stored in both the local and global folders",type:"BOOLEAN",default:!0},enableNetwork:{description:"If false, Yarn will refuse to use the network if required to",type:"BOOLEAN",default:!0},enableOfflineMode:{description:"If true, Yarn will attempt to retrieve files and metadata from the global cache rather than the network",type:"BOOLEAN",default:!1},httpProxy:{description:"URL of the http proxy that must be used for outgoing http requests",type:"STRING",default:null},httpsProxy:{description:"URL of the http proxy that must be used for outgoing https requests",type:"STRING",default:null},unsafeHttpWhitelist:{description:"List of the hostnames for which http queries are allowed (glob patterns are supported)",type:"STRING",default:[],isArray:!0},httpTimeout:{description:"Timeout of each http request in milliseconds",type:"NUMBER",default:6e4},httpRetry:{description:"Retry times on http failure",type:"NUMBER",default:3},networkConcurrency:{description:"Maximal number of concurrent requests",type:"NUMBER",default:50},taskPoolConcurrency:{description:"Maximal amount of concurrent heavy task processing",type:"NUMBER",default:U4()},taskPoolMode:{description:"Execution strategy for heavy tasks",type:"STRING",values:["async","workers"],default:"workers"},networkSettings:{description:"Network settings per hostname (glob patterns are supported)",type:"MAP",valueDefinition:{description:"",type:"SHAPE",properties:{httpsCaFilePath:{description:"Path to file containing one or multiple Certificate Authority signing certificates",type:"ABSOLUTE_PATH",default:null},enableNetwork:{description:"If false, the package manager will refuse to use the network if required to",type:"BOOLEAN",default:null},httpProxy:{description:"URL of the http proxy that must be used for outgoing http requests",type:"STRING",default:null},httpsProxy:{description:"URL of the http proxy that must be used for outgoing https requests",type:"STRING",default:null},httpsKeyFilePath:{description:"Path to file containing private key in PEM format",type:"ABSOLUTE_PATH",default:null},httpsCertFilePath:{description:"Path to file containing certificate chain in PEM format",type:"ABSOLUTE_PATH",default:null}}}},httpsCaFilePath:{description:"A path to a file containing one or multiple Certificate Authority signing certificates",type:"ABSOLUTE_PATH",default:null},httpsKeyFilePath:{description:"Path to file containing private key in PEM format",type:"ABSOLUTE_PATH",default:null},httpsCertFilePath:{description:"Path to file containing certificate chain in PEM format",type:"ABSOLUTE_PATH",default:null},enableStrictSsl:{description:"If false, SSL certificate errors will be ignored",type:"BOOLEAN",default:!0},logFilters:{description:"Overrides for log levels",type:"SHAPE",isArray:!0,concatenateValues:!0,properties:{code:{description:"Code of the messages covered by this override",type:"STRING",default:void 0},text:{description:"Code of the texts covered by this override",type:"STRING",default:void 0},pattern:{description:"Code of the patterns covered by this override",type:"STRING",default:void 0},level:{description:"Log level override, set to null to remove override",type:"STRING",values:Object.values(cS),isNullable:!0,default:void 0}}},enableTelemetry:{description:"If true, telemetry will be periodically sent, following the rules in https://yarnpkg.com/advanced/telemetry",type:"BOOLEAN",default:!0},telemetryInterval:{description:"Minimal amount of time between two telemetry uploads, in days",type:"NUMBER",default:7},telemetryUserId:{description:"If you desire to tell us which project you are, you can set this field. Completely optional and opt-in.",type:"STRING",default:null},enableHardenedMode:{description:"If true, automatically enable --check-resolutions --refresh-lockfile on installs",type:"BOOLEAN",default:Nf.isPR&&Jst,defaultText:"<true on public PRs>"},enableScripts:{description:"If true, packages are allowed to have install scripts by default",type:"BOOLEAN",default:!0},enableStrictSettings:{description:"If true, unknown settings will cause Yarn to abort",type:"BOOLEAN",default:!0},enableImmutableCache:{description:"If true, the cache is reputed immutable and actions that would modify it will throw",type:"BOOLEAN",default:!1},checksumBehavior:{description:"Enumeration defining what to do when a checksum doesn't match expectations",type:"STRING",default:"throw"},injectEnvironmentFiles:{description:"List of all the environment files that Yarn should inject inside the process when it starts",type:"ABSOLUTE_PATH",default:[".env.yarn?"],isArray:!0},packageExtensions:{description:"Map of package corrections to apply on the dependency tree",type:"MAP",valueDefinition:{description:"The extension that will be applied to any package whose version matches the specified range",type:"SHAPE",properties:{dependencies:{description:"The set of dependencies that must be made available to the current package in order for it to work properly",type:"MAP",valueDefinition:{description:"A range",type:"STRING"}},peerDependencies:{description:"Inherited dependencies - the consumer of the package will be tasked to provide them",type:"MAP",valueDefinition:{description:"A semver range",type:"STRING"}},peerDependenciesMeta:{description:"Extra information related to the dependencies listed in the peerDependencies field",type:"MAP",valueDefinition:{description:"The peerDependency meta",type:"SHAPE",properties:{optional:{description:"If true, the selected peer dependency will be marked as optional by the package manager and the consumer omitting it won't be reported as an error",type:"BOOLEAN",default:!1}}}}}}}};iot=process.platform==="win32"?rot:not;nA=class{constructor(e){this.isCI=Nf.isCI;this.projectCwd=null;this.plugins=new Map;this.settings=new Map;this.values=new Map;this.sources=new Map;this.invalid=new Map;this.env={};this.limits=new Map;this.packageExtensions=null;this.startingCwd=e}static create(e,r,o){let a=new nA(e);typeof r<"u"&&!(r instanceof Map)&&(a.projectCwd=r),a.importSettings(Pb);let n=typeof o<"u"?o:r instanceof Map?r:new Map;for(let[u,A]of n)a.activatePlugin(u,A);return a}static async find(e,r,{strict:o=!0,usePathCheck:a=null,useRc:n=!0}={}){let u=tot();delete u.rcFilename;let A=new nA(e),p=await nA.findRcFiles(e),h=await nA.findFolderRcFile(EE());h&&(p.find(me=>me.path===h.path)||p.unshift(h));let E=Mse(p.map(ue=>[ue.path,ue.data])),I=Bt.dot,v=new Set(Object.keys(Pb)),x=({yarnPath:ue,ignorePath:me,injectEnvironmentFiles:he})=>({yarnPath:ue,ignorePath:me,injectEnvironmentFiles:he}),C=({yarnPath:ue,ignorePath:me,injectEnvironmentFiles:he,...Be})=>{let we={};for(let[g,Ee]of Object.entries(Be))v.has(g)&&(we[g]=Ee);return we},R=({yarnPath:ue,ignorePath:me,...he})=>{let Be={};for(let[we,g]of Object.entries(he))v.has(we)||(Be[we]=g);return Be};if(A.importSettings(x(Pb)),A.useWithSource("<environment>",x(u),e,{strict:!1}),E){let[ue,me]=E;A.useWithSource(ue,x(me),I,{strict:!1})}if(a){if(await sot({configuration:A,selfPath:a})!==null)return A;A.useWithSource("<override>",{ignorePath:!0},e,{strict:!1,overwrite:!0})}let N=await nA.findProjectCwd(e);A.startingCwd=e,A.projectCwd=N;let U=Object.assign(Object.create(null),process.env);A.env=U;let V=await Promise.all(A.get("injectEnvironmentFiles").map(async ue=>{let me=ue.endsWith("?")?await oe.readFilePromise(ue.slice(0,-1),"utf8").catch(()=>""):await oe.readFilePromise(ue,"utf8");return(0,Sle.parse)(me)}));for(let ue of V)for(let[me,he]of Object.entries(ue))A.env[me]=iS(he,{env:U});if(A.importSettings(C(Pb)),A.useWithSource("<environment>",C(u),e,{strict:o}),E){let[ue,me]=E;A.useWithSource(ue,C(me),I,{strict:o})}let te=ue=>"default"in ue?ue.default:ue,ae=new Map([["@@core",sse]]);if(r!==null)for(let ue of r.plugins.keys())ae.set(ue,te(r.modules.get(ue)));for(let[ue,me]of ae)A.activatePlugin(ue,me);let fe=new Map([]);if(r!==null){let ue=new Map;for(let Be of ble.builtinModules)ue.set(Be,()=>Df(Be));for(let[Be,we]of r.modules)ue.set(Be,()=>we);let me=new Set,he=async(Be,we)=>{let{factory:g,name:Ee}=Df(Be);if(!g||me.has(Ee))return;let Pe=new Map(ue),ce=ee=>{if(Pe.has(ee))return Pe.get(ee)();throw new it(`This plugin cannot access the package referenced via ${ee} which is neither a builtin, nor an exposed entry`)},ne=await Ky(async()=>te(await g(ce)),ee=>`${ee} (when initializing ${Ee}, defined in ${we})`);ue.set(Ee,()=>ne),me.add(Ee),fe.set(Ee,ne)};if(u.plugins)for(let Be of u.plugins.split(";")){let we=z.resolve(e,le.toPortablePath(Be));await he(we,"<environment>")}for(let{path:Be,cwd:we,data:g}of p)if(!!n&&!!Array.isArray(g.plugins))for(let Ee of g.plugins){let Pe=typeof Ee!="string"?Ee.path:Ee,ce=Ee?.spec??"",ne=Ee?.checksum??"";if(v1.has(ce))continue;let ee=z.resolve(we,le.toPortablePath(Pe));if(!await oe.existsPromise(ee)){if(!ce){let At=Ut(A,z.basename(ee,".cjs"),yt.NAME),H=Ut(A,".gitignore",yt.NAME),at=Ut(A,A.values.get("rcFilename"),yt.NAME),Re=Ut(A,"https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored",yt.URL);throw new it(`Missing source for the ${At} plugin - please try to remove the plugin from ${at} then reinstall it manually. This error usually occurs because ${H} is incorrect, check ${Re} to make sure your plugin folder isn't gitignored.`)}if(!ce.match(/^https?:/)){let At=Ut(A,z.basename(ee,".cjs"),yt.NAME),H=Ut(A,A.values.get("rcFilename"),yt.NAME);throw new it(`Failed to recognize the source for the ${At} plugin - please try to delete the plugin from ${H} then reinstall it manually.`)}let Ie=await N4(ce,{configuration:A}),Fe=Js(Ie);if(ne&&ne!==Fe){let At=Ut(A,z.basename(ee,".cjs"),yt.NAME),H=Ut(A,A.values.get("rcFilename"),yt.NAME),at=Ut(A,`yarn plugin import ${ce}`,yt.CODE);throw new it(`Failed to fetch the ${At} plugin from its remote location: its checksum seems to have changed. If this is expected, please remove the plugin from ${H} then run ${at} to reimport it.`)}await oe.mkdirPromise(z.dirname(ee),{recursive:!0}),await oe.writeFilePromise(ee,Ie)}await he(ee,Be)}}for(let[ue,me]of fe)A.activatePlugin(ue,me);if(A.useWithSource("<environment>",R(u),e,{strict:o}),E){let[ue,me]=E;A.useWithSource(ue,R(me),I,{strict:o})}return A.get("enableGlobalCache")&&(A.values.set("cacheFolder",`${A.get("globalFolder")}/cache`),A.sources.set("cacheFolder","<internal>")),A}static async findRcFiles(e){let r=G4(),o=[],a=e,n=null;for(;a!==n;){n=a;let u=z.join(n,r);if(oe.existsSync(u)){let A=await oe.readFilePromise(u,"utf8"),p;try{p=Ki(A)}catch{let E="";throw A.match(/^\s+(?!-)[^:]+\s+\S+/m)&&(E=" (in particular, make sure you list the colons after each key name)"),new it(`Parse error when loading ${u}; please check it's proper Yaml${E}`)}o.unshift({path:u,cwd:n,data:p})}a=z.dirname(n)}return o}static async findFolderRcFile(e){let r=z.join(e,dr.rc),o;try{o=await oe.readFilePromise(r,"utf8")}catch(n){if(n.code==="ENOENT")return null;throw n}let a=Ki(o);return{path:r,cwd:e,data:a}}static async findProjectCwd(e){let r=null,o=e,a=null;for(;o!==a;){if(a=o,oe.existsSync(z.join(a,dr.lockfile)))return a;oe.existsSync(z.join(a,dr.manifest))&&(r=a),o=z.dirname(a)}return r}static async updateConfiguration(e,r,o={}){let a=G4(),n=z.join(e,a),u=oe.existsSync(n)?Ki(await oe.readFilePromise(n,"utf8")):{},A=!1,p;if(typeof r=="function"){try{p=r(u)}catch{p=r({})}if(p===u)return!1}else{p=u;for(let h of Object.keys(r)){let E=u[h],I=r[h],v;if(typeof I=="function")try{v=I(E)}catch{v=I(void 0)}else v=I;E!==v&&(v===nA.deleteProperty?delete p[h]:p[h]=v,A=!0)}if(!A)return!1}return await oe.changeFilePromise(n,Ba(p),{automaticNewlines:!0}),!0}static async addPlugin(e,r){r.length!==0&&await nA.updateConfiguration(e,o=>{let a=o.plugins??[];if(a.length===0)return{...o,plugins:r};let n=[],u=[...r];for(let A of a){let p=typeof A!="string"?A.path:A,h=u.find(E=>E.path===p);h?(n.push(h),u=u.filter(E=>E!==h)):n.push(A)}return n.push(...u),{...o,plugins:n}})}static async updateHomeConfiguration(e){let r=EE();return await nA.updateConfiguration(r,e)}activatePlugin(e,r){this.plugins.set(e,r),typeof r.configuration<"u"&&this.importSettings(r.configuration)}importSettings(e){for(let[r,o]of Object.entries(e))if(o!=null){if(this.settings.has(r))throw new Error(`Cannot redefine settings "${r}"`);this.settings.set(r,o),this.values.set(r,W4(this,o))}}useWithSource(e,r,o,a){try{this.use(e,r,o,a)}catch(n){throw n.message+=` (in ${Ut(this,e,yt.PATH)})`,n}}use(e,r,o,{strict:a=!0,overwrite:n=!1}={}){a=a&&this.get("enableStrictSettings");for(let u of["enableStrictSettings",...Object.keys(r)]){let A=r[u],p=mM(A);if(p&&(e=p),typeof A>"u"||u==="plugins"||e==="<environment>"&&Xst.has(u))continue;if(u==="rcFilename")throw new it(`The rcFilename settings can only be set via ${`${bb}RC_FILENAME`.toUpperCase()}, not via a rc file`);let h=this.settings.get(u);if(!h){let I=EE(),v=e[0]!=="<"?z.dirname(e):null;if(a&&!(v!==null?I===v:!1))throw new it(`Unrecognized or legacy configuration settings found: ${u} - run "yarn config -v" to see the list of settings supported in Yarn`);this.invalid.set(u,e);continue}if(this.sources.has(u)&&!(n||h.type==="MAP"||h.isArray&&h.concatenateValues))continue;let E;try{E=Y4(this,u,A,h,o)}catch(I){throw I.message+=` in ${Ut(this,e,yt.PATH)}`,I}if(u==="enableStrictSettings"&&e!=="<environment>"){a=E;continue}if(h.type==="MAP"){let I=this.values.get(u);this.values.set(u,new Map(n?[...I,...E]:[...E,...I])),this.sources.set(u,`${this.sources.get(u)}, ${e}`)}else if(h.isArray&&h.concatenateValues){let I=this.values.get(u);this.values.set(u,n?[...I,...E]:[...E,...I]),this.sources.set(u,`${this.sources.get(u)}, ${e}`)}else this.values.set(u,E),this.sources.set(u,e)}}get(e){if(!this.values.has(e))throw new Error(`Invalid configuration key "${e}"`);return this.values.get(e)}getSpecial(e,{hideSecrets:r=!1,getNativePaths:o=!1}){let a=this.get(e),n=this.settings.get(e);if(typeof n>"u")throw new it(`Couldn't find a configuration settings named "${e}"`);return Sb(a,n,{hideSecrets:r,getNativePaths:o})}getSubprocessStreams(e,{header:r,prefix:o,report:a}){let n,u,A=oe.createWriteStream(e);if(this.get("enableInlineBuilds")){let p=a.createStreamReporter(`${o} ${Ut(this,"STDOUT","green")}`),h=a.createStreamReporter(`${o} ${Ut(this,"STDERR","red")}`);n=new q4.PassThrough,n.pipe(p),n.pipe(A),u=new q4.PassThrough,u.pipe(h),u.pipe(A)}else n=A,u=A,typeof r<"u"&&n.write(`${r}
-`);return{stdout:n,stderr:u}}makeResolver(){let e=[];for(let r of this.plugins.values())for(let o of r.resolvers||[])e.push(new o);return new Pd([new c1,new Xn,...e])}makeFetcher(){let e=[];for(let r of this.plugins.values())for(let o of r.fetchers||[])e.push(new o);return new hE([new gE,new mE,...e])}getLinkers(){let e=[];for(let r of this.plugins.values())for(let o of r.linkers||[])e.push(new o);return e}getSupportedArchitectures(){let e=B1(),r=this.get("supportedArchitectures"),o=r.get("os");o!==null&&(o=o.map(u=>u==="current"?e.os:u));let a=r.get("cpu");a!==null&&(a=a.map(u=>u==="current"?e.cpu:u));let n=r.get("libc");return n!==null&&(n=ol(n,u=>u==="current"?e.libc??ol.skip:u)),{os:o,cpu:a,libc:n}}async getPackageExtensions(){if(this.packageExtensions!==null)return this.packageExtensions;this.packageExtensions=new Map;let e=this.packageExtensions,r=(o,a,{userProvided:n=!1}={})=>{if(!xa(o.range))throw new Error("Only semver ranges are allowed as keys for the packageExtensions setting");let u=new Ot;u.load(a,{yamlCompatibilityMode:!0});let A=Yy(e,o.identHash),p=[];A.push([o.range,p]);let h={status:"inactive",userProvided:n,parentDescriptor:o};for(let E of u.dependencies.values())p.push({...h,type:"Dependency",descriptor:E});for(let E of u.peerDependencies.values())p.push({...h,type:"PeerDependency",descriptor:E});for(let[E,I]of u.peerDependenciesMeta)for(let[v,x]of Object.entries(I))p.push({...h,type:"PeerDependencyMeta",selector:E,key:v,value:x})};await this.triggerHook(o=>o.registerPackageExtensions,this,r);for(let[o,a]of this.get("packageExtensions"))r(sh(o,!0),nS(a),{userProvided:!0});return e}normalizeLocator(e){return xa(e.reference)?Qs(e,`${this.get("defaultProtocol")}${e.reference}`):FE.test(e.reference)?Qs(e,`${this.get("defaultProtocol")}${e.reference}`):e}normalizeDependency(e){return xa(e.range)?In(e,`${this.get("defaultProtocol")}${e.range}`):FE.test(e.range)?In(e,`${this.get("defaultProtocol")}${e.range}`):e}normalizeDependencyMap(e){return new Map([...e].map(([r,o])=>[r,this.normalizeDependency(o)]))}normalizePackage(e,{packageExtensions:r}){let o=e1(e),a=r.get(e.identHash);if(typeof a<"u"){let u=e.version;if(u!==null){for(let[A,p]of a)if(!!kf(u,A))for(let h of p)switch(h.status==="inactive"&&(h.status="redundant"),h.type){case"Dependency":typeof o.dependencies.get(h.descriptor.identHash)>"u"&&(h.status="active",o.dependencies.set(h.descriptor.identHash,this.normalizeDependency(h.descriptor)));break;case"PeerDependency":typeof o.peerDependencies.get(h.descriptor.identHash)>"u"&&(h.status="active",o.peerDependencies.set(h.descriptor.identHash,h.descriptor));break;case"PeerDependencyMeta":{let E=o.peerDependenciesMeta.get(h.selector);(typeof E>"u"||!Object.hasOwn(E,h.key)||E[h.key]!==h.value)&&(h.status="active",al(o.peerDependenciesMeta,h.selector,()=>({}))[h.key]=h.value)}break;default:EN(h)}}}let n=u=>u.scope?`${u.scope}__${u.name}`:`${u.name}`;for(let u of o.peerDependenciesMeta.keys()){let A=Vs(u);o.peerDependencies.has(A.identHash)||o.peerDependencies.set(A.identHash,In(A,"*"))}for(let u of o.peerDependencies.values()){if(u.scope==="types")continue;let A=n(u),p=tA("types",A),h=fn(p);o.peerDependencies.has(p.identHash)||o.peerDependenciesMeta.has(h)||(o.peerDependencies.set(p.identHash,In(p,"*")),o.peerDependenciesMeta.set(h,{optional:!0}))}return o.dependencies=new Map(ks(o.dependencies,([,u])=>Sa(u))),o.peerDependencies=new Map(ks(o.peerDependencies,([,u])=>Sa(u))),o}getLimit(e){return al(this.limits,e,()=>(0,xle.default)(this.get(e)))}async triggerHook(e,...r){for(let o of this.plugins.values()){let a=o.hooks;if(!a)continue;let n=e(a);!n||await n(...r)}}async triggerMultipleHooks(e,r){for(let o of r)await this.triggerHook(e,...o)}async reduceHook(e,r,...o){let a=r;for(let n of this.plugins.values()){let u=n.hooks;if(!u)continue;let A=e(u);!A||(a=await A(a,...o))}return a}async firstHook(e,...r){for(let o of this.plugins.values()){let a=o.hooks;if(!a)continue;let n=e(a);if(!n)continue;let u=await n(...r);if(typeof u<"u")return u}return null}},Ke=nA;Ke.deleteProperty=Symbol(),Ke.telemetry=null});var Ur={};zt(Ur,{EndStrategy:()=>J4,ExecError:()=>kb,PipeError:()=>S1,execvp:()=>_4,pipevp:()=>Yc});function xd(t){return t!==null&&typeof t.fd=="number"}function K4(){}function z4(){for(let t of kd)t.kill()}async function Yc(t,e,{cwd:r,env:o=process.env,strict:a=!1,stdin:n=null,stdout:u,stderr:A,end:p=2}){let h=["pipe","pipe","pipe"];n===null?h[0]="ignore":xd(n)&&(h[0]=n),xd(u)&&(h[1]=u),xd(A)&&(h[2]=A);let E=(0,V4.default)(t,e,{cwd:le.fromPortablePath(r),env:{...o,PWD:le.fromPortablePath(r)},stdio:h});kd.add(E),kd.size===1&&(process.on("SIGINT",K4),process.on("SIGTERM",z4)),!xd(n)&&n!==null&&n.pipe(E.stdin),xd(u)||E.stdout.pipe(u,{end:!1}),xd(A)||E.stderr.pipe(A,{end:!1});let I=()=>{for(let v of new Set([u,A]))xd(v)||v.end()};return new Promise((v,x)=>{E.on("error",C=>{kd.delete(E),kd.size===0&&(process.off("SIGINT",K4),process.off("SIGTERM",z4)),(p===2||p===1)&&I(),x(C)}),E.on("close",(C,R)=>{kd.delete(E),kd.size===0&&(process.off("SIGINT",K4),process.off("SIGTERM",z4)),(p===2||p===1&&C!==0)&&I(),C===0||!a?v({code:X4(C,R)}):x(new S1({fileName:t,code:C,signal:R}))})})}async function _4(t,e,{cwd:r,env:o=process.env,encoding:a="utf8",strict:n=!1}){let u=["ignore","pipe","pipe"],A=[],p=[],h=le.fromPortablePath(r);typeof o.PWD<"u"&&(o={...o,PWD:h});let E=(0,V4.default)(t,e,{cwd:h,env:o,stdio:u});return E.stdout.on("data",I=>{A.push(I)}),E.stderr.on("data",I=>{p.push(I)}),await new Promise((I,v)=>{E.on("error",x=>{let C=Ke.create(r),R=Ut(C,t,yt.PATH);v(new Jt(1,`Process ${R} failed to spawn`,N=>{N.reportError(1,` ${Xu(C,{label:"Thrown Error",value:Hc(yt.NO_HINT,x.message)})}`)}))}),E.on("close",(x,C)=>{let R=a==="buffer"?Buffer.concat(A):Buffer.concat(A).toString(a),N=a==="buffer"?Buffer.concat(p):Buffer.concat(p).toString(a);x===0||!n?I({code:X4(x,C),stdout:R,stderr:N}):v(new kb({fileName:t,code:x,signal:C,stdout:R,stderr:N}))})})}function X4(t,e){let r=oot.get(e);return typeof r<"u"?128+r:t??1}function aot(t,e,{configuration:r,report:o}){o.reportError(1,` ${Xu(r,t!==null?{label:"Exit Code",value:Hc(yt.NUMBER,t)}:{label:"Exit Signal",value:Hc(yt.CODE,e)})}`)}var V4,J4,S1,kb,kd,oot,Db=Et(()=>{Pt();V4=$e(sT());P1();Wl();jl();J4=(o=>(o[o.Never=0]="Never",o[o.ErrorCode=1]="ErrorCode",o[o.Always=2]="Always",o))(J4||{}),S1=class extends Jt{constructor({fileName:r,code:o,signal:a}){let n=Ke.create(z.cwd()),u=Ut(n,r,yt.PATH);super(1,`Child ${u} reported an error`,A=>{aot(o,a,{configuration:n,report:A})});this.code=X4(o,a)}},kb=class extends S1{constructor({fileName:r,code:o,signal:a,stdout:n,stderr:u}){super({fileName:r,code:o,signal:a});this.stdout=n,this.stderr=u}};kd=new Set;oot=new Map([["SIGINT",2],["SIGQUIT",3],["SIGKILL",9],["SIGTERM",15]])});function Fle(t){Qle=t}function b1(){return typeof Z4>"u"&&(Z4=Qle()),Z4}var Z4,Qle,$4=Et(()=>{Qle=()=>{throw new Error("Assertion failed: No libzip instance is available, and no factory was configured")}});var Rle=_((Qb,tU)=>{var lot=Object.assign({},ve("fs")),eU=function(){var t=typeof document<"u"&&document.currentScript?document.currentScript.src:void 0;return typeof __filename<"u"&&(t=t||__filename),function(e){e=e||{};var r=typeof e<"u"?e:{},o,a;r.ready=new Promise(function(We,tt){o=We,a=tt});var n={},u;for(u in r)r.hasOwnProperty(u)&&(n[u]=r[u]);var A=[],p="./this.program",h=function(We,tt){throw tt},E=!1,I=!0,v="";function x(We){return r.locateFile?r.locateFile(We,v):v+We}var C,R,N,U;I&&(E?v=ve("path").dirname(v)+"/":v=__dirname+"/",C=function(tt,It){var ir=ii(tt);return ir?It?ir:ir.toString():(N||(N=lot),U||(U=ve("path")),tt=U.normalize(tt),N.readFileSync(tt,It?null:"utf8"))},R=function(tt){var It=C(tt,!0);return It.buffer||(It=new Uint8Array(It)),Ee(It.buffer),It},process.argv.length>1&&(p=process.argv[1].replace(/\\/g,"/")),A=process.argv.slice(2),h=function(We){process.exit(We)},r.inspect=function(){return"[Emscripten Module object]"});var V=r.print||console.log.bind(console),te=r.printErr||console.warn.bind(console);for(u in n)n.hasOwnProperty(u)&&(r[u]=n[u]);n=null,r.arguments&&(A=r.arguments),r.thisProgram&&(p=r.thisProgram),r.quit&&(h=r.quit);var ae=0,fe=function(We){ae=We},ue;r.wasmBinary&&(ue=r.wasmBinary);var me=r.noExitRuntime||!0;typeof WebAssembly!="object"&&Ti("no native wasm support detected");function he(We,tt,It){switch(tt=tt||"i8",tt.charAt(tt.length-1)==="*"&&(tt="i32"),tt){case"i1":return He[We>>0];case"i8":return He[We>>0];case"i16":return up((We>>1)*2);case"i32":return Os((We>>2)*4);case"i64":return Os((We>>2)*4);case"float":return uu((We>>2)*4);case"double":return cp((We>>3)*8);default:Ti("invalid type for getValue: "+tt)}return null}var Be,we=!1,g;function Ee(We,tt){We||Ti("Assertion failed: "+tt)}function Pe(We){var tt=r["_"+We];return Ee(tt,"Cannot call unknown function "+We+", make sure it is exported"),tt}function ce(We,tt,It,ir,$){var ye={string:function(es){var bi=0;if(es!=null&&es!==0){var qo=(es.length<<2)+1;bi=Un(qo),At(es,bi,qo)}return bi},array:function(es){var bi=Un(es.length);return Re(es,bi),bi}};function Ne(es){return tt==="string"?Ie(es):tt==="boolean"?Boolean(es):es}var pt=Pe(We),ht=[],Tt=0;if(ir)for(var er=0;er<ir.length;er++){var $r=ye[It[er]];$r?(Tt===0&&(Tt=ms()),ht[er]=$r(ir[er])):ht[er]=ir[er]}var Gi=pt.apply(null,ht);return Gi=Ne(Gi),Tt!==0&&_s(Tt),Gi}function ne(We,tt,It,ir){It=It||[];var $=It.every(function(Ne){return Ne==="number"}),ye=tt!=="string";return ye&&$&&!ir?Pe(We):function(){return ce(We,tt,It,arguments,ir)}}var ee=new TextDecoder("utf8");function Ie(We,tt){if(!We)return"";for(var It=We+tt,ir=We;!(ir>=It)&&Te[ir];)++ir;return ee.decode(Te.subarray(We,ir))}function Fe(We,tt,It,ir){if(!(ir>0))return 0;for(var $=It,ye=It+ir-1,Ne=0;Ne<We.length;++Ne){var pt=We.charCodeAt(Ne);if(pt>=55296&&pt<=57343){var ht=We.charCodeAt(++Ne);pt=65536+((pt&1023)<<10)|ht&1023}if(pt<=127){if(It>=ye)break;tt[It++]=pt}else if(pt<=2047){if(It+1>=ye)break;tt[It++]=192|pt>>6,tt[It++]=128|pt&63}else if(pt<=65535){if(It+2>=ye)break;tt[It++]=224|pt>>12,tt[It++]=128|pt>>6&63,tt[It++]=128|pt&63}else{if(It+3>=ye)break;tt[It++]=240|pt>>18,tt[It++]=128|pt>>12&63,tt[It++]=128|pt>>6&63,tt[It++]=128|pt&63}}return tt[It]=0,It-$}function At(We,tt,It){return Fe(We,Te,tt,It)}function H(We){for(var tt=0,It=0;It<We.length;++It){var ir=We.charCodeAt(It);ir>=55296&&ir<=57343&&(ir=65536+((ir&1023)<<10)|We.charCodeAt(++It)&1023),ir<=127?++tt:ir<=2047?tt+=2:ir<=65535?tt+=3:tt+=4}return tt}function at(We){var tt=H(We)+1,It=Ni(tt);return It&&Fe(We,He,It,tt),It}function Re(We,tt){He.set(We,tt)}function ke(We,tt){return We%tt>0&&(We+=tt-We%tt),We}var xe,He,Te,Ve,qe,b,w,S,y,F;function J(We){xe=We,r.HEAP_DATA_VIEW=F=new DataView(We),r.HEAP8=He=new Int8Array(We),r.HEAP16=Ve=new Int16Array(We),r.HEAP32=b=new Int32Array(We),r.HEAPU8=Te=new Uint8Array(We),r.HEAPU16=qe=new Uint16Array(We),r.HEAPU32=w=new Uint32Array(We),r.HEAPF32=S=new Float32Array(We),r.HEAPF64=y=new Float64Array(We)}var X=r.INITIAL_MEMORY||16777216,Z,ie=[],be=[],Le=[],ot=!1;function dt(){if(r.preRun)for(typeof r.preRun=="function"&&(r.preRun=[r.preRun]);r.preRun.length;)bt(r.preRun.shift());oo(ie)}function Gt(){ot=!0,oo(be)}function $t(){if(r.postRun)for(typeof r.postRun=="function"&&(r.postRun=[r.postRun]);r.postRun.length;)Qr(r.postRun.shift());oo(Le)}function bt(We){ie.unshift(We)}function an(We){be.unshift(We)}function Qr(We){Le.unshift(We)}var mr=0,br=null,Wr=null;function Kn(We){mr++,r.monitorRunDependencies&&r.monitorRunDependencies(mr)}function Ls(We){if(mr--,r.monitorRunDependencies&&r.monitorRunDependencies(mr),mr==0&&(br!==null&&(clearInterval(br),br=null),Wr)){var tt=Wr;Wr=null,tt()}}r.preloadedImages={},r.preloadedAudios={};function Ti(We){r.onAbort&&r.onAbort(We),We+="",te(We),we=!0,g=1,We="abort("+We+"). Build with -s ASSERTIONS=1 for more info.";var tt=new WebAssembly.RuntimeError(We);throw a(tt),tt}var ps="data:application/octet-stream;base64,";function io(We){return We.startsWith(ps)}var Si="data:application/octet-stream;base64,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QCAAKAJIIgEgASADaiADEAcaAkAgAyAAKAJsIgFNBEAgACABIANrNgJsDAELIABCADcCbAsgACAAKAJoIANrIgE2AmggACAAKAJYIANrNgJYIAEgACgChC5JBEAgACABNgKELgsgAEH8gAEoAgARAwAgAiADaiECCwJAIAAoAgAiASgCBCIERQ0AIAAoAjwhBSAAIAIgBCACIARJGyICBH8gACgCSCAAKAJoaiAFaiEFIAEgBCACazYCBAJAAkACQAJAIAEoAhwiBCgCFEEBaw4CAQACCyAEQaABaiAFIAEoAgAgAkHcgAEoAgARCAAMAgsgASABKAIwIAUgASgCACACQcSAASgCABEEADYCMAwBCyAFIAEoAgAgAhAHGgsgASABKAIAIAJqNgIAIAEgASgCCCACajYCCCAAKAI8BSAFCyACaiICNgI8AkAgACgChC4iASACakEDSQ0AIAAoAmggAWshAQJAIAAoAnRBgQhPBEAgACAAIAAoAkggAWoiAi0AACACLQABIAAoAnwRAAA2AlQMAQsgAUUNACAAIAFBAWsgACgChAERAgAaCyAAKAKELiAAKAI8IgJBAUZrIgRFDQAgACABIAQgACgCgAERBQAgACAAKAKELiAEazYChC4gACgCPCECCyACQYUCSw0AIAAoAgAoAgRFDQAgACgCMCEBDAELCwJAIAAoAkQiAiAAKAJAIgNNDQAgAAJ/IAAoAjwgACgCaGoiASADSwRAIAAoAkggAWpBACACIAFrIgNBggIgA0GCAkkbIgMQGSABIANqDAELIAFBggJqIgEgA00NASAAKAJIIANqQQAgAiADayICIAEgA2siAyACIANJGyIDEBkgACgCQCADags2AkALC50CAQF/AkAgAAJ/IAAoAqAuIgFBwABGBEAgACgCBCAAKAIQaiAAKQOYLjcAACAAQgA3A5guIAAgACgCEEEIajYCEEEADAELIAFBIE4EQCAAKAIEIAAoAhBqIAApA5guPgAAIAAgAEGcLmo1AgA3A5guIAAgACgCEEEEajYCECAAIAAoAqAuQSBrIgE2AqAuCyABQRBOBEAgACgCBCAAKAIQaiAAKQOYLj0AACAAIAAoAhBBAmo2AhAgACAAKQOYLkIQiDcDmC4gACAAKAKgLkEQayIBNgKgLgsgAUEISA0BIAAgACgCECIBQQFqNgIQ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KAJUIgEEfyABQQAgARAiEBkgACgCVAVBAAsQBiAAQQA2AlQLC9wMAgl/AX4jAEFAaiIGJAACQAJAAkACQAJAIAEoAjBBABAjIgVBAkZBACABKAI4QQAQIyIEQQFGGw0AIAVBAUZBACAEQQJGGw0AIAVBAkciAw0BIARBAkcNAQsgASABLwEMQYAQcjsBDEEAIQMMAQsgASABLwEMQf/vA3E7AQxBACEFIANFBEBB9eABIAEoAjAgAEEIahBpIgVFDQILIAJBgAJxBEAgBSEDDAELIARBAkcEQCAFIQMMAQtB9cYBIAEoAjggAEEIahBpIgNFBEAgBRAcDAILIAMgBTYCAAsgASABLwEMQf7/A3EgAS8BUiIFQQBHcjsBDAJAAkACQAJAAn8CQAJAIAEpAyhC/v///w9WDQAgASkDIEL+////D1YNACACQYAEcUUNASABKQNIQv////8PVA0BCyAFQYECa0H//wNxQQNJIQdBAQwBCyAFQYECa0H//wNxIQQgAkGACnFBgApHDQEgBEEDSSEHQQALIQkgBkIcEBciBEUEQCAAQQhqIgAEQCAAQQA2AgQgAEEONgIACyADEBwMBQsgAkGACHEhBQJAAkAgAkGAAnEEQAJAIAUNACABKQMgQv////8PVg0AIAEpAyhCgICAgBBUDQMLIAQgASkDKBAYIAEpAyAhDAwBCwJAAkACQCAFDQAgASkDIEL/////D1YNACABKQMoIgxC/////w9WDQEgASkDSEKAgICAEFQNBAsgASkDKCIMQv////8PVA0BCyAEIAwQGAsgASkDICIMQv////8PWgRAIAQgDBAYCyABKQNIIgxC/////w9UDQELIAQgDBAYCyAELQAARQRAIABBCGoiAARAIABBADYCBCAAQRQ2AgALIAQQCCADEBwMBQtBASEKQQEgBC0AAAR+IAQpAxAFQgALp0H//wNxIAYQRyEFIAQQCCAFIAM2AgAgBw0BDAILIAMhBSAEQQJLDQELIAZCBxAXIgRFBEAgAEEIaiIABEAgAEEANgIEIABBDjYCAAsgBRAcDAMLIARBAhANIARBhxJBAhAsIAQgAS0AUhBwIAQgAS8BEBANIAQtAABFBEAgAEEIaiIABEAgAEEANgIEIABBFDYCAAsgBBAIDAILQYGyAkEHIAYQRyEDIAQQCCADIAU2AgBBASEL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NgIEIABB7A42AhggGiEdDAMLIARB/wFxIgJBwABxRQRAIAggDSADLwECQQJ0aiAdp0F/IAJ0QX9zcUECdGoiAy0AASICayEIIB0gAq2IIR0gAy0AACIERQ0HDAELCyAEQSBxBEAgB0G//gA2AgQgASECDAgLIAdB0f4ANgIEIABB0A42AhggASECDAcLIB1BfyAGdEF/c62DIBt8IhunIQUgCCAEQQ9xIgNrIQggGiAErUIPg4ghHSABIBdrIgYgAjMBAiAaQX8gA3RBf3Otg3ynIgRPDQIgBCAGayIGIBlNDQEgBygCjEdFDQEgB0HR/gA2AgQgAEG5DDYCGAsgASECIAshBQwFCwJAIA5FBEAgDCARIAZraiEDDAELIAYgDk0EQCAMIA4gBmtqIQMMAQsgDCARIAYgDmsiBmtqIQMgBSAGTQ0AIAUgBmshBQJAAkAgASADTSABIA8gAWusIhogBq0iGyAaIBtUGyIapyIGaiICIANLcQ0AIAMgBmogAUsgASADT3ENACABIAMgBhAHGiACIQEMAQsgASADIAMgAWsiASABQR91IgFqIAFzIgIQByACaiEBIBogAq0iHn0iHFANACACIANqIQIDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgASACKQAANwAAIAEgAikAGDcAGCABIAIpABA3ABAgASACKQAINwAIIBpCIH0hGiACQSBqIQIgAUEgaiEBIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAEgAikAADcAACABIAIpABg3ABggASACKQAQNwAQIAEgAikACDcACCABIAIpADg3ADggASACKQAwNwAwIAEgAikAKDcAKCABIAIpACA3ACAgASACKQBYNwBYIAEgAikAUDcAUCABIAIpAEg3AEggASACKQBANwBAIAEgAikAYDcAYCABIAIpAGg3AGggASACKQBwNwBwIAEgAikAeDcAeCACQYABaiECIAFBgAFqIQEgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAEgAikAADcAACABIAIpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCABIAIpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCABIAIoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCABIAIvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCABIAItAAA6AAAgAkEBaiECIAFBAWohAQsgHEIAUg0ACwsgDiEGIAwhAwsgBSAGSwRAAkACQCABIANNIAEgDyABa6wiGiAGrSIbIBogG1QbIhqnIglqIgIgA0txDQAgAyAJaiABSyABIANPcQ0AIAEgAyAJEAcaDAELIAEgAyADIAFrIgEgAUEfdSIBaiABcyIBEAcgAWohAiAaIAGtIh59IhxQDQAgASADaiEBA0ACQCAcIB4gHCAeVBsiG0IgVARAIBshGgwBCyAbIhpCIH0iIEIFiEIBfEIDgyIfUEUEQANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCAaQiB9IRogAUEgaiEBIAJBIGohAiAfQgF9Ih9CAFINAAsLICBC4ABUDQADQCACIAEpAAA3AAAgAiABKQAYNwAYIAIgASkAEDcAECACIAEpAAg3AAggAiABKQA4NwA4IAIgASkAMDcAMCACIAEpACg3ACggAiABKQAgNwAgIAIgASkAWDcAWCACIAEpAFA3AFAgAiABKQBINwBIIAIgASkAQDcAQCACIAEpAGA3AGAgAiABKQBoNwBoIAIgASkAcDcAcCACIAEpAHg3AHggAUGAAWohASACQYABaiECIBpCgAF9IhpCH1YNAAsLIBpCEFoEQCACIAEpAAA3AAAgAiABKQAINwAIIBpCEH0hGiACQRBqIQIgAUEQaiEBCyAaQghaBEAgAiABKQAANwAAIBpCCH0hGiACQQhqIQIgAUEIaiEBCyAaQgRaBEAgAiABKAAANgAAIBpCBH0hGiACQQRqIQIgAUEEaiEBCyAaQgJaBEAgAiABLwAAOwAAIBpCAn0hGiACQQJqIQIgAUECaiEBCyAcIBt9IRwgGlBFBEAgAiABLQAAOgAAIAJBAWohAiABQQFqIQELIBxCAFINAAsLIAUgBmshAUEAIARrIQUCQCAEQQdLBEAgBCEDDAELIAEgBE0EQCAEIQMMAQsgAiAEayEFA0ACQCACIAUpAAA3AAAgBEEBdCEDIAEgBGshASACIARqIQIgBEEDSw0AIAMhBCABIANLDQELC0EAIANrIQULIAIgBWohBAJAIAUgDyACa6wiGiABrSIbIBogG1QbIhqnIgFIIAVBf0pxDQAgBUEBSCABIARqIAJLcQ0AIAIgBCABEAcgAWohAgwDCyACIAQgAyADQR91IgFqIAFzIgEQByABaiECIBogAa0iHn0iHFANAiABIARqIQEDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIBpCIH0hGiABQSBqIQEgAkEgaiECIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCACIAEpADg3ADggAiABKQAwNwAwIAIgASkAKDcAKCACIAEpACA3ACAgAiABKQBYNwBYIAIgASkAUDcAUCACIAEpAEg3AEggAiABKQBANwBAIAIgASkAYDcAYCACIAEpAGg3AGggAiABKQBwNwBwIAIgASkAeDcAeCABQYABaiEBIAJBgAFqIQIgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAIgASkAADcAACACIAEpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCACIAEpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCACIAEoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCACIAEvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCACIAEtAAA6AAAgAkEBaiECIAFBAWohAQsgHFBFDQALDAILAkAgASADTSABIA8gAWusIhogBa0iGyAaIBtUGyIapyIEaiICIANLcQ0AIAMgBGogAUsgASADT3ENACABIAMgBBAHGgwCCyABIAMgAyABayIBIAFBH3UiAWogAXMiARAHIAFqIQIgGiABrSIefSIcUA0BIAEgA2ohAQNAAkAgHCAeIBwgHlQbIhtCIFQEQCAbIRoMAQsgGyIaQiB9IiBCBYhCAXxCA4MiH1BFBEADQCACIAEpAAA3AAAgAiABKQAYNwAYIAIgASkAEDcAECACIAEpAAg3AAggGkIgfSEaIAFBIGohASACQSBqIQIgH0IBfSIfQgBSDQALCyAgQuAAVA0AA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIAIgASkAODcAOCACIAEpADA3ADAgAiABKQAoNwAoIAIgASkAIDcAICACIAEpAFg3AFggAiABKQBQNwBQIAIgASkASDcASCACIAEpAEA3AEAgAiABKQBgNwBgIAIgASkAaDcAaCACIAEpAHA3AHAgAiABKQB4NwB4IAFBgAFqIQEgAkGAAWohAiAaQoABfSIaQh9WDQALCyAaQhBaBEAgAiABKQAANwAAIAIgASkACDcACCAaQhB9IRogAkEQaiECIAFBEGohAQsgGkIIWgRAIAIgASkAADcAACAaQgh9IRogAkEIaiECIAFBCGohAQsgGkIEWgRAIAIgASgAADYAACAaQgR9IRogAkEEaiECIAFBBGohAQsgGkICWgRAIAIgAS8AADsAACAaQgJ9IRogAkECaiECIAFBAmohAQsgHCAbfSEcIBpQRQRAIAIgAS0AADoAACACQQFqIQIgAUEBaiEBCyAcUEUNAAsMAQsCQAJAIBYEQAJAIAQgBUkEQCAHKAKYRyAESw0BCyABIARrIQMCQEEAIARrIgVBf0ogDyABa6wiGiAbIBogG1QbIhqnIgIgBUpxDQAgBUEBSCACIANqIAFLcQ0AIAEgAyACEAcgAmohAgwFCyABIAMgBCAEQR91IgFqIAFzIgEQByABaiECIBogAa0iHn0iHFANBCABIANqIQEDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIBpCIH0hGiABQSBqIQEgAkEgaiECIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCACIAEpADg3ADggAiABKQAwNwAwIAIgASkAKDcAKCACIAEpACA3ACAgAiABKQBYNwBYIAIgASkAUDcAUCACIAEpAEg3AEggAiABKQBANwBAIAIgASkAYDcAYCACIAEpAGg3AGggAiABKQBwNwBwIAIgASkAeDcAeCABQYABaiEBIAJBgAFqIQIgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAIgASkAADcAACACIAEpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCACIAEpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCACIAEoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCACIAEvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCACIAEtAAA6AAAgAkEBaiECIAFBAWohAQsgHFBFDQALDAQLIBAgAWsiCUEBaiIGIAUgBSAGSxshAyABIARrIQIgAUEHcUUNAiADRQ0CIAEgAi0AADoAACACQQFqIQIgAUEBaiIGQQdxQQAgA0EBayIFGw0BIAYhASAFIQMgCSEGDAILAkAgBCAFSQRAIAcoAphHIARLDQELIAEgASAEayIGKQAANwAAIAEgBUEBa0EHcUEBaiIDaiECIAUgA2siBEUNAyADIAZqIQEDQCACIAEpAAA3AAAgAUEIaiEBIAJBCGohAiAEQQhrIgQNAAsMAwsgASAEIAUQPyECDAILIAEgAi0AADoAASAJQQFrIQYgA0ECayEFIAJBAWohAgJAIAFBAmoiCkEHcUUNACAFRQ0AIAEgAi0AADoAAiAJQQJrIQYgA0EDayEFIAJBAWohAgJAIAFBA2oiCkEHcUUNACAFRQ0AIAEgAi0AADoAAyAJQQNrIQYgA0EEayEFIAJBAWohAgJAIAFBBGoiCkEHcUUNACAFRQ0AIAEgAi0AADoABCAJQQRrIQYgA0EFayEFIAJBAWohAgJAIAFBBWoiCkEHcUUNACAFRQ0AIAEgAi0AADoABSAJQQVrIQYgA0EGayEFIAJBAWohAgJAIAFBBmoiCkEHcUUNACAFRQ0AIAEgAi0AADoABiAJQQZrIQYgA0EHayEFIAJBAWohAgJAIAFBB2oiCkEHcUUNACAFRQ0AIAEgAi0AADoAByAJQQdrIQYgA0EIayEDIAFBCGohASACQQFqIQIMBgsgCiEBIAUhAwwFCyAKIQEgBSEDDAQLIAohASAFIQMMAwsgCiEBIAUhAwwCCyAKIQEgBSEDDAELIAohASAFIQMLAkACQCAGQRdNBEAgA0UNASADQQFrIQUgA0EHcSIEBEADQCABIAItAAA6AAAgA0EBayEDIAFBAWohASACQQFqIQIgBEEBayIEDQALCyAFQQdJDQEDQCABIAItAAA6AAAgASACLQABOgABIAEgAi0AAjoAAiABIAItAAM6AAMgASACLQAEOgAEIAEgAi0ABToABSABIAItAAY6AAYgASACLQAHOgAHIAFBCGohASACQQhqIQIgA0EIayIDDQALDAELIAMNAQsgASECDAELIAEgBCADED8hAgsgCyEFDAELIAEgAy0AAjoAACABQQFqIQILIAUgFE8NACACIBNJDQELCyAAIAI2AgwgACAFIAhBA3ZrIgE2AgAgACATIAJrQYMCajYCECAAIBQgAWtBDmo2AgQgByAIQQdxIgA2AogBIAcgHUJ/IACthkJ/hYM+AoQBC+cFAQR/IAMgAiACIANLGyEEIAAgAWshAgJAIABBB3FFDQAgBEUNACAAIAItAAA6AAAgA0EBayEGIAJBAWohAiAAQQFqIgdBB3FBACAEQQFrIgUbRQRAIAchACAFIQQgBiEDDAELIAAgAi0AADoAASADQQJrIQYgBEECayEFIAJBAWohAgJAIABBAmoiB0EHcUUNACAFRQ0AIAAgAi0AADoAAiADQQNrIQYgBEEDayEFIAJBAWohAgJAIABBA2oiB0EHcUUNACAFRQ0AIAAgAi0AADoAAyADQQRrIQYgBEEEayEFIAJBAWohAgJAIABBBGoiB0EHcUUNACAFRQ0AIAAgAi0AADoABCADQQVrIQYgBEEFayEFIAJBAWohAgJAIABBBWoiB0EHcUUNACAFRQ0AIAAgAi0AADoABSADQQZrIQYgBEEGayEFIAJBAWohAgJAIABBBmoiB0EHcUUNACAFRQ0AIAAgAi0AADoABiADQQdrIQYgBEEHayEFIAJBAWohAgJAIABBB2oiB0EHcUUNACAFRQ0AIAAgAi0AADoAByADQQhrIQMgBEEIayEEIABBCGohACACQQFqIQIMBgsgByEAIAUhBCAGIQMMBQsgByEAIAUhBCAGIQMMBAsgByEAIAUhBCAGIQMMAwsgByEAIAUhBCAGIQMMAgsgByEAIAUhBCAGIQMMAQsgByEAIAUhBCAGIQMLAkAgA0EXTQRAIARFDQEgBEEBayEBIARBB3EiAwRAA0AgACACLQAAOgAAIARBAWshBCAAQQFqIQAgAkEBaiECIANBAWsi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CyAAIAMtAAAEfiADKQMQBUIAC6dB//8DcSADKAIEEEcLIQUgAxAICyAEQRBqJAAgBQvgAQICfwF+QTAQCSICRQRAIAEEQCABQQA2AgQgAUEONgIAC0EADwsgAkIANwMIIAJBADYCACACQgA3AxAgAkIANwMYIAJCADcDICACQgA3ACUgAFAEQCACDwsCQCAAQv////8AVg0AIACnQQR0EAkiA0UNACACIAM2AgBBACEBQgEhBANAIAMgAUEEdGoiAUIANwIAIAFCADcABSAAIARSBEAgBKchASAEQgF8IQQMAQsLIAIgADcDCCACIAA3AxAgAg8LIAEEQCABQQA2AgQgAUEONgIAC0EAEBAgAhAGQQAL7gECA38BfiMAQRBrIgQkAAJAIARBDGpCBBAXIgNFBEBBfyECDAELAkAgAQRAIAJBgAZxIQUDQAJAIAUgASgCBHFFDQACQCADKQMIQgBUBEAgA0EAOgAADAELIANCADcDECADQQE6AAALIAMgAS8BCBANIAMgAS8BChANIAMtAABFBEAgAEEIaiIABEAgAEEANgIEIABBFDYCAAtBfyECDAQLQX8hAiAAIARBDGpCBBAbQQBIDQMgATMBCiIGUA0AIAAgASgCDCAGEBtBAEgNAwsgASgCACIBDQALC0EAIQILIAMQCAsgBEEQaiQAIAILPAEBfyAABEAgAUGABnEhAQNAIAEgACgCBHEEQCACIAAvAQpqQQRqIQILIAAoAgAiAA0ACwsgAkH//wNxC5wBAQN/IABFBEBBAA8LIAAhAwNAAn8CQAJAIAAvAQgiAUH04AFNBEAgAUEBRg0BIAFB9cYBRg0BDAILIAFBgbICRg0AIAFB9eABRw0BCyAAKAIAIQEgAEEANgIAIAAoAgwQBiAAEAYgASADIAAgA0YbIQMCQCACRQRAQQAhAgwBCyACIAE2AgALIAEMAQsgACICKAIACyIADQALIAMLsgQCBX8BfgJAAkACQCAAIAGtEBciAQRAIAEtAAANAUEAIQAMAgsgBARAIARBADYCBCAEQQ42AgALQQAPC0EAIQADQCABLQAABH4gASkDCCABKQMQfQVCAAtCBFQNASABEAwhByABIAEQDCIGrRATIghFBEBBACECIAQEQCAEQQA2AgQgBEEVNgIACyABEAggAEUNAwNAIAAoAgAhASAAKAIMEAYg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DCAAQRg2AggLDAMLIAAgBiAFLwFqQQAgBCABEQYAIQEgBhALIAFFDQILAkAgDUUEQCABIQMMAQsgACABIAUvAWgQgQEhAyABEAsgA0UNAQsCQCAJRSAMckUEQCADIQEMAQsgACADQQEQgAEhASADEAsgAUUNAQsgASEDDAELQQAhAwsgBUHwAGokACADC4UBAQF/IAFFBEAgAEEIaiIABEAgAEEANgIEIABBEjYCAAtBAA8LQTgQCSIDRQRAIABBCGoiAARAIABBADYCBCAAQQ42AgALQQAPCyADQQA2AhAgA0IANwIIIANCADcDKCADQQA2AgQgAyACNgIAIANCADcDGCADQQA2AjAgACABQTsgAxBCCw8AIAAgASACQQBBABCCAQusAgECfyABRQRAIABBCGoiAARAIABBADYCBCAAQRI2AgALQQAPCwJAIAJBfUsNACACQf//A3FBCEYNACAAQQhqIgAEQCAAQQA2AgQgAEEQNgIAC0EADwsCQEGwwAAQCSIFBEAgBUEANgIIIAVCADcCACAFQYiBAUGogQEgAxs2AqhAIAUgAjYCFCAFIAM6ABAgBUEAOgAPIAVBADsBDCAFIAMgAkF9SyIGcToADiAFQQggAiAGG0H//wNxIAQgBUGIgQFBqIEBIAMbKAIAEQAAIgI2AqxAIAINASAFEDEgBRAGCyAAQQhqIgAEQCAAQQA2AgQgAEEONgIAC0EADwsgACABQTogBRBCIgAEfyAABSAFKAKsQCAFKAKoQCgCBBEDACAFEDEgBRAGQQALC6ABAQF/IAIgACgCBCIDIAIgA0kbIgIEQCAAIAMgAms2AgQCQAJAAkACQCAAKAIcIgMoAhRBAWsOAgEAAgsgA0GgAWogASAAKAIAIAJB3IABKAIAEQgADAILIAAgACgCMCABIAAoAgAgAkHEgAEoAgARBAA2AjAMAQsgASAAKAIAIAIQBxoLIAAgACgCACACajYCACAAIAAoAgggAmo2AggLC7cCAQR/QX4hAgJAIABFDQAgACgCIEUNACAAKAIkIgRFDQAgACgCHCIBRQ0AIAEoAgAgAEcNAAJAAkAgASgCICIDQTlrDjkBAgICAgICAgICAgIBAgICAQICAgICAgICAgICAgICAgICAQICAgICAgICAgICAQICAgICAgICAgEACyADQZoFRg0AIANBKkcN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DCABajYCDCAGIAYoAgggAWo2AgggBSAFKAIUIAFqNgIUIAUgBSgCECABazYCECAGIAYoAhAgAWsiATYCECABDQAgBiAGKAIENgIIC0EAIQRBACEJIAMoAhBFDQAMCgsgAygCHCgCJCEGIAMgAygCGCIBQQFqNgIYIAEgBmotAAAhASADIARBAWo2AhAgAygCBCAEaiABOgAAIAEEQCADKAIQIQQMAQsLIAMoAhwoAixFDQAgAygCECIGIAlNDQAgBQJ/IAUoAjAhBEEAIAMoAgQgCWoiAUUNABogBCABIAYgCWtB1IABKAIAEQAACzYCMAsgA0HnADYCIAsCQCADKAIcKAIsBEAgAygCDCADKAIQIgFBAmpJBH8gBRAKIAMoAhANAkEABSABCyADKAIEaiAFKAIwOwAAIAMgAygCEEECajYCECADQaABakHkgAEoAgARAQAaCyADQfEANgIgIAUQCiADKAIQRQ0BDAcLDAYLIAUoAgQNAQsgAygCPA0AIApFDQEgAygCIEGaBUYNAQsCfyADKAKIASIBRQRAIAMgChCFAQwBCwJAAkACQCADKAKMAUECaw4CAAECCwJ/AkADQAJAAkAgAygCPA0AIAMQLyADKAI8DQAgCg0BQQAMBAsgAygCSCADKAJoai0AACEEIAMgAygC8C0iAUEBajYC8C0gASADKALsLWpBADoAACADIAMoAvAtIgFBAWo2AvAtIAEgAygC7C1qQQA6AAAgAyADKALwLSIBQQFqNgLwLSABIAMoAuwtaiAEOgAAIAMgBEECdGoiASABLwHkAUEBajsB5AEgAyADKAI8QQFrNgI8IAMgAygCaEEBaiIBNgJoIAMoAvAtIAMoAvQtRw0BQQAhBCADIAMoAlgiBkEATgR/IAMoAkggBmoFQQALIAEgBmtBABAPIAMgAygCaDYCWCADKAIAEAogAygCACgCEA0BDAILCyADQQA2AoQuIApBBEYEQCADIAMoAlgiAUEATgR/IAMoAkggAWoFQQALIAMoAmggAWtBARAPIAMgAygCaDYCWCADKAIAEApBA0ECIAMoAgAoAhAbDAILIAMoAvAtBEBBACEEIAMgAygCWCIBQQBOBH8gAygCSCABagVBAAsgAygCaCABa0EAEA8gAyADKAJoNgJYIAMoAgAQCiADKAIAKAIQRQ0BC0EBIQQLIAQL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bGl0ZXJhbC9sZW5ndGhzIHNldABpbnZhbGlkIGNvZGUgbGVuZ3RocyBzZXQAdW5rbm93biBoZWFkZXIgZmxhZ3Mgc2V0AGludmFsaWQgZGlzdGFuY2VzIHNldABpbnZhbGlkIGJpdCBsZW5ndGggcmVwZWF0AEZpbGUgYWxyZWFkeSBleGlzdHMAdG9vIG1hbnkgbGVuZ3RoIG9yIGRpc3RhbmNlIHN5bWJvbHMAaW52YWxpZCBzdG9yZWQgYmxvY2sgbGVuZ3RocwAlcyVzJXMAYnVmZmVyIGVycm9yAE5vIGVycm9yAHN0cmVhbSBlcnJvcgBUZWxsIGVycm9yAEludGVybmFsIGVycm9yAFNlZWsgZXJyb3IAV3JpdGUgZXJyb3IAZmlsZSBlcnJvcgBSZWFkIGVycm9yAFpsaWIgZXJyb3IAZGF0YSBlcnJvcgBDUkMgZXJyb3IAaW5jb21wYXRpYmxlIHZlcnNpb24AaW52YWxpZCBjb2RlIC0tIG1pc3NpbmcgZW5kLW9mLWJsb2NrAGluY29ycmVjdCBoZWFkZXIgY2hlY2sAaW5jb3JyZWN0IGxlbmd0aCBjaGVjawBpbmNvcnJlY3QgZGF0YSBjaGVjawBpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFjawBoZWFkZXIgY3JjIG1pc21hdGNoADEuMi4xMy56bGliLW5nAGludmFsaWQgd2luZG93IHNpemUAUmVhZC1vbmx5IGFyY2hpdmUATm90IGEgemlwIGFyY2hpdmUAUmVzb3VyY2Ugc3RpbGwgaW4gdXNlAE1hbGxvYyBmYWlsdXJlAGludmFsaWQgYmxvY2sgdHlwZQBGYWlsdXJlIHRvIGNyZWF0ZSB0ZW1wb3JhcnkgZmlsZQBDYW4ndCBvcGVuIGZpbGUATm8gc3VjaCBmaWxlAFByZW1hdHVyZSBlbmQgb2YgZmlsZQBDYW4ndCByZW1vdmUgZmlsZQBpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUAaW52YWxpZCBkaXN0YW5jZSBjb2RlAHVua25vd24gY29tcHJlc3Npb24gbWV0aG9kAHN0cmVhbSBlbmQAQ29tcHJlc3NlZCBkYXRhIGludmFsaWQATXVsdGktZGlzayB6aXAgYXJjaGl2ZXMgbm90IHN1cHBvcnRl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UgAIANIACAAyAAgAsgAIAHIACADyAAgACgAIAIoACABKAAgAygAIACoACACqAAgAagAIAOoACAAaAAgAmgAIAFoACADaAAgAOgAIALoACAB6AAgA+gAIAAYACACGAAgARgAIAMYACAAmAAgApgAIAGYACADmAAgAFgAIAJYACABWAAgA1gAIADYACAC2AAgAdgAIAPYACAAOAAgAjgAIAE4ACADOAAgALgAIAK4ACABuAAgA7gAIAB4ACACeAAgAXgAIAN4ACAA+AAgAvgAIAH4ACAD+AAgAAQAIAIEACABBAAgAwQAIACEACAChAAgAYQAIAOEACAARAAgAkQAIAFEACADRAAgAMQAIALEACABxAAgA8QAIAAkACACJAAgASQAIAMkACAApAAgAqQAIAGkACADpAAgAGQAIAJkACABZAAgA2QAIADkACAC5AAgAeQAIAPkACAAFAAgAhQAIAEUACADFAAgAJQAIAKUACABlAAgA5QAIABUACACVAAgAVQAIANUACAA1AAgAtQAIAHUACAD1AAgADQAIAI0ACABNAAgAzQAIAC0ACACtAAgAbQAIAO0ACAAdAAgAnQAIAF0ACADdAAgAPQAIAL0ACAB9AAgA/QAIABMACQATAQkAkwAJAJMBCQBTAAkAUwEJANMACQDTAQkAMwAJADMBCQCzAAkAswEJAHMACQBzAQkA8wAJAPMBCQALAAkACwEJAIsACQCLAQkASwAJAEsBCQDLAAkAywEJACsACQArAQkAqwAJAKsBCQBrAAkAawEJAOsACQDrAQkAGwAJABsBCQCbAAkAmwEJAFsACQBbAQkA2wAJANsBCQA7AAkAOwEJALsACQC7AQkAewAJAHsBCQD7AAkA+wEJAAcACQAHAQkAhwAJAIcBCQBHAAkARwEJAMcACQDHAQkAJwAJACcBCQCnAAkApwEJAGcACQBnAQkA5wAJAOcBCQAXAAkAFwEJAJcACQCXAQkAVwAJAFcBCQDXAAkA1wEJADcACQA3AQkAtwAJALcBCQB3AAkAdwEJAPcACQD3AQkADwAJAA8BCQCPAAkAjwEJAE8ACQBPAQkAzwAJAM8BCQAvAAkALwEJAK8ACQCvAQkAbwAJAG8BCQDvAAkA7wEJAB8ACQAfAQkAnwAJAJ8BCQBfAAkAXwEJAN8ACQDfAQkAPwAJAD8BCQC/AAkA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SXMgYSBkaXJlY3RvcnkAVGV4dCBmaWxlIGJ1c3kARXhlYyBmb3JtYXQgZXJyb3IASW52YWxpZCBhcmd1bWVudABBcmd1bWVudCBsaXN0IHRvbyBsb25nAFN5bWJvbGljIGxpbmsgbG9vcABGaWxlbmFtZSB0b28gbG9uZwBUb28gbWFueSBvcGVuIGZpbGVzIGluIHN5c3RlbQBObyBmaWxlIGRlc2NyaXB0b3JzIGF2YWlsYWJsZQBCYWQgZmlsZSBkZXNjcmlwdG9yAE5vIGNoaWxkIHByb2Nlc3MAQmFkIGFkZHJlc3MARmlsZSB0b28gbGFyZ2UAVG9vIG1hbnkgbGlua3MATm8gbG9ja3MgYXZhaWxhYmxlAFJlc291cmNlIGRlYWRsb2NrIHdvdWxkIG9jY3VyAFN0YXRlIG5vdCByZWNvdmVyYWJsZQBQcmV2aW91cyBvd25lciBkaWVkAE9wZXJhdGlvbiBjYW5jZWxlZABGdW5jdGlvbiBub3QgaW1wbGVtZW50ZWQATm8gbWVzc2FnZSBvZiBkZXNpcmVkIHR5cGUASWRlbnRpZmllciByZW1vdmVkAERldmljZSBub3QgYSBzdHJlYW0ATm8gZGF0YSBhdmFpbGFibGUARGV2aWNlIHRpbWVvdXQAT3V0IG9mIHN0cmVhbXMgcmVzb3VyY2VzAExpbmsgaGFzIGJlZW4gc2V2ZXJlZABQcm90b2NvbCBlcnJvcgBCYWQgbWVzc2FnZQBGaWxlIGRlc2NyaXB0b3IgaW4gYmFkIHN0YXRlAE5vdCBhIHNvY2tldABEZXN0aW5hdGlvbiBhZGRyZXNzIHJlcXVpcmVkAE1lc3NhZ2UgdG9vIGxhcmdlAFByb3RvY29sIHdyb25nIHR5cGUgZm9yIHNvY2tldABQcm90b2NvbCBub3QgYXZhaWxhYmxlAFByb3RvY29sIG5vdCBzdXBwb3J0ZWQAU29ja2V0IHR5cGUgbm90IHN1cHBvcnRlZABOb3Qgc3VwcG9ydGVkAFByb3RvY29sIGZhbWlseSBub3Qgc3VwcG9ydGVkAEFkZHJlc3MgZmFtaWx5IG5vdCBzdXBwb3J0ZWQgYnkgcHJvdG9jb2wAQWRkcmVzcyBub3QgYXZhaWxhYmxlAE5ldHdvcmsgaXMgZG93bgBOZXR3b3JrIHVucmVhY2hhYmxlAENvbm5lY3Rpb24gcmVzZXQgYnkgbmV0d29yawBDb25uZWN0aW9uIGFib3J0ZWQATm8gYnVmZmVyIHNwYWNlIGF2YWlsYWJsZQBTb2NrZXQgaXMgY29ubmVjdGVkAFNvY2tldCBub3QgY29ubmVjdGVkAENhbm5vdCBzZW5kIGFmdGVyIHNvY2tldCBzaHV0ZG93bgBPcGVyYXRpb24gYWxyZWFkeSBpbiBwcm9ncmVzcwBPcGVyYXRpb24gaW4gcHJvZ3Jlc3MAU3RhbGUgZmlsZSBoYW5kbGUAUmVtb3RlIEkvTyBlcnJvcgBRdW90YSBleGNlZWRlZABObyBtZWRpdW0gZm91bmQAV3JvbmcgbWVkaXVtIHR5cGUATm8gZXJyb3IgaW5mb3JtYXRpb24AQcCAAQuFARMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAgERQADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAQfSCAQsCXEQAQbCDAQsQ/////////////////////w==";io(Si)||(Si=x(Si));function Ns(We){try{if(We==Si&&ue)return new Uint8Array(ue);var tt=ii(We);if(tt)return tt;if(R)return R(We);throw"sync fetching of the wasm failed: you can preload it to Module['wasmBinary'] manually, or emcc.py will do that for you when generating HTML (but not JS)"}catch(It){Ti(It)}}function so(We,tt){var It,ir,$;try{$=Ns(We),ir=new WebAssembly.Module($),It=new WebAssembly.Instance(ir,tt)}catch(Ne){var ye=Ne.toString();throw te("failed to compile wasm module: "+ye),(ye.includes("imported Memory")||ye.includes("memory import"))&&te("Memory size incompatibility issues may be due to changing INITIAL_MEMORY at runtime to something too large. Use ALLOW_MEMORY_GROWTH to allow any size memory (and also make sure not to set INITIAL_MEMORY at runtime to something smaller than it was at compile time)."),Ne}return[It,ir]}function uc(){var We={a:Ua};function tt($,ye){var Ne=$.exports;r.asm=Ne,Be=r.asm.g,J(Be.buffer),Z=r.asm.W,an(r.asm.h),Ls("wasm-instantiate")}if(Kn("wasm-instantiate"),r.instantiateWasm)try{var It=r.instantiateWasm(We,tt);return It}catch($){return te("Module.instantiateWasm callback failed with error: "+$),!1}var ir=so(Si,We);return tt(ir[0]),r.asm}function uu(We){return F.getFloat32(We,!0)}function cp(We){return F.getFloat64(We,!0)}function up(We){return F.getInt16(We,!0)}function Os(We){return F.getInt32(We,!0)}function Dn(We,tt){F.setInt32(We,tt,!0)}function oo(We){for(;We.length>0;){var tt=We.shift();if(typeof tt=="function"){tt(r);continue}var It=tt.func;typeof It=="number"?tt.arg===void 0?Z.get(It)():Z.get(It)(tt.arg):It(tt.arg===void 0?null:tt.arg)}}function Ms(We,tt){var It=new Date(Os((We>>2)*4)*1e3);Dn((tt>>2)*4,It.getUTCSeconds()),Dn((tt+4>>2)*4,It.getUTCMinutes()),Dn((tt+8>>2)*4,It.getUTCHours()),Dn((tt+12>>2)*4,It.getUTCDate()),Dn((tt+16>>2)*4,It.getUTCMonth()),Dn((tt+20>>2)*4,It.getUTCFullYear()-1900),Dn((tt+24>>2)*4,It.getUTCDay()),Dn((tt+36>>2)*4,0),Dn((tt+32>>2)*4,0);var ir=Date.UTC(It.getUTCFullYear(),0,1,0,0,0,0),$=(It.getTime()-ir)/(1e3*60*60*24)|0;return Dn((tt+28>>2)*4,$),Ms.GMTString||(Ms.GMTString=at("GMT")),Dn((tt+40>>2)*4,Ms.GMTString),tt}function yl(We,tt){return Ms(We,tt)}function El(We,tt,It){Te.copyWithin(We,tt,tt+It)}function ao(We){try{return Be.grow(We-xe.byteLength+65535>>>16),J(Be.buffer),1}catch{}}function zn(We){var tt=Te.length;We=We>>>0;var It=2147483648;if(We>It)return!1;for(var ir=1;ir<=4;ir*=2){var $=tt*(1+.2/ir);$=Math.min($,We+100663296);var ye=Math.min(It,ke(Math.max(We,$),65536)),Ne=ao(ye);if(Ne)return!0}return!1}function On(We){fe(We)}function Li(We){var tt=Date.now()/1e3|0;return We&&Dn((We>>2)*4,tt),tt}function Mn(){if(Mn.called)return;Mn.called=!0;var We=new Date().getFullYear(),tt=new Date(We,0,1),It=new Date(We,6,1),ir=tt.getTimezoneOffset(),$=It.getTimezoneOffset(),ye=Math.max(ir,$);Dn((ds()>>2)*4,ye*60),Dn((gs()>>2)*4,Number(ir!=$));function Ne($r){var Gi=$r.toTimeString().match(/\(([A-Za-z ]+)\)$/);return Gi?Gi[1]:"GMT"}var pt=Ne(tt),ht=Ne(It),Tt=at(pt),er=at(ht);$<ir?(Dn((wi()>>2)*4,Tt),Dn((wi()+4>>2)*4,er)):(Dn((wi()>>2)*4,er),Dn((wi()+4>>2)*4,Tt))}function _i(We){Mn();var tt=Date.UTC(Os((We+20>>2)*4)+1900,Os((We+16>>2)*4),Os((We+12>>2)*4),Os((We+8>>2)*4),Os((We+4>>2)*4),Os((We>>2)*4),0),It=new Date(tt);Dn((We+24>>2)*4,It.getUTCDay());var ir=Date.UTC(It.getUTCFullYear(),0,1,0,0,0,0),$=(It.getTime()-ir)/(1e3*60*60*24)|0;return Dn((We+28>>2)*4,$),It.getTime()/1e3|0}var rr=typeof atob=="function"?atob:function(We){var tt="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",It="",ir,$,ye,Ne,pt,ht,Tt,er=0;We=We.replace(/[^A-Za-z0-9\+\/\=]/g,"");do Ne=tt.indexOf(We.charAt(er++)),pt=tt.indexOf(We.charAt(er++)),ht=tt.indexOf(We.charAt(er++)),Tt=tt.indexOf(We.charAt(er++)),ir=Ne<<2|pt>>4,$=(pt&15)<<4|ht>>2,ye=(ht&3)<<6|Tt,It=It+String.fromCharCode(ir),ht!==64&&(It=It+String.fromCharCode($)),Tt!==64&&(It=It+String.fromCharCode(ye));while(er<We.length);return It};function Oe(We){if(typeof I=="boolean"&&I){var tt;try{tt=Buffer.from(We,"base64")}catch{tt=new Buffer(We,"base64")}return new Uint8Array(tt.buffer,tt.byteOffset,tt.byteLength)}try{for(var It=rr(We),ir=new Uint8Array(It.length),$=0;$<It.length;++$)ir[$]=It.charCodeAt($);return ir}catch{throw new Error("Converting base64 string to bytes failed.")}}function ii(We){if(!!io(We))return Oe(We.slice(ps.length))}var Ua={e:yl,c:El,d:zn,a:On,b:Li,f:_i},hr=uc(),Ac=r.___wasm_call_ctors=hr.h,Au=r._zip_ext_count_symlinks=hr.i,fc=r._zip_file_get_external_attributes=hr.j,Cl=r._zipstruct_statS=hr.k,DA=r._zipstruct_stat_size=hr.l,fu=r._zipstruct_stat_mtime=hr.m,Ce=r._zipstruct_stat_crc=hr.n,Rt=r._zipstruct_errorS=hr.o,pc=r._zipstruct_error_code_zip=hr.p,Hi=r._zipstruct_stat_comp_size=hr.q,pu=r._zipstruct_stat_comp_method=hr.r,Yt=r._zip_close=hr.s,wl=r._zip_delete=hr.t,PA=r._zip_dir_add=hr.u,Ap=r._zip_discard=hr.v,hc=r._zip_error_init_with_code=hr.w,SA=r._zip_get_error=hr.x,Qn=r._zip_file_get_error=hr.y,hi=r._zip_error_strerror=hr.z,gc=r._zip_fclose=hr.A,bA=r._zip_file_add=hr.B,sa=r._free=hr.C,Ni=r._malloc=hr.D,_o=r._zip_source_error=hr.E,Ze=r._zip_source_seek=hr.F,lo=r._zip_file_set_external_attributes=hr.G,dc=r._zip_file_set_mtime=hr.H,hu=r._zip_fopen_index=hr.I,qi=r._zip_fread=hr.J,gu=r._zip_get_name=hr.K,xA=r._zip_get_num_entries=hr.L,Ha=r._zip_source_read=hr.M,mc=r._zip_name_locate=hr.N,hs=r._zip_open_from_source=hr.O,Ht=r._zip_set_file_compression=hr.P,Fn=r._zip_source_buffer=hr.Q,Ci=r._zip_source_buffer_create=hr.R,oa=r._zip_source_close=hr.S,co=r._zip_source_free=hr.T,Us=r._zip_source_keep=hr.U,aa=r._zip_source_open=hr.V,la=r._zip_source_tell=hr.X,Ho=r._zip_stat_index=hr.Y,wi=r.__get_tzname=hr.Z,gs=r.__get_daylight=hr._,ds=r.__get_timezone=hr.$,ms=r.stackSave=hr.aa,_s=r.stackRestore=hr.ba,Un=r.stackAlloc=hr.ca;r.cwrap=ne,r.getValue=he;var Pn;Wr=function We(){Pn||ys(),Pn||(Wr=We)};function ys(We){if(We=We||A,mr>0||(dt(),mr>0))return;function tt(){Pn||(Pn=!0,r.calledRun=!0,!we&&(Gt(),o(r),r.onRuntimeInitialized&&r.onRuntimeInitialized(),$t()))}r.setStatus?(r.setStatus("Running..."),setTimeout(function(){setTimeout(function(){r.setStatus("")},1),tt()},1)):tt()}if(r.run=ys,r.preInit)for(typeof r.preInit=="function"&&(r.preInit=[r.preInit]);r.preInit.length>0;)r.preInit.pop()();return ys(),e}}();typeof Qb=="object"&&typeof tU=="object"?tU.exports=eU:typeof define=="function"&&define.amd?define([],function(){return eU}):typeof Qb=="object"&&(Qb.createModule=eU)});var Of,Tle,Lle,Nle=Et(()=>{Of=["number","number"],Tle=(ee=>(ee[ee.ZIP_ER_OK=0]="ZIP_ER_OK",ee[ee.ZIP_ER_MULTIDISK=1]="ZIP_ER_MULTIDISK",ee[ee.ZIP_ER_RENAME=2]="ZIP_ER_RENAME",ee[ee.ZIP_ER_CLOSE=3]="ZIP_ER_CLOSE",ee[ee.ZIP_ER_SEEK=4]="ZIP_ER_SEEK",ee[ee.ZIP_ER_READ=5]="ZIP_ER_READ",ee[ee.ZIP_ER_WRITE=6]="ZIP_ER_WRITE",ee[ee.ZIP_ER_CRC=7]="ZIP_ER_CRC",ee[ee.ZIP_ER_ZIPCLOSED=8]="ZIP_ER_ZIPCLOSED",ee[ee.ZIP_ER_NOENT=9]="ZIP_ER_NOENT",ee[ee.ZIP_ER_EXISTS=10]="ZIP_ER_EXISTS",ee[ee.ZIP_ER_OPEN=11]="ZIP_ER_OPEN",ee[ee.ZIP_ER_TMPOPEN=12]="ZIP_ER_TMPOPEN",ee[ee.ZIP_ER_ZLIB=13]="ZIP_ER_ZLIB",ee[ee.ZIP_ER_MEMORY=14]="ZIP_ER_MEMORY",ee[ee.ZIP_ER_CHANGED=15]="ZIP_ER_CHANGED",ee[ee.ZIP_ER_COMPNOTSUPP=16]="ZIP_ER_COMPNOTSUPP",ee[ee.ZIP_ER_EOF=17]="ZIP_ER_EOF",ee[ee.ZIP_ER_INVAL=18]="ZIP_ER_INVAL",ee[ee.ZIP_ER_NOZIP=19]="ZIP_ER_NOZIP",ee[ee.ZIP_ER_INTERNAL=20]="ZIP_ER_INTERNAL",ee[ee.ZIP_ER_INCONS=21]="ZIP_ER_INCONS",ee[ee.ZIP_ER_REMOVE=22]="ZIP_ER_REMOVE",ee[ee.ZIP_ER_DELETED=23]="ZIP_ER_DELETED",ee[ee.ZIP_ER_ENCRNOTSUPP=24]="ZIP_ER_ENCRNOTSUPP",ee[ee.ZIP_ER_RDONLY=25]="ZIP_ER_RDONLY",ee[ee.ZIP_ER_NOPASSWD=26]="ZIP_ER_NOPASSWD",ee[ee.ZIP_ER_WRONGPASSWD=27]="ZIP_ER_WRONGPASSWD",ee[ee.ZIP_ER_OPNOTSUPP=28]="ZIP_ER_OPNOTSUPP",ee[ee.ZIP_ER_INUSE=29]="ZIP_ER_INUSE",ee[ee.ZIP_ER_TELL=30]="ZIP_ER_TELL",ee[ee.ZIP_ER_COMPRESSED_DATA=31]="ZIP_ER_COMPRESSED_DATA",ee))(Tle||{}),Lle=t=>({get HEAPU8(){return t.HEAPU8},errors:Tle,SEEK_SET:0,SEEK_CUR:1,SEEK_END:2,ZIP_CHECKCONS:4,ZIP_EXCL:2,ZIP_RDONLY:16,ZIP_FL_OVERWRITE:8192,ZIP_FL_COMPRESSED:4,ZIP_OPSYS_DOS:0,ZIP_OPSYS_AMIGA:1,ZIP_OPSYS_OPENVMS:2,ZIP_OPSYS_UNIX:3,ZIP_OPSYS_VM_CMS:4,ZIP_OPSYS_ATARI_ST:5,ZIP_OPSYS_OS_2:6,ZIP_OPSYS_MACINTOSH:7,ZIP_OPSYS_Z_SYSTEM:8,ZIP_OPSYS_CPM:9,ZIP_OPSYS_WINDOWS_NTFS:10,ZIP_OPSYS_MVS:11,ZIP_OPSYS_VSE:12,ZIP_OPSYS_ACORN_RISC:13,ZIP_OPSYS_VFAT:14,ZIP_OPSYS_ALTERNATE_MVS:15,ZIP_OPSYS_BEOS:16,ZIP_OPSYS_TANDEM:17,ZIP_OPSYS_OS_400:18,ZIP_OPSYS_OS_X:19,ZIP_CM_DEFAULT:-1,ZIP_CM_STORE:0,ZIP_CM_DEFLATE:8,uint08S:t._malloc(1),uint32S:t._malloc(4),malloc:t._malloc,free:t._free,getValue:t.getValue,openFromSource:t.cwrap("zip_open_from_source","number",["number","number","number"]),close:t.cwrap("zip_close","number",["number"]),discard:t.cwrap("zip_discard",null,["number"]),getError:t.cwrap("zip_get_error","number",["number"]),getName:t.cwrap("zip_get_name","string",["number","number","number"]),getNumEntries:t.cwrap("zip_get_num_entries","number",["number","number"]),delete:t.cwrap("zip_delete","number",["number","number"]),statIndex:t.cwrap("zip_stat_index","number",["number",...Of,"number","number"]),fopenIndex:t.cwrap("zip_fopen_index","number",["number",...Of,"number"]),fread:t.cwrap("zip_fread","number",["number","number","number","number"]),fclose:t.cwrap("zip_fclose","number",["number"]),dir:{add:t.cwrap("zip_dir_add","number",["number","string"])},file:{add:t.cwrap("zip_file_add","number",["number","string","number","number"]),getError:t.cwrap("zip_file_get_error","number",["number"]),getExternalAttributes:t.cwrap("zip_file_get_external_attributes","number",["number",...Of,"number","number","number"]),setExternalAttributes:t.cwrap("zip_file_set_external_attributes","number",["number",...Of,"number","number","number"]),setMtime:t.cwrap("zip_file_set_mtime","number",["number",...Of,"number","number"]),setCompression:t.cwrap("zip_set_file_compression","number",["number",...Of,"number","number"])},ext:{countSymlinks:t.cwrap("zip_ext_count_symlinks","number",["number"])},error:{initWithCode:t.cwrap("zip_error_init_with_code",null,["number","number"]),strerror:t.cwrap("zip_error_strerror","string",["number"])},name:{locate:t.cwrap("zip_name_locate","number",["number","string","number"])},source:{fromUnattachedBuffer:t.cwrap("zip_source_buffer_create","number",["number",...Of,"number","number"]),fromBuffer:t.cwrap("zip_source_buffer","number",["number","number",...Of,"number"]),free:t.cwrap("zip_source_free",null,["number"]),keep:t.cwrap("zip_source_keep",null,["number"]),open:t.cwrap("zip_source_open","number",["number"]),close:t.cwrap("zip_source_close","number",["number"]),seek:t.cwrap("zip_source_seek","number",["number",...Of,"number"]),tell:t.cwrap("zip_source_tell","number",["number"]),read:t.cwrap("zip_source_read","number",["number","number","number"]),error:t.cwrap("zip_source_error","number",["number"])},struct:{statS:t.cwrap("zipstruct_statS","number",[]),statSize:t.cwrap("zipstruct_stat_size","number",["number"]),statCompSize:t.cwrap("zipstruct_stat_comp_size","number",["number"]),statCompMethod:t.cwrap("zipstruct_stat_comp_method","number",["number"]),statMtime:t.cwrap("zipstruct_stat_mtime","number",["number"]),statCrc:t.cwrap("zipstruct_stat_crc","number",["number"]),errorS:t.cwrap("zipstruct_errorS","number",[]),errorCodeZip:t.cwrap("zipstruct_error_code_zip","number",["number"])}})});function rU(t,e){let r=t.indexOf(e);if(r<=0)return null;let o=r;for(;r>=0&&(o=r+e.length,t[o]!==z.sep);){if(t[r-1]===z.sep)return null;r=t.indexOf(e,o)}return t.length>o&&t[o]!==z.sep?null:t.slice(0,o)}var Jl,Ole=Et(()=>{Pt();Pt();iA();Jl=class extends qp{static async openPromise(e,r){let o=new Jl(r);try{return await e(o)}finally{o.saveAndClose()}}constructor(e={}){let r=e.fileExtensions,o=e.readOnlyArchives,a=typeof r>"u"?A=>rU(A,".zip"):A=>{for(let p of r){let h=rU(A,p);if(h)return h}return null},n=(A,p)=>new Ji(p,{baseFs:A,readOnly:o,stats:A.statSync(p)}),u=async(A,p)=>{let h={baseFs:A,readOnly:o,stats:await A.statPromise(p)};return()=>new Ji(p,h)};super({...e,factorySync:n,factoryPromise:u,getMountPoint:a})}}});function cot(t){if(typeof t=="string"&&String(+t)===t)return+t;if(typeof t=="number"&&Number.isFinite(t))return t<0?Date.now()/1e3:t;if(Mle.types.isDate(t))return t.getTime()/1e3;throw new Error("Invalid time")}function Fb(){return Buffer.from([80,75,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])}var ta,nU,Mle,iU,Ule,Rb,Ji,sU=Et(()=>{Pt();Pt();Pt();Pt();Pt();Pt();ta=ve("fs"),nU=ve("stream"),Mle=ve("util"),iU=$e(ve("zlib"));$4();Ule="mixed";Rb=class extends Error{constructor(r,o){super(r);this.name="Libzip Error",this.code=o}},Ji=class extends Uu{constructor(r,o={}){super();this.listings=new Map;this.entries=new Map;this.fileSources=new Map;this.fds=new Map;this.nextFd=0;this.ready=!1;this.readOnly=!1;let a=o;if(this.level=typeof a.level<"u"?a.level:Ule,r??=Fb(),typeof r=="string"){let{baseFs:A=new Tn}=a;this.baseFs=A,this.path=r}else this.path=null,this.baseFs=null;if(o.stats)this.stats=o.stats;else if(typeof r=="string")try{this.stats=this.baseFs.statSync(r)}catch(A){if(A.code==="ENOENT"&&a.create)this.stats=Ea.makeDefaultStats();else throw A}else this.stats=Ea.makeDefaultStats();this.libzip=b1();let n=this.libzip.malloc(4);try{let A=0;o.readOnly&&(A|=this.libzip.ZIP_RDONLY,this.readOnly=!0),typeof r=="string"&&(r=a.create?Fb():this.baseFs.readFileSync(r));let p=this.allocateUnattachedSource(r);try{this.zip=this.libzip.openFromSource(p,A,n),this.lzSource=p}catch(h){throw this.libzip.source.free(p),h}if(this.zip===0){let h=this.libzip.struct.errorS();throw this.libzip.error.initWithCode(h,this.libzip.getValue(n,"i32")),this.makeLibzipError(h)}}finally{this.libzip.free(n)}this.listings.set(Bt.root,new Set);let u=this.libzip.getNumEntries(this.zip,0);for(let A=0;A<u;++A){let p=this.libzip.getName(this.zip,A,0);if(z.isAbsolute(p))continue;let h=z.resolve(Bt.root,p);this.registerEntry(h,A),p.endsWith("/")&&this.registerListing(h)}if(this.symlinkCount=this.libzip.ext.countSymlinks(this.zip),this.symlinkCount===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));this.ready=!0}makeLibzipError(r){let o=this.libzip.struct.errorCodeZip(r),a=this.libzip.error.strerror(r),n=new Rb(a,this.libzip.errors[o]);if(o===this.libzip.errors.ZIP_ER_CHANGED)throw new Error(`Assertion failed: Unexpected libzip error: ${n.message}`);return n}getExtractHint(r){for(let o of this.entries.keys()){let a=this.pathUtils.extname(o);if(r.relevantExtensions.has(a))return!0}return!1}getAllFiles(){return Array.from(this.entries.keys())}getRealPath(){if(!this.path)throw new Error("ZipFS don't have real paths when loaded from a buffer");return this.path}prepareClose(){if(!this.ready)throw tr.EBUSY("archive closed, close");_g(this)}getBufferAndClose(){if(this.prepareClose(),this.entries.size===0)return this.discardAndClose(),Fb();try{if(this.libzip.source.keep(this.lzSource),this.libzip.close(this.zip)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));if(this.libzip.source.open(this.lzSource)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(this.libzip.source.seek(this.lzSource,0,0,this.libzip.SEEK_END)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));let r=this.libzip.source.tell(this.lzSource);if(r===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(this.libzip.source.seek(this.lzSource,0,0,this.libzip.SEEK_SET)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));let o=this.libzip.malloc(r);if(!o)throw new Error("Couldn't allocate enough memory");try{let a=this.libzip.source.read(this.lzSource,o,r);if(a===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(a<r)throw new Error("Incomplete read");if(a>r)throw new Error("Overread");let n=Buffer.from(this.libzip.HEAPU8.subarray(o,o+r));return process.env.YARN_IS_TEST_ENV&&process.env.YARN_ZIP_DATA_EPILOGUE&&(n=Buffer.concat([n,Buffer.from(process.env.YARN_ZIP_DATA_EPILOGUE)])),n}finally{this.libzip.free(o)}}finally{this.libzip.source.close(this.lzSource),this.libzip.source.free(this.lzSource),this.ready=!1}}discardAndClose(){this.prepareClose(),this.libzip.discard(this.zip),this.ready=!1}saveAndClose(){if(!this.path||!this.baseFs)throw new Error("ZipFS cannot be saved and must be discarded when loaded from a buffer");if(this.readOnly){this.discardAndClose();return}let r=this.baseFs.existsSync(this.path)||this.stats.mode===Ea.DEFAULT_MODE?void 0:this.stats.mode;this.baseFs.writeFileSync(this.path,this.getBufferAndClose(),{mode:r}),this.ready=!1}resolve(r){return z.resolve(Bt.root,r)}async openPromise(r,o,a){return this.openSync(r,o,a)}openSync(r,o,a){let n=this.nextFd++;return this.fds.set(n,{cursor:0,p:r}),n}hasOpenFileHandles(){return!!this.fds.size}async opendirPromise(r,o){return this.opendirSync(r,o)}opendirSync(r,o={}){let a=this.resolveFilename(`opendir '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw tr.ENOENT(`opendir '${r}'`);let n=this.listings.get(a);if(!n)throw tr.ENOTDIR(`opendir '${r}'`);let u=[...n],A=this.openSync(a,"r");return SD(this,a,u,{onClose:()=>{this.closeSync(A)}})}async readPromise(r,o,a,n,u){return this.readSync(r,o,a,n,u)}readSync(r,o,a=0,n=o.byteLength,u=-1){let A=this.fds.get(r);if(typeof A>"u")throw tr.EBADF("read");let p=u===-1||u===null?A.cursor:u,h=this.readFileSync(A.p);h.copy(o,a,p,p+n);let E=Math.max(0,Math.min(h.length-p,n));return(u===-1||u===null)&&(A.cursor+=E),E}async writePromise(r,o,a,n,u){return typeof o=="string"?this.writeSync(r,o,u):this.writeSync(r,o,a,n,u)}writeSync(r,o,a,n,u){throw typeof this.fds.get(r)>"u"?tr.EBADF("read"):new Error("Unimplemented")}async closePromise(r){return this.closeSync(r)}closeSync(r){if(typeof this.fds.get(r)>"u")throw tr.EBADF("read");this.fds.delete(r)}createReadStream(r,{encoding:o}={}){if(r===null)throw new Error("Unimplemented");let a=this.openSync(r,"r"),n=Object.assign(new nU.PassThrough({emitClose:!0,autoDestroy:!0,destroy:(A,p)=>{clearImmediate(u),this.closeSync(a),p(A)}}),{close(){n.destroy()},bytesRead:0,path:r,pending:!1}),u=setImmediate(async()=>{try{let A=await this.readFilePromise(r,o);n.bytesRead=A.length,n.end(A)}catch(A){n.destroy(A)}});return n}createWriteStream(r,{encoding:o}={}){if(this.readOnly)throw tr.EROFS(`open '${r}'`);if(r===null)throw new Error("Unimplemented");let a=[],n=this.openSync(r,"w"),u=Object.assign(new nU.PassThrough({autoDestroy:!0,emitClose:!0,destroy:(A,p)=>{try{A?p(A):(this.writeFileSync(r,Buffer.concat(a),o),p(null))}catch(h){p(h)}finally{this.closeSync(n)}}}),{close(){u.destroy()},bytesWritten:0,path:r,pending:!1});return u.on("data",A=>{let p=Buffer.from(A);u.bytesWritten+=p.length,a.push(p)}),u}async realpathPromise(r){return this.realpathSync(r)}realpathSync(r){let o=this.resolveFilename(`lstat '${r}'`,r);if(!this.entries.has(o)&&!this.listings.has(o))throw tr.ENOENT(`lstat '${r}'`);return o}async existsPromise(r){return this.existsSync(r)}existsSync(r){if(!this.ready)throw tr.EBUSY(`archive closed, existsSync '${r}'`);if(this.symlinkCount===0){let a=z.resolve(Bt.root,r);return this.entries.has(a)||this.listings.has(a)}let o;try{o=this.resolveFilename(`stat '${r}'`,r,void 0,!1)}catch{return!1}return o===void 0?!1:this.entries.has(o)||this.listings.has(o)}async accessPromise(r,o){return this.accessSync(r,o)}accessSync(r,o=ta.constants.F_OK){let a=this.resolveFilename(`access '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw tr.ENOENT(`access '${r}'`);if(this.readOnly&&o&ta.constants.W_OK)throw tr.EROFS(`access '${r}'`)}async statPromise(r,o={bigint:!1}){return o.bigint?this.statSync(r,{bigint:!0}):this.statSync(r)}statSync(r,o={bigint:!1,throwIfNoEntry:!0}){let a=this.resolveFilename(`stat '${r}'`,r,void 0,o.throwIfNoEntry);if(a!==void 0){if(!this.entries.has(a)&&!this.listings.has(a)){if(o.throwIfNoEntry===!1)return;throw tr.ENOENT(`stat '${r}'`)}if(r[r.length-1]==="/"&&!this.listings.has(a))throw tr.ENOTDIR(`stat '${r}'`);return this.statImpl(`stat '${r}'`,a,o)}}async fstatPromise(r,o){return this.fstatSync(r,o)}fstatSync(r,o){let a=this.fds.get(r);if(typeof a>"u")throw tr.EBADF("fstatSync");let{p:n}=a,u=this.resolveFilename(`stat '${n}'`,n);if(!this.entries.has(u)&&!this.listings.has(u))throw tr.ENOENT(`stat '${n}'`);if(n[n.length-1]==="/"&&!this.listings.has(u))throw tr.ENOTDIR(`stat '${n}'`);return this.statImpl(`fstat '${n}'`,u,o)}async lstatPromise(r,o={bigint:!1}){return o.bigint?this.lstatSync(r,{bigint:!0}):this.lstatSync(r)}lstatSync(r,o={bigint:!1,throwIfNoEntry:!0}){let a=this.resolveFilename(`lstat '${r}'`,r,!1,o.throwIfNoEntry);if(a!==void 0){if(!this.entries.has(a)&&!this.listings.has(a)){if(o.throwIfNoEntry===!1)return;throw tr.ENOENT(`lstat '${r}'`)}if(r[r.length-1]==="/"&&!this.listings.has(a))throw tr.ENOTDIR(`lstat '${r}'`);return this.statImpl(`lstat '${r}'`,a,o)}}statImpl(r,o,a={}){let n=this.entries.get(o);if(typeof n<"u"){let u=this.libzip.struct.statS();if(this.libzip.statIndex(this.zip,n,0,0,u)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));let p=this.stats.uid,h=this.stats.gid,E=this.libzip.struct.statSize(u)>>>0,I=512,v=Math.ceil(E/I),x=(this.libzip.struct.statMtime(u)>>>0)*1e3,C=x,R=x,N=x,U=new Date(C),V=new Date(R),te=new Date(N),ae=new Date(x),fe=this.listings.has(o)?ta.constants.S_IFDIR:this.isSymbolicLink(n)?ta.constants.S_IFLNK:ta.constants.S_IFREG,ue=fe===ta.constants.S_IFDIR?493:420,me=fe|this.getUnixMode(n,ue)&511,he=this.libzip.struct.statCrc(u),Be=Object.assign(new Ea.StatEntry,{uid:p,gid:h,size:E,blksize:I,blocks:v,atime:U,birthtime:V,ctime:te,mtime:ae,atimeMs:C,birthtimeMs:R,ctimeMs:N,mtimeMs:x,mode:me,crc:he});return a.bigint===!0?Ea.convertToBigIntStats(Be):Be}if(this.listings.has(o)){let u=this.stats.uid,A=this.stats.gid,p=0,h=512,E=0,I=this.stats.mtimeMs,v=this.stats.mtimeMs,x=this.stats.mtimeMs,C=this.stats.mtimeMs,R=new Date(I),N=new Date(v),U=new Date(x),V=new Date(C),te=ta.constants.S_IFDIR|493,ae=0,fe=Object.assign(new Ea.StatEntry,{uid:u,gid:A,size:p,blksize:h,blocks:E,atime:R,birthtime:N,ctime:U,mtime:V,atimeMs:I,birthtimeMs:v,ctimeMs:x,mtimeMs:C,mode:te,crc:ae});return a.bigint===!0?Ea.convertToBigIntStats(fe):fe}throw new Error("Unreachable")}getUnixMode(r,o){if(this.libzip.file.getExternalAttributes(this.zip,r,0,0,this.libzip.uint08S,this.libzip.uint32S)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));return this.libzip.getValue(this.libzip.uint08S,"i8")>>>0!==this.libzip.ZIP_OPSYS_UNIX?o:this.libzip.getValue(this.libzip.uint32S,"i32")>>>16}registerListing(r){let o=this.listings.get(r);if(o)return o;this.registerListing(z.dirname(r)).add(z.basename(r));let n=new Set;return this.listings.set(r,n),n}registerEntry(r,o){this.registerListing(z.dirname(r)).add(z.basename(r)),this.entries.set(r,o)}unregisterListing(r){this.listings.delete(r),this.listings.get(z.dirname(r))?.delete(z.basename(r))}unregisterEntry(r){this.unregisterListing(r);let o=this.entries.get(r);this.entries.delete(r),!(typeof o>"u")&&(this.fileSources.delete(o),this.isSymbolicLink(o)&&this.symlinkCount--)}deleteEntry(r,o){if(this.unregisterEntry(r),this.libzip.delete(this.zip,o)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}resolveFilename(r,o,a=!0,n=!0){if(!this.ready)throw tr.EBUSY(`archive closed, ${r}`);let u=z.resolve(Bt.root,o);if(u==="/")return Bt.root;let A=this.entries.get(u);if(a&&A!==void 0)if(this.symlinkCount!==0&&this.isSymbolicLink(A)){let p=this.getFileSource(A).toString();return this.resolveFilename(r,z.resolve(z.dirname(u),p),!0,n)}else return u;for(;;){let p=this.resolveFilename(r,z.dirname(u),!0,n);if(p===void 0)return p;let h=this.listings.has(p),E=this.entries.has(p);if(!h&&!E){if(n===!1)return;throw tr.ENOENT(r)}if(!h)throw tr.ENOTDIR(r);if(u=z.resolve(p,z.basename(u)),!a||this.symlinkCount===0)break;let I=this.libzip.name.locate(this.zip,u.slice(1),0);if(I===-1)break;if(this.isSymbolicLink(I)){let v=this.getFileSource(I).toString();u=z.resolve(z.dirname(u),v)}else break}return u}allocateBuffer(r){Buffer.isBuffer(r)||(r=Buffer.from(r));let o=this.libzip.malloc(r.byteLength);if(!o)throw new Error("Couldn't allocate enough memory");return new Uint8Array(this.libzip.HEAPU8.buffer,o,r.byteLength).set(r),{buffer:o,byteLength:r.byteLength}}allocateUnattachedSource(r){let o=this.libzip.struct.errorS(),{buffer:a,byteLength:n}=this.allocateBuffer(r),u=this.libzip.source.fromUnattachedBuffer(a,n,0,1,o);if(u===0)throw this.libzip.free(o),this.makeLibzipError(o);return u}allocateSource(r){let{buffer:o,byteLength:a}=this.allocateBuffer(r),n=this.libzip.source.fromBuffer(this.zip,o,a,0,1);if(n===0)throw this.libzip.free(o),this.makeLibzipError(this.libzip.getError(this.zip));return n}setFileSource(r,o){let a=Buffer.isBuffer(o)?o:Buffer.from(o),n=z.relative(Bt.root,r),u=this.allocateSource(o);try{let A=this.libzip.file.add(this.zip,n,u,this.libzip.ZIP_FL_OVERWRITE);if(A===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));if(this.level!=="mixed"){let p=this.level===0?this.libzip.ZIP_CM_STORE:this.libzip.ZIP_CM_DEFLATE;if(this.libzip.file.setCompression(this.zip,A,0,p,this.level)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}return this.fileSources.set(A,a),A}catch(A){throw this.libzip.source.free(u),A}}isSymbolicLink(r){if(this.symlinkCount===0)return!1;if(this.libzip.file.getExternalAttributes(this.zip,r,0,0,this.libzip.uint08S,this.libzip.uint32S)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));return this.libzip.getValue(this.libzip.uint08S,"i8")>>>0!==this.libzip.ZIP_OPSYS_UNIX?!1:(this.libzip.getValue(this.libzip.uint32S,"i32")>>>16&ta.constants.S_IFMT)===ta.constants.S_IFLNK}getFileSource(r,o={asyncDecompress:!1}){let a=this.fileSources.get(r);if(typeof a<"u")return a;let n=this.libzip.struct.statS();if(this.libzip.statIndex(this.zip,r,0,0,n)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));let A=this.libzip.struct.statCompSize(n),p=this.libzip.struct.statCompMethod(n),h=this.libzip.malloc(A);try{let E=this.libzip.fopenIndex(this.zip,r,0,this.libzip.ZIP_FL_COMPRESSED);if(E===0)throw this.makeLibzipError(this.libzip.getError(this.zip));try{let I=this.libzip.fread(E,h,A,0);if(I===-1)throw this.makeLibzipError(this.libzip.file.getError(E));if(I<A)throw new Error("Incomplete read");if(I>A)throw new Error("Overread");let v=this.libzip.HEAPU8.subarray(h,h+A),x=Buffer.from(v);if(p===0)return this.fileSources.set(r,x),x;if(o.asyncDecompress)return new Promise((C,R)=>{iU.default.inflateRaw(x,(N,U)=>{N?R(N):(this.fileSources.set(r,U),C(U))})});{let C=iU.default.inflateRawSync(x);return this.fileSources.set(r,C),C}}finally{this.libzip.fclose(E)}}finally{this.libzip.free(h)}}async fchmodPromise(r,o){return this.chmodPromise(this.fdToPath(r,"fchmod"),o)}fchmodSync(r,o){return this.chmodSync(this.fdToPath(r,"fchmodSync"),o)}async chmodPromise(r,o){return this.chmodSync(r,o)}chmodSync(r,o){if(this.readOnly)throw tr.EROFS(`chmod '${r}'`);o&=493;let a=this.resolveFilename(`chmod '${r}'`,r,!1),n=this.entries.get(a);if(typeof n>"u")throw new Error(`Assertion failed: The entry should have been registered (${a})`);let A=this.getUnixMode(n,ta.constants.S_IFREG|0)&-512|o;if(this.libzip.file.setExternalAttributes(this.zip,n,0,0,this.libzip.ZIP_OPSYS_UNIX,A<<16)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}async fchownPromise(r,o,a){return this.chownPromise(this.fdToPath(r,"fchown"),o,a)}fchownSync(r,o,a){return this.chownSync(this.fdToPath(r,"fchownSync"),o,a)}async chownPromise(r,o,a){return this.chownSync(r,o,a)}chownSync(r,o,a){throw new Error("Unimplemented")}async renamePromise(r,o){return this.renameSync(r,o)}renameSync(r,o){throw new Error("Unimplemented")}async copyFilePromise(r,o,a){let{indexSource:n,indexDest:u,resolvedDestP:A}=this.prepareCopyFile(r,o,a),p=await this.getFileSource(n,{asyncDecompress:!0}),h=this.setFileSource(A,p);h!==u&&this.registerEntry(A,h)}copyFileSync(r,o,a=0){let{indexSource:n,indexDest:u,resolvedDestP:A}=this.prepareCopyFile(r,o,a),p=this.getFileSource(n),h=this.setFileSource(A,p);h!==u&&this.registerEntry(A,h)}prepareCopyFile(r,o,a=0){if(this.readOnly)throw tr.EROFS(`copyfile '${r} -> '${o}'`);if((a&ta.constants.COPYFILE_FICLONE_FORCE)!==0)throw tr.ENOSYS("unsupported clone operation",`copyfile '${r}' -> ${o}'`);let n=this.resolveFilename(`copyfile '${r} -> ${o}'`,r),u=this.entries.get(n);if(typeof u>"u")throw tr.EINVAL(`copyfile '${r}' -> '${o}'`);let A=this.resolveFilename(`copyfile '${r}' -> ${o}'`,o),p=this.entries.get(A);if((a&(ta.constants.COPYFILE_EXCL|ta.constants.COPYFILE_FICLONE_FORCE))!==0&&typeof p<"u")throw tr.EEXIST(`copyfile '${r}' -> '${o}'`);return{indexSource:u,resolvedDestP:A,indexDest:p}}async appendFilePromise(r,o,a){if(this.readOnly)throw tr.EROFS(`open '${r}'`);return typeof a>"u"?a={flag:"a"}:typeof a=="string"?a={flag:"a",encoding:a}:typeof a.flag>"u"&&(a={flag:"a",...a}),this.writeFilePromise(r,o,a)}appendFileSync(r,o,a={}){if(this.readOnly)throw tr.EROFS(`open '${r}'`);return typeof a>"u"?a={flag:"a"}:typeof a=="string"?a={flag:"a",encoding:a}:typeof a.flag>"u"&&(a={flag:"a",...a}),this.writeFileSync(r,o,a)}fdToPath(r,o){let a=this.fds.get(r)?.p;if(typeof a>"u")throw tr.EBADF(o);return a}async writeFilePromise(r,o,a){let{encoding:n,mode:u,index:A,resolvedP:p}=this.prepareWriteFile(r,a);A!==void 0&&typeof a=="object"&&a.flag&&a.flag.includes("a")&&(o=Buffer.concat([await this.getFileSource(A,{asyncDecompress:!0}),Buffer.from(o)])),n!==null&&(o=o.toString(n));let h=this.setFileSource(p,o);h!==A&&this.registerEntry(p,h),u!==null&&await this.chmodPromise(p,u)}writeFileSync(r,o,a){let{encoding:n,mode:u,index:A,resolvedP:p}=this.prepareWriteFile(r,a);A!==void 0&&typeof a=="object"&&a.flag&&a.flag.includes("a")&&(o=Buffer.concat([this.getFileSource(A),Buffer.from(o)])),n!==null&&(o=o.toString(n));let h=this.setFileSource(p,o);h!==A&&this.registerEntry(p,h),u!==null&&this.chmodSync(p,u)}prepareWriteFile(r,o){if(typeof r=="number"&&(r=this.fdToPath(r,"read")),this.readOnly)throw tr.EROFS(`open '${r}'`);let a=this.resolveFilename(`open '${r}'`,r);if(this.listings.has(a))throw tr.EISDIR(`open '${r}'`);let n=null,u=null;typeof o=="string"?n=o:typeof o=="object"&&({encoding:n=null,mode:u=null}=o);let A=this.entries.get(a);return{encoding:n,mode:u,resolvedP:a,index:A}}async unlinkPromise(r){return this.unlinkSync(r)}unlinkSync(r){if(this.readOnly)throw tr.EROFS(`unlink '${r}'`);let o=this.resolveFilename(`unlink '${r}'`,r);if(this.listings.has(o))throw tr.EISDIR(`unlink '${r}'`);let a=this.entries.get(o);if(typeof a>"u")throw tr.EINVAL(`unlink '${r}'`);this.deleteEntry(o,a)}async utimesPromise(r,o,a){return this.utimesSync(r,o,a)}utimesSync(r,o,a){if(this.readOnly)throw tr.EROFS(`utimes '${r}'`);let n=this.resolveFilename(`utimes '${r}'`,r);this.utimesImpl(n,a)}async lutimesPromise(r,o,a){return this.lutimesSync(r,o,a)}lutimesSync(r,o,a){if(this.readOnly)throw tr.EROFS(`lutimes '${r}'`);let n=this.resolveFilename(`utimes '${r}'`,r,!1);this.utimesImpl(n,a)}utimesImpl(r,o){this.listings.has(r)&&(this.entries.has(r)||this.hydrateDirectory(r));let a=this.entries.get(r);if(a===void 0)throw new Error("Unreachable");if(this.libzip.file.setMtime(this.zip,a,0,cot(o),0)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}async mkdirPromise(r,o){return this.mkdirSync(r,o)}mkdirSync(r,{mode:o=493,recursive:a=!1}={}){if(a)return this.mkdirpSync(r,{chmod:o});if(this.readOnly)throw tr.EROFS(`mkdir '${r}'`);let n=this.resolveFilename(`mkdir '${r}'`,r);if(this.entries.has(n)||this.listings.has(n))throw tr.EEXIST(`mkdir '${r}'`);this.hydrateDirectory(n),this.chmodSync(n,o)}async rmdirPromise(r,o){return this.rmdirSync(r,o)}rmdirSync(r,{recursive:o=!1}={}){if(this.readOnly)throw tr.EROFS(`rmdir '${r}'`);if(o){this.removeSync(r);return}let a=this.resolveFilename(`rmdir '${r}'`,r),n=this.listings.get(a);if(!n)throw tr.ENOTDIR(`rmdir '${r}'`);if(n.size>0)throw tr.ENOTEMPTY(`rmdir '${r}'`);let u=this.entries.get(a);if(typeof u>"u")throw tr.EINVAL(`rmdir '${r}'`);this.deleteEntry(r,u)}async rmPromise(r,o){return this.rmSync(r,o)}rmSync(r,{recursive:o=!1}={}){if(this.readOnly)throw tr.EROFS(`rm '${r}'`);if(o){this.removeSync(r);return}let a=this.resolveFilename(`rm '${r}'`,r),n=this.listings.get(a);if(!n)throw tr.ENOTDIR(`rm '${r}'`);if(n.size>0)throw tr.ENOTEMPTY(`rm '${r}'`);let u=this.entries.get(a);if(typeof u>"u")throw tr.EINVAL(`rm '${r}'`);this.deleteEntry(r,u)}hydrateDirectory(r){let o=this.libzip.dir.add(this.zip,z.relative(Bt.root,r));if(o===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));return this.registerListing(r),this.registerEntry(r,o),o}async linkPromise(r,o){return this.linkSync(r,o)}linkSync(r,o){throw tr.EOPNOTSUPP(`link '${r}' -> '${o}'`)}async symlinkPromise(r,o){return this.symlinkSync(r,o)}symlinkSync(r,o){if(this.readOnly)throw tr.EROFS(`symlink '${r}' -> '${o}'`);let a=this.resolveFilename(`symlink '${r}' -> '${o}'`,o);if(this.listings.has(a))throw tr.EISDIR(`symlink '${r}' -> '${o}'`);if(this.entries.has(a))throw tr.EEXIST(`symlink '${r}' -> '${o}'`);let n=this.setFileSource(a,r);if(this.registerEntry(a,n),this.libzip.file.setExternalAttributes(this.zip,n,0,0,this.libzip.ZIP_OPSYS_UNIX,(ta.constants.S_IFLNK|511)<<16)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));this.symlinkCount+=1}async readFilePromise(r,o){typeof o=="object"&&(o=o?o.encoding:void 0);let a=await this.readFileBuffer(r,{asyncDecompress:!0});return o?a.toString(o):a}readFileSync(r,o){typeof o=="object"&&(o=o?o.encoding:void 0);let a=this.readFileBuffer(r);return o?a.toString(o):a}readFileBuffer(r,o={asyncDecompress:!1}){typeof r=="number"&&(r=this.fdToPath(r,"read"));let a=this.resolveFilename(`open '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw tr.ENOENT(`open '${r}'`);if(r[r.length-1]==="/"&&!this.listings.has(a))throw tr.ENOTDIR(`open '${r}'`);if(this.listings.has(a))throw tr.EISDIR("read");let n=this.entries.get(a);if(n===void 0)throw new Error("Unreachable");return this.getFileSource(n,o)}async readdirPromise(r,o){return this.readdirSync(r,o)}readdirSync(r,o){let a=this.resolveFilename(`scandir '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw tr.ENOENT(`scandir '${r}'`);let n=this.listings.get(a);if(!n)throw tr.ENOTDIR(`scandir '${r}'`);if(o?.recursive)if(o?.withFileTypes){let u=Array.from(n,A=>Object.assign(this.statImpl("lstat",z.join(r,A)),{name:A,path:Bt.dot}));for(let A of u){if(!A.isDirectory())continue;let p=z.join(A.path,A.name),h=this.listings.get(z.join(a,p));for(let E of h)u.push(Object.assign(this.statImpl("lstat",z.join(r,p,E)),{name:E,path:p}))}return u}else{let u=[...n];for(let A of u){let p=this.listings.get(z.join(a,A));if(!(typeof p>"u"))for(let h of p)u.push(z.join(A,h))}return u}else return o?.withFileTypes?Array.from(n,u=>Object.assign(this.statImpl("lstat",z.join(r,u)),{name:u,path:void 0})):[...n]}async readlinkPromise(r){let o=this.prepareReadlink(r);return(await this.getFileSource(o,{asyncDecompress:!0})).toString()}readlinkSync(r){let o=this.prepareReadlink(r);return this.getFileSource(o).toString()}prepareReadlink(r){let o=this.resolveFilename(`readlink '${r}'`,r,!1);if(!this.entries.has(o)&&!this.listings.has(o))throw tr.ENOENT(`readlink '${r}'`);if(r[r.length-1]==="/"&&!this.listings.has(o))throw tr.ENOTDIR(`open '${r}'`);if(this.listings.has(o))throw tr.EINVAL(`readlink '${r}'`);let a=this.entries.get(o);if(a===void 0)throw new Error("Unreachable");if(!this.isSymbolicLink(a))throw tr.EINVAL(`readlink '${r}'`);return a}async truncatePromise(r,o=0){let a=this.resolveFilename(`open '${r}'`,r),n=this.entries.get(a);if(typeof n>"u")throw tr.EINVAL(`open '${r}'`);let u=await this.getFileSource(n,{asyncDecompress:!0}),A=Buffer.alloc(o,0);return u.copy(A),await this.writeFilePromise(r,A)}truncateSync(r,o=0){let a=this.resolveFilename(`open '${r}'`,r),n=this.entries.get(a);if(typeof n>"u")throw tr.EINVAL(`open '${r}'`);let u=this.getFileSource(n),A=Buffer.alloc(o,0);return u.copy(A),this.writeFileSync(r,A)}async ftruncatePromise(r,o){return this.truncatePromise(this.fdToPath(r,"ftruncate"),o)}ftruncateSync(r,o){return this.truncateSync(this.fdToPath(r,"ftruncateSync"),o)}watch(r,o,a){let n;switch(typeof o){case"function":case"string":case"undefined":n=!0;break;default:({persistent:n=!0}=o);break}if(!n)return{on:()=>{},close:()=>{}};let u=setInterval(()=>{},24*60*60*1e3);return{on:()=>{},close:()=>{clearInterval(u)}}}watchFile(r,o,a){let n=z.resolve(Bt.root,r);return ny(this,n,o,a)}unwatchFile(r,o){let a=z.resolve(Bt.root,r);return Ug(this,a,o)}}});function Hle(t,e,r=Buffer.alloc(0),o){let a=new Ji(r),n=I=>I===e||I.startsWith(`${e}/`)?I.slice(0,e.length):null,u=async(I,v)=>()=>a,A=(I,v)=>a,p={...t},h=new Tn(p),E=new qp({baseFs:h,getMountPoint:n,factoryPromise:u,factorySync:A,magicByte:21,maxAge:1/0,typeCheck:o?.typeCheck});return Kw(_le.default,new Gp(E)),a}var _le,qle=Et(()=>{Pt();_le=$e(ve("fs"));sU()});var Gle=Et(()=>{Ole();sU();qle()});var x1={};zt(x1,{DEFAULT_COMPRESSION_LEVEL:()=>Ule,LibzipError:()=>Rb,ZipFS:()=>Ji,ZipOpenFS:()=>Jl,getArchivePart:()=>rU,getLibzipPromise:()=>Aot,getLibzipSync:()=>uot,makeEmptyArchive:()=>Fb,mountMemoryDrive:()=>Hle});function uot(){return b1()}async function Aot(){return b1()}var jle,iA=Et(()=>{$4();jle=$e(Rle());Nle();Gle();Fle(()=>{let t=(0,jle.default)();return Lle(t)})});var RE,Yle=Et(()=>{Pt();qt();k1();RE=class extends nt{constructor(){super(...arguments);this.cwd=ge.String("--cwd",process.cwd(),{description:"The directory to run the command in"});this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=this.args.length>0?`${this.commandName} ${this.args.join(" ")}`:this.commandName;return await TE(r,[],{cwd:le.toPortablePath(this.cwd),stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})}};RE.usage={description:"run a command using yarn's portable shell",details:`
- This command will run a command using Yarn's portable shell.
-
- Make sure to escape glob patterns, redirections, and other features that might be expanded by your own shell.
-
- Note: To escape something from Yarn's shell, you might have to escape it twice, the first time from your own shell.
-
- Note: Don't use this command in Yarn scripts, as Yarn's shell is automatically used.
-
- For a list of features, visit: https://github.com/yarnpkg/berry/blob/master/packages/yarnpkg-shell/README.md.
- `,examples:[["Run a simple command","$0 echo Hello"],["Run a command with a glob pattern","$0 echo '*.js'"],["Run a command with a redirection","$0 echo Hello World '>' hello.txt"],["Run a command with an escaped glob pattern (The double escape is needed in Unix shells)",`$0 echo '"*.js"'`],["Run a command with a variable (Double quotes are needed in Unix shells, to prevent them from expanding the variable)",'$0 "GREETING=Hello echo $GREETING World"']]}});var ll,Wle=Et(()=>{ll=class extends Error{constructor(e){super(e),this.name="ShellError"}}});var Nb={};zt(Nb,{fastGlobOptions:()=>Vle,isBraceExpansion:()=>oU,isGlobPattern:()=>fot,match:()=>pot,micromatchOptions:()=>Lb});function fot(t){if(!Tb.default.scan(t,Lb).isGlob)return!1;try{Tb.default.parse(t,Lb)}catch{return!1}return!0}function pot(t,{cwd:e,baseFs:r}){return(0,Kle.default)(t,{...Vle,cwd:le.fromPortablePath(e),fs:FD(zle.default,new Gp(r))})}function oU(t){return Tb.default.scan(t,Lb).isBrace}var Kle,zle,Tb,Lb,Vle,Jle=Et(()=>{Pt();Kle=$e(RS()),zle=$e(ve("fs")),Tb=$e(Zo()),Lb={strictBrackets:!0},Vle={onlyDirectories:!1,onlyFiles:!1}});function aU(){}function lU(){for(let t of Qd)t.kill()}function ece(t,e,r,o){return a=>{let n=a[0]instanceof sA.Transform?"pipe":a[0],u=a[1]instanceof sA.Transform?"pipe":a[1],A=a[2]instanceof sA.Transform?"pipe":a[2],p=(0,Zle.default)(t,e,{...o,stdio:[n,u,A]});return Qd.add(p),Qd.size===1&&(process.on("SIGINT",aU),process.on("SIGTERM",lU)),a[0]instanceof sA.Transform&&a[0].pipe(p.stdin),a[1]instanceof sA.Transform&&p.stdout.pipe(a[1],{end:!1}),a[2]instanceof sA.Transform&&p.stderr.pipe(a[2],{end:!1}),{stdin:p.stdin,promise:new Promise(h=>{p.on("error",E=>{switch(Qd.delete(p),Qd.size===0&&(process.off("SIGINT",aU),process.off("SIGTERM",lU)),E.code){case"ENOENT":a[2].write(`command not found: ${t}
-`),h(127);break;case"EACCES":a[2].write(`permission denied: ${t}
-`),h(128);break;default:a[2].write(`uncaught error: ${E.message}
-`),h(1);break}}),p.on("close",E=>{Qd.delete(p),Qd.size===0&&(process.off("SIGINT",aU),process.off("SIGTERM",lU)),h(E!==null?E:129)})})}}}function tce(t){return e=>{let r=e[0]==="pipe"?new sA.PassThrough:e[0];return{stdin:r,promise:Promise.resolve().then(()=>t({stdin:r,stdout:e[1],stderr:e[2]}))}}}function Ob(t,e){return LE.start(t,e)}function Xle(t,e=null){let r=new sA.PassThrough,o=new $le.StringDecoder,a="";return r.on("data",n=>{let u=o.write(n),A;do if(A=u.indexOf(`
-`),A!==-1){let p=a+u.substring(0,A);u=u.substring(A+1),a="",t(e!==null?`${e} ${p}`:p)}while(A!==-1);a+=u}),r.on("end",()=>{let n=o.end();n!==""&&t(e!==null?`${e} ${n}`:n)}),r}function rce(t,{prefix:e}){return{stdout:Xle(r=>t.stdout.write(`${r}
-`),t.stdout.isTTY?e:null),stderr:Xle(r=>t.stderr.write(`${r}
-`),t.stderr.isTTY?e:null)}}var Zle,sA,$le,Qd,Xl,cU,LE,uU=Et(()=>{Zle=$e(sT()),sA=ve("stream"),$le=ve("string_decoder"),Qd=new Set;Xl=class{constructor(e){this.stream=e}close(){}get(){return this.stream}},cU=class{constructor(){this.stream=null}close(){if(this.stream===null)throw new Error("Assertion failed: No stream attached");this.stream.end()}attach(e){this.stream=e}get(){if(this.stream===null)throw new Error("Assertion failed: No stream attached");return this.stream}},LE=class{constructor(e,r){this.stdin=null;this.stdout=null;this.stderr=null;this.pipe=null;this.ancestor=e,this.implementation=r}static start(e,{stdin:r,stdout:o,stderr:a}){let n=new LE(null,e);return n.stdin=r,n.stdout=o,n.stderr=a,n}pipeTo(e,r=1){let o=new LE(this,e),a=new cU;return o.pipe=a,o.stdout=this.stdout,o.stderr=this.stderr,(r&1)===1?this.stdout=a:this.ancestor!==null&&(this.stderr=this.ancestor.stdout),(r&2)===2?this.stderr=a:this.ancestor!==null&&(this.stderr=this.ancestor.stderr),o}async exec(){let e=["ignore","ignore","ignore"];if(this.pipe)e[0]="pipe";else{if(this.stdin===null)throw new Error("Assertion failed: No input stream registered");e[0]=this.stdin.get()}let r;if(this.stdout===null)throw new Error("Assertion failed: No output stream registered");r=this.stdout,e[1]=r.get();let o;if(this.stderr===null)throw new Error("Assertion failed: No error stream registered");o=this.stderr,e[2]=o.get();let a=this.implementation(e);return this.pipe&&this.pipe.attach(a.stdin),await a.promise.then(n=>(r.close(),o.close(),n))}async run(){let e=[];for(let o=this;o;o=o.ancestor)e.push(o.exec());return(await Promise.all(e))[0]}}});var T1={};zt(T1,{EntryCommand:()=>RE,ShellError:()=>ll,execute:()=>TE,globUtils:()=>Nb});function nce(t,e,r){let o=new cl.PassThrough({autoDestroy:!0});switch(t){case 0:(e&1)===1&&r.stdin.pipe(o,{end:!1}),(e&2)===2&&r.stdin instanceof cl.Writable&&o.pipe(r.stdin,{end:!1});break;case 1:(e&1)===1&&r.stdout.pipe(o,{end:!1}),(e&2)===2&&o.pipe(r.stdout,{end:!1});break;case 2:(e&1)===1&&r.stderr.pipe(o,{end:!1}),(e&2)===2&&o.pipe(r.stderr,{end:!1});break;default:throw new ll(`Bad file descriptor: "${t}"`)}return o}function Ub(t,e={}){let r={...t,...e};return r.environment={...t.environment,...e.environment},r.variables={...t.variables,...e.variables},r}async function got(t,e,r){let o=[],a=new cl.PassThrough;return a.on("data",n=>o.push(n)),await _b(t,e,Ub(r,{stdout:a})),Buffer.concat(o).toString().replace(/[\r\n]+$/,"")}async function ice(t,e,r){let o=t.map(async n=>{let u=await Fd(n.args,e,r);return{name:n.name,value:u.join(" ")}});return(await Promise.all(o)).reduce((n,u)=>(n[u.name]=u.value,n),{})}function Mb(t){return t.match(/[^ \r\n\t]+/g)||[]}async function uce(t,e,r,o,a=o){switch(t.name){case"$":o(String(process.pid));break;case"#":o(String(e.args.length));break;case"@":if(t.quoted)for(let n of e.args)a(n);else for(let n of e.args){let u=Mb(n);for(let A=0;A<u.length-1;++A)a(u[A]);o(u[u.length-1])}break;case"*":{let n=e.args.join(" ");if(t.quoted)o(n);else for(let u of Mb(n))a(u)}break;case"PPID":o(String(process.ppid));break;case"RANDOM":o(String(Math.floor(Math.random()*32768)));break;default:{let n=parseInt(t.name,10),u,A=Number.isFinite(n);if(A?n>=0&&n<e.args.length&&(u=e.args[n]):Object.hasOwn(r.variables,t.name)?u=r.variables[t.name]:Object.hasOwn(r.environment,t.name)&&(u=r.environment[t.name]),typeof u<"u"&&t.alternativeValue?u=(await Fd(t.alternativeValue,e,r)).join(" "):typeof u>"u"&&(t.defaultValue?u=(await Fd(t.defaultValue,e,r)).join(" "):t.alternativeValue&&(u="")),typeof u>"u")throw A?new ll(`Unbound argument #${n}`):new ll(`Unbound variable "${t.name}"`);if(t.quoted)o(u);else{let p=Mb(u);for(let E=0;E<p.length-1;++E)a(p[E]);let h=p[p.length-1];typeof h<"u"&&o(h)}}break}}async function Q1(t,e,r){if(t.type==="number"){if(Number.isInteger(t.value))return t.value;throw new Error(`Invalid number: "${t.value}", only integers are allowed`)}else if(t.type==="variable"){let o=[];await uce({...t,quoted:!0},e,r,n=>o.push(n));let a=Number(o.join(" "));return Number.isNaN(a)?Q1({type:"variable",name:o.join(" ")},e,r):Q1({type:"number",value:a},e,r)}else return dot[t.type](await Q1(t.left,e,r),await Q1(t.right,e,r))}async function Fd(t,e,r){let o=new Map,a=[],n=[],u=E=>{n.push(E)},A=()=>{n.length>0&&a.push(n.join("")),n=[]},p=E=>{u(E),A()},h=(E,I,v)=>{let x=JSON.stringify({type:E,fd:I}),C=o.get(x);typeof C>"u"&&o.set(x,C=[]),C.push(v)};for(let E of t){let I=!1;switch(E.type){case"redirection":{let v=await Fd(E.args,e,r);for(let x of v)h(E.subtype,E.fd,x)}break;case"argument":for(let v of E.segments)switch(v.type){case"text":u(v.text);break;case"glob":u(v.pattern),I=!0;break;case"shell":{let x=await got(v.shell,e,r);if(v.quoted)u(x);else{let C=Mb(x);for(let R=0;R<C.length-1;++R)p(C[R]);u(C[C.length-1])}}break;case"variable":await uce(v,e,r,u,p);break;case"arithmetic":u(String(await Q1(v.arithmetic,e,r)));break}break}if(A(),I){let v=a.pop();if(typeof v>"u")throw new Error("Assertion failed: Expected a glob pattern to have been set");let x=await e.glob.match(v,{cwd:r.cwd,baseFs:e.baseFs});if(x.length===0){let C=oU(v)?". Note: Brace expansion of arbitrary strings isn't currently supported. For more details, please read this issue: https://github.com/yarnpkg/berry/issues/22":"";throw new ll(`No matches found: "${v}"${C}`)}for(let C of x.sort())p(C)}}if(o.size>0){let E=[];for(let[I,v]of o.entries())E.splice(E.length,0,I,String(v.length),...v);a.splice(0,0,"__ysh_set_redirects",...E,"--")}return a}function F1(t,e,r){e.builtins.has(t[0])||(t=["command",...t]);let o=le.fromPortablePath(r.cwd),a=r.environment;typeof a.PWD<"u"&&(a={...a,PWD:o});let[n,...u]=t;if(n==="command")return ece(u[0],u.slice(1),e,{cwd:o,env:a});let A=e.builtins.get(n);if(typeof A>"u")throw new Error(`Assertion failed: A builtin should exist for "${n}"`);return tce(async({stdin:p,stdout:h,stderr:E})=>{let{stdin:I,stdout:v,stderr:x}=r;r.stdin=p,r.stdout=h,r.stderr=E;try{return await A(u,e,r)}finally{r.stdin=I,r.stdout=v,r.stderr=x}})}function mot(t,e,r){return o=>{let a=new cl.PassThrough,n=_b(t,e,Ub(r,{stdin:a}));return{stdin:a,promise:n}}}function yot(t,e,r){return o=>{let a=new cl.PassThrough,n=_b(t,e,r);return{stdin:a,promise:n}}}function sce(t,e,r,o){if(e.length===0)return t;{let a;do a=String(Math.random());while(Object.hasOwn(o.procedures,a));return o.procedures={...o.procedures},o.procedures[a]=t,F1([...e,"__ysh_run_procedure",a],r,o)}}async function oce(t,e,r){let o=t,a=null,n=null;for(;o;){let u=o.then?{...r}:r,A;switch(o.type){case"command":{let p=await Fd(o.args,e,r),h=await ice(o.envs,e,r);A=o.envs.length?F1(p,e,Ub(u,{environment:h})):F1(p,e,u)}break;case"subshell":{let p=await Fd(o.args,e,r),h=mot(o.subshell,e,u);A=sce(h,p,e,u)}break;case"group":{let p=await Fd(o.args,e,r),h=yot(o.group,e,u);A=sce(h,p,e,u)}break;case"envs":{let p=await ice(o.envs,e,r);u.environment={...u.environment,...p},A=F1(["true"],e,u)}break}if(typeof A>"u")throw new Error("Assertion failed: An action should have been generated");if(a===null)n=Ob(A,{stdin:new Xl(u.stdin),stdout:new Xl(u.stdout),stderr:new Xl(u.stderr)});else{if(n===null)throw new Error("Assertion failed: The execution pipeline should have been setup");switch(a){case"|":n=n.pipeTo(A,1);break;case"|&":n=n.pipeTo(A,3);break}}o.then?(a=o.then.type,o=o.then.chain):o=null}if(n===null)throw new Error("Assertion failed: The execution pipeline should have been setup");return await n.run()}async function Eot(t,e,r,{background:o=!1}={}){function a(n){let u=["#2E86AB","#A23B72","#F18F01","#C73E1D","#CCE2A3"],A=u[n%u.length];return ace.default.hex(A)}if(o){let n=r.nextBackgroundJobIndex++,u=a(n),A=`[${n}]`,p=u(A),{stdout:h,stderr:E}=rce(r,{prefix:p});return r.backgroundJobs.push(oce(t,e,Ub(r,{stdout:h,stderr:E})).catch(I=>E.write(`${I.message}
-`)).finally(()=>{r.stdout.isTTY&&r.stdout.write(`Job ${p}, '${u(uy(t))}' has ended
-`)})),0}return await oce(t,e,r)}async function Cot(t,e,r,{background:o=!1}={}){let a,n=A=>{a=A,r.variables["?"]=String(A)},u=async A=>{try{return await Eot(A.chain,e,r,{background:o&&typeof A.then>"u"})}catch(p){if(!(p instanceof ll))throw p;return r.stderr.write(`${p.message}
-`),1}};for(n(await u(t));t.then;){if(r.exitCode!==null)return r.exitCode;switch(t.then.type){case"&&":a===0&&n(await u(t.then.line));break;case"||":a!==0&&n(await u(t.then.line));break;default:throw new Error(`Assertion failed: Unsupported command type: "${t.then.type}"`)}t=t.then.line}return a}async function _b(t,e,r){let o=r.backgroundJobs;r.backgroundJobs=[];let a=0;for(let{command:n,type:u}of t){if(a=await Cot(n,e,r,{background:u==="&"}),r.exitCode!==null)return r.exitCode;r.variables["?"]=String(a)}return await Promise.all(r.backgroundJobs),r.backgroundJobs=o,a}function Ace(t){switch(t.type){case"variable":return t.name==="@"||t.name==="#"||t.name==="*"||Number.isFinite(parseInt(t.name,10))||"defaultValue"in t&&!!t.defaultValue&&t.defaultValue.some(e=>R1(e))||"alternativeValue"in t&&!!t.alternativeValue&&t.alternativeValue.some(e=>R1(e));case"arithmetic":return AU(t.arithmetic);case"shell":return fU(t.shell);default:return!1}}function R1(t){switch(t.type){case"redirection":return t.args.some(e=>R1(e));case"argument":return t.segments.some(e=>Ace(e));default:throw new Error(`Assertion failed: Unsupported argument type: "${t.type}"`)}}function AU(t){switch(t.type){case"variable":return Ace(t);case"number":return!1;default:return AU(t.left)||AU(t.right)}}function fU(t){return t.some(({command:e})=>{for(;e;){let r=e.chain;for(;r;){let o;switch(r.type){case"subshell":o=fU(r.subshell);break;case"command":o=r.envs.some(a=>a.args.some(n=>R1(n)))||r.args.some(a=>R1(a));break}if(o)return!0;if(!r.then)break;r=r.then.chain}if(!e.then)break;e=e.then.line}return!1})}async function TE(t,e=[],{baseFs:r=new Tn,builtins:o={},cwd:a=le.toPortablePath(process.cwd()),env:n=process.env,stdin:u=process.stdin,stdout:A=process.stdout,stderr:p=process.stderr,variables:h={},glob:E=Nb}={}){let I={};for(let[C,R]of Object.entries(n))typeof R<"u"&&(I[C]=R);let v=new Map(hot);for(let[C,R]of Object.entries(o))v.set(C,R);u===null&&(u=new cl.PassThrough,u.end());let x=LD(t,E);if(!fU(x)&&x.length>0&&e.length>0){let{command:C}=x[x.length-1];for(;C.then;)C=C.then.line;let R=C.chain;for(;R.then;)R=R.then.chain;R.type==="command"&&(R.args=R.args.concat(e.map(N=>({type:"argument",segments:[{type:"text",text:N}]}))))}return await _b(x,{args:e,baseFs:r,builtins:v,initialStdin:u,initialStdout:A,initialStderr:p,glob:E},{cwd:a,environment:I,exitCode:null,procedures:{},stdin:u,stdout:A,stderr:p,variables:Object.assign({},h,{["?"]:0}),nextBackgroundJobIndex:1,backgroundJobs:[]})}var ace,lce,cl,cce,hot,dot,k1=Et(()=>{Pt();Nl();ace=$e(IL()),lce=ve("os"),cl=ve("stream"),cce=ve("timers/promises");Yle();Wle();Jle();uU();uU();hot=new Map([["cd",async([t=(0,lce.homedir)(),...e],r,o)=>{let a=z.resolve(o.cwd,le.toPortablePath(t));if(!(await r.baseFs.statPromise(a).catch(u=>{throw u.code==="ENOENT"?new ll(`cd: no such file or directory: ${t}`):u})).isDirectory())throw new ll(`cd: not a directory: ${t}`);return o.cwd=a,0}],["pwd",async(t,e,r)=>(r.stdout.write(`${le.fromPortablePath(r.cwd)}
-`),0)],[":",async(t,e,r)=>0],["true",async(t,e,r)=>0],["false",async(t,e,r)=>1],["exit",async([t,...e],r,o)=>o.exitCode=parseInt(t??o.variables["?"],10)],["echo",async(t,e,r)=>(r.stdout.write(`${t.join(" ")}
-`),0)],["sleep",async([t],e,r)=>{if(typeof t>"u")throw new ll("sleep: missing operand");let o=Number(t);if(Number.isNaN(o))throw new ll(`sleep: invalid time interval '${t}'`);return await(0,cce.setTimeout)(1e3*o,0)}],["__ysh_run_procedure",async(t,e,r)=>{let o=r.procedures[t[0]];return await Ob(o,{stdin:new Xl(r.stdin),stdout:new Xl(r.stdout),stderr:new Xl(r.stderr)}).run()}],["__ysh_set_redirects",async(t,e,r)=>{let o=r.stdin,a=r.stdout,n=r.stderr,u=[],A=[],p=[],h=0;for(;t[h]!=="--";){let I=t[h++],{type:v,fd:x}=JSON.parse(I),C=V=>{switch(x){case null:case 0:u.push(V);break;default:throw new Error(`Unsupported file descriptor: "${x}"`)}},R=V=>{switch(x){case null:case 1:A.push(V);break;case 2:p.push(V);break;default:throw new Error(`Unsupported file descriptor: "${x}"`)}},N=Number(t[h++]),U=h+N;for(let V=h;V<U;++h,++V)switch(v){case"<":C(()=>e.baseFs.createReadStream(z.resolve(r.cwd,le.toPortablePath(t[V]))));break;case"<<<":C(()=>{let te=new cl.PassThrough;return process.nextTick(()=>{te.write(`${t[V]}
-`),te.end()}),te});break;case"<&":C(()=>nce(Number(t[V]),1,r));break;case">":case">>":{let te=z.resolve(r.cwd,le.toPortablePath(t[V]));R(te==="/dev/null"?new cl.Writable({autoDestroy:!0,emitClose:!0,write(ae,fe,ue){setImmediate(ue)}}):e.baseFs.createWriteStream(te,v===">>"?{flags:"a"}:void 0))}break;case">&":R(nce(Number(t[V]),2,r));break;default:throw new Error(`Assertion failed: Unsupported redirection type: "${v}"`)}}if(u.length>0){let I=new cl.PassThrough;o=I;let v=x=>{if(x===u.length)I.end();else{let C=u[x]();C.pipe(I,{end:!1}),C.on("end",()=>{v(x+1)})}};v(0)}if(A.length>0){let I=new cl.PassThrough;a=I;for(let v of A)I.pipe(v)}if(p.length>0){let I=new cl.PassThrough;n=I;for(let v of p)I.pipe(v)}let E=await Ob(F1(t.slice(h+1),e,r),{stdin:new Xl(o),stdout:new Xl(a),stderr:new Xl(n)}).run();return await Promise.all(A.map(I=>new Promise((v,x)=>{I.on("error",C=>{x(C)}),I.on("close",()=>{v()}),I.end()}))),await Promise.all(p.map(I=>new Promise((v,x)=>{I.on("error",C=>{x(C)}),I.on("close",()=>{v()}),I.end()}))),E}]]);dot={addition:(t,e)=>t+e,subtraction:(t,e)=>t-e,multiplication:(t,e)=>t*e,division:(t,e)=>Math.trunc(t/e)}});var Hb=_((n4t,fce)=>{function wot(t,e){for(var r=-1,o=t==null?0:t.length,a=Array(o);++r<o;)a[r]=e(t[r],r,t);return a}fce.exports=wot});var yce=_((i4t,mce)=>{var pce=hd(),Iot=Hb(),Bot=ql(),vot=pE(),Dot=1/0,hce=pce?pce.prototype:void 0,gce=hce?hce.toString:void 0;function dce(t){if(typeof t=="string")return t;if(Bot(t))return Iot(t,dce)+"";if(vot(t))return gce?gce.call(t):"";var e=t+"";return e=="0"&&1/t==-Dot?"-0":e}mce.exports=dce});var L1=_((s4t,Ece)=>{var Pot=yce();function Sot(t){return t==null?"":Pot(t)}Ece.exports=Sot});var pU=_((o4t,Cce)=>{function bot(t,e,r){var o=-1,a=t.length;e<0&&(e=-e>a?0:a+e),r=r>a?a:r,r<0&&(r+=a),a=e>r?0:r-e>>>0,e>>>=0;for(var n=Array(a);++o<a;)n[o]=t[o+e];return n}Cce.exports=bot});var Ice=_((a4t,wce)=>{var xot=pU();function kot(t,e,r){var o=t.length;return r=r===void 0?o:r,!e&&r>=o?t:xot(t,e,r)}wce.exports=kot});var hU=_((l4t,Bce)=>{var Qot="\\ud800-\\udfff",Fot="\\u0300-\\u036f",Rot="\\ufe20-\\ufe2f",Tot="\\u20d0-\\u20ff",Lot=Fot+Rot+Tot,Not="\\ufe0e\\ufe0f",Oot="\\u200d",Mot=RegExp("["+Oot+Qot+Lot+Not+"]");function Uot(t){return Mot.test(t)}Bce.exports=Uot});var Dce=_((c4t,vce)=>{function _ot(t){return t.split("")}vce.exports=_ot});var Rce=_((u4t,Fce)=>{var Pce="\\ud800-\\udfff",Hot="\\u0300-\\u036f",qot="\\ufe20-\\ufe2f",Got="\\u20d0-\\u20ff",jot=Hot+qot+Got,Yot="\\ufe0e\\ufe0f",Wot="["+Pce+"]",gU="["+jot+"]",dU="\\ud83c[\\udffb-\\udfff]",Kot="(?:"+gU+"|"+dU+")",Sce="[^"+Pce+"]",bce="(?:\\ud83c[\\udde6-\\uddff]){2}",xce="[\\ud800-\\udbff][\\udc00-\\udfff]",zot="\\u200d",kce=Kot+"?",Qce="["+Yot+"]?",Vot="(?:"+zot+"(?:"+[Sce,bce,xce].join("|")+")"+Qce+kce+")*",Jot=Qce+kce+Vot,Xot="(?:"+[Sce+gU+"?",gU,bce,xce,Wot].join("|")+")",Zot=RegExp(dU+"(?="+dU+")|"+Xot+Jot,"g");function $ot(t){return t.match(Zot)||[]}Fce.exports=$ot});var Lce=_((A4t,Tce)=>{var eat=Dce(),tat=hU(),rat=Rce();function nat(t){return tat(t)?rat(t):eat(t)}Tce.exports=nat});var Oce=_((f4t,Nce)=>{var iat=Ice(),sat=hU(),oat=Lce(),aat=L1();function lat(t){return function(e){e=aat(e);var r=sat(e)?oat(e):void 0,o=r?r[0]:e.charAt(0),a=r?iat(r,1).join(""):e.slice(1);return o[t]()+a}}Nce.exports=lat});var Uce=_((p4t,Mce)=>{var cat=Oce(),uat=cat("toUpperCase");Mce.exports=uat});var mU=_((h4t,_ce)=>{var Aat=L1(),fat=Uce();function pat(t){return fat(Aat(t).toLowerCase())}_ce.exports=pat});var Hce=_((g4t,qb)=>{function hat(){var t=0,e=1,r=2,o=3,a=4,n=5,u=6,A=7,p=8,h=9,E=10,I=11,v=12,x=13,C=14,R=15,N=16,U=17,V=0,te=1,ae=2,fe=3,ue=4;function me(g,Ee){return 55296<=g.charCodeAt(Ee)&&g.charCodeAt(Ee)<=56319&&56320<=g.charCodeAt(Ee+1)&&g.charCodeAt(Ee+1)<=57343}function he(g,Ee){Ee===void 0&&(Ee=0);var Pe=g.charCodeAt(Ee);if(55296<=Pe&&Pe<=56319&&Ee<g.length-1){var ce=Pe,ne=g.charCodeAt(Ee+1);return 56320<=ne&&ne<=57343?(ce-55296)*1024+(ne-56320)+65536:ce}if(56320<=Pe&&Pe<=57343&&Ee>=1){var ce=g.charCodeAt(Ee-1),ne=Pe;return 55296<=ce&&ce<=56319?(ce-55296)*1024+(ne-56320)+65536:ne}return Pe}function Be(g,Ee,Pe){var ce=[g].concat(Ee).concat([Pe]),ne=ce[ce.length-2],ee=Pe,Ie=ce.lastIndexOf(C);if(Ie>1&&ce.slice(1,Ie).every(function(H){return H==o})&&[o,x,U].indexOf(g)==-1)return ae;var Fe=ce.lastIndexOf(a);if(Fe>0&&ce.slice(1,Fe).every(function(H){return H==a})&&[v,a].indexOf(ne)==-1)return ce.filter(function(H){return H==a}).length%2==1?fe:ue;if(ne==t&&ee==e)return V;if(ne==r||ne==t||ne==e)return ee==C&&Ee.every(function(H){return H==o})?ae:te;if(ee==r||ee==t||ee==e)return te;if(ne==u&&(ee==u||ee==A||ee==h||ee==E))return V;if((ne==h||ne==A)&&(ee==A||ee==p))return V;if((ne==E||ne==p)&&ee==p)return V;if(ee==o||ee==R)return V;if(ee==n)return V;if(ne==v)return V;var At=ce.indexOf(o)!=-1?ce.lastIndexOf(o)-1:ce.length-2;return[x,U].indexOf(ce[At])!=-1&&ce.slice(At+1,-1).every(function(H){return H==o})&&ee==C||ne==R&&[N,U].indexOf(ee)!=-1?V:Ee.indexOf(a)!=-1?ae:ne==a&&ee==a?V:te}this.nextBreak=function(g,Ee){if(Ee===void 0&&(Ee=0),Ee<0)return 0;if(Ee>=g.length-1)return g.length;for(var Pe=we(he(g,Ee)),ce=[],ne=Ee+1;ne<g.length;ne++)if(!me(g,ne-1)){var ee=we(he(g,ne));if(Be(Pe,ce,ee))return ne;ce.push(ee)}return g.length},this.splitGraphemes=function(g){for(var Ee=[],Pe=0,ce;(ce=this.nextBreak(g,Pe))<g.length;)Ee.push(g.slice(Pe,ce)),Pe=ce;return Pe<g.length&&Ee.push(g.slice(Pe)),Ee},this.iterateGraphemes=function(g){var Ee=0,Pe={next:function(){var ce,ne;return(ne=this.nextBreak(g,Ee))<g.length?(ce=g.slice(Ee,ne),Ee=ne,{value:ce,done:!1}):Ee<g.length?(ce=g.slice(Ee),Ee=g.length,{value:ce,done:!1}):{value:void 0,done:!0}}.bind(this)};return typeof Symbol<"u"&&Symbol.iterator&&(Pe[Symbol.iterator]=function(){return Pe}),Pe},this.countGraphemes=function(g){for(var Ee=0,Pe=0,ce;(ce=this.nextBreak(g,Pe))<g.length;)Pe=ce,Ee++;return Pe<g.length&&Ee++,Ee};function we(g){return 1536<=g&&g<=1541||g==1757||g==1807||g==2274||g==3406||g==69821||70082<=g&&g<=70083||g==72250||72326<=g&&g<=72329||g==73030?v:g==13?t:g==10?e:0<=g&&g<=9||11<=g&&g<=12||14<=g&&g<=31||127<=g&&g<=159||g==173||g==1564||g==6158||g==8203||8206<=g&&g<=8207||g==8232||g==8233||8234<=g&&g<=8238||8288<=g&&g<=8292||g==8293||8294<=g&&g<=8303||55296<=g&&g<=57343||g==65279||65520<=g&&g<=65528||65529<=g&&g<=65531||113824<=g&&g<=113827||119155<=g&&g<=119162||g==917504||g==917505||917506<=g&&g<=917535||917632<=g&&g<=917759||918e3<=g&&g<=921599?r:768<=g&&g<=879||1155<=g&&g<=1159||1160<=g&&g<=1161||1425<=g&&g<=1469||g==1471||1473<=g&&g<=1474||1476<=g&&g<=1477||g==1479||1552<=g&&g<=1562||1611<=g&&g<=1631||g==1648||1750<=g&&g<=1756||1759<=g&&g<=1764||1767<=g&&g<=1768||1770<=g&&g<=1773||g==1809||1840<=g&&g<=1866||1958<=g&&g<=1968||2027<=g&&g<=2035||2070<=g&&g<=2073||2075<=g&&g<=2083||2085<=g&&g<=2087||2089<=g&&g<=2093||2137<=g&&g<=2139||2260<=g&&g<=2273||2275<=g&&g<=2306||g==2362||g==2364||2369<=g&&g<=2376||g==2381||2385<=g&&g<=2391||2402<=g&&g<=2403||g==2433||g==2492||g==2494||2497<=g&&g<=2500||g==2509||g==2519||2530<=g&&g<=2531||2561<=g&&g<=2562||g==2620||2625<=g&&g<=2626||2631<=g&&g<=2632||2635<=g&&g<=2637||g==2641||2672<=g&&g<=2673||g==2677||2689<=g&&g<=2690||g==2748||2753<=g&&g<=2757||2759<=g&&g<=2760||g==2765||2786<=g&&g<=2787||2810<=g&&g<=2815||g==2817||g==2876||g==2878||g==2879||2881<=g&&g<=2884||g==2893||g==2902||g==2903||2914<=g&&g<=2915||g==2946||g==3006||g==3008||g==3021||g==3031||g==3072||3134<=g&&g<=3136||3142<=g&&g<=3144||3146<=g&&g<=3149||3157<=g&&g<=3158||3170<=g&&g<=3171||g==3201||g==3260||g==3263||g==3266||g==3270||3276<=g&&g<=3277||3285<=g&&g<=3286||3298<=g&&g<=3299||3328<=g&&g<=3329||3387<=g&&g<=3388||g==3390||3393<=g&&g<=3396||g==3405||g==3415||3426<=g&&g<=3427||g==3530||g==3535||3538<=g&&g<=3540||g==3542||g==3551||g==3633||3636<=g&&g<=3642||3655<=g&&g<=3662||g==3761||3764<=g&&g<=3769||3771<=g&&g<=3772||3784<=g&&g<=3789||3864<=g&&g<=3865||g==3893||g==3895||g==3897||3953<=g&&g<=3966||3968<=g&&g<=3972||3974<=g&&g<=3975||3981<=g&&g<=3991||3993<=g&&g<=4028||g==4038||4141<=g&&g<=4144||4146<=g&&g<=4151||4153<=g&&g<=4154||4157<=g&&g<=4158||4184<=g&&g<=4185||4190<=g&&g<=4192||4209<=g&&g<=4212||g==4226||4229<=g&&g<=4230||g==4237||g==4253||4957<=g&&g<=4959||5906<=g&&g<=5908||5938<=g&&g<=5940||5970<=g&&g<=5971||6002<=g&&g<=6003||6068<=g&&g<=6069||6071<=g&&g<=6077||g==6086||6089<=g&&g<=6099||g==6109||6155<=g&&g<=6157||6277<=g&&g<=6278||g==6313||6432<=g&&g<=6434||6439<=g&&g<=6440||g==6450||6457<=g&&g<=6459||6679<=g&&g<=6680||g==6683||g==6742||6744<=g&&g<=6750||g==6752||g==6754||6757<=g&&g<=6764||6771<=g&&g<=6780||g==6783||6832<=g&&g<=6845||g==6846||6912<=g&&g<=6915||g==6964||6966<=g&&g<=6970||g==6972||g==6978||7019<=g&&g<=7027||7040<=g&&g<=7041||7074<=g&&g<=7077||7080<=g&&g<=7081||7083<=g&&g<=7085||g==7142||7144<=g&&g<=7145||g==7149||7151<=g&&g<=7153||7212<=g&&g<=7219||7222<=g&&g<=7223||7376<=g&&g<=7378||7380<=g&&g<=7392||7394<=g&&g<=7400||g==7405||g==7412||7416<=g&&g<=7417||7616<=g&&g<=7673||7675<=g&&g<=7679||g==8204||8400<=g&&g<=8412||8413<=g&&g<=8416||g==8417||8418<=g&&g<=8420||8421<=g&&g<=8432||11503<=g&&g<=11505||g==11647||11744<=g&&g<=11775||12330<=g&&g<=12333||12334<=g&&g<=12335||12441<=g&&g<=12442||g==42607||42608<=g&&g<=42610||42612<=g&&g<=42621||42654<=g&&g<=42655||42736<=g&&g<=42737||g==43010||g==43014||g==43019||43045<=g&&g<=43046||43204<=g&&g<=43205||43232<=g&&g<=43249||43302<=g&&g<=43309||43335<=g&&g<=43345||43392<=g&&g<=43394||g==43443||43446<=g&&g<=43449||g==43452||g==43493||43561<=g&&g<=43566||43569<=g&&g<=43570||43573<=g&&g<=43574||g==43587||g==43596||g==43644||g==43696||43698<=g&&g<=43700||43703<=g&&g<=43704||43710<=g&&g<=43711||g==43713||43756<=g&&g<=43757||g==43766||g==44005||g==44008||g==44013||g==64286||65024<=g&&g<=65039||65056<=g&&g<=65071||65438<=g&&g<=65439||g==66045||g==66272||66422<=g&&g<=66426||68097<=g&&g<=68099||68101<=g&&g<=68102||68108<=g&&g<=68111||68152<=g&&g<=68154||g==68159||68325<=g&&g<=68326||g==69633||69688<=g&&g<=69702||69759<=g&&g<=69761||69811<=g&&g<=69814||69817<=g&&g<=69818||69888<=g&&g<=69890||69927<=g&&g<=69931||69933<=g&&g<=69940||g==70003||70016<=g&&g<=70017||70070<=g&&g<=70078||70090<=g&&g<=70092||70191<=g&&g<=70193||g==70196||70198<=g&&g<=70199||g==70206||g==70367||70371<=g&&g<=70378||70400<=g&&g<=70401||g==70460||g==70462||g==70464||g==70487||70502<=g&&g<=70508||70512<=g&&g<=70516||70712<=g&&g<=70719||70722<=g&&g<=70724||g==70726||g==70832||70835<=g&&g<=70840||g==70842||g==70845||70847<=g&&g<=70848||70850<=g&&g<=70851||g==71087||71090<=g&&g<=71093||71100<=g&&g<=71101||71103<=g&&g<=71104||71132<=g&&g<=71133||71219<=g&&g<=71226||g==71229||71231<=g&&g<=71232||g==71339||g==71341||71344<=g&&g<=71349||g==71351||71453<=g&&g<=71455||71458<=g&&g<=71461||71463<=g&&g<=71467||72193<=g&&g<=72198||72201<=g&&g<=72202||72243<=g&&g<=72248||72251<=g&&g<=72254||g==72263||72273<=g&&g<=72278||72281<=g&&g<=72283||72330<=g&&g<=72342||72344<=g&&g<=72345||72752<=g&&g<=72758||72760<=g&&g<=72765||g==72767||72850<=g&&g<=72871||72874<=g&&g<=72880||72882<=g&&g<=72883||72885<=g&&g<=72886||73009<=g&&g<=73014||g==73018||73020<=g&&g<=73021||73023<=g&&g<=73029||g==73031||92912<=g&&g<=92916||92976<=g&&g<=92982||94095<=g&&g<=94098||113821<=g&&g<=113822||g==119141||119143<=g&&g<=119145||119150<=g&&g<=119154||119163<=g&&g<=119170||119173<=g&&g<=119179||119210<=g&&g<=119213||119362<=g&&g<=119364||121344<=g&&g<=121398||121403<=g&&g<=121452||g==121461||g==121476||121499<=g&&g<=121503||121505<=g&&g<=121519||122880<=g&&g<=122886||122888<=g&&g<=122904||122907<=g&&g<=122913||122915<=g&&g<=122916||122918<=g&&g<=122922||125136<=g&&g<=125142||125252<=g&&g<=125258||917536<=g&&g<=917631||917760<=g&&g<=917999?o:127462<=g&&g<=127487?a:g==2307||g==2363||2366<=g&&g<=2368||2377<=g&&g<=2380||2382<=g&&g<=2383||2434<=g&&g<=2435||2495<=g&&g<=2496||2503<=g&&g<=2504||2507<=g&&g<=2508||g==2563||2622<=g&&g<=2624||g==2691||2750<=g&&g<=2752||g==2761||2763<=g&&g<=2764||2818<=g&&g<=2819||g==2880||2887<=g&&g<=2888||2891<=g&&g<=2892||g==3007||3009<=g&&g<=3010||3014<=g&&g<=3016||3018<=g&&g<=3020||3073<=g&&g<=3075||3137<=g&&g<=3140||3202<=g&&g<=3203||g==3262||3264<=g&&g<=3265||3267<=g&&g<=3268||3271<=g&&g<=3272||3274<=g&&g<=3275||3330<=g&&g<=3331||3391<=g&&g<=3392||3398<=g&&g<=3400||3402<=g&&g<=3404||3458<=g&&g<=3459||3536<=g&&g<=3537||3544<=g&&g<=3550||3570<=g&&g<=3571||g==3635||g==3763||3902<=g&&g<=3903||g==3967||g==4145||4155<=g&&g<=4156||4182<=g&&g<=4183||g==4228||g==6070||6078<=g&&g<=6085||6087<=g&&g<=6088||6435<=g&&g<=6438||6441<=g&&g<=6443||6448<=g&&g<=6449||6451<=g&&g<=6456||6681<=g&&g<=6682||g==6741||g==6743||6765<=g&&g<=6770||g==6916||g==6965||g==6971||6973<=g&&g<=6977||6979<=g&&g<=6980||g==7042||g==7073||7078<=g&&g<=7079||g==7082||g==7143||7146<=g&&g<=7148||g==7150||7154<=g&&g<=7155||7204<=g&&g<=7211||7220<=g&&g<=7221||g==7393||7410<=g&&g<=7411||g==7415||43043<=g&&g<=43044||g==43047||43136<=g&&g<=43137||43188<=g&&g<=43203||43346<=g&&g<=43347||g==43395||43444<=g&&g<=43445||43450<=g&&g<=43451||43453<=g&&g<=43456||43567<=g&&g<=43568||43571<=g&&g<=43572||g==43597||g==43755||43758<=g&&g<=43759||g==43765||44003<=g&&g<=44004||44006<=g&&g<=44007||44009<=g&&g<=44010||g==44012||g==69632||g==69634||g==69762||69808<=g&&g<=69810||69815<=g&&g<=69816||g==69932||g==70018||70067<=g&&g<=70069||70079<=g&&g<=70080||70188<=g&&g<=70190||70194<=g&&g<=70195||g==70197||70368<=g&&g<=70370||70402<=g&&g<=70403||g==70463||70465<=g&&g<=70468||70471<=g&&g<=70472||70475<=g&&g<=70477||70498<=g&&g<=70499||70709<=g&&g<=70711||70720<=g&&g<=70721||g==70725||70833<=g&&g<=70834||g==70841||70843<=g&&g<=70844||g==70846||g==70849||71088<=g&&g<=71089||71096<=g&&g<=71099||g==71102||71216<=g&&g<=71218||71227<=g&&g<=71228||g==71230||g==71340||71342<=g&&g<=71343||g==71350||71456<=g&&g<=71457||g==71462||72199<=g&&g<=72200||g==72249||72279<=g&&g<=72280||g==72343||g==72751||g==72766||g==72873||g==72881||g==72884||94033<=g&&g<=94078||g==119142||g==119149?n:4352<=g&&g<=4447||43360<=g&&g<=43388?u:4448<=g&&g<=4519||55216<=g&&g<=55238?A:4520<=g&&g<=4607||55243<=g&&g<=55291?p:g==44032||g==44060||g==44088||g==44116||g==44144||g==44172||g==44200||g==44228||g==44256||g==44284||g==44312||g==44340||g==44368||g==44396||g==44424||g==44452||g==44480||g==44508||g==44536||g==44564||g==44592||g==44620||g==44648||g==44676||g==44704||g==44732||g==44760||g==44788||g==44816||g==44844||g==44872||g==44900||g==44928||g==44956||g==44984||g==45012||g==45040||g==45068||g==45096||g==45124||g==45152||g==45180||g==45208||g==45236||g==45264||g==45292||g==45320||g==45348||g==45376||g==45404||g==45432||g==45460||g==45488||g==45516||g==45544||g==45572||g==45600||g==45628||g==45656||g==45684||g==45712||g==45740||g==45768||g==45796||g==45824||g==45852||g==45880||g==45908||g==45936||g==45964||g==45992||g==46020||g==46048||g==46076||g==46104||g==46132||g==46160||g==46188||g==46216||g==46244||g==46272||g==46300||g==46328||g==46356||g==46384||g==46412||g==46440||g==46468||g==46496||g==46524||g==46552||g==46580||g==46608||g==46636||g==46664||g==46692||g==46720||g==46748||g==46776||g==46804||g==46832||g==46860||g==46888||g==46916||g==46944||g==46972||g==47e3||g==47028||g==47056||g==47084||g==47112||g==47140||g==47168||g==47196||g==47224||g==47252||g==47280||g==47308||g==47336||g==47364||g==47392||g==47420||g==47448||g==47476||g==47504||g==47532||g==47560||g==47588||g==47616||g==47644||g==47672||g==47700||g==47728||g==47756||g==47784||g==47812||g==47840||g==47868||g==47896||g==47924||g==47952||g==47980||g==48008||g==48036||g==48064||g==48092||g==48120||g==48148||g==48176||g==48204||g==48232||g==48260||g==48288||g==48316||g==48344||g==48372||g==48400||g==48428||g==48456||g==48484||g==48512||g==48540||g==48568||g==48596||g==48624||g==48652||g==48680||g==48708||g==48736||g==48764||g==48792||g==48820||g==48848||g==48876||g==48904||g==48932||g==48960||g==48988||g==49016||g==49044||g==49072||g==49100||g==49128||g==49156||g==49184||g==49212||g==49240||g==49268||g==49296||g==49324||g==49352||g==49380||g==49408||g==49436||g==49464||g==49492||g==49520||g==49548||g==49576||g==49604||g==49632||g==49660||g==49688||g==49716||g==49744||g==49772||g==49800||g==49828||g==49856||g==49884||g==49912||g==49940||g==49968||g==49996||g==50024||g==50052||g==50080||g==50108||g==50136||g==50164||g==50192||g==50220||g==50248||g==50276||g==50304||g==50332||g==50360||g==50388||g==50416||g==50444||g==50472||g==50500||g==50528||g==50556||g==50584||g==50612||g==50640||g==50668||g==50696||g==50724||g==50752||g==50780||g==50808||g==50836||g==50864||g==50892||g==50920||g==50948||g==50976||g==51004||g==51032||g==51060||g==51088||g==51116||g==51144||g==51172||g==51200||g==51228||g==51256||g==51284||g==51312||g==51340||g==51368||g==51396||g==51424||g==51452||g==51480||g==51508||g==51536||g==51564||g==51592||g==51620||g==51648||g==51676||g==51704||g==51732||g==51760||g==51788||g==51816||g==51844||g==51872||g==51900||g==51928||g==51956||g==51984||g==52012||g==52040||g==52068||g==52096||g==52124||g==52152||g==52180||g==52208||g==52236||g==52264||g==52292||g==52320||g==52348||g==52376||g==52404||g==52432||g==52460||g==52488||g==52516||g==52544||g==52572||g==52600||g==52628||g==52656||g==52684||g==52712||g==52740||g==52768||g==52796||g==52824||g==52852||g==52880||g==52908||g==52936||g==52964||g==52992||g==53020||g==53048||g==53076||g==53104||g==53132||g==53160||g==53188||g==53216||g==53244||g==53272||g==53300||g==53328||g==53356||g==53384||g==53412||g==53440||g==53468||g==53496||g==53524||g==53552||g==53580||g==53608||g==53636||g==53664||g==53692||g==53720||g==53748||g==53776||g==53804||g==53832||g==53860||g==53888||g==53916||g==53944||g==53972||g==54e3||g==54028||g==54056||g==54084||g==54112||g==54140||g==54168||g==54196||g==54224||g==54252||g==54280||g==54308||g==54336||g==54364||g==54392||g==54420||g==54448||g==54476||g==54504||g==54532||g==54560||g==54588||g==54616||g==54644||g==54672||g==54700||g==54728||g==54756||g==54784||g==54812||g==54840||g==54868||g==54896||g==54924||g==54952||g==54980||g==55008||g==55036||g==55064||g==55092||g==55120||g==55148||g==55176?h:44033<=g&&g<=44059||44061<=g&&g<=44087||44089<=g&&g<=44115||44117<=g&&g<=44143||44145<=g&&g<=44171||44173<=g&&g<=44199||44201<=g&&g<=44227||44229<=g&&g<=44255||44257<=g&&g<=44283||44285<=g&&g<=44311||44313<=g&&g<=44339||44341<=g&&g<=44367||44369<=g&&g<=44395||44397<=g&&g<=44423||44425<=g&&g<=44451||44453<=g&&g<=44479||44481<=g&&g<=44507||44509<=g&&g<=44535||44537<=g&&g<=44563||44565<=g&&g<=44591||44593<=g&&g<=44619||44621<=g&&g<=44647||44649<=g&&g<=44675||44677<=g&&g<=44703||44705<=g&&g<=44731||44733<=g&&g<=44759||44761<=g&&g<=44787||44789<=g&&g<=44815||44817<=g&&g<=44843||44845<=g&&g<=44871||44873<=g&&g<=44899||44901<=g&&g<=44927||44929<=g&&g<=44955||44957<=g&&g<=44983||44985<=g&&g<=45011||45013<=g&&g<=45039||45041<=g&&g<=45067||45069<=g&&g<=45095||45097<=g&&g<=45123||45125<=g&&g<=45151||45153<=g&&g<=45179||45181<=g&&g<=45207||45209<=g&&g<=45235||45237<=g&&g<=45263||45265<=g&&g<=45291||45293<=g&&g<=45319||45321<=g&&g<=45347||45349<=g&&g<=45375||45377<=g&&g<=45403||45405<=g&&g<=45431||45433<=g&&g<=45459||45461<=g&&g<=45487||45489<=g&&g<=45515||45517<=g&&g<=45543||45545<=g&&g<=45571||45573<=g&&g<=45599||45601<=g&&g<=45627||45629<=g&&g<=45655||45657<=g&&g<=45683||45685<=g&&g<=45711||45713<=g&&g<=45739||45741<=g&&g<=45767||45769<=g&&g<=45795||45797<=g&&g<=45823||45825<=g&&g<=45851||45853<=g&&g<=45879||45881<=g&&g<=45907||45909<=g&&g<=45935||45937<=g&&g<=45963||45965<=g&&g<=45991||45993<=g&&g<=46019||46021<=g&&g<=46047||46049<=g&&g<=46075||46077<=g&&g<=46103||46105<=g&&g<=46131||46133<=g&&g<=46159||46161<=g&&g<=46187||46189<=g&&g<=46215||46217<=g&&g<=46243||46245<=g&&g<=46271||46273<=g&&g<=46299||46301<=g&&g<=46327||46329<=g&&g<=46355||46357<=g&&g<=46383||46385<=g&&g<=46411||46413<=g&&g<=46439||46441<=g&&g<=46467||46469<=g&&g<=46495||46497<=g&&g<=46523||46525<=g&&g<=46551||46553<=g&&g<=46579||46581<=g&&g<=46607||46609<=g&&g<=46635||46637<=g&&g<=46663||46665<=g&&g<=46691||46693<=g&&g<=46719||46721<=g&&g<=46747||46749<=g&&g<=46775||46777<=g&&g<=46803||46805<=g&&g<=46831||46833<=g&&g<=46859||46861<=g&&g<=46887||46889<=g&&g<=46915||46917<=g&&g<=46943||46945<=g&&g<=46971||46973<=g&&g<=46999||47001<=g&&g<=47027||47029<=g&&g<=47055||47057<=g&&g<=47083||47085<=g&&g<=47111||47113<=g&&g<=47139||47141<=g&&g<=47167||47169<=g&&g<=47195||47197<=g&&g<=47223||47225<=g&&g<=47251||47253<=g&&g<=47279||47281<=g&&g<=47307||47309<=g&&g<=47335||47337<=g&&g<=47363||47365<=g&&g<=47391||47393<=g&&g<=47419||47421<=g&&g<=47447||47449<=g&&g<=47475||47477<=g&&g<=47503||47505<=g&&g<=47531||47533<=g&&g<=47559||47561<=g&&g<=47587||47589<=g&&g<=47615||47617<=g&&g<=47643||47645<=g&&g<=47671||47673<=g&&g<=47699||47701<=g&&g<=47727||47729<=g&&g<=47755||47757<=g&&g<=47783||47785<=g&&g<=47811||47813<=g&&g<=47839||47841<=g&&g<=47867||47869<=g&&g<=47895||47897<=g&&g<=47923||47925<=g&&g<=47951||47953<=g&&g<=47979||47981<=g&&g<=48007||48009<=g&&g<=48035||48037<=g&&g<=48063||48065<=g&&g<=48091||48093<=g&&g<=48119||48121<=g&&g<=48147||48149<=g&&g<=48175||48177<=g&&g<=48203||48205<=g&&g<=48231||48233<=g&&g<=48259||48261<=g&&g<=48287||48289<=g&&g<=48315||48317<=g&&g<=48343||48345<=g&&g<=48371||48373<=g&&g<=48399||48401<=g&&g<=48427||48429<=g&&g<=48455||48457<=g&&g<=48483||48485<=g&&g<=48511||48513<=g&&g<=48539||48541<=g&&g<=48567||48569<=g&&g<=48595||48597<=g&&g<=48623||48625<=g&&g<=48651||48653<=g&&g<=48679||48681<=g&&g<=48707||48709<=g&&g<=48735||48737<=g&&g<=48763||48765<=g&&g<=48791||48793<=g&&g<=48819||48821<=g&&g<=48847||48849<=g&&g<=48875||48877<=g&&g<=48903||48905<=g&&g<=48931||48933<=g&&g<=48959||48961<=g&&g<=48987||48989<=g&&g<=49015||49017<=g&&g<=49043||49045<=g&&g<=49071||49073<=g&&g<=49099||49101<=g&&g<=49127||49129<=g&&g<=49155||49157<=g&&g<=49183||49185<=g&&g<=49211||49213<=g&&g<=49239||49241<=g&&g<=49267||49269<=g&&g<=49295||49297<=g&&g<=49323||49325<=g&&g<=49351||49353<=g&&g<=49379||49381<=g&&g<=49407||49409<=g&&g<=49435||49437<=g&&g<=49463||49465<=g&&g<=49491||49493<=g&&g<=49519||49521<=g&&g<=49547||49549<=g&&g<=49575||49577<=g&&g<=49603||49605<=g&&g<=49631||49633<=g&&g<=49659||49661<=g&&g<=49687||49689<=g&&g<=49715||49717<=g&&g<=49743||49745<=g&&g<=49771||49773<=g&&g<=49799||49801<=g&&g<=49827||49829<=g&&g<=49855||49857<=g&&g<=49883||49885<=g&&g<=49911||49913<=g&&g<=49939||49941<=g&&g<=49967||49969<=g&&g<=49995||49997<=g&&g<=50023||50025<=g&&g<=50051||50053<=g&&g<=50079||50081<=g&&g<=50107||50109<=g&&g<=50135||50137<=g&&g<=50163||50165<=g&&g<=50191||50193<=g&&g<=50219||50221<=g&&g<=50247||50249<=g&&g<=50275||50277<=g&&g<=50303||50305<=g&&g<=50331||50333<=g&&g<=50359||50361<=g&&g<=50387||50389<=g&&g<=50415||50417<=g&&g<=50443||50445<=g&&g<=50471||50473<=g&&g<=50499||50501<=g&&g<=50527||50529<=g&&g<=50555||50557<=g&&g<=50583||50585<=g&&g<=50611||50613<=g&&g<=50639||50641<=g&&g<=50667||50669<=g&&g<=50695||50697<=g&&g<=50723||50725<=g&&g<=50751||50753<=g&&g<=50779||50781<=g&&g<=50807||50809<=g&&g<=50835||50837<=g&&g<=50863||50865<=g&&g<=50891||50893<=g&&g<=50919||50921<=g&&g<=50947||50949<=g&&g<=50975||50977<=g&&g<=51003||51005<=g&&g<=51031||51033<=g&&g<=51059||51061<=g&&g<=51087||51089<=g&&g<=51115||51117<=g&&g<=51143||51145<=g&&g<=51171||51173<=g&&g<=51199||51201<=g&&g<=51227||51229<=g&&g<=51255||51257<=g&&g<=51283||51285<=g&&g<=51311||51313<=g&&g<=51339||51341<=g&&g<=51367||51369<=g&&g<=51395||51397<=g&&g<=51423||51425<=g&&g<=51451||51453<=g&&g<=51479||51481<=g&&g<=51507||51509<=g&&g<=51535||51537<=g&&g<=51563||51565<=g&&g<=51591||51593<=g&&g<=51619||51621<=g&&g<=51647||51649<=g&&g<=51675||51677<=g&&g<=51703||51705<=g&&g<=51731||51733<=g&&g<=51759||51761<=g&&g<=51787||51789<=g&&g<=51815||51817<=g&&g<=51843||51845<=g&&g<=51871||51873<=g&&g<=51899||51901<=g&&g<=51927||51929<=g&&g<=51955||51957<=g&&g<=51983||51985<=g&&g<=52011||52013<=g&&g<=52039||52041<=g&&g<=52067||52069<=g&&g<=52095||52097<=g&&g<=52123||52125<=g&&g<=52151||52153<=g&&g<=52179||52181<=g&&g<=52207||52209<=g&&g<=52235||52237<=g&&g<=52263||52265<=g&&g<=52291||52293<=g&&g<=52319||52321<=g&&g<=52347||52349<=g&&g<=52375||52377<=g&&g<=52403||52405<=g&&g<=52431||52433<=g&&g<=52459||52461<=g&&g<=52487||52489<=g&&g<=52515||52517<=g&&g<=52543||52545<=g&&g<=52571||52573<=g&&g<=52599||52601<=g&&g<=52627||52629<=g&&g<=52655||52657<=g&&g<=52683||52685<=g&&g<=52711||52713<=g&&g<=52739||52741<=g&&g<=52767||52769<=g&&g<=52795||52797<=g&&g<=52823||52825<=g&&g<=52851||52853<=g&&g<=52879||52881<=g&&g<=52907||52909<=g&&g<=52935||52937<=g&&g<=52963||52965<=g&&g<=52991||52993<=g&&g<=53019||53021<=g&&g<=53047||53049<=g&&g<=53075||53077<=g&&g<=53103||53105<=g&&g<=53131||53133<=g&&g<=53159||53161<=g&&g<=53187||53189<=g&&g<=53215||53217<=g&&g<=53243||53245<=g&&g<=53271||53273<=g&&g<=53299||53301<=g&&g<=53327||53329<=g&&g<=53355||53357<=g&&g<=53383||53385<=g&&g<=53411||53413<=g&&g<=53439||53441<=g&&g<=53467||53469<=g&&g<=53495||53497<=g&&g<=53523||53525<=g&&g<=53551||53553<=g&&g<=53579||53581<=g&&g<=53607||53609<=g&&g<=53635||53637<=g&&g<=53663||53665<=g&&g<=53691||53693<=g&&g<=53719||53721<=g&&g<=53747||53749<=g&&g<=53775||53777<=g&&g<=53803||53805<=g&&g<=53831||53833<=g&&g<=53859||53861<=g&&g<=53887||53889<=g&&g<=53915||53917<=g&&g<=53943||53945<=g&&g<=53971||53973<=g&&g<=53999||54001<=g&&g<=54027||54029<=g&&g<=54055||54057<=g&&g<=54083||54085<=g&&g<=54111||54113<=g&&g<=54139||54141<=g&&g<=54167||54169<=g&&g<=54195||54197<=g&&g<=54223||54225<=g&&g<=54251||54253<=g&&g<=54279||54281<=g&&g<=54307||54309<=g&&g<=54335||54337<=g&&g<=54363||54365<=g&&g<=54391||54393<=g&&g<=54419||54421<=g&&g<=54447||54449<=g&&g<=54475||54477<=g&&g<=54503||54505<=g&&g<=54531||54533<=g&&g<=54559||54561<=g&&g<=54587||54589<=g&&g<=54615||54617<=g&&g<=54643||54645<=g&&g<=54671||54673<=g&&g<=54699||54701<=g&&g<=54727||54729<=g&&g<=54755||54757<=g&&g<=54783||54785<=g&&g<=54811||54813<=g&&g<=54839||54841<=g&&g<=54867||54869<=g&&g<=54895||54897<=g&&g<=54923||54925<=g&&g<=54951||54953<=g&&g<=54979||54981<=g&&g<=55007||55009<=g&&g<=55035||55037<=g&&g<=55063||55065<=g&&g<=55091||55093<=g&&g<=55119||55121<=g&&g<=55147||55149<=g&&g<=55175||55177<=g&&g<=55203?E:g==9757||g==9977||9994<=g&&g<=9997||g==127877||127938<=g&&g<=127940||g==127943||127946<=g&&g<=127948||128066<=g&&g<=128067||128070<=g&&g<=128080||g==128110||128112<=g&&g<=128120||g==128124||128129<=g&&g<=128131||128133<=g&&g<=128135||g==128170||128372<=g&&g<=128373||g==128378||g==128400||128405<=g&&g<=128406||128581<=g&&g<=128583||128587<=g&&g<=128591||g==128675||128692<=g&&g<=128694||g==128704||g==128716||129304<=g&&g<=129308||129310<=g&&g<=129311||g==129318||129328<=g&&g<=129337||129341<=g&&g<=129342||129489<=g&&g<=129501?x:127995<=g&&g<=127999?C:g==8205?R:g==9792||g==9794||9877<=g&&g<=9878||g==9992||g==10084||g==127752||g==127806||g==127859||g==127891||g==127908||g==127912||g==127979||g==127981||g==128139||128187<=g&&g<=128188||g==128295||g==128300||g==128488||g==128640||g==128658?N:128102<=g&&g<=128105?U:I}return this}typeof qb<"u"&&qb.exports&&(qb.exports=hat)});var Gce=_((d4t,qce)=>{var gat=/^(.*?)(\x1b\[[^m]+m|\x1b\]8;;.*?(\x1b\\|\u0007))/,Gb;function dat(){if(Gb)return Gb;if(typeof Intl.Segmenter<"u"){let t=new Intl.Segmenter("en",{granularity:"grapheme"});return Gb=e=>Array.from(t.segment(e),({segment:r})=>r)}else{let t=Hce(),e=new t;return Gb=r=>e.splitGraphemes(r)}}qce.exports=(t,e=0,r=t.length)=>{if(e<0||r<0)throw new RangeError("Negative indices aren't supported by this implementation");let o=r-e,a="",n=0,u=0;for(;t.length>0;){let A=t.match(gat)||[t,t,void 0],p=dat()(A[1]),h=Math.min(e-n,p.length);p=p.slice(h);let E=Math.min(o-u,p.length);a+=p.slice(0,E).join(""),n+=h,u+=E,typeof A[2]<"u"&&(a+=A[2]),t=t.slice(A[0].length)}return a}});var rn,N1=Et(()=>{rn=process.env.YARN_IS_TEST_ENV?"0.0.0":"4.2.2"});function Vce(t,{configuration:e,json:r}){if(!e.get("enableMessageNames"))return"";let a=Ku(t===null?0:t);return!r&&t===null?Ut(e,a,"grey"):a}function yU(t,{configuration:e,json:r}){let o=Vce(t,{configuration:e,json:r});if(!o||t===null||t===0)return o;let a=wr[t],n=`https://yarnpkg.com/advanced/error-codes#${o}---${a}`.toLowerCase();return Zy(e,o,n)}async function NE({configuration:t,stdout:e,forceError:r},o){let a=await Lt.start({configuration:t,stdout:e,includeFooter:!1},async n=>{let u=!1,A=!1;for(let p of o)typeof p.option<"u"&&(p.error||r?(A=!0,n.reportError(50,p.message)):(u=!0,n.reportWarning(50,p.message)),p.callback?.());u&&!A&&n.reportSeparator()});return a.hasErrors()?a.exitCode():null}var Kce,jb,mat,jce,Yce,fh,zce,Wce,yat,Eat,Yb,Cat,Lt,O1=Et(()=>{Kce=$e(Gce()),jb=$e(rd());fP();Wl();N1();jl();mat="\xB7",jce=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],Yce=80,fh=jb.default.GITHUB_ACTIONS?{start:t=>`::group::${t}
-`,end:t=>`::endgroup::
-`}:jb.default.TRAVIS?{start:t=>`travis_fold:start:${t}
-`,end:t=>`travis_fold:end:${t}
-`}:jb.default.GITLAB?{start:t=>`section_start:${Math.floor(Date.now()/1e3)}:${t.toLowerCase().replace(/\W+/g,"_")}[collapsed=true]\r\x1B[0K${t}
-`,end:t=>`section_end:${Math.floor(Date.now()/1e3)}:${t.toLowerCase().replace(/\W+/g,"_")}\r\x1B[0K`}:null,zce=fh!==null,Wce=new Date,yat=["iTerm.app","Apple_Terminal","WarpTerminal","vscode"].includes(process.env.TERM_PROGRAM)||!!process.env.WT_SESSION,Eat=t=>t,Yb=Eat({patrick:{date:[17,3],chars:["\u{1F340}","\u{1F331}"],size:40},simba:{date:[19,7],chars:["\u{1F981}","\u{1F334}"],size:40},jack:{date:[31,10],chars:["\u{1F383}","\u{1F987}"],size:40},hogsfather:{date:[31,12],chars:["\u{1F389}","\u{1F384}"],size:40},default:{chars:["=","-"],size:80}}),Cat=yat&&Object.keys(Yb).find(t=>{let e=Yb[t];return!(e.date&&(e.date[0]!==Wce.getDate()||e.date[1]!==Wce.getMonth()+1))})||"default";Lt=class extends Xs{constructor({configuration:r,stdout:o,json:a=!1,forceSectionAlignment:n=!1,includeNames:u=!0,includePrefix:A=!0,includeFooter:p=!0,includeLogs:h=!a,includeInfos:E=h,includeWarnings:I=h}){super();this.uncommitted=new Set;this.warningCount=0;this.errorCount=0;this.timerFooter=[];this.startTime=Date.now();this.indent=0;this.level=0;this.progress=new Map;this.progressTime=0;this.progressFrame=0;this.progressTimeout=null;this.progressStyle=null;this.progressMaxScaledSize=null;if(XI(this,{configuration:r}),this.configuration=r,this.forceSectionAlignment=n,this.includeNames=u,this.includePrefix=A,this.includeFooter=p,this.includeInfos=E,this.includeWarnings=I,this.json=a,this.stdout=o,r.get("enableProgressBars")&&!a&&o.isTTY&&o.columns>22){let v=r.get("progressBarStyle")||Cat;if(!Object.hasOwn(Yb,v))throw new Error("Assertion failed: Invalid progress bar style");this.progressStyle=Yb[v];let x=Math.min(this.getRecommendedLength(),80);this.progressMaxScaledSize=Math.floor(this.progressStyle.size*x/80)}}static async start(r,o){let a=new this(r),n=process.emitWarning;process.emitWarning=(u,A)=>{if(typeof u!="string"){let h=u;u=h.message,A=A??h.name}let p=typeof A<"u"?`${A}: ${u}`:u;a.reportWarning(0,p)},r.includeVersion&&a.reportInfo(0,Ed(r.configuration,`Yarn ${rn}`,2));try{await o(a)}catch(u){a.reportExceptionOnce(u)}finally{await a.finalize(),process.emitWarning=n}return a}hasErrors(){return this.errorCount>0}exitCode(){return this.hasErrors()?1:0}getRecommendedLength(){let o=this.progressStyle!==null?this.stdout.columns-1:super.getRecommendedLength();return Math.max(40,o-12-this.indent*2)}startSectionSync({reportHeader:r,reportFooter:o,skipIfEmpty:a},n){let u={committed:!1,action:()=>{r?.()}};a?this.uncommitted.add(u):(u.action(),u.committed=!0);let A=Date.now();try{return n()}catch(p){throw this.reportExceptionOnce(p),p}finally{let p=Date.now();this.uncommitted.delete(u),u.committed&&o?.(p-A)}}async startSectionPromise({reportHeader:r,reportFooter:o,skipIfEmpty:a},n){let u={committed:!1,action:()=>{r?.()}};a?this.uncommitted.add(u):(u.action(),u.committed=!0);let A=Date.now();try{return await n()}catch(p){throw this.reportExceptionOnce(p),p}finally{let p=Date.now();this.uncommitted.delete(u),u.committed&&o?.(p-A)}}startTimerImpl(r,o,a){return{cb:typeof o=="function"?o:a,reportHeader:()=>{this.level+=1,this.reportInfo(null,`\u250C ${r}`),this.indent+=1,fh!==null&&!this.json&&this.includeInfos&&this.stdout.write(fh.start(r))},reportFooter:A=>{if(this.indent-=1,fh!==null&&!this.json&&this.includeInfos){this.stdout.write(fh.end(r));for(let p of this.timerFooter)p()}this.configuration.get("enableTimers")&&A>200?this.reportInfo(null,`\u2514 Completed in ${Ut(this.configuration,A,yt.DURATION)}`):this.reportInfo(null,"\u2514 Completed"),this.level-=1},skipIfEmpty:(typeof o=="function"?{}:o).skipIfEmpty}}startTimerSync(r,o,a){let{cb:n,...u}=this.startTimerImpl(r,o,a);return this.startSectionSync(u,n)}async startTimerPromise(r,o,a){let{cb:n,...u}=this.startTimerImpl(r,o,a);return this.startSectionPromise(u,n)}reportSeparator(){this.indent===0?this.writeLine(""):this.reportInfo(null,"")}reportInfo(r,o){if(!this.includeInfos)return;this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:"",u=`${this.formatPrefix(n,"blueBright")}${o}`;this.json?this.reportJson({type:"info",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:o}):this.writeLine(u)}reportWarning(r,o){if(this.warningCount+=1,!this.includeWarnings)return;this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:"";this.json?this.reportJson({type:"warning",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:o}):this.writeLine(`${this.formatPrefix(n,"yellowBright")}${o}`)}reportError(r,o){this.errorCount+=1,this.timerFooter.push(()=>this.reportErrorImpl(r,o)),this.reportErrorImpl(r,o)}reportErrorImpl(r,o){this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:"";this.json?this.reportJson({type:"error",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:o}):this.writeLine(`${this.formatPrefix(n,"redBright")}${o}`,{truncate:!1})}reportFold(r,o){if(!fh)return;let a=`${fh.start(r)}${o}${fh.end(r)}`;this.timerFooter.push(()=>this.stdout.write(a))}reportProgress(r){if(this.progressStyle===null)return{...Promise.resolve(),stop:()=>{}};if(r.hasProgress&&r.hasTitle)throw new Error("Unimplemented: Progress bars can't have both progress and titles.");let o=!1,a=Promise.resolve().then(async()=>{let u={progress:r.hasProgress?0:void 0,title:r.hasTitle?"":void 0};this.progress.set(r,{definition:u,lastScaledSize:r.hasProgress?-1:void 0,lastTitle:void 0}),this.refreshProgress({delta:-1});for await(let{progress:A,title:p}of r)o||u.progress===A&&u.title===p||(u.progress=A,u.title=p,this.refreshProgress());n()}),n=()=>{o||(o=!0,this.progress.delete(r),this.refreshProgress({delta:1}))};return{...a,stop:n}}reportJson(r){this.json&&this.writeLine(`${JSON.stringify(r)}`)}async finalize(){if(!this.includeFooter)return;let r="";this.errorCount>0?r="Failed with errors":this.warningCount>0?r="Done with warnings":r="Done";let o=Ut(this.configuration,Date.now()-this.startTime,yt.DURATION),a=this.configuration.get("enableTimers")?`${r} in ${o}`:r;this.errorCount>0?this.reportError(0,a):this.warningCount>0?this.reportWarning(0,a):this.reportInfo(0,a)}writeLine(r,{truncate:o}={}){this.clearProgress({clear:!0}),this.stdout.write(`${this.truncate(r,{truncate:o})}
-`),this.writeProgress()}writeLines(r,{truncate:o}={}){this.clearProgress({delta:r.length});for(let a of r)this.stdout.write(`${this.truncate(a,{truncate:o})}
-`);this.writeProgress()}commit(){let r=this.uncommitted;this.uncommitted=new Set;for(let o of r)o.committed=!0,o.action()}clearProgress({delta:r=0,clear:o=!1}){this.progressStyle!==null&&this.progress.size+r>0&&(this.stdout.write(`\x1B[${this.progress.size+r}A`),(r>0||o)&&this.stdout.write("\x1B[0J"))}writeProgress(){if(this.progressStyle===null||(this.progressTimeout!==null&&clearTimeout(this.progressTimeout),this.progressTimeout=null,this.progress.size===0))return;let r=Date.now();r-this.progressTime>Yce&&(this.progressFrame=(this.progressFrame+1)%jce.length,this.progressTime=r);let o=jce[this.progressFrame];for(let a of this.progress.values()){let n="";if(typeof a.lastScaledSize<"u"){let h=this.progressStyle.chars[0].repeat(a.lastScaledSize),E=this.progressStyle.chars[1].repeat(this.progressMaxScaledSize-a.lastScaledSize);n=` ${h}${E}`}let u=this.formatName(null),A=u?`${u}: `:"",p=a.definition.title?` ${a.definition.title}`:"";this.stdout.write(`${Ut(this.configuration,"\u27A4","blueBright")} ${A}${o}${n}${p}
-`)}this.progressTimeout=setTimeout(()=>{this.refreshProgress({force:!0})},Yce)}refreshProgress({delta:r=0,force:o=!1}={}){let a=!1,n=!1;if(o||this.progress.size===0)a=!0;else for(let u of this.progress.values()){let A=typeof u.definition.progress<"u"?Math.trunc(this.progressMaxScaledSize*u.definition.progress):void 0,p=u.lastScaledSize;u.lastScaledSize=A;let h=u.lastTitle;if(u.lastTitle=u.definition.title,A!==p||(n=h!==u.definition.title)){a=!0;break}}a&&(this.clearProgress({delta:r,clear:n}),this.writeProgress())}truncate(r,{truncate:o}={}){return this.progressStyle===null&&(o=!1),typeof o>"u"&&(o=this.configuration.get("preferTruncatedLines")),o&&(r=(0,Kce.default)(r,0,this.stdout.columns-1)),r}formatName(r){return this.includeNames?Vce(r,{configuration:this.configuration,json:this.json}):""}formatPrefix(r,o){return this.includePrefix?`${Ut(this.configuration,"\u27A4",o)} ${r}${this.formatIndent()}`:""}formatNameWithHyperlink(r){return this.includeNames?yU(r,{configuration:this.configuration,json:this.json}):""}formatIndent(){return this.level>0||!this.forceSectionAlignment?"\u2502 ".repeat(this.indent):`${mat} `}}});var un={};zt(un,{PackageManager:()=>Zce,detectPackageManager:()=>$ce,executePackageAccessibleBinary:()=>iue,executePackageScript:()=>Wb,executePackageShellcode:()=>EU,executeWorkspaceAccessibleBinary:()=>Sat,executeWorkspaceLifecycleScript:()=>rue,executeWorkspaceScript:()=>tue,getPackageAccessibleBinaries:()=>Kb,getWorkspaceAccessibleBinaries:()=>nue,hasPackageScript:()=>vat,hasWorkspaceScript:()=>CU,isNodeScript:()=>wU,makeScriptEnv:()=>M1,maybeExecuteWorkspaceLifecycleScript:()=>Pat,prepareExternalProject:()=>Bat});async function ph(t,e,r,o=[]){if(process.platform==="win32"){let a=`@goto #_undefined_# 2>NUL || @title %COMSPEC% & @setlocal & @"${r}" ${o.map(n=>`"${n.replace('"','""')}"`).join(" ")} %*`;await oe.writeFilePromise(z.format({dir:t,name:e,ext:".cmd"}),a)}await oe.writeFilePromise(z.join(t,e),`#!/bin/sh
-exec "${r}" ${o.map(a=>`'${a.replace(/'/g,`'"'"'`)}'`).join(" ")} "$@"
-`,{mode:493})}async function $ce(t){let e=await Ot.tryFind(t);if(e?.packageManager){let o=US(e.packageManager);if(o?.name){let a=`found ${JSON.stringify({packageManager:e.packageManager})} in manifest`,[n]=o.reference.split(".");switch(o.name){case"yarn":return{packageManagerField:!0,packageManager:Number(n)===1?"Yarn Classic":"Yarn",reason:a};case"npm":return{packageManagerField:!0,packageManager:"npm",reason:a};case"pnpm":return{packageManagerField:!0,packageManager:"pnpm",reason:a}}}}let r;try{r=await oe.readFilePromise(z.join(t,dr.lockfile),"utf8")}catch{}return r!==void 0?r.match(/^__metadata:$/m)?{packageManager:"Yarn",reason:'"__metadata" key found in yarn.lock'}:{packageManager:"Yarn Classic",reason:'"__metadata" key not found in yarn.lock, must be a Yarn classic lockfile'}:oe.existsSync(z.join(t,"package-lock.json"))?{packageManager:"npm",reason:`found npm's "package-lock.json" lockfile`}:oe.existsSync(z.join(t,"pnpm-lock.yaml"))?{packageManager:"pnpm",reason:`found pnpm's "pnpm-lock.yaml" lockfile`}:null}async function M1({project:t,locator:e,binFolder:r,ignoreCorepack:o,lifecycleScript:a,baseEnv:n=t?.configuration.env??process.env}){let u={};for(let[E,I]of Object.entries(n))typeof I<"u"&&(u[E.toLowerCase()!=="path"?E:"PATH"]=I);let A=le.fromPortablePath(r);u.BERRY_BIN_FOLDER=le.fromPortablePath(A);let p=process.env.COREPACK_ROOT&&!o?le.join(process.env.COREPACK_ROOT,"dist/yarn.js"):process.argv[1];if(await Promise.all([ph(r,"node",process.execPath),...rn!==null?[ph(r,"run",process.execPath,[p,"run"]),ph(r,"yarn",process.execPath,[p]),ph(r,"yarnpkg",process.execPath,[p]),ph(r,"node-gyp",process.execPath,[p,"run","--top-level","node-gyp"])]:[]]),t&&(u.INIT_CWD=le.fromPortablePath(t.configuration.startingCwd),u.PROJECT_CWD=le.fromPortablePath(t.cwd)),u.PATH=u.PATH?`${A}${le.delimiter}${u.PATH}`:`${A}`,u.npm_execpath=`${A}${le.sep}yarn`,u.npm_node_execpath=`${A}${le.sep}node`,e){if(!t)throw new Error("Assertion failed: Missing project");let E=t.tryWorkspaceByLocator(e),I=E?E.manifest.version??"":t.storedPackages.get(e.locatorHash).version??"";u.npm_package_name=fn(e),u.npm_package_version=I;let v;if(E)v=E.cwd;else{let x=t.storedPackages.get(e.locatorHash);if(!x)throw new Error(`Package for ${qr(t.configuration,e)} not found in the project`);let C=t.configuration.getLinkers(),R={project:t,report:new Lt({stdout:new hh.PassThrough,configuration:t.configuration})},N=C.find(U=>U.supportsPackage(x,R));if(!N)throw new Error(`The package ${qr(t.configuration,x)} isn't supported by any of the available linkers`);v=await N.findPackageLocation(x,R)}u.npm_package_json=le.fromPortablePath(z.join(v,dr.manifest))}let h=rn!==null?`yarn/${rn}`:`yarn/${Df("@yarnpkg/core").version}-core`;return u.npm_config_user_agent=`${h} npm/? node/${process.version} ${process.platform} ${process.arch}`,a&&(u.npm_lifecycle_event=a),t&&await t.configuration.triggerHook(E=>E.setupScriptEnvironment,t,u,async(E,I,v)=>await ph(r,E,I,v)),u}async function Bat(t,e,{configuration:r,report:o,workspace:a=null,locator:n=null}){await Iat(async()=>{await oe.mktempPromise(async u=>{let A=z.join(u,"pack.log"),p=null,{stdout:h,stderr:E}=r.getSubprocessStreams(A,{prefix:le.fromPortablePath(t),report:o}),I=n&&qc(n)?r1(n):n,v=I?ba(I):"an external project";h.write(`Packing ${v} from sources
-`);let x=await $ce(t),C;x!==null?(h.write(`Using ${x.packageManager} for bootstrap. Reason: ${x.reason}
-
-`),C=x.packageManager):(h.write(`No package manager configuration detected; defaulting to Yarn
-
-`),C="Yarn");let R=C==="Yarn"&&!x?.packageManagerField;await oe.mktempPromise(async N=>{let U=await M1({binFolder:N,ignoreCorepack:R}),te=new Map([["Yarn Classic",async()=>{let fe=a!==null?["workspace",a]:[],ue=z.join(t,dr.manifest),me=await oe.readFilePromise(ue),he=await Yc(process.execPath,[process.argv[1],"set","version","classic","--only-if-needed","--yarn-path"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(he.code!==0)return he.code;await oe.writeFilePromise(ue,me),await oe.appendFilePromise(z.join(t,".npmignore"),`/.yarn
-`),h.write(`
-`),delete U.NODE_ENV;let Be=await Yc("yarn",["install"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(Be.code!==0)return Be.code;h.write(`
-`);let we=await Yc("yarn",[...fe,"pack","--filename",le.fromPortablePath(e)],{cwd:t,env:U,stdin:p,stdout:h,stderr:E});return we.code!==0?we.code:0}],["Yarn",async()=>{let fe=a!==null?["workspace",a]:[];U.YARN_ENABLE_INLINE_BUILDS="1";let ue=z.join(t,dr.lockfile);await oe.existsPromise(ue)||await oe.writeFilePromise(ue,"");let me=await Yc("yarn",[...fe,"pack","--install-if-needed","--filename",le.fromPortablePath(e)],{cwd:t,env:U,stdin:p,stdout:h,stderr:E});return me.code!==0?me.code:0}],["npm",async()=>{if(a!==null){let Ee=new hh.PassThrough,Pe=zy(Ee);Ee.pipe(h,{end:!1});let ce=await Yc("npm",["--version"],{cwd:t,env:U,stdin:p,stdout:Ee,stderr:E,end:0});if(Ee.end(),ce.code!==0)return h.end(),E.end(),ce.code;let ne=(await Pe).toString().trim();if(!kf(ne,">=7.x")){let ee=tA(null,"npm"),Ie=In(ee,ne),Fe=In(ee,">=7.x");throw new Error(`Workspaces aren't supported by ${Gn(r,Ie)}; please upgrade to ${Gn(r,Fe)} (npm has been detected as the primary package manager for ${Ut(r,t,yt.PATH)})`)}}let fe=a!==null?["--workspace",a]:[];delete U.npm_config_user_agent,delete U.npm_config_production,delete U.NPM_CONFIG_PRODUCTION,delete U.NODE_ENV;let ue=await Yc("npm",["install","--legacy-peer-deps"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(ue.code!==0)return ue.code;let me=new hh.PassThrough,he=zy(me);me.pipe(h);let Be=await Yc("npm",["pack","--silent",...fe],{cwd:t,env:U,stdin:p,stdout:me,stderr:E});if(Be.code!==0)return Be.code;let we=(await he).toString().trim().replace(/^.*\n/s,""),g=z.resolve(t,le.toPortablePath(we));return await oe.renamePromise(g,e),0}]]).get(C);if(typeof te>"u")throw new Error("Assertion failed: Unsupported workflow");let ae=await te();if(!(ae===0||typeof ae>"u"))throw oe.detachTemp(u),new Jt(58,`Packing the package failed (exit code ${ae}, logs can be found here: ${Ut(r,A,yt.PATH)})`)})})})}async function vat(t,e,{project:r}){let o=r.tryWorkspaceByLocator(t);if(o!==null)return CU(o,e);let a=r.storedPackages.get(t.locatorHash);if(!a)throw new Error(`Package for ${qr(r.configuration,t)} not found in the project`);return await Jl.openPromise(async n=>{let u=r.configuration,A=r.configuration.getLinkers(),p={project:r,report:new Lt({stdout:new hh.PassThrough,configuration:u})},h=A.find(x=>x.supportsPackage(a,p));if(!h)throw new Error(`The package ${qr(r.configuration,a)} isn't supported by any of the available linkers`);let E=await h.findPackageLocation(a,p),I=new gn(E,{baseFs:n});return(await Ot.find(Bt.dot,{baseFs:I})).scripts.has(e)})}async function Wb(t,e,r,{cwd:o,project:a,stdin:n,stdout:u,stderr:A}){return await oe.mktempPromise(async p=>{let{manifest:h,env:E,cwd:I}=await eue(t,{project:a,binFolder:p,cwd:o,lifecycleScript:e}),v=h.scripts.get(e);if(typeof v>"u")return 1;let x=async()=>await TE(v,r,{cwd:I,env:E,stdin:n,stdout:u,stderr:A});return await(await a.configuration.reduceHook(R=>R.wrapScriptExecution,x,a,t,e,{script:v,args:r,cwd:I,env:E,stdin:n,stdout:u,stderr:A}))()})}async function EU(t,e,r,{cwd:o,project:a,stdin:n,stdout:u,stderr:A}){return await oe.mktempPromise(async p=>{let{env:h,cwd:E}=await eue(t,{project:a,binFolder:p,cwd:o});return await TE(e,r,{cwd:E,env:h,stdin:n,stdout:u,stderr:A})})}async function Dat(t,{binFolder:e,cwd:r,lifecycleScript:o}){let a=await M1({project:t.project,locator:t.anchoredLocator,binFolder:e,lifecycleScript:o});return await IU(e,await nue(t)),typeof r>"u"&&(r=z.dirname(await oe.realpathPromise(z.join(t.cwd,"package.json")))),{manifest:t.manifest,binFolder:e,env:a,cwd:r}}async function eue(t,{project:e,binFolder:r,cwd:o,lifecycleScript:a}){let n=e.tryWorkspaceByLocator(t);if(n!==null)return Dat(n,{binFolder:r,cwd:o,lifecycleScript:a});let u=e.storedPackages.get(t.locatorHash);if(!u)throw new Error(`Package for ${qr(e.configuration,t)} not found in the project`);return await Jl.openPromise(async A=>{let p=e.configuration,h=e.configuration.getLinkers(),E={project:e,report:new Lt({stdout:new hh.PassThrough,configuration:p})},I=h.find(N=>N.supportsPackage(u,E));if(!I)throw new Error(`The package ${qr(e.configuration,u)} isn't supported by any of the available linkers`);let v=await M1({project:e,locator:t,binFolder:r,lifecycleScript:a});await IU(r,await Kb(t,{project:e}));let x=await I.findPackageLocation(u,E),C=new gn(x,{baseFs:A}),R=await Ot.find(Bt.dot,{baseFs:C});return typeof o>"u"&&(o=x),{manifest:R,binFolder:r,env:v,cwd:o}})}async function tue(t,e,r,{cwd:o,stdin:a,stdout:n,stderr:u}){return await Wb(t.anchoredLocator,e,r,{cwd:o,project:t.project,stdin:a,stdout:n,stderr:u})}function CU(t,e){return t.manifest.scripts.has(e)}async function rue(t,e,{cwd:r,report:o}){let{configuration:a}=t.project,n=null;await oe.mktempPromise(async u=>{let A=z.join(u,`${e}.log`),p=`# This file contains the result of Yarn calling the "${e}" lifecycle script inside a workspace ("${le.fromPortablePath(t.cwd)}")
-`,{stdout:h,stderr:E}=a.getSubprocessStreams(A,{report:o,prefix:qr(a,t.anchoredLocator),header:p});o.reportInfo(36,`Calling the "${e}" lifecycle script`);let I=await tue(t,e,[],{cwd:r,stdin:n,stdout:h,stderr:E});if(h.end(),E.end(),I!==0)throw oe.detachTemp(u),new Jt(36,`${(0,Jce.default)(e)} script failed (exit code ${Ut(a,I,yt.NUMBER)}, logs can be found here: ${Ut(a,A,yt.PATH)}); run ${Ut(a,`yarn ${e}`,yt.CODE)} to investigate`)})}async function Pat(t,e,r){CU(t,e)&&await rue(t,e,r)}function wU(t){let e=z.extname(t);if(e.match(/\.[cm]?[jt]sx?$/))return!0;if(e===".exe"||e===".bin")return!1;let r=Buffer.alloc(4),o;try{o=oe.openSync(t,"r")}catch{return!0}try{oe.readSync(o,r,0,r.length,0)}finally{oe.closeSync(o)}let a=r.readUint32BE();return!(a===3405691582||a===3489328638||a===2135247942||(a&4294901760)===1297743872)}async function Kb(t,{project:e}){let r=e.configuration,o=new Map,a=e.storedPackages.get(t.locatorHash);if(!a)throw new Error(`Package for ${qr(r,t)} not found in the project`);let n=new hh.Writable,u=r.getLinkers(),A={project:e,report:new Lt({configuration:r,stdout:n})},p=new Set([t.locatorHash]);for(let E of a.dependencies.values()){let I=e.storedResolutions.get(E.descriptorHash);if(!I)throw new Error(`Assertion failed: The resolution (${Gn(r,E)}) should have been registered`);p.add(I)}let h=await Promise.all(Array.from(p,async E=>{let I=e.storedPackages.get(E);if(!I)throw new Error(`Assertion failed: The package (${E}) should have been registered`);if(I.bin.size===0)return ol.skip;let v=u.find(C=>C.supportsPackage(I,A));if(!v)return ol.skip;let x=null;try{x=await v.findPackageLocation(I,A)}catch(C){if(C.code==="LOCATOR_NOT_INSTALLED")return ol.skip;throw C}return{dependency:I,packageLocation:x}}));for(let E of h){if(E===ol.skip)continue;let{dependency:I,packageLocation:v}=E;for(let[x,C]of I.bin){let R=z.resolve(v,C);o.set(x,[I,le.fromPortablePath(R),wU(R)])}}return o}async function nue(t){return await Kb(t.anchoredLocator,{project:t.project})}async function IU(t,e){await Promise.all(Array.from(e,([r,[,o,a]])=>a?ph(t,r,process.execPath,[o]):ph(t,r,o,[])))}async function iue(t,e,r,{cwd:o,project:a,stdin:n,stdout:u,stderr:A,nodeArgs:p=[],packageAccessibleBinaries:h}){h??=await Kb(t,{project:a});let E=h.get(e);if(!E)throw new Error(`Binary not found (${e}) for ${qr(a.configuration,t)}`);return await oe.mktempPromise(async I=>{let[,v]=E,x=await M1({project:a,locator:t,binFolder:I});await IU(x.BERRY_BIN_FOLDER,h);let C=wU(le.toPortablePath(v))?Yc(process.execPath,[...p,v,...r],{cwd:o,env:x,stdin:n,stdout:u,stderr:A}):Yc(v,r,{cwd:o,env:x,stdin:n,stdout:u,stderr:A}),R;try{R=await C}finally{await oe.removePromise(x.BERRY_BIN_FOLDER)}return R.code})}async function Sat(t,e,r,{cwd:o,stdin:a,stdout:n,stderr:u,packageAccessibleBinaries:A}){return await iue(t.anchoredLocator,e,r,{project:t.project,cwd:o,stdin:a,stdout:n,stderr:u,packageAccessibleBinaries:A})}var Jce,Xce,hh,Zce,wat,Iat,BU=Et(()=>{Pt();Pt();iA();k1();Jce=$e(mU()),Xce=$e(sd()),hh=ve("stream");fE();Wl();O1();N1();Db();jl();Gl();Qf();bo();Zce=(a=>(a.Yarn1="Yarn Classic",a.Yarn2="Yarn",a.Npm="npm",a.Pnpm="pnpm",a))(Zce||{});wat=2,Iat=(0,Xce.default)(wat)});var OE=_((O4t,oue)=>{"use strict";var sue=new Map([["C","cwd"],["f","file"],["z","gzip"],["P","preservePaths"],["U","unlink"],["strip-components","strip"],["stripComponents","strip"],["keep-newer","newer"],["keepNewer","newer"],["keep-newer-files","newer"],["keepNewerFiles","newer"],["k","keep"],["keep-existing","keep"],["keepExisting","keep"],["m","noMtime"],["no-mtime","noMtime"],["p","preserveOwner"],["L","follow"],["h","follow"]]);oue.exports=t=>t?Object.keys(t).map(e=>[sue.has(e)?sue.get(e):e,t[e]]).reduce((e,r)=>(e[r[0]]=r[1],e),Object.create(null)):{}});var UE=_((M4t,gue)=>{"use strict";var aue=typeof process=="object"&&process?process:{stdout:null,stderr:null},bat=ve("events"),lue=ve("stream"),cue=ve("string_decoder").StringDecoder,Mf=Symbol("EOF"),Uf=Symbol("maybeEmitEnd"),gh=Symbol("emittedEnd"),zb=Symbol("emittingEnd"),U1=Symbol("emittedError"),Vb=Symbol("closed"),uue=Symbol("read"),Jb=Symbol("flush"),Aue=Symbol("flushChunk"),ka=Symbol("encoding"),_f=Symbol("decoder"),Xb=Symbol("flowing"),_1=Symbol("paused"),ME=Symbol("resume"),Fs=Symbol("bufferLength"),vU=Symbol("bufferPush"),DU=Symbol("bufferShift"),Fo=Symbol("objectMode"),Ro=Symbol("destroyed"),PU=Symbol("emitData"),fue=Symbol("emitEnd"),SU=Symbol("emitEnd2"),Hf=Symbol("async"),H1=t=>Promise.resolve().then(t),pue=global._MP_NO_ITERATOR_SYMBOLS_!=="1",xat=pue&&Symbol.asyncIterator||Symbol("asyncIterator not implemented"),kat=pue&&Symbol.iterator||Symbol("iterator not implemented"),Qat=t=>t==="end"||t==="finish"||t==="prefinish",Fat=t=>t instanceof ArrayBuffer||typeof t=="object"&&t.constructor&&t.constructor.name==="ArrayBuffer"&&t.byteLength>=0,Rat=t=>!Buffer.isBuffer(t)&&ArrayBuffer.isView(t),Zb=class{constructor(e,r,o){this.src=e,this.dest=r,this.opts=o,this.ondrain=()=>e[ME](),r.on("drain",this.ondrain)}unpipe(){this.dest.removeListener("drain",this.ondrain)}proxyErrors(){}end(){this.unpipe(),this.opts.end&&this.dest.end()}},bU=class extends Zb{unpipe(){this.src.removeListener("error",this.proxyErrors),super.unpipe()}constructor(e,r,o){super(e,r,o),this.proxyErrors=a=>r.emit("error",a),e.on("error",this.proxyErrors)}};gue.exports=class hue extends lue{constructor(e){super(),this[Xb]=!1,this[_1]=!1,this.pipes=[],this.buffer=[],this[Fo]=e&&e.objectMode||!1,this[Fo]?this[ka]=null:this[ka]=e&&e.encoding||null,this[ka]==="buffer"&&(this[ka]=null),this[Hf]=e&&!!e.async||!1,this[_f]=this[ka]?new cue(this[ka]):null,this[Mf]=!1,this[gh]=!1,this[zb]=!1,this[Vb]=!1,this[U1]=null,this.writable=!0,this.readable=!0,this[Fs]=0,this[Ro]=!1}get bufferLength(){return this[Fs]}get encoding(){return this[ka]}set encoding(e){if(this[Fo])throw new Error("cannot set encoding in objectMode");if(this[ka]&&e!==this[ka]&&(this[_f]&&this[_f].lastNeed||this[Fs]))throw new Error("cannot change encoding");this[ka]!==e&&(this[_f]=e?new cue(e):null,this.buffer.length&&(this.buffer=this.buffer.map(r=>this[_f].write(r)))),this[ka]=e}setEncoding(e){this.encoding=e}get objectMode(){return this[Fo]}set objectMode(e){this[Fo]=this[Fo]||!!e}get async(){return this[Hf]}set async(e){this[Hf]=this[Hf]||!!e}write(e,r,o){if(this[Mf])throw new Error("write after end");if(this[Ro])return this.emit("error",Object.assign(new Error("Cannot call write after a stream was destroyed"),{code:"ERR_STREAM_DESTROYED"})),!0;typeof r=="function"&&(o=r,r="utf8"),r||(r="utf8");let a=this[Hf]?H1:n=>n();return!this[Fo]&&!Buffer.isBuffer(e)&&(Rat(e)?e=Buffer.from(e.buffer,e.byteOffset,e.byteLength):Fat(e)?e=Buffer.from(e):typeof e!="string"&&(this.objectMode=!0)),this[Fo]?(this.flowing&&this[Fs]!==0&&this[Jb](!0),this.flowing?this.emit("data",e):this[vU](e),this[Fs]!==0&&this.emit("readable"),o&&a(o),this.flowing):e.length?(typeof e=="string"&&!(r===this[ka]&&!this[_f].lastNeed)&&(e=Buffer.from(e,r)),Buffer.isBuffer(e)&&this[ka]&&(e=this[_f].write(e)),this.flowing&&this[Fs]!==0&&this[Jb](!0),this.flowing?this.emit("data",e):this[vU](e),this[Fs]!==0&&this.emit("readable"),o&&a(o),this.flowing):(this[Fs]!==0&&this.emit("readable"),o&&a(o),this.flowing)}read(e){if(this[Ro])return null;if(this[Fs]===0||e===0||e>this[Fs])return this[Uf](),null;this[Fo]&&(e=null),this.buffer.length>1&&!this[Fo]&&(this.encoding?this.buffer=[this.buffer.join("")]:this.buffer=[Buffer.concat(this.buffer,this[Fs])]);let r=this[uue](e||null,this.buffer[0]);return this[Uf](),r}[uue](e,r){return e===r.length||e===null?this[DU]():(this.buffer[0]=r.slice(e),r=r.slice(0,e),this[Fs]-=e),this.emit("data",r),!this.buffer.length&&!this[Mf]&&this.emit("drain"),r}end(e,r,o){return typeof e=="function"&&(o=e,e=null),typeof r=="function"&&(o=r,r="utf8"),e&&this.write(e,r),o&&this.once("end",o),this[Mf]=!0,this.writable=!1,(this.flowing||!this[_1])&&this[Uf](),this}[ME](){this[Ro]||(this[_1]=!1,this[Xb]=!0,this.emit("resume"),this.buffer.length?this[Jb]():this[Mf]?this[Uf]():this.emit("drain"))}resume(){return this[ME]()}pause(){this[Xb]=!1,this[_1]=!0}get destroyed(){return this[Ro]}get flowing(){return this[Xb]}get paused(){return this[_1]}[vU](e){this[Fo]?this[Fs]+=1:this[Fs]+=e.length,this.buffer.push(e)}[DU](){return this.buffer.length&&(this[Fo]?this[Fs]-=1:this[Fs]-=this.buffer[0].length),this.buffer.shift()}[Jb](e){do;while(this[Aue](this[DU]()));!e&&!this.buffer.length&&!this[Mf]&&this.emit("drain")}[Aue](e){return e?(this.emit("data",e),this.flowing):!1}pipe(e,r){if(this[Ro])return;let o=this[gh];return r=r||{},e===aue.stdout||e===aue.stderr?r.end=!1:r.end=r.end!==!1,r.proxyErrors=!!r.proxyErrors,o?r.end&&e.end():(this.pipes.push(r.proxyErrors?new bU(this,e,r):new Zb(this,e,r)),this[Hf]?H1(()=>this[ME]()):this[ME]()),e}unpipe(e){let r=this.pipes.find(o=>o.dest===e);r&&(this.pipes.splice(this.pipes.indexOf(r),1),r.unpipe())}addListener(e,r){return this.on(e,r)}on(e,r){let o=super.on(e,r);return e==="data"&&!this.pipes.length&&!this.flowing?this[ME]():e==="readable"&&this[Fs]!==0?super.emit("readable"):Qat(e)&&this[gh]?(super.emit(e),this.removeAllListeners(e)):e==="error"&&this[U1]&&(this[Hf]?H1(()=>r.call(this,this[U1])):r.call(this,this[U1])),o}get emittedEnd(){return this[gh]}[Uf](){!this[zb]&&!this[gh]&&!this[Ro]&&this.buffer.length===0&&this[Mf]&&(this[zb]=!0,this.emit("end"),this.emit("prefinish"),this.emit("finish"),this[Vb]&&this.emit("close"),this[zb]=!1)}emit(e,r,...o){if(e!=="error"&&e!=="close"&&e!==Ro&&this[Ro])return;if(e==="data")return r?this[Hf]?H1(()=>this[PU](r)):this[PU](r):!1;if(e==="end")return this[fue]();if(e==="close"){if(this[Vb]=!0,!this[gh]&&!this[Ro])return;let n=super.emit("close");return this.removeAllListeners("close"),n}else if(e==="error"){this[U1]=r;let n=super.emit("error",r);return this[Uf](),n}else if(e==="resume"){let n=super.emit("resume");return this[Uf](),n}else if(e==="finish"||e==="prefinish"){let n=super.emit(e);return this.removeAllListeners(e),n}let a=super.emit(e,r,...o);return this[Uf](),a}[PU](e){for(let o of this.pipes)o.dest.write(e)===!1&&this.pause();let r=super.emit("data",e);return this[Uf](),r}[fue](){this[gh]||(this[gh]=!0,this.readable=!1,this[Hf]?H1(()=>this[SU]()):this[SU]())}[SU](){if(this[_f]){let r=this[_f].end();if(r){for(let o of this.pipes)o.dest.write(r);super.emit("data",r)}}for(let r of this.pipes)r.end();let e=super.emit("end");return this.removeAllListeners("end"),e}collect(){let e=[];this[Fo]||(e.dataLength=0);let r=this.promise();return this.on("data",o=>{e.push(o),this[Fo]||(e.dataLength+=o.length)}),r.then(()=>e)}concat(){return this[Fo]?Promise.reject(new Error("cannot concat in objectMode")):this.collect().then(e=>this[Fo]?Promise.reject(new Error("cannot concat in objectMode")):this[ka]?e.join(""):Buffer.concat(e,e.dataLength))}promise(){return new Promise((e,r)=>{this.on(Ro,()=>r(new Error("stream destroyed"))),this.on("error",o=>r(o)),this.on("end",()=>e())})}[xat](){return{next:()=>{let r=this.read();if(r!==null)return Promise.resolve({done:!1,value:r});if(this[Mf])return Promise.resolve({done:!0});let o=null,a=null,n=h=>{this.removeListener("data",u),this.removeListener("end",A),a(h)},u=h=>{this.removeListener("error",n),this.removeListener("end",A),this.pause(),o({value:h,done:!!this[Mf]})},A=()=>{this.removeListener("error",n),this.removeListener("data",u),o({done:!0})},p=()=>n(new Error("stream destroyed"));return new Promise((h,E)=>{a=E,o=h,this.once(Ro,p),this.once("error",n),this.once("end",A),this.once("data",u)})}}}[kat](){return{next:()=>{let r=this.read();return{value:r,done:r===null}}}}destroy(e){return this[Ro]?(e?this.emit("error",e):this.emit(Ro),this):(this[Ro]=!0,this.buffer.length=0,this[Fs]=0,typeof this.close=="function"&&!this[Vb]&&this.close(),e?this.emit("error",e):this.emit(Ro),this)}static isStream(e){return!!e&&(e instanceof hue||e instanceof lue||e instanceof bat&&(typeof e.pipe=="function"||typeof e.write=="function"&&typeof e.end=="function"))}}});var mue=_((U4t,due)=>{var Tat=ve("zlib").constants||{ZLIB_VERNUM:4736};due.exports=Object.freeze(Object.assign(Object.create(null),{Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_MEM_ERROR:-4,Z_BUF_ERROR:-5,Z_VERSION_ERROR:-6,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,DEFLATE:1,INFLATE:2,GZIP:3,GUNZIP:4,DEFLATERAW:5,INFLATERAW:6,UNZIP:7,BROTLI_DECODE:8,BROTLI_ENCODE:9,Z_MIN_WINDOWBITS:8,Z_MAX_WINDOWBITS:15,Z_DEFAULT_WINDOWBITS:15,Z_MIN_CHUNK:64,Z_MAX_CHUNK:1/0,Z_DEFAULT_CHUNK:16384,Z_MIN_MEMLEVEL:1,Z_MAX_MEMLEVEL:9,Z_DEFAULT_MEMLEVEL:8,Z_MIN_LEVEL:-1,Z_MAX_LEVEL:9,Z_DEFAULT_LEVEL:-1,BROTLI_OPERATION_PROCESS:0,BROTLI_OPERATION_FLUSH:1,BROTLI_OPERATION_FINISH:2,BROTLI_OPERATION_EMIT_METADATA:3,BROTLI_MODE_GENERIC:0,BROTLI_MODE_TEXT:1,BROTLI_MODE_FONT:2,BROTLI_DEFAULT_MODE:0,BROTLI_MIN_QUALITY:0,BROTLI_MAX_QUALITY:11,BROTLI_DEFAULT_QUALITY:11,BROTLI_MIN_WINDOW_BITS:10,BROTLI_MAX_WINDOW_BITS:24,BROTLI_LARGE_MAX_WINDOW_BITS:30,BROTLI_DEFAULT_WINDOW:22,BROTLI_MIN_INPUT_BLOCK_BITS:16,BROTLI_MAX_INPUT_BLOCK_BITS:24,BROTLI_PARAM_MODE:0,BROTLI_PARAM_QUALITY:1,BROTLI_PARAM_LGWIN:2,BROTLI_PARAM_LGBLOCK:3,BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING:4,BROTLI_PARAM_SIZE_HINT:5,BROTLI_PARAM_LARGE_WINDOW:6,BROTLI_PARAM_NPOSTFIX:7,BROTLI_PARAM_NDIRECT:8,BROTLI_DECODER_RESULT_ERROR:0,BROTLI_DECODER_RESULT_SUCCESS:1,BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:2,BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:3,BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION:0,BROTLI_DECODER_PARAM_LARGE_WINDOW:1,BROTLI_DECODER_NO_ERROR:0,BROTLI_DECODER_SUCCESS:1,BROTLI_DECODER_NEEDS_MORE_INPUT:2,BROTLI_DECODER_NEEDS_MORE_OUTPUT:3,BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE:-1,BROTLI_DECODER_ERROR_FORMAT_RESERVED:-2,BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE:-3,BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET:-4,BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME:-5,BROTLI_DECODER_ERROR_FORMAT_CL_SPACE:-6,BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE:-7,BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT:-8,BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1:-9,BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2:-10,BROTLI_DECODER_ERROR_FORMAT_TRANSFORM:-11,BROTLI_DECODER_ERROR_FORMAT_DICTIONARY:-12,BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS:-13,BROTLI_DECODER_ERROR_FORMAT_PADDING_1:-14,BROTLI_DECODER_ERROR_FORMAT_PADDING_2:-15,BROTLI_DECODER_ERROR_FORMAT_DISTANCE:-16,BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET:-19,BROTLI_DECODER_ERROR_INVALID_ARGUMENTS:-20,BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES:-21,BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS:-22,BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP:-25,BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1:-26,BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2:-27,BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES:-30,BROTLI_DECODER_ERROR_UNREACHABLE:-31},Tat))});var jU=_(ul=>{"use strict";var RU=ve("assert"),dh=ve("buffer").Buffer,Cue=ve("zlib"),Rd=ul.constants=mue(),Lat=UE(),yue=dh.concat,Td=Symbol("_superWrite"),HE=class extends Error{constructor(e){super("zlib: "+e.message),this.code=e.code,this.errno=e.errno,this.code||(this.code="ZLIB_ERROR"),this.message="zlib: "+e.message,Error.captureStackTrace(this,this.constructor)}get name(){return"ZlibError"}},Nat=Symbol("opts"),q1=Symbol("flushFlag"),Eue=Symbol("finishFlushFlag"),GU=Symbol("fullFlushFlag"),ti=Symbol("handle"),$b=Symbol("onError"),_E=Symbol("sawError"),xU=Symbol("level"),kU=Symbol("strategy"),QU=Symbol("ended"),_4t=Symbol("_defaultFullFlush"),ex=class extends Lat{constructor(e,r){if(!e||typeof e!="object")throw new TypeError("invalid options for ZlibBase constructor");super(e),this[_E]=!1,this[QU]=!1,this[Nat]=e,this[q1]=e.flush,this[Eue]=e.finishFlush;try{this[ti]=new Cue[r](e)}catch(o){throw new HE(o)}this[$b]=o=>{this[_E]||(this[_E]=!0,this.close(),this.emit("error",o))},this[ti].on("error",o=>this[$b](new HE(o))),this.once("end",()=>this.close)}close(){this[ti]&&(this[ti].close(),this[ti]=null,this.emit("close"))}reset(){if(!this[_E])return RU(this[ti],"zlib binding closed"),this[ti].reset()}flush(e){this.ended||(typeof e!="number"&&(e=this[GU]),this.write(Object.assign(dh.alloc(0),{[q1]:e})))}end(e,r,o){return e&&this.write(e,r),this.flush(this[Eue]),this[QU]=!0,super.end(null,null,o)}get ended(){return this[QU]}write(e,r,o){if(typeof r=="function"&&(o=r,r="utf8"),typeof e=="string"&&(e=dh.from(e,r)),this[_E])return;RU(this[ti],"zlib binding closed");let a=this[ti]._handle,n=a.close;a.close=()=>{};let u=this[ti].close;this[ti].close=()=>{},dh.concat=h=>h;let A;try{let h=typeof e[q1]=="number"?e[q1]:this[q1];A=this[ti]._processChunk(e,h),dh.concat=yue}catch(h){dh.concat=yue,this[$b](new HE(h))}finally{this[ti]&&(this[ti]._handle=a,a.close=n,this[ti].close=u,this[ti].removeAllListeners("error"))}this[ti]&&this[ti].on("error",h=>this[$b](new HE(h)));let p;if(A)if(Array.isArray(A)&&A.length>0){p=this[Td](dh.from(A[0]));for(let h=1;h<A.length;h++)p=this[Td](A[h])}else p=this[Td](dh.from(A));return o&&o(),p}[Td](e){return super.write(e)}},qf=class extends ex{constructor(e,r){e=e||{},e.flush=e.flush||Rd.Z_NO_FLUSH,e.finishFlush=e.finishFlush||Rd.Z_FINISH,super(e,r),this[GU]=Rd.Z_FULL_FLUSH,this[xU]=e.level,this[kU]=e.strategy}params(e,r){if(!this[_E]){if(!this[ti])throw new Error("cannot switch params when binding is closed");if(!this[ti].params)throw new Error("not supported in this implementation");if(this[xU]!==e||this[kU]!==r){this.flush(Rd.Z_SYNC_FLUSH),RU(this[ti],"zlib binding closed");let o=this[ti].flush;this[ti].flush=(a,n)=>{this.flush(a),n()};try{this[ti].params(e,r)}finally{this[ti].flush=o}this[ti]&&(this[xU]=e,this[kU]=r)}}}},TU=class extends qf{constructor(e){super(e,"Deflate")}},LU=class extends qf{constructor(e){super(e,"Inflate")}},FU=Symbol("_portable"),NU=class extends qf{constructor(e){super(e,"Gzip"),this[FU]=e&&!!e.portable}[Td](e){return this[FU]?(this[FU]=!1,e[9]=255,super[Td](e)):super[Td](e)}},OU=class extends qf{constructor(e){super(e,"Gunzip")}},MU=class extends qf{constructor(e){super(e,"DeflateRaw")}},UU=class extends qf{constructor(e){super(e,"InflateRaw")}},_U=class extends qf{constructor(e){super(e,"Unzip")}},tx=class extends ex{constructor(e,r){e=e||{},e.flush=e.flush||Rd.BROTLI_OPERATION_PROCESS,e.finishFlush=e.finishFlush||Rd.BROTLI_OPERATION_FINISH,super(e,r),this[GU]=Rd.BROTLI_OPERATION_FLUSH}},HU=class extends tx{constructor(e){super(e,"BrotliCompress")}},qU=class extends tx{constructor(e){super(e,"BrotliDecompress")}};ul.Deflate=TU;ul.Inflate=LU;ul.Gzip=NU;ul.Gunzip=OU;ul.DeflateRaw=MU;ul.InflateRaw=UU;ul.Unzip=_U;typeof Cue.BrotliCompress=="function"?(ul.BrotliCompress=HU,ul.BrotliDecompress=qU):ul.BrotliCompress=ul.BrotliDecompress=class{constructor(){throw new Error("Brotli is not supported in this version of Node.js")}}});var qE=_((G4t,wue)=>{var Oat=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform;wue.exports=Oat!=="win32"?t=>t:t=>t&&t.replace(/\\/g,"/")});var rx=_((Y4t,Iue)=>{"use strict";var Mat=UE(),YU=qE(),WU=Symbol("slurp");Iue.exports=class extends Mat{constructor(e,r,o){switch(super(),this.pause(),this.extended=r,this.globalExtended=o,this.header=e,this.startBlockSize=512*Math.ceil(e.size/512),this.blockRemain=this.startBlockSize,this.remain=e.size,this.type=e.type,this.meta=!1,this.ignore=!1,this.type){case"File":case"OldFile":case"Link":case"SymbolicLink":case"CharacterDevice":case"BlockDevice":case"Directory":case"FIFO":case"ContiguousFile":case"GNUDumpDir":break;case"NextFileHasLongLinkpath":case"NextFileHasLongPath":case"OldGnuLongPath":case"GlobalExtendedHeader":case"ExtendedHeader":case"OldExtendedHeader":this.meta=!0;break;default:this.ignore=!0}this.path=YU(e.path),this.mode=e.mode,this.mode&&(this.mode=this.mode&4095),this.uid=e.uid,this.gid=e.gid,this.uname=e.uname,this.gname=e.gname,this.size=e.size,this.mtime=e.mtime,this.atime=e.atime,this.ctime=e.ctime,this.linkpath=YU(e.linkpath),this.uname=e.uname,this.gname=e.gname,r&&this[WU](r),o&&this[WU](o,!0)}write(e){let r=e.length;if(r>this.blockRemain)throw new Error("writing more to entry than is appropriate");let o=this.remain,a=this.blockRemain;return this.remain=Math.max(0,o-r),this.blockRemain=Math.max(0,a-r),this.ignore?!0:o>=r?super.write(e):super.write(e.slice(0,o))}[WU](e,r){for(let o in e)e[o]!==null&&e[o]!==void 0&&!(r&&o==="path")&&(this[o]=o==="path"||o==="linkpath"?YU(e[o]):e[o])}}});var KU=_(nx=>{"use strict";nx.name=new Map([["0","File"],["","OldFile"],["1","Link"],["2","SymbolicLink"],["3","CharacterDevice"],["4","BlockDevice"],["5","Directory"],["6","FIFO"],["7","ContiguousFile"],["g","GlobalExtendedHeader"],["x","ExtendedHeader"],["A","SolarisACL"],["D","GNUDumpDir"],["I","Inode"],["K","NextFileHasLongLinkpath"],["L","NextFileHasLongPath"],["M","ContinuationFile"],["N","OldGnuLongPath"],["S","SparseFile"],["V","TapeVolumeHeader"],["X","OldExtendedHeader"]]);nx.code=new Map(Array.from(nx.name).map(t=>[t[1],t[0]]))});var Pue=_((K4t,Due)=>{"use strict";var Uat=(t,e)=>{if(Number.isSafeInteger(t))t<0?Hat(t,e):_at(t,e);else throw Error("cannot encode number outside of javascript safe integer range");return e},_at=(t,e)=>{e[0]=128;for(var r=e.length;r>1;r--)e[r-1]=t&255,t=Math.floor(t/256)},Hat=(t,e)=>{e[0]=255;var r=!1;t=t*-1;for(var o=e.length;o>1;o--){var a=t&255;t=Math.floor(t/256),r?e[o-1]=Bue(a):a===0?e[o-1]=0:(r=!0,e[o-1]=vue(a))}},qat=t=>{let e=t[0],r=e===128?jat(t.slice(1,t.length)):e===255?Gat(t):null;if(r===null)throw Error("invalid base256 encoding");if(!Number.isSafeInteger(r))throw Error("parsed number outside of javascript safe integer range");return r},Gat=t=>{for(var e=t.length,r=0,o=!1,a=e-1;a>-1;a--){var n=t[a],u;o?u=Bue(n):n===0?u=n:(o=!0,u=vue(n)),u!==0&&(r-=u*Math.pow(256,e-a-1))}return r},jat=t=>{for(var e=t.length,r=0,o=e-1;o>-1;o--){var a=t[o];a!==0&&(r+=a*Math.pow(256,e-o-1))}return r},Bue=t=>(255^t)&255,vue=t=>(255^t)+1&255;Due.exports={encode:Uat,parse:qat}});var jE=_((z4t,bue)=>{"use strict";var zU=KU(),GE=ve("path").posix,Sue=Pue(),VU=Symbol("slurp"),Al=Symbol("type"),ZU=class{constructor(e,r,o,a){this.cksumValid=!1,this.needPax=!1,this.nullBlock=!1,this.block=null,this.path=null,this.mode=null,this.uid=null,this.gid=null,this.size=null,this.mtime=null,this.cksum=null,this[Al]="0",this.linkpath=null,this.uname=null,this.gname=null,this.devmaj=0,this.devmin=0,this.atime=null,this.ctime=null,Buffer.isBuffer(e)?this.decode(e,r||0,o,a):e&&this.set(e)}decode(e,r,o,a){if(r||(r=0),!e||!(e.length>=r+512))throw new Error("need 512 bytes for header");if(this.path=Ld(e,r,100),this.mode=mh(e,r+100,8),this.uid=mh(e,r+108,8),this.gid=mh(e,r+116,8),this.size=mh(e,r+124,12),this.mtime=JU(e,r+136,12),this.cksum=mh(e,r+148,12),this[VU](o),this[VU](a,!0),this[Al]=Ld(e,r+156,1),this[Al]===""&&(this[Al]="0"),this[Al]==="0"&&this.path.substr(-1)==="/"&&(this[Al]="5"),this[Al]==="5"&&(this.size=0),this.linkpath=Ld(e,r+157,100),e.slice(r+257,r+265).toString()==="ustar\x0000")if(this.uname=Ld(e,r+265,32),this.gname=Ld(e,r+297,32),this.devmaj=mh(e,r+329,8),this.devmin=mh(e,r+337,8),e[r+475]!==0){let u=Ld(e,r+345,155);this.path=u+"/"+this.path}else{let u=Ld(e,r+345,130);u&&(this.path=u+"/"+this.path),this.atime=JU(e,r+476,12),this.ctime=JU(e,r+488,12)}let n=8*32;for(let u=r;u<r+148;u++)n+=e[u];for(let u=r+156;u<r+512;u++)n+=e[u];this.cksumValid=n===this.cksum,this.cksum===null&&n===8*32&&(this.nullBlock=!0)}[VU](e,r){for(let o in e)e[o]!==null&&e[o]!==void 0&&!(r&&o==="path")&&(this[o]=e[o])}encode(e,r){if(e||(e=this.block=Buffer.alloc(512),r=0),r||(r=0),!(e.length>=r+512))throw new Error("need 512 bytes for header");let o=this.ctime||this.atime?130:155,a=Yat(this.path||"",o),n=a[0],u=a[1];this.needPax=a[2],this.needPax=Nd(e,r,100,n)||this.needPax,this.needPax=yh(e,r+100,8,this.mode)||this.needPax,this.needPax=yh(e,r+108,8,this.uid)||this.needPax,this.needPax=yh(e,r+116,8,this.gid)||this.needPax,this.needPax=yh(e,r+124,12,this.size)||this.needPax,this.needPax=XU(e,r+136,12,this.mtime)||this.needPax,e[r+156]=this[Al].charCodeAt(0),this.needPax=Nd(e,r+157,100,this.linkpath)||this.needPax,e.write("ustar\x0000",r+257,8),this.needPax=Nd(e,r+265,32,this.uname)||this.needPax,this.needPax=Nd(e,r+297,32,this.gname)||this.needPax,this.needPax=yh(e,r+329,8,this.devmaj)||this.needPax,this.needPax=yh(e,r+337,8,this.devmin)||this.needPax,this.needPax=Nd(e,r+345,o,u)||this.needPax,e[r+475]!==0?this.needPax=Nd(e,r+345,155,u)||this.needPax:(this.needPax=Nd(e,r+345,130,u)||this.needPax,this.needPax=XU(e,r+476,12,this.atime)||this.needPax,this.needPax=XU(e,r+488,12,this.ctime)||this.needPax);let A=8*32;for(let p=r;p<r+148;p++)A+=e[p];for(let p=r+156;p<r+512;p++)A+=e[p];return this.cksum=A,yh(e,r+148,8,this.cksum),this.cksumValid=!0,this.needPax}set(e){for(let r in e)e[r]!==null&&e[r]!==void 0&&(this[r]=e[r])}get type(){return zU.name.get(this[Al])||this[Al]}get typeKey(){return this[Al]}set type(e){zU.code.has(e)?this[Al]=zU.code.get(e):this[Al]=e}},Yat=(t,e)=>{let o=t,a="",n,u=GE.parse(t).root||".";if(Buffer.byteLength(o)<100)n=[o,a,!1];else{a=GE.dirname(o),o=GE.basename(o);do Buffer.byteLength(o)<=100&&Buffer.byteLength(a)<=e?n=[o,a,!1]:Buffer.byteLength(o)>100&&Buffer.byteLength(a)<=e?n=[o.substr(0,100-1),a,!0]:(o=GE.join(GE.basename(a),o),a=GE.dirname(a));while(a!==u&&!n);n||(n=[t.substr(0,100-1),"",!0])}return n},Ld=(t,e,r)=>t.slice(e,e+r).toString("utf8").replace(/\0.*/,""),JU=(t,e,r)=>Wat(mh(t,e,r)),Wat=t=>t===null?null:new Date(t*1e3),mh=(t,e,r)=>t[e]&128?Sue.parse(t.slice(e,e+r)):zat(t,e,r),Kat=t=>isNaN(t)?null:t,zat=(t,e,r)=>Kat(parseInt(t.slice(e,e+r).toString("utf8").replace(/\0.*$/,"").trim(),8)),Vat={12:8589934591,8:2097151},yh=(t,e,r,o)=>o===null?!1:o>Vat[r]||o<0?(Sue.encode(o,t.slice(e,e+r)),!0):(Jat(t,e,r,o),!1),Jat=(t,e,r,o)=>t.write(Xat(o,r),e,r,"ascii"),Xat=(t,e)=>Zat(Math.floor(t).toString(8),e),Zat=(t,e)=>(t.length===e-1?t:new Array(e-t.length-1).join("0")+t+" ")+"\0",XU=(t,e,r,o)=>o===null?!1:yh(t,e,r,o.getTime()/1e3),$at=new Array(156).join("\0"),Nd=(t,e,r,o)=>o===null?!1:(t.write(o+$at,e,r,"utf8"),o.length!==Buffer.byteLength(o)||o.length>r);bue.exports=ZU});var ix=_((V4t,xue)=>{"use strict";var elt=jE(),tlt=ve("path"),G1=class{constructor(e,r){this.atime=e.atime||null,this.charset=e.charset||null,this.comment=e.comment||null,this.ctime=e.ctime||null,this.gid=e.gid||null,this.gname=e.gname||null,this.linkpath=e.linkpath||null,this.mtime=e.mtime||null,this.path=e.path||null,this.size=e.size||null,this.uid=e.uid||null,this.uname=e.uname||null,this.dev=e.dev||null,this.ino=e.ino||null,this.nlink=e.nlink||null,this.global=r||!1}encode(){let e=this.encodeBody();if(e==="")return null;let r=Buffer.byteLength(e),o=512*Math.ceil(1+r/512),a=Buffer.allocUnsafe(o);for(let n=0;n<512;n++)a[n]=0;new elt({path:("PaxHeader/"+tlt.basename(this.path)).slice(0,99),mode:this.mode||420,uid:this.uid||null,gid:this.gid||null,size:r,mtime:this.mtime||null,type:this.global?"GlobalExtendedHeader":"ExtendedHeader",linkpath:"",uname:this.uname||"",gname:this.gname||"",devmaj:0,devmin:0,atime:this.atime||null,ctime:this.ctime||null}).encode(a),a.write(e,512,r,"utf8");for(let n=r+512;n<a.length;n++)a[n]=0;return a}encodeBody(){return this.encodeField("path")+this.encodeField("ctime")+this.encodeField("atime")+this.encodeField("dev")+this.encodeField("ino")+this.encodeField("nlink")+this.encodeField("charset")+this.encodeField("comment")+this.encodeField("gid")+this.encodeField("gname")+this.encodeField("linkpath")+this.encodeField("mtime")+this.encodeField("size")+this.encodeField("uid")+this.encodeField("uname")}encodeField(e){if(this[e]===null||this[e]===void 0)return"";let r=this[e]instanceof Date?this[e].getTime()/1e3:this[e],o=" "+(e==="dev"||e==="ino"||e==="nlink"?"SCHILY.":"")+e+"="+r+`
-`,a=Buffer.byteLength(o),n=Math.floor(Math.log(a)/Math.log(10))+1;return a+n>=Math.pow(10,n)&&(n+=1),n+a+o}};G1.parse=(t,e,r)=>new G1(rlt(nlt(t),e),r);var rlt=(t,e)=>e?Object.keys(t).reduce((r,o)=>(r[o]=t[o],r),e):t,nlt=t=>t.replace(/\n$/,"").split(`
-`).reduce(ilt,Object.create(null)),ilt=(t,e)=>{let r=parseInt(e,10);if(r!==Buffer.byteLength(e)+1)return t;e=e.substr((r+" ").length);let o=e.split("="),a=o.shift().replace(/^SCHILY\.(dev|ino|nlink)/,"$1");if(!a)return t;let n=o.join("=");return t[a]=/^([A-Z]+\.)?([mac]|birth|creation)time$/.test(a)?new Date(n*1e3):/^[0-9]+$/.test(n)?+n:n,t};xue.exports=G1});var YE=_((J4t,kue)=>{kue.exports=t=>{let e=t.length-1,r=-1;for(;e>-1&&t.charAt(e)==="/";)r=e,e--;return r===-1?t:t.slice(0,r)}});var sx=_((X4t,Que)=>{"use strict";Que.exports=t=>class extends t{warn(e,r,o={}){this.file&&(o.file=this.file),this.cwd&&(o.cwd=this.cwd),o.code=r instanceof Error&&r.code||e,o.tarCode=e,!this.strict&&o.recoverable!==!1?(r instanceof Error&&(o=Object.assign(r,o),r=r.message),this.emit("warn",o.tarCode,r,o)):r instanceof Error?this.emit("error",Object.assign(r,o)):this.emit("error",Object.assign(new Error(`${e}: ${r}`),o))}}});var e3=_(($4t,Fue)=>{"use strict";var ox=["|","<",">","?",":"],$U=ox.map(t=>String.fromCharCode(61440+t.charCodeAt(0))),slt=new Map(ox.map((t,e)=>[t,$U[e]])),olt=new Map($U.map((t,e)=>[t,ox[e]]));Fue.exports={encode:t=>ox.reduce((e,r)=>e.split(r).join(slt.get(r)),t),decode:t=>$U.reduce((e,r)=>e.split(r).join(olt.get(r)),t)}});var t3=_((eUt,Tue)=>{var{isAbsolute:alt,parse:Rue}=ve("path").win32;Tue.exports=t=>{let e="",r=Rue(t);for(;alt(t)||r.root;){let o=t.charAt(0)==="/"&&t.slice(0,4)!=="//?/"?"/":r.root;t=t.substr(o.length),e+=o,r=Rue(t)}return[e,t]}});var Nue=_((tUt,Lue)=>{"use strict";Lue.exports=(t,e,r)=>(t&=4095,r&&(t=(t|384)&-19),e&&(t&256&&(t|=64),t&32&&(t|=8),t&4&&(t|=1)),t)});var A3=_((iUt,Jue)=>{"use strict";var Gue=UE(),jue=ix(),Yue=jE(),aA=ve("fs"),Oue=ve("path"),oA=qE(),llt=YE(),Wue=(t,e)=>e?(t=oA(t).replace(/^\.(\/|$)/,""),llt(e)+"/"+t):oA(t),clt=16*1024*1024,Mue=Symbol("process"),Uue=Symbol("file"),_ue=Symbol("directory"),n3=Symbol("symlink"),Hue=Symbol("hardlink"),j1=Symbol("header"),ax=Symbol("read"),i3=Symbol("lstat"),lx=Symbol("onlstat"),s3=Symbol("onread"),o3=Symbol("onreadlink"),a3=Symbol("openfile"),l3=Symbol("onopenfile"),Eh=Symbol("close"),cx=Symbol("mode"),c3=Symbol("awaitDrain"),r3=Symbol("ondrain"),lA=Symbol("prefix"),que=Symbol("hadError"),Kue=sx(),ult=e3(),zue=t3(),Vue=Nue(),ux=Kue(class extends Gue{constructor(e,r){if(r=r||{},super(r),typeof e!="string")throw new TypeError("path is required");this.path=oA(e),this.portable=!!r.portable,this.myuid=process.getuid&&process.getuid()||0,this.myuser=process.env.USER||"",this.maxReadSize=r.maxReadSize||clt,this.linkCache=r.linkCache||new Map,this.statCache=r.statCache||new Map,this.preservePaths=!!r.preservePaths,this.cwd=oA(r.cwd||process.cwd()),this.strict=!!r.strict,this.noPax=!!r.noPax,this.noMtime=!!r.noMtime,this.mtime=r.mtime||null,this.prefix=r.prefix?oA(r.prefix):null,this.fd=null,this.blockLen=null,this.blockRemain=null,this.buf=null,this.offset=null,this.length=null,this.pos=null,this.remain=null,typeof r.onwarn=="function"&&this.on("warn",r.onwarn);let o=!1;if(!this.preservePaths){let[a,n]=zue(this.path);a&&(this.path=n,o=a)}this.win32=!!r.win32||process.platform==="win32",this.win32&&(this.path=ult.decode(this.path.replace(/\\/g,"/")),e=e.replace(/\\/g,"/")),this.absolute=oA(r.absolute||Oue.resolve(this.cwd,e)),this.path===""&&(this.path="./"),o&&this.warn("TAR_ENTRY_INFO",`stripping ${o} from absolute path`,{entry:this,path:o+this.path}),this.statCache.has(this.absolute)?this[lx](this.statCache.get(this.absolute)):this[i3]()}emit(e,...r){return e==="error"&&(this[que]=!0),super.emit(e,...r)}[i3](){aA.lstat(this.absolute,(e,r)=>{if(e)return this.emit("error",e);this[lx](r)})}[lx](e){this.statCache.set(this.absolute,e),this.stat=e,e.isFile()||(e.size=0),this.type=flt(e),this.emit("stat",e),this[Mue]()}[Mue](){switch(this.type){case"File":return this[Uue]();case"Directory":return this[_ue]();case"SymbolicLink":return this[n3]();default:return this.end()}}[cx](e){return Vue(e,this.type==="Directory",this.portable)}[lA](e){return Wue(e,this.prefix)}[j1](){this.type==="Directory"&&this.portable&&(this.noMtime=!0),this.header=new Yue({path:this[lA](this.path),linkpath:this.type==="Link"?this[lA](this.linkpath):this.linkpath,mode:this[cx](this.stat.mode),uid:this.portable?null:this.stat.uid,gid:this.portable?null:this.stat.gid,size:this.stat.size,mtime:this.noMtime?null:this.mtime||this.stat.mtime,type:this.type,uname:this.portable?null:this.stat.uid===this.myuid?this.myuser:"",atime:this.portable?null:this.stat.atime,ctime:this.portable?null:this.stat.ctime}),this.header.encode()&&!this.noPax&&super.write(new jue({atime:this.portable?null:this.header.atime,ctime:this.portable?null:this.header.ctime,gid:this.portable?null:this.header.gid,mtime:this.noMtime?null:this.mtime||this.header.mtime,path:this[lA](this.path),linkpath:this.type==="Link"?this[lA](this.linkpath):this.linkpath,size:this.header.size,uid:this.portable?null:this.header.uid,uname:this.portable?null:this.header.uname,dev:this.portable?null:this.stat.dev,ino:this.portable?null:this.stat.ino,nlink:this.portable?null:this.stat.nlink}).encode()),super.write(this.header.block)}[_ue](){this.path.substr(-1)!=="/"&&(this.path+="/"),this.stat.size=0,this[j1](),this.end()}[n3](){aA.readlink(this.absolute,(e,r)=>{if(e)return this.emit("error",e);this[o3](r)})}[o3](e){this.linkpath=oA(e),this[j1](),this.end()}[Hue](e){this.type="Link",this.linkpath=oA(Oue.relative(this.cwd,e)),this.stat.size=0,this[j1](),this.end()}[Uue](){if(this.stat.nlink>1){let e=this.stat.dev+":"+this.stat.ino;if(this.linkCache.has(e)){let r=this.linkCache.get(e);if(r.indexOf(this.cwd)===0)return this[Hue](r)}this.linkCache.set(e,this.absolute)}if(this[j1](),this.stat.size===0)return this.end();this[a3]()}[a3](){aA.open(this.absolute,"r",(e,r)=>{if(e)return this.emit("error",e);this[l3](r)})}[l3](e){if(this.fd=e,this[que])return this[Eh]();this.blockLen=512*Math.ceil(this.stat.size/512),this.blockRemain=this.blockLen;let r=Math.min(this.blockLen,this.maxReadSize);this.buf=Buffer.allocUnsafe(r),this.offset=0,this.pos=0,this.remain=this.stat.size,this.length=this.buf.length,this[ax]()}[ax](){let{fd:e,buf:r,offset:o,length:a,pos:n}=this;aA.read(e,r,o,a,n,(u,A)=>{if(u)return this[Eh](()=>this.emit("error",u));this[s3](A)})}[Eh](e){aA.close(this.fd,e)}[s3](e){if(e<=0&&this.remain>0){let a=new Error("encountered unexpected EOF");return a.path=this.absolute,a.syscall="read",a.code="EOF",this[Eh](()=>this.emit("error",a))}if(e>this.remain){let a=new Error("did not encounter expected EOF");return a.path=this.absolute,a.syscall="read",a.code="EOF",this[Eh](()=>this.emit("error",a))}if(e===this.remain)for(let a=e;a<this.length&&e<this.blockRemain;a++)this.buf[a+this.offset]=0,e++,this.remain++;let r=this.offset===0&&e===this.buf.length?this.buf:this.buf.slice(this.offset,this.offset+e);this.write(r)?this[r3]():this[c3](()=>this[r3]())}[c3](e){this.once("drain",e)}write(e){if(this.blockRemain<e.length){let r=new Error("writing more data than expected");return r.path=this.absolute,this.emit("error",r)}return this.remain-=e.length,this.blockRemain-=e.length,this.pos+=e.length,this.offset+=e.length,super.write(e)}[r3](){if(!this.remain)return this.blockRemain&&super.write(Buffer.alloc(this.blockRemain)),this[Eh](e=>e?this.emit("error",e):this.end());this.offset>=this.length&&(this.buf=Buffer.allocUnsafe(Math.min(this.blockRemain,this.buf.length)),this.offset=0),this.length=this.buf.length-this.offset,this[ax]()}}),u3=class extends ux{[i3](){this[lx](aA.lstatSync(this.absolute))}[n3](){this[o3](aA.readlinkSync(this.absolute))}[a3](){this[l3](aA.openSync(this.absolute,"r"))}[ax](){let e=!0;try{let{fd:r,buf:o,offset:a,length:n,pos:u}=this,A=aA.readSync(r,o,a,n,u);this[s3](A),e=!1}finally{if(e)try{this[Eh](()=>{})}catch{}}}[c3](e){e()}[Eh](e){aA.closeSync(this.fd),e()}},Alt=Kue(class extends Gue{constructor(e,r){r=r||{},super(r),this.preservePaths=!!r.preservePaths,this.portable=!!r.portable,this.strict=!!r.strict,this.noPax=!!r.noPax,this.noMtime=!!r.noMtime,this.readEntry=e,this.type=e.type,this.type==="Directory"&&this.portable&&(this.noMtime=!0),this.prefix=r.prefix||null,this.path=oA(e.path),this.mode=this[cx](e.mode),this.uid=this.portable?null:e.uid,this.gid=this.portable?null:e.gid,this.uname=this.portable?null:e.uname,this.gname=this.portable?null:e.gname,this.size=e.size,this.mtime=this.noMtime?null:r.mtime||e.mtime,this.atime=this.portable?null:e.atime,this.ctime=this.portable?null:e.ctime,this.linkpath=oA(e.linkpath),typeof r.onwarn=="function"&&this.on("warn",r.onwarn);let o=!1;if(!this.preservePaths){let[a,n]=zue(this.path);a&&(this.path=n,o=a)}this.remain=e.size,this.blockRemain=e.startBlockSize,this.header=new Yue({path:this[lA](this.path),linkpath:this.type==="Link"?this[lA](this.linkpath):this.linkpath,mode:this.mode,uid:this.portable?null:this.uid,gid:this.portable?null:this.gid,size:this.size,mtime:this.noMtime?null:this.mtime,type:this.type,uname:this.portable?null:this.uname,atime:this.portable?null:this.atime,ctime:this.portable?null:this.ctime}),o&&this.warn("TAR_ENTRY_INFO",`stripping ${o} from absolute path`,{entry:this,path:o+this.path}),this.header.encode()&&!this.noPax&&super.write(new jue({atime:this.portable?null:this.atime,ctime:this.portable?null:this.ctime,gid:this.portable?null:this.gid,mtime:this.noMtime?null:this.mtime,path:this[lA](this.path),linkpath:this.type==="Link"?this[lA](this.linkpath):this.linkpath,size:this.size,uid:this.portable?null:this.uid,uname:this.portable?null:this.uname,dev:this.portable?null:this.readEntry.dev,ino:this.portable?null:this.readEntry.ino,nlink:this.portable?null:this.readEntry.nlink}).encode()),super.write(this.header.block),e.pipe(this)}[lA](e){return Wue(e,this.prefix)}[cx](e){return Vue(e,this.type==="Directory",this.portable)}write(e){let r=e.length;if(r>this.blockRemain)throw new Error("writing more to entry than is appropriate");return this.blockRemain-=r,super.write(e)}end(){return this.blockRemain&&super.write(Buffer.alloc(this.blockRemain)),super.end()}});ux.Sync=u3;ux.Tar=Alt;var flt=t=>t.isFile()?"File":t.isDirectory()?"Directory":t.isSymbolicLink()?"SymbolicLink":"Unsupported";Jue.exports=ux});var Ex=_((oUt,nAe)=>{"use strict";var mx=class{constructor(e,r){this.path=e||"./",this.absolute=r,this.entry=null,this.stat=null,this.readdir=null,this.pending=!1,this.ignore=!1,this.piped=!1}},plt=UE(),hlt=jU(),glt=rx(),C3=A3(),dlt=C3.Sync,mlt=C3.Tar,ylt=IP(),Xue=Buffer.alloc(1024),px=Symbol("onStat"),Ax=Symbol("ended"),cA=Symbol("queue"),WE=Symbol("current"),Od=Symbol("process"),fx=Symbol("processing"),Zue=Symbol("processJob"),uA=Symbol("jobs"),f3=Symbol("jobDone"),hx=Symbol("addFSEntry"),$ue=Symbol("addTarEntry"),d3=Symbol("stat"),m3=Symbol("readdir"),gx=Symbol("onreaddir"),dx=Symbol("pipe"),eAe=Symbol("entry"),p3=Symbol("entryOpt"),y3=Symbol("writeEntryClass"),rAe=Symbol("write"),h3=Symbol("ondrain"),yx=ve("fs"),tAe=ve("path"),Elt=sx(),g3=qE(),w3=Elt(class extends plt{constructor(e){super(e),e=e||Object.create(null),this.opt=e,this.file=e.file||"",this.cwd=e.cwd||process.cwd(),this.maxReadSize=e.maxReadSize,this.preservePaths=!!e.preservePaths,this.strict=!!e.strict,this.noPax=!!e.noPax,this.prefix=g3(e.prefix||""),this.linkCache=e.linkCache||new Map,this.statCache=e.statCache||new Map,this.readdirCache=e.readdirCache||new Map,this[y3]=C3,typeof e.onwarn=="function"&&this.on("warn",e.onwarn),this.portable=!!e.portable,this.zip=null,e.gzip?(typeof e.gzip!="object"&&(e.gzip={}),this.portable&&(e.gzip.portable=!0),this.zip=new hlt.Gzip(e.gzip),this.zip.on("data",r=>super.write(r)),this.zip.on("end",r=>super.end()),this.zip.on("drain",r=>this[h3]()),this.on("resume",r=>this.zip.resume())):this.on("drain",this[h3]),this.noDirRecurse=!!e.noDirRecurse,this.follow=!!e.follow,this.noMtime=!!e.noMtime,this.mtime=e.mtime||null,this.filter=typeof e.filter=="function"?e.filter:r=>!0,this[cA]=new ylt,this[uA]=0,this.jobs=+e.jobs||4,this[fx]=!1,this[Ax]=!1}[rAe](e){return super.write(e)}add(e){return this.write(e),this}end(e){return e&&this.write(e),this[Ax]=!0,this[Od](),this}write(e){if(this[Ax])throw new Error("write after end");return e instanceof glt?this[$ue](e):this[hx](e),this.flowing}[$ue](e){let r=g3(tAe.resolve(this.cwd,e.path));if(!this.filter(e.path,e))e.resume();else{let o=new mx(e.path,r,!1);o.entry=new mlt(e,this[p3](o)),o.entry.on("end",a=>this[f3](o)),this[uA]+=1,this[cA].push(o)}this[Od]()}[hx](e){let r=g3(tAe.resolve(this.cwd,e));this[cA].push(new mx(e,r)),this[Od]()}[d3](e){e.pending=!0,this[uA]+=1;let r=this.follow?"stat":"lstat";yx[r](e.absolute,(o,a)=>{e.pending=!1,this[uA]-=1,o?this.emit("error",o):this[px](e,a)})}[px](e,r){this.statCache.set(e.absolute,r),e.stat=r,this.filter(e.path,r)||(e.ignore=!0),this[Od]()}[m3](e){e.pending=!0,this[uA]+=1,yx.readdir(e.absolute,(r,o)=>{if(e.pending=!1,this[uA]-=1,r)return this.emit("error",r);this[gx](e,o)})}[gx](e,r){this.readdirCache.set(e.absolute,r),e.readdir=r,this[Od]()}[Od](){if(!this[fx]){this[fx]=!0;for(let e=this[cA].head;e!==null&&this[uA]<this.jobs;e=e.next)if(this[Zue](e.value),e.value.ignore){let r=e.next;this[cA].removeNode(e),e.next=r}this[fx]=!1,this[Ax]&&!this[cA].length&&this[uA]===0&&(this.zip?this.zip.end(Xue):(super.write(Xue),super.end()))}}get[WE](){return this[cA]&&this[cA].head&&this[cA].head.value}[f3](e){this[cA].shift(),this[uA]-=1,this[Od]()}[Zue](e){if(!e.pending){if(e.entry){e===this[WE]&&!e.piped&&this[dx](e);return}if(e.stat||(this.statCache.has(e.absolute)?this[px](e,this.statCache.get(e.absolute)):this[d3](e)),!!e.stat&&!e.ignore&&!(!this.noDirRecurse&&e.stat.isDirectory()&&!e.readdir&&(this.readdirCache.has(e.absolute)?this[gx](e,this.readdirCache.get(e.absolute)):this[m3](e),!e.readdir))){if(e.entry=this[eAe](e),!e.entry){e.ignore=!0;return}e===this[WE]&&!e.piped&&this[dx](e)}}}[p3](e){return{onwarn:(r,o,a)=>this.warn(r,o,a),noPax:this.noPax,cwd:this.cwd,absolute:e.absolute,preservePaths:this.preservePaths,maxReadSize:this.maxReadSize,strict:this.strict,portable:this.portable,linkCache:this.linkCache,statCache:this.statCache,noMtime:this.noMtime,mtime:this.mtime,prefix:this.prefix}}[eAe](e){this[uA]+=1;try{return new this[y3](e.path,this[p3](e)).on("end",()=>this[f3](e)).on("error",r=>this.emit("error",r))}catch(r){this.emit("error",r)}}[h3](){this[WE]&&this[WE].entry&&this[WE].entry.resume()}[dx](e){e.piped=!0,e.readdir&&e.readdir.forEach(a=>{let n=e.path,u=n==="./"?"":n.replace(/\/*$/,"/");this[hx](u+a)});let r=e.entry,o=this.zip;o?r.on("data",a=>{o.write(a)||r.pause()}):r.on("data",a=>{super.write(a)||r.pause()})}pause(){return this.zip&&this.zip.pause(),super.pause()}}),E3=class extends w3{constructor(e){super(e),this[y3]=dlt}pause(){}resume(){}[d3](e){let r=this.follow?"statSync":"lstatSync";this[px](e,yx[r](e.absolute))}[m3](e,r){this[gx](e,yx.readdirSync(e.absolute))}[dx](e){let r=e.entry,o=this.zip;e.readdir&&e.readdir.forEach(a=>{let n=e.path,u=n==="./"?"":n.replace(/\/*$/,"/");this[hx](u+a)}),o?r.on("data",a=>{o.write(a)}):r.on("data",a=>{super[rAe](a)})}};w3.Sync=E3;nAe.exports=w3});var eC=_(W1=>{"use strict";var Clt=UE(),wlt=ve("events").EventEmitter,Qa=ve("fs"),v3=Qa.writev;if(!v3){let t=process.binding("fs"),e=t.FSReqWrap||t.FSReqCallback;v3=(r,o,a,n)=>{let u=(p,h)=>n(p,h,o),A=new e;A.oncomplete=u,t.writeBuffers(r,o,a,A)}}var ZE=Symbol("_autoClose"),Wc=Symbol("_close"),Y1=Symbol("_ended"),jn=Symbol("_fd"),iAe=Symbol("_finished"),wh=Symbol("_flags"),I3=Symbol("_flush"),D3=Symbol("_handleChunk"),P3=Symbol("_makeBuf"),vx=Symbol("_mode"),Cx=Symbol("_needDrain"),JE=Symbol("_onerror"),$E=Symbol("_onopen"),B3=Symbol("_onread"),zE=Symbol("_onwrite"),Ih=Symbol("_open"),Gf=Symbol("_path"),Md=Symbol("_pos"),AA=Symbol("_queue"),VE=Symbol("_read"),sAe=Symbol("_readSize"),Ch=Symbol("_reading"),wx=Symbol("_remain"),oAe=Symbol("_size"),Ix=Symbol("_write"),KE=Symbol("_writing"),Bx=Symbol("_defaultFlag"),XE=Symbol("_errored"),Dx=class extends Clt{constructor(e,r){if(r=r||{},super(r),this.readable=!0,this.writable=!1,typeof e!="string")throw new TypeError("path must be a string");this[XE]=!1,this[jn]=typeof r.fd=="number"?r.fd:null,this[Gf]=e,this[sAe]=r.readSize||16*1024*1024,this[Ch]=!1,this[oAe]=typeof r.size=="number"?r.size:1/0,this[wx]=this[oAe],this[ZE]=typeof r.autoClose=="boolean"?r.autoClose:!0,typeof this[jn]=="number"?this[VE]():this[Ih]()}get fd(){return this[jn]}get path(){return this[Gf]}write(){throw new TypeError("this is a readable stream")}end(){throw new TypeError("this is a readable stream")}[Ih](){Qa.open(this[Gf],"r",(e,r)=>this[$E](e,r))}[$E](e,r){e?this[JE](e):(this[jn]=r,this.emit("open",r),this[VE]())}[P3](){return Buffer.allocUnsafe(Math.min(this[sAe],this[wx]))}[VE](){if(!this[Ch]){this[Ch]=!0;let e=this[P3]();if(e.length===0)return process.nextTick(()=>this[B3](null,0,e));Qa.read(this[jn],e,0,e.length,null,(r,o,a)=>this[B3](r,o,a))}}[B3](e,r,o){this[Ch]=!1,e?this[JE](e):this[D3](r,o)&&this[VE]()}[Wc](){if(this[ZE]&&typeof this[jn]=="number"){let e=this[jn];this[jn]=null,Qa.close(e,r=>r?this.emit("error",r):this.emit("close"))}}[JE](e){this[Ch]=!0,this[Wc](),this.emit("error",e)}[D3](e,r){let o=!1;return this[wx]-=e,e>0&&(o=super.write(e<r.length?r.slice(0,e):r)),(e===0||this[wx]<=0)&&(o=!1,this[Wc](),super.end()),o}emit(e,r){switch(e){case"prefinish":case"finish":break;case"drain":typeof this[jn]=="number"&&this[VE]();break;case"error":return this[XE]?void 0:(this[XE]=!0,super.emit(e,r));default:return super.emit(e,r)}}},S3=class extends Dx{[Ih](){let e=!0;try{this[$E](null,Qa.openSync(this[Gf],"r")),e=!1}finally{e&&this[Wc]()}}[VE](){let e=!0;try{if(!this[Ch]){this[Ch]=!0;do{let r=this[P3](),o=r.length===0?0:Qa.readSync(this[jn],r,0,r.length,null);if(!this[D3](o,r))break}while(!0);this[Ch]=!1}e=!1}finally{e&&this[Wc]()}}[Wc](){if(this[ZE]&&typeof this[jn]=="number"){let e=this[jn];this[jn]=null,Qa.closeSync(e),this.emit("close")}}},Px=class extends wlt{constructor(e,r){r=r||{},super(r),this.readable=!1,this.writable=!0,this[XE]=!1,this[KE]=!1,this[Y1]=!1,this[Cx]=!1,this[AA]=[],this[Gf]=e,this[jn]=typeof r.fd=="number"?r.fd:null,this[vx]=r.mode===void 0?438:r.mode,this[Md]=typeof r.start=="number"?r.start:null,this[ZE]=typeof r.autoClose=="boolean"?r.autoClose:!0;let o=this[Md]!==null?"r+":"w";this[Bx]=r.flags===void 0,this[wh]=this[Bx]?o:r.flags,this[jn]===null&&this[Ih]()}emit(e,r){if(e==="error"){if(this[XE])return;this[XE]=!0}return super.emit(e,r)}get fd(){return this[jn]}get path(){return this[Gf]}[JE](e){this[Wc](),this[KE]=!0,this.emit("error",e)}[Ih](){Qa.open(this[Gf],this[wh],this[vx],(e,r)=>this[$E](e,r))}[$E](e,r){this[Bx]&&this[wh]==="r+"&&e&&e.code==="ENOENT"?(this[wh]="w",this[Ih]()):e?this[JE](e):(this[jn]=r,this.emit("open",r),this[I3]())}end(e,r){return e&&this.write(e,r),this[Y1]=!0,!this[KE]&&!this[AA].length&&typeof this[jn]=="number"&&this[zE](null,0),this}write(e,r){return typeof e=="string"&&(e=Buffer.from(e,r)),this[Y1]?(this.emit("error",new Error("write() after end()")),!1):this[jn]===null||this[KE]||this[AA].length?(this[AA].push(e),this[Cx]=!0,!1):(this[KE]=!0,this[Ix](e),!0)}[Ix](e){Qa.write(this[jn],e,0,e.length,this[Md],(r,o)=>this[zE](r,o))}[zE](e,r){e?this[JE](e):(this[Md]!==null&&(this[Md]+=r),this[AA].length?this[I3]():(this[KE]=!1,this[Y1]&&!this[iAe]?(this[iAe]=!0,this[Wc](),this.emit("finish")):this[Cx]&&(this[Cx]=!1,this.emit("drain"))))}[I3](){if(this[AA].length===0)this[Y1]&&this[zE](null,0);else if(this[AA].length===1)this[Ix](this[AA].pop());else{let e=this[AA];this[AA]=[],v3(this[jn],e,this[Md],(r,o)=>this[zE](r,o))}}[Wc](){if(this[ZE]&&typeof this[jn]=="number"){let e=this[jn];this[jn]=null,Qa.close(e,r=>r?this.emit("error",r):this.emit("close"))}}},b3=class extends Px{[Ih](){let e;if(this[Bx]&&this[wh]==="r+")try{e=Qa.openSync(this[Gf],this[wh],this[vx])}catch(r){if(r.code==="ENOENT")return this[wh]="w",this[Ih]();throw r}else e=Qa.openSync(this[Gf],this[wh],this[vx]);this[$E](null,e)}[Wc](){if(this[ZE]&&typeof this[jn]=="number"){let e=this[jn];this[jn]=null,Qa.closeSync(e),this.emit("close")}}[Ix](e){let r=!0;try{this[zE](null,Qa.writeSync(this[jn],e,0,e.length,this[Md])),r=!1}finally{if(r)try{this[Wc]()}catch{}}}};W1.ReadStream=Dx;W1.ReadStreamSync=S3;W1.WriteStream=Px;W1.WriteStreamSync=b3});var Rx=_((cUt,pAe)=>{"use strict";var Ilt=sx(),Blt=jE(),vlt=ve("events"),Dlt=IP(),Plt=1024*1024,Slt=rx(),aAe=ix(),blt=jU(),x3=Buffer.from([31,139]),Zl=Symbol("state"),Ud=Symbol("writeEntry"),jf=Symbol("readEntry"),k3=Symbol("nextEntry"),lAe=Symbol("processEntry"),$l=Symbol("extendedHeader"),K1=Symbol("globalExtendedHeader"),Bh=Symbol("meta"),cAe=Symbol("emitMeta"),fi=Symbol("buffer"),Yf=Symbol("queue"),_d=Symbol("ended"),uAe=Symbol("emittedEnd"),Hd=Symbol("emit"),Fa=Symbol("unzip"),Sx=Symbol("consumeChunk"),bx=Symbol("consumeChunkSub"),Q3=Symbol("consumeBody"),AAe=Symbol("consumeMeta"),fAe=Symbol("consumeHeader"),xx=Symbol("consuming"),F3=Symbol("bufferConcat"),R3=Symbol("maybeEnd"),z1=Symbol("writing"),vh=Symbol("aborted"),kx=Symbol("onDone"),qd=Symbol("sawValidEntry"),Qx=Symbol("sawNullBlock"),Fx=Symbol("sawEOF"),xlt=t=>!0;pAe.exports=Ilt(class extends vlt{constructor(e){e=e||{},super(e),this.file=e.file||"",this[qd]=null,this.on(kx,r=>{(this[Zl]==="begin"||this[qd]===!1)&&this.warn("TAR_BAD_ARCHIVE","Unrecognized archive format")}),e.ondone?this.on(kx,e.ondone):this.on(kx,r=>{this.emit("prefinish"),this.emit("finish"),this.emit("end"),this.emit("close")}),this.strict=!!e.strict,this.maxMetaEntrySize=e.maxMetaEntrySize||Plt,this.filter=typeof e.filter=="function"?e.filter:xlt,this.writable=!0,this.readable=!1,this[Yf]=new Dlt,this[fi]=null,this[jf]=null,this[Ud]=null,this[Zl]="begin",this[Bh]="",this[$l]=null,this[K1]=null,this[_d]=!1,this[Fa]=null,this[vh]=!1,this[Qx]=!1,this[Fx]=!1,typeof e.onwarn=="function"&&this.on("warn",e.onwarn),typeof e.onentry=="function"&&this.on("entry",e.onentry)}[fAe](e,r){this[qd]===null&&(this[qd]=!1);let o;try{o=new Blt(e,r,this[$l],this[K1])}catch(a){return this.warn("TAR_ENTRY_INVALID",a)}if(o.nullBlock)this[Qx]?(this[Fx]=!0,this[Zl]==="begin"&&(this[Zl]="header"),this[Hd]("eof")):(this[Qx]=!0,this[Hd]("nullBlock"));else if(this[Qx]=!1,!o.cksumValid)this.warn("TAR_ENTRY_INVALID","checksum failure",{header:o});else if(!o.path)this.warn("TAR_ENTRY_INVALID","path is required",{header:o});else{let a=o.type;if(/^(Symbolic)?Link$/.test(a)&&!o.linkpath)this.warn("TAR_ENTRY_INVALID","linkpath required",{header:o});else if(!/^(Symbolic)?Link$/.test(a)&&o.linkpath)this.warn("TAR_ENTRY_INVALID","linkpath forbidden",{header:o});else{let n=this[Ud]=new Slt(o,this[$l],this[K1]);if(!this[qd])if(n.remain){let u=()=>{n.invalid||(this[qd]=!0)};n.on("end",u)}else this[qd]=!0;n.meta?n.size>this.maxMetaEntrySize?(n.ignore=!0,this[Hd]("ignoredEntry",n),this[Zl]="ignore",n.resume()):n.size>0&&(this[Bh]="",n.on("data",u=>this[Bh]+=u),this[Zl]="meta"):(this[$l]=null,n.ignore=n.ignore||!this.filter(n.path,n),n.ignore?(this[Hd]("ignoredEntry",n),this[Zl]=n.remain?"ignore":"header",n.resume()):(n.remain?this[Zl]="body":(this[Zl]="header",n.end()),this[jf]?this[Yf].push(n):(this[Yf].push(n),this[k3]())))}}}[lAe](e){let r=!0;return e?Array.isArray(e)?this.emit.apply(this,e):(this[jf]=e,this.emit("entry",e),e.emittedEnd||(e.on("end",o=>this[k3]()),r=!1)):(this[jf]=null,r=!1),r}[k3](){do;while(this[lAe](this[Yf].shift()));if(!this[Yf].length){let e=this[jf];!e||e.flowing||e.size===e.remain?this[z1]||this.emit("drain"):e.once("drain",o=>this.emit("drain"))}}[Q3](e,r){let o=this[Ud],a=o.blockRemain,n=a>=e.length&&r===0?e:e.slice(r,r+a);return o.write(n),o.blockRemain||(this[Zl]="header",this[Ud]=null,o.end()),n.length}[AAe](e,r){let o=this[Ud],a=this[Q3](e,r);return this[Ud]||this[cAe](o),a}[Hd](e,r,o){!this[Yf].length&&!this[jf]?this.emit(e,r,o):this[Yf].push([e,r,o])}[cAe](e){switch(this[Hd]("meta",this[Bh]),e.type){case"ExtendedHeader":case"OldExtendedHeader":this[$l]=aAe.parse(this[Bh],this[$l],!1);break;case"GlobalExtendedHeader":this[K1]=aAe.parse(this[Bh],this[K1],!0);break;case"NextFileHasLongPath":case"OldGnuLongPath":this[$l]=this[$l]||Object.create(null),this[$l].path=this[Bh].replace(/\0.*/,"");break;case"NextFileHasLongLinkpath":this[$l]=this[$l]||Object.create(null),this[$l].linkpath=this[Bh].replace(/\0.*/,"");break;default:throw new Error("unknown meta: "+e.type)}}abort(e){this[vh]=!0,this.emit("abort",e),this.warn("TAR_ABORT",e,{recoverable:!1})}write(e){if(this[vh])return;if(this[Fa]===null&&e){if(this[fi]&&(e=Buffer.concat([this[fi],e]),this[fi]=null),e.length<x3.length)return this[fi]=e,!0;for(let o=0;this[Fa]===null&&o<x3.length;o++)e[o]!==x3[o]&&(this[Fa]=!1);if(this[Fa]===null){let o=this[_d];this[_d]=!1,this[Fa]=new blt.Unzip,this[Fa].on("data",n=>this[Sx](n)),this[Fa].on("error",n=>this.abort(n)),this[Fa].on("end",n=>{this[_d]=!0,this[Sx]()}),this[z1]=!0;let a=this[Fa][o?"end":"write"](e);return this[z1]=!1,a}}this[z1]=!0,this[Fa]?this[Fa].write(e):this[Sx](e),this[z1]=!1;let r=this[Yf].length?!1:this[jf]?this[jf].flowing:!0;return!r&&!this[Yf].length&&this[jf].once("drain",o=>this.emit("drain")),r}[F3](e){e&&!this[vh]&&(this[fi]=this[fi]?Buffer.concat([this[fi],e]):e)}[R3](){if(this[_d]&&!this[uAe]&&!this[vh]&&!this[xx]){this[uAe]=!0;let e=this[Ud];if(e&&e.blockRemain){let r=this[fi]?this[fi].length:0;this.warn("TAR_BAD_ARCHIVE",`Truncated input (needed ${e.blockRemain} more bytes, only ${r} available)`,{entry:e}),this[fi]&&e.write(this[fi]),e.end()}this[Hd](kx)}}[Sx](e){if(this[xx])this[F3](e);else if(!e&&!this[fi])this[R3]();else{if(this[xx]=!0,this[fi]){this[F3](e);let r=this[fi];this[fi]=null,this[bx](r)}else this[bx](e);for(;this[fi]&&this[fi].length>=512&&!this[vh]&&!this[Fx];){let r=this[fi];this[fi]=null,this[bx](r)}this[xx]=!1}(!this[fi]||this[_d])&&this[R3]()}[bx](e){let r=0,o=e.length;for(;r+512<=o&&!this[vh]&&!this[Fx];)switch(this[Zl]){case"begin":case"header":this[fAe](e,r),r+=512;break;case"ignore":case"body":r+=this[Q3](e,r);break;case"meta":r+=this[AAe](e,r);break;default:throw new Error("invalid state: "+this[Zl])}r<o&&(this[fi]?this[fi]=Buffer.concat([e.slice(r),this[fi]]):this[fi]=e.slice(r))}end(e){this[vh]||(this[Fa]?this[Fa].end(e):(this[_d]=!0,this.write(e)))}})});var Tx=_((uUt,mAe)=>{"use strict";var klt=OE(),gAe=Rx(),tC=ve("fs"),Qlt=eC(),hAe=ve("path"),T3=YE();mAe.exports=(t,e,r)=>{typeof t=="function"?(r=t,e=null,t={}):Array.isArray(t)&&(e=t,t={}),typeof e=="function"&&(r=e,e=null),e?e=Array.from(e):e=[];let o=klt(t);if(o.sync&&typeof r=="function")throw new TypeError("callback not supported for sync tar functions");if(!o.file&&typeof r=="function")throw new TypeError("callback only supported with file option");return e.length&&Rlt(o,e),o.noResume||Flt(o),o.file&&o.sync?Tlt(o):o.file?Llt(o,r):dAe(o)};var Flt=t=>{let e=t.onentry;t.onentry=e?r=>{e(r),r.resume()}:r=>r.resume()},Rlt=(t,e)=>{let r=new Map(e.map(n=>[T3(n),!0])),o=t.filter,a=(n,u)=>{let A=u||hAe.parse(n).root||".",p=n===A?!1:r.has(n)?r.get(n):a(hAe.dirname(n),A);return r.set(n,p),p};t.filter=o?(n,u)=>o(n,u)&&a(T3(n)):n=>a(T3(n))},Tlt=t=>{let e=dAe(t),r=t.file,o=!0,a;try{let n=tC.statSync(r),u=t.maxReadSize||16*1024*1024;if(n.size<u)e.end(tC.readFileSync(r));else{let A=0,p=Buffer.allocUnsafe(u);for(a=tC.openSync(r,"r");A<n.size;){let h=tC.readSync(a,p,0,u,A);A+=h,e.write(p.slice(0,h))}e.end()}o=!1}finally{if(o&&a)try{tC.closeSync(a)}catch{}}},Llt=(t,e)=>{let r=new gAe(t),o=t.maxReadSize||16*1024*1024,a=t.file,n=new Promise((u,A)=>{r.on("error",A),r.on("end",u),tC.stat(a,(p,h)=>{if(p)A(p);else{let E=new Qlt.ReadStream(a,{readSize:o,size:h.size});E.on("error",A),E.pipe(r)}})});return e?n.then(e,e):n},dAe=t=>new gAe(t)});var BAe=_((AUt,IAe)=>{"use strict";var Nlt=OE(),Lx=Ex(),yAe=eC(),EAe=Tx(),CAe=ve("path");IAe.exports=(t,e,r)=>{if(typeof e=="function"&&(r=e),Array.isArray(t)&&(e=t,t={}),!e||!Array.isArray(e)||!e.length)throw new TypeError("no files or directories specified");e=Array.from(e);let o=Nlt(t);if(o.sync&&typeof r=="function")throw new TypeError("callback not supported for sync tar functions");if(!o.file&&typeof r=="function")throw new TypeError("callback only supported with file option");return o.file&&o.sync?Olt(o,e):o.file?Mlt(o,e,r):o.sync?Ult(o,e):_lt(o,e)};var Olt=(t,e)=>{let r=new Lx.Sync(t),o=new yAe.WriteStreamSync(t.file,{mode:t.mode||438});r.pipe(o),wAe(r,e)},Mlt=(t,e,r)=>{let o=new Lx(t),a=new yAe.WriteStream(t.file,{mode:t.mode||438});o.pipe(a);let n=new Promise((u,A)=>{a.on("error",A),a.on("close",u),o.on("error",A)});return L3(o,e),r?n.then(r,r):n},wAe=(t,e)=>{e.forEach(r=>{r.charAt(0)==="@"?EAe({file:CAe.resolve(t.cwd,r.substr(1)),sync:!0,noResume:!0,onentry:o=>t.add(o)}):t.add(r)}),t.end()},L3=(t,e)=>{for(;e.length;){let r=e.shift();if(r.charAt(0)==="@")return EAe({file:CAe.resolve(t.cwd,r.substr(1)),noResume:!0,onentry:o=>t.add(o)}).then(o=>L3(t,e));t.add(r)}t.end()},Ult=(t,e)=>{let r=new Lx.Sync(t);return wAe(r,e),r},_lt=(t,e)=>{let r=new Lx(t);return L3(r,e),r}});var N3=_((fUt,kAe)=>{"use strict";var Hlt=OE(),vAe=Ex(),fl=ve("fs"),DAe=eC(),PAe=Tx(),SAe=ve("path"),bAe=jE();kAe.exports=(t,e,r)=>{let o=Hlt(t);if(!o.file)throw new TypeError("file is required");if(o.gzip)throw new TypeError("cannot append to compressed archives");if(!e||!Array.isArray(e)||!e.length)throw new TypeError("no files or directories specified");return e=Array.from(e),o.sync?qlt(o,e):jlt(o,e,r)};var qlt=(t,e)=>{let r=new vAe.Sync(t),o=!0,a,n;try{try{a=fl.openSync(t.file,"r+")}catch(p){if(p.code==="ENOENT")a=fl.openSync(t.file,"w+");else throw p}let u=fl.fstatSync(a),A=Buffer.alloc(512);e:for(n=0;n<u.size;n+=512){for(let E=0,I=0;E<512;E+=I){if(I=fl.readSync(a,A,E,A.length-E,n+E),n===0&&A[0]===31&&A[1]===139)throw new Error("cannot append to compressed archives");if(!I)break e}let p=new bAe(A);if(!p.cksumValid)break;let h=512*Math.ceil(p.size/512);if(n+h+512>u.size)break;n+=h,t.mtimeCache&&t.mtimeCache.set(p.path,p.mtime)}o=!1,Glt(t,r,n,a,e)}finally{if(o)try{fl.closeSync(a)}catch{}}},Glt=(t,e,r,o,a)=>{let n=new DAe.WriteStreamSync(t.file,{fd:o,start:r});e.pipe(n),Ylt(e,a)},jlt=(t,e,r)=>{e=Array.from(e);let o=new vAe(t),a=(u,A,p)=>{let h=(C,R)=>{C?fl.close(u,N=>p(C)):p(null,R)},E=0;if(A===0)return h(null,0);let I=0,v=Buffer.alloc(512),x=(C,R)=>{if(C)return h(C);if(I+=R,I<512&&R)return fl.read(u,v,I,v.length-I,E+I,x);if(E===0&&v[0]===31&&v[1]===139)return h(new Error("cannot append to compressed archives"));if(I<512)return h(null,E);let N=new bAe(v);if(!N.cksumValid)return h(null,E);let U=512*Math.ceil(N.size/512);if(E+U+512>A||(E+=U+512,E>=A))return h(null,E);t.mtimeCache&&t.mtimeCache.set(N.path,N.mtime),I=0,fl.read(u,v,0,512,E,x)};fl.read(u,v,0,512,E,x)},n=new Promise((u,A)=>{o.on("error",A);let p="r+",h=(E,I)=>{if(E&&E.code==="ENOENT"&&p==="r+")return p="w+",fl.open(t.file,p,h);if(E)return A(E);fl.fstat(I,(v,x)=>{if(v)return fl.close(I,()=>A(v));a(I,x.size,(C,R)=>{if(C)return A(C);let N=new DAe.WriteStream(t.file,{fd:I,start:R});o.pipe(N),N.on("error",A),N.on("close",u),xAe(o,e)})})};fl.open(t.file,p,h)});return r?n.then(r,r):n},Ylt=(t,e)=>{e.forEach(r=>{r.charAt(0)==="@"?PAe({file:SAe.resolve(t.cwd,r.substr(1)),sync:!0,noResume:!0,onentry:o=>t.add(o)}):t.add(r)}),t.end()},xAe=(t,e)=>{for(;e.length;){let r=e.shift();if(r.charAt(0)==="@")return PAe({file:SAe.resolve(t.cwd,r.substr(1)),noResume:!0,onentry:o=>t.add(o)}).then(o=>xAe(t,e));t.add(r)}t.end()}});var FAe=_((pUt,QAe)=>{"use strict";var Wlt=OE(),Klt=N3();QAe.exports=(t,e,r)=>{let o=Wlt(t);if(!o.file)throw new TypeError("file is required");if(o.gzip)throw new TypeError("cannot append to compressed archives");if(!e||!Array.isArray(e)||!e.length)throw new TypeError("no files or directories specified");return e=Array.from(e),zlt(o),Klt(o,e,r)};var zlt=t=>{let e=t.filter;t.mtimeCache||(t.mtimeCache=new Map),t.filter=e?(r,o)=>e(r,o)&&!(t.mtimeCache.get(r)>o.mtime):(r,o)=>!(t.mtimeCache.get(r)>o.mtime)}});var LAe=_((hUt,TAe)=>{var{promisify:RAe}=ve("util"),Dh=ve("fs"),Vlt=t=>{if(!t)t={mode:511,fs:Dh};else if(typeof t=="object")t={mode:511,fs:Dh,...t};else if(typeof t=="number")t={mode:t,fs:Dh};else if(typeof t=="string")t={mode:parseInt(t,8),fs:Dh};else throw new TypeError("invalid options argument");return t.mkdir=t.mkdir||t.fs.mkdir||Dh.mkdir,t.mkdirAsync=RAe(t.mkdir),t.stat=t.stat||t.fs.stat||Dh.stat,t.statAsync=RAe(t.stat),t.statSync=t.statSync||t.fs.statSync||Dh.statSync,t.mkdirSync=t.mkdirSync||t.fs.mkdirSync||Dh.mkdirSync,t};TAe.exports=Vlt});var OAe=_((gUt,NAe)=>{var Jlt=process.platform,{resolve:Xlt,parse:Zlt}=ve("path"),$lt=t=>{if(/\0/.test(t))throw Object.assign(new TypeError("path must be a string without null bytes"),{path:t,code:"ERR_INVALID_ARG_VALUE"});if(t=Xlt(t),Jlt==="win32"){let e=/[*|"<>?:]/,{root:r}=Zlt(t);if(e.test(t.substr(r.length)))throw Object.assign(new Error("Illegal characters in path."),{path:t,code:"EINVAL"})}return t};NAe.exports=$lt});var qAe=_((dUt,HAe)=>{var{dirname:MAe}=ve("path"),UAe=(t,e,r=void 0)=>r===e?Promise.resolve():t.statAsync(e).then(o=>o.isDirectory()?r:void 0,o=>o.code==="ENOENT"?UAe(t,MAe(e),e):void 0),_Ae=(t,e,r=void 0)=>{if(r!==e)try{return t.statSync(e).isDirectory()?r:void 0}catch(o){return o.code==="ENOENT"?_Ae(t,MAe(e),e):void 0}};HAe.exports={findMade:UAe,findMadeSync:_Ae}});var U3=_((mUt,jAe)=>{var{dirname:GAe}=ve("path"),O3=(t,e,r)=>{e.recursive=!1;let o=GAe(t);return o===t?e.mkdirAsync(t,e).catch(a=>{if(a.code!=="EISDIR")throw a}):e.mkdirAsync(t,e).then(()=>r||t,a=>{if(a.code==="ENOENT")return O3(o,e).then(n=>O3(t,e,n));if(a.code!=="EEXIST"&&a.code!=="EROFS")throw a;return e.statAsync(t).then(n=>{if(n.isDirectory())return r;throw a},()=>{throw a})})},M3=(t,e,r)=>{let o=GAe(t);if(e.recursive=!1,o===t)try{return e.mkdirSync(t,e)}catch(a){if(a.code!=="EISDIR")throw a;return}try{return e.mkdirSync(t,e),r||t}catch(a){if(a.code==="ENOENT")return M3(t,e,M3(o,e,r));if(a.code!=="EEXIST"&&a.code!=="EROFS")throw a;try{if(!e.statSync(t).isDirectory())throw a}catch{throw a}}};jAe.exports={mkdirpManual:O3,mkdirpManualSync:M3}});var KAe=_((yUt,WAe)=>{var{dirname:YAe}=ve("path"),{findMade:ect,findMadeSync:tct}=qAe(),{mkdirpManual:rct,mkdirpManualSync:nct}=U3(),ict=(t,e)=>(e.recursive=!0,YAe(t)===t?e.mkdirAsync(t,e):ect(e,t).then(o=>e.mkdirAsync(t,e).then(()=>o).catch(a=>{if(a.code==="ENOENT")return rct(t,e);throw a}))),sct=(t,e)=>{if(e.recursive=!0,YAe(t)===t)return e.mkdirSync(t,e);let o=tct(e,t);try{return e.mkdirSync(t,e),o}catch(a){if(a.code==="ENOENT")return nct(t,e);throw a}};WAe.exports={mkdirpNative:ict,mkdirpNativeSync:sct}});var XAe=_((EUt,JAe)=>{var zAe=ve("fs"),oct=process.version,_3=oct.replace(/^v/,"").split("."),VAe=+_3[0]>10||+_3[0]==10&&+_3[1]>=12,act=VAe?t=>t.mkdir===zAe.mkdir:()=>!1,lct=VAe?t=>t.mkdirSync===zAe.mkdirSync:()=>!1;JAe.exports={useNative:act,useNativeSync:lct}});var nfe=_((CUt,rfe)=>{var rC=LAe(),nC=OAe(),{mkdirpNative:ZAe,mkdirpNativeSync:$Ae}=KAe(),{mkdirpManual:efe,mkdirpManualSync:tfe}=U3(),{useNative:cct,useNativeSync:uct}=XAe(),iC=(t,e)=>(t=nC(t),e=rC(e),cct(e)?ZAe(t,e):efe(t,e)),Act=(t,e)=>(t=nC(t),e=rC(e),uct(e)?$Ae(t,e):tfe(t,e));iC.sync=Act;iC.native=(t,e)=>ZAe(nC(t),rC(e));iC.manual=(t,e)=>efe(nC(t),rC(e));iC.nativeSync=(t,e)=>$Ae(nC(t),rC(e));iC.manualSync=(t,e)=>tfe(nC(t),rC(e));rfe.exports=iC});var ufe=_((wUt,cfe)=>{"use strict";var ec=ve("fs"),Gd=ve("path"),fct=ec.lchown?"lchown":"chown",pct=ec.lchownSync?"lchownSync":"chownSync",sfe=ec.lchown&&!process.version.match(/v1[1-9]+\./)&&!process.version.match(/v10\.[6-9]/),ife=(t,e,r)=>{try{return ec[pct](t,e,r)}catch(o){if(o.code!=="ENOENT")throw o}},hct=(t,e,r)=>{try{return ec.chownSync(t,e,r)}catch(o){if(o.code!=="ENOENT")throw o}},gct=sfe?(t,e,r,o)=>a=>{!a||a.code!=="EISDIR"?o(a):ec.chown(t,e,r,o)}:(t,e,r,o)=>o,H3=sfe?(t,e,r)=>{try{return ife(t,e,r)}catch(o){if(o.code!=="EISDIR")throw o;hct(t,e,r)}}:(t,e,r)=>ife(t,e,r),dct=process.version,ofe=(t,e,r)=>ec.readdir(t,e,r),mct=(t,e)=>ec.readdirSync(t,e);/^v4\./.test(dct)&&(ofe=(t,e,r)=>ec.readdir(t,r));var Nx=(t,e,r,o)=>{ec[fct](t,e,r,gct(t,e,r,a=>{o(a&&a.code!=="ENOENT"?a:null)}))},afe=(t,e,r,o,a)=>{if(typeof e=="string")return ec.lstat(Gd.resolve(t,e),(n,u)=>{if(n)return a(n.code!=="ENOENT"?n:null);u.name=e,afe(t,u,r,o,a)});if(e.isDirectory())q3(Gd.resolve(t,e.name),r,o,n=>{if(n)return a(n);let u=Gd.resolve(t,e.name);Nx(u,r,o,a)});else{let n=Gd.resolve(t,e.name);Nx(n,r,o,a)}},q3=(t,e,r,o)=>{ofe(t,{withFileTypes:!0},(a,n)=>{if(a){if(a.code==="ENOENT")return o();if(a.code!=="ENOTDIR"&&a.code!=="ENOTSUP")return o(a)}if(a||!n.length)return Nx(t,e,r,o);let u=n.length,A=null,p=h=>{if(!A){if(h)return o(A=h);if(--u===0)return Nx(t,e,r,o)}};n.forEach(h=>afe(t,h,e,r,p))})},yct=(t,e,r,o)=>{if(typeof e=="string")try{let a=ec.lstatSync(Gd.resolve(t,e));a.name=e,e=a}catch(a){if(a.code==="ENOENT")return;throw a}e.isDirectory()&&lfe(Gd.resolve(t,e.name),r,o),H3(Gd.resolve(t,e.name),r,o)},lfe=(t,e,r)=>{let o;try{o=mct(t,{withFileTypes:!0})}catch(a){if(a.code==="ENOENT")return;if(a.code==="ENOTDIR"||a.code==="ENOTSUP")return H3(t,e,r);throw a}return o&&o.length&&o.forEach(a=>yct(t,a,e,r)),H3(t,e,r)};cfe.exports=q3;q3.sync=lfe});var hfe=_((IUt,G3)=>{"use strict";var Afe=nfe(),tc=ve("fs"),Ox=ve("path"),ffe=ufe(),Kc=qE(),Mx=class extends Error{constructor(e,r){super("Cannot extract through symbolic link"),this.path=r,this.symlink=e}get name(){return"SylinkError"}},Ux=class extends Error{constructor(e,r){super(r+": Cannot cd into '"+e+"'"),this.path=e,this.code=r}get name(){return"CwdError"}},_x=(t,e)=>t.get(Kc(e)),V1=(t,e,r)=>t.set(Kc(e),r),Ect=(t,e)=>{tc.stat(t,(r,o)=>{(r||!o.isDirectory())&&(r=new Ux(t,r&&r.code||"ENOTDIR")),e(r)})};G3.exports=(t,e,r)=>{t=Kc(t);let o=e.umask,a=e.mode|448,n=(a&o)!==0,u=e.uid,A=e.gid,p=typeof u=="number"&&typeof A=="number"&&(u!==e.processUid||A!==e.processGid),h=e.preserve,E=e.unlink,I=e.cache,v=Kc(e.cwd),x=(N,U)=>{N?r(N):(V1(I,t,!0),U&&p?ffe(U,u,A,V=>x(V)):n?tc.chmod(t,a,r):r())};if(I&&_x(I,t)===!0)return x();if(t===v)return Ect(t,x);if(h)return Afe(t,{mode:a}).then(N=>x(null,N),x);let R=Kc(Ox.relative(v,t)).split("/");Hx(v,R,a,I,E,v,null,x)};var Hx=(t,e,r,o,a,n,u,A)=>{if(!e.length)return A(null,u);let p=e.shift(),h=Kc(Ox.resolve(t+"/"+p));if(_x(o,h))return Hx(h,e,r,o,a,n,u,A);tc.mkdir(h,r,pfe(h,e,r,o,a,n,u,A))},pfe=(t,e,r,o,a,n,u,A)=>p=>{p?tc.lstat(t,(h,E)=>{if(h)h.path=h.path&&Kc(h.path),A(h);else if(E.isDirectory())Hx(t,e,r,o,a,n,u,A);else if(a)tc.unlink(t,I=>{if(I)return A(I);tc.mkdir(t,r,pfe(t,e,r,o,a,n,u,A))});else{if(E.isSymbolicLink())return A(new Mx(t,t+"/"+e.join("/")));A(p)}}):(u=u||t,Hx(t,e,r,o,a,n,u,A))},Cct=t=>{let e=!1,r="ENOTDIR";try{e=tc.statSync(t).isDirectory()}catch(o){r=o.code}finally{if(!e)throw new Ux(t,r)}};G3.exports.sync=(t,e)=>{t=Kc(t);let r=e.umask,o=e.mode|448,a=(o&r)!==0,n=e.uid,u=e.gid,A=typeof n=="number"&&typeof u=="number"&&(n!==e.processUid||u!==e.processGid),p=e.preserve,h=e.unlink,E=e.cache,I=Kc(e.cwd),v=N=>{V1(E,t,!0),N&&A&&ffe.sync(N,n,u),a&&tc.chmodSync(t,o)};if(E&&_x(E,t)===!0)return v();if(t===I)return Cct(I),v();if(p)return v(Afe.sync(t,o));let C=Kc(Ox.relative(I,t)).split("/"),R=null;for(let N=C.shift(),U=I;N&&(U+="/"+N);N=C.shift())if(U=Kc(Ox.resolve(U)),!_x(E,U))try{tc.mkdirSync(U,o),R=R||U,V1(E,U,!0)}catch{let te=tc.lstatSync(U);if(te.isDirectory()){V1(E,U,!0);continue}else if(h){tc.unlinkSync(U),tc.mkdirSync(U,o),R=R||U,V1(E,U,!0);continue}else if(te.isSymbolicLink())return new Mx(U,U+"/"+C.join("/"))}return v(R)}});var Y3=_((BUt,gfe)=>{var j3=Object.create(null),{hasOwnProperty:wct}=Object.prototype;gfe.exports=t=>(wct.call(j3,t)||(j3[t]=t.normalize("NFKD")),j3[t])});var Efe=_((vUt,yfe)=>{var dfe=ve("assert"),Ict=Y3(),Bct=YE(),{join:mfe}=ve("path"),vct=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform,Dct=vct==="win32";yfe.exports=()=>{let t=new Map,e=new Map,r=h=>h.split("/").slice(0,-1).reduce((I,v)=>(I.length&&(v=mfe(I[I.length-1],v)),I.push(v||"/"),I),[]),o=new Set,a=h=>{let E=e.get(h);if(!E)throw new Error("function does not have any path reservations");return{paths:E.paths.map(I=>t.get(I)),dirs:[...E.dirs].map(I=>t.get(I))}},n=h=>{let{paths:E,dirs:I}=a(h);return E.every(v=>v[0]===h)&&I.every(v=>v[0]instanceof Set&&v[0].has(h))},u=h=>o.has(h)||!n(h)?!1:(o.add(h),h(()=>A(h)),!0),A=h=>{if(!o.has(h))return!1;let{paths:E,dirs:I}=e.get(h),v=new Set;return E.forEach(x=>{let C=t.get(x);dfe.equal(C[0],h),C.length===1?t.delete(x):(C.shift(),typeof C[0]=="function"?v.add(C[0]):C[0].forEach(R=>v.add(R)))}),I.forEach(x=>{let C=t.get(x);dfe(C[0]instanceof Set),C[0].size===1&&C.length===1?t.delete(x):C[0].size===1?(C.shift(),v.add(C[0])):C[0].delete(h)}),o.delete(h),v.forEach(x=>u(x)),!0};return{check:n,reserve:(h,E)=>{h=Dct?["win32 parallelization disabled"]:h.map(v=>Ict(Bct(mfe(v))).toLowerCase());let I=new Set(h.map(v=>r(v)).reduce((v,x)=>v.concat(x)));return e.set(E,{dirs:I,paths:h}),h.forEach(v=>{let x=t.get(v);x?x.push(E):t.set(v,[E])}),I.forEach(v=>{let x=t.get(v);x?x[x.length-1]instanceof Set?x[x.length-1].add(E):x.push(new Set([E])):t.set(v,[new Set([E])])}),u(E)}}}});var Ife=_((DUt,wfe)=>{var Pct=process.platform,Sct=Pct==="win32",bct=global.__FAKE_TESTING_FS__||ve("fs"),{O_CREAT:xct,O_TRUNC:kct,O_WRONLY:Qct,UV_FS_O_FILEMAP:Cfe=0}=bct.constants,Fct=Sct&&!!Cfe,Rct=512*1024,Tct=Cfe|kct|xct|Qct;wfe.exports=Fct?t=>t<Rct?Tct:"w":()=>"w"});var e_=_((PUt,Nfe)=>{"use strict";var Lct=ve("assert"),Nct=Rx(),vn=ve("fs"),Oct=eC(),Wf=ve("path"),Rfe=hfe(),Bfe=e3(),Mct=Efe(),Uct=t3(),pl=qE(),_ct=YE(),Hct=Y3(),vfe=Symbol("onEntry"),z3=Symbol("checkFs"),Dfe=Symbol("checkFs2"),jx=Symbol("pruneCache"),V3=Symbol("isReusable"),rc=Symbol("makeFs"),J3=Symbol("file"),X3=Symbol("directory"),Yx=Symbol("link"),Pfe=Symbol("symlink"),Sfe=Symbol("hardlink"),bfe=Symbol("unsupported"),xfe=Symbol("checkPath"),Ph=Symbol("mkdir"),To=Symbol("onError"),qx=Symbol("pending"),kfe=Symbol("pend"),sC=Symbol("unpend"),W3=Symbol("ended"),K3=Symbol("maybeClose"),Z3=Symbol("skip"),J1=Symbol("doChown"),X1=Symbol("uid"),Z1=Symbol("gid"),$1=Symbol("checkedCwd"),Tfe=ve("crypto"),Lfe=Ife(),qct=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform,e2=qct==="win32",Gct=(t,e)=>{if(!e2)return vn.unlink(t,e);let r=t+".DELETE."+Tfe.randomBytes(16).toString("hex");vn.rename(t,r,o=>{if(o)return e(o);vn.unlink(r,e)})},jct=t=>{if(!e2)return vn.unlinkSync(t);let e=t+".DELETE."+Tfe.randomBytes(16).toString("hex");vn.renameSync(t,e),vn.unlinkSync(e)},Qfe=(t,e,r)=>t===t>>>0?t:e===e>>>0?e:r,Ffe=t=>Hct(_ct(pl(t))).toLowerCase(),Yct=(t,e)=>{e=Ffe(e);for(let r of t.keys()){let o=Ffe(r);(o===e||o.indexOf(e+"/")===0)&&t.delete(r)}},Wct=t=>{for(let e of t.keys())t.delete(e)},t2=class extends Nct{constructor(e){if(e||(e={}),e.ondone=r=>{this[W3]=!0,this[K3]()},super(e),this[$1]=!1,this.reservations=Mct(),this.transform=typeof e.transform=="function"?e.transform:null,this.writable=!0,this.readable=!1,this[qx]=0,this[W3]=!1,this.dirCache=e.dirCache||new Map,typeof e.uid=="number"||typeof e.gid=="number"){if(typeof e.uid!="number"||typeof e.gid!="number")throw new TypeError("cannot set owner without number uid and gid");if(e.preserveOwner)throw new TypeError("cannot preserve owner in archive and also set owner explicitly");this.uid=e.uid,this.gid=e.gid,this.setOwner=!0}else this.uid=null,this.gid=null,this.setOwner=!1;e.preserveOwner===void 0&&typeof e.uid!="number"?this.preserveOwner=process.getuid&&process.getuid()===0:this.preserveOwner=!!e.preserveOwner,this.processUid=(this.preserveOwner||this.setOwner)&&process.getuid?process.getuid():null,this.processGid=(this.preserveOwner||this.setOwner)&&process.getgid?process.getgid():null,this.forceChown=e.forceChown===!0,this.win32=!!e.win32||e2,this.newer=!!e.newer,this.keep=!!e.keep,this.noMtime=!!e.noMtime,this.preservePaths=!!e.preservePaths,this.unlink=!!e.unlink,this.cwd=pl(Wf.resolve(e.cwd||process.cwd())),this.strip=+e.strip||0,this.processUmask=e.noChmod?0:process.umask(),this.umask=typeof e.umask=="number"?e.umask:this.processUmask,this.dmode=e.dmode||511&~this.umask,this.fmode=e.fmode||438&~this.umask,this.on("entry",r=>this[vfe](r))}warn(e,r,o={}){return(e==="TAR_BAD_ARCHIVE"||e==="TAR_ABORT")&&(o.recoverable=!1),super.warn(e,r,o)}[K3](){this[W3]&&this[qx]===0&&(this.emit("prefinish"),this.emit("finish"),this.emit("end"),this.emit("close"))}[xfe](e){if(this.strip){let r=pl(e.path).split("/");if(r.length<this.strip)return!1;if(e.path=r.slice(this.strip).join("/"),e.type==="Link"){let o=pl(e.linkpath).split("/");if(o.length>=this.strip)e.linkpath=o.slice(this.strip).join("/");else return!1}}if(!this.preservePaths){let r=pl(e.path),o=r.split("/");if(o.includes("..")||e2&&/^[a-z]:\.\.$/i.test(o[0]))return this.warn("TAR_ENTRY_ERROR","path contains '..'",{entry:e,path:r}),!1;let[a,n]=Uct(r);a&&(e.path=n,this.warn("TAR_ENTRY_INFO",`stripping ${a} from absolute path`,{entry:e,path:r}))}if(Wf.isAbsolute(e.path)?e.absolute=pl(Wf.resolve(e.path)):e.absolute=pl(Wf.resolve(this.cwd,e.path)),!this.preservePaths&&e.absolute.indexOf(this.cwd+"/")!==0&&e.absolute!==this.cwd)return this.warn("TAR_ENTRY_ERROR","path escaped extraction target",{entry:e,path:pl(e.path),resolvedPath:e.absolute,cwd:this.cwd}),!1;if(e.absolute===this.cwd&&e.type!=="Directory"&&e.type!=="GNUDumpDir")return!1;if(this.win32){let{root:r}=Wf.win32.parse(e.absolute);e.absolute=r+Bfe.encode(e.absolute.substr(r.length));let{root:o}=Wf.win32.parse(e.path);e.path=o+Bfe.encode(e.path.substr(o.length))}return!0}[vfe](e){if(!this[xfe](e))return e.resume();switch(Lct.equal(typeof e.absolute,"string"),e.type){case"Directory":case"GNUDumpDir":e.mode&&(e.mode=e.mode|448);case"File":case"OldFile":case"ContiguousFile":case"Link":case"SymbolicLink":return this[z3](e);case"CharacterDevice":case"BlockDevice":case"FIFO":default:return this[bfe](e)}}[To](e,r){e.name==="CwdError"?this.emit("error",e):(this.warn("TAR_ENTRY_ERROR",e,{entry:r}),this[sC](),r.resume())}[Ph](e,r,o){Rfe(pl(e),{uid:this.uid,gid:this.gid,processUid:this.processUid,processGid:this.processGid,umask:this.processUmask,preserve:this.preservePaths,unlink:this.unlink,cache:this.dirCache,cwd:this.cwd,mode:r,noChmod:this.noChmod},o)}[J1](e){return this.forceChown||this.preserveOwner&&(typeof e.uid=="number"&&e.uid!==this.processUid||typeof e.gid=="number"&&e.gid!==this.processGid)||typeof this.uid=="number"&&this.uid!==this.processUid||typeof this.gid=="number"&&this.gid!==this.processGid}[X1](e){return Qfe(this.uid,e.uid,this.processUid)}[Z1](e){return Qfe(this.gid,e.gid,this.processGid)}[J3](e,r){let o=e.mode&4095||this.fmode,a=new Oct.WriteStream(e.absolute,{flags:Lfe(e.size),mode:o,autoClose:!1});a.on("error",p=>{a.fd&&vn.close(a.fd,()=>{}),a.write=()=>!0,this[To](p,e),r()});let n=1,u=p=>{if(p){a.fd&&vn.close(a.fd,()=>{}),this[To](p,e),r();return}--n===0&&vn.close(a.fd,h=>{h?this[To](h,e):this[sC](),r()})};a.on("finish",p=>{let h=e.absolute,E=a.fd;if(e.mtime&&!this.noMtime){n++;let I=e.atime||new Date,v=e.mtime;vn.futimes(E,I,v,x=>x?vn.utimes(h,I,v,C=>u(C&&x)):u())}if(this[J1](e)){n++;let I=this[X1](e),v=this[Z1](e);vn.fchown(E,I,v,x=>x?vn.chown(h,I,v,C=>u(C&&x)):u())}u()});let A=this.transform&&this.transform(e)||e;A!==e&&(A.on("error",p=>{this[To](p,e),r()}),e.pipe(A)),A.pipe(a)}[X3](e,r){let o=e.mode&4095||this.dmode;this[Ph](e.absolute,o,a=>{if(a){this[To](a,e),r();return}let n=1,u=A=>{--n===0&&(r(),this[sC](),e.resume())};e.mtime&&!this.noMtime&&(n++,vn.utimes(e.absolute,e.atime||new Date,e.mtime,u)),this[J1](e)&&(n++,vn.chown(e.absolute,this[X1](e),this[Z1](e),u)),u()})}[bfe](e){e.unsupported=!0,this.warn("TAR_ENTRY_UNSUPPORTED",`unsupported entry type: ${e.type}`,{entry:e}),e.resume()}[Pfe](e,r){this[Yx](e,e.linkpath,"symlink",r)}[Sfe](e,r){let o=pl(Wf.resolve(this.cwd,e.linkpath));this[Yx](e,o,"link",r)}[kfe](){this[qx]++}[sC](){this[qx]--,this[K3]()}[Z3](e){this[sC](),e.resume()}[V3](e,r){return e.type==="File"&&!this.unlink&&r.isFile()&&r.nlink<=1&&!e2}[z3](e){this[kfe]();let r=[e.path];e.linkpath&&r.push(e.linkpath),this.reservations.reserve(r,o=>this[Dfe](e,o))}[jx](e){e.type==="SymbolicLink"?Wct(this.dirCache):e.type!=="Directory"&&Yct(this.dirCache,e.absolute)}[Dfe](e,r){this[jx](e);let o=A=>{this[jx](e),r(A)},a=()=>{this[Ph](this.cwd,this.dmode,A=>{if(A){this[To](A,e),o();return}this[$1]=!0,n()})},n=()=>{if(e.absolute!==this.cwd){let A=pl(Wf.dirname(e.absolute));if(A!==this.cwd)return this[Ph](A,this.dmode,p=>{if(p){this[To](p,e),o();return}u()})}u()},u=()=>{vn.lstat(e.absolute,(A,p)=>{if(p&&(this.keep||this.newer&&p.mtime>e.mtime)){this[Z3](e),o();return}if(A||this[V3](e,p))return this[rc](null,e,o);if(p.isDirectory()){if(e.type==="Directory"){let h=!this.noChmod&&e.mode&&(p.mode&4095)!==e.mode,E=I=>this[rc](I,e,o);return h?vn.chmod(e.absolute,e.mode,E):E()}if(e.absolute!==this.cwd)return vn.rmdir(e.absolute,h=>this[rc](h,e,o))}if(e.absolute===this.cwd)return this[rc](null,e,o);Gct(e.absolute,h=>this[rc](h,e,o))})};this[$1]?n():a()}[rc](e,r,o){if(e){this[To](e,r),o();return}switch(r.type){case"File":case"OldFile":case"ContiguousFile":return this[J3](r,o);case"Link":return this[Sfe](r,o);case"SymbolicLink":return this[Pfe](r,o);case"Directory":case"GNUDumpDir":return this[X3](r,o)}}[Yx](e,r,o,a){vn[o](r,e.absolute,n=>{n?this[To](n,e):(this[sC](),e.resume()),a()})}},Gx=t=>{try{return[null,t()]}catch(e){return[e,null]}},$3=class extends t2{[rc](e,r){return super[rc](e,r,()=>{})}[z3](e){if(this[jx](e),!this[$1]){let n=this[Ph](this.cwd,this.dmode);if(n)return this[To](n,e);this[$1]=!0}if(e.absolute!==this.cwd){let n=pl(Wf.dirname(e.absolute));if(n!==this.cwd){let u=this[Ph](n,this.dmode);if(u)return this[To](u,e)}}let[r,o]=Gx(()=>vn.lstatSync(e.absolute));if(o&&(this.keep||this.newer&&o.mtime>e.mtime))return this[Z3](e);if(r||this[V3](e,o))return this[rc](null,e);if(o.isDirectory()){if(e.type==="Directory"){let u=!this.noChmod&&e.mode&&(o.mode&4095)!==e.mode,[A]=u?Gx(()=>{vn.chmodSync(e.absolute,e.mode)}):[];return this[rc](A,e)}let[n]=Gx(()=>vn.rmdirSync(e.absolute));this[rc](n,e)}let[a]=e.absolute===this.cwd?[]:Gx(()=>jct(e.absolute));this[rc](a,e)}[J3](e,r){let o=e.mode&4095||this.fmode,a=A=>{let p;try{vn.closeSync(n)}catch(h){p=h}(A||p)&&this[To](A||p,e),r()},n;try{n=vn.openSync(e.absolute,Lfe(e.size),o)}catch(A){return a(A)}let u=this.transform&&this.transform(e)||e;u!==e&&(u.on("error",A=>this[To](A,e)),e.pipe(u)),u.on("data",A=>{try{vn.writeSync(n,A,0,A.length)}catch(p){a(p)}}),u.on("end",A=>{let p=null;if(e.mtime&&!this.noMtime){let h=e.atime||new Date,E=e.mtime;try{vn.futimesSync(n,h,E)}catch(I){try{vn.utimesSync(e.absolute,h,E)}catch{p=I}}}if(this[J1](e)){let h=this[X1](e),E=this[Z1](e);try{vn.fchownSync(n,h,E)}catch(I){try{vn.chownSync(e.absolute,h,E)}catch{p=p||I}}}a(p)})}[X3](e,r){let o=e.mode&4095||this.dmode,a=this[Ph](e.absolute,o);if(a){this[To](a,e),r();return}if(e.mtime&&!this.noMtime)try{vn.utimesSync(e.absolute,e.atime||new Date,e.mtime)}catch{}if(this[J1](e))try{vn.chownSync(e.absolute,this[X1](e),this[Z1](e))}catch{}r(),e.resume()}[Ph](e,r){try{return Rfe.sync(pl(e),{uid:this.uid,gid:this.gid,processUid:this.processUid,processGid:this.processGid,umask:this.processUmask,preserve:this.preservePaths,unlink:this.unlink,cache:this.dirCache,cwd:this.cwd,mode:r})}catch(o){return o}}[Yx](e,r,o,a){try{vn[o+"Sync"](r,e.absolute),a(),e.resume()}catch(n){return this[To](n,e)}}};t2.Sync=$3;Nfe.exports=t2});var Hfe=_((SUt,_fe)=>{"use strict";var Kct=OE(),Wx=e_(),Mfe=ve("fs"),Ufe=eC(),Ofe=ve("path"),t_=YE();_fe.exports=(t,e,r)=>{typeof t=="function"?(r=t,e=null,t={}):Array.isArray(t)&&(e=t,t={}),typeof e=="function"&&(r=e,e=null),e?e=Array.from(e):e=[];let o=Kct(t);if(o.sync&&typeof r=="function")throw new TypeError("callback not supported for sync tar functions");if(!o.file&&typeof r=="function")throw new TypeError("callback only supported with file option");return e.length&&zct(o,e),o.file&&o.sync?Vct(o):o.file?Jct(o,r):o.sync?Xct(o):Zct(o)};var zct=(t,e)=>{let r=new Map(e.map(n=>[t_(n),!0])),o=t.filter,a=(n,u)=>{let A=u||Ofe.parse(n).root||".",p=n===A?!1:r.has(n)?r.get(n):a(Ofe.dirname(n),A);return r.set(n,p),p};t.filter=o?(n,u)=>o(n,u)&&a(t_(n)):n=>a(t_(n))},Vct=t=>{let e=new Wx.Sync(t),r=t.file,o=Mfe.statSync(r),a=t.maxReadSize||16*1024*1024;new Ufe.ReadStreamSync(r,{readSize:a,size:o.size}).pipe(e)},Jct=(t,e)=>{let r=new Wx(t),o=t.maxReadSize||16*1024*1024,a=t.file,n=new Promise((u,A)=>{r.on("error",A),r.on("close",u),Mfe.stat(a,(p,h)=>{if(p)A(p);else{let E=new Ufe.ReadStream(a,{readSize:o,size:h.size});E.on("error",A),E.pipe(r)}})});return e?n.then(e,e):n},Xct=t=>new Wx.Sync(t),Zct=t=>new Wx(t)});var qfe=_(us=>{"use strict";us.c=us.create=BAe();us.r=us.replace=N3();us.t=us.list=Tx();us.u=us.update=FAe();us.x=us.extract=Hfe();us.Pack=Ex();us.Unpack=e_();us.Parse=Rx();us.ReadEntry=rx();us.WriteEntry=A3();us.Header=jE();us.Pax=ix();us.types=KU()});var r_,Gfe,Sh,r2,n2,jfe=Et(()=>{r_=$e(sd()),Gfe=ve("worker_threads"),Sh=Symbol("kTaskInfo"),r2=class{constructor(e,r){this.fn=e;this.limit=(0,r_.default)(r.poolSize)}run(e){return this.limit(()=>this.fn(e))}},n2=class{constructor(e,r){this.source=e;this.workers=[];this.limit=(0,r_.default)(r.poolSize),this.cleanupInterval=setInterval(()=>{if(this.limit.pendingCount===0&&this.limit.activeCount===0){let o=this.workers.pop();o?o.terminate():clearInterval(this.cleanupInterval)}},5e3).unref()}createWorker(){this.cleanupInterval.refresh();let e=new Gfe.Worker(this.source,{eval:!0,execArgv:[...process.execArgv,"--unhandled-rejections=strict"]});return e.on("message",r=>{if(!e[Sh])throw new Error("Assertion failed: Worker sent a result without having a task assigned");e[Sh].resolve(r),e[Sh]=null,e.unref(),this.workers.push(e)}),e.on("error",r=>{e[Sh]?.reject(r),e[Sh]=null}),e.on("exit",r=>{r!==0&&e[Sh]?.reject(new Error(`Worker exited with code ${r}`)),e[Sh]=null}),e}run(e){return this.limit(()=>{let r=this.workers.pop()??this.createWorker();return r.ref(),new Promise((o,a)=>{r[Sh]={resolve:o,reject:a},r.postMessage(e)})})}}});var Wfe=_((QUt,Yfe)=>{var n_;Yfe.exports.getContent=()=>(typeof n_>"u"&&(n_=ve("zlib").brotliDecompressSync(Buffer.from("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","base64")).toString()),n_)});var Xi={};zt(Xi,{convertToZip:()=>rut,convertToZipWorker:()=>o_,extractArchiveTo:()=>Xfe,getDefaultTaskPool:()=>Vfe,getTaskPoolForConfiguration:()=>Jfe,makeArchiveFromDirectory:()=>tut});function $ct(t,e){switch(t){case"async":return new r2(o_,{poolSize:e});case"workers":return new n2((0,s_.getContent)(),{poolSize:e});default:throw new Error(`Assertion failed: Unknown value ${t} for taskPoolMode`)}}function Vfe(){return typeof i_>"u"&&(i_=$ct("workers",Vi.availableParallelism())),i_}function Jfe(t){return typeof t>"u"?Vfe():al(eut,t,()=>{let e=t.get("taskPoolMode"),r=t.get("taskPoolConcurrency");switch(e){case"async":return new r2(o_,{poolSize:r});case"workers":return new n2((0,s_.getContent)(),{poolSize:r});default:throw new Error(`Assertion failed: Unknown value ${e} for taskPoolMode`)}})}async function o_(t){let{tmpFile:e,tgz:r,compressionLevel:o,extractBufferOpts:a}=t,n=new Ji(e,{create:!0,level:o,stats:Ea.makeDefaultStats()}),u=Buffer.from(r.buffer,r.byteOffset,r.byteLength);return await Xfe(u,n,a),n.saveAndClose(),e}async function tut(t,{baseFs:e=new Tn,prefixPath:r=Bt.root,compressionLevel:o,inMemory:a=!1}={}){let n;if(a)n=new Ji(null,{level:o});else{let A=await oe.mktempPromise(),p=z.join(A,"archive.zip");n=new Ji(p,{create:!0,level:o})}let u=z.resolve(Bt.root,r);return await n.copyPromise(u,t,{baseFs:e,stableTime:!0,stableSort:!0}),n}async function rut(t,e={}){let r=await oe.mktempPromise(),o=z.join(r,"archive.zip"),a=e.compressionLevel??e.configuration?.get("compressionLevel")??"mixed",n={prefixPath:e.prefixPath,stripComponents:e.stripComponents};return await(e.taskPool??Jfe(e.configuration)).run({tmpFile:o,tgz:t,compressionLevel:a,extractBufferOpts:n}),new Ji(o,{level:e.compressionLevel})}async function*nut(t){let e=new zfe.default.Parse,r=new Kfe.PassThrough({objectMode:!0,autoDestroy:!0,emitClose:!0});e.on("entry",o=>{r.write(o)}),e.on("error",o=>{r.destroy(o)}),e.on("close",()=>{r.destroyed||r.end()}),e.end(t);for await(let o of r){let a=o;yield a,a.resume()}}async function Xfe(t,e,{stripComponents:r=0,prefixPath:o=Bt.dot}={}){function a(n){if(n.path[0]==="/")return!0;let u=n.path.split(/\//g);return!!(u.some(A=>A==="..")||u.length<=r)}for await(let n of nut(t)){if(a(n))continue;let u=z.normalize(le.toPortablePath(n.path)).replace(/\/$/,"").split(/\//g);if(u.length<=r)continue;let A=u.slice(r).join("/"),p=z.join(o,A),h=420;switch((n.type==="Directory"||((n.mode??0)&73)!==0)&&(h|=73),n.type){case"Directory":e.mkdirpSync(z.dirname(p),{chmod:493,utimes:[vi.SAFE_TIME,vi.SAFE_TIME]}),e.mkdirSync(p,{mode:h}),e.utimesSync(p,vi.SAFE_TIME,vi.SAFE_TIME);break;case"OldFile":case"File":e.mkdirpSync(z.dirname(p),{chmod:493,utimes:[vi.SAFE_TIME,vi.SAFE_TIME]}),e.writeFileSync(p,await zy(n),{mode:h}),e.utimesSync(p,vi.SAFE_TIME,vi.SAFE_TIME);break;case"SymbolicLink":e.mkdirpSync(z.dirname(p),{chmod:493,utimes:[vi.SAFE_TIME,vi.SAFE_TIME]}),e.symlinkSync(n.linkpath,p),e.lutimesSync(p,vi.SAFE_TIME,vi.SAFE_TIME);break}}return e}var Kfe,zfe,s_,i_,eut,Zfe=Et(()=>{Ye();Pt();iA();Kfe=ve("stream"),zfe=$e(qfe());jfe();Gl();s_=$e(Wfe());eut=new WeakMap});var epe=_((a_,$fe)=>{(function(t,e){typeof a_=="object"?$fe.exports=e():typeof define=="function"&&define.amd?define(e):t.treeify=e()})(a_,function(){function t(a,n){var u=n?"\u2514":"\u251C";return a?u+="\u2500 ":u+="\u2500\u2500\u2510",u}function e(a,n){var u=[];for(var A in a)!a.hasOwnProperty(A)||n&&typeof a[A]=="function"||u.push(A);return u}function r(a,n,u,A,p,h,E){var I="",v=0,x,C,R=A.slice(0);if(R.push([n,u])&&A.length>0&&(A.forEach(function(U,V){V>0&&(I+=(U[1]?" ":"\u2502")+" "),!C&&U[0]===n&&(C=!0)}),I+=t(a,u)+a,p&&(typeof n!="object"||n instanceof Date)&&(I+=": "+n),C&&(I+=" (circular ref.)"),E(I)),!C&&typeof n=="object"){var N=e(n,h);N.forEach(function(U){x=++v===N.length,r(U,n[U],x,R,p,h,E)})}}var o={};return o.asLines=function(a,n,u,A){var p=typeof u!="function"?u:!1;r(".",a,!1,[],n,p,A||u)},o.asTree=function(a,n,u){var A="";return r(".",a,!1,[],n,u,function(p){A+=p+`
-`}),A},o})});var $s={};zt($s,{emitList:()=>iut,emitTree:()=>ipe,treeNodeToJson:()=>npe,treeNodeToTreeify:()=>rpe});function rpe(t,{configuration:e}){let r={},o=0,a=(n,u)=>{let A=Array.isArray(n)?n.entries():Object.entries(n);for(let[p,h]of A){if(!h)continue;let{label:E,value:I,children:v}=h,x=[];typeof E<"u"&&x.push(Ed(e,E,2)),typeof I<"u"&&x.push(Ut(e,I[0],I[1])),x.length===0&&x.push(Ed(e,`${p}`,2));let C=x.join(": ").trim(),R=`\0${o++}\0`,N=u[`${R}${C}`]={};typeof v<"u"&&a(v,N)}};if(typeof t.children>"u")throw new Error("The root node must only contain children");return a(t.children,r),r}function npe(t){let e=r=>{if(typeof r.children>"u"){if(typeof r.value>"u")throw new Error("Assertion failed: Expected a value to be set if the children are missing");return Cd(r.value[0],r.value[1])}let o=Array.isArray(r.children)?r.children.entries():Object.entries(r.children??{}),a=Array.isArray(r.children)?[]:{};for(let[n,u]of o)u&&(a[sut(n)]=e(u));return typeof r.value>"u"?a:{value:Cd(r.value[0],r.value[1]),children:a}};return e(t)}function iut(t,{configuration:e,stdout:r,json:o}){let a=t.map(n=>({value:n}));ipe({children:a},{configuration:e,stdout:r,json:o})}function ipe(t,{configuration:e,stdout:r,json:o,separators:a=0}){if(o){let u=Array.isArray(t.children)?t.children.values():Object.values(t.children??{});for(let A of u)A&&r.write(`${JSON.stringify(npe(A))}
-`);return}let n=(0,tpe.asTree)(rpe(t,{configuration:e}),!1,!1);if(n=n.replace(/\0[0-9]+\0/g,""),a>=1&&(n=n.replace(/^([├└]─)/gm,`\u2502
-$1`).replace(/^│\n/,"")),a>=2)for(let u=0;u<2;++u)n=n.replace(/^([│ ].{2}[├│ ].{2}[^\n]+\n)(([│ ]).{2}[├└].{2}[^\n]*\n[│ ].{2}[│ ].{2}[├└]─)/gm,`$1$3 \u2502
-$2`).replace(/^│\n/,"");if(a>=3)throw new Error("Only the first two levels are accepted by treeUtils.emitTree");r.write(n)}function sut(t){return typeof t=="string"?t.replace(/^\0[0-9]+\0/,""):t}var tpe,spe=Et(()=>{tpe=$e(epe());jl()});function i2(t){let e=t.match(out);if(!e?.groups)throw new Error("Assertion failed: Expected the checksum to match the requested pattern");let r=e.groups.cacheVersion?parseInt(e.groups.cacheVersion):null;return{cacheKey:e.groups.cacheKey??null,cacheVersion:r,cacheSpec:e.groups.cacheSpec??null,hash:e.groups.hash}}var ope,l_,c_,Kx,Nr,out,u_=Et(()=>{Ye();Pt();Pt();iA();ope=ve("crypto"),l_=$e(ve("fs"));Wl();ih();Gl();bo();c_=Vy(process.env.YARN_CACHE_CHECKPOINT_OVERRIDE??process.env.YARN_CACHE_VERSION_OVERRIDE??9),Kx=Vy(process.env.YARN_CACHE_VERSION_OVERRIDE??10),Nr=class{constructor(e,{configuration:r,immutable:o=r.get("enableImmutableCache"),check:a=!1}){this.markedFiles=new Set;this.mutexes=new Map;this.cacheId=`-${(0,ope.randomBytes)(8).toString("hex")}.tmp`;this.configuration=r,this.cwd=e,this.immutable=o,this.check=a;let{cacheSpec:n,cacheKey:u}=Nr.getCacheKey(r);this.cacheSpec=n,this.cacheKey=u}static async find(e,{immutable:r,check:o}={}){let a=new Nr(e.get("cacheFolder"),{configuration:e,immutable:r,check:o});return await a.setup(),a}static getCacheKey(e){let r=e.get("compressionLevel"),o=r!=="mixed"?`c${r}`:"";return{cacheKey:[Kx,o].join(""),cacheSpec:o}}get mirrorCwd(){if(!this.configuration.get("enableMirror"))return null;let e=`${this.configuration.get("globalFolder")}/cache`;return e!==this.cwd?e:null}getVersionFilename(e){return`${lE(e)}-${this.cacheKey}.zip`}getChecksumFilename(e,r){let a=i2(r).hash.slice(0,10);return`${lE(e)}-${a}.zip`}isChecksumCompatible(e){if(e===null)return!1;let{cacheVersion:r,cacheSpec:o}=i2(e);if(r===null||r<c_)return!1;let a=this.configuration.get("cacheMigrationMode");return!(r<Kx&&a==="always"||o!==this.cacheSpec&&a!=="required-only")}getLocatorPath(e,r){return this.mirrorCwd===null?z.resolve(this.cwd,this.getVersionFilename(e)):r===null?z.resolve(this.cwd,this.getVersionFilename(e)):z.resolve(this.cwd,this.getChecksumFilename(e,r))}getLocatorMirrorPath(e){let r=this.mirrorCwd;return r!==null?z.resolve(r,this.getVersionFilename(e)):null}async setup(){if(!this.configuration.get("enableGlobalCache"))if(this.immutable){if(!await oe.existsPromise(this.cwd))throw new Jt(56,"Cache path does not exist.")}else{await oe.mkdirPromise(this.cwd,{recursive:!0});let e=z.resolve(this.cwd,".gitignore");await oe.changeFilePromise(e,`/.gitignore
-*.flock
-*.tmp
-`)}(this.mirrorCwd||!this.immutable)&&await oe.mkdirPromise(this.mirrorCwd||this.cwd,{recursive:!0})}async fetchPackageFromCache(e,r,{onHit:o,onMiss:a,loader:n,...u}){let A=this.getLocatorMirrorPath(e),p=new Tn,h=()=>{let he=new Ji,Be=z.join(Bt.root,nM(e));return he.mkdirSync(Be,{recursive:!0}),he.writeJsonSync(z.join(Be,dr.manifest),{name:fn(e),mocked:!0}),he},E=async(he,{isColdHit:Be,controlPath:we=null})=>{if(we===null&&u.unstablePackages?.has(e.locatorHash))return{isValid:!0,hash:null};let g=r&&!Be?i2(r).cacheKey:this.cacheKey,Ee=!u.skipIntegrityCheck||!r?`${g}/${await LS(he)}`:r;if(we!==null){let ce=!u.skipIntegrityCheck||!r?`${this.cacheKey}/${await LS(we)}`:r;if(Ee!==ce)throw new Jt(18,"The remote archive doesn't match the local checksum - has the local cache been corrupted?")}let Pe=null;switch(r!==null&&Ee!==r&&(this.check?Pe="throw":i2(r).cacheKey!==i2(Ee).cacheKey?Pe="update":Pe=this.configuration.get("checksumBehavior")),Pe){case null:case"update":return{isValid:!0,hash:Ee};case"ignore":return{isValid:!0,hash:r};case"reset":return{isValid:!1,hash:r};default:case"throw":throw new Jt(18,"The remote archive doesn't match the expected checksum")}},I=async he=>{if(!n)throw new Error(`Cache check required but no loader configured for ${qr(this.configuration,e)}`);let Be=await n(),we=Be.getRealPath();Be.saveAndClose(),await oe.chmodPromise(we,420);let g=await E(he,{controlPath:we,isColdHit:!1});if(!g.isValid)throw new Error("Assertion failed: Expected a valid checksum");return g.hash},v=async()=>{if(A===null||!await oe.existsPromise(A)){let he=await n(),Be=he.getRealPath();return he.saveAndClose(),{source:"loader",path:Be}}return{source:"mirror",path:A}},x=async()=>{if(!n)throw new Error(`Cache entry required but missing for ${qr(this.configuration,e)}`);if(this.immutable)throw new Jt(56,`Cache entry required but missing for ${qr(this.configuration,e)}`);let{path:he,source:Be}=await v(),{hash:we}=await E(he,{isColdHit:!0}),g=this.getLocatorPath(e,we),Ee=[];Be!=="mirror"&&A!==null&&Ee.push(async()=>{let ce=`${A}${this.cacheId}`;await oe.copyFilePromise(he,ce,l_.default.constants.COPYFILE_FICLONE),await oe.chmodPromise(ce,420),await oe.renamePromise(ce,A)}),(!u.mirrorWriteOnly||A===null)&&Ee.push(async()=>{let ce=`${g}${this.cacheId}`;await oe.copyFilePromise(he,ce,l_.default.constants.COPYFILE_FICLONE),await oe.chmodPromise(ce,420),await oe.renamePromise(ce,g)});let Pe=u.mirrorWriteOnly?A??g:g;return await Promise.all(Ee.map(ce=>ce())),[!1,Pe,we]},C=async()=>{let Be=(async()=>{let we=u.unstablePackages?.has(e.locatorHash),g=we||!r||this.isChecksumCompatible(r)?this.getLocatorPath(e,r):null,Ee=g!==null?this.markedFiles.has(g)||await p.existsPromise(g):!1,Pe=!!u.mockedPackages?.has(e.locatorHash)&&(!this.check||!Ee),ce=Pe||Ee,ne=ce?o:a;if(ne&&ne(),ce){let ee=null,Ie=g;if(!Pe)if(this.check)ee=await I(Ie);else{let Fe=await E(Ie,{isColdHit:!1});if(Fe.isValid)ee=Fe.hash;else return x()}return[Pe,Ie,ee]}else{if(this.immutable&&we)throw new Jt(56,`Cache entry required but missing for ${qr(this.configuration,e)}; consider defining ${de.pretty(this.configuration,"supportedArchitectures",de.Type.CODE)} to cache packages for multiple systems`);return x()}})();this.mutexes.set(e.locatorHash,Be);try{return await Be}finally{this.mutexes.delete(e.locatorHash)}};for(let he;he=this.mutexes.get(e.locatorHash);)await he;let[R,N,U]=await C();R||this.markedFiles.add(N);let V,te=R?()=>h():()=>new Ji(N,{baseFs:p,readOnly:!0}),ae=new iy(()=>CN(()=>V=te(),he=>`Failed to open the cache entry for ${qr(this.configuration,e)}: ${he}`),z),fe=new _u(N,{baseFs:ae,pathUtils:z}),ue=()=>{V?.discardAndClose()},me=u.unstablePackages?.has(e.locatorHash)?null:U;return[fe,ue,me]}},out=/^(?:(?<cacheKey>(?<cacheVersion>[0-9]+)(?<cacheSpec>.*))\/)?(?<hash>.*)$/});var zx,ape=Et(()=>{zx=(r=>(r[r.SCRIPT=0]="SCRIPT",r[r.SHELLCODE=1]="SHELLCODE",r))(zx||{})});var aut,oC,A_=Et(()=>{Pt();Nl();Qf();bo();aut=[[/^(git(?:\+(?:https|ssh))?:\/\/.*(?:\.git)?)#(.*)$/,(t,e,r,o)=>`${r}#commit=${o}`],[/^https:\/\/((?:[^/]+?)@)?codeload\.github\.com\/([^/]+\/[^/]+)\/tar\.gz\/([0-9a-f]+)$/,(t,e,r="",o,a)=>`https://${r}github.com/${o}.git#commit=${a}`],[/^https:\/\/((?:[^/]+?)@)?github\.com\/([^/]+\/[^/]+?)(?:\.git)?#([0-9a-f]+)$/,(t,e,r="",o,a)=>`https://${r}github.com/${o}.git#commit=${a}`],[/^https?:\/\/[^/]+\/(?:[^/]+\/)*(?:@.+(?:\/|(?:%2f)))?([^/]+)\/(?:-|download)\/\1-[^/]+\.tgz(?:#|$)/,t=>`npm:${t}`],[/^https:\/\/npm\.pkg\.github\.com\/download\/(?:@[^/]+)\/(?:[^/]+)\/(?:[^/]+)\/(?:[0-9a-f]+)(?:#|$)/,t=>`npm:${t}`],[/^https:\/\/npm\.fontawesome\.com\/(?:@[^/]+)\/([^/]+)\/-\/([^/]+)\/\1-\2.tgz(?:#|$)/,t=>`npm:${t}`],[/^https?:\/\/[^/]+\/.*\/(@[^/]+)\/([^/]+)\/-\/\1\/\2-(?:[.\d\w-]+)\.tgz(?:#|$)/,(t,e)=>_S({protocol:"npm:",source:null,selector:t,params:{__archiveUrl:e}})],[/^[^/]+\.tgz#[0-9a-f]+$/,t=>`npm:${t}`]],oC=class{constructor(e){this.resolver=e;this.resolutions=null}async setup(e,{report:r}){let o=z.join(e.cwd,dr.lockfile);if(!oe.existsSync(o))return;let a=await oe.readFilePromise(o,"utf8"),n=Ki(a);if(Object.hasOwn(n,"__metadata"))return;let u=this.resolutions=new Map;for(let A of Object.keys(n)){let p=s1(A);if(!p){r.reportWarning(14,`Failed to parse the string "${A}" into a proper descriptor`);continue}let h=xa(p.range)?In(p,`npm:${p.range}`):p,{version:E,resolved:I}=n[A];if(!I)continue;let v;for(let[C,R]of aut){let N=I.match(C);if(N){v=R(E,...N);break}}if(!v){r.reportWarning(14,`${Gn(e.configuration,h)}: Only some patterns can be imported from legacy lockfiles (not "${I}")`);continue}let x=h;try{let C=vd(h.range),R=s1(C.selector,!0);R&&(x=R)}catch{}u.set(h.descriptorHash,Qs(x,v))}}supportsDescriptor(e,r){return this.resolutions?this.resolutions.has(e.descriptorHash):!1}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error("Assertion failed: This resolver doesn't support resolving locators to packages")}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!this.resolutions)throw new Error("Assertion failed: The resolution store should have been setup");let a=this.resolutions.get(e.descriptorHash);if(!a)throw new Error("Assertion failed: The resolution should have been registered");let n=$O(a),u=o.project.configuration.normalizeDependency(n);return await this.resolver.getCandidates(u,r,o)}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){throw new Error("Assertion failed: This resolver doesn't support resolving locators to packages")}}});var fA,lpe=Et(()=>{Wl();O1();jl();fA=class extends Xs{constructor({configuration:r,stdout:o,suggestInstall:a=!0}){super();this.errorCount=0;XI(this,{configuration:r}),this.configuration=r,this.stdout=o,this.suggestInstall=a}static async start(r,o){let a=new this(r);try{await o(a)}catch(n){a.reportExceptionOnce(n)}finally{await a.finalize()}return a}hasErrors(){return this.errorCount>0}exitCode(){return this.hasErrors()?1:0}reportCacheHit(r){}reportCacheMiss(r){}startSectionSync(r,o){return o()}async startSectionPromise(r,o){return await o()}startTimerSync(r,o,a){return(typeof o=="function"?o:a)()}async startTimerPromise(r,o,a){return await(typeof o=="function"?o:a)()}reportSeparator(){}reportInfo(r,o){}reportWarning(r,o){}reportError(r,o){this.errorCount+=1,this.stdout.write(`${Ut(this.configuration,"\u27A4","redBright")} ${this.formatNameWithHyperlink(r)}: ${o}
-`)}reportProgress(r){return{...Promise.resolve().then(async()=>{for await(let{}of r);}),stop:()=>{}}}reportJson(r){}reportFold(r,o){}async finalize(){this.errorCount>0&&(this.stdout.write(`
-`),this.stdout.write(`${Ut(this.configuration,"\u27A4","redBright")} Errors happened when preparing the environment required to run this command.
-`),this.suggestInstall&&this.stdout.write(`${Ut(this.configuration,"\u27A4","redBright")} This might be caused by packages being missing from the lockfile, in which case running "yarn install" might help.
-`))}formatNameWithHyperlink(r){return yU(r,{configuration:this.configuration,json:!1})}}});var aC,f_=Et(()=>{bo();aC=class{constructor(e){this.resolver=e}supportsDescriptor(e,r){return!!(r.project.storedResolutions.get(e.descriptorHash)||r.project.originalPackages.has(OS(e).locatorHash))}supportsLocator(e,r){return!!(r.project.originalPackages.has(e.locatorHash)&&!r.project.lockfileNeedsRefresh)}shouldPersistResolution(e,r){throw new Error("The shouldPersistResolution method shouldn't be called on the lockfile resolver, which would always answer yes")}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return this.resolver.getResolutionDependencies(e,r)}async getCandidates(e,r,o){let a=o.project.storedResolutions.get(e.descriptorHash);if(a){let u=o.project.originalPackages.get(a);if(u)return[u]}let n=o.project.originalPackages.get(OS(e).locatorHash);if(n)return[n];throw new Error("Resolution expected from the lockfile data")}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let o=r.project.originalPackages.get(e.locatorHash);if(!o)throw new Error("The lockfile resolver isn't meant to resolve packages - they should already have been stored into a cache");return o}}});function Kf(){}function lut(t,e,r,o,a){for(var n=0,u=e.length,A=0,p=0;n<u;n++){var h=e[n];if(h.removed){if(h.value=t.join(o.slice(p,p+h.count)),p+=h.count,n&&e[n-1].added){var I=e[n-1];e[n-1]=e[n],e[n]=I}}else{if(!h.added&&a){var E=r.slice(A,A+h.count);E=E.map(function(x,C){var R=o[p+C];return R.length>x.length?R:x}),h.value=t.join(E)}else h.value=t.join(r.slice(A,A+h.count));A+=h.count,h.added||(p+=h.count)}}var v=e[u-1];return u>1&&typeof v.value=="string"&&(v.added||v.removed)&&t.equals("",v.value)&&(e[u-2].value+=v.value,e.pop()),e}function cut(t){return{newPos:t.newPos,components:t.components.slice(0)}}function uut(t,e){if(typeof t=="function")e.callback=t;else if(t)for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e}function Ape(t,e,r){return r=uut(r,{ignoreWhitespace:!0}),m_.diff(t,e,r)}function Aut(t,e,r){return y_.diff(t,e,r)}function Vx(t){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Vx=function(e){return typeof e}:Vx=function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Vx(t)}function p_(t){return hut(t)||gut(t)||dut(t)||mut()}function hut(t){if(Array.isArray(t))return h_(t)}function gut(t){if(typeof Symbol<"u"&&Symbol.iterator in Object(t))return Array.from(t)}function dut(t,e){if(!!t){if(typeof t=="string")return h_(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r==="Object"&&t.constructor&&(r=t.constructor.name),r==="Map"||r==="Set")return Array.from(t);if(r==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return h_(t,e)}}function h_(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,o=new Array(e);r<e;r++)o[r]=t[r];return o}function mut(){throw new TypeError(`Invalid attempt to spread non-iterable instance.
-In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function g_(t,e,r,o,a){e=e||[],r=r||[],o&&(t=o(a,t));var n;for(n=0;n<e.length;n+=1)if(e[n]===t)return r[n];var u;if(yut.call(t)==="[object Array]"){for(e.push(t),u=new Array(t.length),r.push(u),n=0;n<t.length;n+=1)u[n]=g_(t[n],e,r,o,a);return e.pop(),r.pop(),u}if(t&&t.toJSON&&(t=t.toJSON()),Vx(t)==="object"&&t!==null){e.push(t),u={},r.push(u);var A=[],p;for(p in t)t.hasOwnProperty(p)&&A.push(p);for(A.sort(),n=0;n<A.length;n+=1)p=A[n],u[p]=g_(t[p],e,r,o,p);e.pop(),r.pop()}else u=t;return u}function fpe(t,e,r,o,a,n,u){u||(u={}),typeof u.context>"u"&&(u.context=4);var A=Aut(r,o,u);if(!A)return;A.push({value:"",lines:[]});function p(U){return U.map(function(V){return" "+V})}for(var h=[],E=0,I=0,v=[],x=1,C=1,R=function(V){var te=A[V],ae=te.lines||te.value.replace(/\n$/,"").split(`
-`);if(te.lines=ae,te.added||te.removed){var fe;if(!E){var ue=A[V-1];E=x,I=C,ue&&(v=u.context>0?p(ue.lines.slice(-u.context)):[],E-=v.length,I-=v.length)}(fe=v).push.apply(fe,p_(ae.map(function(ce){return(te.added?"+":"-")+ce}))),te.added?C+=ae.length:x+=ae.length}else{if(E)if(ae.length<=u.context*2&&V<A.length-2){var me;(me=v).push.apply(me,p_(p(ae)))}else{var he,Be=Math.min(ae.length,u.context);(he=v).push.apply(he,p_(p(ae.slice(0,Be))));var we={oldStart:E,oldLines:x-E+Be,newStart:I,newLines:C-I+Be,lines:v};if(V>=A.length-2&&ae.length<=u.context){var g=/\n$/.test(r),Ee=/\n$/.test(o),Pe=ae.length==0&&v.length>we.oldLines;!g&&Pe&&r.length>0&&v.splice(we.oldLines,0,"\\ No newline at end of file"),(!g&&!Pe||!Ee)&&v.push("\\ No newline at end of file")}h.push(we),E=0,I=0,v=[]}x+=ae.length,C+=ae.length}},N=0;N<A.length;N++)R(N);return{oldFileName:t,newFileName:e,oldHeader:a,newHeader:n,hunks:h}}var i3t,cpe,upe,m_,y_,fut,put,yut,s2,d_,E_=Et(()=>{Kf.prototype={diff:function(e,r){var o=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},a=o.callback;typeof o=="function"&&(a=o,o={}),this.options=o;var n=this;function u(R){return a?(setTimeout(function(){a(void 0,R)},0),!0):R}e=this.castInput(e),r=this.castInput(r),e=this.removeEmpty(this.tokenize(e)),r=this.removeEmpty(this.tokenize(r));var A=r.length,p=e.length,h=1,E=A+p;o.maxEditLength&&(E=Math.min(E,o.maxEditLength));var I=[{newPos:-1,components:[]}],v=this.extractCommon(I[0],r,e,0);if(I[0].newPos+1>=A&&v+1>=p)return u([{value:this.join(r),count:r.length}]);function x(){for(var R=-1*h;R<=h;R+=2){var N=void 0,U=I[R-1],V=I[R+1],te=(V?V.newPos:0)-R;U&&(I[R-1]=void 0);var ae=U&&U.newPos+1<A,fe=V&&0<=te&&te<p;if(!ae&&!fe){I[R]=void 0;continue}if(!ae||fe&&U.newPos<V.newPos?(N=cut(V),n.pushComponent(N.components,void 0,!0)):(N=U,N.newPos++,n.pushComponent(N.components,!0,void 0)),te=n.extractCommon(N,r,e,R),N.newPos+1>=A&&te+1>=p)return u(lut(n,N.components,r,e,n.useLongestToken));I[R]=N}h++}if(a)(function R(){setTimeout(function(){if(h>E)return a();x()||R()},0)})();else for(;h<=E;){var C=x();if(C)return C}},pushComponent:function(e,r,o){var a=e[e.length-1];a&&a.added===r&&a.removed===o?e[e.length-1]={count:a.count+1,added:r,removed:o}:e.push({count:1,added:r,removed:o})},extractCommon:function(e,r,o,a){for(var n=r.length,u=o.length,A=e.newPos,p=A-a,h=0;A+1<n&&p+1<u&&this.equals(r[A+1],o[p+1]);)A++,p++,h++;return h&&e.components.push({count:h}),e.newPos=A,p},equals:function(e,r){return this.options.comparator?this.options.comparator(e,r):e===r||this.options.ignoreCase&&e.toLowerCase()===r.toLowerCase()},removeEmpty:function(e){for(var r=[],o=0;o<e.length;o++)e[o]&&r.push(e[o]);return r},castInput:function(e){return e},tokenize:function(e){return e.split("")},join:function(e){return e.join("")}};i3t=new Kf;cpe=/^[A-Za-z\xC0-\u02C6\u02C8-\u02D7\u02DE-\u02FF\u1E00-\u1EFF]+$/,upe=/\S/,m_=new Kf;m_.equals=function(t,e){return this.options.ignoreCase&&(t=t.toLowerCase(),e=e.toLowerCase()),t===e||this.options.ignoreWhitespace&&!upe.test(t)&&!upe.test(e)};m_.tokenize=function(t){for(var e=t.split(/([^\S\r\n]+|[()[\]{}'"\r\n]|\b)/),r=0;r<e.length-1;r++)!e[r+1]&&e[r+2]&&cpe.test(e[r])&&cpe.test(e[r+2])&&(e[r]+=e[r+2],e.splice(r+1,2),r--);return e};y_=new Kf;y_.tokenize=function(t){var e=[],r=t.split(/(\n|\r\n)/);r[r.length-1]||r.pop();for(var o=0;o<r.length;o++){var a=r[o];o%2&&!this.options.newlineIsToken?e[e.length-1]+=a:(this.options.ignoreWhitespace&&(a=a.trim()),e.push(a))}return e};fut=new Kf;fut.tokenize=function(t){return t.split(/(\S.+?[.!?])(?=\s+|$)/)};put=new Kf;put.tokenize=function(t){return t.split(/([{}:;,]|\s+)/)};yut=Object.prototype.toString,s2=new Kf;s2.useLongestToken=!0;s2.tokenize=y_.tokenize;s2.castInput=function(t){var e=this.options,r=e.undefinedReplacement,o=e.stringifyReplacer,a=o===void 0?function(n,u){return typeof u>"u"?r:u}:o;return typeof t=="string"?t:JSON.stringify(g_(t,null,null,a),a," ")};s2.equals=function(t,e){return Kf.prototype.equals.call(s2,t.replace(/,([\r\n])/g,"$1"),e.replace(/,([\r\n])/g,"$1"))};d_=new Kf;d_.tokenize=function(t){return t.slice()};d_.join=d_.removeEmpty=function(t){return t}});var hpe=_((o3t,ppe)=>{var Eut=ql(),Cut=pE(),wut=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Iut=/^\w*$/;function But(t,e){if(Eut(t))return!1;var r=typeof t;return r=="number"||r=="symbol"||r=="boolean"||t==null||Cut(t)?!0:Iut.test(t)||!wut.test(t)||e!=null&&t in Object(e)}ppe.exports=But});var mpe=_((a3t,dpe)=>{var gpe=UP(),vut="Expected a function";function C_(t,e){if(typeof t!="function"||e!=null&&typeof e!="function")throw new TypeError(vut);var r=function(){var o=arguments,a=e?e.apply(this,o):o[0],n=r.cache;if(n.has(a))return n.get(a);var u=t.apply(this,o);return r.cache=n.set(a,u)||n,u};return r.cache=new(C_.Cache||gpe),r}C_.Cache=gpe;dpe.exports=C_});var Epe=_((l3t,ype)=>{var Dut=mpe(),Put=500;function Sut(t){var e=Dut(t,function(o){return r.size===Put&&r.clear(),o}),r=e.cache;return e}ype.exports=Sut});var w_=_((c3t,Cpe)=>{var but=Epe(),xut=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,kut=/\\(\\)?/g,Qut=but(function(t){var e=[];return t.charCodeAt(0)===46&&e.push(""),t.replace(xut,function(r,o,a,n){e.push(a?n.replace(kut,"$1"):o||r)}),e});Cpe.exports=Qut});var jd=_((u3t,wpe)=>{var Fut=ql(),Rut=hpe(),Tut=w_(),Lut=L1();function Nut(t,e){return Fut(t)?t:Rut(t,e)?[t]:Tut(Lut(t))}wpe.exports=Nut});var lC=_((A3t,Ipe)=>{var Out=pE(),Mut=1/0;function Uut(t){if(typeof t=="string"||Out(t))return t;var e=t+"";return e=="0"&&1/t==-Mut?"-0":e}Ipe.exports=Uut});var Jx=_((f3t,Bpe)=>{var _ut=jd(),Hut=lC();function qut(t,e){e=_ut(e,t);for(var r=0,o=e.length;t!=null&&r<o;)t=t[Hut(e[r++])];return r&&r==o?t:void 0}Bpe.exports=qut});var I_=_((p3t,Dpe)=>{var Gut=tS(),jut=jd(),Yut=_I(),vpe=sl(),Wut=lC();function Kut(t,e,r,o){if(!vpe(t))return t;e=jut(e,t);for(var a=-1,n=e.length,u=n-1,A=t;A!=null&&++a<n;){var p=Wut(e[a]),h=r;if(p==="__proto__"||p==="constructor"||p==="prototype")return t;if(a!=u){var E=A[p];h=o?o(E,p,A):void 0,h===void 0&&(h=vpe(E)?E:Yut(e[a+1])?[]:{})}Gut(A,p,h),A=A[p]}return t}Dpe.exports=Kut});var Spe=_((h3t,Ppe)=>{var zut=Jx(),Vut=I_(),Jut=jd();function Xut(t,e,r){for(var o=-1,a=e.length,n={};++o<a;){var u=e[o],A=zut(t,u);r(A,u)&&Vut(n,Jut(u,t),A)}return n}Ppe.exports=Xut});var xpe=_((g3t,bpe)=>{function Zut(t,e){return t!=null&&e in Object(t)}bpe.exports=Zut});var B_=_((d3t,kpe)=>{var $ut=jd(),eAt=OI(),tAt=ql(),rAt=_I(),nAt=jP(),iAt=lC();function sAt(t,e,r){e=$ut(e,t);for(var o=-1,a=e.length,n=!1;++o<a;){var u=iAt(e[o]);if(!(n=t!=null&&r(t,u)))break;t=t[u]}return n||++o!=a?n:(a=t==null?0:t.length,!!a&&nAt(a)&&rAt(u,a)&&(tAt(t)||eAt(t)))}kpe.exports=sAt});var Fpe=_((m3t,Qpe)=>{var oAt=xpe(),aAt=B_();function lAt(t,e){return t!=null&&aAt(t,e,oAt)}Qpe.exports=lAt});var Tpe=_((y3t,Rpe)=>{var cAt=Spe(),uAt=Fpe();function AAt(t,e){return cAt(t,e,function(r,o){return uAt(t,o)})}Rpe.exports=AAt});var Mpe=_((E3t,Ope)=>{var Lpe=hd(),fAt=OI(),pAt=ql(),Npe=Lpe?Lpe.isConcatSpreadable:void 0;function hAt(t){return pAt(t)||fAt(t)||!!(Npe&&t&&t[Npe])}Ope.exports=hAt});var Hpe=_((C3t,_pe)=>{var gAt=qP(),dAt=Mpe();function Upe(t,e,r,o,a){var n=-1,u=t.length;for(r||(r=dAt),a||(a=[]);++n<u;){var A=t[n];e>0&&r(A)?e>1?Upe(A,e-1,r,o,a):gAt(a,A):o||(a[a.length]=A)}return a}_pe.exports=Upe});var Gpe=_((w3t,qpe)=>{var mAt=Hpe();function yAt(t){var e=t==null?0:t.length;return e?mAt(t,1):[]}qpe.exports=yAt});var v_=_((I3t,jpe)=>{var EAt=Gpe(),CAt=fN(),wAt=pN();function IAt(t){return wAt(CAt(t,void 0,EAt),t+"")}jpe.exports=IAt});var D_=_((B3t,Ype)=>{var BAt=Tpe(),vAt=v_(),DAt=vAt(function(t,e){return t==null?{}:BAt(t,e)});Ype.exports=DAt});var Xx,Wpe=Et(()=>{Wl();Xx=class{constructor(e){this.resolver=e}supportsDescriptor(e,r){return this.resolver.supportsDescriptor(e,r)}supportsLocator(e,r){return this.resolver.supportsLocator(e,r)}shouldPersistResolution(e,r){return this.resolver.shouldPersistResolution(e,r)}bindDescriptor(e,r,o){return this.resolver.bindDescriptor(e,r,o)}getResolutionDependencies(e,r){return this.resolver.getResolutionDependencies(e,r)}async getCandidates(e,r,o){throw new Jt(20,`This package doesn't seem to be present in your lockfile; run "yarn install" to update the lockfile`)}async getSatisfying(e,r,o,a){throw new Jt(20,`This package doesn't seem to be present in your lockfile; run "yarn install" to update the lockfile`)}async resolve(e,r){throw new Jt(20,`This package doesn't seem to be present in your lockfile; run "yarn install" to update the lockfile`)}}});var Qi,P_=Et(()=>{Wl();Qi=class extends Xs{reportCacheHit(e){}reportCacheMiss(e){}startSectionSync(e,r){return r()}async startSectionPromise(e,r){return await r()}startTimerSync(e,r,o){return(typeof r=="function"?r:o)()}async startTimerPromise(e,r,o){return await(typeof r=="function"?r:o)()}reportSeparator(){}reportInfo(e,r){}reportWarning(e,r){}reportError(e,r){}reportProgress(e){return{...Promise.resolve().then(async()=>{for await(let{}of e);}),stop:()=>{}}}reportJson(e){}reportFold(e,r){}async finalize(){}}});var Kpe,cC,S_=Et(()=>{Pt();Kpe=$e(RS());fE();Dd();jl();ih();Qf();bo();cC=class{constructor(e,{project:r}){this.workspacesCwds=new Set;this.project=r,this.cwd=e}async setup(){this.manifest=await Ot.tryFind(this.cwd)??new Ot,this.relativeCwd=z.relative(this.project.cwd,this.cwd)||Bt.dot;let e=this.manifest.name?this.manifest.name:tA(null,`${this.computeCandidateName()}-${Js(this.relativeCwd).substring(0,6)}`);this.anchoredDescriptor=In(e,`${Xn.protocol}${this.relativeCwd}`),this.anchoredLocator=Qs(e,`${Xn.protocol}${this.relativeCwd}`);let r=this.manifest.workspaceDefinitions.map(({pattern:a})=>a);if(r.length===0)return;let o=await(0,Kpe.default)(r,{cwd:le.fromPortablePath(this.cwd),onlyDirectories:!0,ignore:["**/node_modules","**/.git","**/.yarn"]});o.sort(),await o.reduce(async(a,n)=>{let u=z.resolve(this.cwd,le.toPortablePath(n)),A=await oe.existsPromise(z.join(u,"package.json"));await a,A&&this.workspacesCwds.add(u)},Promise.resolve())}get anchoredPackage(){let e=this.project.storedPackages.get(this.anchoredLocator.locatorHash);if(!e)throw new Error(`Assertion failed: Expected workspace ${a1(this.project.configuration,this)} (${Ut(this.project.configuration,z.join(this.cwd,dr.manifest),yt.PATH)}) to have been resolved. Run "yarn install" to update the lockfile`);return e}accepts(e){let r=e.indexOf(":"),o=r!==-1?e.slice(0,r+1):null,a=r!==-1?e.slice(r+1):e;if(o===Xn.protocol&&z.normalize(a)===this.relativeCwd||o===Xn.protocol&&(a==="*"||a==="^"||a==="~"))return!0;let n=xa(a);return n?o===Xn.protocol?n.test(this.manifest.version??"0.0.0"):this.project.configuration.get("enableTransparentWorkspaces")&&this.manifest.version!==null?n.test(this.manifest.version):!1:!1}computeCandidateName(){return this.cwd===this.project.cwd?"root-workspace":`${z.basename(this.cwd)}`||"unnamed-workspace"}getRecursiveWorkspaceDependencies({dependencies:e=Ot.hardDependencies}={}){let r=new Set,o=a=>{for(let n of e)for(let u of a.manifest[n].values()){let A=this.project.tryWorkspaceByDescriptor(u);A===null||r.has(A)||(r.add(A),o(A))}};return o(this),r}getRecursiveWorkspaceDependents({dependencies:e=Ot.hardDependencies}={}){let r=new Set,o=a=>{for(let n of this.project.workspaces)e.some(A=>[...n.manifest[A].values()].some(p=>{let h=this.project.tryWorkspaceByDescriptor(p);return h!==null&&i1(h.anchoredLocator,a.anchoredLocator)}))&&!r.has(n)&&(r.add(n),o(n))};return o(this),r}getRecursiveWorkspaceChildren(){let e=new Set([this]);for(let r of e)for(let o of r.workspacesCwds){let a=this.project.workspacesByCwd.get(o);a&&e.add(a)}return e.delete(this),Array.from(e)}async persistManifest(){let e={};this.manifest.exportTo(e);let r=z.join(this.cwd,Ot.fileName),o=`${JSON.stringify(e,null,this.manifest.indent)}
-`;await oe.changeFilePromise(r,o,{automaticNewlines:!0}),this.manifest.raw=e}}});function QAt({project:t,allDescriptors:e,allResolutions:r,allPackages:o,accessibleLocators:a=new Set,optionalBuilds:n=new Set,peerRequirements:u=new Map,peerWarnings:A=[],volatileDescriptors:p=new Set}){let h=new Map,E=[],I=new Map,v=new Map,x=new Map,C=new Map,R=new Map,N=new Map(t.workspaces.map(ue=>{let me=ue.anchoredLocator.locatorHash,he=o.get(me);if(typeof he>"u")throw new Error("Assertion failed: The workspace should have an associated package");return[me,e1(he)]})),U=()=>{let ue=oe.mktempSync(),me=z.join(ue,"stacktrace.log"),he=String(E.length+1).length,Be=E.map((we,g)=>`${`${g+1}.`.padStart(he," ")} ${ba(we)}
-`).join("");throw oe.writeFileSync(me,Be),oe.detachTemp(ue),new Jt(45,`Encountered a stack overflow when resolving peer dependencies; cf ${le.fromPortablePath(me)}`)},V=ue=>{let me=r.get(ue.descriptorHash);if(typeof me>"u")throw new Error("Assertion failed: The resolution should have been registered");let he=o.get(me);if(!he)throw new Error("Assertion failed: The package could not be found");return he},te=(ue,me,he,{top:Be,optional:we})=>{E.length>1e3&&U(),E.push(me);let g=ae(ue,me,he,{top:Be,optional:we});return E.pop(),g},ae=(ue,me,he,{top:Be,optional:we})=>{if(we||n.delete(me.locatorHash),a.has(me.locatorHash))return;a.add(me.locatorHash);let g=o.get(me.locatorHash);if(!g)throw new Error(`Assertion failed: The package (${qr(t.configuration,me)}) should have been registered`);let Ee=[],Pe=[],ce=[],ne=[],ee=[];for(let Fe of Array.from(g.dependencies.values())){if(g.peerDependencies.has(Fe.identHash)&&g.locatorHash!==Be)continue;if(bf(Fe))throw new Error("Assertion failed: Virtual packages shouldn't be encountered when virtualizing a branch");p.delete(Fe.descriptorHash);let At=we;if(!At){let Te=g.dependenciesMeta.get(fn(Fe));if(typeof Te<"u"){let Ve=Te.get(null);typeof Ve<"u"&&Ve.optional&&(At=!0)}}let H=r.get(Fe.descriptorHash);if(!H)throw new Error(`Assertion failed: The resolution (${Gn(t.configuration,Fe)}) should have been registered`);let at=N.get(H)||o.get(H);if(!at)throw new Error(`Assertion failed: The package (${H}, resolved from ${Gn(t.configuration,Fe)}) should have been registered`);if(at.peerDependencies.size===0){te(Fe,at,new Map,{top:Be,optional:At});continue}let Re,ke,xe=new Set,He;Pe.push(()=>{Re=tM(Fe,me.locatorHash),ke=rM(at,me.locatorHash),g.dependencies.delete(Fe.identHash),g.dependencies.set(Re.identHash,Re),r.set(Re.descriptorHash,ke.locatorHash),e.set(Re.descriptorHash,Re),o.set(ke.locatorHash,ke),Ee.push([at,Re,ke])}),ce.push(()=>{He=new Map;for(let Te of ke.peerDependencies.values()){let Ve=g.dependencies.get(Te.identHash);if(!Ve&&n1(me,Te)&&(ue.identHash===me.identHash?Ve=ue:(Ve=In(me,ue.range),e.set(Ve.descriptorHash,Ve),r.set(Ve.descriptorHash,me.locatorHash),p.delete(Ve.descriptorHash))),(!Ve||Ve.range==="missing:")&&ke.dependencies.has(Te.identHash)){ke.peerDependencies.delete(Te.identHash);continue}Ve||(Ve=In(Te,"missing:")),ke.dependencies.set(Ve.identHash,Ve),bf(Ve)&&yd(x,Ve.descriptorHash).add(ke.locatorHash),I.set(Ve.identHash,Ve),Ve.range==="missing:"&&xe.add(Ve.identHash),He.set(Te.identHash,he.get(Te.identHash)??ke.locatorHash)}ke.dependencies=new Map(ks(ke.dependencies,([Te,Ve])=>fn(Ve)))}),ne.push(()=>{if(!o.has(ke.locatorHash))return;let Te=h.get(at.locatorHash);typeof Te=="number"&&Te>=2&&U();let Ve=h.get(at.locatorHash),qe=typeof Ve<"u"?Ve+1:1;h.set(at.locatorHash,qe),te(Re,ke,He,{top:Be,optional:At}),h.set(at.locatorHash,qe-1)}),ee.push(()=>{let Te=g.dependencies.get(Fe.identHash);if(typeof Te>"u")throw new Error("Assertion failed: Expected the peer dependency to have been turned into a dependency");let Ve=r.get(Te.descriptorHash);if(typeof Ve>"u")throw new Error("Assertion failed: Expected the descriptor to be registered");if(yd(R,Ve).add(me.locatorHash),!!o.has(ke.locatorHash)){for(let qe of ke.peerDependencies.values()){let b=He.get(qe.identHash);if(typeof b>"u")throw new Error("Assertion failed: Expected the peer dependency ident to be registered");Yy(Wy(C,b),fn(qe)).push(ke.locatorHash)}for(let qe of xe)ke.dependencies.delete(qe)}})}for(let Fe of[...Pe,...ce])Fe();let Ie;do{Ie=!0;for(let[Fe,At,H]of Ee){let at=Wy(v,Fe.locatorHash),Re=Js(...[...H.dependencies.values()].map(Te=>{let Ve=Te.range!=="missing:"?r.get(Te.descriptorHash):"missing:";if(typeof Ve>"u")throw new Error(`Assertion failed: Expected the resolution for ${Gn(t.configuration,Te)} to have been registered`);return Ve===Be?`${Ve} (top)`:Ve}),At.identHash),ke=at.get(Re);if(typeof ke>"u"){at.set(Re,At);continue}if(ke===At)continue;o.delete(H.locatorHash),e.delete(At.descriptorHash),r.delete(At.descriptorHash),a.delete(H.locatorHash);let xe=x.get(At.descriptorHash)||[],He=[g.locatorHash,...xe];x.delete(At.descriptorHash);for(let Te of He){let Ve=o.get(Te);typeof Ve>"u"||(Ve.dependencies.get(At.identHash).descriptorHash!==ke.descriptorHash&&(Ie=!1),Ve.dependencies.set(At.identHash,ke))}}}while(!Ie);for(let Fe of[...ne,...ee])Fe()};for(let ue of t.workspaces){let me=ue.anchoredLocator;p.delete(ue.anchoredDescriptor.descriptorHash),te(ue.anchoredDescriptor,me,new Map,{top:me.locatorHash,optional:!1})}let fe=new Map;for(let[ue,me]of R){let he=o.get(ue);if(typeof he>"u")throw new Error("Assertion failed: Expected the root to be registered");let Be=C.get(ue);if(!(typeof Be>"u"))for(let we of me){let g=o.get(we);if(!(typeof g>"u")&&!!t.tryWorkspaceByLocator(g))for(let[Ee,Pe]of Be){let ce=Vs(Ee);if(g.peerDependencies.has(ce.identHash))continue;let ne=`p${Js(we,Ee,ue).slice(0,5)}`;u.set(ne,{subject:we,requested:ce,rootRequester:ue,allRequesters:Pe});let ee=he.dependencies.get(ce.identHash);if(typeof ee<"u"){let Ie=V(ee),Fe=Ie.version??"0.0.0",At=new Set;for(let at of Pe){let Re=o.get(at);if(typeof Re>"u")throw new Error("Assertion failed: Expected the link to be registered");let ke=Re.peerDependencies.get(ce.identHash);if(typeof ke>"u")throw new Error("Assertion failed: Expected the ident to be registered");At.add(ke.range)}if(![...At].every(at=>{if(at.startsWith(Xn.protocol)){if(!t.tryWorkspaceByLocator(Ie))return!1;at=at.slice(Xn.protocol.length),(at==="^"||at==="~")&&(at="*")}return kf(Fe,at)})){let at=al(fe,Ie.locatorHash,()=>({type:2,requested:ce,subject:Ie,dependents:new Map,requesters:new Map,links:new Map,version:Fe,hash:`p${Ie.locatorHash.slice(0,5)}`}));at.dependents.set(g.locatorHash,g),at.requesters.set(he.locatorHash,he);for(let Re of Pe)at.links.set(Re,o.get(Re));A.push({type:1,subject:g,requested:ce,requester:he,version:Fe,hash:ne,requirementCount:Pe.length})}}else he.peerDependenciesMeta.get(Ee)?.optional||A.push({type:0,subject:g,requested:ce,requester:he,hash:ne})}}}A.push(...fe.values())}function FAt(t,e){let r=IN(t.peerWarnings,"type"),o=r[2]?.map(n=>{let u=Array.from(n.links.values(),E=>{let I=t.storedPackages.get(E.locatorHash);if(typeof I>"u")throw new Error("Assertion failed: Expected the package to be registered");let v=I.peerDependencies.get(n.requested.identHash);if(typeof v>"u")throw new Error("Assertion failed: Expected the ident to be registered");return v.range}),A=n.links.size>1?"and other dependencies request":"requests",p=sM(u),h=p?cE(t.configuration,p):Ut(t.configuration,"but they have non-overlapping ranges!","redBright");return`${cs(t.configuration,n.requested)} is listed by your project with version ${o1(t.configuration,n.version)}, which doesn't satisfy what ${cs(t.configuration,n.requesters.values().next().value)} (${Ut(t.configuration,n.hash,yt.CODE)}) ${A} (${h}).`})??[],a=r[0]?.map(n=>`${qr(t.configuration,n.subject)} doesn't provide ${cs(t.configuration,n.requested)} (${Ut(t.configuration,n.hash,yt.CODE)}), requested by ${cs(t.configuration,n.requester)}.`)??[];e.startSectionSync({reportFooter:()=>{e.reportWarning(86,`Some peer dependencies are incorrectly met; run ${Ut(t.configuration,"yarn explain peer-requirements <hash>",yt.CODE)} for details, where ${Ut(t.configuration,"<hash>",yt.CODE)} is the six-letter p-prefixed code.`)},skipIfEmpty:!0},()=>{for(let n of ks(o,u=>Xy.default(u)))e.reportWarning(60,n);for(let n of ks(a,u=>Xy.default(u)))e.reportWarning(2,n)})}var Zx,$x,ek,Jpe,k_,x_,Q_,tk,PAt,SAt,zpe,bAt,xAt,kAt,hl,b_,rk,Vpe,St,Xpe=Et(()=>{Pt();Pt();Nl();qt();Zx=ve("crypto");E_();$x=$e(D_()),ek=$e(sd()),Jpe=$e(Jn()),k_=ve("util"),x_=$e(ve("v8")),Q_=$e(ve("zlib"));u_();P1();A_();f_();fE();uM();Wl();Wpe();O1();P_();Dd();S_();WS();jl();ih();Gl();vb();BU();Qf();bo();tk=Vy(process.env.YARN_LOCKFILE_VERSION_OVERRIDE??8),PAt=3,SAt=/ *, */g,zpe=/\/$/,bAt=32,xAt=(0,k_.promisify)(Q_.default.gzip),kAt=(0,k_.promisify)(Q_.default.gunzip),hl=(r=>(r.UpdateLockfile="update-lockfile",r.SkipBuild="skip-build",r))(hl||{}),b_={restoreLinkersCustomData:["linkersCustomData"],restoreResolutions:["accessibleLocators","conditionalLocators","disabledLocators","optionalBuilds","storedDescriptors","storedResolutions","storedPackages","lockFileChecksum"],restoreBuildState:["skippedBuilds","storedBuildState"]},rk=(o=>(o[o.NotProvided=0]="NotProvided",o[o.NotCompatible=1]="NotCompatible",o[o.NotCompatibleAggregate=2]="NotCompatibleAggregate",o))(rk||{}),Vpe=t=>Js(`${PAt}`,t),St=class{constructor(e,{configuration:r}){this.resolutionAliases=new Map;this.workspaces=[];this.workspacesByCwd=new Map;this.workspacesByIdent=new Map;this.storedResolutions=new Map;this.storedDescriptors=new Map;this.storedPackages=new Map;this.storedChecksums=new Map;this.storedBuildState=new Map;this.accessibleLocators=new Set;this.conditionalLocators=new Set;this.disabledLocators=new Set;this.originalPackages=new Map;this.optionalBuilds=new Set;this.skippedBuilds=new Set;this.lockfileLastVersion=null;this.lockfileNeedsRefresh=!1;this.peerRequirements=new Map;this.peerWarnings=[];this.linkersCustomData=new Map;this.lockFileChecksum=null;this.installStateChecksum=null;this.configuration=r,this.cwd=e}static async find(e,r){if(!e.projectCwd)throw new it(`No project found in ${r}`);let o=e.projectCwd,a=r,n=null;for(;n!==e.projectCwd;){if(n=a,oe.existsSync(z.join(n,dr.manifest))){o=n;break}a=z.dirname(n)}let u=new St(e.projectCwd,{configuration:e});Ke.telemetry?.reportProject(u.cwd),await u.setupResolutions(),await u.setupWorkspaces(),Ke.telemetry?.reportWorkspaceCount(u.workspaces.length),Ke.telemetry?.reportDependencyCount(u.workspaces.reduce((C,R)=>C+R.manifest.dependencies.size+R.manifest.devDependencies.size,0));let A=u.tryWorkspaceByCwd(o);if(A)return{project:u,workspace:A,locator:A.anchoredLocator};let p=await u.findLocatorForLocation(`${o}/`,{strict:!0});if(p)return{project:u,locator:p,workspace:null};let h=Ut(e,u.cwd,yt.PATH),E=Ut(e,z.relative(u.cwd,o),yt.PATH),I=`- If ${h} isn't intended to be a project, remove any yarn.lock and/or package.json file there.`,v=`- If ${h} is intended to be a project, it might be that you forgot to list ${E} in its workspace configuration.`,x=`- Finally, if ${h} is fine and you intend ${E} to be treated as a completely separate project (not even a workspace), create an empty yarn.lock file in it.`;throw new it(`The nearest package directory (${Ut(e,o,yt.PATH)}) doesn't seem to be part of the project declared in ${Ut(e,u.cwd,yt.PATH)}.
-
-${[I,v,x].join(`
-`)}`)}async setupResolutions(){this.storedResolutions=new Map,this.storedDescriptors=new Map,this.storedPackages=new Map,this.lockFileChecksum=null;let e=z.join(this.cwd,dr.lockfile),r=this.configuration.get("defaultLanguageName");if(oe.existsSync(e)){let o=await oe.readFilePromise(e,"utf8");this.lockFileChecksum=Vpe(o);let a=Ki(o);if(a.__metadata){let n=a.__metadata.version,u=a.__metadata.cacheKey;this.lockfileLastVersion=n,this.lockfileNeedsRefresh=n<tk;for(let A of Object.keys(a)){if(A==="__metadata")continue;let p=a[A];if(typeof p.resolution>"u")throw new Error(`Assertion failed: Expected the lockfile entry to have a resolution field (${A})`);let h=xf(p.resolution,!0),E=new Ot;E.load(p,{yamlCompatibilityMode:!0});let I=E.version,v=E.languageName||r,x=p.linkType.toUpperCase(),C=p.conditions??null,R=E.dependencies,N=E.peerDependencies,U=E.dependenciesMeta,V=E.peerDependenciesMeta,te=E.bin;if(p.checksum!=null){let fe=typeof u<"u"&&!p.checksum.includes("/")?`${u}/${p.checksum}`:p.checksum;this.storedChecksums.set(h.locatorHash,fe)}let ae={...h,version:I,languageName:v,linkType:x,conditions:C,dependencies:R,peerDependencies:N,dependenciesMeta:U,peerDependenciesMeta:V,bin:te};this.originalPackages.set(ae.locatorHash,ae);for(let fe of A.split(SAt)){let ue=sh(fe);n<=6&&(ue=this.configuration.normalizeDependency(ue),ue=In(ue,ue.range.replace(/^patch:[^@]+@(?!npm(:|%3A))/,"$1npm%3A"))),this.storedDescriptors.set(ue.descriptorHash,ue),this.storedResolutions.set(ue.descriptorHash,h.locatorHash)}}}else o.includes("yarn lockfile v1")&&(this.lockfileLastVersion=-1)}}async setupWorkspaces(){this.workspaces=[],this.workspacesByCwd=new Map,this.workspacesByIdent=new Map;let e=new Set,r=(0,ek.default)(4),o=async(a,n)=>{if(e.has(n))return a;e.add(n);let u=new cC(n,{project:this});await r(()=>u.setup());let A=a.then(()=>{this.addWorkspace(u)});return Array.from(u.workspacesCwds).reduce(o,A)};await o(Promise.resolve(),this.cwd)}addWorkspace(e){let r=this.workspacesByIdent.get(e.anchoredLocator.identHash);if(typeof r<"u")throw new Error(`Duplicate workspace name ${cs(this.configuration,e.anchoredLocator)}: ${le.fromPortablePath(e.cwd)} conflicts with ${le.fromPortablePath(r.cwd)}`);this.workspaces.push(e),this.workspacesByCwd.set(e.cwd,e),this.workspacesByIdent.set(e.anchoredLocator.identHash,e)}get topLevelWorkspace(){return this.getWorkspaceByCwd(this.cwd)}tryWorkspaceByCwd(e){z.isAbsolute(e)||(e=z.resolve(this.cwd,e)),e=z.normalize(e).replace(/\/+$/,"");let r=this.workspacesByCwd.get(e);return r||null}getWorkspaceByCwd(e){let r=this.tryWorkspaceByCwd(e);if(!r)throw new Error(`Workspace not found (${e})`);return r}tryWorkspaceByFilePath(e){let r=null;for(let o of this.workspaces)z.relative(o.cwd,e).startsWith("../")||r&&r.cwd.length>=o.cwd.length||(r=o);return r||null}getWorkspaceByFilePath(e){let r=this.tryWorkspaceByFilePath(e);if(!r)throw new Error(`Workspace not found (${e})`);return r}tryWorkspaceByIdent(e){let r=this.workspacesByIdent.get(e.identHash);return typeof r>"u"?null:r}getWorkspaceByIdent(e){let r=this.tryWorkspaceByIdent(e);if(!r)throw new Error(`Workspace not found (${cs(this.configuration,e)})`);return r}tryWorkspaceByDescriptor(e){if(e.range.startsWith(Xn.protocol)){let o=e.range.slice(Xn.protocol.length);if(o!=="^"&&o!=="~"&&o!=="*"&&!xa(o))return this.tryWorkspaceByCwd(o)}let r=this.tryWorkspaceByIdent(e);return r===null||(bf(e)&&(e=t1(e)),!r.accepts(e.range))?null:r}getWorkspaceByDescriptor(e){let r=this.tryWorkspaceByDescriptor(e);if(r===null)throw new Error(`Workspace not found (${Gn(this.configuration,e)})`);return r}tryWorkspaceByLocator(e){let r=this.tryWorkspaceByIdent(e);return r===null||(qc(e)&&(e=r1(e)),r.anchoredLocator.locatorHash!==e.locatorHash)?null:r}getWorkspaceByLocator(e){let r=this.tryWorkspaceByLocator(e);if(!r)throw new Error(`Workspace not found (${qr(this.configuration,e)})`);return r}deleteDescriptor(e){this.storedResolutions.delete(e),this.storedDescriptors.delete(e)}deleteLocator(e){this.originalPackages.delete(e),this.storedPackages.delete(e),this.accessibleLocators.delete(e)}forgetResolution(e){if("descriptorHash"in e){let r=this.storedResolutions.get(e.descriptorHash);this.deleteDescriptor(e.descriptorHash);let o=new Set(this.storedResolutions.values());typeof r<"u"&&!o.has(r)&&this.deleteLocator(r)}if("locatorHash"in e){this.deleteLocator(e.locatorHash);for(let[r,o]of this.storedResolutions)o===e.locatorHash&&this.deleteDescriptor(r)}}forgetTransientResolutions(){let e=this.configuration.makeResolver(),r=new Map;for(let[o,a]of this.storedResolutions.entries()){let n=r.get(a);n||r.set(a,n=new Set),n.add(o)}for(let o of this.originalPackages.values()){let a;try{a=e.shouldPersistResolution(o,{project:this,resolver:e})}catch{a=!1}if(!a){this.deleteLocator(o.locatorHash);let n=r.get(o.locatorHash);if(n){r.delete(o.locatorHash);for(let u of n)this.deleteDescriptor(u)}}}}forgetVirtualResolutions(){for(let e of this.storedPackages.values())for(let[r,o]of e.dependencies)bf(o)&&e.dependencies.set(r,t1(o))}getDependencyMeta(e,r){let o={},n=this.topLevelWorkspace.manifest.dependenciesMeta.get(fn(e));if(!n)return o;let u=n.get(null);if(u&&Object.assign(o,u),r===null||!Jpe.default.valid(r))return o;for(let[A,p]of n)A!==null&&A===r&&Object.assign(o,p);return o}async findLocatorForLocation(e,{strict:r=!1}={}){let o=new Qi,a=this.configuration.getLinkers(),n={project:this,report:o};for(let u of a){let A=await u.findPackageLocator(e,n);if(A){if(r&&(await u.findPackageLocation(A,n)).replace(zpe,"")!==e.replace(zpe,""))continue;return A}}return null}async loadUserConfig(){let e=z.join(this.cwd,".pnp.cjs");await oe.existsPromise(e)&&Df(e).setup();let r=z.join(this.cwd,"yarn.config.cjs");return await oe.existsPromise(r)?Df(r):null}async preparePackage(e,{resolver:r,resolveOptions:o}){let a=await this.configuration.getPackageExtensions(),n=this.configuration.normalizePackage(e,{packageExtensions:a});for(let[u,A]of n.dependencies){let p=await this.configuration.reduceHook(E=>E.reduceDependency,A,this,n,A,{resolver:r,resolveOptions:o});if(!n1(A,p))throw new Error("Assertion failed: The descriptor ident cannot be changed through aliases");let h=r.bindDescriptor(p,n,o);n.dependencies.set(u,h)}return n}async resolveEverything(e){if(!this.workspacesByCwd||!this.workspacesByIdent)throw new Error("Workspaces must have been setup before calling this function");this.forgetVirtualResolutions();let r=new Map(this.originalPackages),o=[];e.lockfileOnly||this.forgetTransientResolutions();let a=e.resolver||this.configuration.makeResolver(),n=new oC(a);await n.setup(this,{report:e.report});let u=e.lockfileOnly?[new Xx(a)]:[n,a],A=new Pd([new aC(a),...u]),p=new Pd([...u]),h=this.configuration.makeFetcher(),E=e.lockfileOnly?{project:this,report:e.report,resolver:A}:{project:this,report:e.report,resolver:A,fetchOptions:{project:this,cache:e.cache,checksums:this.storedChecksums,report:e.report,fetcher:h,cacheOptions:{mirrorWriteOnly:!0}}},I=new Map,v=new Map,x=new Map,C=new Map,R=new Map,N=new Map,U=this.topLevelWorkspace.anchoredLocator,V=new Set,te=[],ae=M4(),fe=this.configuration.getSupportedArchitectures();await e.report.startProgressPromise(Xs.progressViaTitle(),async ce=>{let ne=async H=>{let at=await Ky(async()=>await A.resolve(H,E),He=>`${qr(this.configuration,H)}: ${He}`);if(!i1(H,at))throw new Error(`Assertion failed: The locator cannot be changed by the resolver (went from ${qr(this.configuration,H)} to ${qr(this.configuration,at)})`);C.set(at.locatorHash,at),!r.delete(at.locatorHash)&&!this.tryWorkspaceByLocator(at)&&o.push(at);let ke=await this.preparePackage(at,{resolver:A,resolveOptions:E}),xe=_c([...ke.dependencies.values()].map(He=>At(He)));return te.push(xe),xe.catch(()=>{}),v.set(ke.locatorHash,ke),ke},ee=async H=>{let at=R.get(H.locatorHash);if(typeof at<"u")return at;let Re=Promise.resolve().then(()=>ne(H));return R.set(H.locatorHash,Re),Re},Ie=async(H,at)=>{let Re=await At(at);return I.set(H.descriptorHash,H),x.set(H.descriptorHash,Re.locatorHash),Re},Fe=async H=>{ce.setTitle(Gn(this.configuration,H));let at=this.resolutionAliases.get(H.descriptorHash);if(typeof at<"u")return Ie(H,this.storedDescriptors.get(at));let Re=A.getResolutionDependencies(H,E),ke=Object.fromEntries(await _c(Object.entries(Re).map(async([Te,Ve])=>{let qe=A.bindDescriptor(Ve,U,E),b=await At(qe);return V.add(b.locatorHash),[Te,b]}))),He=(await Ky(async()=>await A.getCandidates(H,ke,E),Te=>`${Gn(this.configuration,H)}: ${Te}`))[0];if(typeof He>"u")throw new Jt(82,`${Gn(this.configuration,H)}: No candidates found`);if(e.checkResolutions){let{locators:Te}=await p.getSatisfying(H,ke,[He],{...E,resolver:p});if(!Te.find(Ve=>Ve.locatorHash===He.locatorHash))throw new Jt(78,`Invalid resolution ${ZI(this.configuration,H,He)}`)}return I.set(H.descriptorHash,H),x.set(H.descriptorHash,He.locatorHash),ee(He)},At=H=>{let at=N.get(H.descriptorHash);if(typeof at<"u")return at;I.set(H.descriptorHash,H);let Re=Promise.resolve().then(()=>Fe(H));return N.set(H.descriptorHash,Re),Re};for(let H of this.workspaces){let at=H.anchoredDescriptor;te.push(At(at))}for(;te.length>0;){let H=[...te];te.length=0,await _c(H)}});let ue=ol(r.values(),ce=>this.tryWorkspaceByLocator(ce)?ol.skip:ce);if(o.length>0||ue.length>0){let ce=new Set(this.workspaces.flatMap(H=>{let at=v.get(H.anchoredLocator.locatorHash);if(!at)throw new Error("Assertion failed: The workspace should have been resolved");return Array.from(at.dependencies.values(),Re=>{let ke=x.get(Re.descriptorHash);if(!ke)throw new Error("Assertion failed: The resolution should have been registered");return ke})})),ne=H=>ce.has(H.locatorHash)?"0":"1",ee=H=>ba(H),Ie=ks(o,[ne,ee]),Fe=ks(ue,[ne,ee]),At=e.report.getRecommendedLength();Ie.length>0&&e.report.reportInfo(85,`${Ut(this.configuration,"+",yt.ADDED)} ${lS(this.configuration,Ie,At)}`),Fe.length>0&&e.report.reportInfo(85,`${Ut(this.configuration,"-",yt.REMOVED)} ${lS(this.configuration,Fe,At)}`)}let me=new Set(this.resolutionAliases.values()),he=new Set(v.keys()),Be=new Set,we=new Map,g=[];QAt({project:this,accessibleLocators:Be,volatileDescriptors:me,optionalBuilds:he,peerRequirements:we,peerWarnings:g,allDescriptors:I,allResolutions:x,allPackages:v});for(let ce of V)he.delete(ce);for(let ce of me)I.delete(ce),x.delete(ce);let Ee=new Set,Pe=new Set;for(let ce of v.values())ce.conditions!=null&&(!he.has(ce.locatorHash)||(qS(ce,fe)||(qS(ce,ae)&&e.report.reportWarningOnce(77,`${qr(this.configuration,ce)}: Your current architecture (${process.platform}-${process.arch}) is supported by this package, but is missing from the ${Ut(this.configuration,"supportedArchitectures",yt.SETTING)} setting`),Pe.add(ce.locatorHash)),Ee.add(ce.locatorHash)));this.storedResolutions=x,this.storedDescriptors=I,this.storedPackages=v,this.accessibleLocators=Be,this.conditionalLocators=Ee,this.disabledLocators=Pe,this.originalPackages=C,this.optionalBuilds=he,this.peerRequirements=we,this.peerWarnings=g}async fetchEverything({cache:e,report:r,fetcher:o,mode:a,persistProject:n=!0}){let u={mockedPackages:this.disabledLocators,unstablePackages:this.conditionalLocators},A=o||this.configuration.makeFetcher(),p={checksums:this.storedChecksums,project:this,cache:e,fetcher:A,report:r,cacheOptions:u},h=Array.from(new Set(ks(this.storedResolutions.values(),[C=>{let R=this.storedPackages.get(C);if(!R)throw new Error("Assertion failed: The locator should have been registered");return ba(R)}])));a==="update-lockfile"&&(h=h.filter(C=>!this.storedChecksums.has(C)));let E=!1,I=Xs.progressViaCounter(h.length);await r.reportProgress(I);let v=(0,ek.default)(bAt);if(await _c(h.map(C=>v(async()=>{let R=this.storedPackages.get(C);if(!R)throw new Error("Assertion failed: The locator should have been registered");if(qc(R))return;let N;try{N=await A.fetch(R,p)}catch(U){U.message=`${qr(this.configuration,R)}: ${U.message}`,r.reportExceptionOnce(U),E=U;return}N.checksum!=null?this.storedChecksums.set(R.locatorHash,N.checksum):this.storedChecksums.delete(R.locatorHash),N.releaseFs&&N.releaseFs()}).finally(()=>{I.tick()}))),E)throw E;let x=n&&a!=="update-lockfile"?await this.cacheCleanup({cache:e,report:r}):null;if(r.cacheMisses.size>0||x){let R=(await Promise.all([...r.cacheMisses].map(async ue=>{let me=this.storedPackages.get(ue),he=this.storedChecksums.get(ue)??null,Be=e.getLocatorPath(me,he);return(await oe.statPromise(Be)).size}))).reduce((ue,me)=>ue+me,0)-(x?.size??0),N=r.cacheMisses.size,U=x?.count??0,V=`${rS(N,{zero:"No new packages",one:"A package was",more:`${Ut(this.configuration,N,yt.NUMBER)} packages were`})} added to the project`,te=`${rS(U,{zero:"none were",one:"one was",more:`${Ut(this.configuration,U,yt.NUMBER)} were`})} removed`,ae=R!==0?` (${Ut(this.configuration,R,yt.SIZE_DIFF)})`:"",fe=U>0?N>0?`${V}, and ${te}${ae}.`:`${V}, but ${te}${ae}.`:`${V}${ae}.`;r.reportInfo(13,fe)}}async linkEverything({cache:e,report:r,fetcher:o,mode:a}){let n={mockedPackages:this.disabledLocators,unstablePackages:this.conditionalLocators,skipIntegrityCheck:!0},u=o||this.configuration.makeFetcher(),A={checksums:this.storedChecksums,project:this,cache:e,fetcher:u,report:r,cacheOptions:n},p=this.configuration.getLinkers(),h={project:this,report:r},E=new Map(p.map(ce=>{let ne=ce.makeInstaller(h),ee=ce.getCustomDataKey(),Ie=this.linkersCustomData.get(ee);return typeof Ie<"u"&&ne.attachCustomData(Ie),[ce,ne]})),I=new Map,v=new Map,x=new Map,C=new Map(await _c([...this.accessibleLocators].map(async ce=>{let ne=this.storedPackages.get(ce);if(!ne)throw new Error("Assertion failed: The locator should have been registered");return[ce,await u.fetch(ne,A)]}))),R=[],N=new Set,U=[];for(let ce of this.accessibleLocators){let ne=this.storedPackages.get(ce);if(typeof ne>"u")throw new Error("Assertion failed: The locator should have been registered");let ee=C.get(ne.locatorHash);if(typeof ee>"u")throw new Error("Assertion failed: The fetch result should have been registered");let Ie=[],Fe=H=>{Ie.push(H)},At=this.tryWorkspaceByLocator(ne);if(At!==null){let H=[],{scripts:at}=At.manifest;for(let ke of["preinstall","install","postinstall"])at.has(ke)&&H.push({type:0,script:ke});try{for(let[ke,xe]of E)if(ke.supportsPackage(ne,h)&&(await xe.installPackage(ne,ee,{holdFetchResult:Fe})).buildRequest!==null)throw new Error("Assertion failed: Linkers can't return build directives for workspaces; this responsibility befalls to the Yarn core")}finally{Ie.length===0?ee.releaseFs?.():R.push(_c(Ie).catch(()=>{}).then(()=>{ee.releaseFs?.()}))}let Re=z.join(ee.packageFs.getRealPath(),ee.prefixPath);v.set(ne.locatorHash,Re),!qc(ne)&&H.length>0&&x.set(ne.locatorHash,{buildDirectives:H,buildLocations:[Re]})}else{let H=p.find(ke=>ke.supportsPackage(ne,h));if(!H)throw new Jt(12,`${qr(this.configuration,ne)} isn't supported by any available linker`);let at=E.get(H);if(!at)throw new Error("Assertion failed: The installer should have been registered");let Re;try{Re=await at.installPackage(ne,ee,{holdFetchResult:Fe})}finally{Ie.length===0?ee.releaseFs?.():R.push(_c(Ie).then(()=>{}).then(()=>{ee.releaseFs?.()}))}I.set(ne.locatorHash,H),v.set(ne.locatorHash,Re.packageLocation),Re.buildRequest&&Re.packageLocation&&(Re.buildRequest.skipped?(N.add(ne.locatorHash),this.skippedBuilds.has(ne.locatorHash)||U.push([ne,Re.buildRequest.explain])):x.set(ne.locatorHash,{buildDirectives:Re.buildRequest.directives,buildLocations:[Re.packageLocation]}))}}let V=new Map;for(let ce of this.accessibleLocators){let ne=this.storedPackages.get(ce);if(!ne)throw new Error("Assertion failed: The locator should have been registered");let ee=this.tryWorkspaceByLocator(ne)!==null,Ie=async(Fe,At)=>{let H=v.get(ne.locatorHash);if(typeof H>"u")throw new Error(`Assertion failed: The package (${qr(this.configuration,ne)}) should have been registered`);let at=[];for(let Re of ne.dependencies.values()){let ke=this.storedResolutions.get(Re.descriptorHash);if(typeof ke>"u")throw new Error(`Assertion failed: The resolution (${Gn(this.configuration,Re)}, from ${qr(this.configuration,ne)})should have been registered`);let xe=this.storedPackages.get(ke);if(typeof xe>"u")throw new Error(`Assertion failed: The package (${ke}, resolved from ${Gn(this.configuration,Re)}) should have been registered`);let He=this.tryWorkspaceByLocator(xe)===null?I.get(ke):null;if(typeof He>"u")throw new Error(`Assertion failed: The package (${ke}, resolved from ${Gn(this.configuration,Re)}) should have been registered`);He===Fe||He===null?v.get(xe.locatorHash)!==null&&at.push([Re,xe]):!ee&&H!==null&&Yy(V,ke).push(H)}H!==null&&await At.attachInternalDependencies(ne,at)};if(ee)for(let[Fe,At]of E)Fe.supportsPackage(ne,h)&&await Ie(Fe,At);else{let Fe=I.get(ne.locatorHash);if(!Fe)throw new Error("Assertion failed: The linker should have been found");let At=E.get(Fe);if(!At)throw new Error("Assertion failed: The installer should have been registered");await Ie(Fe,At)}}for(let[ce,ne]of V){let ee=this.storedPackages.get(ce);if(!ee)throw new Error("Assertion failed: The package should have been registered");let Ie=I.get(ee.locatorHash);if(!Ie)throw new Error("Assertion failed: The linker should have been found");let Fe=E.get(Ie);if(!Fe)throw new Error("Assertion failed: The installer should have been registered");await Fe.attachExternalDependents(ee,ne)}let te=new Map;for(let[ce,ne]of E){let ee=await ne.finalizeInstall();for(let Ie of ee?.records??[])Ie.buildRequest.skipped?(N.add(Ie.locator.locatorHash),this.skippedBuilds.has(Ie.locator.locatorHash)||U.push([Ie.locator,Ie.buildRequest.explain])):x.set(Ie.locator.locatorHash,{buildDirectives:Ie.buildRequest.directives,buildLocations:Ie.buildLocations});typeof ee?.customData<"u"&&te.set(ce.getCustomDataKey(),ee.customData)}if(this.linkersCustomData=te,await _c(R),a==="skip-build")return;for(let[,ce]of ks(U,([ne])=>ba(ne)))ce(r);let ae=new Set(this.storedPackages.keys()),fe=new Set(x.keys());for(let ce of fe)ae.delete(ce);let ue=(0,Zx.createHash)("sha512");ue.update(process.versions.node),await this.configuration.triggerHook(ce=>ce.globalHashGeneration,this,ce=>{ue.update("\0"),ue.update(ce)});let me=ue.digest("hex"),he=new Map,Be=ce=>{let ne=he.get(ce.locatorHash);if(typeof ne<"u")return ne;let ee=this.storedPackages.get(ce.locatorHash);if(typeof ee>"u")throw new Error("Assertion failed: The package should have been registered");let Ie=(0,Zx.createHash)("sha512");Ie.update(ce.locatorHash),he.set(ce.locatorHash,"<recursive>");for(let Fe of ee.dependencies.values()){let At=this.storedResolutions.get(Fe.descriptorHash);if(typeof At>"u")throw new Error(`Assertion failed: The resolution (${Gn(this.configuration,Fe)}) should have been registered`);let H=this.storedPackages.get(At);if(typeof H>"u")throw new Error("Assertion failed: The package should have been registered");Ie.update(Be(H))}return ne=Ie.digest("hex"),he.set(ce.locatorHash,ne),ne},we=(ce,ne)=>{let ee=(0,Zx.createHash)("sha512");ee.update(me),ee.update(Be(ce));for(let Ie of ne)ee.update(Ie);return ee.digest("hex")},g=new Map,Ee=!1,Pe=ce=>{let ne=new Set([ce.locatorHash]);for(let ee of ne){let Ie=this.storedPackages.get(ee);if(!Ie)throw new Error("Assertion failed: The package should have been registered");for(let Fe of Ie.dependencies.values()){let At=this.storedResolutions.get(Fe.descriptorHash);if(!At)throw new Error(`Assertion failed: The resolution (${Gn(this.configuration,Fe)}) should have been registered`);if(At!==ce.locatorHash&&fe.has(At))return!1;let H=this.storedPackages.get(At);if(!H)throw new Error("Assertion failed: The package should have been registered");let at=this.tryWorkspaceByLocator(H);if(at){if(at.anchoredLocator.locatorHash!==ce.locatorHash&&fe.has(at.anchoredLocator.locatorHash))return!1;ne.add(at.anchoredLocator.locatorHash)}ne.add(At)}}return!0};for(;fe.size>0;){let ce=fe.size,ne=[];for(let ee of fe){let Ie=this.storedPackages.get(ee);if(!Ie)throw new Error("Assertion failed: The package should have been registered");if(!Pe(Ie))continue;let Fe=x.get(Ie.locatorHash);if(!Fe)throw new Error("Assertion failed: The build directive should have been registered");let At=we(Ie,Fe.buildLocations);if(this.storedBuildState.get(Ie.locatorHash)===At){g.set(Ie.locatorHash,At),fe.delete(ee);continue}Ee||(await this.persistInstallStateFile(),Ee=!0),this.storedBuildState.has(Ie.locatorHash)?r.reportInfo(8,`${qr(this.configuration,Ie)} must be rebuilt because its dependency tree changed`):r.reportInfo(7,`${qr(this.configuration,Ie)} must be built because it never has been before or the last one failed`);let H=Fe.buildLocations.map(async at=>{if(!z.isAbsolute(at))throw new Error(`Assertion failed: Expected the build location to be absolute (not ${at})`);for(let Re of Fe.buildDirectives){let ke=`# This file contains the result of Yarn building a package (${ba(Ie)})
-`;switch(Re.type){case 0:ke+=`# Script name: ${Re.script}
-`;break;case 1:ke+=`# Script code: ${Re.script}
-`;break}let xe=null;if(!await oe.mktempPromise(async Te=>{let Ve=z.join(Te,"build.log"),{stdout:qe,stderr:b}=this.configuration.getSubprocessStreams(Ve,{header:ke,prefix:qr(this.configuration,Ie),report:r}),w;try{switch(Re.type){case 0:w=await Wb(Ie,Re.script,[],{cwd:at,project:this,stdin:xe,stdout:qe,stderr:b});break;case 1:w=await EU(Ie,Re.script,[],{cwd:at,project:this,stdin:xe,stdout:qe,stderr:b});break}}catch(F){b.write(F.stack),w=1}if(qe.end(),b.end(),w===0)return!0;oe.detachTemp(Te);let S=`${qr(this.configuration,Ie)} couldn't be built successfully (exit code ${Ut(this.configuration,w,yt.NUMBER)}, logs can be found here: ${Ut(this.configuration,Ve,yt.PATH)})`,y=this.optionalBuilds.has(Ie.locatorHash);return y?r.reportInfo(9,S):r.reportError(9,S),zce&&r.reportFold(le.fromPortablePath(Ve),oe.readFileSync(Ve,"utf8")),y}))return!1}return!0});ne.push(...H,Promise.allSettled(H).then(at=>{fe.delete(ee),at.every(Re=>Re.status==="fulfilled"&&Re.value===!0)&&g.set(Ie.locatorHash,At)}))}if(await _c(ne),ce===fe.size){let ee=Array.from(fe).map(Ie=>{let Fe=this.storedPackages.get(Ie);if(!Fe)throw new Error("Assertion failed: The package should have been registered");return qr(this.configuration,Fe)}).join(", ");r.reportError(3,`Some packages have circular dependencies that make their build order unsatisfiable - as a result they won't be built (affected packages are: ${ee})`);break}}this.storedBuildState=g,this.skippedBuilds=N}async installWithNewReport(e,r){return(await Lt.start({configuration:this.configuration,json:e.json,stdout:e.stdout,forceSectionAlignment:!0,includeLogs:!e.json&&!e.quiet,includeVersion:!0},async a=>{await this.install({...r,report:a})})).exitCode()}async install(e){let r=this.configuration.get("nodeLinker");Ke.telemetry?.reportInstall(r);let o=!1;if(await e.report.startTimerPromise("Project validation",{skipIfEmpty:!0},async()=>{this.configuration.get("enableOfflineMode")&&e.report.reportWarning(90,"Offline work is enabled; Yarn won't fetch packages from the remote registry if it can avoid it"),await this.configuration.triggerHook(E=>E.validateProject,this,{reportWarning:(E,I)=>{e.report.reportWarning(E,I)},reportError:(E,I)=>{e.report.reportError(E,I),o=!0}})}),o)return;let a=await this.configuration.getPackageExtensions();for(let E of a.values())for(let[,I]of E)for(let v of I)v.status="inactive";let n=z.join(this.cwd,dr.lockfile),u=null;if(e.immutable)try{u=await oe.readFilePromise(n,"utf8")}catch(E){throw E.code==="ENOENT"?new Jt(28,"The lockfile would have been created by this install, which is explicitly forbidden."):E}await e.report.startTimerPromise("Resolution step",async()=>{await this.resolveEverything(e)}),await e.report.startTimerPromise("Post-resolution validation",{skipIfEmpty:!0},async()=>{FAt(this,e.report);for(let[,E]of a)for(let[,I]of E)for(let v of I)if(v.userProvided){let x=Ut(this.configuration,v,yt.PACKAGE_EXTENSION);switch(v.status){case"inactive":e.report.reportWarning(68,`${x}: No matching package in the dependency tree; you may not need this rule anymore.`);break;case"redundant":e.report.reportWarning(69,`${x}: This rule seems redundant when applied on the original package; the extension may have been applied upstream.`);break}}if(u!==null){let E=Hg(u,this.generateLockfile());if(E!==u){let I=fpe(n,n,u,E,void 0,void 0,{maxEditLength:100});if(I){e.report.reportSeparator();for(let v of I.hunks){e.report.reportInfo(null,`@@ -${v.oldStart},${v.oldLines} +${v.newStart},${v.newLines} @@`);for(let x of v.lines)x.startsWith("+")?e.report.reportError(28,Ut(this.configuration,x,yt.ADDED)):x.startsWith("-")?e.report.reportError(28,Ut(this.configuration,x,yt.REMOVED)):e.report.reportInfo(null,Ut(this.configuration,x,"grey"))}e.report.reportSeparator()}throw new Jt(28,"The lockfile would have been modified by this install, which is explicitly forbidden.")}}});for(let E of a.values())for(let[,I]of E)for(let v of I)v.userProvided&&v.status==="active"&&Ke.telemetry?.reportPackageExtension(Cd(v,yt.PACKAGE_EXTENSION));await e.report.startTimerPromise("Fetch step",async()=>{await this.fetchEverything(e)});let A=e.immutable?[...new Set(this.configuration.get("immutablePatterns"))].sort():[],p=await Promise.all(A.map(async E=>NS(E,{cwd:this.cwd})));(typeof e.persistProject>"u"||e.persistProject)&&await this.persist(),await e.report.startTimerPromise("Link step",async()=>{if(e.mode==="update-lockfile"){e.report.reportWarning(73,`Skipped due to ${Ut(this.configuration,"mode=update-lockfile",yt.CODE)}`);return}await this.linkEverything(e);let E=await Promise.all(A.map(async I=>NS(I,{cwd:this.cwd})));for(let I=0;I<A.length;++I)p[I]!==E[I]&&e.report.reportError(64,`The checksum for ${A[I]} has been modified by this install, which is explicitly forbidden.`)}),await this.persistInstallStateFile();let h=!1;await e.report.startTimerPromise("Post-install validation",{skipIfEmpty:!0},async()=>{await this.configuration.triggerHook(E=>E.validateProjectAfterInstall,this,{reportWarning:(E,I)=>{e.report.reportWarning(E,I)},reportError:(E,I)=>{e.report.reportError(E,I),h=!0}})}),!h&&await this.configuration.triggerHook(E=>E.afterAllInstalled,this,e)}generateLockfile(){let e=new Map;for(let[n,u]of this.storedResolutions.entries()){let A=e.get(u);A||e.set(u,A=new Set),A.add(n)}let r={},{cacheKey:o}=Nr.getCacheKey(this.configuration);r.__metadata={version:tk,cacheKey:o};for(let[n,u]of e.entries()){let A=this.originalPackages.get(n);if(!A)continue;let p=[];for(let I of u){let v=this.storedDescriptors.get(I);if(!v)throw new Error("Assertion failed: The descriptor should have been registered");p.push(v)}let h=p.map(I=>Sa(I)).sort().join(", "),E=new Ot;E.version=A.linkType==="HARD"?A.version:"0.0.0-use.local",E.languageName=A.languageName,E.dependencies=new Map(A.dependencies),E.peerDependencies=new Map(A.peerDependencies),E.dependenciesMeta=new Map(A.dependenciesMeta),E.peerDependenciesMeta=new Map(A.peerDependenciesMeta),E.bin=new Map(A.bin),r[h]={...E.exportTo({},{compatibilityMode:!1}),linkType:A.linkType.toLowerCase(),resolution:ba(A),checksum:this.storedChecksums.get(A.locatorHash),conditions:A.conditions||void 0}}return`${[`# This file is generated by running "yarn install" inside your project.
-`,`# Manual changes might be lost - proceed with caution!
-`].join("")}
-`+Ba(r)}async persistLockfile(){let e=z.join(this.cwd,dr.lockfile),r="";try{r=await oe.readFilePromise(e,"utf8")}catch{}let o=this.generateLockfile(),a=Hg(r,o);a!==r&&(await oe.writeFilePromise(e,a),this.lockFileChecksum=Vpe(a),this.lockfileNeedsRefresh=!1)}async persistInstallStateFile(){let e=[];for(let u of Object.values(b_))e.push(...u);let r=(0,$x.default)(this,e),o=x_.default.serialize(r),a=Js(o);if(this.installStateChecksum===a)return;let n=this.configuration.get("installStatePath");await oe.mkdirPromise(z.dirname(n),{recursive:!0}),await oe.writeFilePromise(n,await xAt(o)),this.installStateChecksum=a}async restoreInstallState({restoreLinkersCustomData:e=!0,restoreResolutions:r=!0,restoreBuildState:o=!0}={}){let a=this.configuration.get("installStatePath"),n;try{let u=await kAt(await oe.readFilePromise(a));n=x_.default.deserialize(u),this.installStateChecksum=Js(u)}catch{r&&await this.applyLightResolution();return}e&&typeof n.linkersCustomData<"u"&&(this.linkersCustomData=n.linkersCustomData),o&&Object.assign(this,(0,$x.default)(n,b_.restoreBuildState)),r&&(n.lockFileChecksum===this.lockFileChecksum?Object.assign(this,(0,$x.default)(n,b_.restoreResolutions)):await this.applyLightResolution())}async applyLightResolution(){await this.resolveEverything({lockfileOnly:!0,report:new Qi}),await this.persistInstallStateFile()}async persist(){let e=(0,ek.default)(4);await Promise.all([this.persistLockfile(),...this.workspaces.map(r=>e(()=>r.persistManifest()))])}async cacheCleanup({cache:e,report:r}){if(this.configuration.get("enableGlobalCache"))return null;let o=new Set([".gitignore"]);if(!CM(e.cwd,this.cwd)||!await oe.existsPromise(e.cwd))return null;let a=[];for(let u of await oe.readdirPromise(e.cwd)){if(o.has(u))continue;let A=z.resolve(e.cwd,u);e.markedFiles.has(A)||(e.immutable?r.reportError(56,`${Ut(this.configuration,z.basename(A),"magenta")} appears to be unused and would be marked for deletion, but the cache is immutable`):a.push(oe.lstatPromise(A).then(async p=>(await oe.removePromise(A),p.size))))}if(a.length===0)return null;let n=await Promise.all(a);return{count:a.length,size:n.reduce((u,A)=>u+A,0)}}}});function RAt(t){let o=Math.floor(t.timeNow/864e5),a=t.updateInterval*864e5,n=t.state.lastUpdate??t.timeNow+a+Math.floor(a*t.randomInitialInterval),u=n+a,A=t.state.lastTips??o*864e5,p=A+864e5+8*36e5-t.timeZone,h=u<=t.timeNow,E=p<=t.timeNow,I=null;return(h||E||!t.state.lastUpdate||!t.state.lastTips)&&(I={},I.lastUpdate=h?t.timeNow:n,I.lastTips=A,I.blocks=h?{}:t.state.blocks,I.displayedTips=t.state.displayedTips),{nextState:I,triggerUpdate:h,triggerTips:E,nextTips:E?o*864e5:A}}var uC,Zpe=Et(()=>{Pt();N1();ih();Ib();Gl();Qf();uC=class{constructor(e,r){this.values=new Map;this.hits=new Map;this.enumerators=new Map;this.nextTips=0;this.displayedTips=[];this.shouldCommitTips=!1;this.configuration=e;let o=this.getRegistryPath();this.isNew=!oe.existsSync(o),this.shouldShowTips=!1,this.sendReport(r),this.startBuffer()}commitTips(){this.shouldShowTips&&(this.shouldCommitTips=!0)}selectTip(e){let r=new Set(this.displayedTips),o=A=>A&&rn?kf(rn,A):!1,a=e.map((A,p)=>p).filter(A=>e[A]&&o(e[A]?.selector));if(a.length===0)return null;let n=a.filter(A=>!r.has(A));if(n.length===0){let A=Math.floor(a.length*.2);this.displayedTips=A>0?this.displayedTips.slice(-A):[],n=a.filter(p=>!r.has(p))}let u=n[Math.floor(Math.random()*n.length)];return this.displayedTips.push(u),this.commitTips(),e[u]}reportVersion(e){this.reportValue("version",e.replace(/-git\..*/,"-git"))}reportCommandName(e){this.reportValue("commandName",e||"<none>")}reportPluginName(e){this.reportValue("pluginName",e)}reportProject(e){this.reportEnumerator("projectCount",e)}reportInstall(e){this.reportHit("installCount",e)}reportPackageExtension(e){this.reportValue("packageExtension",e)}reportWorkspaceCount(e){this.reportValue("workspaceCount",String(e))}reportDependencyCount(e){this.reportValue("dependencyCount",String(e))}reportValue(e,r){yd(this.values,e).add(r)}reportEnumerator(e,r){yd(this.enumerators,e).add(Js(r))}reportHit(e,r="*"){let o=Wy(this.hits,e),a=al(o,r,()=>0);o.set(r,a+1)}getRegistryPath(){let e=this.configuration.get("globalFolder");return z.join(e,"telemetry.json")}sendReport(e){let r=this.getRegistryPath(),o;try{o=oe.readJsonSync(r)}catch{o={}}let{nextState:a,triggerUpdate:n,triggerTips:u,nextTips:A}=RAt({state:o,timeNow:Date.now(),timeZone:new Date().getTimezoneOffset()*60*1e3,randomInitialInterval:Math.random(),updateInterval:this.configuration.get("telemetryInterval")});if(this.nextTips=A,this.displayedTips=o.displayedTips??[],a!==null)try{oe.mkdirSync(z.dirname(r),{recursive:!0}),oe.writeJsonSync(r,a)}catch{return!1}if(u&&this.configuration.get("enableTips")&&(this.shouldShowTips=!0),n){let p=o.blocks??{};if(Object.keys(p).length===0){let h=`https://browser-http-intake.logs.datadoghq.eu/v1/input/${e}?ddsource=yarn`,E=I=>O4(h,I,{configuration:this.configuration}).catch(()=>{});for(let[I,v]of Object.entries(o.blocks??{})){if(Object.keys(v).length===0)continue;let x=v;x.userId=I,x.reportType="primary";for(let N of Object.keys(x.enumerators??{}))x.enumerators[N]=x.enumerators[N].length;E(x);let C=new Map,R=20;for(let[N,U]of Object.entries(x.values))U.length>0&&C.set(N,U.slice(0,R));for(;C.size>0;){let N={};N.userId=I,N.reportType="secondary",N.metrics={};for(let[U,V]of C)N.metrics[U]=V.shift(),V.length===0&&C.delete(U);E(N)}}}}return!0}applyChanges(){let e=this.getRegistryPath(),r;try{r=oe.readJsonSync(e)}catch{r={}}let o=this.configuration.get("telemetryUserId")??"*",a=r.blocks=r.blocks??{},n=a[o]=a[o]??{};for(let u of this.hits.keys()){let A=n.hits=n.hits??{},p=A[u]=A[u]??{};for(let[h,E]of this.hits.get(u))p[h]=(p[h]??0)+E}for(let u of["values","enumerators"])for(let A of this[u].keys()){let p=n[u]=n[u]??{};p[A]=[...new Set([...p[A]??[],...this[u].get(A)??[]])]}this.shouldCommitTips&&(r.lastTips=this.nextTips,r.displayedTips=this.displayedTips),oe.mkdirSync(z.dirname(e),{recursive:!0}),oe.writeJsonSync(e,r)}startBuffer(){process.on("exit",()=>{try{this.applyChanges()}catch{}})}}});var o2={};zt(o2,{BuildDirectiveType:()=>zx,CACHE_CHECKPOINT:()=>c_,CACHE_VERSION:()=>Kx,Cache:()=>Nr,Configuration:()=>Ke,DEFAULT_RC_FILENAME:()=>j4,FormatType:()=>kle,InstallMode:()=>hl,LEGACY_PLUGINS:()=>v1,LOCKFILE_VERSION:()=>tk,LegacyMigrationResolver:()=>oC,LightReport:()=>fA,LinkType:()=>Jy,LockfileResolver:()=>aC,Manifest:()=>Ot,MessageName:()=>wr,MultiFetcher:()=>hE,PackageExtensionStatus:()=>vN,PackageExtensionType:()=>BN,PeerWarningType:()=>rk,Project:()=>St,Report:()=>Xs,ReportError:()=>Jt,SettingsType:()=>D1,StreamReport:()=>Lt,TAG_REGEXP:()=>FE,TelemetryManager:()=>uC,ThrowReport:()=>Qi,VirtualFetcher:()=>gE,WindowsLinkType:()=>xb,Workspace:()=>cC,WorkspaceFetcher:()=>mE,WorkspaceResolver:()=>Xn,YarnVersion:()=>rn,execUtils:()=>Ur,folderUtils:()=>YS,formatUtils:()=>de,hashUtils:()=>wn,httpUtils:()=>nn,miscUtils:()=>_e,nodeUtils:()=>Vi,parseMessageName:()=>AP,reportOptionDeprecations:()=>NE,scriptUtils:()=>un,semverUtils:()=>kr,stringifyMessageName:()=>Ku,structUtils:()=>W,tgzUtils:()=>Xi,treeUtils:()=>$s});var Ye=Et(()=>{Db();WS();jl();ih();Ib();Gl();vb();BU();Qf();bo();Zfe();spe();u_();P1();P1();ape();A_();lpe();f_();fE();fP();cM();Xpe();Wl();O1();Zpe();P_();AM();fM();Dd();S_();N1();Cne()});var ihe=_((z_t,l2)=>{"use strict";var LAt=process.env.TERM_PROGRAM==="Hyper",NAt=process.platform==="win32",the=process.platform==="linux",F_={ballotDisabled:"\u2612",ballotOff:"\u2610",ballotOn:"\u2611",bullet:"\u2022",bulletWhite:"\u25E6",fullBlock:"\u2588",heart:"\u2764",identicalTo:"\u2261",line:"\u2500",mark:"\u203B",middot:"\xB7",minus:"\uFF0D",multiplication:"\xD7",obelus:"\xF7",pencilDownRight:"\u270E",pencilRight:"\u270F",pencilUpRight:"\u2710",percent:"%",pilcrow2:"\u2761",pilcrow:"\xB6",plusMinus:"\xB1",section:"\xA7",starsOff:"\u2606",starsOn:"\u2605",upDownArrow:"\u2195"},rhe=Object.assign({},F_,{check:"\u221A",cross:"\xD7",ellipsisLarge:"...",ellipsis:"...",info:"i",question:"?",questionSmall:"?",pointer:">",pointerSmall:"\xBB",radioOff:"( )",radioOn:"(*)",warning:"\u203C"}),nhe=Object.assign({},F_,{ballotCross:"\u2718",check:"\u2714",cross:"\u2716",ellipsisLarge:"\u22EF",ellipsis:"\u2026",info:"\u2139",question:"?",questionFull:"\uFF1F",questionSmall:"\uFE56",pointer:the?"\u25B8":"\u276F",pointerSmall:the?"\u2023":"\u203A",radioOff:"\u25EF",radioOn:"\u25C9",warning:"\u26A0"});l2.exports=NAt&&!LAt?rhe:nhe;Reflect.defineProperty(l2.exports,"common",{enumerable:!1,value:F_});Reflect.defineProperty(l2.exports,"windows",{enumerable:!1,value:rhe});Reflect.defineProperty(l2.exports,"other",{enumerable:!1,value:nhe})});var zc=_((V_t,R_)=>{"use strict";var OAt=t=>t!==null&&typeof t=="object"&&!Array.isArray(t),MAt=/[\u001b\u009b][[\]#;?()]*(?:(?:(?:[^\W_]*;?[^\W_]*)\u0007)|(?:(?:[0-9]{1,4}(;[0-9]{0,4})*)?[~0-9=<>cf-nqrtyA-PRZ]))/g,she=()=>{let t={enabled:!0,visible:!0,styles:{},keys:{}};"FORCE_COLOR"in process.env&&(t.enabled=process.env.FORCE_COLOR!=="0");let e=n=>{let u=n.open=`\x1B[${n.codes[0]}m`,A=n.close=`\x1B[${n.codes[1]}m`,p=n.regex=new RegExp(`\\u001b\\[${n.codes[1]}m`,"g");return n.wrap=(h,E)=>{h.includes(A)&&(h=h.replace(p,A+u));let I=u+h+A;return E?I.replace(/\r*\n/g,`${A}$&${u}`):I},n},r=(n,u,A)=>typeof n=="function"?n(u):n.wrap(u,A),o=(n,u)=>{if(n===""||n==null)return"";if(t.enabled===!1)return n;if(t.visible===!1)return"";let A=""+n,p=A.includes(`
-`),h=u.length;for(h>0&&u.includes("unstyle")&&(u=[...new Set(["unstyle",...u])].reverse());h-- >0;)A=r(t.styles[u[h]],A,p);return A},a=(n,u,A)=>{t.styles[n]=e({name:n,codes:u}),(t.keys[A]||(t.keys[A]=[])).push(n),Reflect.defineProperty(t,n,{configurable:!0,enumerable:!0,set(h){t.alias(n,h)},get(){let h=E=>o(E,h.stack);return Reflect.setPrototypeOf(h,t),h.stack=this.stack?this.stack.concat(n):[n],h}})};return a("reset",[0,0],"modifier"),a("bold",[1,22],"modifier"),a("dim",[2,22],"modifier"),a("italic",[3,23],"modifier"),a("underline",[4,24],"modifier"),a("inverse",[7,27],"modifier"),a("hidden",[8,28],"modifier"),a("strikethrough",[9,29],"modifier"),a("black",[30,39],"color"),a("red",[31,39],"color"),a("green",[32,39],"color"),a("yellow",[33,39],"color"),a("blue",[34,39],"color"),a("magenta",[35,39],"color"),a("cyan",[36,39],"color"),a("white",[37,39],"color"),a("gray",[90,39],"color"),a("grey",[90,39],"color"),a("bgBlack",[40,49],"bg"),a("bgRed",[41,49],"bg"),a("bgGreen",[42,49],"bg"),a("bgYellow",[43,49],"bg"),a("bgBlue",[44,49],"bg"),a("bgMagenta",[45,49],"bg"),a("bgCyan",[46,49],"bg"),a("bgWhite",[47,49],"bg"),a("blackBright",[90,39],"bright"),a("redBright",[91,39],"bright"),a("greenBright",[92,39],"bright"),a("yellowBright",[93,39],"bright"),a("blueBright",[94,39],"bright"),a("magentaBright",[95,39],"bright"),a("cyanBright",[96,39],"bright"),a("whiteBright",[97,39],"bright"),a("bgBlackBright",[100,49],"bgBright"),a("bgRedBright",[101,49],"bgBright"),a("bgGreenBright",[102,49],"bgBright"),a("bgYellowBright",[103,49],"bgBright"),a("bgBlueBright",[104,49],"bgBright"),a("bgMagentaBright",[105,49],"bgBright"),a("bgCyanBright",[106,49],"bgBright"),a("bgWhiteBright",[107,49],"bgBright"),t.ansiRegex=MAt,t.hasColor=t.hasAnsi=n=>(t.ansiRegex.lastIndex=0,typeof n=="string"&&n!==""&&t.ansiRegex.test(n)),t.alias=(n,u)=>{let A=typeof u=="string"?t[u]:u;if(typeof A!="function")throw new TypeError("Expected alias to be the name of an existing color (string) or a function");A.stack||(Reflect.defineProperty(A,"name",{value:n}),t.styles[n]=A,A.stack=[n]),Reflect.defineProperty(t,n,{configurable:!0,enumerable:!0,set(p){t.alias(n,p)},get(){let p=h=>o(h,p.stack);return Reflect.setPrototypeOf(p,t),p.stack=this.stack?this.stack.concat(A.stack):A.stack,p}})},t.theme=n=>{if(!OAt(n))throw new TypeError("Expected theme to be an object");for(let u of Object.keys(n))t.alias(u,n[u]);return t},t.alias("unstyle",n=>typeof n=="string"&&n!==""?(t.ansiRegex.lastIndex=0,n.replace(t.ansiRegex,"")):""),t.alias("noop",n=>n),t.none=t.clear=t.noop,t.stripColor=t.unstyle,t.symbols=ihe(),t.define=a,t};R_.exports=she();R_.exports.create=she});var Lo=_(sn=>{"use strict";var UAt=Object.prototype.toString,nc=zc(),ohe=!1,T_=[],ahe={yellow:"blue",cyan:"red",green:"magenta",black:"white",blue:"yellow",red:"cyan",magenta:"green",white:"black"};sn.longest=(t,e)=>t.reduce((r,o)=>Math.max(r,e?o[e].length:o.length),0);sn.hasColor=t=>!!t&&nc.hasColor(t);var ik=sn.isObject=t=>t!==null&&typeof t=="object"&&!Array.isArray(t);sn.nativeType=t=>UAt.call(t).slice(8,-1).toLowerCase().replace(/\s/g,"");sn.isAsyncFn=t=>sn.nativeType(t)==="asyncfunction";sn.isPrimitive=t=>t!=null&&typeof t!="object"&&typeof t!="function";sn.resolve=(t,e,...r)=>typeof e=="function"?e.call(t,...r):e;sn.scrollDown=(t=[])=>[...t.slice(1),t[0]];sn.scrollUp=(t=[])=>[t.pop(),...t];sn.reorder=(t=[])=>{let e=t.slice();return e.sort((r,o)=>r.index>o.index?1:r.index<o.index?-1:0),e};sn.swap=(t,e,r)=>{let o=t.length,a=r===o?0:r<0?o-1:r,n=t[e];t[e]=t[a],t[a]=n};sn.width=(t,e=80)=>{let r=t&&t.columns?t.columns:e;return t&&typeof t.getWindowSize=="function"&&(r=t.getWindowSize()[0]),process.platform==="win32"?r-1:r};sn.height=(t,e=20)=>{let r=t&&t.rows?t.rows:e;return t&&typeof t.getWindowSize=="function"&&(r=t.getWindowSize()[1]),r};sn.wordWrap=(t,e={})=>{if(!t)return t;typeof e=="number"&&(e={width:e});let{indent:r="",newline:o=`
-`+r,width:a=80}=e,n=(o+r).match(/[^\S\n]/g)||[];a-=n.length;let u=`.{1,${a}}([\\s\\u200B]+|$)|[^\\s\\u200B]+?([\\s\\u200B]+|$)`,A=t.trim(),p=new RegExp(u,"g"),h=A.match(p)||[];return h=h.map(E=>E.replace(/\n$/,"")),e.padEnd&&(h=h.map(E=>E.padEnd(a," "))),e.padStart&&(h=h.map(E=>E.padStart(a," "))),r+h.join(o)};sn.unmute=t=>{let e=t.stack.find(o=>nc.keys.color.includes(o));return e?nc[e]:t.stack.find(o=>o.slice(2)==="bg")?nc[e.slice(2)]:o=>o};sn.pascal=t=>t?t[0].toUpperCase()+t.slice(1):"";sn.inverse=t=>{if(!t||!t.stack)return t;let e=t.stack.find(o=>nc.keys.color.includes(o));if(e){let o=nc["bg"+sn.pascal(e)];return o?o.black:t}let r=t.stack.find(o=>o.slice(0,2)==="bg");return r?nc[r.slice(2).toLowerCase()]||t:nc.none};sn.complement=t=>{if(!t||!t.stack)return t;let e=t.stack.find(o=>nc.keys.color.includes(o)),r=t.stack.find(o=>o.slice(0,2)==="bg");if(e&&!r)return nc[ahe[e]||e];if(r){let o=r.slice(2).toLowerCase(),a=ahe[o];return a&&nc["bg"+sn.pascal(a)]||t}return nc.none};sn.meridiem=t=>{let e=t.getHours(),r=t.getMinutes(),o=e>=12?"pm":"am";e=e%12;let a=e===0?12:e,n=r<10?"0"+r:r;return a+":"+n+" "+o};sn.set=(t={},e="",r)=>e.split(".").reduce((o,a,n,u)=>{let A=u.length-1>n?o[a]||{}:r;return!sn.isObject(A)&&n<u.length-1&&(A={}),o[a]=A},t);sn.get=(t={},e="",r)=>{let o=t[e]==null?e.split(".").reduce((a,n)=>a&&a[n],t):t[e];return o??r};sn.mixin=(t,e)=>{if(!ik(t))return e;if(!ik(e))return t;for(let r of Object.keys(e)){let o=Object.getOwnPropertyDescriptor(e,r);if(o.hasOwnProperty("value"))if(t.hasOwnProperty(r)&&ik(o.value)){let a=Object.getOwnPropertyDescriptor(t,r);ik(a.value)?t[r]=sn.merge({},t[r],e[r]):Reflect.defineProperty(t,r,o)}else Reflect.defineProperty(t,r,o);else Reflect.defineProperty(t,r,o)}return t};sn.merge=(...t)=>{let e={};for(let r of t)sn.mixin(e,r);return e};sn.mixinEmitter=(t,e)=>{let r=e.constructor.prototype;for(let o of Object.keys(r)){let a=r[o];typeof a=="function"?sn.define(t,o,a.bind(e)):sn.define(t,o,a)}};sn.onExit=t=>{let e=(r,o)=>{ohe||(ohe=!0,T_.forEach(a=>a()),r===!0&&process.exit(128+o))};T_.length===0&&(process.once("SIGTERM",e.bind(null,!0,15)),process.once("SIGINT",e.bind(null,!0,2)),process.once("exit",e)),T_.push(t)};sn.define=(t,e,r)=>{Reflect.defineProperty(t,e,{value:r})};sn.defineExport=(t,e,r)=>{let o;Reflect.defineProperty(t,e,{enumerable:!0,configurable:!0,set(a){o=a},get(){return o?o():r()}})}});var lhe=_(hC=>{"use strict";hC.ctrl={a:"first",b:"backward",c:"cancel",d:"deleteForward",e:"last",f:"forward",g:"reset",i:"tab",k:"cutForward",l:"reset",n:"newItem",m:"cancel",j:"submit",p:"search",r:"remove",s:"save",u:"undo",w:"cutLeft",x:"toggleCursor",v:"paste"};hC.shift={up:"shiftUp",down:"shiftDown",left:"shiftLeft",right:"shiftRight",tab:"prev"};hC.fn={up:"pageUp",down:"pageDown",left:"pageLeft",right:"pageRight",delete:"deleteForward"};hC.option={b:"backward",f:"forward",d:"cutRight",left:"cutLeft",up:"altUp",down:"altDown"};hC.keys={pageup:"pageUp",pagedown:"pageDown",home:"home",end:"end",cancel:"cancel",delete:"deleteForward",backspace:"delete",down:"down",enter:"submit",escape:"cancel",left:"left",space:"space",number:"number",return:"submit",right:"right",tab:"next",up:"up"}});var Ahe=_((Z_t,uhe)=>{"use strict";var che=ve("readline"),_At=lhe(),HAt=/^(?:\x1b)([a-zA-Z0-9])$/,qAt=/^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/,GAt={OP:"f1",OQ:"f2",OR:"f3",OS:"f4","[11~":"f1","[12~":"f2","[13~":"f3","[14~":"f4","[[A":"f1","[[B":"f2","[[C":"f3","[[D":"f4","[[E":"f5","[15~":"f5","[17~":"f6","[18~":"f7","[19~":"f8","[20~":"f9","[21~":"f10","[23~":"f11","[24~":"f12","[A":"up","[B":"down","[C":"right","[D":"left","[E":"clear","[F":"end","[H":"home",OA:"up",OB:"down",OC:"right",OD:"left",OE:"clear",OF:"end",OH:"home","[1~":"home","[2~":"insert","[3~":"delete","[4~":"end","[5~":"pageup","[6~":"pagedown","[[5~":"pageup","[[6~":"pagedown","[7~":"home","[8~":"end","[a":"up","[b":"down","[c":"right","[d":"left","[e":"clear","[2$":"insert","[3$":"delete","[5$":"pageup","[6$":"pagedown","[7$":"home","[8$":"end",Oa:"up",Ob:"down",Oc:"right",Od:"left",Oe:"clear","[2^":"insert","[3^":"delete","[5^":"pageup","[6^":"pagedown","[7^":"home","[8^":"end","[Z":"tab"};function jAt(t){return["[a","[b","[c","[d","[e","[2$","[3$","[5$","[6$","[7$","[8$","[Z"].includes(t)}function YAt(t){return["Oa","Ob","Oc","Od","Oe","[2^","[3^","[5^","[6^","[7^","[8^"].includes(t)}var sk=(t="",e={})=>{let r,o={name:e.name,ctrl:!1,meta:!1,shift:!1,option:!1,sequence:t,raw:t,...e};if(Buffer.isBuffer(t)?t[0]>127&&t[1]===void 0?(t[0]-=128,t="\x1B"+String(t)):t=String(t):t!==void 0&&typeof t!="string"?t=String(t):t||(t=o.sequence||""),o.sequence=o.sequence||t||o.name,t==="\r")o.raw=void 0,o.name="return";else if(t===`
-`)o.name="enter";else if(t===" ")o.name="tab";else if(t==="\b"||t==="\x7F"||t==="\x1B\x7F"||t==="\x1B\b")o.name="backspace",o.meta=t.charAt(0)==="\x1B";else if(t==="\x1B"||t==="\x1B\x1B")o.name="escape",o.meta=t.length===2;else if(t===" "||t==="\x1B ")o.name="space",o.meta=t.length===2;else if(t<="")o.name=String.fromCharCode(t.charCodeAt(0)+"a".charCodeAt(0)-1),o.ctrl=!0;else if(t.length===1&&t>="0"&&t<="9")o.name="number";else if(t.length===1&&t>="a"&&t<="z")o.name=t;else if(t.length===1&&t>="A"&&t<="Z")o.name=t.toLowerCase(),o.shift=!0;else if(r=HAt.exec(t))o.meta=!0,o.shift=/^[A-Z]$/.test(r[1]);else if(r=qAt.exec(t)){let a=[...t];a[0]==="\x1B"&&a[1]==="\x1B"&&(o.option=!0);let n=[r[1],r[2],r[4],r[6]].filter(Boolean).join(""),u=(r[3]||r[5]||1)-1;o.ctrl=!!(u&4),o.meta=!!(u&10),o.shift=!!(u&1),o.code=n,o.name=GAt[n],o.shift=jAt(n)||o.shift,o.ctrl=YAt(n)||o.ctrl}return o};sk.listen=(t={},e)=>{let{stdin:r}=t;if(!r||r!==process.stdin&&!r.isTTY)throw new Error("Invalid stream passed");let o=che.createInterface({terminal:!0,input:r});che.emitKeypressEvents(r,o);let a=(A,p)=>e(A,sk(A,p),o),n=r.isRaw;return r.isTTY&&r.setRawMode(!0),r.on("keypress",a),o.resume(),()=>{r.isTTY&&r.setRawMode(n),r.removeListener("keypress",a),o.pause(),o.close()}};sk.action=(t,e,r)=>{let o={..._At,...r};return e.ctrl?(e.action=o.ctrl[e.name],e):e.option&&o.option?(e.action=o.option[e.name],e):e.shift?(e.action=o.shift[e.name],e):(e.action=o.keys[e.name],e)};uhe.exports=sk});var phe=_(($_t,fhe)=>{"use strict";fhe.exports=t=>{t.timers=t.timers||{};let e=t.options.timers;if(!!e)for(let r of Object.keys(e)){let o=e[r];typeof o=="number"&&(o={interval:o}),WAt(t,r,o)}};function WAt(t,e,r={}){let o=t.timers[e]={name:e,start:Date.now(),ms:0,tick:0},a=r.interval||120;o.frames=r.frames||[],o.loading=!0;let n=setInterval(()=>{o.ms=Date.now()-o.start,o.tick++,t.render()},a);return o.stop=()=>{o.loading=!1,clearInterval(n)},Reflect.defineProperty(o,"interval",{value:n}),t.once("close",()=>o.stop()),o.stop}});var ghe=_((e8t,hhe)=>{"use strict";var{define:KAt,width:zAt}=Lo(),L_=class{constructor(e){let r=e.options;KAt(this,"_prompt",e),this.type=e.type,this.name=e.name,this.message="",this.header="",this.footer="",this.error="",this.hint="",this.input="",this.cursor=0,this.index=0,this.lines=0,this.tick=0,this.prompt="",this.buffer="",this.width=zAt(r.stdout||process.stdout),Object.assign(this,r),this.name=this.name||this.message,this.message=this.message||this.name,this.symbols=e.symbols,this.styles=e.styles,this.required=new Set,this.cancelled=!1,this.submitted=!1}clone(){let e={...this};return e.status=this.status,e.buffer=Buffer.from(e.buffer),delete e.clone,e}set color(e){this._color=e}get color(){let e=this.prompt.styles;if(this.cancelled)return e.cancelled;if(this.submitted)return e.submitted;let r=this._color||e[this.status];return typeof r=="function"?r:e.pending}set loading(e){this._loading=e}get loading(){return typeof this._loading=="boolean"?this._loading:this.loadingChoices?"choices":!1}get status(){return this.cancelled?"cancelled":this.submitted?"submitted":"pending"}};hhe.exports=L_});var mhe=_((t8t,dhe)=>{"use strict";var N_=Lo(),eo=zc(),O_={default:eo.noop,noop:eo.noop,set inverse(t){this._inverse=t},get inverse(){return this._inverse||N_.inverse(this.primary)},set complement(t){this._complement=t},get complement(){return this._complement||N_.complement(this.primary)},primary:eo.cyan,success:eo.green,danger:eo.magenta,strong:eo.bold,warning:eo.yellow,muted:eo.dim,disabled:eo.gray,dark:eo.dim.gray,underline:eo.underline,set info(t){this._info=t},get info(){return this._info||this.primary},set em(t){this._em=t},get em(){return this._em||this.primary.underline},set heading(t){this._heading=t},get heading(){return this._heading||this.muted.underline},set pending(t){this._pending=t},get pending(){return this._pending||this.primary},set submitted(t){this._submitted=t},get submitted(){return this._submitted||this.success},set cancelled(t){this._cancelled=t},get cancelled(){return this._cancelled||this.danger},set typing(t){this._typing=t},get typing(){return this._typing||this.dim},set placeholder(t){this._placeholder=t},get placeholder(){return this._placeholder||this.primary.dim},set highlight(t){this._highlight=t},get highlight(){return this._highlight||this.inverse}};O_.merge=(t={})=>{t.styles&&typeof t.styles.enabled=="boolean"&&(eo.enabled=t.styles.enabled),t.styles&&typeof t.styles.visible=="boolean"&&(eo.visible=t.styles.visible);let e=N_.merge({},O_,t.styles);delete e.merge;for(let r of Object.keys(eo))e.hasOwnProperty(r)||Reflect.defineProperty(e,r,{get:()=>eo[r]});for(let r of Object.keys(eo.styles))e.hasOwnProperty(r)||Reflect.defineProperty(e,r,{get:()=>eo[r]});return e};dhe.exports=O_});var Ehe=_((r8t,yhe)=>{"use strict";var M_=process.platform==="win32",zf=zc(),VAt=Lo(),U_={...zf.symbols,upDownDoubleArrow:"\u21D5",upDownDoubleArrow2:"\u2B0D",upDownArrow:"\u2195",asterisk:"*",asterism:"\u2042",bulletWhite:"\u25E6",electricArrow:"\u2301",ellipsisLarge:"\u22EF",ellipsisSmall:"\u2026",fullBlock:"\u2588",identicalTo:"\u2261",indicator:zf.symbols.check,leftAngle:"\u2039",mark:"\u203B",minus:"\u2212",multiplication:"\xD7",obelus:"\xF7",percent:"%",pilcrow:"\xB6",pilcrow2:"\u2761",pencilUpRight:"\u2710",pencilDownRight:"\u270E",pencilRight:"\u270F",plus:"+",plusMinus:"\xB1",pointRight:"\u261E",rightAngle:"\u203A",section:"\xA7",hexagon:{off:"\u2B21",on:"\u2B22",disabled:"\u2B22"},ballot:{on:"\u2611",off:"\u2610",disabled:"\u2612"},stars:{on:"\u2605",off:"\u2606",disabled:"\u2606"},folder:{on:"\u25BC",off:"\u25B6",disabled:"\u25B6"},prefix:{pending:zf.symbols.question,submitted:zf.symbols.check,cancelled:zf.symbols.cross},separator:{pending:zf.symbols.pointerSmall,submitted:zf.symbols.middot,cancelled:zf.symbols.middot},radio:{off:M_?"( )":"\u25EF",on:M_?"(*)":"\u25C9",disabled:M_?"(|)":"\u24BE"},numbers:["\u24EA","\u2460","\u2461","\u2462","\u2463","\u2464","\u2465","\u2466","\u2467","\u2468","\u2469","\u246A","\u246B","\u246C","\u246D","\u246E","\u246F","\u2470","\u2471","\u2472","\u2473","\u3251","\u3252","\u3253","\u3254","\u3255","\u3256","\u3257","\u3258","\u3259","\u325A","\u325B","\u325C","\u325D","\u325E","\u325F","\u32B1","\u32B2","\u32B3","\u32B4","\u32B5","\u32B6","\u32B7","\u32B8","\u32B9","\u32BA","\u32BB","\u32BC","\u32BD","\u32BE","\u32BF"]};U_.merge=t=>{let e=VAt.merge({},zf.symbols,U_,t.symbols);return delete e.merge,e};yhe.exports=U_});var whe=_((n8t,Che)=>{"use strict";var JAt=mhe(),XAt=Ehe(),ZAt=Lo();Che.exports=t=>{t.options=ZAt.merge({},t.options.theme,t.options),t.symbols=XAt.merge(t.options),t.styles=JAt.merge(t.options)}});var Phe=_((vhe,Dhe)=>{"use strict";var Ihe=process.env.TERM_PROGRAM==="Apple_Terminal",$At=zc(),__=Lo(),Vc=Dhe.exports=vhe,Di="\x1B[",Bhe="\x07",H_=!1,bh=Vc.code={bell:Bhe,beep:Bhe,beginning:`${Di}G`,down:`${Di}J`,esc:Di,getPosition:`${Di}6n`,hide:`${Di}?25l`,line:`${Di}2K`,lineEnd:`${Di}K`,lineStart:`${Di}1K`,restorePosition:Di+(Ihe?"8":"u"),savePosition:Di+(Ihe?"7":"s"),screen:`${Di}2J`,show:`${Di}?25h`,up:`${Di}1J`},Yd=Vc.cursor={get hidden(){return H_},hide(){return H_=!0,bh.hide},show(){return H_=!1,bh.show},forward:(t=1)=>`${Di}${t}C`,backward:(t=1)=>`${Di}${t}D`,nextLine:(t=1)=>`${Di}E`.repeat(t),prevLine:(t=1)=>`${Di}F`.repeat(t),up:(t=1)=>t?`${Di}${t}A`:"",down:(t=1)=>t?`${Di}${t}B`:"",right:(t=1)=>t?`${Di}${t}C`:"",left:(t=1)=>t?`${Di}${t}D`:"",to(t,e){return e?`${Di}${e+1};${t+1}H`:`${Di}${t+1}G`},move(t=0,e=0){let r="";return r+=t<0?Yd.left(-t):t>0?Yd.right(t):"",r+=e<0?Yd.up(-e):e>0?Yd.down(e):"",r},restore(t={}){let{after:e,cursor:r,initial:o,input:a,prompt:n,size:u,value:A}=t;if(o=__.isPrimitive(o)?String(o):"",a=__.isPrimitive(a)?String(a):"",A=__.isPrimitive(A)?String(A):"",u){let p=Vc.cursor.up(u)+Vc.cursor.to(n.length),h=a.length-r;return h>0&&(p+=Vc.cursor.left(h)),p}if(A||e){let p=!a&&!!o?-o.length:-a.length+r;return e&&(p-=e.length),a===""&&o&&!n.includes(o)&&(p+=o.length),Vc.cursor.move(p)}}},q_=Vc.erase={screen:bh.screen,up:bh.up,down:bh.down,line:bh.line,lineEnd:bh.lineEnd,lineStart:bh.lineStart,lines(t){let e="";for(let r=0;r<t;r++)e+=Vc.erase.line+(r<t-1?Vc.cursor.up(1):"");return t&&(e+=Vc.code.beginning),e}};Vc.clear=(t="",e=process.stdout.columns)=>{if(!e)return q_.line+Yd.to(0);let r=n=>[...$At.unstyle(n)].length,o=t.split(/\r?\n/),a=0;for(let n of o)a+=1+Math.floor(Math.max(r(n)-1,0)/e);return(q_.line+Yd.prevLine()).repeat(a-1)+q_.line+Yd.to(0)}});var gC=_((i8t,bhe)=>{"use strict";var eft=ve("events"),She=zc(),G_=Ahe(),tft=phe(),rft=ghe(),nft=whe(),Ra=Lo(),Wd=Phe(),c2=class extends eft{constructor(e={}){super(),this.name=e.name,this.type=e.type,this.options=e,nft(this),tft(this),this.state=new rft(this),this.initial=[e.initial,e.default].find(r=>r!=null),this.stdout=e.stdout||process.stdout,this.stdin=e.stdin||process.stdin,this.scale=e.scale||1,this.term=this.options.term||process.env.TERM_PROGRAM,this.margin=sft(this.options.margin),this.setMaxListeners(0),ift(this)}async keypress(e,r={}){this.keypressed=!0;let o=G_.action(e,G_(e,r),this.options.actions);this.state.keypress=o,this.emit("keypress",e,o),this.emit("state",this.state.clone());let a=this.options[o.action]||this[o.action]||this.dispatch;if(typeof a=="function")return await a.call(this,e,o);this.alert()}alert(){delete this.state.alert,this.options.show===!1?this.emit("alert"):this.stdout.write(Wd.code.beep)}cursorHide(){this.stdout.write(Wd.cursor.hide()),Ra.onExit(()=>this.cursorShow())}cursorShow(){this.stdout.write(Wd.cursor.show())}write(e){!e||(this.stdout&&this.state.show!==!1&&this.stdout.write(e),this.state.buffer+=e)}clear(e=0){let r=this.state.buffer;this.state.buffer="",!(!r&&!e||this.options.show===!1)&&this.stdout.write(Wd.cursor.down(e)+Wd.clear(r,this.width))}restore(){if(this.state.closed||this.options.show===!1)return;let{prompt:e,after:r,rest:o}=this.sections(),{cursor:a,initial:n="",input:u="",value:A=""}=this,p=this.state.size=o.length,h={after:r,cursor:a,initial:n,input:u,prompt:e,size:p,value:A},E=Wd.cursor.restore(h);E&&this.stdout.write(E)}sections(){let{buffer:e,input:r,prompt:o}=this.state;o=She.unstyle(o);let a=She.unstyle(e),n=a.indexOf(o),u=a.slice(0,n),p=a.slice(n).split(`
-`),h=p[0],E=p[p.length-1],v=(o+(r?" "+r:"")).length,x=v<h.length?h.slice(v+1):"";return{header:u,prompt:h,after:x,rest:p.slice(1),last:E}}async submit(){this.state.submitted=!0,this.state.validating=!0,this.options.onSubmit&&await this.options.onSubmit.call(this,this.name,this.value,this);let e=this.state.error||await this.validate(this.value,this.state);if(e!==!0){let r=`
-`+this.symbols.pointer+" ";typeof e=="string"?r+=e.trim():r+="Invalid input",this.state.error=`
-`+this.styles.danger(r),this.state.submitted=!1,await this.render(),await this.alert(),this.state.validating=!1,this.state.error=void 0;return}this.state.validating=!1,await this.render(),await this.close(),this.value=await this.result(this.value),this.emit("submit",this.value)}async cancel(e){this.state.cancelled=this.state.submitted=!0,await this.render(),await this.close(),typeof this.options.onCancel=="function"&&await this.options.onCancel.call(this,this.name,this.value,this),this.emit("cancel",await this.error(e))}async close(){this.state.closed=!0;try{let e=this.sections(),r=Math.ceil(e.prompt.length/this.width);e.rest&&this.write(Wd.cursor.down(e.rest.length)),this.write(`
-`.repeat(r))}catch{}this.emit("close")}start(){!this.stop&&this.options.show!==!1&&(this.stop=G_.listen(this,this.keypress.bind(this)),this.once("close",this.stop))}async skip(){return this.skipped=this.options.skip===!0,typeof this.options.skip=="function"&&(this.skipped=await this.options.skip.call(this,this.name,this.value)),this.skipped}async initialize(){let{format:e,options:r,result:o}=this;if(this.format=()=>e.call(this,this.value),this.result=()=>o.call(this,this.value),typeof r.initial=="function"&&(this.initial=await r.initial.call(this,this)),typeof r.onRun=="function"&&await r.onRun.call(this,this),typeof r.onSubmit=="function"){let a=r.onSubmit.bind(this),n=this.submit.bind(this);delete this.options.onSubmit,this.submit=async()=>(await a(this.name,this.value,this),n())}await this.start(),await this.render()}render(){throw new Error("expected prompt to have a custom render method")}run(){return new Promise(async(e,r)=>{if(this.once("submit",e),this.once("cancel",r),await this.skip())return this.render=()=>{},this.submit();await this.initialize(),this.emit("run")})}async element(e,r,o){let{options:a,state:n,symbols:u,timers:A}=this,p=A&&A[e];n.timer=p;let h=a[e]||n[e]||u[e],E=r&&r[e]!=null?r[e]:await h;if(E==="")return E;let I=await this.resolve(E,n,r,o);return!I&&r&&r[e]?this.resolve(h,n,r,o):I}async prefix(){let e=await this.element("prefix")||this.symbols,r=this.timers&&this.timers.prefix,o=this.state;return o.timer=r,Ra.isObject(e)&&(e=e[o.status]||e.pending),Ra.hasColor(e)?e:(this.styles[o.status]||this.styles.pending)(e)}async message(){let e=await this.element("message");return Ra.hasColor(e)?e:this.styles.strong(e)}async separator(){let e=await this.element("separator")||this.symbols,r=this.timers&&this.timers.separator,o=this.state;o.timer=r;let a=e[o.status]||e.pending||o.separator,n=await this.resolve(a,o);return Ra.isObject(n)&&(n=n[o.status]||n.pending),Ra.hasColor(n)?n:this.styles.muted(n)}async pointer(e,r){let o=await this.element("pointer",e,r);if(typeof o=="string"&&Ra.hasColor(o))return o;if(o){let a=this.styles,n=this.index===r,u=n?a.primary:h=>h,A=await this.resolve(o[n?"on":"off"]||o,this.state),p=Ra.hasColor(A)?A:u(A);return n?p:" ".repeat(A.length)}}async indicator(e,r){let o=await this.element("indicator",e,r);if(typeof o=="string"&&Ra.hasColor(o))return o;if(o){let a=this.styles,n=e.enabled===!0,u=n?a.success:a.dark,A=o[n?"on":"off"]||o;return Ra.hasColor(A)?A:u(A)}return""}body(){return null}footer(){if(this.state.status==="pending")return this.element("footer")}header(){if(this.state.status==="pending")return this.element("header")}async hint(){if(this.state.status==="pending"&&!this.isValue(this.state.input)){let e=await this.element("hint");return Ra.hasColor(e)?e:this.styles.muted(e)}}error(e){return this.state.submitted?"":e||this.state.error}format(e){return e}result(e){return e}validate(e){return this.options.required===!0?this.isValue(e):!0}isValue(e){return e!=null&&e!==""}resolve(e,...r){return Ra.resolve(this,e,...r)}get base(){return c2.prototype}get style(){return this.styles[this.state.status]}get height(){return this.options.rows||Ra.height(this.stdout,25)}get width(){return this.options.columns||Ra.width(this.stdout,80)}get size(){return{width:this.width,height:this.height}}set cursor(e){this.state.cursor=e}get cursor(){return this.state.cursor}set input(e){this.state.input=e}get input(){return this.state.input}set value(e){this.state.value=e}get value(){let{input:e,value:r}=this.state,o=[r,e].find(this.isValue.bind(this));return this.isValue(o)?o:this.initial}static get prompt(){return e=>new this(e).run()}};function ift(t){let e=a=>t[a]===void 0||typeof t[a]=="function",r=["actions","choices","initial","margin","roles","styles","symbols","theme","timers","value"],o=["body","footer","error","header","hint","indicator","message","prefix","separator","skip"];for(let a of Object.keys(t.options)){if(r.includes(a)||/^on[A-Z]/.test(a))continue;let n=t.options[a];typeof n=="function"&&e(a)?o.includes(a)||(t[a]=n.bind(t)):typeof t[a]!="function"&&(t[a]=n)}}function sft(t){typeof t=="number"&&(t=[t,t,t,t]);let e=[].concat(t||[]),r=a=>a%2===0?`
-`:" ",o=[];for(let a=0;a<4;a++){let n=r(a);e[a]?o.push(n.repeat(e[a])):o.push("")}return o}bhe.exports=c2});var Qhe=_((s8t,khe)=>{"use strict";var oft=Lo(),xhe={default(t,e){return e},checkbox(t,e){throw new Error("checkbox role is not implemented yet")},editable(t,e){throw new Error("editable role is not implemented yet")},expandable(t,e){throw new Error("expandable role is not implemented yet")},heading(t,e){return e.disabled="",e.indicator=[e.indicator," "].find(r=>r!=null),e.message=e.message||"",e},input(t,e){throw new Error("input role is not implemented yet")},option(t,e){return xhe.default(t,e)},radio(t,e){throw new Error("radio role is not implemented yet")},separator(t,e){return e.disabled="",e.indicator=[e.indicator," "].find(r=>r!=null),e.message=e.message||t.symbols.line.repeat(5),e},spacer(t,e){return e}};khe.exports=(t,e={})=>{let r=oft.merge({},xhe,e.roles);return r[t]||r.default}});var u2=_((o8t,The)=>{"use strict";var aft=zc(),lft=gC(),cft=Qhe(),ok=Lo(),{reorder:j_,scrollUp:uft,scrollDown:Aft,isObject:Fhe,swap:fft}=ok,Y_=class extends lft{constructor(e){super(e),this.cursorHide(),this.maxSelected=e.maxSelected||1/0,this.multiple=e.multiple||!1,this.initial=e.initial||0,this.delay=e.delay||0,this.longest=0,this.num=""}async initialize(){typeof this.options.initial=="function"&&(this.initial=await this.options.initial.call(this)),await this.reset(!0),await super.initialize()}async reset(){let{choices:e,initial:r,autofocus:o,suggest:a}=this.options;if(this.state._choices=[],this.state.choices=[],this.choices=await Promise.all(await this.toChoices(e)),this.choices.forEach(n=>n.enabled=!1),typeof a!="function"&&this.selectable.length===0)throw new Error("At least one choice must be selectable");Fhe(r)&&(r=Object.keys(r)),Array.isArray(r)?(o!=null&&(this.index=this.findIndex(o)),r.forEach(n=>this.enable(this.find(n))),await this.render()):(o!=null&&(r=o),typeof r=="string"&&(r=this.findIndex(r)),typeof r=="number"&&r>-1&&(this.index=Math.max(0,Math.min(r,this.choices.length)),this.enable(this.find(this.index)))),this.isDisabled(this.focused)&&await this.down()}async toChoices(e,r){this.state.loadingChoices=!0;let o=[],a=0,n=async(u,A)=>{typeof u=="function"&&(u=await u.call(this)),u instanceof Promise&&(u=await u);for(let p=0;p<u.length;p++){let h=u[p]=await this.toChoice(u[p],a++,A);o.push(h),h.choices&&await n(h.choices,h)}return o};return n(e,r).then(u=>(this.state.loadingChoices=!1,u))}async toChoice(e,r,o){if(typeof e=="function"&&(e=await e.call(this,this)),e instanceof Promise&&(e=await e),typeof e=="string"&&(e={name:e}),e.normalized)return e;e.normalized=!0;let a=e.value;if(e=cft(e.role,this.options)(this,e),typeof e.disabled=="string"&&!e.hint&&(e.hint=e.disabled,e.disabled=!0),e.disabled===!0&&e.hint==null&&(e.hint="(disabled)"),e.index!=null)return e;e.name=e.name||e.key||e.title||e.value||e.message,e.message=e.message||e.name||"",e.value=[e.value,e.name].find(this.isValue.bind(this)),e.input="",e.index=r,e.cursor=0,ok.define(e,"parent",o),e.level=o?o.level+1:1,e.indent==null&&(e.indent=o?o.indent+" ":e.indent||""),e.path=o?o.path+"."+e.name:e.name,e.enabled=!!(this.multiple&&!this.isDisabled(e)&&(e.enabled||this.isSelected(e))),this.isDisabled(e)||(this.longest=Math.max(this.longest,aft.unstyle(e.message).length));let u={...e};return e.reset=(A=u.input,p=u.value)=>{for(let h of Object.keys(u))e[h]=u[h];e.input=A,e.value=p},a==null&&typeof e.initial=="function"&&(e.input=await e.initial.call(this,this.state,e,r)),e}async onChoice(e,r){this.emit("choice",e,r,this),typeof e.onChoice=="function"&&await e.onChoice.call(this,this.state,e,r)}async addChoice(e,r,o){let a=await this.toChoice(e,r,o);return this.choices.push(a),this.index=this.choices.length-1,this.limit=this.choices.length,a}async newItem(e,r,o){let a={name:"New choice name?",editable:!0,newChoice:!0,...e},n=await this.addChoice(a,r,o);return n.updateChoice=()=>{delete n.newChoice,n.name=n.message=n.input,n.input="",n.cursor=0},this.render()}indent(e){return e.indent==null?e.level>1?" ".repeat(e.level-1):"":e.indent}dispatch(e,r){if(this.multiple&&this[r.name])return this[r.name]();this.alert()}focus(e,r){return typeof r!="boolean"&&(r=e.enabled),r&&!e.enabled&&this.selected.length>=this.maxSelected?this.alert():(this.index=e.index,e.enabled=r&&!this.isDisabled(e),e)}space(){return this.multiple?(this.toggle(this.focused),this.render()):this.alert()}a(){if(this.maxSelected<this.choices.length)return this.alert();let e=this.selectable.every(r=>r.enabled);return this.choices.forEach(r=>r.enabled=!e),this.render()}i(){return this.choices.length-this.selected.length>this.maxSelected?this.alert():(this.choices.forEach(e=>e.enabled=!e.enabled),this.render())}g(e=this.focused){return this.choices.some(r=>!!r.parent)?(this.toggle(e.parent&&!e.choices?e.parent:e),this.render()):this.a()}toggle(e,r){if(!e.enabled&&this.selected.length>=this.maxSelected)return this.alert();typeof r!="boolean"&&(r=!e.enabled),e.enabled=r,e.choices&&e.choices.forEach(a=>this.toggle(a,r));let o=e.parent;for(;o;){let a=o.choices.filter(n=>this.isDisabled(n));o.enabled=a.every(n=>n.enabled===!0),o=o.parent}return Rhe(this,this.choices),this.emit("toggle",e,this),e}enable(e){return this.selected.length>=this.maxSelected?this.alert():(e.enabled=!this.isDisabled(e),e.choices&&e.choices.forEach(this.enable.bind(this)),e)}disable(e){return e.enabled=!1,e.choices&&e.choices.forEach(this.disable.bind(this)),e}number(e){this.num+=e;let r=o=>{let a=Number(o);if(a>this.choices.length-1)return this.alert();let n=this.focused,u=this.choices.find(A=>a===A.index);if(!u.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(this.visible.indexOf(u)===-1){let A=j_(this.choices),p=A.indexOf(u);if(n.index>p){let h=A.slice(p,p+this.limit),E=A.filter(I=>!h.includes(I));this.choices=h.concat(E)}else{let h=p-this.limit+1;this.choices=A.slice(h).concat(A.slice(0,h))}}return this.index=this.choices.indexOf(u),this.toggle(this.focused),this.render()};return clearTimeout(this.numberTimeout),new Promise(o=>{let a=this.choices.length,n=this.num,u=(A=!1,p)=>{clearTimeout(this.numberTimeout),A&&(p=r(n)),this.num="",o(p)};if(n==="0"||n.length===1&&Number(n+"0")>a)return u(!0);if(Number(n)>a)return u(!1,this.alert());this.numberTimeout=setTimeout(()=>u(!0),this.delay)})}home(){return this.choices=j_(this.choices),this.index=0,this.render()}end(){let e=this.choices.length-this.limit,r=j_(this.choices);return this.choices=r.slice(e).concat(r.slice(0,e)),this.index=this.limit-1,this.render()}first(){return this.index=0,this.render()}last(){return this.index=this.visible.length-1,this.render()}prev(){return this.visible.length<=1?this.alert():this.up()}next(){return this.visible.length<=1?this.alert():this.down()}right(){return this.cursor>=this.input.length?this.alert():(this.cursor++,this.render())}left(){return this.cursor<=0?this.alert():(this.cursor--,this.render())}up(){let e=this.choices.length,r=this.visible.length,o=this.index;return this.options.scroll===!1&&o===0?this.alert():e>r&&o===0?this.scrollUp():(this.index=(o-1%e+e)%e,this.isDisabled()?this.up():this.render())}down(){let e=this.choices.length,r=this.visible.length,o=this.index;return this.options.scroll===!1&&o===r-1?this.alert():e>r&&o===r-1?this.scrollDown():(this.index=(o+1)%e,this.isDisabled()?this.down():this.render())}scrollUp(e=0){return this.choices=uft(this.choices),this.index=e,this.isDisabled()?this.up():this.render()}scrollDown(e=this.visible.length-1){return this.choices=Aft(this.choices),this.index=e,this.isDisabled()?this.down():this.render()}async shiftUp(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index-1),await this.up(),this.sorting=!1;return}return this.scrollUp(this.index)}async shiftDown(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index+1),await this.down(),this.sorting=!1;return}return this.scrollDown(this.index)}pageUp(){return this.visible.length<=1?this.alert():(this.limit=Math.max(this.limit-1,0),this.index=Math.min(this.limit-1,this.index),this._limit=this.limit,this.isDisabled()?this.up():this.render())}pageDown(){return this.visible.length>=this.choices.length?this.alert():(this.index=Math.max(0,this.index),this.limit=Math.min(this.limit+1,this.choices.length),this._limit=this.limit,this.isDisabled()?this.down():this.render())}swap(e){fft(this.choices,this.index,e)}isDisabled(e=this.focused){return e&&["disabled","collapsed","hidden","completing","readonly"].some(o=>e[o]===!0)?!0:e&&e.role==="heading"}isEnabled(e=this.focused){if(Array.isArray(e))return e.every(r=>this.isEnabled(r));if(e.choices){let r=e.choices.filter(o=>!this.isDisabled(o));return e.enabled&&r.every(o=>this.isEnabled(o))}return e.enabled&&!this.isDisabled(e)}isChoice(e,r){return e.name===r||e.index===Number(r)}isSelected(e){return Array.isArray(this.initial)?this.initial.some(r=>this.isChoice(e,r)):this.isChoice(e,this.initial)}map(e=[],r="value"){return[].concat(e||[]).reduce((o,a)=>(o[a]=this.find(a,r),o),{})}filter(e,r){let a=typeof e=="function"?e:(A,p)=>[A.name,p].includes(e),u=(this.options.multiple?this.state._choices:this.choices).filter(a);return r?u.map(A=>A[r]):u}find(e,r){if(Fhe(e))return r?e[r]:e;let a=typeof e=="function"?e:(u,A)=>[u.name,A].includes(e),n=this.choices.find(a);if(n)return r?n[r]:n}findIndex(e){return this.choices.indexOf(this.find(e))}async submit(){let e=this.focused;if(!e)return this.alert();if(e.newChoice)return e.input?(e.updateChoice(),this.render()):this.alert();if(this.choices.some(u=>u.newChoice))return this.alert();let{reorder:r,sort:o}=this.options,a=this.multiple===!0,n=this.selected;return n===void 0?this.alert():(Array.isArray(n)&&r!==!1&&o!==!0&&(n=ok.reorder(n)),this.value=a?n.map(u=>u.name):n.name,super.submit())}set choices(e=[]){this.state._choices=this.state._choices||[],this.state.choices=e;for(let r of e)this.state._choices.some(o=>o.name===r.name)||this.state._choices.push(r);if(!this._initial&&this.options.initial){this._initial=!0;let r=this.initial;if(typeof r=="string"||typeof r=="number"){let o=this.find(r);o&&(this.initial=o.index,this.focus(o,!0))}}}get choices(){return Rhe(this,this.state.choices||[])}set visible(e){this.state.visible=e}get visible(){return(this.state.visible||this.choices).slice(0,this.limit)}set limit(e){this.state.limit=e}get limit(){let{state:e,options:r,choices:o}=this,a=e.limit||this._limit||r.limit||o.length;return Math.min(a,this.height)}set value(e){super.value=e}get value(){return typeof super.value!="string"&&super.value===this.initial?this.input:super.value}set index(e){this.state.index=e}get index(){return Math.max(0,this.state?this.state.index:0)}get enabled(){return this.filter(this.isEnabled.bind(this))}get focused(){let e=this.choices[this.index];return e&&this.state.submitted&&this.multiple!==!0&&(e.enabled=!0),e}get selectable(){return this.choices.filter(e=>!this.isDisabled(e))}get selected(){return this.multiple?this.enabled:this.focused}};function Rhe(t,e){if(e instanceof Promise)return e;if(typeof e=="function"){if(ok.isAsyncFn(e))return e;e=e.call(t,t)}for(let r of e){if(Array.isArray(r.choices)){let o=r.choices.filter(a=>!t.isDisabled(a));r.enabled=o.every(a=>a.enabled===!0)}t.isDisabled(r)===!0&&delete r.enabled}return e}The.exports=Y_});var xh=_((a8t,Lhe)=>{"use strict";var pft=u2(),W_=Lo(),K_=class extends pft{constructor(e){super(e),this.emptyError=this.options.emptyError||"No items were selected"}async dispatch(e,r){if(this.multiple)return this[r.name]?await this[r.name](e,r):await super.dispatch(e,r);this.alert()}separator(){if(this.options.separator)return super.separator();let e=this.styles.muted(this.symbols.ellipsis);return this.state.submitted?super.separator():e}pointer(e,r){return!this.multiple||this.options.pointer?super.pointer(e,r):""}indicator(e,r){return this.multiple?super.indicator(e,r):""}choiceMessage(e,r){let o=this.resolve(e.message,this.state,e,r);return e.role==="heading"&&!W_.hasColor(o)&&(o=this.styles.strong(o)),this.resolve(o,this.state,e,r)}choiceSeparator(){return":"}async renderChoice(e,r){await this.onChoice(e,r);let o=this.index===r,a=await this.pointer(e,r),n=await this.indicator(e,r)+(e.pad||""),u=await this.resolve(e.hint,this.state,e,r);u&&!W_.hasColor(u)&&(u=this.styles.muted(u));let A=this.indent(e),p=await this.choiceMessage(e,r),h=()=>[this.margin[3],A+a+n,p,this.margin[1],u].filter(Boolean).join(" ");return e.role==="heading"?h():e.disabled?(W_.hasColor(p)||(p=this.styles.disabled(p)),h()):(o&&(p=this.styles.em(p)),h())}async renderChoices(){if(this.state.loading==="choices")return this.styles.warning("Loading choices");if(this.state.submitted)return"";let e=this.visible.map(async(n,u)=>await this.renderChoice(n,u)),r=await Promise.all(e);r.length||r.push(this.styles.danger("No matching choices"));let o=this.margin[0]+r.join(`
-`),a;return this.options.choicesHeader&&(a=await this.resolve(this.options.choicesHeader,this.state)),[a,o].filter(Boolean).join(`
-`)}format(){return!this.state.submitted||this.state.cancelled?"":Array.isArray(this.selected)?this.selected.map(e=>this.styles.primary(e.name)).join(", "):this.styles.primary(this.selected.name)}async render(){let{submitted:e,size:r}=this.state,o="",a=await this.header(),n=await this.prefix(),u=await this.separator(),A=await this.message();this.options.promptLine!==!1&&(o=[n,A,u,""].join(" "),this.state.prompt=o);let p=await this.format(),h=await this.error()||await this.hint(),E=await this.renderChoices(),I=await this.footer();p&&(o+=p),h&&!o.includes(h)&&(o+=" "+h),e&&!p&&!E.trim()&&this.multiple&&this.emptyError!=null&&(o+=this.styles.danger(this.emptyError)),this.clear(r),this.write([a,o,E,I].filter(Boolean).join(`
-`)),this.write(this.margin[2]),this.restore()}};Lhe.exports=K_});var Ohe=_((l8t,Nhe)=>{"use strict";var hft=xh(),gft=(t,e)=>{let r=t.toLowerCase();return o=>{let n=o.toLowerCase().indexOf(r),u=e(o.slice(n,n+r.length));return n>=0?o.slice(0,n)+u+o.slice(n+r.length):o}},z_=class extends hft{constructor(e){super(e),this.cursorShow()}moveCursor(e){this.state.cursor+=e}dispatch(e){return this.append(e)}space(e){return this.options.multiple?super.space(e):this.append(e)}append(e){let{cursor:r,input:o}=this.state;return this.input=o.slice(0,r)+e+o.slice(r),this.moveCursor(1),this.complete()}delete(){let{cursor:e,input:r}=this.state;return r?(this.input=r.slice(0,e-1)+r.slice(e),this.moveCursor(-1),this.complete()):this.alert()}deleteForward(){let{cursor:e,input:r}=this.state;return r[e]===void 0?this.alert():(this.input=`${r}`.slice(0,e)+`${r}`.slice(e+1),this.complete())}number(e){return this.append(e)}async complete(){this.completing=!0,this.choices=await this.suggest(this.input,this.state._choices),this.state.limit=void 0,this.index=Math.min(Math.max(this.visible.length-1,0),this.index),await this.render(),this.completing=!1}suggest(e=this.input,r=this.state._choices){if(typeof this.options.suggest=="function")return this.options.suggest.call(this,e,r);let o=e.toLowerCase();return r.filter(a=>a.message.toLowerCase().includes(o))}pointer(){return""}format(){if(!this.focused)return this.input;if(this.options.multiple&&this.state.submitted)return this.selected.map(e=>this.styles.primary(e.message)).join(", ");if(this.state.submitted){let e=this.value=this.input=this.focused.value;return this.styles.primary(e)}return this.input}async render(){if(this.state.status!=="pending")return super.render();let e=this.options.highlight?this.options.highlight.bind(this):this.styles.placeholder,r=gft(this.input,e),o=this.choices;this.choices=o.map(a=>({...a,message:r(a.message)})),await super.render(),this.choices=o}submit(){return this.options.multiple&&(this.value=this.selected.map(e=>e.name)),super.submit()}};Nhe.exports=z_});var J_=_((c8t,Mhe)=>{"use strict";var V_=Lo();Mhe.exports=(t,e={})=>{t.cursorHide();let{input:r="",initial:o="",pos:a,showCursor:n=!0,color:u}=e,A=u||t.styles.placeholder,p=V_.inverse(t.styles.primary),h=R=>p(t.styles.black(R)),E=r,I=" ",v=h(I);if(t.blink&&t.blink.off===!0&&(h=R=>R,v=""),n&&a===0&&o===""&&r==="")return h(I);if(n&&a===0&&(r===o||r===""))return h(o[0])+A(o.slice(1));o=V_.isPrimitive(o)?`${o}`:"",r=V_.isPrimitive(r)?`${r}`:"";let x=o&&o.startsWith(r)&&o!==r,C=x?h(o[r.length]):v;if(a!==r.length&&n===!0&&(E=r.slice(0,a)+h(r[a])+r.slice(a+1),C=""),n===!1&&(C=""),x){let R=t.styles.unstyle(E+C);return E+C+A(o.slice(R.length))}return E+C}});var ak=_((u8t,Uhe)=>{"use strict";var dft=zc(),mft=xh(),yft=J_(),X_=class extends mft{constructor(e){super({...e,multiple:!0}),this.type="form",this.initial=this.options.initial,this.align=[this.options.align,"right"].find(r=>r!=null),this.emptyError="",this.values={}}async reset(e){return await super.reset(),e===!0&&(this._index=this.index),this.index=this._index,this.values={},this.choices.forEach(r=>r.reset&&r.reset()),this.render()}dispatch(e){return!!e&&this.append(e)}append(e){let r=this.focused;if(!r)return this.alert();let{cursor:o,input:a}=r;return r.value=r.input=a.slice(0,o)+e+a.slice(o),r.cursor++,this.render()}delete(){let e=this.focused;if(!e||e.cursor<=0)return this.alert();let{cursor:r,input:o}=e;return e.value=e.input=o.slice(0,r-1)+o.slice(r),e.cursor--,this.render()}deleteForward(){let e=this.focused;if(!e)return this.alert();let{cursor:r,input:o}=e;if(o[r]===void 0)return this.alert();let a=`${o}`.slice(0,r)+`${o}`.slice(r+1);return e.value=e.input=a,this.render()}right(){let e=this.focused;return e?e.cursor>=e.input.length?this.alert():(e.cursor++,this.render()):this.alert()}left(){let e=this.focused;return e?e.cursor<=0?this.alert():(e.cursor--,this.render()):this.alert()}space(e,r){return this.dispatch(e,r)}number(e,r){return this.dispatch(e,r)}next(){let e=this.focused;if(!e)return this.alert();let{initial:r,input:o}=e;return r&&r.startsWith(o)&&o!==r?(e.value=e.input=r,e.cursor=e.value.length,this.render()):super.next()}prev(){let e=this.focused;return e?e.cursor===0?super.prev():(e.value=e.input="",e.cursor=0,this.render()):this.alert()}separator(){return""}format(e){return this.state.submitted?"":super.format(e)}pointer(){return""}indicator(e){return e.input?"\u29BF":"\u2299"}async choiceSeparator(e,r){let o=await this.resolve(e.separator,this.state,e,r)||":";return o?" "+this.styles.disabled(o):""}async renderChoice(e,r){await this.onChoice(e,r);let{state:o,styles:a}=this,{cursor:n,initial:u="",name:A,hint:p,input:h=""}=e,{muted:E,submitted:I,primary:v,danger:x}=a,C=p,R=this.index===r,N=e.validate||(()=>!0),U=await this.choiceSeparator(e,r),V=e.message;this.align==="right"&&(V=V.padStart(this.longest+1," ")),this.align==="left"&&(V=V.padEnd(this.longest+1," "));let te=this.values[A]=h||u,ae=h?"success":"dark";await N.call(e,te,this.state)!==!0&&(ae="danger");let fe=a[ae],ue=fe(await this.indicator(e,r))+(e.pad||""),me=this.indent(e),he=()=>[me,ue,V+U,h,C].filter(Boolean).join(" ");if(o.submitted)return V=dft.unstyle(V),h=I(h),C="",he();if(e.format)h=await e.format.call(this,h,e,r);else{let Be=this.styles.muted;h=yft(this,{input:h,initial:u,pos:n,showCursor:R,color:Be})}return this.isValue(h)||(h=this.styles.muted(this.symbols.ellipsis)),e.result&&(this.values[A]=await e.result.call(this,te,e,r)),R&&(V=v(V)),e.error?h+=(h?" ":"")+x(e.error.trim()):e.hint&&(h+=(h?" ":"")+E(e.hint.trim())),he()}async submit(){return this.value=this.values,super.base.submit.call(this)}};Uhe.exports=X_});var Z_=_((A8t,Hhe)=>{"use strict";var Eft=ak(),Cft=()=>{throw new Error("expected prompt to have a custom authenticate method")},_he=(t=Cft)=>{class e extends Eft{constructor(o){super(o)}async submit(){this.value=await t.call(this,this.values,this.state),super.base.submit.call(this)}static create(o){return _he(o)}}return e};Hhe.exports=_he()});var jhe=_((f8t,Ghe)=>{"use strict";var wft=Z_();function Ift(t,e){return t.username===this.options.username&&t.password===this.options.password}var qhe=(t=Ift)=>{let e=[{name:"username",message:"username"},{name:"password",message:"password",format(o){return this.options.showPassword?o:(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(o.length))}}];class r extends wft.create(t){constructor(a){super({...a,choices:e})}static create(a){return qhe(a)}}return r};Ghe.exports=qhe()});var lk=_((p8t,Yhe)=>{"use strict";var Bft=gC(),{isPrimitive:vft,hasColor:Dft}=Lo(),$_=class extends Bft{constructor(e){super(e),this.cursorHide()}async initialize(){let e=await this.resolve(this.initial,this.state);this.input=await this.cast(e),await super.initialize()}dispatch(e){return this.isValue(e)?(this.input=e,this.submit()):this.alert()}format(e){let{styles:r,state:o}=this;return o.submitted?r.success(e):r.primary(e)}cast(e){return this.isTrue(e)}isTrue(e){return/^[ty1]/i.test(e)}isFalse(e){return/^[fn0]/i.test(e)}isValue(e){return vft(e)&&(this.isTrue(e)||this.isFalse(e))}async hint(){if(this.state.status==="pending"){let e=await this.element("hint");return Dft(e)?e:this.styles.muted(e)}}async render(){let{input:e,size:r}=this.state,o=await this.prefix(),a=await this.separator(),n=await this.message(),u=this.styles.muted(this.default),A=[o,n,u,a].filter(Boolean).join(" ");this.state.prompt=A;let p=await this.header(),h=this.value=this.cast(e),E=await this.format(h),I=await this.error()||await this.hint(),v=await this.footer();I&&!A.includes(I)&&(E+=" "+I),A+=" "+E,this.clear(r),this.write([p,A,v].filter(Boolean).join(`
-`)),this.restore()}set value(e){super.value=e}get value(){return this.cast(super.value)}};Yhe.exports=$_});var Khe=_((h8t,Whe)=>{"use strict";var Pft=lk(),e8=class extends Pft{constructor(e){super(e),this.default=this.options.default||(this.initial?"(Y/n)":"(y/N)")}};Whe.exports=e8});var Vhe=_((g8t,zhe)=>{"use strict";var Sft=xh(),bft=ak(),dC=bft.prototype,t8=class extends Sft{constructor(e){super({...e,multiple:!0}),this.align=[this.options.align,"left"].find(r=>r!=null),this.emptyError="",this.values={}}dispatch(e,r){let o=this.focused,a=o.parent||{};return!o.editable&&!a.editable&&(e==="a"||e==="i")?super[e]():dC.dispatch.call(this,e,r)}append(e,r){return dC.append.call(this,e,r)}delete(e,r){return dC.delete.call(this,e,r)}space(e){return this.focused.editable?this.append(e):super.space()}number(e){return this.focused.editable?this.append(e):super.number(e)}next(){return this.focused.editable?dC.next.call(this):super.next()}prev(){return this.focused.editable?dC.prev.call(this):super.prev()}async indicator(e,r){let o=e.indicator||"",a=e.editable?o:super.indicator(e,r);return await this.resolve(a,this.state,e,r)||""}indent(e){return e.role==="heading"?"":e.editable?" ":" "}async renderChoice(e,r){return e.indent="",e.editable?dC.renderChoice.call(this,e,r):super.renderChoice(e,r)}error(){return""}footer(){return this.state.error}async validate(){let e=!0;for(let r of this.choices){if(typeof r.validate!="function"||r.role==="heading")continue;let o=r.parent?this.value[r.parent.name]:this.value;if(r.editable?o=r.value===r.name?r.initial||"":r.value:this.isDisabled(r)||(o=r.enabled===!0),e=await r.validate(o,this.state),e!==!0)break}return e!==!0&&(this.state.error=typeof e=="string"?e:"Invalid Input"),e}submit(){if(this.focused.newChoice===!0)return super.submit();if(this.choices.some(e=>e.newChoice))return this.alert();this.value={};for(let e of this.choices){let r=e.parent?this.value[e.parent.name]:this.value;if(e.role==="heading"){this.value[e.name]={};continue}e.editable?r[e.name]=e.value===e.name?e.initial||"":e.value:this.isDisabled(e)||(r[e.name]=e.enabled===!0)}return this.base.submit.call(this)}};zhe.exports=t8});var Kd=_((d8t,Jhe)=>{"use strict";var xft=gC(),kft=J_(),{isPrimitive:Qft}=Lo(),r8=class extends xft{constructor(e){super(e),this.initial=Qft(this.initial)?String(this.initial):"",this.initial&&this.cursorHide(),this.state.prevCursor=0,this.state.clipboard=[]}async keypress(e,r={}){let o=this.state.prevKeypress;return this.state.prevKeypress=r,this.options.multiline===!0&&r.name==="return"&&(!o||o.name!=="return")?this.append(`
-`,r):super.keypress(e,r)}moveCursor(e){this.cursor+=e}reset(){return this.input=this.value="",this.cursor=0,this.render()}dispatch(e,r){if(!e||r.ctrl||r.code)return this.alert();this.append(e)}append(e){let{cursor:r,input:o}=this.state;this.input=`${o}`.slice(0,r)+e+`${o}`.slice(r),this.moveCursor(String(e).length),this.render()}insert(e){this.append(e)}delete(){let{cursor:e,input:r}=this.state;if(e<=0)return this.alert();this.input=`${r}`.slice(0,e-1)+`${r}`.slice(e),this.moveCursor(-1),this.render()}deleteForward(){let{cursor:e,input:r}=this.state;if(r[e]===void 0)return this.alert();this.input=`${r}`.slice(0,e)+`${r}`.slice(e+1),this.render()}cutForward(){let e=this.cursor;if(this.input.length<=e)return this.alert();this.state.clipboard.push(this.input.slice(e)),this.input=this.input.slice(0,e),this.render()}cutLeft(){let e=this.cursor;if(e===0)return this.alert();let r=this.input.slice(0,e),o=this.input.slice(e),a=r.split(" ");this.state.clipboard.push(a.pop()),this.input=a.join(" "),this.cursor=this.input.length,this.input+=o,this.render()}paste(){if(!this.state.clipboard.length)return this.alert();this.insert(this.state.clipboard.pop()),this.render()}toggleCursor(){this.state.prevCursor?(this.cursor=this.state.prevCursor,this.state.prevCursor=0):(this.state.prevCursor=this.cursor,this.cursor=0),this.render()}first(){this.cursor=0,this.render()}last(){this.cursor=this.input.length-1,this.render()}next(){let e=this.initial!=null?String(this.initial):"";if(!e||!e.startsWith(this.input))return this.alert();this.input=this.initial,this.cursor=this.initial.length,this.render()}prev(){if(!this.input)return this.alert();this.reset()}backward(){return this.left()}forward(){return this.right()}right(){return this.cursor>=this.input.length?this.alert():(this.moveCursor(1),this.render())}left(){return this.cursor<=0?this.alert():(this.moveCursor(-1),this.render())}isValue(e){return!!e}async format(e=this.value){let r=await this.resolve(this.initial,this.state);return this.state.submitted?this.styles.submitted(e||r):kft(this,{input:e,initial:r,pos:this.cursor})}async render(){let e=this.state.size,r=await this.prefix(),o=await this.separator(),a=await this.message(),n=[r,a,o].filter(Boolean).join(" ");this.state.prompt=n;let u=await this.header(),A=await this.format(),p=await this.error()||await this.hint(),h=await this.footer();p&&!A.includes(p)&&(A+=" "+p),n+=" "+A,this.clear(e),this.write([u,n,h].filter(Boolean).join(`
-`)),this.restore()}};Jhe.exports=r8});var Zhe=_((m8t,Xhe)=>{"use strict";var Fft=t=>t.filter((e,r)=>t.lastIndexOf(e)===r),ck=t=>Fft(t).filter(Boolean);Xhe.exports=(t,e={},r="")=>{let{past:o=[],present:a=""}=e,n,u;switch(t){case"prev":case"undo":return n=o.slice(0,o.length-1),u=o[o.length-1]||"",{past:ck([r,...n]),present:u};case"next":case"redo":return n=o.slice(1),u=o[0]||"",{past:ck([...n,r]),present:u};case"save":return{past:ck([...o,r]),present:""};case"remove":return u=ck(o.filter(A=>A!==r)),a="",u.length&&(a=u.pop()),{past:u,present:a};default:throw new Error(`Invalid action: "${t}"`)}}});var i8=_((y8t,e0e)=>{"use strict";var Rft=Kd(),$he=Zhe(),n8=class extends Rft{constructor(e){super(e);let r=this.options.history;if(r&&r.store){let o=r.values||this.initial;this.autosave=!!r.autosave,this.store=r.store,this.data=this.store.get("values")||{past:[],present:o},this.initial=this.data.present||this.data.past[this.data.past.length-1]}}completion(e){return this.store?(this.data=$he(e,this.data,this.input),this.data.present?(this.input=this.data.present,this.cursor=this.input.length,this.render()):this.alert()):this.alert()}altUp(){return this.completion("prev")}altDown(){return this.completion("next")}prev(){return this.save(),super.prev()}save(){!this.store||(this.data=$he("save",this.data,this.input),this.store.set("values",this.data))}submit(){return this.store&&this.autosave===!0&&this.save(),super.submit()}};e0e.exports=n8});var r0e=_((E8t,t0e)=>{"use strict";var Tft=Kd(),s8=class extends Tft{format(){return""}};t0e.exports=s8});var i0e=_((C8t,n0e)=>{"use strict";var Lft=Kd(),o8=class extends Lft{constructor(e={}){super(e),this.sep=this.options.separator||/, */,this.initial=e.initial||""}split(e=this.value){return e?String(e).split(this.sep):[]}format(){let e=this.state.submitted?this.styles.primary:r=>r;return this.list.map(e).join(", ")}async submit(e){let r=this.state.error||await this.validate(this.list,this.state);return r!==!0?(this.state.error=r,super.submit()):(this.value=this.list,super.submit())}get list(){return this.split()}};n0e.exports=o8});var o0e=_((w8t,s0e)=>{"use strict";var Nft=xh(),a8=class extends Nft{constructor(e){super({...e,multiple:!0})}};s0e.exports=a8});var c8=_((I8t,a0e)=>{"use strict";var Oft=Kd(),l8=class extends Oft{constructor(e={}){super({style:"number",...e}),this.min=this.isValue(e.min)?this.toNumber(e.min):-1/0,this.max=this.isValue(e.max)?this.toNumber(e.max):1/0,this.delay=e.delay!=null?e.delay:1e3,this.float=e.float!==!1,this.round=e.round===!0||e.float===!1,this.major=e.major||10,this.minor=e.minor||1,this.initial=e.initial!=null?e.initial:"",this.input=String(this.initial),this.cursor=this.input.length,this.cursorShow()}append(e){return!/[-+.]/.test(e)||e==="."&&this.input.includes(".")?this.alert("invalid number"):super.append(e)}number(e){return super.append(e)}next(){return this.input&&this.input!==this.initial?this.alert():this.isValue(this.initial)?(this.input=this.initial,this.cursor=String(this.initial).length,this.render()):this.alert()}up(e){let r=e||this.minor,o=this.toNumber(this.input);return o>this.max+r?this.alert():(this.input=`${o+r}`,this.render())}down(e){let r=e||this.minor,o=this.toNumber(this.input);return o<this.min-r?this.alert():(this.input=`${o-r}`,this.render())}shiftDown(){return this.down(this.major)}shiftUp(){return this.up(this.major)}format(e=this.input){return typeof this.options.format=="function"?this.options.format.call(this,e):this.styles.info(e)}toNumber(e=""){return this.float?+e:Math.round(+e)}isValue(e){return/^[-+]?[0-9]+((\.)|(\.[0-9]+))?$/.test(e)}submit(){let e=[this.input,this.initial].find(r=>this.isValue(r));return this.value=this.toNumber(e||0),super.submit()}};a0e.exports=l8});var c0e=_((B8t,l0e)=>{l0e.exports=c8()});var A0e=_((v8t,u0e)=>{"use strict";var Mft=Kd(),u8=class extends Mft{constructor(e){super(e),this.cursorShow()}format(e=this.input){return this.keypressed?(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(e.length)):""}};u0e.exports=u8});var h0e=_((D8t,p0e)=>{"use strict";var Uft=zc(),_ft=u2(),f0e=Lo(),A8=class extends _ft{constructor(e={}){super(e),this.widths=[].concat(e.messageWidth||50),this.align=[].concat(e.align||"left"),this.linebreak=e.linebreak||!1,this.edgeLength=e.edgeLength||3,this.newline=e.newline||`
- `;let r=e.startNumber||1;typeof this.scale=="number"&&(this.scaleKey=!1,this.scale=Array(this.scale).fill(0).map((o,a)=>({name:a+r})))}async reset(){return this.tableized=!1,await super.reset(),this.render()}tableize(){if(this.tableized===!0)return;this.tableized=!0;let e=0;for(let r of this.choices){e=Math.max(e,r.message.length),r.scaleIndex=r.initial||2,r.scale=[];for(let o=0;o<this.scale.length;o++)r.scale.push({index:o})}this.widths[0]=Math.min(this.widths[0],e+3)}async dispatch(e,r){if(this.multiple)return this[r.name]?await this[r.name](e,r):await super.dispatch(e,r);this.alert()}heading(e,r,o){return this.styles.strong(e)}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;return e.scaleIndex>=this.scale.length-1?this.alert():(e.scaleIndex++,this.render())}left(){let e=this.focused;return e.scaleIndex<=0?this.alert():(e.scaleIndex--,this.render())}indent(){return""}format(){return this.state.submitted?this.choices.map(r=>this.styles.info(r.index)).join(", "):""}pointer(){return""}renderScaleKey(){return this.scaleKey===!1||this.state.submitted?"":["",...this.scale.map(o=>` ${o.name} - ${o.message}`)].map(o=>this.styles.muted(o)).join(`
-`)}renderScaleHeading(e){let r=this.scale.map(p=>p.name);typeof this.options.renderScaleHeading=="function"&&(r=this.options.renderScaleHeading.call(this,e));let o=this.scaleLength-r.join("").length,a=Math.round(o/(r.length-1)),u=r.map(p=>this.styles.strong(p)).join(" ".repeat(a)),A=" ".repeat(this.widths[0]);return this.margin[3]+A+this.margin[1]+u}scaleIndicator(e,r,o){if(typeof this.options.scaleIndicator=="function")return this.options.scaleIndicator.call(this,e,r,o);let a=e.scaleIndex===r.index;return r.disabled?this.styles.hint(this.symbols.radio.disabled):a?this.styles.success(this.symbols.radio.on):this.symbols.radio.off}renderScale(e,r){let o=e.scale.map(n=>this.scaleIndicator(e,n,r)),a=this.term==="Hyper"?"":" ";return o.join(a+this.symbols.line.repeat(this.edgeLength))}async renderChoice(e,r){await this.onChoice(e,r);let o=this.index===r,a=await this.pointer(e,r),n=await e.hint;n&&!f0e.hasColor(n)&&(n=this.styles.muted(n));let u=C=>this.margin[3]+C.replace(/\s+$/,"").padEnd(this.widths[0]," "),A=this.newline,p=this.indent(e),h=await this.resolve(e.message,this.state,e,r),E=await this.renderScale(e,r),I=this.margin[1]+this.margin[3];this.scaleLength=Uft.unstyle(E).length,this.widths[0]=Math.min(this.widths[0],this.width-this.scaleLength-I.length);let x=f0e.wordWrap(h,{width:this.widths[0],newline:A}).split(`
-`).map(C=>u(C)+this.margin[1]);return o&&(E=this.styles.info(E),x=x.map(C=>this.styles.info(C))),x[0]+=E,this.linebreak&&x.push(""),[p+a,x.join(`
-`)].filter(Boolean)}async renderChoices(){if(this.state.submitted)return"";this.tableize();let e=this.visible.map(async(a,n)=>await this.renderChoice(a,n)),r=await Promise.all(e),o=await this.renderScaleHeading();return this.margin[0]+[o,...r.map(a=>a.join(" "))].join(`
-`)}async render(){let{submitted:e,size:r}=this.state,o=await this.prefix(),a=await this.separator(),n=await this.message(),u="";this.options.promptLine!==!1&&(u=[o,n,a,""].join(" "),this.state.prompt=u);let A=await this.header(),p=await this.format(),h=await this.renderScaleKey(),E=await this.error()||await this.hint(),I=await this.renderChoices(),v=await this.footer(),x=this.emptyError;p&&(u+=p),E&&!u.includes(E)&&(u+=" "+E),e&&!p&&!I.trim()&&this.multiple&&x!=null&&(u+=this.styles.danger(x)),this.clear(r),this.write([A,u,h,I,v].filter(Boolean).join(`
-`)),this.state.submitted||this.write(this.margin[2]),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIndex;return this.base.submit.call(this)}};p0e.exports=A8});var m0e=_((P8t,d0e)=>{"use strict";var g0e=zc(),Hft=(t="")=>typeof t=="string"?t.replace(/^['"]|['"]$/g,""):"",p8=class{constructor(e){this.name=e.key,this.field=e.field||{},this.value=Hft(e.initial||this.field.initial||""),this.message=e.message||this.name,this.cursor=0,this.input="",this.lines=[]}},qft=async(t={},e={},r=o=>o)=>{let o=new Set,a=t.fields||[],n=t.template,u=[],A=[],p=[],h=1;typeof n=="function"&&(n=await n());let E=-1,I=()=>n[++E],v=()=>n[E+1],x=C=>{C.line=h,u.push(C)};for(x({type:"bos",value:""});E<n.length-1;){let C=I();if(/^[^\S\n ]$/.test(C)){x({type:"text",value:C});continue}if(C===`
-`){x({type:"newline",value:C}),h++;continue}if(C==="\\"){C+=I(),x({type:"text",value:C});continue}if((C==="$"||C==="#"||C==="{")&&v()==="{"){let N=I();C+=N;let U={type:"template",open:C,inner:"",close:"",value:C},V;for(;V=I();){if(V==="}"){v()==="}"&&(V+=I()),U.value+=V,U.close=V;break}V===":"?(U.initial="",U.key=U.inner):U.initial!==void 0&&(U.initial+=V),U.value+=V,U.inner+=V}U.template=U.open+(U.initial||U.inner)+U.close,U.key=U.key||U.inner,e.hasOwnProperty(U.key)&&(U.initial=e[U.key]),U=r(U),x(U),p.push(U.key),o.add(U.key);let te=A.find(ae=>ae.name===U.key);U.field=a.find(ae=>ae.name===U.key),te||(te=new p8(U),A.push(te)),te.lines.push(U.line-1);continue}let R=u[u.length-1];R.type==="text"&&R.line===h?R.value+=C:x({type:"text",value:C})}return x({type:"eos",value:""}),{input:n,tabstops:u,unique:o,keys:p,items:A}};d0e.exports=async t=>{let e=t.options,r=new Set(e.required===!0?[]:e.required||[]),o={...e.values,...e.initial},{tabstops:a,items:n,keys:u}=await qft(e,o),A=f8("result",t,e),p=f8("format",t,e),h=f8("validate",t,e,!0),E=t.isValue.bind(t);return async(I={},v=!1)=>{let x=0;I.required=r,I.items=n,I.keys=u,I.output="";let C=async(V,te,ae,fe)=>{let ue=await h(V,te,ae,fe);return ue===!1?"Invalid field "+ae.name:ue};for(let V of a){let te=V.value,ae=V.key;if(V.type!=="template"){te&&(I.output+=te);continue}if(V.type==="template"){let fe=n.find(we=>we.name===ae);e.required===!0&&I.required.add(fe.name);let ue=[fe.input,I.values[fe.value],fe.value,te].find(E),he=(fe.field||{}).message||V.inner;if(v){let we=await C(I.values[ae],I,fe,x);if(we&&typeof we=="string"||we===!1){I.invalid.set(ae,we);continue}I.invalid.delete(ae);let g=await A(I.values[ae],I,fe,x);I.output+=g0e.unstyle(g);continue}fe.placeholder=!1;let Be=te;te=await p(te,I,fe,x),ue!==te?(I.values[ae]=ue,te=t.styles.typing(ue),I.missing.delete(he)):(I.values[ae]=void 0,ue=`<${he}>`,te=t.styles.primary(ue),fe.placeholder=!0,I.required.has(ae)&&I.missing.add(he)),I.missing.has(he)&&I.validating&&(te=t.styles.warning(ue)),I.invalid.has(ae)&&I.validating&&(te=t.styles.danger(ue)),x===I.index&&(Be!==te?te=t.styles.underline(te):te=t.styles.heading(g0e.unstyle(te))),x++}te&&(I.output+=te)}let R=I.output.split(`
-`).map(V=>" "+V),N=n.length,U=0;for(let V of n)I.invalid.has(V.name)&&V.lines.forEach(te=>{R[te][0]===" "&&(R[te]=I.styles.danger(I.symbols.bullet)+R[te].slice(1))}),t.isValue(I.values[V.name])&&U++;return I.completed=(U/N*100).toFixed(0),I.output=R.join(`
-`),I.output}};function f8(t,e,r,o){return(a,n,u,A)=>typeof u.field[t]=="function"?u.field[t].call(e,a,n,u,A):[o,a].find(p=>e.isValue(p))}});var E0e=_((S8t,y0e)=>{"use strict";var Gft=zc(),jft=m0e(),Yft=gC(),h8=class extends Yft{constructor(e){super(e),this.cursorHide(),this.reset(!0)}async initialize(){this.interpolate=await jft(this),await super.initialize()}async reset(e){this.state.keys=[],this.state.invalid=new Map,this.state.missing=new Set,this.state.completed=0,this.state.values={},e!==!0&&(await this.initialize(),await this.render())}moveCursor(e){let r=this.getItem();this.cursor+=e,r.cursor+=e}dispatch(e,r){if(!r.code&&!r.ctrl&&e!=null&&this.getItem()){this.append(e,r);return}this.alert()}append(e,r){let o=this.getItem(),a=o.input.slice(0,this.cursor),n=o.input.slice(this.cursor);this.input=o.input=`${a}${e}${n}`,this.moveCursor(1),this.render()}delete(){let e=this.getItem();if(this.cursor<=0||!e.input)return this.alert();let r=e.input.slice(this.cursor),o=e.input.slice(0,this.cursor-1);this.input=e.input=`${o}${r}`,this.moveCursor(-1),this.render()}increment(e){return e>=this.state.keys.length-1?0:e+1}decrement(e){return e<=0?this.state.keys.length-1:e-1}first(){this.state.index=0,this.render()}last(){this.state.index=this.state.keys.length-1,this.render()}right(){if(this.cursor>=this.input.length)return this.alert();this.moveCursor(1),this.render()}left(){if(this.cursor<=0)return this.alert();this.moveCursor(-1),this.render()}prev(){this.state.index=this.decrement(this.state.index),this.getItem(),this.render()}next(){this.state.index=this.increment(this.state.index),this.getItem(),this.render()}up(){this.prev()}down(){this.next()}format(e){let r=this.state.completed<100?this.styles.warning:this.styles.success;return this.state.submitted===!0&&this.state.completed!==100&&(r=this.styles.danger),r(`${this.state.completed}% completed`)}async render(){let{index:e,keys:r=[],submitted:o,size:a}=this.state,n=[this.options.newline,`
-`].find(V=>V!=null),u=await this.prefix(),A=await this.separator(),p=await this.message(),h=[u,p,A].filter(Boolean).join(" ");this.state.prompt=h;let E=await this.header(),I=await this.error()||"",v=await this.hint()||"",x=o?"":await this.interpolate(this.state),C=this.state.key=r[e]||"",R=await this.format(C),N=await this.footer();R&&(h+=" "+R),v&&!R&&this.state.completed===0&&(h+=" "+v),this.clear(a);let U=[E,h,x,N,I.trim()];this.write(U.filter(Boolean).join(n)),this.restore()}getItem(e){let{items:r,keys:o,index:a}=this.state,n=r.find(u=>u.name===o[a]);return n&&n.input!=null&&(this.input=n.input,this.cursor=n.cursor),n}async submit(){typeof this.interpolate!="function"&&await this.initialize(),await this.interpolate(this.state,!0);let{invalid:e,missing:r,output:o,values:a}=this.state;if(e.size){let A="";for(let[p,h]of e)A+=`Invalid ${p}: ${h}
-`;return this.state.error=A,super.submit()}if(r.size)return this.state.error="Required: "+[...r.keys()].join(", "),super.submit();let u=Gft.unstyle(o).split(`
-`).map(A=>A.slice(1)).join(`
-`);return this.value={values:a,result:u},super.submit()}};y0e.exports=h8});var w0e=_((b8t,C0e)=>{"use strict";var Wft="(Use <shift>+<up/down> to sort)",Kft=xh(),g8=class extends Kft{constructor(e){super({...e,reorder:!1,sort:!0,multiple:!0}),this.state.hint=[this.options.hint,Wft].find(this.isValue.bind(this))}indicator(){return""}async renderChoice(e,r){let o=await super.renderChoice(e,r),a=this.symbols.identicalTo+" ",n=this.index===r&&this.sorting?this.styles.muted(a):" ";return this.options.drag===!1&&(n=""),this.options.numbered===!0?n+`${r+1} - `+o:n+o}get selected(){return this.choices}submit(){return this.value=this.choices.map(e=>e.value),super.submit()}};C0e.exports=g8});var B0e=_((x8t,I0e)=>{"use strict";var zft=u2(),d8=class extends zft{constructor(e={}){if(super(e),this.emptyError=e.emptyError||"No items were selected",this.term=process.env.TERM_PROGRAM,!this.options.header){let r=["","4 - Strongly Agree","3 - Agree","2 - Neutral","1 - Disagree","0 - Strongly Disagree",""];r=r.map(o=>this.styles.muted(o)),this.state.header=r.join(`
- `)}}async toChoices(...e){if(this.createdScales)return!1;this.createdScales=!0;let r=await super.toChoices(...e);for(let o of r)o.scale=Vft(5,this.options),o.scaleIdx=2;return r}dispatch(){this.alert()}space(){let e=this.focused,r=e.scale[e.scaleIdx],o=r.selected;return e.scale.forEach(a=>a.selected=!1),r.selected=!o,this.render()}indicator(){return""}pointer(){return""}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;return e.scaleIdx>=e.scale.length-1?this.alert():(e.scaleIdx++,this.render())}left(){let e=this.focused;return e.scaleIdx<=0?this.alert():(e.scaleIdx--,this.render())}indent(){return" "}async renderChoice(e,r){await this.onChoice(e,r);let o=this.index===r,a=this.term==="Hyper",n=a?9:8,u=a?"":" ",A=this.symbols.line.repeat(n),p=" ".repeat(n+(a?0:1)),h=te=>(te?this.styles.success("\u25C9"):"\u25EF")+u,E=r+1+".",I=o?this.styles.heading:this.styles.noop,v=await this.resolve(e.message,this.state,e,r),x=this.indent(e),C=x+e.scale.map((te,ae)=>h(ae===e.scaleIdx)).join(A),R=te=>te===e.scaleIdx?I(te):te,N=x+e.scale.map((te,ae)=>R(ae)).join(p),U=()=>[E,v].filter(Boolean).join(" "),V=()=>[U(),C,N," "].filter(Boolean).join(`
-`);return o&&(C=this.styles.cyan(C),N=this.styles.cyan(N)),V()}async renderChoices(){if(this.state.submitted)return"";let e=this.visible.map(async(o,a)=>await this.renderChoice(o,a)),r=await Promise.all(e);return r.length||r.push(this.styles.danger("No matching choices")),r.join(`
-`)}format(){return this.state.submitted?this.choices.map(r=>this.styles.info(r.scaleIdx)).join(", "):""}async render(){let{submitted:e,size:r}=this.state,o=await this.prefix(),a=await this.separator(),n=await this.message(),u=[o,n,a].filter(Boolean).join(" ");this.state.prompt=u;let A=await this.header(),p=await this.format(),h=await this.error()||await this.hint(),E=await this.renderChoices(),I=await this.footer();(p||!h)&&(u+=" "+p),h&&!u.includes(h)&&(u+=" "+h),e&&!p&&!E&&this.multiple&&this.type!=="form"&&(u+=this.styles.danger(this.emptyError)),this.clear(r),this.write([u,A,E,I].filter(Boolean).join(`
-`)),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIdx;return this.base.submit.call(this)}};function Vft(t,e={}){if(Array.isArray(e.scale))return e.scale.map(o=>({...o}));let r=[];for(let o=1;o<t+1;o++)r.push({i:o,selected:!1});return r}I0e.exports=d8});var D0e=_((k8t,v0e)=>{v0e.exports=i8()});var S0e=_((Q8t,P0e)=>{"use strict";var Jft=lk(),m8=class extends Jft{async initialize(){await super.initialize(),this.value=this.initial=!!this.options.initial,this.disabled=this.options.disabled||"no",this.enabled=this.options.enabled||"yes",await this.render()}reset(){this.value=this.initial,this.render()}delete(){this.alert()}toggle(){this.value=!this.value,this.render()}enable(){if(this.value===!0)return this.alert();this.value=!0,this.render()}disable(){if(this.value===!1)return this.alert();this.value=!1,this.render()}up(){this.toggle()}down(){this.toggle()}right(){this.toggle()}left(){this.toggle()}next(){this.toggle()}prev(){this.toggle()}dispatch(e="",r){switch(e.toLowerCase()){case" ":return this.toggle();case"1":case"y":case"t":return this.enable();case"0":case"n":case"f":return this.disable();default:return this.alert()}}format(){let e=o=>this.styles.primary.underline(o);return[this.value?this.disabled:e(this.disabled),this.value?e(this.enabled):this.enabled].join(this.styles.muted(" / "))}async render(){let{size:e}=this.state,r=await this.header(),o=await this.prefix(),a=await this.separator(),n=await this.message(),u=await this.format(),A=await this.error()||await this.hint(),p=await this.footer(),h=[o,n,a,u].join(" ");this.state.prompt=h,A&&!h.includes(A)&&(h+=" "+A),this.clear(e),this.write([r,h,p].filter(Boolean).join(`
-`)),this.write(this.margin[2]),this.restore()}};P0e.exports=m8});var x0e=_((F8t,b0e)=>{"use strict";var Xft=xh(),y8=class extends Xft{constructor(e){if(super(e),typeof this.options.correctChoice!="number"||this.options.correctChoice<0)throw new Error("Please specify the index of the correct answer from the list of choices")}async toChoices(e,r){let o=await super.toChoices(e,r);if(o.length<2)throw new Error("Please give at least two choices to the user");if(this.options.correctChoice>o.length)throw new Error("Please specify the index of the correct answer from the list of choices");return o}check(e){return e.index===this.options.correctChoice}async result(e){return{selectedAnswer:e,correctAnswer:this.options.choices[this.options.correctChoice].value,correct:await this.check(this.state)}}};b0e.exports=y8});var Q0e=_(E8=>{"use strict";var k0e=Lo(),As=(t,e)=>{k0e.defineExport(E8,t,e),k0e.defineExport(E8,t.toLowerCase(),e)};As("AutoComplete",()=>Ohe());As("BasicAuth",()=>jhe());As("Confirm",()=>Khe());As("Editable",()=>Vhe());As("Form",()=>ak());As("Input",()=>i8());As("Invisible",()=>r0e());As("List",()=>i0e());As("MultiSelect",()=>o0e());As("Numeral",()=>c0e());As("Password",()=>A0e());As("Scale",()=>h0e());As("Select",()=>xh());As("Snippet",()=>E0e());As("Sort",()=>w0e());As("Survey",()=>B0e());As("Text",()=>D0e());As("Toggle",()=>S0e());As("Quiz",()=>x0e())});var R0e=_((T8t,F0e)=>{F0e.exports={ArrayPrompt:u2(),AuthPrompt:Z_(),BooleanPrompt:lk(),NumberPrompt:c8(),StringPrompt:Kd()}});var f2=_((L8t,L0e)=>{"use strict";var T0e=ve("assert"),w8=ve("events"),kh=Lo(),Jc=class extends w8{constructor(e,r){super(),this.options=kh.merge({},e),this.answers={...r}}register(e,r){if(kh.isObject(e)){for(let a of Object.keys(e))this.register(a,e[a]);return this}T0e.equal(typeof r,"function","expected a function");let o=e.toLowerCase();return r.prototype instanceof this.Prompt?this.prompts[o]=r:this.prompts[o]=r(this.Prompt,this),this}async prompt(e=[]){for(let r of[].concat(e))try{typeof r=="function"&&(r=await r.call(this)),await this.ask(kh.merge({},this.options,r))}catch(o){return Promise.reject(o)}return this.answers}async ask(e){typeof e=="function"&&(e=await e.call(this));let r=kh.merge({},this.options,e),{type:o,name:a}=e,{set:n,get:u}=kh;if(typeof o=="function"&&(o=await o.call(this,e,this.answers)),!o)return this.answers[a];T0e(this.prompts[o],`Prompt "${o}" is not registered`);let A=new this.prompts[o](r),p=u(this.answers,a);A.state.answers=this.answers,A.enquirer=this,a&&A.on("submit",E=>{this.emit("answer",a,E,A),n(this.answers,a,E)});let h=A.emit.bind(A);return A.emit=(...E)=>(this.emit.call(this,...E),h(...E)),this.emit("prompt",A,this),r.autofill&&p!=null?(A.value=A.input=p,r.autofill==="show"&&await A.submit()):p=A.value=await A.run(),p}use(e){return e.call(this,this),this}set Prompt(e){this._Prompt=e}get Prompt(){return this._Prompt||this.constructor.Prompt}get prompts(){return this.constructor.prompts}static set Prompt(e){this._Prompt=e}static get Prompt(){return this._Prompt||gC()}static get prompts(){return Q0e()}static get types(){return R0e()}static get prompt(){let e=(r,...o)=>{let a=new this(...o),n=a.emit.bind(a);return a.emit=(...u)=>(e.emit(...u),n(...u)),a.prompt(r)};return kh.mixinEmitter(e,new w8),e}};kh.mixinEmitter(Jc,new w8);var C8=Jc.prompts;for(let t of Object.keys(C8)){let e=t.toLowerCase(),r=o=>new C8[t](o).run();Jc.prompt[e]=r,Jc[e]=r,Jc[t]||Reflect.defineProperty(Jc,t,{get:()=>C8[t]})}var A2=t=>{kh.defineExport(Jc,t,()=>Jc.types[t])};A2("ArrayPrompt");A2("AuthPrompt");A2("BooleanPrompt");A2("NumberPrompt");A2("StringPrompt");L0e.exports=Jc});var d2=_((mHt,q0e)=>{var npt=Jx();function ipt(t,e,r){var o=t==null?void 0:npt(t,e);return o===void 0?r:o}q0e.exports=ipt});var Y0e=_((BHt,j0e)=>{function spt(t,e){for(var r=-1,o=t==null?0:t.length;++r<o&&e(t[r],r,t)!==!1;);return t}j0e.exports=spt});var K0e=_((vHt,W0e)=>{var opt=md(),apt=VP();function lpt(t,e){return t&&opt(e,apt(e),t)}W0e.exports=lpt});var V0e=_((DHt,z0e)=>{var cpt=md(),upt=jy();function Apt(t,e){return t&&cpt(e,upt(e),t)}z0e.exports=Apt});var X0e=_((PHt,J0e)=>{var fpt=md(),ppt=GP();function hpt(t,e){return fpt(t,ppt(t),e)}J0e.exports=hpt});var S8=_((SHt,Z0e)=>{var gpt=qP(),dpt=eS(),mpt=GP(),ypt=KL(),Ept=Object.getOwnPropertySymbols,Cpt=Ept?function(t){for(var e=[];t;)gpt(e,mpt(t)),t=dpt(t);return e}:ypt;Z0e.exports=Cpt});var ege=_((bHt,$0e)=>{var wpt=md(),Ipt=S8();function Bpt(t,e){return wpt(t,Ipt(t),e)}$0e.exports=Bpt});var b8=_((xHt,tge)=>{var vpt=WL(),Dpt=S8(),Ppt=jy();function Spt(t){return vpt(t,Ppt,Dpt)}tge.exports=Spt});var nge=_((kHt,rge)=>{var bpt=Object.prototype,xpt=bpt.hasOwnProperty;function kpt(t){var e=t.length,r=new t.constructor(e);return e&&typeof t[0]=="string"&&xpt.call(t,"index")&&(r.index=t.index,r.input=t.input),r}rge.exports=kpt});var sge=_((QHt,ige)=>{var Qpt=ZP();function Fpt(t,e){var r=e?Qpt(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.byteLength)}ige.exports=Fpt});var age=_((FHt,oge)=>{var Rpt=/\w*$/;function Tpt(t){var e=new t.constructor(t.source,Rpt.exec(t));return e.lastIndex=t.lastIndex,e}oge.exports=Tpt});var fge=_((RHt,Age)=>{var lge=hd(),cge=lge?lge.prototype:void 0,uge=cge?cge.valueOf:void 0;function Lpt(t){return uge?Object(uge.call(t)):{}}Age.exports=Lpt});var hge=_((THt,pge)=>{var Npt=ZP(),Opt=sge(),Mpt=age(),Upt=fge(),_pt=aN(),Hpt="[object Boolean]",qpt="[object Date]",Gpt="[object Map]",jpt="[object Number]",Ypt="[object RegExp]",Wpt="[object Set]",Kpt="[object String]",zpt="[object Symbol]",Vpt="[object ArrayBuffer]",Jpt="[object DataView]",Xpt="[object Float32Array]",Zpt="[object Float64Array]",$pt="[object Int8Array]",eht="[object Int16Array]",tht="[object Int32Array]",rht="[object Uint8Array]",nht="[object Uint8ClampedArray]",iht="[object Uint16Array]",sht="[object Uint32Array]";function oht(t,e,r){var o=t.constructor;switch(e){case Vpt:return Npt(t);case Hpt:case qpt:return new o(+t);case Jpt:return Opt(t,r);case Xpt:case Zpt:case $pt:case eht:case tht:case rht:case nht:case iht:case sht:return _pt(t,r);case Gpt:return new o;case jpt:case Kpt:return new o(t);case Ypt:return Mpt(t);case Wpt:return new o;case zpt:return Upt(t)}}pge.exports=oht});var dge=_((LHt,gge)=>{var aht=jI(),lht=Ju(),cht="[object Map]";function uht(t){return lht(t)&&aht(t)==cht}gge.exports=uht});var Cge=_((NHt,Ege)=>{var Aht=dge(),fht=YP(),mge=WP(),yge=mge&&mge.isMap,pht=yge?fht(yge):Aht;Ege.exports=pht});var Ige=_((OHt,wge)=>{var hht=jI(),ght=Ju(),dht="[object Set]";function mht(t){return ght(t)&&hht(t)==dht}wge.exports=mht});var Pge=_((MHt,Dge)=>{var yht=Ige(),Eht=YP(),Bge=WP(),vge=Bge&&Bge.isSet,Cht=vge?Eht(vge):yht;Dge.exports=Cht});var x8=_((UHt,kge)=>{var wht=_P(),Iht=Y0e(),Bht=tS(),vht=K0e(),Dht=V0e(),Pht=oN(),Sht=$P(),bht=X0e(),xht=ege(),kht=XL(),Qht=b8(),Fht=jI(),Rht=nge(),Tht=hge(),Lht=lN(),Nht=ql(),Oht=UI(),Mht=Cge(),Uht=sl(),_ht=Pge(),Hht=VP(),qht=jy(),Ght=1,jht=2,Yht=4,Sge="[object Arguments]",Wht="[object Array]",Kht="[object Boolean]",zht="[object Date]",Vht="[object Error]",bge="[object Function]",Jht="[object GeneratorFunction]",Xht="[object Map]",Zht="[object Number]",xge="[object Object]",$ht="[object RegExp]",e0t="[object Set]",t0t="[object String]",r0t="[object Symbol]",n0t="[object WeakMap]",i0t="[object ArrayBuffer]",s0t="[object DataView]",o0t="[object Float32Array]",a0t="[object Float64Array]",l0t="[object Int8Array]",c0t="[object Int16Array]",u0t="[object Int32Array]",A0t="[object Uint8Array]",f0t="[object Uint8ClampedArray]",p0t="[object Uint16Array]",h0t="[object Uint32Array]",ri={};ri[Sge]=ri[Wht]=ri[i0t]=ri[s0t]=ri[Kht]=ri[zht]=ri[o0t]=ri[a0t]=ri[l0t]=ri[c0t]=ri[u0t]=ri[Xht]=ri[Zht]=ri[xge]=ri[$ht]=ri[e0t]=ri[t0t]=ri[r0t]=ri[A0t]=ri[f0t]=ri[p0t]=ri[h0t]=!0;ri[Vht]=ri[bge]=ri[n0t]=!1;function Ak(t,e,r,o,a,n){var u,A=e&Ght,p=e&jht,h=e&Yht;if(r&&(u=a?r(t,o,a,n):r(t)),u!==void 0)return u;if(!Uht(t))return t;var E=Nht(t);if(E){if(u=Rht(t),!A)return Sht(t,u)}else{var I=Fht(t),v=I==bge||I==Jht;if(Oht(t))return Pht(t,A);if(I==xge||I==Sge||v&&!a){if(u=p||v?{}:Lht(t),!A)return p?xht(t,Dht(u,t)):bht(t,vht(u,t))}else{if(!ri[I])return a?t:{};u=Tht(t,I,A)}}n||(n=new wht);var x=n.get(t);if(x)return x;n.set(t,u),_ht(t)?t.forEach(function(N){u.add(Ak(N,e,r,N,t,n))}):Mht(t)&&t.forEach(function(N,U){u.set(U,Ak(N,e,r,U,t,n))});var C=h?p?Qht:kht:p?qht:Hht,R=E?void 0:C(t);return Iht(R||t,function(N,U){R&&(U=N,N=t[U]),Bht(u,U,Ak(N,e,r,U,t,n))}),u}kge.exports=Ak});var k8=_((_Ht,Qge)=>{var g0t=x8(),d0t=1,m0t=4;function y0t(t){return g0t(t,d0t|m0t)}Qge.exports=y0t});var Q8=_((HHt,Fge)=>{var E0t=I_();function C0t(t,e,r){return t==null?t:E0t(t,e,r)}Fge.exports=C0t});var Oge=_((KHt,Nge)=>{var w0t=Object.prototype,I0t=w0t.hasOwnProperty;function B0t(t,e){return t!=null&&I0t.call(t,e)}Nge.exports=B0t});var Uge=_((zHt,Mge)=>{var v0t=Oge(),D0t=B_();function P0t(t,e){return t!=null&&D0t(t,e,v0t)}Mge.exports=P0t});var Hge=_((VHt,_ge)=>{function S0t(t){var e=t==null?0:t.length;return e?t[e-1]:void 0}_ge.exports=S0t});var Gge=_((JHt,qge)=>{var b0t=Jx(),x0t=pU();function k0t(t,e){return e.length<2?t:b0t(t,x0t(e,0,-1))}qge.exports=k0t});var R8=_((XHt,jge)=>{var Q0t=jd(),F0t=Hge(),R0t=Gge(),T0t=lC();function L0t(t,e){return e=Q0t(e,t),t=R0t(t,e),t==null||delete t[T0t(F0t(e))]}jge.exports=L0t});var T8=_((ZHt,Yge)=>{var N0t=R8();function O0t(t,e){return t==null?!0:N0t(t,e)}Yge.exports=O0t});var Jge=_((S6t,_0t)=>{_0t.exports={name:"@yarnpkg/cli",version:"4.2.2",license:"BSD-2-Clause",main:"./sources/index.ts",exports:{".":"./sources/index.ts","./polyfills":"./sources/polyfills.ts","./package.json":"./package.json"},dependencies:{"@yarnpkg/core":"workspace:^","@yarnpkg/fslib":"workspace:^","@yarnpkg/libzip":"workspace:^","@yarnpkg/parsers":"workspace:^","@yarnpkg/plugin-compat":"workspace:^","@yarnpkg/plugin-constraints":"workspace:^","@yarnpkg/plugin-dlx":"workspace:^","@yarnpkg/plugin-essentials":"workspace:^","@yarnpkg/plugin-exec":"workspace:^","@yarnpkg/plugin-file":"workspace:^","@yarnpkg/plugin-git":"workspace:^","@yarnpkg/plugin-github":"workspace:^","@yarnpkg/plugin-http":"workspace:^","@yarnpkg/plugin-init":"workspace:^","@yarnpkg/plugin-interactive-tools":"workspace:^","@yarnpkg/plugin-link":"workspace:^","@yarnpkg/plugin-nm":"workspace:^","@yarnpkg/plugin-npm":"workspace:^","@yarnpkg/plugin-npm-cli":"workspace:^","@yarnpkg/plugin-pack":"workspace:^","@yarnpkg/plugin-patch":"workspace:^","@yarnpkg/plugin-pnp":"workspace:^","@yarnpkg/plugin-pnpm":"workspace:^","@yarnpkg/plugin-stage":"workspace:^","@yarnpkg/plugin-typescript":"workspace:^","@yarnpkg/plugin-version":"workspace:^","@yarnpkg/plugin-workspace-tools":"workspace:^","@yarnpkg/shell":"workspace:^","ci-info":"^3.2.0",clipanion:"^4.0.0-rc.2",semver:"^7.1.2",tslib:"^2.4.0",typanion:"^3.14.0"},devDependencies:{"@types/semver":"^7.1.0","@yarnpkg/builder":"workspace:^","@yarnpkg/monorepo":"workspace:^","@yarnpkg/pnpify":"workspace:^"},peerDependencies:{"@yarnpkg/core":"workspace:^"},scripts:{postpack:"rm -rf lib",prepack:'run build:compile "$(pwd)"',"build:cli+hook":"run build:pnp:hook && builder build bundle","build:cli":"builder build bundle","run:cli":"builder run","update-local":"run build:cli --no-git-hash && rsync -a --delete bundles/ bin/"},publishConfig:{main:"./lib/index.js",bin:null,exports:{".":"./lib/index.js","./package.json":"./package.json"}},files:["/lib/**/*","!/lib/pluginConfiguration.*","!/lib/cli.*"],"@yarnpkg/builder":{bundles:{standard:["@yarnpkg/plugin-essentials","@yarnpkg/plugin-compat","@yarnpkg/plugin-constraints","@yarnpkg/plugin-dlx","@yarnpkg/plugin-exec","@yarnpkg/plugin-file","@yarnpkg/plugin-git","@yarnpkg/plugin-github","@yarnpkg/plugin-http","@yarnpkg/plugin-init","@yarnpkg/plugin-interactive-tools","@yarnpkg/plugin-link","@yarnpkg/plugin-nm","@yarnpkg/plugin-npm","@yarnpkg/plugin-npm-cli","@yarnpkg/plugin-pack","@yarnpkg/plugin-patch","@yarnpkg/plugin-pnp","@yarnpkg/plugin-pnpm","@yarnpkg/plugin-stage","@yarnpkg/plugin-typescript","@yarnpkg/plugin-version","@yarnpkg/plugin-workspace-tools"]}},repository:{type:"git",url:"ssh://git@github.com/yarnpkg/berry.git",directory:"packages/yarnpkg-cli"},engines:{node:">=18.12.0"}}});var G8=_((i9t,lde)=>{"use strict";lde.exports=function(e,r){r===!0&&(r=0);var o="";if(typeof e=="string")try{o=new URL(e).protocol}catch{}else e&&e.constructor===URL&&(o=e.protocol);var a=o.split(/\:|\+/).filter(Boolean);return typeof r=="number"?a[r]:a}});var ude=_((s9t,cde)=>{"use strict";var sgt=G8();function ogt(t){var e={protocols:[],protocol:null,port:null,resource:"",host:"",user:"",password:"",pathname:"",hash:"",search:"",href:t,query:{},parse_failed:!1};try{var r=new URL(t);e.protocols=sgt(r),e.protocol=e.protocols[0],e.port=r.port,e.resource=r.hostname,e.host=r.host,e.user=r.username||"",e.password=r.password||"",e.pathname=r.pathname,e.hash=r.hash.slice(1),e.search=r.search.slice(1),e.href=r.href,e.query=Object.fromEntries(r.searchParams)}catch{e.protocols=["file"],e.protocol=e.protocols[0],e.port="",e.resource="",e.user="",e.pathname="",e.hash="",e.search="",e.href=t,e.query={},e.parse_failed=!0}return e}cde.exports=ogt});var pde=_((o9t,fde)=>{"use strict";var agt=ude();function lgt(t){return t&&typeof t=="object"&&"default"in t?t:{default:t}}var cgt=lgt(agt),ugt="text/plain",Agt="us-ascii",Ade=(t,e)=>e.some(r=>r instanceof RegExp?r.test(t):r===t),fgt=(t,{stripHash:e})=>{let r=/^data:(?<type>[^,]*?),(?<data>[^#]*?)(?:#(?<hash>.*))?$/.exec(t);if(!r)throw new Error(`Invalid URL: ${t}`);let{type:o,data:a,hash:n}=r.groups,u=o.split(";");n=e?"":n;let A=!1;u[u.length-1]==="base64"&&(u.pop(),A=!0);let p=(u.shift()||"").toLowerCase(),E=[...u.map(I=>{let[v,x=""]=I.split("=").map(C=>C.trim());return v==="charset"&&(x=x.toLowerCase(),x===Agt)?"":`${v}${x?`=${x}`:""}`}).filter(Boolean)];return A&&E.push("base64"),(E.length>0||p&&p!==ugt)&&E.unshift(p),`data:${E.join(";")},${A?a.trim():a}${n?`#${n}`:""}`};function pgt(t,e){if(e={defaultProtocol:"http:",normalizeProtocol:!0,forceHttp:!1,forceHttps:!1,stripAuthentication:!0,stripHash:!1,stripTextFragment:!0,stripWWW:!0,removeQueryParameters:[/^utm_\w+/i],removeTrailingSlash:!0,removeSingleSlash:!0,removeDirectoryIndex:!1,sortQueryParameters:!0,...e},t=t.trim(),/^data:/i.test(t))return fgt(t,e);if(/^view-source:/i.test(t))throw new Error("`view-source:` is not supported as it is a non-standard protocol");let r=t.startsWith("//");!r&&/^\.*\//.test(t)||(t=t.replace(/^(?!(?:\w+:)?\/\/)|^\/\//,e.defaultProtocol));let a=new URL(t);if(e.forceHttp&&e.forceHttps)throw new Error("The `forceHttp` and `forceHttps` options cannot be used together");if(e.forceHttp&&a.protocol==="https:"&&(a.protocol="http:"),e.forceHttps&&a.protocol==="http:"&&(a.protocol="https:"),e.stripAuthentication&&(a.username="",a.password=""),e.stripHash?a.hash="":e.stripTextFragment&&(a.hash=a.hash.replace(/#?:~:text.*?$/i,"")),a.pathname){let u=/\b[a-z][a-z\d+\-.]{1,50}:\/\//g,A=0,p="";for(;;){let E=u.exec(a.pathname);if(!E)break;let I=E[0],v=E.index,x=a.pathname.slice(A,v);p+=x.replace(/\/{2,}/g,"/"),p+=I,A=v+I.length}let h=a.pathname.slice(A,a.pathname.length);p+=h.replace(/\/{2,}/g,"/"),a.pathname=p}if(a.pathname)try{a.pathname=decodeURI(a.pathname)}catch{}if(e.removeDirectoryIndex===!0&&(e.removeDirectoryIndex=[/^index\.[a-z]+$/]),Array.isArray(e.removeDirectoryIndex)&&e.removeDirectoryIndex.length>0){let u=a.pathname.split("/"),A=u[u.length-1];Ade(A,e.removeDirectoryIndex)&&(u=u.slice(0,-1),a.pathname=u.slice(1).join("/")+"/")}if(a.hostname&&(a.hostname=a.hostname.replace(/\.$/,""),e.stripWWW&&/^www\.(?!www\.)[a-z\-\d]{1,63}\.[a-z.\-\d]{2,63}$/.test(a.hostname)&&(a.hostname=a.hostname.replace(/^www\./,""))),Array.isArray(e.removeQueryParameters))for(let u of[...a.searchParams.keys()])Ade(u,e.removeQueryParameters)&&a.searchParams.delete(u);if(e.removeQueryParameters===!0&&(a.search=""),e.sortQueryParameters){a.searchParams.sort();try{a.search=decodeURIComponent(a.search)}catch{}}e.removeTrailingSlash&&(a.pathname=a.pathname.replace(/\/$/,""));let n=t;return t=a.toString(),!e.removeSingleSlash&&a.pathname==="/"&&!n.endsWith("/")&&a.hash===""&&(t=t.replace(/\/$/,"")),(e.removeTrailingSlash||a.pathname==="/")&&a.hash===""&&e.removeSingleSlash&&(t=t.replace(/\/$/,"")),r&&!e.normalizeProtocol&&(t=t.replace(/^http:\/\//,"//")),e.stripProtocol&&(t=t.replace(/^(?:https?:)?\/\//,"")),t}var j8=(t,e=!1)=>{let r=/^(?:([a-z_][a-z0-9_-]{0,31})@|https?:\/\/)([\w\.\-@]+)[\/:]([\~,\.\w,\-,\_,\/]+?(?:\.git|\/)?)$/,o=n=>{let u=new Error(n);throw u.subject_url=t,u};(typeof t!="string"||!t.trim())&&o("Invalid url."),t.length>j8.MAX_INPUT_LENGTH&&o("Input exceeds maximum length. If needed, change the value of parseUrl.MAX_INPUT_LENGTH."),e&&(typeof e!="object"&&(e={stripHash:!1}),t=pgt(t,e));let a=cgt.default(t);if(a.parse_failed){let n=a.href.match(r);n?(a.protocols=["ssh"],a.protocol="ssh",a.resource=n[2],a.host=n[2],a.user=n[1],a.pathname=`/${n[3]}`,a.parse_failed=!1):o("URL parsing failed.")}return a};j8.MAX_INPUT_LENGTH=2048;fde.exports=j8});var dde=_((a9t,gde)=>{"use strict";var hgt=G8();function hde(t){if(Array.isArray(t))return t.indexOf("ssh")!==-1||t.indexOf("rsync")!==-1;if(typeof t!="string")return!1;var e=hgt(t);if(t=t.substring(t.indexOf("://")+3),hde(e))return!0;var r=new RegExp(".([a-zA-Z\\d]+):(\\d+)/");return!t.match(r)&&t.indexOf("@")<t.indexOf(":")}gde.exports=hde});var Ede=_((l9t,yde)=>{"use strict";var ggt=pde(),mde=dde();function dgt(t){var e=ggt(t);return e.token="",e.password==="x-oauth-basic"?e.token=e.user:e.user==="x-token-auth"&&(e.token=e.password),mde(e.protocols)||e.protocols.length===0&&mde(t)?e.protocol="ssh":e.protocols.length?e.protocol=e.protocols[0]:(e.protocol="file",e.protocols=["file"]),e.href=e.href.replace(/\/$/,""),e}yde.exports=dgt});var wde=_((c9t,Cde)=>{"use strict";var mgt=Ede();function Y8(t){if(typeof t!="string")throw new Error("The url must be a string.");var e=/^([a-z\d-]{1,39})\/([-\.\w]{1,100})$/i;e.test(t)&&(t="https://github.com/"+t);var r=mgt(t),o=r.resource.split("."),a=null;switch(r.toString=function(N){return Y8.stringify(this,N)},r.source=o.length>2?o.slice(1-o.length).join("."):r.source=r.resource,r.git_suffix=/\.git$/.test(r.pathname),r.name=decodeURIComponent((r.pathname||r.href).replace(/(^\/)|(\/$)/g,"").replace(/\.git$/,"")),r.owner=decodeURIComponent(r.user),r.source){case"git.cloudforge.com":r.owner=r.user,r.organization=o[0],r.source="cloudforge.com";break;case"visualstudio.com":if(r.resource==="vs-ssh.visualstudio.com"){a=r.name.split("/"),a.length===4&&(r.organization=a[1],r.owner=a[2],r.name=a[3],r.full_name=a[2]+"/"+a[3]);break}else{a=r.name.split("/"),a.length===2?(r.owner=a[1],r.name=a[1],r.full_name="_git/"+r.name):a.length===3?(r.name=a[2],a[0]==="DefaultCollection"?(r.owner=a[2],r.organization=a[0],r.full_name=r.organization+"/_git/"+r.name):(r.owner=a[0],r.full_name=r.owner+"/_git/"+r.name)):a.length===4&&(r.organization=a[0],r.owner=a[1],r.name=a[3],r.full_name=r.organization+"/"+r.owner+"/_git/"+r.name);break}case"dev.azure.com":case"azure.com":if(r.resource==="ssh.dev.azure.com"){a=r.name.split("/"),a.length===4&&(r.organization=a[1],r.owner=a[2],r.name=a[3]);break}else{a=r.name.split("/"),a.length===5?(r.organization=a[0],r.owner=a[1],r.name=a[4],r.full_name="_git/"+r.name):a.length===3?(r.name=a[2],a[0]==="DefaultCollection"?(r.owner=a[2],r.organization=a[0],r.full_name=r.organization+"/_git/"+r.name):(r.owner=a[0],r.full_name=r.owner+"/_git/"+r.name)):a.length===4&&(r.organization=a[0],r.owner=a[1],r.name=a[3],r.full_name=r.organization+"/"+r.owner+"/_git/"+r.name),r.query&&r.query.path&&(r.filepath=r.query.path.replace(/^\/+/g,"")),r.query&&r.query.version&&(r.ref=r.query.version.replace(/^GB/,""));break}default:a=r.name.split("/");var n=a.length-1;if(a.length>=2){var u=a.indexOf("-",2),A=a.indexOf("blob",2),p=a.indexOf("tree",2),h=a.indexOf("commit",2),E=a.indexOf("src",2),I=a.indexOf("raw",2),v=a.indexOf("edit",2);n=u>0?u-1:A>0?A-1:p>0?p-1:h>0?h-1:E>0?E-1:I>0?I-1:v>0?v-1:n,r.owner=a.slice(0,n).join("/"),r.name=a[n],h&&(r.commit=a[n+2])}r.ref="",r.filepathtype="",r.filepath="";var x=a.length>n&&a[n+1]==="-"?n+1:n;a.length>x+2&&["raw","src","blob","tree","edit"].indexOf(a[x+1])>=0&&(r.filepathtype=a[x+1],r.ref=a[x+2],a.length>x+3&&(r.filepath=a.slice(x+3).join("/"))),r.organization=r.owner;break}r.full_name||(r.full_name=r.owner,r.name&&(r.full_name&&(r.full_name+="/"),r.full_name+=r.name)),r.owner.startsWith("scm/")&&(r.source="bitbucket-server",r.owner=r.owner.replace("scm/",""),r.organization=r.owner,r.full_name=r.owner+"/"+r.name);var C=/(projects|users)\/(.*?)\/repos\/(.*?)((\/.*$)|$)/,R=C.exec(r.pathname);return R!=null&&(r.source="bitbucket-server",R[1]==="users"?r.owner="~"+R[2]:r.owner=R[2],r.organization=r.owner,r.name=R[3],a=R[4].split("/"),a.length>1&&(["raw","browse"].indexOf(a[1])>=0?(r.filepathtype=a[1],a.length>2&&(r.filepath=a.slice(2).join("/"))):a[1]==="commits"&&a.length>2&&(r.commit=a[2])),r.full_name=r.owner+"/"+r.name,r.query.at?r.ref=r.query.at:r.ref=""),r}Y8.stringify=function(t,e){e=e||(t.protocols&&t.protocols.length?t.protocols.join("+"):t.protocol);var r=t.port?":"+t.port:"",o=t.user||"git",a=t.git_suffix?".git":"";switch(e){case"ssh":return r?"ssh://"+o+"@"+t.resource+r+"/"+t.full_name+a:o+"@"+t.resource+":"+t.full_name+a;case"git+ssh":case"ssh+git":case"ftp":case"ftps":return e+"://"+o+"@"+t.resource+r+"/"+t.full_name+a;case"http":case"https":var n=t.token?ygt(t):t.user&&(t.protocols.includes("http")||t.protocols.includes("https"))?t.user+"@":"";return e+"://"+n+t.resource+r+"/"+Egt(t)+a;default:return t.href}};function ygt(t){switch(t.source){case"bitbucket.org":return"x-token-auth:"+t.token+"@";default:return t.token+"@"}}function Egt(t){switch(t.source){case"bitbucket-server":return"scm/"+t.full_name;default:return""+t.full_name}}Cde.exports=Y8});var Ode=_((q5t,Nde)=>{var kgt=Hb(),Qgt=$P(),Fgt=ql(),Rgt=pE(),Tgt=w_(),Lgt=lC(),Ngt=L1();function Ogt(t){return Fgt(t)?kgt(t,Lgt):Rgt(t)?[t]:Qgt(Tgt(Ngt(t)))}Nde.exports=Ogt});function Hgt(t,e){return e===1&&_gt.has(t[0])}function B2(t){let e=Array.isArray(t)?t:(0,_de.default)(t);return e.map((o,a)=>Mgt.test(o)?`[${o}]`:Ugt.test(o)&&!Hgt(e,a)?`.${o}`:`[${JSON.stringify(o)}]`).join("").replace(/^\./,"")}function qgt(t,e){let r=[];if(e.methodName!==null&&r.push(de.pretty(t,e.methodName,de.Type.CODE)),e.file!==null){let o=[];o.push(de.pretty(t,e.file,de.Type.PATH)),e.line!==null&&(o.push(de.pretty(t,e.line,de.Type.NUMBER)),e.column!==null&&o.push(de.pretty(t,e.column,de.Type.NUMBER))),r.push(`(${o.join(de.pretty(t,":","grey"))})`)}return r.join(" ")}function gk(t,{manifestUpdates:e,reportedErrors:r},{fix:o}={}){let a=new Map,n=new Map,u=[...r.keys()].map(A=>[A,new Map]);for(let[A,p]of[...u,...e]){let h=r.get(A)?.map(x=>({text:x,fixable:!1}))??[],E=!1,I=t.getWorkspaceByCwd(A),v=I.manifest.exportTo({});for(let[x,C]of p){if(C.size>1){let R=[...C].map(([N,U])=>{let V=de.pretty(t.configuration,N,de.Type.INSPECT),te=U.size>0?qgt(t.configuration,U.values().next().value):null;return te!==null?`
-${V} at ${te}`:`
-${V}`}).join("");h.push({text:`Conflict detected in constraint targeting ${de.pretty(t.configuration,x,de.Type.CODE)}; conflicting values are:${R}`,fixable:!1})}else{let[[R]]=C,N=(0,Mde.default)(v,x);if(JSON.stringify(N)===JSON.stringify(R))continue;if(!o){let U=typeof N>"u"?`Missing field ${de.pretty(t.configuration,x,de.Type.CODE)}; expected ${de.pretty(t.configuration,R,de.Type.INSPECT)}`:typeof R>"u"?`Extraneous field ${de.pretty(t.configuration,x,de.Type.CODE)} currently set to ${de.pretty(t.configuration,N,de.Type.INSPECT)}`:`Invalid field ${de.pretty(t.configuration,x,de.Type.CODE)}; expected ${de.pretty(t.configuration,R,de.Type.INSPECT)}, found ${de.pretty(t.configuration,N,de.Type.INSPECT)}`;h.push({text:U,fixable:!0});continue}typeof R>"u"?(0,Hde.default)(v,x):(0,Ude.default)(v,x,R),E=!0}E&&a.set(I,v)}h.length>0&&n.set(I,h)}return{changedWorkspaces:a,remainingErrors:n}}function qde(t,{configuration:e}){let r={children:[]};for(let[o,a]of t){let n=[];for(let A of a){let p=A.text.split(/\n/);A.fixable&&(p[0]=`${de.pretty(e,"\u2699","gray")} ${p[0]}`),n.push({value:de.tuple(de.Type.NO_HINT,p[0]),children:p.slice(1).map(h=>({value:de.tuple(de.Type.NO_HINT,h)}))})}let u={value:de.tuple(de.Type.LOCATOR,o.anchoredLocator),children:_e.sortMap(n,A=>A.value[1])};r.children.push(u)}return r.children=_e.sortMap(r.children,o=>o.value[1]),r}var Mde,Ude,_de,Hde,wC,Mgt,Ugt,_gt,v2=Et(()=>{Ye();Mde=$e(d2()),Ude=$e(Q8()),_de=$e(Ode()),Hde=$e(T8()),wC=class{constructor(e){this.indexedFields=e;this.items=[];this.indexes={};this.clear()}clear(){this.items=[];for(let e of this.indexedFields)this.indexes[e]=new Map}insert(e){this.items.push(e);for(let r of this.indexedFields){let o=Object.hasOwn(e,r)?e[r]:void 0;if(typeof o>"u")continue;_e.getArrayWithDefault(this.indexes[r],o).push(e)}return e}find(e){if(typeof e>"u")return this.items;let r=Object.entries(e);if(r.length===0)return this.items;let o=[],a;for(let[u,A]of r){let p=u,h=Object.hasOwn(this.indexes,p)?this.indexes[p]:void 0;if(typeof h>"u"){o.push([p,A]);continue}let E=new Set(h.get(A)??[]);if(E.size===0)return[];if(typeof a>"u")a=E;else for(let I of a)E.has(I)||a.delete(I);if(a.size===0)break}let n=[...a??[]];return o.length>0&&(n=n.filter(u=>{for(let[A,p]of o)if(!(typeof p<"u"?Object.hasOwn(u,A)&&u[A]===p:Object.hasOwn(u,A)===!1))return!1;return!0})),n}},Mgt=/^[0-9]+$/,Ugt=/^[a-zA-Z0-9_]+$/,_gt=new Set(["scripts",...Ot.allDependencies])});var Gde=_((e7t,sH)=>{var Ggt;(function(t){var e=function(){return{"append/2":[new t.type.Rule(new t.type.Term("append",[new t.type.Var("X"),new t.type.Var("L")]),new t.type.Term("foldl",[new t.type.Term("append",[]),new t.type.Var("X"),new t.type.Term("[]",[]),new t.type.Var("L")]))],"append/3":[new t.type.Rule(new t.type.Term("append",[new t.type.Term("[]",[]),new t.type.Var("X"),new t.type.Var("X")]),null),new t.type.Rule(new t.type.Term("append",[new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("T")]),new t.type.Var("X"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("S")])]),new t.type.Term("append",[new t.type.Var("T"),new t.type.Var("X"),new t.type.Var("S")]))],"member/2":[new t.type.Rule(new t.type.Term("member",[new t.type.Var("X"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("_")])]),null),new t.type.Rule(new t.type.Term("member",[new t.type.Var("X"),new t.type.Term(".",[new t.type.Var("_"),new t.type.Var("Xs")])]),new t.type.Term("member",[new t.type.Var("X"),new t.type.Var("Xs")]))],"permutation/2":[new t.type.Rule(new t.type.Term("permutation",[new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("permutation",[new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("T")]),new t.type.Var("S")]),new t.type.Term(",",[new t.type.Term("permutation",[new t.type.Var("T"),new t.type.Var("P")]),new t.type.Term(",",[new t.type.Term("append",[new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("P")]),new t.type.Term("append",[new t.type.Var("X"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("Y")]),new t.type.Var("S")])])]))],"maplist/2":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("X")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("Xs")])]))],"maplist/3":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("A"),new t.type.Var("As")]),new t.type.Term(".",[new t.type.Var("B"),new t.type.Var("Bs")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("A"),new t.type.Var("B")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("As"),new t.type.Var("Bs")])]))],"maplist/4":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("A"),new t.type.Var("As")]),new t.type.Term(".",[new t.type.Var("B"),new t.type.Var("Bs")]),new t.type.Term(".",[new t.type.Var("C"),new t.type.Var("Cs")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("A"),new t.type.Var("B"),new t.type.Var("C")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("As"),new t.type.Var("Bs"),new t.type.Var("Cs")])]))],"maplist/5":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("A"),new t.type.Var("As")]),new t.type.Term(".",[new t.type.Var("B"),new t.type.Var("Bs")]),new t.type.Term(".",[new t.type.Var("C"),new t.type.Var("Cs")]),new t.type.Term(".",[new t.type.Var("D"),new t.type.Var("Ds")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("A"),new t.type.Var("B"),new t.type.Var("C"),new t.type.Var("D")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("As"),new t.type.Var("Bs"),new t.type.Var("Cs"),new t.type.Var("Ds")])]))],"maplist/6":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("A"),new t.type.Var("As")]),new t.type.Term(".",[new t.type.Var("B"),new t.type.Var("Bs")]),new t.type.Term(".",[new t.type.Var("C"),new t.type.Var("Cs")]),new t.type.Term(".",[new t.type.Var("D"),new t.type.Var("Ds")]),new t.type.Term(".",[new t.type.Var("E"),new t.type.Var("Es")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("A"),new t.type.Var("B"),new t.type.Var("C"),new t.type.Var("D"),new t.type.Var("E")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("As"),new t.type.Var("Bs"),new t.type.Var("Cs"),new t.type.Var("Ds"),new t.type.Var("Es")])]))],"maplist/7":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("A"),new t.type.Var("As")]),new t.type.Term(".",[new t.type.Var("B"),new t.type.Var("Bs")]),new t.type.Term(".",[new t.type.Var("C"),new t.type.Var("Cs")]),new t.type.Term(".",[new t.type.Var("D"),new t.type.Var("Ds")]),new t.type.Term(".",[new t.type.Var("E"),new t.type.Var("Es")]),new t.type.Term(".",[new t.type.Var("F"),new t.type.Var("Fs")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("A"),new t.type.Var("B"),new t.type.Var("C"),new t.type.Var("D"),new t.type.Var("E"),new t.type.Var("F")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("As"),new t.type.Var("Bs"),new t.type.Var("Cs"),new t.type.Var("Ds"),new t.type.Var("Es"),new t.type.Var("Fs")])]))],"maplist/8":[new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("A"),new t.type.Var("As")]),new t.type.Term(".",[new t.type.Var("B"),new t.type.Var("Bs")]),new t.type.Term(".",[new t.type.Var("C"),new t.type.Var("Cs")]),new t.type.Term(".",[new t.type.Var("D"),new t.type.Var("Ds")]),new t.type.Term(".",[new t.type.Var("E"),new t.type.Var("Es")]),new t.type.Term(".",[new t.type.Var("F"),new t.type.Var("Fs")]),new t.type.Term(".",[new t.type.Var("G"),new t.type.Var("Gs")])]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P"),new t.type.Var("A"),new t.type.Var("B"),new t.type.Var("C"),new t.type.Var("D"),new t.type.Var("E"),new t.type.Var("F"),new t.type.Var("G")]),new t.type.Term("maplist",[new t.type.Var("P"),new t.type.Var("As"),new t.type.Var("Bs"),new t.type.Var("Cs"),new t.type.Var("Ds"),new t.type.Var("Es"),new t.type.Var("Fs"),new t.type.Var("Gs")])]))],"include/3":[new t.type.Rule(new t.type.Term("include",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("include",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("T")]),new t.type.Var("L")]),new t.type.Term(",",[new t.type.Term("=..",[new t.type.Var("P"),new t.type.Var("A")]),new t.type.Term(",",[new t.type.Term("append",[new t.type.Var("A"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Term("[]",[])]),new t.type.Var("B")]),new t.type.Term(",",[new t.type.Term("=..",[new t.type.Var("F"),new t.type.Var("B")]),new t.type.Term(",",[new t.type.Term(";",[new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("F")]),new t.type.Term(",",[new t.type.Term("=",[new t.type.Var("L"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("S")])]),new t.type.Term("!",[])])]),new t.type.Term("=",[new t.type.Var("L"),new t.type.Var("S")])]),new t.type.Term("include",[new t.type.Var("P"),new t.type.Var("T"),new t.type.Var("S")])])])])]))],"exclude/3":[new t.type.Rule(new t.type.Term("exclude",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Term("[]",[])]),null),new t.type.Rule(new t.type.Term("exclude",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("T")]),new t.type.Var("S")]),new t.type.Term(",",[new t.type.Term("exclude",[new t.type.Var("P"),new t.type.Var("T"),new t.type.Var("E")]),new t.type.Term(",",[new t.type.Term("=..",[new t.type.Var("P"),new t.type.Var("L")]),new t.type.Term(",",[new t.type.Term("append",[new t.type.Var("L"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Term("[]",[])]),new t.type.Var("Q")]),new t.type.Term(",",[new t.type.Term("=..",[new t.type.Var("R"),new t.type.Var("Q")]),new t.type.Term(";",[new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("R")]),new t.type.Term(",",[new t.type.Term("!",[]),new t.type.Term("=",[new t.type.Var("S"),new t.type.Var("E")])])]),new t.type.Term("=",[new t.type.Var("S"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("E")])])])])])])]))],"foldl/4":[new t.type.Rule(new t.type.Term("foldl",[new t.type.Var("_"),new t.type.Term("[]",[]),new t.type.Var("I"),new t.type.Var("I")]),null),new t.type.Rule(new t.type.Term("foldl",[new t.type.Var("P"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Var("T")]),new t.type.Var("I"),new t.type.Var("R")]),new t.type.Term(",",[new t.type.Term("=..",[new t.type.Var("P"),new t.type.Var("L")]),new t.type.Term(",",[new t.type.Term("append",[new t.type.Var("L"),new t.type.Term(".",[new t.type.Var("I"),new t.type.Term(".",[new t.type.Var("H"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Term("[]",[])])])]),new t.type.Var("L2")]),new t.type.Term(",",[new t.type.Term("=..",[new t.type.Var("P2"),new t.type.Var("L2")]),new t.type.Term(",",[new t.type.Term("call",[new t.type.Var("P2")]),new t.type.Term("foldl",[new t.type.Var("P"),new t.type.Var("T"),new t.type.Var("X"),new t.type.Var("R")])])])])]))],"select/3":[new t.type.Rule(new t.type.Term("select",[new t.type.Var("E"),new t.type.Term(".",[new t.type.Var("E"),new t.type.Var("Xs")]),new t.type.Var("Xs")]),null),new t.type.Rule(new t.type.Term("select",[new t.type.Var("E"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")]),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Ys")])]),new t.type.Term("select",[new t.type.Var("E"),new t.type.Var("Xs"),new t.type.Var("Ys")]))],"sum_list/2":[new t.type.Rule(new t.type.Term("sum_list",[new t.type.Term("[]",[]),new t.type.Num(0,!1)]),null),new t.type.Rule(new t.type.Term("sum_list",[new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")]),new t.type.Var("S")]),new t.type.Term(",",[new t.type.Term("sum_list",[new t.type.Var("Xs"),new t.type.Var("Y")]),new t.type.Term("is",[new t.type.Var("S"),new t.type.Term("+",[new t.type.Var("X"),new t.type.Var("Y")])])]))],"max_list/2":[new t.type.Rule(new t.type.Term("max_list",[new t.type.Term(".",[new t.type.Var("X"),new t.type.Term("[]",[])]),new t.type.Var("X")]),null),new t.type.Rule(new t.type.Term("max_list",[new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")]),new t.type.Var("S")]),new t.type.Term(",",[new t.type.Term("max_list",[new t.type.Var("Xs"),new t.type.Var("Y")]),new t.type.Term(";",[new t.type.Term(",",[new t.type.Term(">=",[new t.type.Var("X"),new t.type.Var("Y")]),new t.type.Term(",",[new t.type.Term("=",[new t.type.Var("S"),new t.type.Var("X")]),new t.type.Term("!",[])])]),new t.type.Term("=",[new t.type.Var("S"),new t.type.Var("Y")])])]))],"min_list/2":[new t.type.Rule(new t.type.Term("min_list",[new t.type.Term(".",[new t.type.Var("X"),new t.type.Term("[]",[])]),new t.type.Var("X")]),null),new t.type.Rule(new t.type.Term("min_list",[new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")]),new t.type.Var("S")]),new t.type.Term(",",[new t.type.Term("min_list",[new t.type.Var("Xs"),new t.type.Var("Y")]),new t.type.Term(";",[new t.type.Term(",",[new t.type.Term("=<",[new t.type.Var("X"),new t.type.Var("Y")]),new t.type.Term(",",[new t.type.Term("=",[new t.type.Var("S"),new t.type.Var("X")]),new t.type.Term("!",[])])]),new t.type.Term("=",[new t.type.Var("S"),new t.type.Var("Y")])])]))],"prod_list/2":[new t.type.Rule(new t.type.Term("prod_list",[new t.type.Term("[]",[]),new t.type.Num(1,!1)]),null),new t.type.Rule(new t.type.Term("prod_list",[new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")]),new t.type.Var("S")]),new t.type.Term(",",[new t.type.Term("prod_list",[new t.type.Var("Xs"),new t.type.Var("Y")]),new t.type.Term("is",[new t.type.Var("S"),new t.type.Term("*",[new t.type.Var("X"),new t.type.Var("Y")])])]))],"last/2":[new t.type.Rule(new t.type.Term("last",[new t.type.Term(".",[new t.type.Var("X"),new t.type.Term("[]",[])]),new t.type.Var("X")]),null),new t.type.Rule(new t.type.Term("last",[new t.type.Term(".",[new t.type.Var("_"),new t.type.Var("Xs")]),new t.type.Var("X")]),new t.type.Term("last",[new t.type.Var("Xs"),new t.type.Var("X")]))],"prefix/2":[new t.type.Rule(new t.type.Term("prefix",[new t.type.Var("Part"),new t.type.Var("Whole")]),new t.type.Term("append",[new t.type.Var("Part"),new t.type.Var("_"),new t.type.Var("Whole")]))],"nth0/3":[new t.type.Rule(new t.type.Term("nth0",[new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z")]),new t.type.Term(";",[new t.type.Term("->",[new t.type.Term("var",[new t.type.Var("X")]),new t.type.Term("nth",[new t.type.Num(0,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("_")])]),new t.type.Term(",",[new t.type.Term(">=",[new t.type.Var("X"),new t.type.Num(0,!1)]),new t.type.Term(",",[new t.type.Term("nth",[new t.type.Num(0,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("_")]),new t.type.Term("!",[])])])]))],"nth1/3":[new t.type.Rule(new t.type.Term("nth1",[new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z")]),new t.type.Term(";",[new t.type.Term("->",[new t.type.Term("var",[new t.type.Var("X")]),new t.type.Term("nth",[new t.type.Num(1,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("_")])]),new t.type.Term(",",[new t.type.Term(">",[new t.type.Var("X"),new t.type.Num(0,!1)]),new t.type.Term(",",[new t.type.Term("nth",[new t.type.Num(1,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("_")]),new t.type.Term("!",[])])])]))],"nth0/4":[new t.type.Rule(new t.type.Term("nth0",[new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("W")]),new t.type.Term(";",[new t.type.Term("->",[new t.type.Term("var",[new t.type.Var("X")]),new t.type.Term("nth",[new t.type.Num(0,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("W")])]),new t.type.Term(",",[new t.type.Term(">=",[new t.type.Var("X"),new t.type.Num(0,!1)]),new t.type.Term(",",[new t.type.Term("nth",[new t.type.Num(0,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("W")]),new t.type.Term("!",[])])])]))],"nth1/4":[new t.type.Rule(new t.type.Term("nth1",[new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("W")]),new t.type.Term(";",[new t.type.Term("->",[new t.type.Term("var",[new t.type.Var("X")]),new t.type.Term("nth",[new t.type.Num(1,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("W")])]),new t.type.Term(",",[new t.type.Term(">",[new t.type.Var("X"),new t.type.Num(0,!1)]),new t.type.Term(",",[new t.type.Term("nth",[new t.type.Num(1,!1),new t.type.Var("X"),new t.type.Var("Y"),new t.type.Var("Z"),new t.type.Var("W")]),new t.type.Term("!",[])])])]))],"nth/5":[new t.type.Rule(new t.type.Term("nth",[new t.type.Var("N"),new t.type.Var("N"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")]),new t.type.Var("X"),new t.type.Var("Xs")]),null),new t.type.Rule(new t.type.Term("nth",[new t.type.Var("N"),new t.type.Var("O"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Xs")]),new t.type.Var("Y"),new t.type.Term(".",[new t.type.Var("X"),new t.type.Var("Ys")])]),new t.type.Term(",",[new t.type.Term("is",[new t.type.Var("M"),new t.type.Term("+",[new t.type.Var("N"),new t.type.Num(1,!1)])]),new t.type.Term("nth",[new t.type.Var("M"),new t.type.Var("O"),new t.type.Var("Xs"),new t.type.Var("Y"),new t.type.Var("Ys")])]))],"length/2":function(o,a,n){var u=n.args[0],A=n.args[1];if(!t.type.is_variable(A)&&!t.type.is_integer(A))o.throw_error(t.error.type("integer",A,n.indicator));else if(t.type.is_integer(A)&&A.value<0)o.throw_error(t.error.domain("not_less_than_zero",A,n.indicator));else{var p=new t.type.Term("length",[u,new t.type.Num(0,!1),A]);t.type.is_integer(A)&&(p=new t.type.Term(",",[p,new t.type.Term("!",[])])),o.prepend([new t.type.State(a.goal.replace(p),a.substitution,a)])}},"length/3":[new t.type.Rule(new t.type.Term("length",[new t.type.Term("[]",[]),new t.type.Var("N"),new t.type.Var("N")]),null),new t.type.Rule(new t.type.Term("length",[new t.type.Term(".",[new t.type.Var("_"),new t.type.Var("X")]),new t.type.Var("A"),new t.type.Var("N")]),new t.type.Term(",",[new t.type.Term("succ",[new t.type.Var("A"),new t.type.Var("B")]),new t.type.Term("length",[new t.type.Var("X"),new t.type.Var("B"),new t.type.Var("N")])]))],"replicate/3":function(o,a,n){var u=n.args[0],A=n.args[1],p=n.args[2];if(t.type.is_variable(A))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_integer(A))o.throw_error(t.error.type("integer",A,n.indicator));else if(A.value<0)o.throw_error(t.error.domain("not_less_than_zero",A,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))o.throw_error(t.error.type("list",p,n.indicator));else{for(var h=new t.type.Term("[]"),E=0;E<A.value;E++)h=new t.type.Term(".",[u,h]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[h,p])),a.substitution,a)])}},"sort/2":function(o,a,n){var u=n.args[0],A=n.args[1];if(t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(A)&&!t.type.is_fully_list(A))o.throw_error(t.error.type("list",A,n.indicator));else{for(var p=[],h=u;h.indicator==="./2";)p.push(h.args[0]),h=h.args[1];if(t.type.is_variable(h))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_empty_list(h))o.throw_error(t.error.type("list",u,n.indicator));else{for(var E=p.sort(t.compare),I=E.length-1;I>0;I--)E[I].equals(E[I-1])&&E.splice(I,1);for(var v=new t.type.Term("[]"),I=E.length-1;I>=0;I--)v=new t.type.Term(".",[E[I],v]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[v,A])),a.substitution,a)])}}},"msort/2":function(o,a,n){var u=n.args[0],A=n.args[1];if(t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(A)&&!t.type.is_fully_list(A))o.throw_error(t.error.type("list",A,n.indicator));else{for(var p=[],h=u;h.indicator==="./2";)p.push(h.args[0]),h=h.args[1];if(t.type.is_variable(h))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_empty_list(h))o.throw_error(t.error.type("list",u,n.indicator));else{for(var E=p.sort(t.compare),I=new t.type.Term("[]"),v=E.length-1;v>=0;v--)I=new t.type.Term(".",[E[v],I]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[I,A])),a.substitution,a)])}}},"keysort/2":function(o,a,n){var u=n.args[0],A=n.args[1];if(t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(A)&&!t.type.is_fully_list(A))o.throw_error(t.error.type("list",A,n.indicator));else{for(var p=[],h,E=u;E.indicator==="./2";){if(h=E.args[0],t.type.is_variable(h)){o.throw_error(t.error.instantiation(n.indicator));return}else if(!t.type.is_term(h)||h.indicator!=="-/2"){o.throw_error(t.error.type("pair",h,n.indicator));return}h.args[0].pair=h.args[1],p.push(h.args[0]),E=E.args[1]}if(t.type.is_variable(E))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_empty_list(E))o.throw_error(t.error.type("list",u,n.indicator));else{for(var I=p.sort(t.compare),v=new t.type.Term("[]"),x=I.length-1;x>=0;x--)v=new t.type.Term(".",[new t.type.Term("-",[I[x],I[x].pair]),v]),delete I[x].pair;o.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[v,A])),a.substitution,a)])}}},"take/3":function(o,a,n){var u=n.args[0],A=n.args[1],p=n.args[2];if(t.type.is_variable(A)||t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_list(A))o.throw_error(t.error.type("list",A,n.indicator));else if(!t.type.is_integer(u))o.throw_error(t.error.type("integer",u,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))o.throw_error(t.error.type("list",p,n.indicator));else{for(var h=u.value,E=[],I=A;h>0&&I.indicator==="./2";)E.push(I.args[0]),I=I.args[1],h--;if(h===0){for(var v=new t.type.Term("[]"),h=E.length-1;h>=0;h--)v=new t.type.Term(".",[E[h],v]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[v,p])),a.substitution,a)])}}},"drop/3":function(o,a,n){var u=n.args[0],A=n.args[1],p=n.args[2];if(t.type.is_variable(A)||t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_list(A))o.throw_error(t.error.type("list",A,n.indicator));else if(!t.type.is_integer(u))o.throw_error(t.error.type("integer",u,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))o.throw_error(t.error.type("list",p,n.indicator));else{for(var h=u.value,E=[],I=A;h>0&&I.indicator==="./2";)E.push(I.args[0]),I=I.args[1],h--;h===0&&o.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[I,p])),a.substitution,a)])}},"reverse/2":function(o,a,n){var u=n.args[0],A=n.args[1],p=t.type.is_instantiated_list(u),h=t.type.is_instantiated_list(A);if(t.type.is_variable(u)&&t.type.is_variable(A))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(u)&&!t.type.is_fully_list(u))o.throw_error(t.error.type("list",u,n.indicator));else if(!t.type.is_variable(A)&&!t.type.is_fully_list(A))o.throw_error(t.error.type("list",A,n.indicator));else if(!p&&!h)o.throw_error(t.error.instantiation(n.indicator));else{for(var E=p?u:A,I=new t.type.Term("[]",[]);E.indicator==="./2";)I=new t.type.Term(".",[E.args[0],I]),E=E.args[1];o.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[I,p?A:u])),a.substitution,a)])}},"list_to_set/2":function(o,a,n){var u=n.args[0],A=n.args[1];if(t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else{for(var p=u,h=[];p.indicator==="./2";)h.push(p.args[0]),p=p.args[1];if(t.type.is_variable(p))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_term(p)||p.indicator!=="[]/0")o.throw_error(t.error.type("list",u,n.indicator));else{for(var E=[],I=new t.type.Term("[]",[]),v,x=0;x<h.length;x++){v=!1;for(var C=0;C<E.length&&!v;C++)v=t.compare(h[x],E[C])===0;v||E.push(h[x])}for(x=E.length-1;x>=0;x--)I=new t.type.Term(".",[E[x],I]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term("=",[A,I])),a.substitution,a)])}}}}},r=["append/2","append/3","member/2","permutation/2","maplist/2","maplist/3","maplist/4","maplist/5","maplist/6","maplist/7","maplist/8","include/3","exclude/3","foldl/4","sum_list/2","max_list/2","min_list/2","prod_list/2","last/2","prefix/2","nth0/3","nth1/3","nth0/4","nth1/4","length/2","replicate/3","select/3","sort/2","msort/2","keysort/2","take/3","drop/3","reverse/2","list_to_set/2"];typeof sH<"u"?sH.exports=function(o){t=o,new t.type.Module("lists",e(),r)}:new t.type.Module("lists",e(),r)})(Ggt)});var ime=_(Yr=>{"use strict";var em=process.platform==="win32",oH="aes-256-cbc",jgt="sha256",Wde="The current environment doesn't support interactive reading from TTY.",Yn=ve("fs"),jde=process.binding("tty_wrap").TTY,lH=ve("child_process"),u0=ve("path"),cH={prompt:"> ",hideEchoBack:!1,mask:"*",limit:[],limitMessage:"Input another, please.$<( [)limit(])>",defaultInput:"",trueValue:[],falseValue:[],caseSensitive:!1,keepWhitespace:!1,encoding:"utf8",bufferSize:1024,print:void 0,history:!0,cd:!1,phContent:void 0,preCheck:void 0},Jf="none",Zc,BC,Yde=!1,c0,mk,aH,Ygt=0,hH="",$d=[],yk,Kde=!1,uH=!1,D2=!1;function zde(t){function e(r){return r.replace(/[^\w\u0080-\uFFFF]/g,function(o){return"#"+o.charCodeAt(0)+";"})}return mk.concat(function(r){var o=[];return Object.keys(r).forEach(function(a){r[a]==="boolean"?t[a]&&o.push("--"+a):r[a]==="string"&&t[a]&&o.push("--"+a,e(t[a]))}),o}({display:"string",displayOnly:"boolean",keyIn:"boolean",hideEchoBack:"boolean",mask:"string",limit:"string",caseSensitive:"boolean"}))}function Wgt(t,e){function r(U){var V,te="",ae;for(aH=aH||ve("os").tmpdir();;){V=u0.join(aH,U+te);try{ae=Yn.openSync(V,"wx")}catch(fe){if(fe.code==="EEXIST"){te++;continue}else throw fe}Yn.closeSync(ae);break}return V}var o,a,n,u={},A,p,h=r("readline-sync.stdout"),E=r("readline-sync.stderr"),I=r("readline-sync.exit"),v=r("readline-sync.done"),x=ve("crypto"),C,R,N;C=x.createHash(jgt),C.update(""+process.pid+Ygt+++Math.random()),N=C.digest("hex"),R=x.createDecipher(oH,N),o=zde(t),em?(a=process.env.ComSpec||"cmd.exe",process.env.Q='"',n=["/V:ON","/S","/C","(%Q%"+a+"%Q% /V:ON /S /C %Q%%Q%"+c0+"%Q%"+o.map(function(U){return" %Q%"+U+"%Q%"}).join("")+" & (echo !ERRORLEVEL!)>%Q%"+I+"%Q%%Q%) 2>%Q%"+E+"%Q% |%Q%"+process.execPath+"%Q% %Q%"+__dirname+"\\encrypt.js%Q% %Q%"+oH+"%Q% %Q%"+N+"%Q% >%Q%"+h+"%Q% & (echo 1)>%Q%"+v+"%Q%"]):(a="/bin/sh",n=["-c",'("'+c0+'"'+o.map(function(U){return" '"+U.replace(/'/g,"'\\''")+"'"}).join("")+'; echo $?>"'+I+'") 2>"'+E+'" |"'+process.execPath+'" "'+__dirname+'/encrypt.js" "'+oH+'" "'+N+'" >"'+h+'"; echo 1 >"'+v+'"']),D2&&D2("_execFileSync",o);try{lH.spawn(a,n,e)}catch(U){u.error=new Error(U.message),u.error.method="_execFileSync - spawn",u.error.program=a,u.error.args=n}for(;Yn.readFileSync(v,{encoding:t.encoding}).trim()!=="1";);return(A=Yn.readFileSync(I,{encoding:t.encoding}).trim())==="0"?u.input=R.update(Yn.readFileSync(h,{encoding:"binary"}),"hex",t.encoding)+R.final(t.encoding):(p=Yn.readFileSync(E,{encoding:t.encoding}).trim(),u.error=new Error(Wde+(p?`
-`+p:"")),u.error.method="_execFileSync",u.error.program=a,u.error.args=n,u.error.extMessage=p,u.error.exitCode=+A),Yn.unlinkSync(h),Yn.unlinkSync(E),Yn.unlinkSync(I),Yn.unlinkSync(v),u}function Kgt(t){var e,r={},o,a={env:process.env,encoding:t.encoding};if(c0||(em?process.env.PSModulePath?(c0="powershell.exe",mk=["-ExecutionPolicy","Bypass","-File",__dirname+"\\read.ps1"]):(c0="cscript.exe",mk=["//nologo",__dirname+"\\read.cs.js"]):(c0="/bin/sh",mk=[__dirname+"/read.sh"])),em&&!process.env.PSModulePath&&(a.stdio=[process.stdin]),lH.execFileSync){e=zde(t),D2&&D2("execFileSync",e);try{r.input=lH.execFileSync(c0,e,a)}catch(n){o=n.stderr?(n.stderr+"").trim():"",r.error=new Error(Wde+(o?`
-`+o:"")),r.error.method="execFileSync",r.error.program=c0,r.error.args=e,r.error.extMessage=o,r.error.exitCode=n.status,r.error.code=n.code,r.error.signal=n.signal}}else r=Wgt(t,a);return r.error||(r.input=r.input.replace(/^\s*'|'\s*$/g,""),t.display=""),r}function AH(t){var e="",r=t.display,o=!t.display&&t.keyIn&&t.hideEchoBack&&!t.mask;function a(){var n=Kgt(t);if(n.error)throw n.error;return n.input}return uH&&uH(t),function(){var n,u,A;function p(){return n||(n=process.binding("fs"),u=process.binding("constants")),n}if(typeof Jf=="string")if(Jf=null,em){if(A=function(h){var E=h.replace(/^\D+/,"").split("."),I=0;return(E[0]=+E[0])&&(I+=E[0]*1e4),(E[1]=+E[1])&&(I+=E[1]*100),(E[2]=+E[2])&&(I+=E[2]),I}(process.version),!(A>=20302&&A<40204||A>=5e4&&A<50100||A>=50600&&A<60200)&&process.stdin.isTTY)process.stdin.pause(),Jf=process.stdin.fd,BC=process.stdin._handle;else try{Jf=p().open("CONIN$",u.O_RDWR,parseInt("0666",8)),BC=new jde(Jf,!0)}catch{}if(process.stdout.isTTY)Zc=process.stdout.fd;else{try{Zc=Yn.openSync("\\\\.\\CON","w")}catch{}if(typeof Zc!="number")try{Zc=p().open("CONOUT$",u.O_RDWR,parseInt("0666",8))}catch{}}}else{if(process.stdin.isTTY){process.stdin.pause();try{Jf=Yn.openSync("/dev/tty","r"),BC=process.stdin._handle}catch{}}else try{Jf=Yn.openSync("/dev/tty","r"),BC=new jde(Jf,!1)}catch{}if(process.stdout.isTTY)Zc=process.stdout.fd;else try{Zc=Yn.openSync("/dev/tty","w")}catch{}}}(),function(){var n,u,A=!t.hideEchoBack&&!t.keyIn,p,h,E,I,v;yk="";function x(C){return C===Yde?!0:BC.setRawMode(C)!==0?!1:(Yde=C,!0)}if(Kde||!BC||typeof Zc!="number"&&(t.display||!A)){e=a();return}if(t.display&&(Yn.writeSync(Zc,t.display),t.display=""),!t.displayOnly){if(!x(!A)){e=a();return}for(h=t.keyIn?1:t.bufferSize,p=Buffer.allocUnsafe&&Buffer.alloc?Buffer.alloc(h):new Buffer(h),t.keyIn&&t.limit&&(u=new RegExp("[^"+t.limit+"]","g"+(t.caseSensitive?"":"i")));;){E=0;try{E=Yn.readSync(Jf,p,0,h)}catch(C){if(C.code!=="EOF"){x(!1),e+=a();return}}if(E>0?(I=p.toString(t.encoding,0,E),yk+=I):(I=`
-`,yk+=String.fromCharCode(0)),I&&typeof(v=(I.match(/^(.*?)[\r\n]/)||[])[1])=="string"&&(I=v,n=!0),I&&(I=I.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g,"")),I&&u&&(I=I.replace(u,"")),I&&(A||(t.hideEchoBack?t.mask&&Yn.writeSync(Zc,new Array(I.length+1).join(t.mask)):Yn.writeSync(Zc,I)),e+=I),!t.keyIn&&n||t.keyIn&&e.length>=h)break}!A&&!o&&Yn.writeSync(Zc,`
-`),x(!1)}}(),t.print&&!o&&t.print(r+(t.displayOnly?"":(t.hideEchoBack?new Array(e.length+1).join(t.mask):e)+`
-`),t.encoding),t.displayOnly?"":hH=t.keepWhitespace||t.keyIn?e:e.trim()}function zgt(t,e){var r=[];function o(a){a!=null&&(Array.isArray(a)?a.forEach(o):(!e||e(a))&&r.push(a))}return o(t),r}function gH(t){return t.replace(/[\x00-\x7f]/g,function(e){return"\\x"+("00"+e.charCodeAt().toString(16)).substr(-2)})}function Rs(){var t=Array.prototype.slice.call(arguments),e,r;return t.length&&typeof t[0]=="boolean"&&(r=t.shift(),r&&(e=Object.keys(cH),t.unshift(cH))),t.reduce(function(o,a){return a==null||(a.hasOwnProperty("noEchoBack")&&!a.hasOwnProperty("hideEchoBack")&&(a.hideEchoBack=a.noEchoBack,delete a.noEchoBack),a.hasOwnProperty("noTrim")&&!a.hasOwnProperty("keepWhitespace")&&(a.keepWhitespace=a.noTrim,delete a.noTrim),r||(e=Object.keys(a)),e.forEach(function(n){var u;if(!!a.hasOwnProperty(n))switch(u=a[n],n){case"mask":case"limitMessage":case"defaultInput":case"encoding":u=u!=null?u+"":"",u&&n!=="limitMessage"&&(u=u.replace(/[\r\n]/g,"")),o[n]=u;break;case"bufferSize":!isNaN(u=parseInt(u,10))&&typeof u=="number"&&(o[n]=u);break;case"displayOnly":case"keyIn":case"hideEchoBack":case"caseSensitive":case"keepWhitespace":case"history":case"cd":o[n]=!!u;break;case"limit":case"trueValue":case"falseValue":o[n]=zgt(u,function(A){var p=typeof A;return p==="string"||p==="number"||p==="function"||A instanceof RegExp}).map(function(A){return typeof A=="string"?A.replace(/[\r\n]/g,""):A});break;case"print":case"phContent":case"preCheck":o[n]=typeof u=="function"?u:void 0;break;case"prompt":case"display":o[n]=u??"";break}})),o},{})}function fH(t,e,r){return e.some(function(o){var a=typeof o;return a==="string"?r?t===o:t.toLowerCase()===o.toLowerCase():a==="number"?parseFloat(t)===o:a==="function"?o(t):o instanceof RegExp?o.test(t):!1})}function dH(t,e){var r=u0.normalize(em?(process.env.HOMEDRIVE||"")+(process.env.HOMEPATH||""):process.env.HOME||"").replace(/[\/\\]+$/,"");return t=u0.normalize(t),e?t.replace(/^~(?=\/|\\|$)/,r):t.replace(new RegExp("^"+gH(r)+"(?=\\/|\\\\|$)",em?"i":""),"~")}function vC(t,e){var r="(?:\\(([\\s\\S]*?)\\))?(\\w+|.-.)(?:\\(([\\s\\S]*?)\\))?",o=new RegExp("(\\$)?(\\$<"+r+">)","g"),a=new RegExp("(\\$)?(\\$\\{"+r+"\\})","g");function n(u,A,p,h,E,I){var v;return A||typeof(v=e(E))!="string"?p:v?(h||"")+v+(I||""):""}return t.replace(o,n).replace(a,n)}function Vde(t,e,r){var o,a=[],n=-1,u=0,A="",p;function h(E,I){return I.length>3?(E.push(I[0]+"..."+I[I.length-1]),p=!0):I.length&&(E=E.concat(I)),E}return o=t.reduce(function(E,I){return E.concat((I+"").split(""))},[]).reduce(function(E,I){var v,x;return e||(I=I.toLowerCase()),v=/^\d$/.test(I)?1:/^[A-Z]$/.test(I)?2:/^[a-z]$/.test(I)?3:0,r&&v===0?A+=I:(x=I.charCodeAt(0),v&&v===n&&x===u+1?a.push(I):(E=h(E,a),a=[I],n=v),u=x),E},[]),o=h(o,a),A&&(o.push(A),p=!0),{values:o,suppressed:p}}function Jde(t,e){return t.join(t.length>2?", ":e?" / ":"/")}function Xde(t,e){var r,o,a={},n;if(e.phContent&&(r=e.phContent(t,e)),typeof r!="string")switch(t){case"hideEchoBack":case"mask":case"defaultInput":case"caseSensitive":case"keepWhitespace":case"encoding":case"bufferSize":case"history":case"cd":r=e.hasOwnProperty(t)?typeof e[t]=="boolean"?e[t]?"on":"off":e[t]+"":"";break;case"limit":case"trueValue":case"falseValue":o=e[e.hasOwnProperty(t+"Src")?t+"Src":t],e.keyIn?(a=Vde(o,e.caseSensitive),o=a.values):o=o.filter(function(u){var A=typeof u;return A==="string"||A==="number"}),r=Jde(o,a.suppressed);break;case"limitCount":case"limitCountNotZero":r=e[e.hasOwnProperty("limitSrc")?"limitSrc":"limit"].length,r=r||t!=="limitCountNotZero"?r+"":"";break;case"lastInput":r=hH;break;case"cwd":case"CWD":case"cwdHome":r=process.cwd(),t==="CWD"?r=u0.basename(r):t==="cwdHome"&&(r=dH(r));break;case"date":case"time":case"localeDate":case"localeTime":r=new Date()["to"+t.replace(/^./,function(u){return u.toUpperCase()})+"String"]();break;default:typeof(n=(t.match(/^history_m(\d+)$/)||[])[1])=="string"&&(r=$d[$d.length-n]||"")}return r}function Zde(t){var e=/^(.)-(.)$/.exec(t),r="",o,a,n,u;if(!e)return null;for(o=e[1].charCodeAt(0),a=e[2].charCodeAt(0),u=o<a?1:-1,n=o;n!==a+u;n+=u)r+=String.fromCharCode(n);return r}function pH(t){var e=new RegExp(/(\s*)(?:("|')(.*?)(?:\2|$)|(\S+))/g),r,o="",a=[],n;for(t=t.trim();r=e.exec(t);)n=r[3]||r[4]||"",r[1]&&(a.push(o),o=""),o+=n;return o&&a.push(o),a}function $de(t,e){return e.trueValue.length&&fH(t,e.trueValue,e.caseSensitive)?!0:e.falseValue.length&&fH(t,e.falseValue,e.caseSensitive)?!1:t}function eme(t){var e,r,o,a,n,u,A;function p(E){return Xde(E,t)}function h(E){t.display+=(/[^\r\n]$/.test(t.display)?`
-`:"")+E}for(t.limitSrc=t.limit,t.displaySrc=t.display,t.limit="",t.display=vC(t.display+"",p);;){if(e=AH(t),r=!1,o="",t.defaultInput&&!e&&(e=t.defaultInput),t.history&&((a=/^\s*\!(?:\!|-1)(:p)?\s*$/.exec(e))?(n=$d[0]||"",a[1]?r=!0:e=n,h(n+`
-`),r||(t.displayOnly=!0,AH(t),t.displayOnly=!1)):e&&e!==$d[$d.length-1]&&($d=[e])),!r&&t.cd&&e)switch(u=pH(e),u[0].toLowerCase()){case"cd":if(u[1])try{process.chdir(dH(u[1],!0))}catch(E){h(E+"")}r=!0;break;case"pwd":h(process.cwd()),r=!0;break}if(!r&&t.preCheck&&(A=t.preCheck(e,t),e=A.res,A.forceNext&&(r=!0)),!r){if(!t.limitSrc.length||fH(e,t.limitSrc,t.caseSensitive))break;t.limitMessage&&(o=vC(t.limitMessage,p))}h((o?o+`
-`:"")+vC(t.displaySrc+"",p))}return $de(e,t)}Yr._DBG_set_useExt=function(t){Kde=t};Yr._DBG_set_checkOptions=function(t){uH=t};Yr._DBG_set_checkMethod=function(t){D2=t};Yr._DBG_clearHistory=function(){hH="",$d=[]};Yr.setDefaultOptions=function(t){return cH=Rs(!0,t),Rs(!0)};Yr.question=function(t,e){return eme(Rs(Rs(!0,e),{display:t}))};Yr.prompt=function(t){var e=Rs(!0,t);return e.display=e.prompt,eme(e)};Yr.keyIn=function(t,e){var r=Rs(Rs(!0,e),{display:t,keyIn:!0,keepWhitespace:!0});return r.limitSrc=r.limit.filter(function(o){var a=typeof o;return a==="string"||a==="number"}).map(function(o){return vC(o+"",Zde)}),r.limit=gH(r.limitSrc.join("")),["trueValue","falseValue"].forEach(function(o){r[o]=r[o].reduce(function(a,n){var u=typeof n;return u==="string"||u==="number"?a=a.concat((n+"").split("")):a.push(n),a},[])}),r.display=vC(r.display+"",function(o){return Xde(o,r)}),$de(AH(r),r)};Yr.questionEMail=function(t,e){return t==null&&(t="Input e-mail address: "),Yr.question(t,Rs({hideEchoBack:!1,limit:/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,limitMessage:"Input valid e-mail address, please.",trueValue:null,falseValue:null},e,{keepWhitespace:!1,cd:!1}))};Yr.questionNewPassword=function(t,e){var r,o,a,n=Rs({hideEchoBack:!0,mask:"*",limitMessage:`It can include: $<charlist>
-And the length must be: $<length>`,trueValue:null,falseValue:null,caseSensitive:!0},e,{history:!1,cd:!1,phContent:function(x){return x==="charlist"?r.text:x==="length"?o+"..."+a:null}}),u,A,p,h,E,I,v;for(e=e||{},u=vC(e.charlist?e.charlist+"":"$<!-~>",Zde),(isNaN(o=parseInt(e.min,10))||typeof o!="number")&&(o=12),(isNaN(a=parseInt(e.max,10))||typeof a!="number")&&(a=24),h=new RegExp("^["+gH(u)+"]{"+o+","+a+"}$"),r=Vde([u],n.caseSensitive,!0),r.text=Jde(r.values,r.suppressed),A=e.confirmMessage!=null?e.confirmMessage:"Reinput a same one to confirm it: ",p=e.unmatchMessage!=null?e.unmatchMessage:"It differs from first one. Hit only the Enter key if you want to retry from first one.",t==null&&(t="Input new password: "),E=n.limitMessage;!v;)n.limit=h,n.limitMessage=E,I=Yr.question(t,n),n.limit=[I,""],n.limitMessage=p,v=Yr.question(A,n);return I};function tme(t,e,r){var o;function a(n){return o=r(n),!isNaN(o)&&typeof o=="number"}return Yr.question(t,Rs({limitMessage:"Input valid number, please."},e,{limit:a,cd:!1})),o}Yr.questionInt=function(t,e){return tme(t,e,function(r){return parseInt(r,10)})};Yr.questionFloat=function(t,e){return tme(t,e,parseFloat)};Yr.questionPath=function(t,e){var r,o="",a=Rs({hideEchoBack:!1,limitMessage:`$<error(
-)>Input valid path, please.$<( Min:)min>$<( Max:)max>`,history:!0,cd:!0},e,{keepWhitespace:!1,limit:function(n){var u,A,p;n=dH(n,!0),o="";function h(E){E.split(/\/|\\/).reduce(function(I,v){var x=u0.resolve(I+=v+u0.sep);if(!Yn.existsSync(x))Yn.mkdirSync(x);else if(!Yn.statSync(x).isDirectory())throw new Error("Non directory already exists: "+x);return I},"")}try{if(u=Yn.existsSync(n),r=u?Yn.realpathSync(n):u0.resolve(n),!e.hasOwnProperty("exists")&&!u||typeof e.exists=="boolean"&&e.exists!==u)return o=(u?"Already exists":"No such file or directory")+": "+r,!1;if(!u&&e.create&&(e.isDirectory?h(r):(h(u0.dirname(r)),Yn.closeSync(Yn.openSync(r,"w"))),r=Yn.realpathSync(r)),u&&(e.min||e.max||e.isFile||e.isDirectory)){if(A=Yn.statSync(r),e.isFile&&!A.isFile())return o="Not file: "+r,!1;if(e.isDirectory&&!A.isDirectory())return o="Not directory: "+r,!1;if(e.min&&A.size<+e.min||e.max&&A.size>+e.max)return o="Size "+A.size+" is out of range: "+r,!1}if(typeof e.validate=="function"&&(p=e.validate(r))!==!0)return typeof p=="string"&&(o=p),!1}catch(E){return o=E+"",!1}return!0},phContent:function(n){return n==="error"?o:n!=="min"&&n!=="max"?null:e.hasOwnProperty(n)?e[n]+"":""}});return e=e||{},t==null&&(t='Input path (you can "cd" and "pwd"): '),Yr.question(t,a),r};function rme(t,e){var r={},o={};return typeof t=="object"?(Object.keys(t).forEach(function(a){typeof t[a]=="function"&&(o[e.caseSensitive?a:a.toLowerCase()]=t[a])}),r.preCheck=function(a){var n;return r.args=pH(a),n=r.args[0]||"",e.caseSensitive||(n=n.toLowerCase()),r.hRes=n!=="_"&&o.hasOwnProperty(n)?o[n].apply(a,r.args.slice(1)):o.hasOwnProperty("_")?o._.apply(a,r.args):null,{res:a,forceNext:!1}},o.hasOwnProperty("_")||(r.limit=function(){var a=r.args[0]||"";return e.caseSensitive||(a=a.toLowerCase()),o.hasOwnProperty(a)})):r.preCheck=function(a){return r.args=pH(a),r.hRes=typeof t=="function"?t.apply(a,r.args):!0,{res:a,forceNext:!1}},r}Yr.promptCL=function(t,e){var r=Rs({hideEchoBack:!1,limitMessage:"Requested command is not available.",caseSensitive:!1,history:!0},e),o=rme(t,r);return r.limit=o.limit,r.preCheck=o.preCheck,Yr.prompt(r),o.args};Yr.promptLoop=function(t,e){for(var r=Rs({hideEchoBack:!1,trueValue:null,falseValue:null,caseSensitive:!1,history:!0},e);!t(Yr.prompt(r)););};Yr.promptCLLoop=function(t,e){var r=Rs({hideEchoBack:!1,limitMessage:"Requested command is not available.",caseSensitive:!1,history:!0},e),o=rme(t,r);for(r.limit=o.limit,r.preCheck=o.preCheck;Yr.prompt(r),!o.hRes;);};Yr.promptSimShell=function(t){return Yr.prompt(Rs({hideEchoBack:!1,history:!0},t,{prompt:function(){return em?"$<cwd>>":(process.env.USER||"")+(process.env.HOSTNAME?"@"+process.env.HOSTNAME.replace(/\..*$/,""):"")+":$<cwdHome>$ "}()}))};function nme(t,e,r){var o;return t==null&&(t="Are you sure? "),(!e||e.guide!==!1)&&(t+="")&&(t=t.replace(/\s*:?\s*$/,"")+" [y/n]: "),o=Yr.keyIn(t,Rs(e,{hideEchoBack:!1,limit:r,trueValue:"y",falseValue:"n",caseSensitive:!1})),typeof o=="boolean"?o:""}Yr.keyInYN=function(t,e){return nme(t,e)};Yr.keyInYNStrict=function(t,e){return nme(t,e,"yn")};Yr.keyInPause=function(t,e){t==null&&(t="Continue..."),(!e||e.guide!==!1)&&(t+="")&&(t=t.replace(/\s+$/,"")+" (Hit any key)"),Yr.keyIn(t,Rs({limit:null},e,{hideEchoBack:!0,mask:""}))};Yr.keyInSelect=function(t,e,r){var o=Rs({hideEchoBack:!1},r,{trueValue:null,falseValue:null,caseSensitive:!1,phContent:function(p){return p==="itemsCount"?t.length+"":p==="firstItem"?(t[0]+"").trim():p==="lastItem"?(t[t.length-1]+"").trim():null}}),a="",n={},u=49,A=`
-`;if(!Array.isArray(t)||!t.length||t.length>35)throw"`items` must be Array (max length: 35).";return t.forEach(function(p,h){var E=String.fromCharCode(u);a+=E,n[E]=h,A+="["+E+"] "+(p+"").trim()+`
-`,u=u===57?97:u+1}),(!r||r.cancel!==!1)&&(a+="0",n[0]=-1,A+="[0] "+(r&&r.cancel!=null&&typeof r.cancel!="boolean"?(r.cancel+"").trim():"CANCEL")+`
-`),o.limit=a,A+=`
-`,e==null&&(e="Choose one from list: "),(e+="")&&((!r||r.guide!==!1)&&(e=e.replace(/\s*:?\s*$/,"")+" [$<limit>]: "),A+=e),n[Yr.keyIn(A,o).toLowerCase()]};Yr.getRawInput=function(){return yk};function P2(t,e){var r;return e.length&&(r={},r[t]=e[0]),Yr.setDefaultOptions(r)[t]}Yr.setPrint=function(){return P2("print",arguments)};Yr.setPrompt=function(){return P2("prompt",arguments)};Yr.setEncoding=function(){return P2("encoding",arguments)};Yr.setMask=function(){return P2("mask",arguments)};Yr.setBufferSize=function(){return P2("bufferSize",arguments)}});var mH=_((r7t,gl)=>{(function(){var t={major:0,minor:2,patch:66,status:"beta"};tau_file_system={files:{},open:function(w,S,y){var F=tau_file_system.files[w];if(!F){if(y==="read")return null;F={path:w,text:"",type:S,get:function(J,X){return X===this.text.length||X>this.text.length?"end_of_file":this.text.substring(X,X+J)},put:function(J,X){return X==="end_of_file"?(this.text+=J,!0):X==="past_end_of_file"?null:(this.text=this.text.substring(0,X)+J+this.text.substring(X+J.length),!0)},get_byte:function(J){if(J==="end_of_stream")return-1;var X=Math.floor(J/2);if(this.text.length<=X)return-1;var Z=n(this.text[Math.floor(J/2)],0);return J%2===0?Z&255:Z/256>>>0},put_byte:function(J,X){var Z=X==="end_of_stream"?this.text.length:Math.floor(X/2);if(this.text.length<Z)return null;var ie=this.text.length===Z?-1:n(this.text[Math.floor(X/2)],0);return X%2===0?(ie=ie/256>>>0,ie=(ie&255)<<8|J&255):(ie=ie&255,ie=(J&255)<<8|ie&255),this.text.length===Z?this.text+=u(ie):this.text=this.text.substring(0,Z)+u(ie)+this.text.substring(Z+1),!0},flush:function(){return!0},close:function(){var J=tau_file_system.files[this.path];return J?!0:null}},tau_file_system.files[w]=F}return y==="write"&&(F.text=""),F}},tau_user_input={buffer:"",get:function(w,S){for(var y;tau_user_input.buffer.length<w;)y=window.prompt(),y&&(tau_user_input.buffer+=y);return y=tau_user_input.buffer.substr(0,w),tau_user_input.buffer=tau_user_input.buffer.substr(w),y}},tau_user_output={put:function(w,S){return console.log(w),!0},flush:function(){return!0}},nodejs_file_system={open:function(w,S,y){var F=ve("fs"),J=F.openSync(w,y[0]);return y==="read"&&!F.existsSync(w)?null:{get:function(X,Z){var ie=new Buffer(X);return F.readSync(J,ie,0,X,Z),ie.toString()},put:function(X,Z){var ie=Buffer.from(X);if(Z==="end_of_file")F.writeSync(J,ie);else{if(Z==="past_end_of_file")return null;F.writeSync(J,ie,0,ie.length,Z)}return!0},get_byte:function(X){return null},put_byte:function(X,Z){return null},flush:function(){return!0},close:function(){return F.closeSync(J),!0}}}},nodejs_user_input={buffer:"",get:function(w,S){for(var y,F=ime();nodejs_user_input.buffer.length<w;)nodejs_user_input.buffer+=F.question();return y=nodejs_user_input.buffer.substr(0,w),nodejs_user_input.buffer=nodejs_user_input.buffer.substr(w),y}},nodejs_user_output={put:function(w,S){return process.stdout.write(w),!0},flush:function(){return!0}};var e;Array.prototype.indexOf?e=function(w,S){return w.indexOf(S)}:e=function(w,S){for(var y=w.length,F=0;F<y;F++)if(S===w[F])return F;return-1};var r=function(w,S){if(w.length!==0){for(var y=w[0],F=w.length,J=1;J<F;J++)y=S(y,w[J]);return y}},o;Array.prototype.map?o=function(w,S){return w.map(S)}:o=function(w,S){for(var y=[],F=w.length,J=0;J<F;J++)y.push(S(w[J]));return y};var a;Array.prototype.filter?a=function(w,S){return w.filter(S)}:a=function(w,S){for(var y=[],F=w.length,J=0;J<F;J++)S(w[J])&&y.push(w[J]);return y};var n;String.prototype.codePointAt?n=function(w,S){return w.codePointAt(S)}:n=function(w,S){return w.charCodeAt(S)};var u;String.fromCodePoint?u=function(){return String.fromCodePoint.apply(null,arguments)}:u=function(){return String.fromCharCode.apply(null,arguments)};var A=0,p=1,h=/(\\a)|(\\b)|(\\f)|(\\n)|(\\r)|(\\t)|(\\v)|\\x([0-9a-fA-F]+)\\|\\([0-7]+)\\|(\\\\)|(\\')|('')|(\\")|(\\`)|(\\.)|(.)/g,E={"\\a":7,"\\b":8,"\\f":12,"\\n":10,"\\r":13,"\\t":9,"\\v":11};function I(w){var S=[],y=!1;return w.replace(h,function(F,J,X,Z,ie,be,Le,ot,dt,Gt,$t,bt,an,Qr,mr,br,Wr){switch(!0){case dt!==void 0:return S.push(parseInt(dt,16)),"";case Gt!==void 0:return S.push(parseInt(Gt,8)),"";case $t!==void 0:case bt!==void 0:case an!==void 0:case Qr!==void 0:case mr!==void 0:return S.push(n(F.substr(1),0)),"";case Wr!==void 0:return S.push(n(Wr,0)),"";case br!==void 0:y=!0;default:return S.push(E[F]),""}}),y?null:S}function v(w,S){var y="";if(w.length<2)return w;try{w=w.replace(/\\([0-7]+)\\/g,function(Z,ie){return u(parseInt(ie,8))}),w=w.replace(/\\x([0-9a-fA-F]+)\\/g,function(Z,ie){return u(parseInt(ie,16))})}catch{return null}for(var F=0;F<w.length;F++){var J=w.charAt(F),X=w.charAt(F+1);if(J===S&&X===S)F++,y+=S;else if(J==="\\")if(["a","b","f","n","r","t","v","'",'"',"\\","a","\b","\f",`
-`,"\r"," ","\v"].indexOf(X)!==-1)switch(F+=1,X){case"a":y+="a";break;case"b":y+="\b";break;case"f":y+="\f";break;case"n":y+=`
-`;break;case"r":y+="\r";break;case"t":y+=" ";break;case"v":y+="\v";break;case"'":y+="'";break;case'"':y+='"';break;case"\\":y+="\\";break}else return null;else y+=J}return y}function x(w){for(var S="",y=0;y<w.length;y++)switch(w.charAt(y)){case"'":S+="\\'";break;case"\\":S+="\\\\";break;case"\b":S+="\\b";break;case"\f":S+="\\f";break;case`
-`:S+="\\n";break;case"\r":S+="\\r";break;case" ":S+="\\t";break;case"\v":S+="\\v";break;default:S+=w.charAt(y);break}return S}function C(w){var S=w.substr(2);switch(w.substr(0,2).toLowerCase()){case"0x":return parseInt(S,16);case"0b":return parseInt(S,2);case"0o":return parseInt(S,8);case"0'":return I(S)[0];default:return parseFloat(w)}}var R={whitespace:/^\s*(?:(?:%.*)|(?:\/\*(?:\n|\r|.)*?\*\/)|(?:\s+))\s*/,variable:/^(?:[A-Z_][a-zA-Z0-9_]*)/,atom:/^(\!|,|;|[a-z][0-9a-zA-Z_]*|[#\$\&\*\+\-\.\/\:\<\=\>\?\@\^\~\\]+|'(?:[^']*?(?:\\(?:x?\d+)?\\)*(?:'')*(?:\\')*)*')/,number:/^(?:0o[0-7]+|0x[0-9a-fA-F]+|0b[01]+|0'(?:''|\\[abfnrtv\\'"`]|\\x?\d+\\|[^\\])|\d+(?:\.\d+(?:[eE][+-]?\d+)?)?)/,string:/^(?:"([^"]|""|\\")*"|`([^`]|``|\\`)*`)/,l_brace:/^(?:\[)/,r_brace:/^(?:\])/,l_bracket:/^(?:\{)/,r_bracket:/^(?:\})/,bar:/^(?:\|)/,l_paren:/^(?:\()/,r_paren:/^(?:\))/};function N(w,S){return w.get_flag("char_conversion").id==="on"?S.replace(/./g,function(y){return w.get_char_conversion(y)}):S}function U(w){this.thread=w,this.text="",this.tokens=[]}U.prototype.set_last_tokens=function(w){return this.tokens=w},U.prototype.new_text=function(w){this.text=w,this.tokens=[]},U.prototype.get_tokens=function(w){var S,y=0,F=0,J=0,X=[],Z=!1;if(w){var ie=this.tokens[w-1];y=ie.len,S=N(this.thread,this.text.substr(ie.len)),F=ie.line,J=ie.start}else S=this.text;if(/^\s*$/.test(S))return null;for(;S!=="";){var be=[],Le=!1;if(/^\n/.exec(S)!==null){F++,J=0,y++,S=S.replace(/\n/,""),Z=!0;continue}for(var ot in R)if(R.hasOwnProperty(ot)){var dt=R[ot].exec(S);dt&&be.push({value:dt[0],name:ot,matches:dt})}if(!be.length)return this.set_last_tokens([{value:S,matches:[],name:"lexical",line:F,start:J}]);var ie=r(be,function(Qr,mr){return Qr.value.length>=mr.value.length?Qr:mr});switch(ie.start=J,ie.line=F,S=S.replace(ie.value,""),J+=ie.value.length,y+=ie.value.length,ie.name){case"atom":ie.raw=ie.value,ie.value.charAt(0)==="'"&&(ie.value=v(ie.value.substr(1,ie.value.length-2),"'"),ie.value===null&&(ie.name="lexical",ie.value="unknown escape sequence"));break;case"number":ie.float=ie.value.substring(0,2)!=="0x"&&ie.value.match(/[.eE]/)!==null&&ie.value!=="0'.",ie.value=C(ie.value),ie.blank=Le;break;case"string":var Gt=ie.value.charAt(0);ie.value=v(ie.value.substr(1,ie.value.length-2),Gt),ie.value===null&&(ie.name="lexical",ie.value="unknown escape sequence");break;case"whitespace":var $t=X[X.length-1];$t&&($t.space=!0),Le=!0;continue;case"r_bracket":X.length>0&&X[X.length-1].name==="l_bracket"&&(ie=X.pop(),ie.name="atom",ie.value="{}",ie.raw="{}",ie.space=!1);break;case"r_brace":X.length>0&&X[X.length-1].name==="l_brace"&&(ie=X.pop(),ie.name="atom",ie.value="[]",ie.raw="[]",ie.space=!1);break}ie.len=y,X.push(ie),Le=!1}var bt=this.set_last_tokens(X);return bt.length===0?null:bt};function V(w,S,y,F,J){if(!S[y])return{type:A,value:b.error.syntax(S[y-1],"expression expected",!0)};var X;if(F==="0"){var Z=S[y];switch(Z.name){case"number":return{type:p,len:y+1,value:new b.type.Num(Z.value,Z.float)};case"variable":return{type:p,len:y+1,value:new b.type.Var(Z.value)};case"string":var ie;switch(w.get_flag("double_quotes").id){case"atom":ie=new H(Z.value,[]);break;case"codes":ie=new H("[]",[]);for(var be=Z.value.length-1;be>=0;be--)ie=new H(".",[new b.type.Num(n(Z.value,be),!1),ie]);break;case"chars":ie=new H("[]",[]);for(var be=Z.value.length-1;be>=0;be--)ie=new H(".",[new b.type.Term(Z.value.charAt(be),[]),ie]);break}return{type:p,len:y+1,value:ie};case"l_paren":var bt=V(w,S,y+1,w.__get_max_priority(),!0);return bt.type!==p?bt:S[bt.len]&&S[bt.len].name==="r_paren"?(bt.len++,bt):{type:A,derived:!0,value:b.error.syntax(S[bt.len]?S[bt.len]:S[bt.len-1],") or operator expected",!S[bt.len])};case"l_bracket":var bt=V(w,S,y+1,w.__get_max_priority(),!0);return bt.type!==p?bt:S[bt.len]&&S[bt.len].name==="r_bracket"?(bt.len++,bt.value=new H("{}",[bt.value]),bt):{type:A,derived:!0,value:b.error.syntax(S[bt.len]?S[bt.len]:S[bt.len-1],"} or operator expected",!S[bt.len])}}var Le=te(w,S,y,J);return Le.type===p||Le.derived||(Le=ae(w,S,y),Le.type===p||Le.derived)?Le:{type:A,derived:!1,value:b.error.syntax(S[y],"unexpected token")}}var ot=w.__get_max_priority(),dt=w.__get_next_priority(F),Gt=y;if(S[y].name==="atom"&&S[y+1]&&(S[y].space||S[y+1].name!=="l_paren")){var Z=S[y++],$t=w.__lookup_operator_classes(F,Z.value);if($t&&$t.indexOf("fy")>-1){var bt=V(w,S,y,F,J);if(bt.type!==A)return Z.value==="-"&&!Z.space&&b.type.is_number(bt.value)?{value:new b.type.Num(-bt.value.value,bt.value.is_float),len:bt.len,type:p}:{value:new b.type.Term(Z.value,[bt.value]),len:bt.len,type:p};X=bt}else if($t&&$t.indexOf("fx")>-1){var bt=V(w,S,y,dt,J);if(bt.type!==A)return{value:new b.type.Term(Z.value,[bt.value]),len:bt.len,type:p};X=bt}}y=Gt;var bt=V(w,S,y,dt,J);if(bt.type===p){y=bt.len;var Z=S[y];if(S[y]&&(S[y].name==="atom"&&w.__lookup_operator_classes(F,Z.value)||S[y].name==="bar"&&w.__lookup_operator_classes(F,"|"))){var an=dt,Qr=F,$t=w.__lookup_operator_classes(F,Z.value);if($t.indexOf("xf")>-1)return{value:new b.type.Term(Z.value,[bt.value]),len:++bt.len,type:p};if($t.indexOf("xfx")>-1){var mr=V(w,S,y+1,an,J);return mr.type===p?{value:new b.type.Term(Z.value,[bt.value,mr.value]),len:mr.len,type:p}:(mr.derived=!0,mr)}else if($t.indexOf("xfy")>-1){var mr=V(w,S,y+1,Qr,J);return mr.type===p?{value:new b.type.Term(Z.value,[bt.value,mr.value]),len:mr.len,type:p}:(mr.derived=!0,mr)}else if(bt.type!==A)for(;;){y=bt.len;var Z=S[y];if(Z&&Z.name==="atom"&&w.__lookup_operator_classes(F,Z.value)){var $t=w.__lookup_operator_classes(F,Z.value);if($t.indexOf("yf")>-1)bt={value:new b.type.Term(Z.value,[bt.value]),len:++y,type:p};else if($t.indexOf("yfx")>-1){var mr=V(w,S,++y,an,J);if(mr.type===A)return mr.derived=!0,mr;y=mr.len,bt={value:new b.type.Term(Z.value,[bt.value,mr.value]),len:y,type:p}}else break}else break}}else X={type:A,value:b.error.syntax(S[bt.len-1],"operator expected")};return bt}return bt}function te(w,S,y,F){if(!S[y]||S[y].name==="atom"&&S[y].raw==="."&&!F&&(S[y].space||!S[y+1]||S[y+1].name!=="l_paren"))return{type:A,derived:!1,value:b.error.syntax(S[y-1],"unfounded token")};var J=S[y],X=[];if(S[y].name==="atom"&&S[y].raw!==","){if(y++,S[y-1].space)return{type:p,len:y,value:new b.type.Term(J.value,X)};if(S[y]&&S[y].name==="l_paren"){if(S[y+1]&&S[y+1].name==="r_paren")return{type:A,derived:!0,value:b.error.syntax(S[y+1],"argument expected")};var Z=V(w,S,++y,"999",!0);if(Z.type===A)return Z.derived?Z:{type:A,derived:!0,value:b.error.syntax(S[y]?S[y]:S[y-1],"argument expected",!S[y])};for(X.push(Z.value),y=Z.len;S[y]&&S[y].name==="atom"&&S[y].value===",";){if(Z=V(w,S,y+1,"999",!0),Z.type===A)return Z.derived?Z:{type:A,derived:!0,value:b.error.syntax(S[y+1]?S[y+1]:S[y],"argument expected",!S[y+1])};X.push(Z.value),y=Z.len}if(S[y]&&S[y].name==="r_paren")y++;else return{type:A,derived:!0,value:b.error.syntax(S[y]?S[y]:S[y-1],", or ) expected",!S[y])}}return{type:p,len:y,value:new b.type.Term(J.value,X)}}return{type:A,derived:!1,value:b.error.syntax(S[y],"term expected")}}function ae(w,S,y){if(!S[y])return{type:A,derived:!1,value:b.error.syntax(S[y-1],"[ expected")};if(S[y]&&S[y].name==="l_brace"){var F=V(w,S,++y,"999",!0),J=[F.value],X=void 0;if(F.type===A)return S[y]&&S[y].name==="r_brace"?{type:p,len:y+1,value:new b.type.Term("[]",[])}:{type:A,derived:!0,value:b.error.syntax(S[y],"] expected")};for(y=F.len;S[y]&&S[y].name==="atom"&&S[y].value===",";){if(F=V(w,S,y+1,"999",!0),F.type===A)return F.derived?F:{type:A,derived:!0,value:b.error.syntax(S[y+1]?S[y+1]:S[y],"argument expected",!S[y+1])};J.push(F.value),y=F.len}var Z=!1;if(S[y]&&S[y].name==="bar"){if(Z=!0,F=V(w,S,y+1,"999",!0),F.type===A)return F.derived?F:{type:A,derived:!0,value:b.error.syntax(S[y+1]?S[y+1]:S[y],"argument expected",!S[y+1])};X=F.value,y=F.len}return S[y]&&S[y].name==="r_brace"?{type:p,len:y+1,value:g(J,X)}:{type:A,derived:!0,value:b.error.syntax(S[y]?S[y]:S[y-1],Z?"] expected":", or | or ] expected",!S[y])}}return{type:A,derived:!1,value:b.error.syntax(S[y],"list expected")}}function fe(w,S,y){var F=S[y].line,J=V(w,S,y,w.__get_max_priority(),!1),X=null,Z;if(J.type!==A)if(y=J.len,S[y]&&S[y].name==="atom"&&S[y].raw===".")if(y++,b.type.is_term(J.value)){if(J.value.indicator===":-/2"?(X=new b.type.Rule(J.value.args[0],we(J.value.args[1])),Z={value:X,len:y,type:p}):J.value.indicator==="-->/2"?(X=he(new b.type.Rule(J.value.args[0],J.value.args[1]),w),X.body=we(X.body),Z={value:X,len:y,type:b.type.is_rule(X)?p:A}):(X=new b.type.Rule(J.value,null),Z={value:X,len:y,type:p}),X){var ie=X.singleton_variables();ie.length>0&&w.throw_warning(b.warning.singleton(ie,X.head.indicator,F))}return Z}else return{type:A,value:b.error.syntax(S[y],"callable expected")};else return{type:A,value:b.error.syntax(S[y]?S[y]:S[y-1],". or operator expected")};return J}function ue(w,S,y){y=y||{},y.from=y.from?y.from:"$tau-js",y.reconsult=y.reconsult!==void 0?y.reconsult:!0;var F=new U(w),J={},X;F.new_text(S);var Z=0,ie=F.get_tokens(Z);do{if(ie===null||!ie[Z])break;var be=fe(w,ie,Z);if(be.type===A)return new H("throw",[be.value]);if(be.value.body===null&&be.value.head.indicator==="?-/1"){var Le=new Ve(w.session);Le.add_goal(be.value.head.args[0]),Le.answer(function(dt){b.type.is_error(dt)?w.throw_warning(dt.args[0]):(dt===!1||dt===null)&&w.throw_warning(b.warning.failed_goal(be.value.head.args[0],be.len))}),Z=be.len;var ot=!0}else if(be.value.body===null&&be.value.head.indicator===":-/1"){var ot=w.run_directive(be.value.head.args[0]);Z=be.len,be.value.head.args[0].indicator==="char_conversion/2"&&(ie=F.get_tokens(Z),Z=0)}else{X=be.value.head.indicator,y.reconsult!==!1&&J[X]!==!0&&!w.is_multifile_predicate(X)&&(w.session.rules[X]=a(w.session.rules[X]||[],function(Gt){return Gt.dynamic}),J[X]=!0);var ot=w.add_rule(be.value,y);Z=be.len}if(!ot)return ot}while(!0);return!0}function me(w,S){var y=new U(w);y.new_text(S);var F=0;do{var J=y.get_tokens(F);if(J===null)break;var X=V(w,J,0,w.__get_max_priority(),!1);if(X.type!==A){var Z=X.len,ie=Z;if(J[Z]&&J[Z].name==="atom"&&J[Z].raw===".")w.add_goal(we(X.value));else{var be=J[Z];return new H("throw",[b.error.syntax(be||J[Z-1],". or operator expected",!be)])}F=X.len+1}else return new H("throw",[X.value])}while(!0);return!0}function he(w,S){w=w.rename(S);var y=S.next_free_variable(),F=Be(w.body,y,S);return F.error?F.value:(w.body=F.value,w.head.args=w.head.args.concat([y,F.variable]),w.head=new H(w.head.id,w.head.args),w)}function Be(w,S,y){var F;if(b.type.is_term(w)&&w.indicator==="!/0")return{value:w,variable:S,error:!1};if(b.type.is_term(w)&&w.indicator===",/2"){var J=Be(w.args[0],S,y);if(J.error)return J;var X=Be(w.args[1],J.variable,y);return X.error?X:{value:new H(",",[J.value,X.value]),variable:X.variable,error:!1}}else{if(b.type.is_term(w)&&w.indicator==="{}/1")return{value:w.args[0],variable:S,error:!1};if(b.type.is_empty_list(w))return{value:new H("true",[]),variable:S,error:!1};if(b.type.is_list(w)){F=y.next_free_variable();for(var Z=w,ie;Z.indicator==="./2";)ie=Z,Z=Z.args[1];return b.type.is_variable(Z)?{value:b.error.instantiation("DCG"),variable:S,error:!0}:b.type.is_empty_list(Z)?(ie.args[1]=F,{value:new H("=",[S,w]),variable:F,error:!1}):{value:b.error.type("list",w,"DCG"),variable:S,error:!0}}else return b.type.is_callable(w)?(F=y.next_free_variable(),w.args=w.args.concat([S,F]),w=new H(w.id,w.args),{value:w,variable:F,error:!1}):{value:b.error.type("callable",w,"DCG"),variable:S,error:!0}}}function we(w){return b.type.is_variable(w)?new H("call",[w]):b.type.is_term(w)&&[",/2",";/2","->/2"].indexOf(w.indicator)!==-1?new H(w.id,[we(w.args[0]),we(w.args[1])]):w}function g(w,S){for(var y=S||new b.type.Term("[]",[]),F=w.length-1;F>=0;F--)y=new b.type.Term(".",[w[F],y]);return y}function Ee(w,S){for(var y=w.length-1;y>=0;y--)w[y]===S&&w.splice(y,1)}function Pe(w){for(var S={},y=[],F=0;F<w.length;F++)w[F]in S||(y.push(w[F]),S[w[F]]=!0);return y}function ce(w,S,y,F){if(w.session.rules[y]!==null){for(var J=0;J<w.session.rules[y].length;J++)if(w.session.rules[y][J]===F){w.session.rules[y].splice(J,1),w.success(S);break}}}function ne(w){return function(S,y,F){var J=F.args[0],X=F.args.slice(1,w);if(b.type.is_variable(J))S.throw_error(b.error.instantiation(S.level));else if(!b.type.is_callable(J))S.throw_error(b.error.type("callable",J,S.level));else{var Z=new H(J.id,J.args.concat(X));S.prepend([new xe(y.goal.replace(Z),y.substitution,y)])}}}function ee(w){for(var S=w.length-1;S>=0;S--)if(w.charAt(S)==="/")return new H("/",[new H(w.substring(0,S)),new Fe(parseInt(w.substring(S+1)),!1)])}function Ie(w){this.id=w}function Fe(w,S){this.is_float=S!==void 0?S:parseInt(w)!==w,this.value=this.is_float?w:parseInt(w)}var At=0;function H(w,S,y){this.ref=y||++At,this.id=w,this.args=S||[],this.indicator=w+"/"+this.args.length}var at=0;function Re(w,S,y,F,J,X){this.id=at++,this.stream=w,this.mode=S,this.alias=y,this.type=F!==void 0?F:"text",this.reposition=J!==void 0?J:!0,this.eof_action=X!==void 0?X:"eof_code",this.position=this.mode==="append"?"end_of_stream":0,this.output=this.mode==="write"||this.mode==="append",this.input=this.mode==="read"}function ke(w){w=w||{},this.links=w}function xe(w,S,y){S=S||new ke,y=y||null,this.goal=w,this.substitution=S,this.parent=y}function He(w,S,y){this.head=w,this.body=S,this.dynamic=y||!1}function Te(w){w=w===void 0||w<=0?1e3:w,this.rules={},this.src_predicates={},this.rename=0,this.modules=[],this.thread=new Ve(this),this.total_threads=1,this.renamed_variables={},this.public_predicates={},this.multifile_predicates={},this.limit=w,this.streams={user_input:new Re(typeof gl<"u"&&gl.exports?nodejs_user_input:tau_user_input,"read","user_input","text",!1,"reset"),user_output:new Re(typeof gl<"u"&&gl.exports?nodejs_user_output:tau_user_output,"write","user_output","text",!1,"eof_code")},this.file_system=typeof gl<"u"&&gl.exports?nodejs_file_system:tau_file_system,this.standard_input=this.streams.user_input,this.standard_output=this.streams.user_output,this.current_input=this.streams.user_input,this.current_output=this.streams.user_output,this.format_success=function(S){return S.substitution},this.format_error=function(S){return S.goal},this.flag={bounded:b.flag.bounded.value,max_integer:b.flag.max_integer.value,min_integer:b.flag.min_integer.value,integer_rounding_function:b.flag.integer_rounding_function.value,char_conversion:b.flag.char_conversion.value,debug:b.flag.debug.value,max_arity:b.flag.max_arity.value,unknown:b.flag.unknown.value,double_quotes:b.flag.double_quotes.value,occurs_check:b.flag.occurs_check.value,dialect:b.flag.dialect.value,version_data:b.flag.version_data.value,nodejs:b.flag.nodejs.value},this.__loaded_modules=[],this.__char_conversion={},this.__operators={1200:{":-":["fx","xfx"],"-->":["xfx"],"?-":["fx"]},1100:{";":["xfy"]},1050:{"->":["xfy"]},1e3:{",":["xfy"]},900:{"\\+":["fy"]},700:{"=":["xfx"],"\\=":["xfx"],"==":["xfx"],"\\==":["xfx"],"@<":["xfx"],"@=<":["xfx"],"@>":["xfx"],"@>=":["xfx"],"=..":["xfx"],is:["xfx"],"=:=":["xfx"],"=\\=":["xfx"],"<":["xfx"],"=<":["xfx"],">":["xfx"],">=":["xfx"]},600:{":":["xfy"]},500:{"+":["yfx"],"-":["yfx"],"/\\":["yfx"],"\\/":["yfx"]},400:{"*":["yfx"],"/":["yfx"],"//":["yfx"],rem:["yfx"],mod:["yfx"],"<<":["yfx"],">>":["yfx"]},200:{"**":["xfx"],"^":["xfy"],"-":["fy"],"+":["fy"],"\\":["fy"]}}}function Ve(w){this.epoch=Date.now(),this.session=w,this.session.total_threads++,this.total_steps=0,this.cpu_time=0,this.cpu_time_last=0,this.points=[],this.debugger=!1,this.debugger_states=[],this.level="top_level/0",this.__calls=[],this.current_limit=this.session.limit,this.warnings=[]}function qe(w,S,y){this.id=w,this.rules=S,this.exports=y,b.module[w]=this}qe.prototype.exports_predicate=function(w){return this.exports.indexOf(w)!==-1},Ie.prototype.unify=function(w,S){if(S&&e(w.variables(),this.id)!==-1&&!b.type.is_variable(w))return null;var y={};return y[this.id]=w,new ke(y)},Fe.prototype.unify=function(w,S){return b.type.is_number(w)&&this.value===w.value&&this.is_float===w.is_float?new ke:null},H.prototype.unify=function(w,S){if(b.type.is_term(w)&&this.indicator===w.indicator){for(var y=new ke,F=0;F<this.args.length;F++){var J=b.unify(this.args[F].apply(y),w.args[F].apply(y),S);if(J===null)return null;for(var X in J.links)y.links[X]=J.links[X];y=y.apply(J)}return y}return null},Re.prototype.unify=function(w,S){return b.type.is_stream(w)&&this.id===w.id?new ke:null},Ie.prototype.toString=function(w){return this.id},Fe.prototype.toString=function(w){return this.is_float&&e(this.value.toString(),".")===-1?this.value+".0":this.value.toString()},H.prototype.toString=function(w,S,y){if(w=w||{},w.quoted=w.quoted===void 0?!0:w.quoted,w.ignore_ops=w.ignore_ops===void 0?!1:w.ignore_ops,w.numbervars=w.numbervars===void 0?!1:w.numbervars,S=S===void 0?1200:S,y=y===void 0?"":y,w.numbervars&&this.indicator==="$VAR/1"&&b.type.is_integer(this.args[0])&&this.args[0].value>=0){var F=this.args[0].value,J=Math.floor(F/26),X=F%26;return"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[X]+(J!==0?J:"")}switch(this.indicator){case"[]/0":case"{}/0":case"!/0":return this.id;case"{}/1":return"{"+this.args[0].toString(w)+"}";case"./2":for(var Z="["+this.args[0].toString(w),ie=this.args[1];ie.indicator==="./2";)Z+=", "+ie.args[0].toString(w),ie=ie.args[1];return ie.indicator!=="[]/0"&&(Z+="|"+ie.toString(w)),Z+="]",Z;case",/2":return"("+this.args[0].toString(w)+", "+this.args[1].toString(w)+")";default:var be=this.id,Le=w.session?w.session.lookup_operator(this.id,this.args.length):null;if(w.session===void 0||w.ignore_ops||Le===null)return w.quoted&&!/^(!|,|;|[a-z][0-9a-zA-Z_]*)$/.test(be)&&be!=="{}"&&be!=="[]"&&(be="'"+x(be)+"'"),be+(this.args.length?"("+o(this.args,function($t){return $t.toString(w)}).join(", ")+")":"");var ot=Le.priority>S.priority||Le.priority===S.priority&&(Le.class==="xfy"&&this.indicator!==S.indicator||Le.class==="yfx"&&this.indicator!==S.indicator||this.indicator===S.indicator&&Le.class==="yfx"&&y==="right"||this.indicator===S.indicator&&Le.class==="xfy"&&y==="left");Le.indicator=this.indicator;var dt=ot?"(":"",Gt=ot?")":"";return this.args.length===0?"("+this.id+")":["fy","fx"].indexOf(Le.class)!==-1?dt+be+" "+this.args[0].toString(w,Le)+Gt:["yf","xf"].indexOf(Le.class)!==-1?dt+this.args[0].toString(w,Le)+" "+be+Gt:dt+this.args[0].toString(w,Le,"left")+" "+this.id+" "+this.args[1].toString(w,Le,"right")+Gt}},Re.prototype.toString=function(w){return"<stream>("+this.id+")"},ke.prototype.toString=function(w){var S="{";for(var y in this.links)!this.links.hasOwnProperty(y)||(S!=="{"&&(S+=", "),S+=y+"/"+this.links[y].toString(w));return S+="}",S},xe.prototype.toString=function(w){return this.goal===null?"<"+this.substitution.toString(w)+">":"<"+this.goal.toString(w)+", "+this.substitution.toString(w)+">"},He.prototype.toString=function(w){return this.body?this.head.toString(w)+" :- "+this.body.toString(w)+".":this.head.toString(w)+"."},Te.prototype.toString=function(w){for(var S="",y=0;y<this.modules.length;y++)S+=":- use_module(library("+this.modules[y]+`)).
-`;S+=`
-`;for(key in this.rules)for(y=0;y<this.rules[key].length;y++)S+=this.rules[key][y].toString(w),S+=`
-`;return S},Ie.prototype.clone=function(){return new Ie(this.id)},Fe.prototype.clone=function(){return new Fe(this.value,this.is_float)},H.prototype.clone=function(){return new H(this.id,o(this.args,function(w){return w.clone()}))},Re.prototype.clone=function(){return new Stram(this.stream,this.mode,this.alias,this.type,this.reposition,this.eof_action)},ke.prototype.clone=function(){var w={};for(var S in this.links)!this.links.hasOwnProperty(S)||(w[S]=this.links[S].clone());return new ke(w)},xe.prototype.clone=function(){return new xe(this.goal.clone(),this.substitution.clone(),this.parent)},He.prototype.clone=function(){return new He(this.head.clone(),this.body!==null?this.body.clone():null)},Ie.prototype.equals=function(w){return b.type.is_variable(w)&&this.id===w.id},Fe.prototype.equals=function(w){return b.type.is_number(w)&&this.value===w.value&&this.is_float===w.is_float},H.prototype.equals=function(w){if(!b.type.is_term(w)||this.indicator!==w.indicator)return!1;for(var S=0;S<this.args.length;S++)if(!this.args[S].equals(w.args[S]))return!1;return!0},Re.prototype.equals=function(w){return b.type.is_stream(w)&&this.id===w.id},ke.prototype.equals=function(w){var S;if(!b.type.is_substitution(w))return!1;for(S in this.links)if(!!this.links.hasOwnProperty(S)&&(!w.links[S]||!this.links[S].equals(w.links[S])))return!1;for(S in w.links)if(!!w.links.hasOwnProperty(S)&&!this.links[S])return!1;return!0},xe.prototype.equals=function(w){return b.type.is_state(w)&&this.goal.equals(w.goal)&&this.substitution.equals(w.substitution)&&this.parent===w.parent},He.prototype.equals=function(w){return b.type.is_rule(w)&&this.head.equals(w.head)&&(this.body===null&&w.body===null||this.body!==null&&this.body.equals(w.body))},Ie.prototype.rename=function(w){return w.get_free_variable(this)},Fe.prototype.rename=function(w){return this},H.prototype.rename=function(w){return new H(this.id,o(this.args,function(S){return S.rename(w)}))},Re.prototype.rename=function(w){return this},He.prototype.rename=function(w){return new He(this.head.rename(w),this.body!==null?this.body.rename(w):null)},Ie.prototype.variables=function(){return[this.id]},Fe.prototype.variables=function(){return[]},H.prototype.variables=function(){return[].concat.apply([],o(this.args,function(w){return w.variables()}))},Re.prototype.variables=function(){return[]},He.prototype.variables=function(){return this.body===null?this.head.variables():this.head.variables().concat(this.body.variables())},Ie.prototype.apply=function(w){return w.lookup(this.id)?w.lookup(this.id):this},Fe.prototype.apply=function(w){return this},H.prototype.apply=function(w){if(this.indicator==="./2"){for(var S=[],y=this;y.indicator==="./2";)S.push(y.args[0].apply(w)),y=y.args[1];for(var F=y.apply(w),J=S.length-1;J>=0;J--)F=new H(".",[S[J],F]);return F}return new H(this.id,o(this.args,function(X){return X.apply(w)}),this.ref)},Re.prototype.apply=function(w){return this},He.prototype.apply=function(w){return new He(this.head.apply(w),this.body!==null?this.body.apply(w):null)},ke.prototype.apply=function(w){var S,y={};for(S in this.links)!this.links.hasOwnProperty(S)||(y[S]=this.links[S].apply(w));return new ke(y)},H.prototype.select=function(){for(var w=this;w.indicator===",/2";)w=w.args[0];return w},H.prototype.replace=function(w){return this.indicator===",/2"?this.args[0].indicator===",/2"?new H(",",[this.args[0].replace(w),this.args[1]]):w===null?this.args[1]:new H(",",[w,this.args[1]]):w},H.prototype.search=function(w){if(b.type.is_term(w)&&w.ref!==void 0&&this.ref===w.ref)return!0;for(var S=0;S<this.args.length;S++)if(b.type.is_term(this.args[S])&&this.args[S].search(w))return!0;return!1},Te.prototype.get_current_input=function(){return this.current_input},Ve.prototype.get_current_input=function(){return this.session.get_current_input()},Te.prototype.get_current_output=function(){return this.current_output},Ve.prototype.get_current_output=function(){return this.session.get_current_output()},Te.prototype.set_current_input=function(w){this.current_input=w},Ve.prototype.set_current_input=function(w){return this.session.set_current_input(w)},Te.prototype.set_current_output=function(w){this.current_input=w},Ve.prototype.set_current_output=function(w){return this.session.set_current_output(w)},Te.prototype.get_stream_by_alias=function(w){return this.streams[w]},Ve.prototype.get_stream_by_alias=function(w){return this.session.get_stream_by_alias(w)},Te.prototype.file_system_open=function(w,S,y){return this.file_system.open(w,S,y)},Ve.prototype.file_system_open=function(w,S,y){return this.session.file_system_open(w,S,y)},Te.prototype.get_char_conversion=function(w){return this.__char_conversion[w]||w},Ve.prototype.get_char_conversion=function(w){return this.session.get_char_conversion(w)},Te.prototype.parse=function(w){return this.thread.parse(w)},Ve.prototype.parse=function(w){var S=new U(this);S.new_text(w);var y=S.get_tokens();if(y===null)return!1;var F=V(this,y,0,this.__get_max_priority(),!1);return F.len!==y.length?!1:{value:F.value,expr:F,tokens:y}},Te.prototype.get_flag=function(w){return this.flag[w]},Ve.prototype.get_flag=function(w){return this.session.get_flag(w)},Te.prototype.add_rule=function(w,S){return S=S||{},S.from=S.from?S.from:"$tau-js",this.src_predicates[w.head.indicator]=S.from,this.rules[w.head.indicator]||(this.rules[w.head.indicator]=[]),this.rules[w.head.indicator].push(w),this.public_predicates.hasOwnProperty(w.head.indicator)||(this.public_predicates[w.head.indicator]=!1),!0},Ve.prototype.add_rule=function(w,S){return this.session.add_rule(w,S)},Te.prototype.run_directive=function(w){this.thread.run_directive(w)},Ve.prototype.run_directive=function(w){return b.type.is_directive(w)?(b.directive[w.indicator](this,w),!0):!1},Te.prototype.__get_max_priority=function(){return"1200"},Ve.prototype.__get_max_priority=function(){return this.session.__get_max_priority()},Te.prototype.__get_next_priority=function(w){var S=0;w=parseInt(w);for(var y in this.__operators)if(!!this.__operators.hasOwnProperty(y)){var F=parseInt(y);F>S&&F<w&&(S=F)}return S.toString()},Ve.prototype.__get_next_priority=function(w){return this.session.__get_next_priority(w)},Te.prototype.__lookup_operator_classes=function(w,S){return this.__operators.hasOwnProperty(w)&&this.__operators[w][S]instanceof Array&&this.__operators[w][S]||!1},Ve.prototype.__lookup_operator_classes=function(w,S){return this.session.__lookup_operator_classes(w,S)},Te.prototype.lookup_operator=function(w,S){for(var y in this.__operators)if(this.__operators[y][w]){for(var F=0;F<this.__operators[y][w].length;F++)if(S===0||this.__operators[y][w][F].length===S+1)return{priority:y,class:this.__operators[y][w][F]}}return null},Ve.prototype.lookup_operator=function(w,S){return this.session.lookup_operator(w,S)},Te.prototype.throw_warning=function(w){this.thread.throw_warning(w)},Ve.prototype.throw_warning=function(w){this.warnings.push(w)},Te.prototype.get_warnings=function(){return this.thread.get_warnings()},Ve.prototype.get_warnings=function(){return this.warnings},Te.prototype.add_goal=function(w,S){this.thread.add_goal(w,S)},Ve.prototype.add_goal=function(w,S,y){y=y||null,S===!0&&(this.points=[]);for(var F=w.variables(),J={},X=0;X<F.length;X++)J[F[X]]=new Ie(F[X]);this.points.push(new xe(w,new ke(J),y))},Te.prototype.consult=function(w,S){return this.thread.consult(w,S)},Ve.prototype.consult=function(w,S){var y="";if(typeof w=="string"){y=w;var F=y.length;if(y.substring(F-3,F)===".pl"&&document.getElementById(y)){var J=document.getElementById(y),X=J.getAttribute("type");X!==null&&X.replace(/ /g,"").toLowerCase()==="text/prolog"&&(y=J.text)}}else if(w.nodeName)switch(w.nodeName.toLowerCase()){case"input":case"textarea":y=w.value;break;default:y=w.innerHTML;break}else return!1;return this.warnings=[],ue(this,y,S)},Te.prototype.query=function(w){return this.thread.query(w)},Ve.prototype.query=function(w){return this.points=[],this.debugger_points=[],me(this,w)},Te.prototype.head_point=function(){return this.thread.head_point()},Ve.prototype.head_point=function(){return this.points[this.points.length-1]},Te.prototype.get_free_variable=function(w){return this.thread.get_free_variable(w)},Ve.prototype.get_free_variable=function(w){var S=[];if(w.id==="_"||this.session.renamed_variables[w.id]===void 0){for(this.session.rename++,this.points.length>0&&(S=this.head_point().substitution.domain());e(S,b.format_variable(this.session.rename))!==-1;)this.session.rename++;if(w.id==="_")return new Ie(b.format_variable(this.session.rename));this.session.renamed_variables[w.id]=b.format_variable(this.session.rename)}return new Ie(this.session.renamed_variables[w.id])},Te.prototype.next_free_variable=function(){return this.thread.next_free_variable()},Ve.prototype.next_free_variable=function(){this.session.rename++;var w=[];for(this.points.length>0&&(w=this.head_point().substitution.domain());e(w,b.format_variable(this.session.rename))!==-1;)this.session.rename++;return new Ie(b.format_variable(this.session.rename))},Te.prototype.is_public_predicate=function(w){return!this.public_predicates.hasOwnProperty(w)||this.public_predicates[w]===!0},Ve.prototype.is_public_predicate=function(w){return this.session.is_public_predicate(w)},Te.prototype.is_multifile_predicate=function(w){return this.multifile_predicates.hasOwnProperty(w)&&this.multifile_predicates[w]===!0},Ve.prototype.is_multifile_predicate=function(w){return this.session.is_multifile_predicate(w)},Te.prototype.prepend=function(w){return this.thread.prepend(w)},Ve.prototype.prepend=function(w){for(var S=w.length-1;S>=0;S--)this.points.push(w[S])},Te.prototype.success=function(w,S){return this.thread.success(w,S)},Ve.prototype.success=function(w,y){var y=typeof y>"u"?w:y;this.prepend([new xe(w.goal.replace(null),w.substitution,y)])},Te.prototype.throw_error=function(w){return this.thread.throw_error(w)},Ve.prototype.throw_error=function(w){this.prepend([new xe(new H("throw",[w]),new ke,null,null)])},Te.prototype.step_rule=function(w,S){return this.thread.step_rule(w,S)},Ve.prototype.step_rule=function(w,S){var y=S.indicator;if(w==="user"&&(w=null),w===null&&this.session.rules.hasOwnProperty(y))return this.session.rules[y];for(var F=w===null?this.session.modules:e(this.session.modules,w)===-1?[]:[w],J=0;J<F.length;J++){var X=b.module[F[J]];if(X.rules.hasOwnProperty(y)&&(X.rules.hasOwnProperty(this.level)||X.exports_predicate(y)))return b.module[F[J]].rules[y]}return null},Te.prototype.step=function(){return this.thread.step()},Ve.prototype.step=function(){if(this.points.length!==0){var w=!1,S=this.points.pop();if(this.debugger&&this.debugger_states.push(S),b.type.is_term(S.goal)){var y=S.goal.select(),F=null,J=[];if(y!==null){this.total_steps++;for(var X=S;X.parent!==null&&X.parent.goal.search(y);)X=X.parent;if(this.level=X.parent===null?"top_level/0":X.parent.goal.select().indicator,b.type.is_term(y)&&y.indicator===":/2"&&(F=y.args[0].id,y=y.args[1]),F===null&&b.type.is_builtin(y))this.__call_indicator=y.indicator,w=b.predicate[y.indicator](this,S,y);else{var Z=this.step_rule(F,y);if(Z===null)this.session.rules.hasOwnProperty(y.indicator)||(this.get_flag("unknown").id==="error"?this.throw_error(b.error.existence("procedure",y.indicator,this.level)):this.get_flag("unknown").id==="warning"&&this.throw_warning("unknown procedure "+y.indicator+" (from "+this.level+")"));else if(Z instanceof Function)w=Z(this,S,y);else{for(var ie in Z)if(!!Z.hasOwnProperty(ie)){var be=Z[ie];this.session.renamed_variables={},be=be.rename(this);var Le=this.get_flag("occurs_check").indicator==="true/0",ot=new xe,dt=b.unify(y,be.head,Le);dt!==null&&(ot.goal=S.goal.replace(be.body),ot.goal!==null&&(ot.goal=ot.goal.apply(dt)),ot.substitution=S.substitution.apply(dt),ot.parent=S,J.push(ot))}this.prepend(J)}}}}else b.type.is_variable(S.goal)?this.throw_error(b.error.instantiation(this.level)):this.throw_error(b.error.type("callable",S.goal,this.level));return w}},Te.prototype.answer=function(w){return this.thread.answer(w)},Ve.prototype.answer=function(w){w=w||function(S){},this.__calls.push(w),!(this.__calls.length>1)&&this.again()},Te.prototype.answers=function(w,S,y){return this.thread.answers(w,S,y)},Ve.prototype.answers=function(w,S,y){var F=S||1e3,J=this;if(S<=0){y&&y();return}this.answer(function(X){w(X),X!==!1?setTimeout(function(){J.answers(w,S-1,y)},1):y&&y()})},Te.prototype.again=function(w){return this.thread.again(w)},Ve.prototype.again=function(w){for(var S,y=Date.now();this.__calls.length>0;){for(this.warnings=[],w!==!1&&(this.current_limit=this.session.limit);this.current_limit>0&&this.points.length>0&&this.head_point().goal!==null&&!b.type.is_error(this.head_point().goal);)if(this.current_limit--,this.step()===!0)return;var F=Date.now();this.cpu_time_last=F-y,this.cpu_time+=this.cpu_time_last;var J=this.__calls.shift();this.current_limit<=0?J(null):this.points.length===0?J(!1):b.type.is_error(this.head_point().goal)?(S=this.session.format_error(this.points.pop()),this.points=[],J(S)):(this.debugger&&this.debugger_states.push(this.head_point()),S=this.session.format_success(this.points.pop()),J(S))}},Te.prototype.unfold=function(w){if(w.body===null)return!1;var S=w.head,y=w.body,F=y.select(),J=new Ve(this),X=[];J.add_goal(F),J.step();for(var Z=J.points.length-1;Z>=0;Z--){var ie=J.points[Z],be=S.apply(ie.substitution),Le=y.replace(ie.goal);Le!==null&&(Le=Le.apply(ie.substitution)),X.push(new He(be,Le))}var ot=this.rules[S.indicator],dt=e(ot,w);return X.length>0&&dt!==-1?(ot.splice.apply(ot,[dt,1].concat(X)),!0):!1},Ve.prototype.unfold=function(w){return this.session.unfold(w)},Ie.prototype.interpret=function(w){return b.error.instantiation(w.level)},Fe.prototype.interpret=function(w){return this},H.prototype.interpret=function(w){return b.type.is_unitary_list(this)?this.args[0].interpret(w):b.operate(w,this)},Ie.prototype.compare=function(w){return this.id<w.id?-1:this.id>w.id?1:0},Fe.prototype.compare=function(w){if(this.value===w.value&&this.is_float===w.is_float)return 0;if(this.value<w.value||this.value===w.value&&this.is_float&&!w.is_float)return-1;if(this.value>w.value)return 1},H.prototype.compare=function(w){if(this.args.length<w.args.length||this.args.length===w.args.length&&this.id<w.id)return-1;if(this.args.length>w.args.length||this.args.length===w.args.length&&this.id>w.id)return 1;for(var S=0;S<this.args.length;S++){var y=b.compare(this.args[S],w.args[S]);if(y!==0)return y}return 0},ke.prototype.lookup=function(w){return this.links[w]?this.links[w]:null},ke.prototype.filter=function(w){var S={};for(var y in this.links)if(!!this.links.hasOwnProperty(y)){var F=this.links[y];w(y,F)&&(S[y]=F)}return new ke(S)},ke.prototype.exclude=function(w){var S={};for(var y in this.links)!this.links.hasOwnProperty(y)||e(w,y)===-1&&(S[y]=this.links[y]);return new ke(S)},ke.prototype.add=function(w,S){this.links[w]=S},ke.prototype.domain=function(w){var S=w===!0?function(J){return J}:function(J){return new Ie(J)},y=[];for(var F in this.links)y.push(S(F));return y},Ie.prototype.compile=function(){return'new pl.type.Var("'+this.id.toString()+'")'},Fe.prototype.compile=function(){return"new pl.type.Num("+this.value.toString()+", "+this.is_float.toString()+")"},H.prototype.compile=function(){return'new pl.type.Term("'+this.id.replace(/"/g,'\\"')+'", ['+o(this.args,function(w){return w.compile()})+"])"},He.prototype.compile=function(){return"new pl.type.Rule("+this.head.compile()+", "+(this.body===null?"null":this.body.compile())+")"},Te.prototype.compile=function(){var w,S=[],y;for(var F in this.rules)if(!!this.rules.hasOwnProperty(F)){var J=this.rules[F];y=[],w='"'+F+'": [';for(var X=0;X<J.length;X++)y.push(J[X].compile());w+=y.join(),w+="]",S.push(w)}return"{"+S.join()+"};"},Ie.prototype.toJavaScript=function(){},Fe.prototype.toJavaScript=function(){return this.value},H.prototype.toJavaScript=function(){if(this.args.length===0&&this.indicator!=="[]/0")return this.id;if(b.type.is_list(this)){for(var w=[],S=this,y;S.indicator==="./2";){if(y=S.args[0].toJavaScript(),y===void 0)return;w.push(y),S=S.args[1]}if(S.indicator==="[]/0")return w}},He.prototype.singleton_variables=function(){var w=this.head.variables(),S={},y=[];this.body!==null&&(w=w.concat(this.body.variables()));for(var F=0;F<w.length;F++)S[w[F]]===void 0&&(S[w[F]]=0),S[w[F]]++;for(var J in S)J!=="_"&&S[J]===1&&y.push(J);return y};var b={__env:typeof gl<"u"&&gl.exports?global:window,module:{},version:t,parser:{tokenizer:U,expression:V},utils:{str_indicator:ee,codePointAt:n,fromCodePoint:u},statistics:{getCountTerms:function(){return At}},fromJavaScript:{test:{boolean:function(w){return w===!0||w===!1},number:function(w){return typeof w=="number"},string:function(w){return typeof w=="string"},list:function(w){return w instanceof Array},variable:function(w){return w===void 0},any:function(w){return!0}},conversion:{boolean:function(w){return new H(w?"true":"false",[])},number:function(w){return new Fe(w,w%1!==0)},string:function(w){return new H(w,[])},list:function(w){for(var S=[],y,F=0;F<w.length;F++){if(y=b.fromJavaScript.apply(w[F]),y===void 0)return;S.push(y)}return g(S)},variable:function(w){return new Ie("_")},any:function(w){}},apply:function(w){for(var S in b.fromJavaScript.test)if(S!=="any"&&b.fromJavaScript.test[S](w))return b.fromJavaScript.conversion[S](w);return b.fromJavaScript.conversion.any(w)}},type:{Var:Ie,Num:Fe,Term:H,Rule:He,State:xe,Stream:Re,Module:qe,Thread:Ve,Session:Te,Substitution:ke,order:[Ie,Fe,H,Re],compare:function(w,S){var y=e(b.type.order,w.constructor),F=e(b.type.order,S.constructor);if(y<F)return-1;if(y>F)return 1;if(w.constructor===Fe){if(w.is_float&&S.is_float)return 0;if(w.is_float)return-1;if(S.is_float)return 1}return 0},is_substitution:function(w){return w instanceof ke},is_state:function(w){return w instanceof xe},is_rule:function(w){return w instanceof He},is_variable:function(w){return w instanceof Ie},is_stream:function(w){return w instanceof Re},is_anonymous_var:function(w){return w instanceof Ie&&w.id==="_"},is_callable:function(w){return w instanceof H},is_number:function(w){return w instanceof Fe},is_integer:function(w){return w instanceof Fe&&!w.is_float},is_float:function(w){return w instanceof Fe&&w.is_float},is_term:function(w){return w instanceof H},is_atom:function(w){return w instanceof H&&w.args.length===0},is_ground:function(w){if(w instanceof Ie)return!1;if(w instanceof H){for(var S=0;S<w.args.length;S++)if(!b.type.is_ground(w.args[S]))return!1}return!0},is_atomic:function(w){return w instanceof H&&w.args.length===0||w instanceof Fe},is_compound:function(w){return w instanceof H&&w.args.length>0},is_list:function(w){return w instanceof H&&(w.indicator==="[]/0"||w.indicator==="./2")},is_empty_list:function(w){return w instanceof H&&w.indicator==="[]/0"},is_non_empty_list:function(w){return w instanceof H&&w.indicator==="./2"},is_fully_list:function(w){for(;w instanceof H&&w.indicator==="./2";)w=w.args[1];return w instanceof Ie||w instanceof H&&w.indicator==="[]/0"},is_instantiated_list:function(w){for(;w instanceof H&&w.indicator==="./2";)w=w.args[1];return w instanceof H&&w.indicator==="[]/0"},is_unitary_list:function(w){return w instanceof H&&w.indicator==="./2"&&w.args[1]instanceof H&&w.args[1].indicator==="[]/0"},is_character:function(w){return w instanceof H&&(w.id.length===1||w.id.length>0&&w.id.length<=2&&n(w.id,0)>=65536)},is_character_code:function(w){return w instanceof Fe&&!w.is_float&&w.value>=0&&w.value<=1114111},is_byte:function(w){return w instanceof Fe&&!w.is_float&&w.value>=0&&w.value<=255},is_operator:function(w){return w instanceof H&&b.arithmetic.evaluation[w.indicator]},is_directive:function(w){return w instanceof H&&b.directive[w.indicator]!==void 0},is_builtin:function(w){return w instanceof H&&b.predicate[w.indicator]!==void 0},is_error:function(w){return w instanceof H&&w.indicator==="throw/1"},is_predicate_indicator:function(w){return w instanceof H&&w.indicator==="//2"&&w.args[0]instanceof H&&w.args[0].args.length===0&&w.args[1]instanceof Fe&&w.args[1].is_float===!1},is_flag:function(w){return w instanceof H&&w.args.length===0&&b.flag[w.id]!==void 0},is_value_flag:function(w,S){if(!b.type.is_flag(w))return!1;for(var y in b.flag[w.id].allowed)if(!!b.flag[w.id].allowed.hasOwnProperty(y)&&b.flag[w.id].allowed[y].equals(S))return!0;return!1},is_io_mode:function(w){return b.type.is_atom(w)&&["read","write","append"].indexOf(w.id)!==-1},is_stream_option:function(w){return b.type.is_term(w)&&(w.indicator==="alias/1"&&b.type.is_atom(w.args[0])||w.indicator==="reposition/1"&&b.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false")||w.indicator==="type/1"&&b.type.is_atom(w.args[0])&&(w.args[0].id==="text"||w.args[0].id==="binary")||w.indicator==="eof_action/1"&&b.type.is_atom(w.args[0])&&(w.args[0].id==="error"||w.args[0].id==="eof_code"||w.args[0].id==="reset"))},is_stream_position:function(w){return b.type.is_integer(w)&&w.value>=0||b.type.is_atom(w)&&(w.id==="end_of_stream"||w.id==="past_end_of_stream")},is_stream_property:function(w){return b.type.is_term(w)&&(w.indicator==="input/0"||w.indicator==="output/0"||w.indicator==="alias/1"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0]))||w.indicator==="file_name/1"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0]))||w.indicator==="position/1"&&(b.type.is_variable(w.args[0])||b.type.is_stream_position(w.args[0]))||w.indicator==="reposition/1"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false"))||w.indicator==="type/1"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id==="text"||w.args[0].id==="binary"))||w.indicator==="mode/1"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id==="read"||w.args[0].id==="write"||w.args[0].id==="append"))||w.indicator==="eof_action/1"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id==="error"||w.args[0].id==="eof_code"||w.args[0].id==="reset"))||w.indicator==="end_of_stream/1"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id==="at"||w.args[0].id==="past"||w.args[0].id==="not")))},is_streamable:function(w){return w.__proto__.stream!==void 0},is_read_option:function(w){return b.type.is_term(w)&&["variables/1","variable_names/1","singletons/1"].indexOf(w.indicator)!==-1},is_write_option:function(w){return b.type.is_term(w)&&(w.indicator==="quoted/1"&&b.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false")||w.indicator==="ignore_ops/1"&&b.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false")||w.indicator==="numbervars/1"&&b.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false"))},is_close_option:function(w){return b.type.is_term(w)&&w.indicator==="force/1"&&b.type.is_atom(w.args[0])&&(w.args[0].id==="true"||w.args[0].id==="false")},is_modifiable_flag:function(w){return b.type.is_flag(w)&&b.flag[w.id].changeable},is_module:function(w){return w instanceof H&&w.indicator==="library/1"&&w.args[0]instanceof H&&w.args[0].args.length===0&&b.module[w.args[0].id]!==void 0}},arithmetic:{evaluation:{"e/0":{type_args:null,type_result:!0,fn:function(w){return Math.E}},"pi/0":{type_args:null,type_result:!0,fn:function(w){return Math.PI}},"tau/0":{type_args:null,type_result:!0,fn:function(w){return 2*Math.PI}},"epsilon/0":{type_args:null,type_result:!0,fn:function(w){return Number.EPSILON}},"+/1":{type_args:null,type_result:null,fn:function(w,S){return w}},"-/1":{type_args:null,type_result:null,fn:function(w,S){return-w}},"\\/1":{type_args:!1,type_result:!1,fn:function(w,S){return~w}},"abs/1":{type_args:null,type_result:null,fn:function(w,S){return Math.abs(w)}},"sign/1":{type_args:null,type_result:null,fn:function(w,S){return Math.sign(w)}},"float_integer_part/1":{type_args:!0,type_result:!1,fn:function(w,S){return parseInt(w)}},"float_fractional_part/1":{type_args:!0,type_result:!0,fn:function(w,S){return w-parseInt(w)}},"float/1":{type_args:null,type_result:!0,fn:function(w,S){return parseFloat(w)}},"floor/1":{type_args:!0,type_result:!1,fn:function(w,S){return Math.floor(w)}},"truncate/1":{type_args:!0,type_result:!1,fn:function(w,S){return parseInt(w)}},"round/1":{type_args:!0,type_result:!1,fn:function(w,S){return Math.round(w)}},"ceiling/1":{type_args:!0,type_result:!1,fn:function(w,S){return Math.ceil(w)}},"sin/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.sin(w)}},"cos/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.cos(w)}},"tan/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.tan(w)}},"asin/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.asin(w)}},"acos/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.acos(w)}},"atan/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.atan(w)}},"atan2/2":{type_args:null,type_result:!0,fn:function(w,S,y){return Math.atan2(w,S)}},"exp/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.exp(w)}},"sqrt/1":{type_args:null,type_result:!0,fn:function(w,S){return Math.sqrt(w)}},"log/1":{type_args:null,type_result:!0,fn:function(w,S){return w>0?Math.log(w):b.error.evaluation("undefined",S.__call_indicator)}},"+/2":{type_args:null,type_result:null,fn:function(w,S,y){return w+S}},"-/2":{type_args:null,type_result:null,fn:function(w,S,y){return w-S}},"*/2":{type_args:null,type_result:null,fn:function(w,S,y){return w*S}},"//2":{type_args:null,type_result:!0,fn:function(w,S,y){return S?w/S:b.error.evaluation("zero_division",y.__call_indicator)}},"///2":{type_args:!1,type_result:!1,fn:function(w,S,y){return S?parseInt(w/S):b.error.evaluation("zero_division",y.__call_indicator)}},"**/2":{type_args:null,type_result:!0,fn:function(w,S,y){return Math.pow(w,S)}},"^/2":{type_args:null,type_result:null,fn:function(w,S,y){return Math.pow(w,S)}},"<</2":{type_args:!1,type_result:!1,fn:function(w,S,y){return w<<S}},">>/2":{type_args:!1,type_result:!1,fn:function(w,S,y){return w>>S}},"/\\/2":{type_args:!1,type_result:!1,fn:function(w,S,y){return w&S}},"\\//2":{type_args:!1,type_result:!1,fn:function(w,S,y){return w|S}},"xor/2":{type_args:!1,type_result:!1,fn:function(w,S,y){return w^S}},"rem/2":{type_args:!1,type_result:!1,fn:function(w,S,y){return S?w%S:b.error.evaluation("zero_division",y.__call_indicator)}},"mod/2":{type_args:!1,type_result:!1,fn:function(w,S,y){return S?w-parseInt(w/S)*S:b.error.evaluation("zero_division",y.__call_indicator)}},"max/2":{type_args:null,type_result:null,fn:function(w,S,y){return Math.max(w,S)}},"min/2":{type_args:null,type_result:null,fn:function(w,S,y){return Math.min(w,S)}}}},directive:{"dynamic/1":function(w,S){var y=S.args[0];if(b.type.is_variable(y))w.throw_error(b.error.instantiation(S.indicator));else if(!b.type.is_compound(y)||y.indicator!=="//2")w.throw_error(b.error.type("predicate_indicator",y,S.indicator));else if(b.type.is_variable(y.args[0])||b.type.is_variable(y.args[1]))w.throw_error(b.error.instantiation(S.indicator));else if(!b.type.is_atom(y.args[0]))w.throw_error(b.error.type("atom",y.args[0],S.indicator));else if(!b.type.is_integer(y.args[1]))w.throw_error(b.error.type("integer",y.args[1],S.indicator));else{var F=S.args[0].args[0].id+"/"+S.args[0].args[1].value;w.session.public_predicates[F]=!0,w.session.rules[F]||(w.session.rules[F]=[])}},"multifile/1":function(w,S){var y=S.args[0];b.type.is_variable(y)?w.throw_error(b.error.instantiation(S.indicator)):!b.type.is_compound(y)||y.indicator!=="//2"?w.throw_error(b.error.type("predicate_indicator",y,S.indicator)):b.type.is_variable(y.args[0])||b.type.is_variable(y.args[1])?w.throw_error(b.error.instantiation(S.indicator)):b.type.is_atom(y.args[0])?b.type.is_integer(y.args[1])?w.session.multifile_predicates[S.args[0].args[0].id+"/"+S.args[0].args[1].value]=!0:w.throw_error(b.error.type("integer",y.args[1],S.indicator)):w.throw_error(b.error.type("atom",y.args[0],S.indicator))},"set_prolog_flag/2":function(w,S){var y=S.args[0],F=S.args[1];b.type.is_variable(y)||b.type.is_variable(F)?w.throw_error(b.error.instantiation(S.indicator)):b.type.is_atom(y)?b.type.is_flag(y)?b.type.is_value_flag(y,F)?b.type.is_modifiable_flag(y)?w.session.flag[y.id]=F:w.throw_error(b.error.permission("modify","flag",y)):w.throw_error(b.error.domain("flag_value",new H("+",[y,F]),S.indicator)):w.throw_error(b.error.domain("prolog_flag",y,S.indicator)):w.throw_error(b.error.type("atom",y,S.indicator))},"use_module/1":function(w,S){var y=S.args[0];if(b.type.is_variable(y))w.throw_error(b.error.instantiation(S.indicator));else if(!b.type.is_term(y))w.throw_error(b.error.type("term",y,S.indicator));else if(b.type.is_module(y)){var F=y.args[0].id;e(w.session.modules,F)===-1&&w.session.modules.push(F)}},"char_conversion/2":function(w,S){var y=S.args[0],F=S.args[1];b.type.is_variable(y)||b.type.is_variable(F)?w.throw_error(b.error.instantiation(S.indicator)):b.type.is_character(y)?b.type.is_character(F)?y.id===F.id?delete w.session.__char_conversion[y.id]:w.session.__char_conversion[y.id]=F.id:w.throw_error(b.error.type("character",F,S.indicator)):w.throw_error(b.error.type("character",y,S.indicator))},"op/3":function(w,S){var y=S.args[0],F=S.args[1],J=S.args[2];if(b.type.is_variable(y)||b.type.is_variable(F)||b.type.is_variable(J))w.throw_error(b.error.instantiation(S.indicator));else if(!b.type.is_integer(y))w.throw_error(b.error.type("integer",y,S.indicator));else if(!b.type.is_atom(F))w.throw_error(b.error.type("atom",F,S.indicator));else if(!b.type.is_atom(J))w.throw_error(b.error.type("atom",J,S.indicator));else if(y.value<0||y.value>1200)w.throw_error(b.error.domain("operator_priority",y,S.indicator));else if(J.id===",")w.throw_error(b.error.permission("modify","operator",J,S.indicator));else if(J.id==="|"&&(y.value<1001||F.id.length!==3))w.throw_error(b.error.permission("modify","operator",J,S.indicator));else if(["fy","fx","yf","xf","xfx","yfx","xfy"].indexOf(F.id)===-1)w.throw_error(b.error.domain("operator_specifier",F,S.indicator));else{var X={prefix:null,infix:null,postfix:null};for(var Z in w.session.__operators)if(!!w.session.__operators.hasOwnProperty(Z)){var ie=w.session.__operators[Z][J.id];ie&&(e(ie,"fx")!==-1&&(X.prefix={priority:Z,type:"fx"}),e(ie,"fy")!==-1&&(X.prefix={priority:Z,type:"fy"}),e(ie,"xf")!==-1&&(X.postfix={priority:Z,type:"xf"}),e(ie,"yf")!==-1&&(X.postfix={priority:Z,type:"yf"}),e(ie,"xfx")!==-1&&(X.infix={priority:Z,type:"xfx"}),e(ie,"xfy")!==-1&&(X.infix={priority:Z,type:"xfy"}),e(ie,"yfx")!==-1&&(X.infix={priority:Z,type:"yfx"}))}var be;switch(F.id){case"fy":case"fx":be="prefix";break;case"yf":case"xf":be="postfix";break;default:be="infix";break}if(((X.prefix&&be==="prefix"||X.postfix&&be==="postfix"||X.infix&&be==="infix")&&X[be].type!==F.id||X.infix&&be==="postfix"||X.postfix&&be==="infix")&&y.value!==0)w.throw_error(b.error.permission("create","operator",J,S.indicator));else return X[be]&&(Ee(w.session.__operators[X[be].priority][J.id],F.id),w.session.__operators[X[be].priority][J.id].length===0&&delete w.session.__operators[X[be].priority][J.id]),y.value>0&&(w.session.__operators[y.value]||(w.session.__operators[y.value.toString()]={}),w.session.__operators[y.value][J.id]||(w.session.__operators[y.value][J.id]=[]),w.session.__operators[y.value][J.id].push(F.id)),!0}}},predicate:{"op/3":function(w,S,y){b.directive["op/3"](w,y)&&w.success(S)},"current_op/3":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2],Z=[];for(var ie in w.session.__operators)for(var be in w.session.__operators[ie])for(var Le=0;Le<w.session.__operators[ie][be].length;Le++)Z.push(new xe(S.goal.replace(new H(",",[new H("=",[new Fe(ie,!1),F]),new H(",",[new H("=",[new H(w.session.__operators[ie][be][Le],[]),J]),new H("=",[new H(be,[]),X])])])),S.substitution,S));w.prepend(Z)},";/2":function(w,S,y){if(b.type.is_term(y.args[0])&&y.args[0].indicator==="->/2"){var F=w.points,J=w.session.format_success,X=w.session.format_error;w.session.format_success=function(Le){return Le.substitution},w.session.format_error=function(Le){return Le.goal},w.points=[new xe(y.args[0].args[0],S.substitution,S)];var Z=function(Le){w.points=F,w.session.format_success=J,w.session.format_error=X,Le===!1?w.prepend([new xe(S.goal.replace(y.args[1]),S.substitution,S)]):b.type.is_error(Le)?w.throw_error(Le.args[0]):Le===null?(w.prepend([S]),w.__calls.shift()(null)):w.prepend([new xe(S.goal.replace(y.args[0].args[1]).apply(Le),S.substitution.apply(Le),S)])};w.__calls.unshift(Z)}else{var ie=new xe(S.goal.replace(y.args[0]),S.substitution,S),be=new xe(S.goal.replace(y.args[1]),S.substitution,S);w.prepend([ie,be])}},"!/0":function(w,S,y){var F,J,X=[];for(F=S,J=null;F.parent!==null&&F.parent.goal.search(y);)if(J=F,F=F.parent,F.goal!==null){var Z=F.goal.select();if(Z&&Z.id==="call"&&Z.search(y)){F=J;break}}for(var ie=w.points.length-1;ie>=0;ie--){for(var be=w.points[ie],Le=be.parent;Le!==null&&Le!==F.parent;)Le=Le.parent;Le===null&&Le!==F.parent&&X.push(be)}w.points=X.reverse(),w.success(S)},"\\+/1":function(w,S,y){var F=y.args[0];b.type.is_variable(F)?w.throw_error(b.error.instantiation(w.level)):b.type.is_callable(F)?w.prepend([new xe(S.goal.replace(new H(",",[new H(",",[new H("call",[F]),new H("!",[])]),new H("fail",[])])),S.substitution,S),new xe(S.goal.replace(null),S.substitution,S)]):w.throw_error(b.error.type("callable",F,w.level))},"->/2":function(w,S,y){var F=S.goal.replace(new H(",",[y.args[0],new H(",",[new H("!"),y.args[1]])]));w.prepend([new xe(F,S.substitution,S)])},"fail/0":function(w,S,y){},"false/0":function(w,S,y){},"true/0":function(w,S,y){w.success(S)},"call/1":ne(1),"call/2":ne(2),"call/3":ne(3),"call/4":ne(4),"call/5":ne(5),"call/6":ne(6),"call/7":ne(7),"call/8":ne(8),"once/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("call",[F]),new H("!",[])])),S.substitution,S)])},"forall/2":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H("\\+",[new H(",",[new H("call",[F]),new H("\\+",[new H("call",[J])])])])),S.substitution,S)])},"repeat/0":function(w,S,y){w.prepend([new xe(S.goal.replace(null),S.substitution,S),S])},"throw/1":function(w,S,y){b.type.is_variable(y.args[0])?w.throw_error(b.error.instantiation(w.level)):w.throw_error(y.args[0])},"catch/3":function(w,S,y){var F=w.points;w.points=[],w.prepend([new xe(y.args[0],S.substitution,S)]);var J=w.session.format_success,X=w.session.format_error;w.session.format_success=function(ie){return ie.substitution},w.session.format_error=function(ie){return ie.goal};var Z=function(ie){var be=w.points;if(w.points=F,w.session.format_success=J,w.session.format_error=X,b.type.is_error(ie)){for(var Le=[],ot=w.points.length-1;ot>=0;ot--){for(var $t=w.points[ot],dt=$t.parent;dt!==null&&dt!==S.parent;)dt=dt.parent;dt===null&&dt!==S.parent&&Le.push($t)}w.points=Le;var Gt=w.get_flag("occurs_check").indicator==="true/0",$t=new xe,bt=b.unify(ie.args[0],y.args[1],Gt);bt!==null?($t.substitution=S.substitution.apply(bt),$t.goal=S.goal.replace(y.args[2]).apply(bt),$t.parent=S,w.prepend([$t])):w.throw_error(ie.args[0])}else if(ie!==!1){for(var an=ie===null?[]:[new xe(S.goal.apply(ie).replace(null),S.substitution.apply(ie),S)],Qr=[],ot=be.length-1;ot>=0;ot--){Qr.push(be[ot]);var mr=be[ot].goal!==null?be[ot].goal.select():null;if(b.type.is_term(mr)&&mr.indicator==="!/0")break}var br=o(Qr,function(Wr){return Wr.goal===null&&(Wr.goal=new H("true",[])),Wr=new xe(S.goal.replace(new H("catch",[Wr.goal,y.args[1],y.args[2]])),S.substitution.apply(Wr.substitution),Wr.parent),Wr.exclude=y.args[0].variables(),Wr}).reverse();w.prepend(br),w.prepend(an),ie===null&&(this.current_limit=0,w.__calls.shift()(null))}};w.__calls.unshift(Z)},"=/2":function(w,S,y){var F=w.get_flag("occurs_check").indicator==="true/0",J=new xe,X=b.unify(y.args[0],y.args[1],F);X!==null&&(J.goal=S.goal.apply(X).replace(null),J.substitution=S.substitution.apply(X),J.parent=S,w.prepend([J]))},"unify_with_occurs_check/2":function(w,S,y){var F=new xe,J=b.unify(y.args[0],y.args[1],!0);J!==null&&(F.goal=S.goal.apply(J).replace(null),F.substitution=S.substitution.apply(J),F.parent=S,w.prepend([F]))},"\\=/2":function(w,S,y){var F=w.get_flag("occurs_check").indicator==="true/0",J=b.unify(y.args[0],y.args[1],F);J===null&&w.success(S)},"subsumes_term/2":function(w,S,y){var F=w.get_flag("occurs_check").indicator==="true/0",J=b.unify(y.args[1],y.args[0],F);J!==null&&y.args[1].apply(J).equals(y.args[1])&&w.success(S)},"findall/3":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];if(b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(J))w.throw_error(b.error.type("callable",J,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_list(X))w.throw_error(b.error.type("list",X,y.indicator));else{var Z=w.next_free_variable(),ie=new H(",",[J,new H("=",[Z,F])]),be=w.points,Le=w.session.limit,ot=w.session.format_success;w.session.format_success=function($t){return $t.substitution},w.add_goal(ie,!0,S);var dt=[],Gt=function($t){if($t!==!1&&$t!==null&&!b.type.is_error($t))w.__calls.unshift(Gt),dt.push($t.links[Z.id]),w.session.limit=w.current_limit;else if(w.points=be,w.session.limit=Le,w.session.format_success=ot,b.type.is_error($t))w.throw_error($t.args[0]);else if(w.current_limit>0){for(var bt=new H("[]"),an=dt.length-1;an>=0;an--)bt=new H(".",[dt[an],bt]);w.prepend([new xe(S.goal.replace(new H("=",[X,bt])),S.substitution,S)])}};w.__calls.unshift(Gt)}},"bagof/3":function(w,S,y){var F,J=y.args[0],X=y.args[1],Z=y.args[2];if(b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(X))w.throw_error(b.error.type("callable",X,y.indicator));else if(!b.type.is_variable(Z)&&!b.type.is_list(Z))w.throw_error(b.error.type("list",Z,y.indicator));else{var ie=w.next_free_variable(),be;X.indicator==="^/2"?(be=X.args[0].variables(),X=X.args[1]):be=[],be=be.concat(J.variables());for(var Le=X.variables().filter(function(br){return e(be,br)===-1}),ot=new H("[]"),dt=Le.length-1;dt>=0;dt--)ot=new H(".",[new Ie(Le[dt]),ot]);var Gt=new H(",",[X,new H("=",[ie,new H(",",[ot,J])])]),$t=w.points,bt=w.session.limit,an=w.session.format_success;w.session.format_success=function(br){return br.substitution},w.add_goal(Gt,!0,S);var Qr=[],mr=function(br){if(br!==!1&&br!==null&&!b.type.is_error(br)){w.__calls.unshift(mr);var Wr=!1,Kn=br.links[ie.id].args[0],Ls=br.links[ie.id].args[1];for(var Ti in Qr)if(!!Qr.hasOwnProperty(Ti)){var ps=Qr[Ti];if(ps.variables.equals(Kn)){ps.answers.push(Ls),Wr=!0;break}}Wr||Qr.push({variables:Kn,answers:[Ls]}),w.session.limit=w.current_limit}else if(w.points=$t,w.session.limit=bt,w.session.format_success=an,b.type.is_error(br))w.throw_error(br.args[0]);else if(w.current_limit>0){for(var io=[],Si=0;Si<Qr.length;Si++){br=Qr[Si].answers;for(var Ns=new H("[]"),so=br.length-1;so>=0;so--)Ns=new H(".",[br[so],Ns]);io.push(new xe(S.goal.replace(new H(",",[new H("=",[ot,Qr[Si].variables]),new H("=",[Z,Ns])])),S.substitution,S))}w.prepend(io)}};w.__calls.unshift(mr)}},"setof/3":function(w,S,y){var F,J=y.args[0],X=y.args[1],Z=y.args[2];if(b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(X))w.throw_error(b.error.type("callable",X,y.indicator));else if(!b.type.is_variable(Z)&&!b.type.is_list(Z))w.throw_error(b.error.type("list",Z,y.indicator));else{var ie=w.next_free_variable(),be;X.indicator==="^/2"?(be=X.args[0].variables(),X=X.args[1]):be=[],be=be.concat(J.variables());for(var Le=X.variables().filter(function(br){return e(be,br)===-1}),ot=new H("[]"),dt=Le.length-1;dt>=0;dt--)ot=new H(".",[new Ie(Le[dt]),ot]);var Gt=new H(",",[X,new H("=",[ie,new H(",",[ot,J])])]),$t=w.points,bt=w.session.limit,an=w.session.format_success;w.session.format_success=function(br){return br.substitution},w.add_goal(Gt,!0,S);var Qr=[],mr=function(br){if(br!==!1&&br!==null&&!b.type.is_error(br)){w.__calls.unshift(mr);var Wr=!1,Kn=br.links[ie.id].args[0],Ls=br.links[ie.id].args[1];for(var Ti in Qr)if(!!Qr.hasOwnProperty(Ti)){var ps=Qr[Ti];if(ps.variables.equals(Kn)){ps.answers.push(Ls),Wr=!0;break}}Wr||Qr.push({variables:Kn,answers:[Ls]}),w.session.limit=w.current_limit}else if(w.points=$t,w.session.limit=bt,w.session.format_success=an,b.type.is_error(br))w.throw_error(br.args[0]);else if(w.current_limit>0){for(var io=[],Si=0;Si<Qr.length;Si++){br=Qr[Si].answers.sort(b.compare);for(var Ns=new H("[]"),so=br.length-1;so>=0;so--)Ns=new H(".",[br[so],Ns]);io.push(new xe(S.goal.replace(new H(",",[new H("=",[ot,Qr[Si].variables]),new H("=",[Z,Ns])])),S.substitution,S))}w.prepend(io)}};w.__calls.unshift(mr)}},"functor/3":function(w,S,y){var F,J=y.args[0],X=y.args[1],Z=y.args[2];if(b.type.is_variable(J)&&(b.type.is_variable(X)||b.type.is_variable(Z)))w.throw_error(b.error.instantiation("functor/3"));else if(!b.type.is_variable(Z)&&!b.type.is_integer(Z))w.throw_error(b.error.type("integer",y.args[2],"functor/3"));else if(!b.type.is_variable(X)&&!b.type.is_atomic(X))w.throw_error(b.error.type("atomic",y.args[1],"functor/3"));else if(b.type.is_integer(X)&&b.type.is_integer(Z)&&Z.value!==0)w.throw_error(b.error.type("atom",y.args[1],"functor/3"));else if(b.type.is_variable(J)){if(y.args[2].value>=0){for(var ie=[],be=0;be<Z.value;be++)ie.push(w.next_free_variable());var Le=b.type.is_integer(X)?X:new H(X.id,ie);w.prepend([new xe(S.goal.replace(new H("=",[J,Le])),S.substitution,S)])}}else{var ot=b.type.is_integer(J)?J:new H(J.id,[]),dt=b.type.is_integer(J)?new Fe(0,!1):new Fe(J.args.length,!1),Gt=new H(",",[new H("=",[ot,X]),new H("=",[dt,Z])]);w.prepend([new xe(S.goal.replace(Gt),S.substitution,S)])}},"arg/3":function(w,S,y){if(b.type.is_variable(y.args[0])||b.type.is_variable(y.args[1]))w.throw_error(b.error.instantiation(y.indicator));else if(y.args[0].value<0)w.throw_error(b.error.domain("not_less_than_zero",y.args[0],y.indicator));else if(!b.type.is_compound(y.args[1]))w.throw_error(b.error.type("compound",y.args[1],y.indicator));else{var F=y.args[0].value;if(F>0&&F<=y.args[1].args.length){var J=new H("=",[y.args[1].args[F-1],y.args[2]]);w.prepend([new xe(S.goal.replace(J),S.substitution,S)])}}},"=../2":function(w,S,y){var F;if(b.type.is_variable(y.args[0])&&(b.type.is_variable(y.args[1])||b.type.is_non_empty_list(y.args[1])&&b.type.is_variable(y.args[1].args[0])))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_fully_list(y.args[1]))w.throw_error(b.error.type("list",y.args[1],y.indicator));else if(b.type.is_variable(y.args[0])){if(!b.type.is_variable(y.args[1])){var X=[];for(F=y.args[1].args[1];F.indicator==="./2";)X.push(F.args[0]),F=F.args[1];b.type.is_variable(y.args[0])&&b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):X.length===0&&b.type.is_compound(y.args[1].args[0])?w.throw_error(b.error.type("atomic",y.args[1].args[0],y.indicator)):X.length>0&&(b.type.is_compound(y.args[1].args[0])||b.type.is_number(y.args[1].args[0]))?w.throw_error(b.error.type("atom",y.args[1].args[0],y.indicator)):X.length===0?w.prepend([new xe(S.goal.replace(new H("=",[y.args[1].args[0],y.args[0]],S)),S.substitution,S)]):w.prepend([new xe(S.goal.replace(new H("=",[new H(y.args[1].args[0].id,X),y.args[0]])),S.substitution,S)])}}else{if(b.type.is_atomic(y.args[0]))F=new H(".",[y.args[0],new H("[]")]);else{F=new H("[]");for(var J=y.args[0].args.length-1;J>=0;J--)F=new H(".",[y.args[0].args[J],F]);F=new H(".",[new H(y.args[0].id),F])}w.prepend([new xe(S.goal.replace(new H("=",[F,y.args[1]])),S.substitution,S)])}},"copy_term/2":function(w,S,y){var F=y.args[0].rename(w);w.prepend([new xe(S.goal.replace(new H("=",[F,y.args[1]])),S.substitution,S.parent)])},"term_variables/2":function(w,S,y){var F=y.args[0],J=y.args[1];if(!b.type.is_fully_list(J))w.throw_error(b.error.type("list",J,y.indicator));else{var X=g(o(Pe(F.variables()),function(Z){return new Ie(Z)}));w.prepend([new xe(S.goal.replace(new H("=",[J,X])),S.substitution,S)])}},"clause/2":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(y.args[0]))w.throw_error(b.error.type("callable",y.args[0],y.indicator));else if(!b.type.is_variable(y.args[1])&&!b.type.is_callable(y.args[1]))w.throw_error(b.error.type("callable",y.args[1],y.indicator));else if(w.session.rules[y.args[0].indicator]!==void 0)if(w.is_public_predicate(y.args[0].indicator)){var F=[];for(var J in w.session.rules[y.args[0].indicator])if(!!w.session.rules[y.args[0].indicator].hasOwnProperty(J)){var X=w.session.rules[y.args[0].indicator][J];w.session.renamed_variables={},X=X.rename(w),X.body===null&&(X.body=new H("true"));var Z=new H(",",[new H("=",[X.head,y.args[0]]),new H("=",[X.body,y.args[1]])]);F.push(new xe(S.goal.replace(Z),S.substitution,S))}w.prepend(F)}else w.throw_error(b.error.permission("access","private_procedure",y.args[0].indicator,y.indicator))},"current_predicate/1":function(w,S,y){var F=y.args[0];if(!b.type.is_variable(F)&&(!b.type.is_compound(F)||F.indicator!=="//2"))w.throw_error(b.error.type("predicate_indicator",F,y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_variable(F.args[0])&&!b.type.is_atom(F.args[0]))w.throw_error(b.error.type("atom",F.args[0],y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_variable(F.args[1])&&!b.type.is_integer(F.args[1]))w.throw_error(b.error.type("integer",F.args[1],y.indicator));else{var J=[];for(var X in w.session.rules)if(!!w.session.rules.hasOwnProperty(X)){var Z=X.lastIndexOf("/"),ie=X.substr(0,Z),be=parseInt(X.substr(Z+1,X.length-(Z+1))),Le=new H("/",[new H(ie),new Fe(be,!1)]),ot=new H("=",[Le,F]);J.push(new xe(S.goal.replace(ot),S.substitution,S))}w.prepend(J)}},"asserta/1":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(y.args[0]))w.throw_error(b.error.type("callable",y.args[0],y.indicator));else{var F,J;y.args[0].indicator===":-/2"?(F=y.args[0].args[0],J=we(y.args[0].args[1])):(F=y.args[0],J=null),b.type.is_callable(F)?J!==null&&!b.type.is_callable(J)?w.throw_error(b.error.type("callable",J,y.indicator)):w.is_public_predicate(F.indicator)?(w.session.rules[F.indicator]===void 0&&(w.session.rules[F.indicator]=[]),w.session.public_predicates[F.indicator]=!0,w.session.rules[F.indicator]=[new He(F,J,!0)].concat(w.session.rules[F.indicator]),w.success(S)):w.throw_error(b.error.permission("modify","static_procedure",F.indicator,y.indicator)):w.throw_error(b.error.type("callable",F,y.indicator))}},"assertz/1":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(y.args[0]))w.throw_error(b.error.type("callable",y.args[0],y.indicator));else{var F,J;y.args[0].indicator===":-/2"?(F=y.args[0].args[0],J=we(y.args[0].args[1])):(F=y.args[0],J=null),b.type.is_callable(F)?J!==null&&!b.type.is_callable(J)?w.throw_error(b.error.type("callable",J,y.indicator)):w.is_public_predicate(F.indicator)?(w.session.rules[F.indicator]===void 0&&(w.session.rules[F.indicator]=[]),w.session.public_predicates[F.indicator]=!0,w.session.rules[F.indicator].push(new He(F,J,!0)),w.success(S)):w.throw_error(b.error.permission("modify","static_procedure",F.indicator,y.indicator)):w.throw_error(b.error.type("callable",F,y.indicator))}},"retract/1":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(y.args[0]))w.throw_error(b.error.type("callable",y.args[0],y.indicator));else{var F,J;if(y.args[0].indicator===":-/2"?(F=y.args[0].args[0],J=y.args[0].args[1]):(F=y.args[0],J=new H("true")),typeof S.retract>"u")if(w.is_public_predicate(F.indicator)){if(w.session.rules[F.indicator]!==void 0){for(var X=[],Z=0;Z<w.session.rules[F.indicator].length;Z++){w.session.renamed_variables={};var ie=w.session.rules[F.indicator][Z],be=ie.rename(w);be.body===null&&(be.body=new H("true",[]));var Le=w.get_flag("occurs_check").indicator==="true/0",ot=b.unify(new H(",",[F,J]),new H(",",[be.head,be.body]),Le);if(ot!==null){var dt=new xe(S.goal.replace(new H(",",[new H("retract",[new H(":-",[F,J])]),new H(",",[new H("=",[F,be.head]),new H("=",[J,be.body])])])),S.substitution,S);dt.retract=ie,X.push(dt)}}w.prepend(X)}}else w.throw_error(b.error.permission("modify","static_procedure",F.indicator,y.indicator));else ce(w,S,F.indicator,S.retract)}},"retractall/1":function(w,S,y){var F=y.args[0];b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_callable(F)?w.prepend([new xe(S.goal.replace(new H(",",[new H("retract",[new b.type.Term(":-",[F,new Ie("_")])]),new H("fail",[])])),S.substitution,S),new xe(S.goal.replace(null),S.substitution,S)]):w.throw_error(b.error.type("callable",F,y.indicator))},"abolish/1":function(w,S,y){if(b.type.is_variable(y.args[0])||b.type.is_term(y.args[0])&&y.args[0].indicator==="//2"&&(b.type.is_variable(y.args[0].args[0])||b.type.is_variable(y.args[0].args[1])))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_term(y.args[0])||y.args[0].indicator!=="//2")w.throw_error(b.error.type("predicate_indicator",y.args[0],y.indicator));else if(!b.type.is_atom(y.args[0].args[0]))w.throw_error(b.error.type("atom",y.args[0].args[0],y.indicator));else if(!b.type.is_integer(y.args[0].args[1]))w.throw_error(b.error.type("integer",y.args[0].args[1],y.indicator));else if(y.args[0].args[1].value<0)w.throw_error(b.error.domain("not_less_than_zero",y.args[0].args[1],y.indicator));else if(b.type.is_number(w.get_flag("max_arity"))&&y.args[0].args[1].value>w.get_flag("max_arity").value)w.throw_error(b.error.representation("max_arity",y.indicator));else{var F=y.args[0].args[0].id+"/"+y.args[0].args[1].value;w.is_public_predicate(F)?(delete w.session.rules[F],w.success(S)):w.throw_error(b.error.permission("modify","static_procedure",F,y.indicator))}},"atom_length/2":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_atom(y.args[0]))w.throw_error(b.error.type("atom",y.args[0],y.indicator));else if(!b.type.is_variable(y.args[1])&&!b.type.is_integer(y.args[1]))w.throw_error(b.error.type("integer",y.args[1],y.indicator));else if(b.type.is_integer(y.args[1])&&y.args[1].value<0)w.throw_error(b.error.domain("not_less_than_zero",y.args[1],y.indicator));else{var F=new Fe(y.args[0].id.length,!1);w.prepend([new xe(S.goal.replace(new H("=",[F,y.args[1]])),S.substitution,S)])}},"atom_concat/3":function(w,S,y){var F,J,X=y.args[0],Z=y.args[1],ie=y.args[2];if(b.type.is_variable(ie)&&(b.type.is_variable(X)||b.type.is_variable(Z)))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_atom(X))w.throw_error(b.error.type("atom",X,y.indicator));else if(!b.type.is_variable(Z)&&!b.type.is_atom(Z))w.throw_error(b.error.type("atom",Z,y.indicator));else if(!b.type.is_variable(ie)&&!b.type.is_atom(ie))w.throw_error(b.error.type("atom",ie,y.indicator));else{var be=b.type.is_variable(X),Le=b.type.is_variable(Z);if(!be&&!Le)J=new H("=",[ie,new H(X.id+Z.id)]),w.prepend([new xe(S.goal.replace(J),S.substitution,S)]);else if(be&&!Le)F=ie.id.substr(0,ie.id.length-Z.id.length),F+Z.id===ie.id&&(J=new H("=",[X,new H(F)]),w.prepend([new xe(S.goal.replace(J),S.substitution,S)]));else if(Le&&!be)F=ie.id.substr(X.id.length),X.id+F===ie.id&&(J=new H("=",[Z,new H(F)]),w.prepend([new xe(S.goal.replace(J),S.substitution,S)]));else{for(var ot=[],dt=0;dt<=ie.id.length;dt++){var Gt=new H(ie.id.substr(0,dt)),$t=new H(ie.id.substr(dt));J=new H(",",[new H("=",[Gt,X]),new H("=",[$t,Z])]),ot.push(new xe(S.goal.replace(J),S.substitution,S))}w.prepend(ot)}}},"sub_atom/5":function(w,S,y){var F,J=y.args[0],X=y.args[1],Z=y.args[2],ie=y.args[3],be=y.args[4];if(b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_integer(X))w.throw_error(b.error.type("integer",X,y.indicator));else if(!b.type.is_variable(Z)&&!b.type.is_integer(Z))w.throw_error(b.error.type("integer",Z,y.indicator));else if(!b.type.is_variable(ie)&&!b.type.is_integer(ie))w.throw_error(b.error.type("integer",ie,y.indicator));else if(b.type.is_integer(X)&&X.value<0)w.throw_error(b.error.domain("not_less_than_zero",X,y.indicator));else if(b.type.is_integer(Z)&&Z.value<0)w.throw_error(b.error.domain("not_less_than_zero",Z,y.indicator));else if(b.type.is_integer(ie)&&ie.value<0)w.throw_error(b.error.domain("not_less_than_zero",ie,y.indicator));else{var Le=[],ot=[],dt=[];if(b.type.is_variable(X))for(F=0;F<=J.id.length;F++)Le.push(F);else Le.push(X.value);if(b.type.is_variable(Z))for(F=0;F<=J.id.length;F++)ot.push(F);else ot.push(Z.value);if(b.type.is_variable(ie))for(F=0;F<=J.id.length;F++)dt.push(F);else dt.push(ie.value);var Gt=[];for(var $t in Le)if(!!Le.hasOwnProperty($t)){F=Le[$t];for(var bt in ot)if(!!ot.hasOwnProperty(bt)){var an=ot[bt],Qr=J.id.length-F-an;if(e(dt,Qr)!==-1&&F+an+Qr===J.id.length){var mr=J.id.substr(F,an);if(J.id===J.id.substr(0,F)+mr+J.id.substr(F+an,Qr)){var br=new H("=",[new H(mr),be]),Wr=new H("=",[X,new Fe(F)]),Kn=new H("=",[Z,new Fe(an)]),Ls=new H("=",[ie,new Fe(Qr)]),Ti=new H(",",[new H(",",[new H(",",[Wr,Kn]),Ls]),br]);Gt.push(new xe(S.goal.replace(Ti),S.substitution,S))}}}}w.prepend(Gt)}},"atom_chars/2":function(w,S,y){var F=y.args[0],J=y.args[1];if(b.type.is_variable(F)&&b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_atom(F))w.throw_error(b.error.type("atom",F,y.indicator));else if(b.type.is_variable(F)){for(var ie=J,be=b.type.is_variable(F),Le="";ie.indicator==="./2";){if(b.type.is_character(ie.args[0]))Le+=ie.args[0].id;else if(b.type.is_variable(ie.args[0])&&be){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_variable(ie.args[0])){w.throw_error(b.error.type("character",ie.args[0],y.indicator));return}ie=ie.args[1]}b.type.is_variable(ie)&&be?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_empty_list(ie)&&!b.type.is_variable(ie)?w.throw_error(b.error.type("list",J,y.indicator)):w.prepend([new xe(S.goal.replace(new H("=",[new H(Le),F])),S.substitution,S)])}else{for(var X=new H("[]"),Z=F.id.length-1;Z>=0;Z--)X=new H(".",[new H(F.id.charAt(Z)),X]);w.prepend([new xe(S.goal.replace(new H("=",[J,X])),S.substitution,S)])}},"atom_codes/2":function(w,S,y){var F=y.args[0],J=y.args[1];if(b.type.is_variable(F)&&b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_atom(F))w.throw_error(b.error.type("atom",F,y.indicator));else if(b.type.is_variable(F)){for(var ie=J,be=b.type.is_variable(F),Le="";ie.indicator==="./2";){if(b.type.is_character_code(ie.args[0]))Le+=u(ie.args[0].value);else if(b.type.is_variable(ie.args[0])&&be){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_variable(ie.args[0])){w.throw_error(b.error.representation("character_code",y.indicator));return}ie=ie.args[1]}b.type.is_variable(ie)&&be?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_empty_list(ie)&&!b.type.is_variable(ie)?w.throw_error(b.error.type("list",J,y.indicator)):w.prepend([new xe(S.goal.replace(new H("=",[new H(Le),F])),S.substitution,S)])}else{for(var X=new H("[]"),Z=F.id.length-1;Z>=0;Z--)X=new H(".",[new Fe(n(F.id,Z),!1),X]);w.prepend([new xe(S.goal.replace(new H("=",[J,X])),S.substitution,S)])}},"char_code/2":function(w,S,y){var F=y.args[0],J=y.args[1];if(b.type.is_variable(F)&&b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_character(F))w.throw_error(b.error.type("character",F,y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_integer(J))w.throw_error(b.error.type("integer",J,y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_character_code(J))w.throw_error(b.error.representation("character_code",y.indicator));else if(b.type.is_variable(J)){var X=new Fe(n(F.id,0),!1);w.prepend([new xe(S.goal.replace(new H("=",[X,J])),S.substitution,S)])}else{var Z=new H(u(J.value));w.prepend([new xe(S.goal.replace(new H("=",[Z,F])),S.substitution,S)])}},"number_chars/2":function(w,S,y){var F,J=y.args[0],X=y.args[1];if(b.type.is_variable(J)&&b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_number(J))w.throw_error(b.error.type("number",J,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_list(X))w.throw_error(b.error.type("list",X,y.indicator));else{var Z=b.type.is_variable(J);if(!b.type.is_variable(X)){var ie=X,be=!0;for(F="";ie.indicator==="./2";){if(b.type.is_character(ie.args[0]))F+=ie.args[0].id;else if(b.type.is_variable(ie.args[0]))be=!1;else if(!b.type.is_variable(ie.args[0])){w.throw_error(b.error.type("character",ie.args[0],y.indicator));return}ie=ie.args[1]}if(be=be&&b.type.is_empty_list(ie),!b.type.is_empty_list(ie)&&!b.type.is_variable(ie)){w.throw_error(b.error.type("list",X,y.indicator));return}if(!be&&Z){w.throw_error(b.error.instantiation(y.indicator));return}else if(be)if(b.type.is_variable(ie)&&Z){w.throw_error(b.error.instantiation(y.indicator));return}else{var Le=w.parse(F),ot=Le.value;!b.type.is_number(ot)||Le.tokens[Le.tokens.length-1].space?w.throw_error(b.error.syntax_by_predicate("parseable_number",y.indicator)):w.prepend([new xe(S.goal.replace(new H("=",[J,ot])),S.substitution,S)]);return}}if(!Z){F=J.toString();for(var dt=new H("[]"),Gt=F.length-1;Gt>=0;Gt--)dt=new H(".",[new H(F.charAt(Gt)),dt]);w.prepend([new xe(S.goal.replace(new H("=",[X,dt])),S.substitution,S)])}}},"number_codes/2":function(w,S,y){var F,J=y.args[0],X=y.args[1];if(b.type.is_variable(J)&&b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_number(J))w.throw_error(b.error.type("number",J,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_list(X))w.throw_error(b.error.type("list",X,y.indicator));else{var Z=b.type.is_variable(J);if(!b.type.is_variable(X)){var ie=X,be=!0;for(F="";ie.indicator==="./2";){if(b.type.is_character_code(ie.args[0]))F+=u(ie.args[0].value);else if(b.type.is_variable(ie.args[0]))be=!1;else if(!b.type.is_variable(ie.args[0])){w.throw_error(b.error.type("character_code",ie.args[0],y.indicator));return}ie=ie.args[1]}if(be=be&&b.type.is_empty_list(ie),!b.type.is_empty_list(ie)&&!b.type.is_variable(ie)){w.throw_error(b.error.type("list",X,y.indicator));return}if(!be&&Z){w.throw_error(b.error.instantiation(y.indicator));return}else if(be)if(b.type.is_variable(ie)&&Z){w.throw_error(b.error.instantiation(y.indicator));return}else{var Le=w.parse(F),ot=Le.value;!b.type.is_number(ot)||Le.tokens[Le.tokens.length-1].space?w.throw_error(b.error.syntax_by_predicate("parseable_number",y.indicator)):w.prepend([new xe(S.goal.replace(new H("=",[J,ot])),S.substitution,S)]);return}}if(!Z){F=J.toString();for(var dt=new H("[]"),Gt=F.length-1;Gt>=0;Gt--)dt=new H(".",[new Fe(n(F,Gt),!1),dt]);w.prepend([new xe(S.goal.replace(new H("=",[X,dt])),S.substitution,S)])}}},"upcase_atom/2":function(w,S,y){var F=y.args[0],J=y.args[1];b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_atom(F)?!b.type.is_variable(J)&&!b.type.is_atom(J)?w.throw_error(b.error.type("atom",J,y.indicator)):w.prepend([new xe(S.goal.replace(new H("=",[J,new H(F.id.toUpperCase(),[])])),S.substitution,S)]):w.throw_error(b.error.type("atom",F,y.indicator))},"downcase_atom/2":function(w,S,y){var F=y.args[0],J=y.args[1];b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_atom(F)?!b.type.is_variable(J)&&!b.type.is_atom(J)?w.throw_error(b.error.type("atom",J,y.indicator)):w.prepend([new xe(S.goal.replace(new H("=",[J,new H(F.id.toLowerCase(),[])])),S.substitution,S)]):w.throw_error(b.error.type("atom",F,y.indicator))},"atomic_list_concat/2":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H("atomic_list_concat",[F,new H("",[]),J])),S.substitution,S)])},"atomic_list_concat/3":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];if(b.type.is_variable(J)||b.type.is_variable(F)&&b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_list(F))w.throw_error(b.error.type("list",F,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_atom(X))w.throw_error(b.error.type("atom",X,y.indicator));else if(b.type.is_variable(X)){for(var ie="",be=F;b.type.is_term(be)&&be.indicator==="./2";){if(!b.type.is_atom(be.args[0])&&!b.type.is_number(be.args[0])){w.throw_error(b.error.type("atomic",be.args[0],y.indicator));return}ie!==""&&(ie+=J.id),b.type.is_atom(be.args[0])?ie+=be.args[0].id:ie+=""+be.args[0].value,be=be.args[1]}ie=new H(ie,[]),b.type.is_variable(be)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_term(be)||be.indicator!=="[]/0"?w.throw_error(b.error.type("list",F,y.indicator)):w.prepend([new xe(S.goal.replace(new H("=",[ie,X])),S.substitution,S)])}else{var Z=g(o(X.id.split(J.id),function(Le){return new H(Le,[])}));w.prepend([new xe(S.goal.replace(new H("=",[Z,F])),S.substitution,S)])}},"@=</2":function(w,S,y){b.compare(y.args[0],y.args[1])<=0&&w.success(S)},"==/2":function(w,S,y){b.compare(y.args[0],y.args[1])===0&&w.success(S)},"\\==/2":function(w,S,y){b.compare(y.args[0],y.args[1])!==0&&w.success(S)},"@</2":function(w,S,y){b.compare(y.args[0],y.args[1])<0&&w.success(S)},"@>/2":function(w,S,y){b.compare(y.args[0],y.args[1])>0&&w.success(S)},"@>=/2":function(w,S,y){b.compare(y.args[0],y.args[1])>=0&&w.success(S)},"compare/3":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];if(!b.type.is_variable(F)&&!b.type.is_atom(F))w.throw_error(b.error.type("atom",F,y.indicator));else if(b.type.is_atom(F)&&["<",">","="].indexOf(F.id)===-1)w.throw_error(b.type.domain("order",F,y.indicator));else{var Z=b.compare(J,X);Z=Z===0?"=":Z===-1?"<":">",w.prepend([new xe(S.goal.replace(new H("=",[F,new H(Z,[])])),S.substitution,S)])}},"is/2":function(w,S,y){var F=y.args[1].interpret(w);b.type.is_number(F)?w.prepend([new xe(S.goal.replace(new H("=",[y.args[0],F],w.level)),S.substitution,S)]):w.throw_error(F)},"between/3":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];if(b.type.is_variable(F)||b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_integer(F))w.throw_error(b.error.type("integer",F,y.indicator));else if(!b.type.is_integer(J))w.throw_error(b.error.type("integer",J,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_integer(X))w.throw_error(b.error.type("integer",X,y.indicator));else if(b.type.is_variable(X)){var Z=[new xe(S.goal.replace(new H("=",[X,F])),S.substitution,S)];F.value<J.value&&Z.push(new xe(S.goal.replace(new H("between",[new Fe(F.value+1,!1),J,X])),S.substitution,S)),w.prepend(Z)}else F.value<=X.value&&J.value>=X.value&&w.success(S)},"succ/2":function(w,S,y){var F=y.args[0],J=y.args[1];b.type.is_variable(F)&&b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_variable(F)&&!b.type.is_integer(F)?w.throw_error(b.error.type("integer",F,y.indicator)):!b.type.is_variable(J)&&!b.type.is_integer(J)?w.throw_error(b.error.type("integer",J,y.indicator)):!b.type.is_variable(F)&&F.value<0?w.throw_error(b.error.domain("not_less_than_zero",F,y.indicator)):!b.type.is_variable(J)&&J.value<0?w.throw_error(b.error.domain("not_less_than_zero",J,y.indicator)):(b.type.is_variable(J)||J.value>0)&&(b.type.is_variable(F)?w.prepend([new xe(S.goal.replace(new H("=",[F,new Fe(J.value-1,!1)])),S.substitution,S)]):w.prepend([new xe(S.goal.replace(new H("=",[J,new Fe(F.value+1,!1)])),S.substitution,S)]))},"=:=/2":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F===0&&w.success(S)},"=\\=/2":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F!==0&&w.success(S)},"</2":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F<0&&w.success(S)},"=</2":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F<=0&&w.success(S)},">/2":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F>0&&w.success(S)},">=/2":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F>=0&&w.success(S)},"var/1":function(w,S,y){b.type.is_variable(y.args[0])&&w.success(S)},"atom/1":function(w,S,y){b.type.is_atom(y.args[0])&&w.success(S)},"atomic/1":function(w,S,y){b.type.is_atomic(y.args[0])&&w.success(S)},"compound/1":function(w,S,y){b.type.is_compound(y.args[0])&&w.success(S)},"integer/1":function(w,S,y){b.type.is_integer(y.args[0])&&w.success(S)},"float/1":function(w,S,y){b.type.is_float(y.args[0])&&w.success(S)},"number/1":function(w,S,y){b.type.is_number(y.args[0])&&w.success(S)},"nonvar/1":function(w,S,y){b.type.is_variable(y.args[0])||w.success(S)},"ground/1":function(w,S,y){y.variables().length===0&&w.success(S)},"acyclic_term/1":function(w,S,y){for(var F=S.substitution.apply(S.substitution),J=y.args[0].variables(),X=0;X<J.length;X++)if(S.substitution.links[J[X]]!==void 0&&!S.substitution.links[J[X]].equals(F.links[J[X]]))return;w.success(S)},"callable/1":function(w,S,y){b.type.is_callable(y.args[0])&&w.success(S)},"is_list/1":function(w,S,y){for(var F=y.args[0];b.type.is_term(F)&&F.indicator==="./2";)F=F.args[1];b.type.is_term(F)&&F.indicator==="[]/0"&&w.success(S)},"current_input/1":function(w,S,y){var F=y.args[0];!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain("stream",F,y.indicator)):(b.type.is_atom(F)&&w.get_stream_by_alias(F.id)&&(F=w.get_stream_by_alias(F.id)),w.prepend([new xe(S.goal.replace(new H("=",[F,w.get_current_input()])),S.substitution,S)]))},"current_output/1":function(w,S,y){var F=y.args[0];!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain("stream_or_alias",F,y.indicator)):(b.type.is_atom(F)&&w.get_stream_by_alias(F.id)&&(F=w.get_stream_by_alias(F.id)),w.prepend([new xe(S.goal.replace(new H("=",[F,w.get_current_output()])),S.substitution,S)]))},"set_input/1":function(w,S,y){var F=y.args[0],J=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain("stream_or_alias",F,y.indicator)):b.type.is_stream(J)?J.output===!0?w.throw_error(b.error.permission("input","stream",F,y.indicator)):(w.set_current_input(J),w.success(S)):w.throw_error(b.error.existence("stream",F,y.indicator))},"set_output/1":function(w,S,y){var F=y.args[0],J=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain("stream_or_alias",F,y.indicator)):b.type.is_stream(J)?J.input===!0?w.throw_error(b.error.permission("output","stream",F,y.indicator)):(w.set_current_output(J),w.success(S)):w.throw_error(b.error.existence("stream",F,y.indicator))},"open/3":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];w.prepend([new xe(S.goal.replace(new H("open",[F,J,X,new H("[]",[])])),S.substitution,S)])},"open/4":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2],Z=y.args[3];if(b.type.is_variable(F)||b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_atom(J))w.throw_error(b.error.type("atom",J,y.indicator));else if(!b.type.is_list(Z))w.throw_error(b.error.type("list",Z,y.indicator));else if(!b.type.is_variable(X))w.throw_error(b.error.type("variable",X,y.indicator));else if(!b.type.is_atom(F)&&!b.type.is_streamable(F))w.throw_error(b.error.domain("source_sink",F,y.indicator));else if(!b.type.is_io_mode(J))w.throw_error(b.error.domain("io_mode",J,y.indicator));else{for(var ie={},be=Z,Le;b.type.is_term(be)&&be.indicator==="./2";){if(Le=be.args[0],b.type.is_variable(Le)){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_stream_option(Le)){w.throw_error(b.error.domain("stream_option",Le,y.indicator));return}ie[Le.id]=Le.args[0].id,be=be.args[1]}if(be.indicator!=="[]/0"){b.type.is_variable(be)?w.throw_error(b.error.instantiation(y.indicator)):w.throw_error(b.error.type("list",Z,y.indicator));return}else{var ot=ie.alias;if(ot&&w.get_stream_by_alias(ot)){w.throw_error(b.error.permission("open","source_sink",new H("alias",[new H(ot,[])]),y.indicator));return}ie.type||(ie.type="text");var dt;if(b.type.is_atom(F)?dt=w.file_system_open(F.id,ie.type,J.id):dt=F.stream(ie.type,J.id),dt===!1){w.throw_error(b.error.permission("open","source_sink",F,y.indicator));return}else if(dt===null){w.throw_error(b.error.existence("source_sink",F,y.indicator));return}var Gt=new Re(dt,J.id,ie.alias,ie.type,ie.reposition==="true",ie.eof_action);ot?w.session.streams[ot]=Gt:w.session.streams[Gt.id]=Gt,w.prepend([new xe(S.goal.replace(new H("=",[X,Gt])),S.substitution,S)])}}},"close/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H("close",[F,new H("[]",[])])),S.substitution,S)])},"close/2":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F)||b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_list(J))w.throw_error(b.error.type("list",J,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain("stream_or_alias",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence("stream",F,y.indicator));else{for(var Z={},ie=J,be;b.type.is_term(ie)&&ie.indicator==="./2";){if(be=ie.args[0],b.type.is_variable(be)){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_close_option(be)){w.throw_error(b.error.domain("close_option",be,y.indicator));return}Z[be.id]=be.args[0].id==="true",ie=ie.args[1]}if(ie.indicator!=="[]/0"){b.type.is_variable(ie)?w.throw_error(b.error.instantiation(y.indicator)):w.throw_error(b.error.type("list",J,y.indicator));return}else{if(X===w.session.standard_input||X===w.session.standard_output){w.success(S);return}else X===w.session.current_input?w.session.current_input=w.session.standard_input:X===w.session.current_output&&(w.session.current_output=w.session.current_output);X.alias!==null?delete w.session.streams[X.alias]:delete w.session.streams[X.id],X.output&&X.stream.flush();var Le=X.stream.close();X.stream=null,(Z.force===!0||Le===!0)&&w.success(S)}}},"flush_output/0":function(w,S,y){w.prepend([new xe(S.goal.replace(new H(",",[new H("current_output",[new Ie("S")]),new H("flush_output",[new Ie("S")])])),S.substitution,S)])},"flush_output/1":function(w,S,y){var F=y.args[0],J=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain("stream_or_alias",F,y.indicator)):!b.type.is_stream(J)||J.stream===null?w.throw_error(b.error.existence("stream",F,y.indicator)):F.input===!0?w.throw_error(b.error.permission("output","stream",output,y.indicator)):(J.stream.flush(),w.success(S))},"stream_property/2":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain("stream_or_alias",F,y.indicator));else if(!b.type.is_variable(F)&&(!b.type.is_stream(X)||X.stream===null))w.throw_error(b.error.existence("stream",F,y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_stream_property(J))w.throw_error(b.error.domain("stream_property",J,y.indicator));else{var Z=[],ie=[];if(!b.type.is_variable(F))Z.push(X);else for(var be in w.session.streams)Z.push(w.session.streams[be]);for(var Le=0;Le<Z.length;Le++){var ot=[];Z[Le].filename&&ot.push(new H("file_name",[new H(Z[Le].file_name,[])])),ot.push(new H("mode",[new H(Z[Le].mode,[])])),ot.push(new H(Z[Le].input?"input":"output",[])),Z[Le].alias&&ot.push(new H("alias",[new H(Z[Le].alias,[])])),ot.push(new H("position",[typeof Z[Le].position=="number"?new Fe(Z[Le].position,!1):new H(Z[Le].position,[])])),ot.push(new H("end_of_stream",[new H(Z[Le].position==="end_of_stream"?"at":Z[Le].position==="past_end_of_stream"?"past":"not",[])])),ot.push(new H("eof_action",[new H(Z[Le].eof_action,[])])),ot.push(new H("reposition",[new H(Z[Le].reposition?"true":"false",[])])),ot.push(new H("type",[new H(Z[Le].type,[])]));for(var dt=0;dt<ot.length;dt++)ie.push(new xe(S.goal.replace(new H(",",[new H("=",[b.type.is_variable(F)?F:X,Z[Le]]),new H("=",[J,ot[dt]])])),S.substitution,S))}w.prepend(ie)}},"at_end_of_stream/0":function(w,S,y){w.prepend([new xe(S.goal.replace(new H(",",[new H("current_input",[new Ie("S")]),new H(",",[new H("stream_property",[new Ie("S"),new H("end_of_stream",[new Ie("E")])]),new H(",",[new H("!",[]),new H(";",[new H("=",[new Ie("E"),new H("at",[])]),new H("=",[new Ie("E"),new H("past",[])])])])])])),S.substitution,S)])},"at_end_of_stream/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("stream_property",[F,new H("end_of_stream",[new Ie("E")])]),new H(",",[new H("!",[]),new H(";",[new H("=",[new Ie("E"),new H("at",[])]),new H("=",[new Ie("E"),new H("past",[])])])])])),S.substitution,S)])},"set_stream_position/2":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain("stream_or_alias",F,y.indicator)):!b.type.is_stream(X)||X.stream===null?w.throw_error(b.error.existence("stream",F,y.indicator)):b.type.is_stream_position(J)?X.reposition===!1?w.throw_error(b.error.permission("reposition","stream",F,y.indicator)):(b.type.is_integer(J)?X.position=J.value:X.position=J.id,w.success(S)):w.throw_error(b.error.domain("stream_position",J,y.indicator))},"get_char/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_input",[new Ie("S")]),new H("get_char",[new Ie("S"),F])])),S.substitution,S)])},"get_char/2":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_character(J))w.throw_error(b.error.type("in_character",J,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain("stream_or_alias",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence("stream",F,y.indicator));else if(X.output)w.throw_error(b.error.permission("input","stream",F,y.indicator));else if(X.type==="binary")w.throw_error(b.error.permission("input","binary_stream",F,y.indicator));else if(X.position==="past_end_of_stream"&&X.eof_action==="error")w.throw_error(b.error.permission("input","past_end_of_stream",F,y.indicator));else{var Z;if(X.position==="end_of_stream")Z="end_of_file",X.position="past_end_of_stream";else{if(Z=X.stream.get(1,X.position),Z===null){w.throw_error(b.error.representation("character",y.indicator));return}X.position++}w.prepend([new xe(S.goal.replace(new H("=",[new H(Z,[]),J])),S.substitution,S)])}},"get_code/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_input",[new Ie("S")]),new H("get_code",[new Ie("S"),F])])),S.substitution,S)])},"get_code/2":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_integer(J))w.throw_error(b.error.type("integer",char,y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain("stream_or_alias",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence("stream",F,y.indicator));else if(X.output)w.throw_error(b.error.permission("input","stream",F,y.indicator));else if(X.type==="binary")w.throw_error(b.error.permission("input","binary_stream",F,y.indicator));else if(X.position==="past_end_of_stream"&&X.eof_action==="error")w.throw_error(b.error.permission("input","past_end_of_stream",F,y.indicator));else{var Z;if(X.position==="end_of_stream")Z=-1,X.position="past_end_of_stream";else{if(Z=X.stream.get(1,X.position),Z===null){w.throw_error(b.error.representation("character",y.indicator));return}Z=n(Z,0),X.position++}w.prepend([new xe(S.goal.replace(new H("=",[new Fe(Z,!1),J])),S.substitution,S)])}},"peek_char/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_input",[new Ie("S")]),new H("peek_char",[new Ie("S"),F])])),S.substitution,S)])},"peek_char/2":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_character(J))w.throw_error(b.error.type("in_character",J,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain("stream_or_alias",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence("stream",F,y.indicator));else if(X.output)w.throw_error(b.error.permission("input","stream",F,y.indicator));else if(X.type==="binary")w.throw_error(b.error.permission("input","binary_stream",F,y.indicator));else if(X.position==="past_end_of_stream"&&X.eof_action==="error")w.throw_error(b.error.permission("input","past_end_of_stream",F,y.indicator));else{var Z;if(X.position==="end_of_stream")Z="end_of_file",X.position="past_end_of_stream";else if(Z=X.stream.get(1,X.position),Z===null){w.throw_error(b.error.representation("character",y.indicator));return}w.prepend([new xe(S.goal.replace(new H("=",[new H(Z,[]),J])),S.substitution,S)])}},"peek_code/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_input",[new Ie("S")]),new H("peek_code",[new Ie("S"),F])])),S.substitution,S)])},"peek_code/2":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_integer(J))w.throw_error(b.error.type("integer",char,y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain("stream_or_alias",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence("stream",F,y.indicator));else if(X.output)w.throw_error(b.error.permission("input","stream",F,y.indicator));else if(X.type==="binary")w.throw_error(b.error.permission("input","binary_stream",F,y.indicator));else if(X.position==="past_end_of_stream"&&X.eof_action==="error")w.throw_error(b.error.permission("input","past_end_of_stream",F,y.indicator));else{var Z;if(X.position==="end_of_stream")Z=-1,X.position="past_end_of_stream";else{if(Z=X.stream.get(1,X.position),Z===null){w.throw_error(b.error.representation("character",y.indicator));return}Z=n(Z,0)}w.prepend([new xe(S.goal.replace(new H("=",[new Fe(Z,!1),J])),S.substitution,S)])}},"put_char/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_output",[new Ie("S")]),new H("put_char",[new Ie("S"),F])])),S.substitution,S)])},"put_char/2":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_character(J)?!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain("stream_or_alias",F,y.indicator)):!b.type.is_stream(X)||X.stream===null?w.throw_error(b.error.existence("stream",F,y.indicator)):X.input?w.throw_error(b.error.permission("output","stream",F,y.indicator)):X.type==="binary"?w.throw_error(b.error.permission("output","binary_stream",F,y.indicator)):X.stream.put(J.id,X.position)&&(typeof X.position=="number"&&X.position++,w.success(S)):w.throw_error(b.error.type("character",J,y.indicator))},"put_code/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_output",[new Ie("S")]),new H("put_code",[new Ie("S"),F])])),S.substitution,S)])},"put_code/2":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_integer(J)?b.type.is_character_code(J)?!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain("stream_or_alias",F,y.indicator)):!b.type.is_stream(X)||X.stream===null?w.throw_error(b.error.existence("stream",F,y.indicator)):X.input?w.throw_error(b.error.permission("output","stream",F,y.indicator)):X.type==="binary"?w.throw_error(b.error.permission("output","binary_stream",F,y.indicator)):X.stream.put_char(u(J.value),X.position)&&(typeof X.position=="number"&&X.position++,w.success(S)):w.throw_error(b.error.representation("character_code",y.indicator)):w.throw_error(b.error.type("integer",J,y.indicator))},"nl/0":function(w,S,y){w.prepend([new xe(S.goal.replace(new H(",",[new H("current_output",[new Ie("S")]),new H("put_char",[new Ie("S"),new H(`
-`,[])])])),S.substitution,S)])},"nl/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H("put_char",[F,new H(`
-`,[])])),S.substitution,S)])},"get_byte/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_input",[new Ie("S")]),new H("get_byte",[new Ie("S"),F])])),S.substitution,S)])},"get_byte/2":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_byte(J))w.throw_error(b.error.type("in_byte",char,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain("stream_or_alias",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence("stream",F,y.indicator));else if(X.output)w.throw_error(b.error.permission("input","stream",F,y.indicator));else if(X.type==="text")w.throw_error(b.error.permission("input","text_stream",F,y.indicator));else if(X.position==="past_end_of_stream"&&X.eof_action==="error")w.throw_error(b.error.permission("input","past_end_of_stream",F,y.indicator));else{var Z;if(X.position==="end_of_stream")Z="end_of_file",X.position="past_end_of_stream";else{if(Z=X.stream.get_byte(X.position),Z===null){w.throw_error(b.error.representation("byte",y.indicator));return}X.position++}w.prepend([new xe(S.goal.replace(new H("=",[new Fe(Z,!1),J])),S.substitution,S)])}},"peek_byte/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_input",[new Ie("S")]),new H("peek_byte",[new Ie("S"),F])])),S.substitution,S)])},"peek_byte/2":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_byte(J))w.throw_error(b.error.type("in_byte",char,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain("stream_or_alias",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence("stream",F,y.indicator));else if(X.output)w.throw_error(b.error.permission("input","stream",F,y.indicator));else if(X.type==="text")w.throw_error(b.error.permission("input","text_stream",F,y.indicator));else if(X.position==="past_end_of_stream"&&X.eof_action==="error")w.throw_error(b.error.permission("input","past_end_of_stream",F,y.indicator));else{var Z;if(X.position==="end_of_stream")Z="end_of_file",X.position="past_end_of_stream";else if(Z=X.stream.get_byte(X.position),Z===null){w.throw_error(b.error.representation("byte",y.indicator));return}w.prepend([new xe(S.goal.replace(new H("=",[new Fe(Z,!1),J])),S.substitution,S)])}},"put_byte/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_output",[new Ie("S")]),new H("put_byte",[new Ie("S"),F])])),S.substitution,S)])},"put_byte/2":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_byte(J)?!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain("stream_or_alias",F,y.indicator)):!b.type.is_stream(X)||X.stream===null?w.throw_error(b.error.existence("stream",F,y.indicator)):X.input?w.throw_error(b.error.permission("output","stream",F,y.indicator)):X.type==="text"?w.throw_error(b.error.permission("output","text_stream",F,y.indicator)):X.stream.put_byte(J.value,X.position)&&(typeof X.position=="number"&&X.position++,w.success(S)):w.throw_error(b.error.type("byte",J,y.indicator))},"read/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_input",[new Ie("S")]),new H("read_term",[new Ie("S"),F,new H("[]",[])])])),S.substitution,S)])},"read/2":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H("read_term",[F,J,new H("[]",[])])),S.substitution,S)])},"read_term/2":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_input",[new Ie("S")]),new H("read_term",[new Ie("S"),F,J])])),S.substitution,S)])},"read_term/3":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2],Z=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F)||b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_list(X))w.throw_error(b.error.type("list",X,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain("stream_or_alias",F,y.indicator));else if(!b.type.is_stream(Z)||Z.stream===null)w.throw_error(b.error.existence("stream",F,y.indicator));else if(Z.output)w.throw_error(b.error.permission("input","stream",F,y.indicator));else if(Z.type==="binary")w.throw_error(b.error.permission("input","binary_stream",F,y.indicator));else if(Z.position==="past_end_of_stream"&&Z.eof_action==="error")w.throw_error(b.error.permission("input","past_end_of_stream",F,y.indicator));else{for(var ie={},be=X,Le;b.type.is_term(be)&&be.indicator==="./2";){if(Le=be.args[0],b.type.is_variable(Le)){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_read_option(Le)){w.throw_error(b.error.domain("read_option",Le,y.indicator));return}ie[Le.id]=Le.args[0],be=be.args[1]}if(be.indicator!=="[]/0"){b.type.is_variable(be)?w.throw_error(b.error.instantiation(y.indicator)):w.throw_error(b.error.type("list",X,y.indicator));return}else{for(var ot,dt,Gt,$t="",bt=[],an=null;an===null||an.name!=="atom"||an.value!=="."||Gt.type===A&&b.flatten_error(new H("throw",[Gt.value])).found==="token_not_found";){if(ot=Z.stream.get(1,Z.position),ot===null){w.throw_error(b.error.representation("character",y.indicator));return}if(ot==="end_of_file"||ot==="past_end_of_file"){Gt?w.throw_error(b.error.syntax(bt[Gt.len-1],". or expression expected",!1)):w.throw_error(b.error.syntax(null,"token not found",!0));return}Z.position++,$t+=ot,dt=new U(w),dt.new_text($t),bt=dt.get_tokens(),an=bt!==null&&bt.length>0?bt[bt.length-1]:null,bt!==null&&(Gt=V(w,bt,0,w.__get_max_priority(),!1))}if(Gt.type===p&&Gt.len===bt.length-1&&an.value==="."){Gt=Gt.value.rename(w);var Qr=new H("=",[J,Gt]);if(ie.variables){var mr=g(o(Pe(Gt.variables()),function(br){return new Ie(br)}));Qr=new H(",",[Qr,new H("=",[ie.variables,mr])])}if(ie.variable_names){var mr=g(o(Pe(Gt.variables()),function(Wr){var Kn;for(Kn in w.session.renamed_variables)if(w.session.renamed_variables.hasOwnProperty(Kn)&&w.session.renamed_variables[Kn]===Wr)break;return new H("=",[new H(Kn,[]),new Ie(Wr)])}));Qr=new H(",",[Qr,new H("=",[ie.variable_names,mr])])}if(ie.singletons){var mr=g(o(new He(Gt,null).singleton_variables(),function(Wr){var Kn;for(Kn in w.session.renamed_variables)if(w.session.renamed_variables.hasOwnProperty(Kn)&&w.session.renamed_variables[Kn]===Wr)break;return new H("=",[new H(Kn,[]),new Ie(Wr)])}));Qr=new H(",",[Qr,new H("=",[ie.singletons,mr])])}w.prepend([new xe(S.goal.replace(Qr),S.substitution,S)])}else Gt.type===p?w.throw_error(b.error.syntax(bt[Gt.len],"unexpected token",!1)):w.throw_error(Gt.value)}}},"write/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_output",[new Ie("S")]),new H("write",[new Ie("S"),F])])),S.substitution,S)])},"write/2":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H("write_term",[F,J,new H(".",[new H("quoted",[new H("false",[])]),new H(".",[new H("ignore_ops",[new H("false")]),new H(".",[new H("numbervars",[new H("true")]),new H("[]",[])])])])])),S.substitution,S)])},"writeq/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_output",[new Ie("S")]),new H("writeq",[new Ie("S"),F])])),S.substitution,S)])},"writeq/2":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H("write_term",[F,J,new H(".",[new H("quoted",[new H("true",[])]),new H(".",[new H("ignore_ops",[new H("false")]),new H(".",[new H("numbervars",[new H("true")]),new H("[]",[])])])])])),S.substitution,S)])},"write_canonical/1":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_output",[new Ie("S")]),new H("write_canonical",[new Ie("S"),F])])),S.substitution,S)])},"write_canonical/2":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H("write_term",[F,J,new H(".",[new H("quoted",[new H("true",[])]),new H(".",[new H("ignore_ops",[new H("true")]),new H(".",[new H("numbervars",[new H("false")]),new H("[]",[])])])])])),S.substitution,S)])},"write_term/2":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H(",",[new H("current_output",[new Ie("S")]),new H("write_term",[new Ie("S"),F,J])])),S.substitution,S)])},"write_term/3":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2],Z=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F)||b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_list(X))w.throw_error(b.error.type("list",X,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain("stream_or_alias",F,y.indicator));else if(!b.type.is_stream(Z)||Z.stream===null)w.throw_error(b.error.existence("stream",F,y.indicator));else if(Z.input)w.throw_error(b.error.permission("output","stream",F,y.indicator));else if(Z.type==="binary")w.throw_error(b.error.permission("output","binary_stream",F,y.indicator));else if(Z.position==="past_end_of_stream"&&Z.eof_action==="error")w.throw_error(b.error.permission("output","past_end_of_stream",F,y.indicator));else{for(var ie={},be=X,Le;b.type.is_term(be)&&be.indicator==="./2";){if(Le=be.args[0],b.type.is_variable(Le)){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_write_option(Le)){w.throw_error(b.error.domain("write_option",Le,y.indicator));return}ie[Le.id]=Le.args[0].id==="true",be=be.args[1]}if(be.indicator!=="[]/0"){b.type.is_variable(be)?w.throw_error(b.error.instantiation(y.indicator)):w.throw_error(b.error.type("list",X,y.indicator));return}else{ie.session=w.session;var ot=J.toString(ie);Z.stream.put(ot,Z.position),typeof Z.position=="number"&&(Z.position+=ot.length),w.success(S)}}},"halt/0":function(w,S,y){w.points=[]},"halt/1":function(w,S,y){var F=y.args[0];b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_integer(F)?w.points=[]:w.throw_error(b.error.type("integer",F,y.indicator))},"current_prolog_flag/2":function(w,S,y){var F=y.args[0],J=y.args[1];if(!b.type.is_variable(F)&&!b.type.is_atom(F))w.throw_error(b.error.type("atom",F,y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_flag(F))w.throw_error(b.error.domain("prolog_flag",F,y.indicator));else{var X=[];for(var Z in b.flag)if(!!b.flag.hasOwnProperty(Z)){var ie=new H(",",[new H("=",[new H(Z),F]),new H("=",[w.get_flag(Z),J])]);X.push(new xe(S.goal.replace(ie),S.substitution,S))}w.prepend(X)}},"set_prolog_flag/2":function(w,S,y){var F=y.args[0],J=y.args[1];b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_atom(F)?b.type.is_flag(F)?b.type.is_value_flag(F,J)?b.type.is_modifiable_flag(F)?(w.session.flag[F.id]=J,w.success(S)):w.throw_error(b.error.permission("modify","flag",F)):w.throw_error(b.error.domain("flag_value",new H("+",[F,J]),y.indicator)):w.throw_error(b.error.domain("prolog_flag",F,y.indicator)):w.throw_error(b.error.type("atom",F,y.indicator))}},flag:{bounded:{allowed:[new H("true"),new H("false")],value:new H("true"),changeable:!1},max_integer:{allowed:[new Fe(Number.MAX_SAFE_INTEGER)],value:new Fe(Number.MAX_SAFE_INTEGER),changeable:!1},min_integer:{allowed:[new Fe(Number.MIN_SAFE_INTEGER)],value:new Fe(Number.MIN_SAFE_INTEGER),changeable:!1},integer_rounding_function:{allowed:[new H("down"),new H("toward_zero")],value:new H("toward_zero"),changeable:!1},char_conversion:{allowed:[new H("on"),new H("off")],value:new H("on"),changeable:!0},debug:{allowed:[new H("on"),new H("off")],value:new H("off"),changeable:!0},max_arity:{allowed:[new H("unbounded")],value:new H("unbounded"),changeable:!1},unknown:{allowed:[new H("error"),new H("fail"),new H("warning")],value:new H("error"),changeable:!0},double_quotes:{allowed:[new H("chars"),new H("codes"),new H("atom")],value:new H("codes"),changeable:!0},occurs_check:{allowed:[new H("false"),new H("true")],value:new H("false"),changeable:!0},dialect:{allowed:[new H("tau")],value:new H("tau"),changeable:!1},version_data:{allowed:[new H("tau",[new Fe(t.major,!1),new Fe(t.minor,!1),new Fe(t.patch,!1),new H(t.status)])],value:new H("tau",[new Fe(t.major,!1),new Fe(t.minor,!1),new Fe(t.patch,!1),new H(t.status)]),changeable:!1},nodejs:{allowed:[new H("yes"),new H("no")],value:new H(typeof gl<"u"&&gl.exports?"yes":"no"),changeable:!1}},unify:function(w,S,y){y=y===void 0?!1:y;for(var F=[{left:w,right:S}],J={};F.length!==0;){var X=F.pop();if(w=X.left,S=X.right,b.type.is_term(w)&&b.type.is_term(S)){if(w.indicator!==S.indicator)return null;for(var Z=0;Z<w.args.length;Z++)F.push({left:w.args[Z],right:S.args[Z]})}else if(b.type.is_number(w)&&b.type.is_number(S)){if(w.value!==S.value||w.is_float!==S.is_float)return null}else if(b.type.is_variable(w)){if(b.type.is_variable(S)&&w.id===S.id)continue;if(y===!0&&S.variables().indexOf(w.id)!==-1)return null;if(w.id!=="_"){var ie=new ke;ie.add(w.id,S);for(var Z=0;Z<F.length;Z++)F[Z].left=F[Z].left.apply(ie),F[Z].right=F[Z].right.apply(ie);for(var Z in J)J[Z]=J[Z].apply(ie);J[w.id]=S}}else if(b.type.is_variable(S))F.push({left:S,right:w});else if(w.unify!==void 0){if(!w.unify(S))return null}else return null}return new ke(J)},compare:function(w,S){var y=b.type.compare(w,S);return y!==0?y:w.compare(S)},arithmetic_compare:function(w,S,y){var F=S.interpret(w);if(b.type.is_number(F)){var J=y.interpret(w);return b.type.is_number(J)?F.value<J.value?-1:F.value>J.value?1:0:J}else return F},operate:function(w,S){if(b.type.is_operator(S)){for(var y=b.type.is_operator(S),F=[],J,X=!1,Z=0;Z<S.args.length;Z++){if(J=S.args[Z].interpret(w),b.type.is_number(J)){if(y.type_args!==null&&J.is_float!==y.type_args)return b.error.type(y.type_args?"float":"integer",J,w.__call_indicator);F.push(J.value)}else return J;X=X||J.is_float}return F.push(w),J=b.arithmetic.evaluation[S.indicator].fn.apply(this,F),X=y.type_result===null?X:y.type_result,b.type.is_term(J)?J:J===Number.POSITIVE_INFINITY||J===Number.NEGATIVE_INFINITY?b.error.evaluation("overflow",w.__call_indicator):X===!1&&w.get_flag("bounded").id==="true"&&(J>w.get_flag("max_integer").value||J<w.get_flag("min_integer").value)?b.error.evaluation("int_overflow",w.__call_indicator):new Fe(J,X)}else return b.error.type("evaluable",S.indicator,w.__call_indicator)},error:{existence:function(w,S,y){return typeof S=="string"&&(S=ee(S)),new H("error",[new H("existence_error",[new H(w),S]),ee(y)])},type:function(w,S,y){return new H("error",[new H("type_error",[new H(w),S]),ee(y)])},instantiation:function(w){return new H("error",[new H("instantiation_error"),ee(w)])},domain:function(w,S,y){return new H("error",[new H("domain_error",[new H(w),S]),ee(y)])},representation:function(w,S){return new H("error",[new H("representation_error",[new H(w)]),ee(S)])},permission:function(w,S,y,F){return new H("error",[new H("permission_error",[new H(w),new H(S),y]),ee(F)])},evaluation:function(w,S){return new H("error",[new H("evaluation_error",[new H(w)]),ee(S)])},syntax:function(w,S,y){w=w||{value:"",line:0,column:0,matches:[""],start:0};var F=y&&w.matches.length>0?w.start+w.matches[0].length:w.start,J=y?new H("token_not_found"):new H("found",[new H(w.value.toString())]),X=new H(".",[new H("line",[new Fe(w.line+1)]),new H(".",[new H("column",[new Fe(F+1)]),new H(".",[J,new H("[]",[])])])]);return new H("error",[new H("syntax_error",[new H(S)]),X])},syntax_by_predicate:function(w,S){return new H("error",[new H("syntax_error",[new H(w)]),ee(S)])}},warning:{singleton:function(w,S,y){for(var F=new H("[]"),J=w.length-1;J>=0;J--)F=new H(".",[new Ie(w[J]),F]);return new H("warning",[new H("singleton_variables",[F,ee(S)]),new H(".",[new H("line",[new Fe(y,!1)]),new H("[]")])])},failed_goal:function(w,S){return new H("warning",[new H("failed_goal",[w]),new H(".",[new H("line",[new Fe(S,!1)]),new H("[]")])])}},format_variable:function(w){return"_"+w},format_answer:function(w,S,F){S instanceof Te&&(S=S.thread);var F=F||{};if(F.session=S?S.session:void 0,b.type.is_error(w))return"uncaught exception: "+w.args[0].toString();if(w===!1)return"false.";if(w===null)return"limit exceeded ;";var J=0,X="";if(b.type.is_substitution(w)){var Z=w.domain(!0);w=w.filter(function(Le,ot){return!b.type.is_variable(ot)||Z.indexOf(ot.id)!==-1&&Le!==ot.id})}for(var ie in w.links)!w.links.hasOwnProperty(ie)||(J++,X!==""&&(X+=", "),X+=ie.toString(F)+" = "+w.links[ie].toString(F));var be=typeof S>"u"||S.points.length>0?" ;":".";return J===0?"true"+be:X+be},flatten_error:function(w){if(!b.type.is_error(w))return null;w=w.args[0];var S={};return S.type=w.args[0].id,S.thrown=S.type==="syntax_error"?null:w.args[1].id,S.expected=null,S.found=null,S.representation=null,S.existence=null,S.existence_type=null,S.line=null,S.column=null,S.permission_operation=null,S.permission_type=null,S.evaluation_type=null,S.type==="type_error"||S.type==="domain_error"?(S.expected=w.args[0].args[0].id,S.found=w.args[0].args[1].toString()):S.type==="syntax_error"?w.args[1].indicator==="./2"?(S.expected=w.args[0].args[0].id,S.found=w.args[1].args[1].args[1].args[0],S.found=S.found.id==="token_not_found"?S.found.id:S.found.args[0].id,S.line=w.args[1].args[0].args[0].value,S.column=w.args[1].args[1].args[0].args[0].value):S.thrown=w.args[1].id:S.type==="permission_error"?(S.found=w.args[0].args[2].toString(),S.permission_operation=w.args[0].args[0].id,S.permission_type=w.args[0].args[1].id):S.type==="evaluation_error"?S.evaluation_type=w.args[0].args[0].id:S.type==="representation_error"?S.representation=w.args[0].args[0].id:S.type==="existence_error"&&(S.existence=w.args[0].args[1].toString(),S.existence_type=w.args[0].args[0].id),S},create:function(w){return new b.type.Session(w)}};typeof gl<"u"?gl.exports=b:window.pl=b})()});function sme(t,e,r){t.prepend(r.map(o=>new Ta.default.type.State(e.goal.replace(o),e.substitution,e)))}function yH(t){let e=ame.get(t.session);if(e==null)throw new Error("Assertion failed: A project should have been registered for the active session");return e}function lme(t,e){ame.set(t,e),t.consult(`:- use_module(library(${Xgt.id})).`)}var EH,Ta,ome,A0,Vgt,Jgt,ame,Xgt,cme=Et(()=>{Ye();EH=$e(d2()),Ta=$e(mH()),ome=$e(ve("vm")),{is_atom:A0,is_variable:Vgt,is_instantiated_list:Jgt}=Ta.default.type;ame=new WeakMap;Xgt=new Ta.default.type.Module("constraints",{["project_workspaces_by_descriptor/3"]:(t,e,r)=>{let[o,a,n]=r.args;if(!A0(o)||!A0(a)){t.throw_error(Ta.default.error.instantiation(r.indicator));return}let u=W.parseIdent(o.id),A=W.makeDescriptor(u,a.id),h=yH(t).tryWorkspaceByDescriptor(A);Vgt(n)&&h!==null&&sme(t,e,[new Ta.default.type.Term("=",[n,new Ta.default.type.Term(String(h.relativeCwd))])]),A0(n)&&h!==null&&h.relativeCwd===n.id&&t.success(e)},["workspace_field/3"]:(t,e,r)=>{let[o,a,n]=r.args;if(!A0(o)||!A0(a)){t.throw_error(Ta.default.error.instantiation(r.indicator));return}let A=yH(t).tryWorkspaceByCwd(o.id);if(A==null)return;let p=(0,EH.default)(A.manifest.raw,a.id);typeof p>"u"||sme(t,e,[new Ta.default.type.Term("=",[n,new Ta.default.type.Term(typeof p=="object"?JSON.stringify(p):p)])])},["workspace_field_test/3"]:(t,e,r)=>{let[o,a,n]=r.args;t.prepend([new Ta.default.type.State(e.goal.replace(new Ta.default.type.Term("workspace_field_test",[o,a,n,new Ta.default.type.Term("[]",[])])),e.substitution,e)])},["workspace_field_test/4"]:(t,e,r)=>{let[o,a,n,u]=r.args;if(!A0(o)||!A0(a)||!A0(n)||!Jgt(u)){t.throw_error(Ta.default.error.instantiation(r.indicator));return}let p=yH(t).tryWorkspaceByCwd(o.id);if(p==null)return;let h=(0,EH.default)(p.manifest.raw,a.id);if(typeof h>"u")return;let E={$$:h};for(let[v,x]of u.toJavaScript().entries())E[`$${v}`]=x;ome.default.runInNewContext(n.id,E)&&t.success(e)}},["project_workspaces_by_descriptor/3","workspace_field/3","workspace_field_test/3","workspace_field_test/4"])});var b2={};zt(b2,{Constraints:()=>S2,DependencyType:()=>pme});function to(t){if(t instanceof DC.default.type.Num)return t.value;if(t instanceof DC.default.type.Term)switch(t.indicator){case"throw/1":return to(t.args[0]);case"error/1":return to(t.args[0]);case"error/2":if(t.args[0]instanceof DC.default.type.Term&&t.args[0].indicator==="syntax_error/1")return Object.assign(to(t.args[0]),...to(t.args[1]));{let e=to(t.args[0]);return e.message+=` (in ${to(t.args[1])})`,e}case"syntax_error/1":return new Jt(43,`Syntax error: ${to(t.args[0])}`);case"existence_error/2":return new Jt(44,`Existence error: ${to(t.args[0])} ${to(t.args[1])} not found`);case"instantiation_error/0":return new Jt(75,"Instantiation error: an argument is variable when an instantiated argument was expected");case"line/1":return{line:to(t.args[0])};case"column/1":return{column:to(t.args[0])};case"found/1":return{found:to(t.args[0])};case"./2":return[to(t.args[0])].concat(to(t.args[1]));case"//2":return`${to(t.args[0])}/${to(t.args[1])}`;default:return t.id}throw`couldn't pretty print because of unsupported node ${t}`}function Ame(t){let e;try{e=to(t)}catch(r){throw typeof r=="string"?new Jt(42,`Unknown error: ${t} (note: ${r})`):r}return typeof e.line<"u"&&typeof e.column<"u"&&(e.message+=` at line ${e.line}, column ${e.column}`),e}function tm(t){return t.id==="null"?null:`${t.toJavaScript()}`}function Zgt(t){if(t.id==="null")return null;{let e=t.toJavaScript();if(typeof e!="string")return JSON.stringify(e);try{return JSON.stringify(JSON.parse(e))}catch{return JSON.stringify(e)}}}function f0(t){return typeof t=="string"?`'${t}'`:"[]"}var fme,DC,pme,ume,CH,S2,x2=Et(()=>{Ye();Ye();Pt();fme=$e(Gde()),DC=$e(mH());v2();cme();(0,fme.default)(DC.default);pme=(o=>(o.Dependencies="dependencies",o.DevDependencies="devDependencies",o.PeerDependencies="peerDependencies",o))(pme||{}),ume=["dependencies","devDependencies","peerDependencies"];CH=class{constructor(e,r){let o=1e3*e.workspaces.length;this.session=DC.default.create(o),lme(this.session,e),this.session.consult(":- use_module(library(lists))."),this.session.consult(r)}fetchNextAnswer(){return new Promise(e=>{this.session.answer(r=>{e(r)})})}async*makeQuery(e){let r=this.session.query(e);if(r!==!0)throw Ame(r);for(;;){let o=await this.fetchNextAnswer();if(o===null)throw new Jt(79,"Resolution limit exceeded");if(!o)break;if(o.id==="throw")throw Ame(o);yield o}}};S2=class{constructor(e){this.source="";this.project=e;let r=e.configuration.get("constraintsPath");oe.existsSync(r)&&(this.source=oe.readFileSync(r,"utf8"))}static async find(e){return new S2(e)}getProjectDatabase(){let e="";for(let r of ume)e+=`dependency_type(${r}).
-`;for(let r of this.project.workspacesByCwd.values()){let o=r.relativeCwd;e+=`workspace(${f0(o)}).
-`,e+=`workspace_ident(${f0(o)}, ${f0(W.stringifyIdent(r.anchoredLocator))}).
-`,e+=`workspace_version(${f0(o)}, ${f0(r.manifest.version)}).
-`;for(let a of ume)for(let n of r.manifest[a].values())e+=`workspace_has_dependency(${f0(o)}, ${f0(W.stringifyIdent(n))}, ${f0(n.range)}, ${a}).
-`}return e+=`workspace(_) :- false.
-`,e+=`workspace_ident(_, _) :- false.
-`,e+=`workspace_version(_, _) :- false.
-`,e+=`workspace_has_dependency(_, _, _, _) :- false.
-`,e}getDeclarations(){let e="";return e+=`gen_enforced_dependency(_, _, _, _) :- false.
-`,e+=`gen_enforced_field(_, _, _) :- false.
-`,e}get fullSource(){return`${this.getProjectDatabase()}
-${this.source}
-${this.getDeclarations()}`}createSession(){return new CH(this.project,this.fullSource)}async processClassic(){let e=this.createSession();return{enforcedDependencies:await this.genEnforcedDependencies(e),enforcedFields:await this.genEnforcedFields(e)}}async process(){let{enforcedDependencies:e,enforcedFields:r}=await this.processClassic(),o=new Map;for(let{workspace:a,dependencyIdent:n,dependencyRange:u,dependencyType:A}of e){let p=B2([A,W.stringifyIdent(n)]),h=_e.getMapWithDefault(o,a.cwd);_e.getMapWithDefault(h,p).set(u??void 0,new Set)}for(let{workspace:a,fieldPath:n,fieldValue:u}of r){let A=B2(n),p=_e.getMapWithDefault(o,a.cwd);_e.getMapWithDefault(p,A).set(JSON.parse(u)??void 0,new Set)}return{manifestUpdates:o,reportedErrors:new Map}}async genEnforcedDependencies(e){let r=[];for await(let o of e.makeQuery("workspace(WorkspaceCwd), dependency_type(DependencyType), gen_enforced_dependency(WorkspaceCwd, DependencyIdent, DependencyRange, DependencyType).")){let a=z.resolve(this.project.cwd,tm(o.links.WorkspaceCwd)),n=tm(o.links.DependencyIdent),u=tm(o.links.DependencyRange),A=tm(o.links.DependencyType);if(a===null||n===null)throw new Error("Invalid rule");let p=this.project.getWorkspaceByCwd(a),h=W.parseIdent(n);r.push({workspace:p,dependencyIdent:h,dependencyRange:u,dependencyType:A})}return _e.sortMap(r,[({dependencyRange:o})=>o!==null?"0":"1",({workspace:o})=>W.stringifyIdent(o.anchoredLocator),({dependencyIdent:o})=>W.stringifyIdent(o)])}async genEnforcedFields(e){let r=[];for await(let o of e.makeQuery("workspace(WorkspaceCwd), gen_enforced_field(WorkspaceCwd, FieldPath, FieldValue).")){let a=z.resolve(this.project.cwd,tm(o.links.WorkspaceCwd)),n=tm(o.links.FieldPath),u=Zgt(o.links.FieldValue);if(a===null||n===null)throw new Error("Invalid rule");let A=this.project.getWorkspaceByCwd(a);r.push({workspace:A,fieldPath:n,fieldValue:u})}return _e.sortMap(r,[({workspace:o})=>W.stringifyIdent(o.anchoredLocator),({fieldPath:o})=>o])}async*query(e){let r=this.createSession();for await(let o of r.makeQuery(e)){let a={};for(let[n,u]of Object.entries(o.links))n!=="_"&&(a[n]=tm(u));yield a}}}});var Ime=_(Ik=>{"use strict";Object.defineProperty(Ik,"__esModule",{value:!0});function j2(t){let e=[...t.caches],r=e.shift();return r===void 0?wme():{get(o,a,n={miss:()=>Promise.resolve()}){return r.get(o,a,n).catch(()=>j2({caches:e}).get(o,a,n))},set(o,a){return r.set(o,a).catch(()=>j2({caches:e}).set(o,a))},delete(o){return r.delete(o).catch(()=>j2({caches:e}).delete(o))},clear(){return r.clear().catch(()=>j2({caches:e}).clear())}}}function wme(){return{get(t,e,r={miss:()=>Promise.resolve()}){return e().then(a=>Promise.all([a,r.miss(a)])).then(([a])=>a)},set(t,e){return Promise.resolve(e)},delete(t){return Promise.resolve()},clear(){return Promise.resolve()}}}Ik.createFallbackableCache=j2;Ik.createNullCache=wme});var vme=_((FWt,Bme)=>{Bme.exports=Ime()});var Dme=_(TH=>{"use strict";Object.defineProperty(TH,"__esModule",{value:!0});function mdt(t={serializable:!0}){let e={};return{get(r,o,a={miss:()=>Promise.resolve()}){let n=JSON.stringify(r);if(n in e)return Promise.resolve(t.serializable?JSON.parse(e[n]):e[n]);let u=o(),A=a&&a.miss||(()=>Promise.resolve());return u.then(p=>A(p)).then(()=>u)},set(r,o){return e[JSON.stringify(r)]=t.serializable?JSON.stringify(o):o,Promise.resolve(o)},delete(r){return delete e[JSON.stringify(r)],Promise.resolve()},clear(){return e={},Promise.resolve()}}}TH.createInMemoryCache=mdt});var Sme=_((TWt,Pme)=>{Pme.exports=Dme()});var xme=_($c=>{"use strict";Object.defineProperty($c,"__esModule",{value:!0});function ydt(t,e,r){let o={"x-algolia-api-key":r,"x-algolia-application-id":e};return{headers(){return t===LH.WithinHeaders?o:{}},queryParameters(){return t===LH.WithinQueryParameters?o:{}}}}function Edt(t){let e=0,r=()=>(e++,new Promise(o=>{setTimeout(()=>{o(t(r))},Math.min(100*e,1e3))}));return t(r)}function bme(t,e=(r,o)=>Promise.resolve()){return Object.assign(t,{wait(r){return bme(t.then(o=>Promise.all([e(o,r),o])).then(o=>o[1]))}})}function Cdt(t){let e=t.length-1;for(e;e>0;e--){let r=Math.floor(Math.random()*(e+1)),o=t[e];t[e]=t[r],t[r]=o}return t}function wdt(t,e){return e&&Object.keys(e).forEach(r=>{t[r]=e[r](t)}),t}function Idt(t,...e){let r=0;return t.replace(/%s/g,()=>encodeURIComponent(e[r++]))}var Bdt="4.22.1",vdt=t=>()=>t.transporter.requester.destroy(),LH={WithinQueryParameters:0,WithinHeaders:1};$c.AuthMode=LH;$c.addMethods=wdt;$c.createAuth=ydt;$c.createRetryablePromise=Edt;$c.createWaitablePromise=bme;$c.destroy=vdt;$c.encode=Idt;$c.shuffle=Cdt;$c.version=Bdt});var Y2=_((NWt,kme)=>{kme.exports=xme()});var Qme=_(NH=>{"use strict";Object.defineProperty(NH,"__esModule",{value:!0});var Ddt={Delete:"DELETE",Get:"GET",Post:"POST",Put:"PUT"};NH.MethodEnum=Ddt});var W2=_((MWt,Fme)=>{Fme.exports=Qme()});var Kme=_(Fi=>{"use strict";Object.defineProperty(Fi,"__esModule",{value:!0});var Tme=W2();function OH(t,e){let r=t||{},o=r.data||{};return Object.keys(r).forEach(a=>{["timeout","headers","queryParameters","data","cacheable"].indexOf(a)===-1&&(o[a]=r[a])}),{data:Object.entries(o).length>0?o:void 0,timeout:r.timeout||e,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var K2={Read:1,Write:2,Any:3},xC={Up:1,Down:2,Timeouted:3},Lme=2*60*1e3;function UH(t,e=xC.Up){return{...t,status:e,lastUpdate:Date.now()}}function Nme(t){return t.status===xC.Up||Date.now()-t.lastUpdate>Lme}function Ome(t){return t.status===xC.Timeouted&&Date.now()-t.lastUpdate<=Lme}function _H(t){return typeof t=="string"?{protocol:"https",url:t,accept:K2.Any}:{protocol:t.protocol||"https",url:t.url,accept:t.accept||K2.Any}}function Pdt(t,e){return Promise.all(e.map(r=>t.get(r,()=>Promise.resolve(UH(r))))).then(r=>{let o=r.filter(A=>Nme(A)),a=r.filter(A=>Ome(A)),n=[...o,...a],u=n.length>0?n.map(A=>_H(A)):e;return{getTimeout(A,p){return(a.length===0&&A===0?1:a.length+3+A)*p},statelessHosts:u}})}var Sdt=({isTimedOut:t,status:e})=>!t&&~~e===0,bdt=t=>{let e=t.status;return t.isTimedOut||Sdt(t)||~~(e/100)!==2&&~~(e/100)!==4},xdt=({status:t})=>~~(t/100)===2,kdt=(t,e)=>bdt(t)?e.onRetry(t):xdt(t)?e.onSuccess(t):e.onFail(t);function Rme(t,e,r,o){let a=[],n=qme(r,o),u=Gme(t,o),A=r.method,p=r.method!==Tme.MethodEnum.Get?{}:{...r.data,...o.data},h={"x-algolia-agent":t.userAgent.value,...t.queryParameters,...p,...o.queryParameters},E=0,I=(v,x)=>{let C=v.pop();if(C===void 0)throw Wme(MH(a));let R={data:n,headers:u,method:A,url:_me(C,r.path,h),connectTimeout:x(E,t.timeouts.connect),responseTimeout:x(E,o.timeout)},N=V=>{let te={request:R,response:V,host:C,triesLeft:v.length};return a.push(te),te},U={onSuccess:V=>Mme(V),onRetry(V){let te=N(V);return V.isTimedOut&&E++,Promise.all([t.logger.info("Retryable failure",HH(te)),t.hostsCache.set(C,UH(C,V.isTimedOut?xC.Timeouted:xC.Down))]).then(()=>I(v,x))},onFail(V){throw N(V),Ume(V,MH(a))}};return t.requester.send(R).then(V=>kdt(V,U))};return Pdt(t.hostsCache,e).then(v=>I([...v.statelessHosts].reverse(),v.getTimeout))}function Qdt(t){let{hostsCache:e,logger:r,requester:o,requestsCache:a,responsesCache:n,timeouts:u,userAgent:A,hosts:p,queryParameters:h,headers:E}=t,I={hostsCache:e,logger:r,requester:o,requestsCache:a,responsesCache:n,timeouts:u,userAgent:A,headers:E,queryParameters:h,hosts:p.map(v=>_H(v)),read(v,x){let C=OH(x,I.timeouts.read),R=()=>Rme(I,I.hosts.filter(V=>(V.accept&K2.Read)!==0),v,C);if((C.cacheable!==void 0?C.cacheable:v.cacheable)!==!0)return R();let U={request:v,mappedRequestOptions:C,transporter:{queryParameters:I.queryParameters,headers:I.headers}};return I.responsesCache.get(U,()=>I.requestsCache.get(U,()=>I.requestsCache.set(U,R()).then(V=>Promise.all([I.requestsCache.delete(U),V]),V=>Promise.all([I.requestsCache.delete(U),Promise.reject(V)])).then(([V,te])=>te)),{miss:V=>I.responsesCache.set(U,V)})},write(v,x){return Rme(I,I.hosts.filter(C=>(C.accept&K2.Write)!==0),v,OH(x,I.timeouts.write))}};return I}function Fdt(t){let e={value:`Algolia for JavaScript (${t})`,add(r){let o=`; ${r.segment}${r.version!==void 0?` (${r.version})`:""}`;return e.value.indexOf(o)===-1&&(e.value=`${e.value}${o}`),e}};return e}function Mme(t){try{return JSON.parse(t.content)}catch(e){throw Yme(e.message,t)}}function Ume({content:t,status:e},r){let o=t;try{o=JSON.parse(t).message}catch{}return jme(o,e,r)}function Rdt(t,...e){let r=0;return t.replace(/%s/g,()=>encodeURIComponent(e[r++]))}function _me(t,e,r){let o=Hme(r),a=`${t.protocol}://${t.url}/${e.charAt(0)==="/"?e.substr(1):e}`;return o.length&&(a+=`?${o}`),a}function Hme(t){let e=r=>Object.prototype.toString.call(r)==="[object Object]"||Object.prototype.toString.call(r)==="[object Array]";return Object.keys(t).map(r=>Rdt("%s=%s",r,e(t[r])?JSON.stringify(t[r]):t[r])).join("&")}function qme(t,e){if(t.method===Tme.MethodEnum.Get||t.data===void 0&&e.data===void 0)return;let r=Array.isArray(t.data)?t.data:{...t.data,...e.data};return JSON.stringify(r)}function Gme(t,e){let r={...t.headers,...e.headers},o={};return Object.keys(r).forEach(a=>{let n=r[a];o[a.toLowerCase()]=n}),o}function MH(t){return t.map(e=>HH(e))}function HH(t){let e=t.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return{...t,request:{...t.request,headers:{...t.request.headers,...e}}}}function jme(t,e,r){return{name:"ApiError",message:t,status:e,transporterStackTrace:r}}function Yme(t,e){return{name:"DeserializationError",message:t,response:e}}function Wme(t){return{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:t}}Fi.CallEnum=K2;Fi.HostStatusEnum=xC;Fi.createApiError=jme;Fi.createDeserializationError=Yme;Fi.createMappedRequestOptions=OH;Fi.createRetryError=Wme;Fi.createStatefulHost=UH;Fi.createStatelessHost=_H;Fi.createTransporter=Qdt;Fi.createUserAgent=Fdt;Fi.deserializeFailure=Ume;Fi.deserializeSuccess=Mme;Fi.isStatefulHostTimeouted=Ome;Fi.isStatefulHostUp=Nme;Fi.serializeData=qme;Fi.serializeHeaders=Gme;Fi.serializeQueryParameters=Hme;Fi.serializeUrl=_me;Fi.stackFrameWithoutCredentials=HH;Fi.stackTraceWithoutCredentials=MH});var z2=_((_Wt,zme)=>{zme.exports=Kme()});var Vme=_(y0=>{"use strict";Object.defineProperty(y0,"__esModule",{value:!0});var kC=Y2(),Tdt=z2(),V2=W2(),Ldt=t=>{let e=t.region||"us",r=kC.createAuth(kC.AuthMode.WithinHeaders,t.appId,t.apiKey),o=Tdt.createTransporter({hosts:[{url:`analytics.${e}.algolia.com`}],...t,headers:{...r.headers(),"content-type":"application/json",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}}),a=t.appId;return kC.addMethods({appId:a,transporter:o},t.methods)},Ndt=t=>(e,r)=>t.transporter.write({method:V2.MethodEnum.Post,path:"2/abtests",data:e},r),Odt=t=>(e,r)=>t.transporter.write({method:V2.MethodEnum.Delete,path:kC.encode("2/abtests/%s",e)},r),Mdt=t=>(e,r)=>t.transporter.read({method:V2.MethodEnum.Get,path:kC.encode("2/abtests/%s",e)},r),Udt=t=>e=>t.transporter.read({method:V2.MethodEnum.Get,path:"2/abtests"},e),_dt=t=>(e,r)=>t.transporter.write({method:V2.MethodEnum.Post,path:kC.encode("2/abtests/%s/stop",e)},r);y0.addABTest=Ndt;y0.createAnalyticsClient=Ldt;y0.deleteABTest=Odt;y0.getABTest=Mdt;y0.getABTests=Udt;y0.stopABTest=_dt});var Xme=_((qWt,Jme)=>{Jme.exports=Vme()});var $me=_(J2=>{"use strict";Object.defineProperty(J2,"__esModule",{value:!0});var qH=Y2(),Hdt=z2(),Zme=W2(),qdt=t=>{let e=t.region||"us",r=qH.createAuth(qH.AuthMode.WithinHeaders,t.appId,t.apiKey),o=Hdt.createTransporter({hosts:[{url:`personalization.${e}.algolia.com`}],...t,headers:{...r.headers(),"content-type":"application/json",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}});return qH.addMethods({appId:t.appId,transporter:o},t.methods)},Gdt=t=>e=>t.transporter.read({method:Zme.MethodEnum.Get,path:"1/strategies/personalization"},e),jdt=t=>(e,r)=>t.transporter.write({method:Zme.MethodEnum.Post,path:"1/strategies/personalization",data:e},r);J2.createPersonalizationClient=qdt;J2.getPersonalizationStrategy=Gdt;J2.setPersonalizationStrategy=jdt});var tye=_((jWt,eye)=>{eye.exports=$me()});var gye=_(Ft=>{"use strict";Object.defineProperty(Ft,"__esModule",{value:!0});var jt=Y2(),La=z2(),Ir=W2(),Ydt=ve("crypto");function Bk(t){let e=r=>t.request(r).then(o=>{if(t.batch!==void 0&&t.batch(o.hits),!t.shouldStop(o))return o.cursor?e({cursor:o.cursor}):e({page:(r.page||0)+1})});return e({})}var Wdt=t=>{let e=t.appId,r=jt.createAuth(t.authMode!==void 0?t.authMode:jt.AuthMode.WithinHeaders,e,t.apiKey),o=La.createTransporter({hosts:[{url:`${e}-dsn.algolia.net`,accept:La.CallEnum.Read},{url:`${e}.algolia.net`,accept:La.CallEnum.Write}].concat(jt.shuffle([{url:`${e}-1.algolianet.com`},{url:`${e}-2.algolianet.com`},{url:`${e}-3.algolianet.com`}])),...t,headers:{...r.headers(),"content-type":"application/x-www-form-urlencoded",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}}),a={transporter:o,appId:e,addAlgoliaAgent(n,u){o.userAgent.add({segment:n,version:u})},clearCache(){return Promise.all([o.requestsCache.clear(),o.responsesCache.clear()]).then(()=>{})}};return jt.addMethods(a,t.methods)};function rye(){return{name:"MissingObjectIDError",message:"All objects must have an unique objectID (like a primary key) to be valid. Algolia is also able to generate objectIDs automatically but *it's not recommended*. To do it, use the `{'autoGenerateObjectIDIfNotExist': true}` option."}}function nye(){return{name:"ObjectNotFoundError",message:"Object not found."}}function iye(){return{name:"ValidUntilNotFoundError",message:"ValidUntil not found in given secured api key."}}var Kdt=t=>(e,r)=>{let{queryParameters:o,...a}=r||{},n={acl:e,...o!==void 0?{queryParameters:o}:{}},u=(A,p)=>jt.createRetryablePromise(h=>X2(t)(A.key,p).catch(E=>{if(E.status!==404)throw E;return h()}));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:"1/keys",data:n},a),u)},zdt=t=>(e,r,o)=>{let a=La.createMappedRequestOptions(o);return a.queryParameters["X-Algolia-User-ID"]=e,t.transporter.write({method:Ir.MethodEnum.Post,path:"1/clusters/mapping",data:{cluster:r}},a)},Vdt=t=>(e,r,o)=>t.transporter.write({method:Ir.MethodEnum.Post,path:"1/clusters/mapping/batch",data:{users:e,cluster:r}},o),Jdt=t=>(e,r)=>jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!0,requests:{action:"addEntry",body:[]}}},r),(o,a)=>QC(t)(o.taskID,a)),vk=t=>(e,r,o)=>{let a=(n,u)=>Z2(t)(e,{methods:{waitTask:Zi}}).waitTask(n.taskID,u);return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/operation",e),data:{operation:"copy",destination:r}},o),a)},Xdt=t=>(e,r,o)=>vk(t)(e,r,{...o,scope:[Pk.Rules]}),Zdt=t=>(e,r,o)=>vk(t)(e,r,{...o,scope:[Pk.Settings]}),$dt=t=>(e,r,o)=>vk(t)(e,r,{...o,scope:[Pk.Synonyms]}),emt=t=>(e,r)=>e.method===Ir.MethodEnum.Get?t.transporter.read(e,r):t.transporter.write(e,r),tmt=t=>(e,r)=>{let o=(a,n)=>jt.createRetryablePromise(u=>X2(t)(e,n).then(u).catch(A=>{if(A.status!==404)throw A}));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:jt.encode("1/keys/%s",e)},r),o)},rmt=t=>(e,r,o)=>{let a=r.map(n=>({action:"deleteEntry",body:{objectID:n}}));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!1,requests:a}},o),(n,u)=>QC(t)(n.taskID,u))},nmt=()=>(t,e)=>{let r=La.serializeQueryParameters(e),o=Ydt.createHmac("sha256",t).update(r).digest("hex");return Buffer.from(o+r).toString("base64")},X2=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode("1/keys/%s",e)},r),sye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode("1/task/%s",e.toString())},r),imt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:"/1/dictionaries/*/settings"},e),smt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:"1/logs"},e),omt=()=>t=>{let e=Buffer.from(t,"base64").toString("ascii"),r=/validUntil=(\d+)/,o=e.match(r);if(o===null)throw iye();return parseInt(o[1],10)-Math.round(new Date().getTime()/1e3)},amt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:"1/clusters/mapping/top"},e),lmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode("1/clusters/mapping/%s",e)},r),cmt=t=>e=>{let{retrieveMappings:r,...o}=e||{};return r===!0&&(o.getClusters=!0),t.transporter.read({method:Ir.MethodEnum.Get,path:"1/clusters/mapping/pending"},o)},Z2=t=>(e,r={})=>{let o={transporter:t.transporter,appId:t.appId,indexName:e};return jt.addMethods(o,r.methods)},umt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:"1/keys"},e),Amt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:"1/clusters"},e),fmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:"1/indexes"},e),pmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:"1/clusters/mapping"},e),hmt=t=>(e,r,o)=>{let a=(n,u)=>Z2(t)(e,{methods:{waitTask:Zi}}).waitTask(n.taskID,u);return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/operation",e),data:{operation:"move",destination:r}},o),a)},gmt=t=>(e,r)=>{let o=(a,n)=>Promise.all(Object.keys(a.taskID).map(u=>Z2(t)(u,{methods:{waitTask:Zi}}).waitTask(a.taskID[u],n)));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:"1/indexes/*/batch",data:{requests:e}},r),o)},dmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:"1/indexes/*/objects",data:{requests:e}},r),mmt=t=>(e,r)=>{let o=e.map(a=>({...a,params:La.serializeQueryParameters(a.params||{})}));return t.transporter.read({method:Ir.MethodEnum.Post,path:"1/indexes/*/queries",data:{requests:o},cacheable:!0},r)},ymt=t=>(e,r)=>Promise.all(e.map(o=>{let{facetName:a,facetQuery:n,...u}=o.params;return Z2(t)(o.indexName,{methods:{searchForFacetValues:fye}}).searchForFacetValues(a,n,{...r,...u})})),Emt=t=>(e,r)=>{let o=La.createMappedRequestOptions(r);return o.queryParameters["X-Algolia-User-ID"]=e,t.transporter.write({method:Ir.MethodEnum.Delete,path:"1/clusters/mapping"},o)},Cmt=t=>(e,r,o)=>{let a=r.map(n=>({action:"addEntry",body:n}));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!0,requests:a}},o),(n,u)=>QC(t)(n.taskID,u))},wmt=t=>(e,r)=>{let o=(a,n)=>jt.createRetryablePromise(u=>X2(t)(e,n).catch(A=>{if(A.status!==404)throw A;return u()}));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("1/keys/%s/restore",e)},r),o)},Imt=t=>(e,r,o)=>{let a=r.map(n=>({action:"addEntry",body:n}));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!1,requests:a}},o),(n,u)=>QC(t)(n.taskID,u))},Bmt=t=>(e,r,o)=>t.transporter.read({method:Ir.MethodEnum.Post,path:jt.encode("/1/dictionaries/%s/search",e),data:{query:r},cacheable:!0},o),vmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:"1/clusters/mapping/search",data:{query:e}},r),Dmt=t=>(e,r)=>jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Put,path:"/1/dictionaries/*/settings",data:e},r),(o,a)=>QC(t)(o.taskID,a)),Pmt=t=>(e,r)=>{let o=Object.assign({},r),{queryParameters:a,...n}=r||{},u=a?{queryParameters:a}:{},A=["acl","indexes","referers","restrictSources","queryParameters","description","maxQueriesPerIPPerHour","maxHitsPerQuery"],p=E=>Object.keys(o).filter(I=>A.indexOf(I)!==-1).every(I=>{if(Array.isArray(E[I])&&Array.isArray(o[I])){let v=E[I];return v.length===o[I].length&&v.every((x,C)=>x===o[I][C])}else return E[I]===o[I]}),h=(E,I)=>jt.createRetryablePromise(v=>X2(t)(e,I).then(x=>p(x)?Promise.resolve():v()));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Put,path:jt.encode("1/keys/%s",e),data:u},n),h)},QC=t=>(e,r)=>jt.createRetryablePromise(o=>sye(t)(e,r).then(a=>a.status!=="published"?o():void 0)),oye=t=>(e,r)=>{let o=(a,n)=>Zi(t)(a.taskID,n);return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/batch",t.indexName),data:{requests:e}},r),o)},Smt=t=>e=>Bk({shouldStop:r=>r.cursor===void 0,...e,request:r=>t.transporter.read({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/browse",t.indexName),data:r},e)}),bmt=t=>e=>{let r={hitsPerPage:1e3,...e};return Bk({shouldStop:o=>o.hits.length<r.hitsPerPage,...r,request(o){return pye(t)("",{...r,...o}).then(a=>({...a,hits:a.hits.map(n=>(delete n._highlightResult,n))}))}})},xmt=t=>e=>{let r={hitsPerPage:1e3,...e};return Bk({shouldStop:o=>o.hits.length<r.hitsPerPage,...r,request(o){return hye(t)("",{...r,...o}).then(a=>({...a,hits:a.hits.map(n=>(delete n._highlightResult,n))}))}})},Dk=t=>(e,r,o)=>{let{batchSize:a,...n}=o||{},u={taskIDs:[],objectIDs:[]},A=(p=0)=>{let h=[],E;for(E=p;E<e.length&&(h.push(e[E]),h.length!==(a||1e3));E++);return h.length===0?Promise.resolve(u):oye(t)(h.map(I=>({action:r,body:I})),n).then(I=>(u.objectIDs=u.objectIDs.concat(I.objectIDs),u.taskIDs.push(I.taskID),E++,A(E)))};return jt.createWaitablePromise(A(),(p,h)=>Promise.all(p.taskIDs.map(E=>Zi(t)(E,h))))},kmt=t=>e=>jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/clear",t.indexName)},e),(r,o)=>Zi(t)(r.taskID,o)),Qmt=t=>e=>{let{forwardToReplicas:r,...o}=e||{},a=La.createMappedRequestOptions(o);return r&&(a.queryParameters.forwardToReplicas=1),jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/rules/clear",t.indexName)},a),(n,u)=>Zi(t)(n.taskID,u))},Fmt=t=>e=>{let{forwardToReplicas:r,...o}=e||{},a=La.createMappedRequestOptions(o);return r&&(a.queryParameters.forwardToReplicas=1),jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/synonyms/clear",t.indexName)},a),(n,u)=>Zi(t)(n.taskID,u))},Rmt=t=>(e,r)=>jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/deleteByQuery",t.indexName),data:e},r),(o,a)=>Zi(t)(o.taskID,a)),Tmt=t=>e=>jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:jt.encode("1/indexes/%s",t.indexName)},e),(r,o)=>Zi(t)(r.taskID,o)),Lmt=t=>(e,r)=>jt.createWaitablePromise(aye(t)([e],r).then(o=>({taskID:o.taskIDs[0]})),(o,a)=>Zi(t)(o.taskID,a)),aye=t=>(e,r)=>{let o=e.map(a=>({objectID:a}));return Dk(t)(o,im.DeleteObject,r)},Nmt=t=>(e,r)=>{let{forwardToReplicas:o,...a}=r||{},n=La.createMappedRequestOptions(a);return o&&(n.queryParameters.forwardToReplicas=1),jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:jt.encode("1/indexes/%s/rules/%s",t.indexName,e)},n),(u,A)=>Zi(t)(u.taskID,A))},Omt=t=>(e,r)=>{let{forwardToReplicas:o,...a}=r||{},n=La.createMappedRequestOptions(a);return o&&(n.queryParameters.forwardToReplicas=1),jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:jt.encode("1/indexes/%s/synonyms/%s",t.indexName,e)},n),(u,A)=>Zi(t)(u.taskID,A))},Mmt=t=>e=>lye(t)(e).then(()=>!0).catch(r=>{if(r.status!==404)throw r;return!1}),Umt=t=>(e,r,o)=>t.transporter.read({method:Ir.MethodEnum.Post,path:jt.encode("1/answers/%s/prediction",t.indexName),data:{query:e,queryLanguages:r},cacheable:!0},o),_mt=t=>(e,r)=>{let{query:o,paginate:a,...n}=r||{},u=0,A=()=>Aye(t)(o||"",{...n,page:u}).then(p=>{for(let[h,E]of Object.entries(p.hits))if(e(E))return{object:E,position:parseInt(h,10),page:u};if(u++,a===!1||u>=p.nbPages)throw nye();return A()});return A()},Hmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode("1/indexes/%s/%s",t.indexName,e)},r),qmt=()=>(t,e)=>{for(let[r,o]of Object.entries(t.hits))if(o.objectID===e)return parseInt(r,10);return-1},Gmt=t=>(e,r)=>{let{attributesToRetrieve:o,...a}=r||{},n=e.map(u=>({indexName:t.indexName,objectID:u,...o?{attributesToRetrieve:o}:{}}));return t.transporter.read({method:Ir.MethodEnum.Post,path:"1/indexes/*/objects",data:{requests:n}},a)},jmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode("1/indexes/%s/rules/%s",t.indexName,e)},r),lye=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode("1/indexes/%s/settings",t.indexName),data:{getVersion:2}},e),Ymt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode("1/indexes/%s/synonyms/%s",t.indexName,e)},r),cye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode("1/indexes/%s/task/%s",t.indexName,e.toString())},r),Wmt=t=>(e,r)=>jt.createWaitablePromise(uye(t)([e],r).then(o=>({objectID:o.objectIDs[0],taskID:o.taskIDs[0]})),(o,a)=>Zi(t)(o.taskID,a)),uye=t=>(e,r)=>{let{createIfNotExists:o,...a}=r||{},n=o?im.PartialUpdateObject:im.PartialUpdateObjectNoCreate;return Dk(t)(e,n,a)},Kmt=t=>(e,r)=>{let{safe:o,autoGenerateObjectIDIfNotExist:a,batchSize:n,...u}=r||{},A=(C,R,N,U)=>jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/operation",C),data:{operation:N,destination:R}},U),(V,te)=>Zi(t)(V.taskID,te)),p=Math.random().toString(36).substring(7),h=`${t.indexName}_tmp_${p}`,E=GH({appId:t.appId,transporter:t.transporter,indexName:h}),I=[],v=A(t.indexName,h,"copy",{...u,scope:["settings","synonyms","rules"]});I.push(v);let x=(o?v.wait(u):v).then(()=>{let C=E(e,{...u,autoGenerateObjectIDIfNotExist:a,batchSize:n});return I.push(C),o?C.wait(u):C}).then(()=>{let C=A(h,t.indexName,"move",u);return I.push(C),o?C.wait(u):C}).then(()=>Promise.all(I)).then(([C,R,N])=>({objectIDs:R.objectIDs,taskIDs:[C.taskID,...R.taskIDs,N.taskID]}));return jt.createWaitablePromise(x,(C,R)=>Promise.all(I.map(N=>N.wait(R))))},zmt=t=>(e,r)=>jH(t)(e,{...r,clearExistingRules:!0}),Vmt=t=>(e,r)=>YH(t)(e,{...r,clearExistingSynonyms:!0}),Jmt=t=>(e,r)=>jt.createWaitablePromise(GH(t)([e],r).then(o=>({objectID:o.objectIDs[0],taskID:o.taskIDs[0]})),(o,a)=>Zi(t)(o.taskID,a)),GH=t=>(e,r)=>{let{autoGenerateObjectIDIfNotExist:o,...a}=r||{},n=o?im.AddObject:im.UpdateObject;if(n===im.UpdateObject){for(let u of e)if(u.objectID===void 0)return jt.createWaitablePromise(Promise.reject(rye()))}return Dk(t)(e,n,a)},Xmt=t=>(e,r)=>jH(t)([e],r),jH=t=>(e,r)=>{let{forwardToReplicas:o,clearExistingRules:a,...n}=r||{},u=La.createMappedRequestOptions(n);return o&&(u.queryParameters.forwardToReplicas=1),a&&(u.queryParameters.clearExistingRules=1),jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/rules/batch",t.indexName),data:e},u),(A,p)=>Zi(t)(A.taskID,p))},Zmt=t=>(e,r)=>YH(t)([e],r),YH=t=>(e,r)=>{let{forwardToReplicas:o,clearExistingSynonyms:a,replaceExistingSynonyms:n,...u}=r||{},A=La.createMappedRequestOptions(u);return o&&(A.queryParameters.forwardToReplicas=1),(n||a)&&(A.queryParameters.replaceExistingSynonyms=1),jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/synonyms/batch",t.indexName),data:e},A),(p,h)=>Zi(t)(p.taskID,h))},Aye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/query",t.indexName),data:{query:e},cacheable:!0},r),fye=t=>(e,r,o)=>t.transporter.read({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/facets/%s/query",t.indexName,e),data:{facetQuery:r},cacheable:!0},o),pye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/rules/search",t.indexName),data:{query:e}},r),hye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:jt.encode("1/indexes/%s/synonyms/search",t.indexName),data:{query:e}},r),$mt=t=>(e,r)=>{let{forwardToReplicas:o,...a}=r||{},n=La.createMappedRequestOptions(a);return o&&(n.queryParameters.forwardToReplicas=1),jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Put,path:jt.encode("1/indexes/%s/settings",t.indexName),data:e},n),(u,A)=>Zi(t)(u.taskID,A))},Zi=t=>(e,r)=>jt.createRetryablePromise(o=>cye(t)(e,r).then(a=>a.status!=="published"?o():void 0)),eyt={AddObject:"addObject",Analytics:"analytics",Browser:"browse",DeleteIndex:"deleteIndex",DeleteObject:"deleteObject",EditSettings:"editSettings",Inference:"inference",ListIndexes:"listIndexes",Logs:"logs",Personalization:"personalization",Recommendation:"recommendation",Search:"search",SeeUnretrievableAttributes:"seeUnretrievableAttributes",Settings:"settings",Usage:"usage"},im={AddObject:"addObject",UpdateObject:"updateObject",PartialUpdateObject:"partialUpdateObject",PartialUpdateObjectNoCreate:"partialUpdateObjectNoCreate",DeleteObject:"deleteObject",DeleteIndex:"delete",ClearIndex:"clear"},Pk={Settings:"settings",Synonyms:"synonyms",Rules:"rules"},tyt={None:"none",StopIfEnoughMatches:"stopIfEnoughMatches"},ryt={Synonym:"synonym",OneWaySynonym:"oneWaySynonym",AltCorrection1:"altCorrection1",AltCorrection2:"altCorrection2",Placeholder:"placeholder"};Ft.ApiKeyACLEnum=eyt;Ft.BatchActionEnum=im;Ft.ScopeEnum=Pk;Ft.StrategyEnum=tyt;Ft.SynonymEnum=ryt;Ft.addApiKey=Kdt;Ft.assignUserID=zdt;Ft.assignUserIDs=Vdt;Ft.batch=oye;Ft.browseObjects=Smt;Ft.browseRules=bmt;Ft.browseSynonyms=xmt;Ft.chunkedBatch=Dk;Ft.clearDictionaryEntries=Jdt;Ft.clearObjects=kmt;Ft.clearRules=Qmt;Ft.clearSynonyms=Fmt;Ft.copyIndex=vk;Ft.copyRules=Xdt;Ft.copySettings=Zdt;Ft.copySynonyms=$dt;Ft.createBrowsablePromise=Bk;Ft.createMissingObjectIDError=rye;Ft.createObjectNotFoundError=nye;Ft.createSearchClient=Wdt;Ft.createValidUntilNotFoundError=iye;Ft.customRequest=emt;Ft.deleteApiKey=tmt;Ft.deleteBy=Rmt;Ft.deleteDictionaryEntries=rmt;Ft.deleteIndex=Tmt;Ft.deleteObject=Lmt;Ft.deleteObjects=aye;Ft.deleteRule=Nmt;Ft.deleteSynonym=Omt;Ft.exists=Mmt;Ft.findAnswers=Umt;Ft.findObject=_mt;Ft.generateSecuredApiKey=nmt;Ft.getApiKey=X2;Ft.getAppTask=sye;Ft.getDictionarySettings=imt;Ft.getLogs=smt;Ft.getObject=Hmt;Ft.getObjectPosition=qmt;Ft.getObjects=Gmt;Ft.getRule=jmt;Ft.getSecuredApiKeyRemainingValidity=omt;Ft.getSettings=lye;Ft.getSynonym=Ymt;Ft.getTask=cye;Ft.getTopUserIDs=amt;Ft.getUserID=lmt;Ft.hasPendingMappings=cmt;Ft.initIndex=Z2;Ft.listApiKeys=umt;Ft.listClusters=Amt;Ft.listIndices=fmt;Ft.listUserIDs=pmt;Ft.moveIndex=hmt;Ft.multipleBatch=gmt;Ft.multipleGetObjects=dmt;Ft.multipleQueries=mmt;Ft.multipleSearchForFacetValues=ymt;Ft.partialUpdateObject=Wmt;Ft.partialUpdateObjects=uye;Ft.removeUserID=Emt;Ft.replaceAllObjects=Kmt;Ft.replaceAllRules=zmt;Ft.replaceAllSynonyms=Vmt;Ft.replaceDictionaryEntries=Cmt;Ft.restoreApiKey=wmt;Ft.saveDictionaryEntries=Imt;Ft.saveObject=Jmt;Ft.saveObjects=GH;Ft.saveRule=Xmt;Ft.saveRules=jH;Ft.saveSynonym=Zmt;Ft.saveSynonyms=YH;Ft.search=Aye;Ft.searchDictionaryEntries=Bmt;Ft.searchForFacetValues=fye;Ft.searchRules=pye;Ft.searchSynonyms=hye;Ft.searchUserIDs=vmt;Ft.setDictionarySettings=Dmt;Ft.setSettings=$mt;Ft.updateApiKey=Pmt;Ft.waitAppTask=QC;Ft.waitTask=Zi});var mye=_((WWt,dye)=>{dye.exports=gye()});var yye=_(Sk=>{"use strict";Object.defineProperty(Sk,"__esModule",{value:!0});function nyt(){return{debug(t,e){return Promise.resolve()},info(t,e){return Promise.resolve()},error(t,e){return Promise.resolve()}}}var iyt={Debug:1,Info:2,Error:3};Sk.LogLevelEnum=iyt;Sk.createNullLogger=nyt});var Cye=_((zWt,Eye)=>{Eye.exports=yye()});var vye=_(WH=>{"use strict";Object.defineProperty(WH,"__esModule",{value:!0});var wye=ve("http"),Iye=ve("https"),syt=ve("url"),Bye={keepAlive:!0},oyt=new wye.Agent(Bye),ayt=new Iye.Agent(Bye);function lyt({agent:t,httpAgent:e,httpsAgent:r,requesterOptions:o={}}={}){let a=e||t||oyt,n=r||t||ayt;return{send(u){return new Promise(A=>{let p=syt.parse(u.url),h=p.query===null?p.pathname:`${p.pathname}?${p.query}`,E={...o,agent:p.protocol==="https:"?n:a,hostname:p.hostname,path:h,method:u.method,headers:{...o&&o.headers?o.headers:{},...u.headers},...p.port!==void 0?{port:p.port||""}:{}},I=(p.protocol==="https:"?Iye:wye).request(E,R=>{let N=[];R.on("data",U=>{N=N.concat(U)}),R.on("end",()=>{clearTimeout(x),clearTimeout(C),A({status:R.statusCode||0,content:Buffer.concat(N).toString(),isTimedOut:!1})})}),v=(R,N)=>setTimeout(()=>{I.abort(),A({status:0,content:N,isTimedOut:!0})},R*1e3),x=v(u.connectTimeout,"Connection timeout"),C;I.on("error",R=>{clearTimeout(x),clearTimeout(C),A({status:0,content:R.message,isTimedOut:!1})}),I.once("response",()=>{clearTimeout(x),C=v(u.responseTimeout,"Socket timeout")}),u.data!==void 0&&I.write(u.data),I.end()})},destroy(){return a.destroy(),n.destroy(),Promise.resolve()}}}WH.createNodeHttpRequester=lyt});var Pye=_((JWt,Dye)=>{Dye.exports=vye()});var kye=_((XWt,xye)=>{"use strict";var Sye=vme(),cyt=Sme(),FC=Xme(),zH=Y2(),KH=tye(),_t=mye(),uyt=Cye(),Ayt=Pye(),fyt=z2();function bye(t,e,r){let o={appId:t,apiKey:e,timeouts:{connect:2,read:5,write:30},requester:Ayt.createNodeHttpRequester(),logger:uyt.createNullLogger(),responsesCache:Sye.createNullCache(),requestsCache:Sye.createNullCache(),hostsCache:cyt.createInMemoryCache(),userAgent:fyt.createUserAgent(zH.version).add({segment:"Node.js",version:process.versions.node})},a={...o,...r},n=()=>u=>KH.createPersonalizationClient({...o,...u,methods:{getPersonalizationStrategy:KH.getPersonalizationStrategy,setPersonalizationStrategy:KH.setPersonalizationStrategy}});return _t.createSearchClient({...a,methods:{search:_t.multipleQueries,searchForFacetValues:_t.multipleSearchForFacetValues,multipleBatch:_t.multipleBatch,multipleGetObjects:_t.multipleGetObjects,multipleQueries:_t.multipleQueries,copyIndex:_t.copyIndex,copySettings:_t.copySettings,copyRules:_t.copyRules,copySynonyms:_t.copySynonyms,moveIndex:_t.moveIndex,listIndices:_t.listIndices,getLogs:_t.getLogs,listClusters:_t.listClusters,multipleSearchForFacetValues:_t.multipleSearchForFacetValues,getApiKey:_t.getApiKey,addApiKey:_t.addApiKey,listApiKeys:_t.listApiKeys,updateApiKey:_t.updateApiKey,deleteApiKey:_t.deleteApiKey,restoreApiKey:_t.restoreApiKey,assignUserID:_t.assignUserID,assignUserIDs:_t.assignUserIDs,getUserID:_t.getUserID,searchUserIDs:_t.searchUserIDs,listUserIDs:_t.listUserIDs,getTopUserIDs:_t.getTopUserIDs,removeUserID:_t.removeUserID,hasPendingMappings:_t.hasPendingMappings,generateSecuredApiKey:_t.generateSecuredApiKey,getSecuredApiKeyRemainingValidity:_t.getSecuredApiKeyRemainingValidity,destroy:zH.destroy,clearDictionaryEntries:_t.clearDictionaryEntries,deleteDictionaryEntries:_t.deleteDictionaryEntries,getDictionarySettings:_t.getDictionarySettings,getAppTask:_t.getAppTask,replaceDictionaryEntries:_t.replaceDictionaryEntries,saveDictionaryEntries:_t.saveDictionaryEntries,searchDictionaryEntries:_t.searchDictionaryEntries,setDictionarySettings:_t.setDictionarySettings,waitAppTask:_t.waitAppTask,customRequest:_t.customRequest,initIndex:u=>A=>_t.initIndex(u)(A,{methods:{batch:_t.batch,delete:_t.deleteIndex,findAnswers:_t.findAnswers,getObject:_t.getObject,getObjects:_t.getObjects,saveObject:_t.saveObject,saveObjects:_t.saveObjects,search:_t.search,searchForFacetValues:_t.searchForFacetValues,waitTask:_t.waitTask,setSettings:_t.setSettings,getSettings:_t.getSettings,partialUpdateObject:_t.partialUpdateObject,partialUpdateObjects:_t.partialUpdateObjects,deleteObject:_t.deleteObject,deleteObjects:_t.deleteObjects,deleteBy:_t.deleteBy,clearObjects:_t.clearObjects,browseObjects:_t.browseObjects,getObjectPosition:_t.getObjectPosition,findObject:_t.findObject,exists:_t.exists,saveSynonym:_t.saveSynonym,saveSynonyms:_t.saveSynonyms,getSynonym:_t.getSynonym,searchSynonyms:_t.searchSynonyms,browseSynonyms:_t.browseSynonyms,deleteSynonym:_t.deleteSynonym,clearSynonyms:_t.clearSynonyms,replaceAllObjects:_t.replaceAllObjects,replaceAllSynonyms:_t.replaceAllSynonyms,searchRules:_t.searchRules,getRule:_t.getRule,deleteRule:_t.deleteRule,saveRule:_t.saveRule,saveRules:_t.saveRules,replaceAllRules:_t.replaceAllRules,browseRules:_t.browseRules,clearRules:_t.clearRules}}),initAnalytics:()=>u=>FC.createAnalyticsClient({...o,...u,methods:{addABTest:FC.addABTest,getABTest:FC.getABTest,getABTests:FC.getABTests,stopABTest:FC.stopABTest,deleteABTest:FC.deleteABTest}}),initPersonalization:n,initRecommendation:()=>u=>(a.logger.info("The `initRecommendation` method is deprecated. Use `initPersonalization` instead."),n()(u))}})}bye.version=zH.version;xye.exports=bye});var JH=_((ZWt,VH)=>{var Qye=kye();VH.exports=Qye;VH.exports.default=Qye});var $H=_((eKt,Tye)=>{"use strict";var Rye=Object.getOwnPropertySymbols,hyt=Object.prototype.hasOwnProperty,gyt=Object.prototype.propertyIsEnumerable;function dyt(t){if(t==null)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(t)}function myt(){try{if(!Object.assign)return!1;var t=new String("abc");if(t[5]="de",Object.getOwnPropertyNames(t)[0]==="5")return!1;for(var e={},r=0;r<10;r++)e["_"+String.fromCharCode(r)]=r;var o=Object.getOwnPropertyNames(e).map(function(n){return e[n]});if(o.join("")!=="0123456789")return!1;var a={};return"abcdefghijklmnopqrst".split("").forEach(function(n){a[n]=n}),Object.keys(Object.assign({},a)).join("")==="abcdefghijklmnopqrst"}catch{return!1}}Tye.exports=myt()?Object.assign:function(t,e){for(var r,o=dyt(t),a,n=1;n<arguments.length;n++){r=Object(arguments[n]);for(var u in r)hyt.call(r,u)&&(o[u]=r[u]);if(Rye){a=Rye(r);for(var A=0;A<a.length;A++)gyt.call(r,a[A])&&(o[a[A]]=r[a[A]])}}return o}});var Wye=_(Ln=>{"use strict";var i6=$H(),eu=typeof Symbol=="function"&&Symbol.for,$2=eu?Symbol.for("react.element"):60103,yyt=eu?Symbol.for("react.portal"):60106,Eyt=eu?Symbol.for("react.fragment"):60107,Cyt=eu?Symbol.for("react.strict_mode"):60108,wyt=eu?Symbol.for("react.profiler"):60114,Iyt=eu?Symbol.for("react.provider"):60109,Byt=eu?Symbol.for("react.context"):60110,vyt=eu?Symbol.for("react.forward_ref"):60112,Dyt=eu?Symbol.for("react.suspense"):60113,Pyt=eu?Symbol.for("react.memo"):60115,Syt=eu?Symbol.for("react.lazy"):60116,Lye=typeof Symbol=="function"&&Symbol.iterator;function eB(t){for(var e="https://reactjs.org/docs/error-decoder.html?invariant="+t,r=1;r<arguments.length;r++)e+="&args[]="+encodeURIComponent(arguments[r]);return"Minified React error #"+t+"; visit "+e+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var Nye={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Oye={};function RC(t,e,r){this.props=t,this.context=e,this.refs=Oye,this.updater=r||Nye}RC.prototype.isReactComponent={};RC.prototype.setState=function(t,e){if(typeof t!="object"&&typeof t!="function"&&t!=null)throw Error(eB(85));this.updater.enqueueSetState(this,t,e,"setState")};RC.prototype.forceUpdate=function(t){this.updater.enqueueForceUpdate(this,t,"forceUpdate")};function Mye(){}Mye.prototype=RC.prototype;function s6(t,e,r){this.props=t,this.context=e,this.refs=Oye,this.updater=r||Nye}var o6=s6.prototype=new Mye;o6.constructor=s6;i6(o6,RC.prototype);o6.isPureReactComponent=!0;var a6={current:null},Uye=Object.prototype.hasOwnProperty,_ye={key:!0,ref:!0,__self:!0,__source:!0};function Hye(t,e,r){var o,a={},n=null,u=null;if(e!=null)for(o in e.ref!==void 0&&(u=e.ref),e.key!==void 0&&(n=""+e.key),e)Uye.call(e,o)&&!_ye.hasOwnProperty(o)&&(a[o]=e[o]);var A=arguments.length-2;if(A===1)a.children=r;else if(1<A){for(var p=Array(A),h=0;h<A;h++)p[h]=arguments[h+2];a.children=p}if(t&&t.defaultProps)for(o in A=t.defaultProps,A)a[o]===void 0&&(a[o]=A[o]);return{$$typeof:$2,type:t,key:n,ref:u,props:a,_owner:a6.current}}function byt(t,e){return{$$typeof:$2,type:t.type,key:e,ref:t.ref,props:t.props,_owner:t._owner}}function l6(t){return typeof t=="object"&&t!==null&&t.$$typeof===$2}function xyt(t){var e={"=":"=0",":":"=2"};return"$"+(""+t).replace(/[=:]/g,function(r){return e[r]})}var qye=/\/+/g,bk=[];function Gye(t,e,r,o){if(bk.length){var a=bk.pop();return a.result=t,a.keyPrefix=e,a.func=r,a.context=o,a.count=0,a}return{result:t,keyPrefix:e,func:r,context:o,count:0}}function jye(t){t.result=null,t.keyPrefix=null,t.func=null,t.context=null,t.count=0,10>bk.length&&bk.push(t)}function t6(t,e,r,o){var a=typeof t;(a==="undefined"||a==="boolean")&&(t=null);var n=!1;if(t===null)n=!0;else switch(a){case"string":case"number":n=!0;break;case"object":switch(t.$$typeof){case $2:case yyt:n=!0}}if(n)return r(o,t,e===""?"."+e6(t,0):e),1;if(n=0,e=e===""?".":e+":",Array.isArray(t))for(var u=0;u<t.length;u++){a=t[u];var A=e+e6(a,u);n+=t6(a,A,r,o)}else if(t===null||typeof t!="object"?A=null:(A=Lye&&t[Lye]||t["@@iterator"],A=typeof A=="function"?A:null),typeof A=="function")for(t=A.call(t),u=0;!(a=t.next()).done;)a=a.value,A=e+e6(a,u++),n+=t6(a,A,r,o);else if(a==="object")throw r=""+t,Error(eB(31,r==="[object Object]"?"object with keys {"+Object.keys(t).join(", ")+"}":r,""));return n}function r6(t,e,r){return t==null?0:t6(t,"",e,r)}function e6(t,e){return typeof t=="object"&&t!==null&&t.key!=null?xyt(t.key):e.toString(36)}function kyt(t,e){t.func.call(t.context,e,t.count++)}function Qyt(t,e,r){var o=t.result,a=t.keyPrefix;t=t.func.call(t.context,e,t.count++),Array.isArray(t)?n6(t,o,r,function(n){return n}):t!=null&&(l6(t)&&(t=byt(t,a+(!t.key||e&&e.key===t.key?"":(""+t.key).replace(qye,"$&/")+"/")+r)),o.push(t))}function n6(t,e,r,o,a){var n="";r!=null&&(n=(""+r).replace(qye,"$&/")+"/"),e=Gye(e,n,o,a),r6(t,Qyt,e),jye(e)}var Yye={current:null};function Xf(){var t=Yye.current;if(t===null)throw Error(eB(321));return t}var Fyt={ReactCurrentDispatcher:Yye,ReactCurrentBatchConfig:{suspense:null},ReactCurrentOwner:a6,IsSomeRendererActing:{current:!1},assign:i6};Ln.Children={map:function(t,e,r){if(t==null)return t;var o=[];return n6(t,o,null,e,r),o},forEach:function(t,e,r){if(t==null)return t;e=Gye(null,null,e,r),r6(t,kyt,e),jye(e)},count:function(t){return r6(t,function(){return null},null)},toArray:function(t){var e=[];return n6(t,e,null,function(r){return r}),e},only:function(t){if(!l6(t))throw Error(eB(143));return t}};Ln.Component=RC;Ln.Fragment=Eyt;Ln.Profiler=wyt;Ln.PureComponent=s6;Ln.StrictMode=Cyt;Ln.Suspense=Dyt;Ln.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=Fyt;Ln.cloneElement=function(t,e,r){if(t==null)throw Error(eB(267,t));var o=i6({},t.props),a=t.key,n=t.ref,u=t._owner;if(e!=null){if(e.ref!==void 0&&(n=e.ref,u=a6.current),e.key!==void 0&&(a=""+e.key),t.type&&t.type.defaultProps)var A=t.type.defaultProps;for(p in e)Uye.call(e,p)&&!_ye.hasOwnProperty(p)&&(o[p]=e[p]===void 0&&A!==void 0?A[p]:e[p])}var p=arguments.length-2;if(p===1)o.children=r;else if(1<p){A=Array(p);for(var h=0;h<p;h++)A[h]=arguments[h+2];o.children=A}return{$$typeof:$2,type:t.type,key:a,ref:n,props:o,_owner:u}};Ln.createContext=function(t,e){return e===void 0&&(e=null),t={$$typeof:Byt,_calculateChangedBits:e,_currentValue:t,_currentValue2:t,_threadCount:0,Provider:null,Consumer:null},t.Provider={$$typeof:Iyt,_context:t},t.Consumer=t};Ln.createElement=Hye;Ln.createFactory=function(t){var e=Hye.bind(null,t);return e.type=t,e};Ln.createRef=function(){return{current:null}};Ln.forwardRef=function(t){return{$$typeof:vyt,render:t}};Ln.isValidElement=l6;Ln.lazy=function(t){return{$$typeof:Syt,_ctor:t,_status:-1,_result:null}};Ln.memo=function(t,e){return{$$typeof:Pyt,type:t,compare:e===void 0?null:e}};Ln.useCallback=function(t,e){return Xf().useCallback(t,e)};Ln.useContext=function(t,e){return Xf().useContext(t,e)};Ln.useDebugValue=function(){};Ln.useEffect=function(t,e){return Xf().useEffect(t,e)};Ln.useImperativeHandle=function(t,e,r){return Xf().useImperativeHandle(t,e,r)};Ln.useLayoutEffect=function(t,e){return Xf().useLayoutEffect(t,e)};Ln.useMemo=function(t,e){return Xf().useMemo(t,e)};Ln.useReducer=function(t,e,r){return Xf().useReducer(t,e,r)};Ln.useRef=function(t){return Xf().useRef(t)};Ln.useState=function(t){return Xf().useState(t)};Ln.version="16.13.1"});var on=_((rKt,Kye)=>{"use strict";Kye.exports=Wye()});var u6=_((nKt,c6)=>{"use strict";var An=c6.exports;c6.exports.default=An;var Nn="\x1B[",tB="\x1B]",TC="\x07",xk=";",zye=process.env.TERM_PROGRAM==="Apple_Terminal";An.cursorTo=(t,e)=>{if(typeof t!="number")throw new TypeError("The `x` argument is required");return typeof e!="number"?Nn+(t+1)+"G":Nn+(e+1)+";"+(t+1)+"H"};An.cursorMove=(t,e)=>{if(typeof t!="number")throw new TypeError("The `x` argument is required");let r="";return t<0?r+=Nn+-t+"D":t>0&&(r+=Nn+t+"C"),e<0?r+=Nn+-e+"A":e>0&&(r+=Nn+e+"B"),r};An.cursorUp=(t=1)=>Nn+t+"A";An.cursorDown=(t=1)=>Nn+t+"B";An.cursorForward=(t=1)=>Nn+t+"C";An.cursorBackward=(t=1)=>Nn+t+"D";An.cursorLeft=Nn+"G";An.cursorSavePosition=zye?"\x1B7":Nn+"s";An.cursorRestorePosition=zye?"\x1B8":Nn+"u";An.cursorGetPosition=Nn+"6n";An.cursorNextLine=Nn+"E";An.cursorPrevLine=Nn+"F";An.cursorHide=Nn+"?25l";An.cursorShow=Nn+"?25h";An.eraseLines=t=>{let e="";for(let r=0;r<t;r++)e+=An.eraseLine+(r<t-1?An.cursorUp():"");return t&&(e+=An.cursorLeft),e};An.eraseEndLine=Nn+"K";An.eraseStartLine=Nn+"1K";An.eraseLine=Nn+"2K";An.eraseDown=Nn+"J";An.eraseUp=Nn+"1J";An.eraseScreen=Nn+"2J";An.scrollUp=Nn+"S";An.scrollDown=Nn+"T";An.clearScreen="\x1Bc";An.clearTerminal=process.platform==="win32"?`${An.eraseScreen}${Nn}0f`:`${An.eraseScreen}${Nn}3J${Nn}H`;An.beep=TC;An.link=(t,e)=>[tB,"8",xk,xk,e,TC,t,tB,"8",xk,xk,TC].join("");An.image=(t,e={})=>{let r=`${tB}1337;File=inline=1`;return e.width&&(r+=`;width=${e.width}`),e.height&&(r+=`;height=${e.height}`),e.preserveAspectRatio===!1&&(r+=";preserveAspectRatio=0"),r+":"+t.toString("base64")+TC};An.iTerm={setCwd:(t=process.cwd())=>`${tB}50;CurrentDir=${t}${TC}`,annotation:(t,e={})=>{let r=`${tB}1337;`,o=typeof e.x<"u",a=typeof e.y<"u";if((o||a)&&!(o&&a&&typeof e.length<"u"))throw new Error("`x`, `y` and `length` must be defined when `x` or `y` is defined");return t=t.replace(/\|/g,""),r+=e.isHidden?"AddHiddenAnnotation=":"AddAnnotation=",e.length>0?r+=(o?[t,e.length,e.x,e.y]:[e.length,t]).join("|"):r+=t,r+TC}}});var Jye=_((iKt,A6)=>{"use strict";var Vye=(t,e)=>{for(let r of Reflect.ownKeys(e))Object.defineProperty(t,r,Object.getOwnPropertyDescriptor(e,r));return t};A6.exports=Vye;A6.exports.default=Vye});var Zye=_((sKt,Qk)=>{"use strict";var Ryt=Jye(),kk=new WeakMap,Xye=(t,e={})=>{if(typeof t!="function")throw new TypeError("Expected a function");let r,o=0,a=t.displayName||t.name||"<anonymous>",n=function(...u){if(kk.set(n,++o),o===1)r=t.apply(this,u),t=null;else if(e.throw===!0)throw new Error(`Function \`${a}\` can only be called once`);return r};return Ryt(n,t),kk.set(n,o),n};Qk.exports=Xye;Qk.exports.default=Xye;Qk.exports.callCount=t=>{if(!kk.has(t))throw new Error(`The given function \`${t.name}\` is not wrapped by the \`onetime\` package`);return kk.get(t)}});var $ye=_((oKt,Fk)=>{Fk.exports=["SIGABRT","SIGALRM","SIGHUP","SIGINT","SIGTERM"];process.platform!=="win32"&&Fk.exports.push("SIGVTALRM","SIGXCPU","SIGXFSZ","SIGUSR2","SIGTRAP","SIGSYS","SIGQUIT","SIGIOT");process.platform==="linux"&&Fk.exports.push("SIGIO","SIGPOLL","SIGPWR","SIGSTKFLT","SIGUNUSED")});var h6=_((aKt,OC)=>{var Ei=global.process,sm=function(t){return t&&typeof t=="object"&&typeof t.removeListener=="function"&&typeof t.emit=="function"&&typeof t.reallyExit=="function"&&typeof t.listeners=="function"&&typeof t.kill=="function"&&typeof t.pid=="number"&&typeof t.on=="function"};sm(Ei)?(eEe=ve("assert"),LC=$ye(),tEe=/^win/i.test(Ei.platform),rB=ve("events"),typeof rB!="function"&&(rB=rB.EventEmitter),Ei.__signal_exit_emitter__?Ts=Ei.__signal_exit_emitter__:(Ts=Ei.__signal_exit_emitter__=new rB,Ts.count=0,Ts.emitted={}),Ts.infinite||(Ts.setMaxListeners(1/0),Ts.infinite=!0),OC.exports=function(t,e){if(!sm(global.process))return function(){};eEe.equal(typeof t,"function","a callback must be provided for exit handler"),NC===!1&&f6();var r="exit";e&&e.alwaysLast&&(r="afterexit");var o=function(){Ts.removeListener(r,t),Ts.listeners("exit").length===0&&Ts.listeners("afterexit").length===0&&Rk()};return Ts.on(r,t),o},Rk=function(){!NC||!sm(global.process)||(NC=!1,LC.forEach(function(e){try{Ei.removeListener(e,Tk[e])}catch{}}),Ei.emit=Lk,Ei.reallyExit=p6,Ts.count-=1)},OC.exports.unload=Rk,om=function(e,r,o){Ts.emitted[e]||(Ts.emitted[e]=!0,Ts.emit(e,r,o))},Tk={},LC.forEach(function(t){Tk[t]=function(){if(!!sm(global.process)){var r=Ei.listeners(t);r.length===Ts.count&&(Rk(),om("exit",null,t),om("afterexit",null,t),tEe&&t==="SIGHUP"&&(t="SIGINT"),Ei.kill(Ei.pid,t))}}}),OC.exports.signals=function(){return LC},NC=!1,f6=function(){NC||!sm(global.process)||(NC=!0,Ts.count+=1,LC=LC.filter(function(e){try{return Ei.on(e,Tk[e]),!0}catch{return!1}}),Ei.emit=nEe,Ei.reallyExit=rEe)},OC.exports.load=f6,p6=Ei.reallyExit,rEe=function(e){!sm(global.process)||(Ei.exitCode=e||0,om("exit",Ei.exitCode,null),om("afterexit",Ei.exitCode,null),p6.call(Ei,Ei.exitCode))},Lk=Ei.emit,nEe=function(e,r){if(e==="exit"&&sm(global.process)){r!==void 0&&(Ei.exitCode=r);var o=Lk.apply(this,arguments);return om("exit",Ei.exitCode,null),om("afterexit",Ei.exitCode,null),o}else return Lk.apply(this,arguments)}):OC.exports=function(){return function(){}};var eEe,LC,tEe,rB,Ts,Rk,om,Tk,NC,f6,p6,rEe,Lk,nEe});var sEe=_((lKt,iEe)=>{"use strict";var Tyt=Zye(),Lyt=h6();iEe.exports=Tyt(()=>{Lyt(()=>{process.stderr.write("\x1B[?25h")},{alwaysLast:!0})})});var g6=_(MC=>{"use strict";var Nyt=sEe(),Nk=!1;MC.show=(t=process.stderr)=>{!t.isTTY||(Nk=!1,t.write("\x1B[?25h"))};MC.hide=(t=process.stderr)=>{!t.isTTY||(Nyt(),Nk=!0,t.write("\x1B[?25l"))};MC.toggle=(t,e)=>{t!==void 0&&(Nk=t),Nk?MC.show(e):MC.hide(e)}});var cEe=_(nB=>{"use strict";var lEe=nB&&nB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(nB,"__esModule",{value:!0});var oEe=lEe(u6()),aEe=lEe(g6()),Oyt=(t,{showCursor:e=!1}={})=>{let r=0,o="",a=!1,n=u=>{!e&&!a&&(aEe.default.hide(),a=!0);let A=u+`
-`;A!==o&&(o=A,t.write(oEe.default.eraseLines(r)+A),r=A.split(`
-`).length)};return n.clear=()=>{t.write(oEe.default.eraseLines(r)),o="",r=0},n.done=()=>{o="",r=0,e||(aEe.default.show(),a=!1)},n};nB.default={create:Oyt}});var uEe=_((AKt,Myt)=>{Myt.exports=[{name:"AppVeyor",constant:"APPVEYOR",env:"APPVEYOR",pr:"APPVEYOR_PULL_REQUEST_NUMBER"},{name:"Azure Pipelines",constant:"AZURE_PIPELINES",env:"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI",pr:"SYSTEM_PULLREQUEST_PULLREQUESTID"},{name:"Bamboo",constant:"BAMBOO",env:"bamboo_planKey"},{name:"Bitbucket Pipelines",constant:"BITBUCKET",env:"BITBUCKET_COMMIT",pr:"BITBUCKET_PR_ID"},{name:"Bitrise",constant:"BITRISE",env:"BITRISE_IO",pr:"BITRISE_PULL_REQUEST"},{name:"Buddy",constant:"BUDDY",env:"BUDDY_WORKSPACE_ID",pr:"BUDDY_EXECUTION_PULL_REQUEST_ID"},{name:"Buildkite",constant:"BUILDKITE",env:"BUILDKITE",pr:{env:"BUILDKITE_PULL_REQUEST",ne:"false"}},{name:"CircleCI",constant:"CIRCLE",env:"CIRCLECI",pr:"CIRCLE_PULL_REQUEST"},{name:"Cirrus CI",constant:"CIRRUS",env:"CIRRUS_CI",pr:"CIRRUS_PR"},{name:"AWS CodeBuild",constant:"CODEBUILD",env:"CODEBUILD_BUILD_ARN"},{name:"Codeship",constant:"CODESHIP",env:{CI_NAME:"codeship"}},{name:"Drone",constant:"DRONE",env:"DRONE",pr:{DRONE_BUILD_EVENT:"pull_request"}},{name:"dsari",constant:"DSARI",env:"DSARI"},{name:"GitLab CI",constant:"GITLAB",env:"GITLAB_CI"},{name:"GoCD",constant:"GOCD",env:"GO_PIPELINE_LABEL"},{name:"Hudson",constant:"HUDSON",env:"HUDSON_URL"},{name:"Jenkins",constant:"JENKINS",env:["JENKINS_URL","BUILD_ID"],pr:{any:["ghprbPullId","CHANGE_ID"]}},{name:"Magnum CI",constant:"MAGNUM",env:"MAGNUM"},{name:"Netlify CI",constant:"NETLIFY",env:"NETLIFY_BUILD_BASE",pr:{env:"PULL_REQUEST",ne:"false"}},{name:"Sail CI",constant:"SAIL",env:"SAILCI",pr:"SAIL_PULL_REQUEST_NUMBER"},{name:"Semaphore",constant:"SEMAPHORE",env:"SEMAPHORE",pr:"PULL_REQUEST_NUMBER"},{name:"Shippable",constant:"SHIPPABLE",env:"SHIPPABLE",pr:{IS_PULL_REQUEST:"true"}},{name:"Solano CI",constant:"SOLANO",env:"TDDIUM",pr:"TDDIUM_PR_ID"},{name:"Strider CD",constant:"STRIDER",env:"STRIDER"},{name:"TaskCluster",constant:"TASKCLUSTER",env:["TASK_ID","RUN_ID"]},{name:"TeamCity",constant:"TEAMCITY",env:"TEAMCITY_VERSION"},{name:"Travis CI",constant:"TRAVIS",env:"TRAVIS",pr:{env:"TRAVIS_PULL_REQUEST",ne:"false"}}]});var pEe=_(dl=>{"use strict";var fEe=uEe(),hA=process.env;Object.defineProperty(dl,"_vendors",{value:fEe.map(function(t){return t.constant})});dl.name=null;dl.isPR=null;fEe.forEach(function(t){var e=Array.isArray(t.env)?t.env:[t.env],r=e.every(function(o){return AEe(o)});if(dl[t.constant]=r,r)switch(dl.name=t.name,typeof t.pr){case"string":dl.isPR=!!hA[t.pr];break;case"object":"env"in t.pr?dl.isPR=t.pr.env in hA&&hA[t.pr.env]!==t.pr.ne:"any"in t.pr?dl.isPR=t.pr.any.some(function(o){return!!hA[o]}):dl.isPR=AEe(t.pr);break;default:dl.isPR=null}});dl.isCI=!!(hA.CI||hA.CONTINUOUS_INTEGRATION||hA.BUILD_NUMBER||hA.RUN_ID||dl.name);function AEe(t){return typeof t=="string"?!!hA[t]:Object.keys(t).every(function(e){return hA[e]===t[e]})}});var gEe=_((pKt,hEe)=>{"use strict";hEe.exports=pEe().isCI});var mEe=_((hKt,dEe)=>{"use strict";var Uyt=t=>{let e=new Set;do for(let r of Reflect.ownKeys(t))e.add([t,r]);while((t=Reflect.getPrototypeOf(t))&&t!==Object.prototype);return e};dEe.exports=(t,{include:e,exclude:r}={})=>{let o=a=>{let n=u=>typeof u=="string"?a===u:u.test(a);return e?e.some(n):r?!r.some(n):!0};for(let[a,n]of Uyt(t.constructor.prototype)){if(n==="constructor"||!o(n))continue;let u=Reflect.getOwnPropertyDescriptor(a,n);u&&typeof u.value=="function"&&(t[n]=t[n].bind(t))}return t}});var vEe=_(kn=>{"use strict";Object.defineProperty(kn,"__esModule",{value:!0});var _C,oB,Hk,qk,I6;typeof window>"u"||typeof MessageChannel!="function"?(UC=null,d6=null,m6=function(){if(UC!==null)try{var t=kn.unstable_now();UC(!0,t),UC=null}catch(e){throw setTimeout(m6,0),e}},yEe=Date.now(),kn.unstable_now=function(){return Date.now()-yEe},_C=function(t){UC!==null?setTimeout(_C,0,t):(UC=t,setTimeout(m6,0))},oB=function(t,e){d6=setTimeout(t,e)},Hk=function(){clearTimeout(d6)},qk=function(){return!1},I6=kn.unstable_forceFrameRate=function(){}):(Ok=window.performance,y6=window.Date,EEe=window.setTimeout,CEe=window.clearTimeout,typeof console<"u"&&(wEe=window.cancelAnimationFrame,typeof window.requestAnimationFrame!="function"&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),typeof wEe!="function"&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")),typeof Ok=="object"&&typeof Ok.now=="function"?kn.unstable_now=function(){return Ok.now()}:(IEe=y6.now(),kn.unstable_now=function(){return y6.now()-IEe}),iB=!1,sB=null,Mk=-1,E6=5,C6=0,qk=function(){return kn.unstable_now()>=C6},I6=function(){},kn.unstable_forceFrameRate=function(t){0>t||125<t?console.error("forceFrameRate takes a positive int between 0 and 125, forcing framerates higher than 125 fps is not unsupported"):E6=0<t?Math.floor(1e3/t):5},w6=new MessageChannel,Uk=w6.port2,w6.port1.onmessage=function(){if(sB!==null){var t=kn.unstable_now();C6=t+E6;try{sB(!0,t)?Uk.postMessage(null):(iB=!1,sB=null)}catch(e){throw Uk.postMessage(null),e}}else iB=!1},_C=function(t){sB=t,iB||(iB=!0,Uk.postMessage(null))},oB=function(t,e){Mk=EEe(function(){t(kn.unstable_now())},e)},Hk=function(){CEe(Mk),Mk=-1});var UC,d6,m6,yEe,Ok,y6,EEe,CEe,wEe,IEe,iB,sB,Mk,E6,C6,w6,Uk;function B6(t,e){var r=t.length;t.push(e);e:for(;;){var o=Math.floor((r-1)/2),a=t[o];if(a!==void 0&&0<_k(a,e))t[o]=e,t[r]=a,r=o;else break e}}function ic(t){return t=t[0],t===void 0?null:t}function Gk(t){var e=t[0];if(e!==void 0){var r=t.pop();if(r!==e){t[0]=r;e:for(var o=0,a=t.length;o<a;){var n=2*(o+1)-1,u=t[n],A=n+1,p=t[A];if(u!==void 0&&0>_k(u,r))p!==void 0&&0>_k(p,u)?(t[o]=p,t[A]=r,o=A):(t[o]=u,t[n]=r,o=n);else if(p!==void 0&&0>_k(p,r))t[o]=p,t[A]=r,o=A;else break e}}return e}return null}function _k(t,e){var r=t.sortIndex-e.sortIndex;return r!==0?r:t.id-e.id}var tu=[],E0=[],_yt=1,na=null,No=3,jk=!1,am=!1,aB=!1;function Yk(t){for(var e=ic(E0);e!==null;){if(e.callback===null)Gk(E0);else if(e.startTime<=t)Gk(E0),e.sortIndex=e.expirationTime,B6(tu,e);else break;e=ic(E0)}}function v6(t){if(aB=!1,Yk(t),!am)if(ic(tu)!==null)am=!0,_C(D6);else{var e=ic(E0);e!==null&&oB(v6,e.startTime-t)}}function D6(t,e){am=!1,aB&&(aB=!1,Hk()),jk=!0;var r=No;try{for(Yk(e),na=ic(tu);na!==null&&(!(na.expirationTime>e)||t&&!qk());){var o=na.callback;if(o!==null){na.callback=null,No=na.priorityLevel;var a=o(na.expirationTime<=e);e=kn.unstable_now(),typeof a=="function"?na.callback=a:na===ic(tu)&&Gk(tu),Yk(e)}else Gk(tu);na=ic(tu)}if(na!==null)var n=!0;else{var u=ic(E0);u!==null&&oB(v6,u.startTime-e),n=!1}return n}finally{na=null,No=r,jk=!1}}function BEe(t){switch(t){case 1:return-1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var Hyt=I6;kn.unstable_ImmediatePriority=1;kn.unstable_UserBlockingPriority=2;kn.unstable_NormalPriority=3;kn.unstable_IdlePriority=5;kn.unstable_LowPriority=4;kn.unstable_runWithPriority=function(t,e){switch(t){case 1:case 2:case 3:case 4:case 5:break;default:t=3}var r=No;No=t;try{return e()}finally{No=r}};kn.unstable_next=function(t){switch(No){case 1:case 2:case 3:var e=3;break;default:e=No}var r=No;No=e;try{return t()}finally{No=r}};kn.unstable_scheduleCallback=function(t,e,r){var o=kn.unstable_now();if(typeof r=="object"&&r!==null){var a=r.delay;a=typeof a=="number"&&0<a?o+a:o,r=typeof r.timeout=="number"?r.timeout:BEe(t)}else r=BEe(t),a=o;return r=a+r,t={id:_yt++,callback:e,priorityLevel:t,startTime:a,expirationTime:r,sortIndex:-1},a>o?(t.sortIndex=a,B6(E0,t),ic(tu)===null&&t===ic(E0)&&(aB?Hk():aB=!0,oB(v6,a-o))):(t.sortIndex=r,B6(tu,t),am||jk||(am=!0,_C(D6))),t};kn.unstable_cancelCallback=function(t){t.callback=null};kn.unstable_wrapCallback=function(t){var e=No;return function(){var r=No;No=e;try{return t.apply(this,arguments)}finally{No=r}}};kn.unstable_getCurrentPriorityLevel=function(){return No};kn.unstable_shouldYield=function(){var t=kn.unstable_now();Yk(t);var e=ic(tu);return e!==na&&na!==null&&e!==null&&e.callback!==null&&e.startTime<=t&&e.expirationTime<na.expirationTime||qk()};kn.unstable_requestPaint=Hyt;kn.unstable_continueExecution=function(){am||jk||(am=!0,_C(D6))};kn.unstable_pauseExecution=function(){};kn.unstable_getFirstCallbackNode=function(){return ic(tu)};kn.unstable_Profiling=null});var P6=_((dKt,DEe)=>{"use strict";DEe.exports=vEe()});var PEe=_((mKt,lB)=>{lB.exports=function t(e){"use strict";var r=$H(),o=on(),a=P6();function n(P){for(var D="https://reactjs.org/docs/error-decoder.html?invariant="+P,T=1;T<arguments.length;T++)D+="&args[]="+encodeURIComponent(arguments[T]);return"Minified React error #"+P+"; visit "+D+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var u=o.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;u.hasOwnProperty("ReactCurrentDispatcher")||(u.ReactCurrentDispatcher={current:null}),u.hasOwnProperty("ReactCurrentBatchConfig")||(u.ReactCurrentBatchConfig={suspense:null});var A=typeof Symbol=="function"&&Symbol.for,p=A?Symbol.for("react.element"):60103,h=A?Symbol.for("react.portal"):60106,E=A?Symbol.for("react.fragment"):60107,I=A?Symbol.for("react.strict_mode"):60108,v=A?Symbol.for("react.profiler"):60114,x=A?Symbol.for("react.provider"):60109,C=A?Symbol.for("react.context"):60110,R=A?Symbol.for("react.concurrent_mode"):60111,N=A?Symbol.for("react.forward_ref"):60112,U=A?Symbol.for("react.suspense"):60113,V=A?Symbol.for("react.suspense_list"):60120,te=A?Symbol.for("react.memo"):60115,ae=A?Symbol.for("react.lazy"):60116;A&&Symbol.for("react.fundamental"),A&&Symbol.for("react.responder"),A&&Symbol.for("react.scope");var fe=typeof Symbol=="function"&&Symbol.iterator;function ue(P){return P===null||typeof P!="object"?null:(P=fe&&P[fe]||P["@@iterator"],typeof P=="function"?P:null)}function me(P){if(P._status===-1){P._status=0;var D=P._ctor;D=D(),P._result=D,D.then(function(T){P._status===0&&(T=T.default,P._status=1,P._result=T)},function(T){P._status===0&&(P._status=2,P._result=T)})}}function he(P){if(P==null)return null;if(typeof P=="function")return P.displayName||P.name||null;if(typeof P=="string")return P;switch(P){case E:return"Fragment";case h:return"Portal";case v:return"Profiler";case I:return"StrictMode";case U:return"Suspense";case V:return"SuspenseList"}if(typeof P=="object")switch(P.$$typeof){case C:return"Context.Consumer";case x:return"Context.Provider";case N:var D=P.render;return D=D.displayName||D.name||"",P.displayName||(D!==""?"ForwardRef("+D+")":"ForwardRef");case te:return he(P.type);case ae:if(P=P._status===1?P._result:null)return he(P)}return null}function Be(P){var D=P,T=P;if(P.alternate)for(;D.return;)D=D.return;else{P=D;do D=P,(D.effectTag&1026)!==0&&(T=D.return),P=D.return;while(P)}return D.tag===3?T:null}function we(P){if(Be(P)!==P)throw Error(n(188))}function g(P){var D=P.alternate;if(!D){if(D=Be(P),D===null)throw Error(n(188));return D!==P?null:P}for(var T=P,q=D;;){var Y=T.return;if(Y===null)break;var Ae=Y.alternate;if(Ae===null){if(q=Y.return,q!==null){T=q;continue}break}if(Y.child===Ae.child){for(Ae=Y.child;Ae;){if(Ae===T)return we(Y),P;if(Ae===q)return we(Y),D;Ae=Ae.sibling}throw Error(n(188))}if(T.return!==q.return)T=Y,q=Ae;else{for(var De=!1,vt=Y.child;vt;){if(vt===T){De=!0,T=Y,q=Ae;break}if(vt===q){De=!0,q=Y,T=Ae;break}vt=vt.sibling}if(!De){for(vt=Ae.child;vt;){if(vt===T){De=!0,T=Ae,q=Y;break}if(vt===q){De=!0,q=Ae,T=Y;break}vt=vt.sibling}if(!De)throw Error(n(189))}}if(T.alternate!==q)throw Error(n(190))}if(T.tag!==3)throw Error(n(188));return T.stateNode.current===T?P:D}function Ee(P){if(P=g(P),!P)return null;for(var D=P;;){if(D.tag===5||D.tag===6)return D;if(D.child)D.child.return=D,D=D.child;else{if(D===P)break;for(;!D.sibling;){if(!D.return||D.return===P)return null;D=D.return}D.sibling.return=D.return,D=D.sibling}}return null}function Pe(P){if(P=g(P),!P)return null;for(var D=P;;){if(D.tag===5||D.tag===6)return D;if(D.child&&D.tag!==4)D.child.return=D,D=D.child;else{if(D===P)break;for(;!D.sibling;){if(!D.return||D.return===P)return null;D=D.return}D.sibling.return=D.return,D=D.sibling}}return null}var ce=e.getPublicInstance,ne=e.getRootHostContext,ee=e.getChildHostContext,Ie=e.prepareForCommit,Fe=e.resetAfterCommit,At=e.createInstance,H=e.appendInitialChild,at=e.finalizeInitialChildren,Re=e.prepareUpdate,ke=e.shouldSetTextContent,xe=e.shouldDeprioritizeSubtree,He=e.createTextInstance,Te=e.setTimeout,Ve=e.clearTimeout,qe=e.noTimeout,b=e.isPrimaryRenderer,w=e.supportsMutation,S=e.supportsPersistence,y=e.supportsHydration,F=e.appendChild,J=e.appendChildToContainer,X=e.commitTextUpdate,Z=e.commitMount,ie=e.commitUpdate,be=e.insertBefore,Le=e.insertInContainerBefore,ot=e.removeChild,dt=e.removeChildFromContainer,Gt=e.resetTextContent,$t=e.hideInstance,bt=e.hideTextInstance,an=e.unhideInstance,Qr=e.unhideTextInstance,mr=e.cloneInstance,br=e.createContainerChildSet,Wr=e.appendChildToContainerChildSet,Kn=e.finalizeContainerChildren,Ls=e.replaceContainerChildren,Ti=e.cloneHiddenInstance,ps=e.cloneHiddenTextInstance,io=e.canHydrateInstance,Si=e.canHydrateTextInstance,Ns=e.isSuspenseInstancePending,so=e.isSuspenseInstanceFallback,uc=e.getNextHydratableSibling,uu=e.getFirstHydratableChild,cp=e.hydrateInstance,up=e.hydrateTextInstance,Os=e.getNextHydratableInstanceAfterSuspenseInstance,Dn=e.commitHydratedContainer,oo=e.commitHydratedSuspenseInstance,Ms=/^(.*)[\\\/]/;function yl(P){var D="";do{e:switch(P.tag){case 3:case 4:case 6:case 7:case 10:case 9:var T="";break e;default:var q=P._debugOwner,Y=P._debugSource,Ae=he(P.type);T=null,q&&(T=he(q.type)),q=Ae,Ae="",Y?Ae=" (at "+Y.fileName.replace(Ms,"")+":"+Y.lineNumber+")":T&&(Ae=" (created by "+T+")"),T=`
- in `+(q||"Unknown")+Ae}D+=T,P=P.return}while(P);return D}var El=[],ao=-1;function zn(P){0>ao||(P.current=El[ao],El[ao]=null,ao--)}function On(P,D){ao++,El[ao]=P.current,P.current=D}var Li={},Mn={current:Li},_i={current:!1},rr=Li;function Oe(P,D){var T=P.type.contextTypes;if(!T)return Li;var q=P.stateNode;if(q&&q.__reactInternalMemoizedUnmaskedChildContext===D)return q.__reactInternalMemoizedMaskedChildContext;var Y={},Ae;for(Ae in T)Y[Ae]=D[Ae];return q&&(P=P.stateNode,P.__reactInternalMemoizedUnmaskedChildContext=D,P.__reactInternalMemoizedMaskedChildContext=Y),Y}function ii(P){return P=P.childContextTypes,P!=null}function Ua(P){zn(_i,P),zn(Mn,P)}function hr(P){zn(_i,P),zn(Mn,P)}function Ac(P,D,T){if(Mn.current!==Li)throw Error(n(168));On(Mn,D,P),On(_i,T,P)}function Au(P,D,T){var q=P.stateNode;if(P=D.childContextTypes,typeof q.getChildContext!="function")return T;q=q.getChildContext();for(var Y in q)if(!(Y in P))throw Error(n(108,he(D)||"Unknown",Y));return r({},T,{},q)}function fc(P){var D=P.stateNode;return D=D&&D.__reactInternalMemoizedMergedChildContext||Li,rr=Mn.current,On(Mn,D,P),On(_i,_i.current,P),!0}function Cl(P,D,T){var q=P.stateNode;if(!q)throw Error(n(169));T?(D=Au(P,D,rr),q.__reactInternalMemoizedMergedChildContext=D,zn(_i,P),zn(Mn,P),On(Mn,D,P)):zn(_i,P),On(_i,T,P)}var DA=a.unstable_runWithPriority,fu=a.unstable_scheduleCallback,Ce=a.unstable_cancelCallback,Rt=a.unstable_shouldYield,pc=a.unstable_requestPaint,Hi=a.unstable_now,pu=a.unstable_getCurrentPriorityLevel,Yt=a.unstable_ImmediatePriority,wl=a.unstable_UserBlockingPriority,PA=a.unstable_NormalPriority,Ap=a.unstable_LowPriority,hc=a.unstable_IdlePriority,SA={},Qn=pc!==void 0?pc:function(){},hi=null,gc=null,bA=!1,sa=Hi(),Ni=1e4>sa?Hi:function(){return Hi()-sa};function _o(){switch(pu()){case Yt:return 99;case wl:return 98;case PA:return 97;case Ap:return 96;case hc:return 95;default:throw Error(n(332))}}function Ze(P){switch(P){case 99:return Yt;case 98:return wl;case 97:return PA;case 96:return Ap;case 95:return hc;default:throw Error(n(332))}}function lo(P,D){return P=Ze(P),DA(P,D)}function dc(P,D,T){return P=Ze(P),fu(P,D,T)}function hu(P){return hi===null?(hi=[P],gc=fu(Yt,gu)):hi.push(P),SA}function qi(){if(gc!==null){var P=gc;gc=null,Ce(P)}gu()}function gu(){if(!bA&&hi!==null){bA=!0;var P=0;try{var D=hi;lo(99,function(){for(;P<D.length;P++){var T=D[P];do T=T(!0);while(T!==null)}}),hi=null}catch(T){throw hi!==null&&(hi=hi.slice(P+1)),fu(Yt,qi),T}finally{bA=!1}}}var xA=3;function Ha(P,D,T){return T/=10,1073741821-(((1073741821-P+D/10)/T|0)+1)*T}function mc(P,D){return P===D&&(P!==0||1/P===1/D)||P!==P&&D!==D}var hs=typeof Object.is=="function"?Object.is:mc,Ht=Object.prototype.hasOwnProperty;function Fn(P,D){if(hs(P,D))return!0;if(typeof P!="object"||P===null||typeof D!="object"||D===null)return!1;var T=Object.keys(P),q=Object.keys(D);if(T.length!==q.length)return!1;for(q=0;q<T.length;q++)if(!Ht.call(D,T[q])||!hs(P[T[q]],D[T[q]]))return!1;return!0}function Ci(P,D){if(P&&P.defaultProps){D=r({},D),P=P.defaultProps;for(var T in P)D[T]===void 0&&(D[T]=P[T])}return D}var oa={current:null},co=null,Us=null,aa=null;function la(){aa=Us=co=null}function Ho(P,D){var T=P.type._context;b?(On(oa,T._currentValue,P),T._currentValue=D):(On(oa,T._currentValue2,P),T._currentValue2=D)}function wi(P){var D=oa.current;zn(oa,P),P=P.type._context,b?P._currentValue=D:P._currentValue2=D}function gs(P,D){for(;P!==null;){var T=P.alternate;if(P.childExpirationTime<D)P.childExpirationTime=D,T!==null&&T.childExpirationTime<D&&(T.childExpirationTime=D);else if(T!==null&&T.childExpirationTime<D)T.childExpirationTime=D;else break;P=P.return}}function ds(P,D){co=P,aa=Us=null,P=P.dependencies,P!==null&&P.firstContext!==null&&(P.expirationTime>=D&&(Go=!0),P.firstContext=null)}function ms(P,D){if(aa!==P&&D!==!1&&D!==0)if((typeof D!="number"||D===1073741823)&&(aa=P,D=1073741823),D={context:P,observedBits:D,next:null},Us===null){if(co===null)throw Error(n(308));Us=D,co.dependencies={expirationTime:0,firstContext:D,responders:null}}else Us=Us.next=D;return b?P._currentValue:P._currentValue2}var _s=!1;function Un(P){return{baseState:P,firstUpdate:null,lastUpdate:null,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function Pn(P){return{baseState:P.baseState,firstUpdate:P.firstUpdate,lastUpdate:P.lastUpdate,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function ys(P,D){return{expirationTime:P,suspenseConfig:D,tag:0,payload:null,callback:null,next:null,nextEffect:null}}function We(P,D){P.lastUpdate===null?P.firstUpdate=P.lastUpdate=D:(P.lastUpdate.next=D,P.lastUpdate=D)}function tt(P,D){var T=P.alternate;if(T===null){var q=P.updateQueue,Y=null;q===null&&(q=P.updateQueue=Un(P.memoizedState))}else q=P.updateQueue,Y=T.updateQueue,q===null?Y===null?(q=P.updateQueue=Un(P.memoizedState),Y=T.updateQueue=Un(T.memoizedState)):q=P.updateQueue=Pn(Y):Y===null&&(Y=T.updateQueue=Pn(q));Y===null||q===Y?We(q,D):q.lastUpdate===null||Y.lastUpdate===null?(We(q,D),We(Y,D)):(We(q,D),Y.lastUpdate=D)}function It(P,D){var T=P.updateQueue;T=T===null?P.updateQueue=Un(P.memoizedState):ir(P,T),T.lastCapturedUpdate===null?T.firstCapturedUpdate=T.lastCapturedUpdate=D:(T.lastCapturedUpdate.next=D,T.lastCapturedUpdate=D)}function ir(P,D){var T=P.alternate;return T!==null&&D===T.updateQueue&&(D=P.updateQueue=Pn(D)),D}function $(P,D,T,q,Y,Ae){switch(T.tag){case 1:return P=T.payload,typeof P=="function"?P.call(Ae,q,Y):P;case 3:P.effectTag=P.effectTag&-4097|64;case 0:if(P=T.payload,Y=typeof P=="function"?P.call(Ae,q,Y):P,Y==null)break;return r({},q,Y);case 2:_s=!0}return q}function ye(P,D,T,q,Y){_s=!1,D=ir(P,D);for(var Ae=D.baseState,De=null,vt=0,wt=D.firstUpdate,xt=Ae;wt!==null;){var _r=wt.expirationTime;_r<Y?(De===null&&(De=wt,Ae=xt),vt<_r&&(vt=_r)):(Sw(_r,wt.suspenseConfig),xt=$(P,D,wt,xt,T,q),wt.callback!==null&&(P.effectTag|=32,wt.nextEffect=null,D.lastEffect===null?D.firstEffect=D.lastEffect=wt:(D.lastEffect.nextEffect=wt,D.lastEffect=wt))),wt=wt.next}for(_r=null,wt=D.firstCapturedUpdate;wt!==null;){var is=wt.expirationTime;is<Y?(_r===null&&(_r=wt,De===null&&(Ae=xt)),vt<is&&(vt=is)):(xt=$(P,D,wt,xt,T,q),wt.callback!==null&&(P.effectTag|=32,wt.nextEffect=null,D.lastCapturedEffect===null?D.firstCapturedEffect=D.lastCapturedEffect=wt:(D.lastCapturedEffect.nextEffect=wt,D.lastCapturedEffect=wt))),wt=wt.next}De===null&&(D.lastUpdate=null),_r===null?D.lastCapturedUpdate=null:P.effectTag|=32,De===null&&_r===null&&(Ae=xt),D.baseState=Ae,D.firstUpdate=De,D.firstCapturedUpdate=_r,Hm(vt),P.expirationTime=vt,P.memoizedState=xt}function Ne(P,D,T){D.firstCapturedUpdate!==null&&(D.lastUpdate!==null&&(D.lastUpdate.next=D.firstCapturedUpdate,D.lastUpdate=D.lastCapturedUpdate),D.firstCapturedUpdate=D.lastCapturedUpdate=null),pt(D.firstEffect,T),D.firstEffect=D.lastEffect=null,pt(D.firstCapturedEffect,T),D.firstCapturedEffect=D.lastCapturedEffect=null}function pt(P,D){for(;P!==null;){var T=P.callback;if(T!==null){P.callback=null;var q=D;if(typeof T!="function")throw Error(n(191,T));T.call(q)}P=P.nextEffect}}var ht=u.ReactCurrentBatchConfig,Tt=new o.Component().refs;function er(P,D,T,q){D=P.memoizedState,T=T(q,D),T=T==null?D:r({},D,T),P.memoizedState=T,q=P.updateQueue,q!==null&&P.expirationTime===0&&(q.baseState=T)}var $r={isMounted:function(P){return(P=P._reactInternalFiber)?Be(P)===P:!1},enqueueSetState:function(P,D,T){P=P._reactInternalFiber;var q=ga(),Y=ht.suspense;q=qA(q,P,Y),Y=ys(q,Y),Y.payload=D,T!=null&&(Y.callback=T),tt(P,Y),bc(P,q)},enqueueReplaceState:function(P,D,T){P=P._reactInternalFiber;var q=ga(),Y=ht.suspense;q=qA(q,P,Y),Y=ys(q,Y),Y.tag=1,Y.payload=D,T!=null&&(Y.callback=T),tt(P,Y),bc(P,q)},enqueueForceUpdate:function(P,D){P=P._reactInternalFiber;var T=ga(),q=ht.suspense;T=qA(T,P,q),q=ys(T,q),q.tag=2,D!=null&&(q.callback=D),tt(P,q),bc(P,T)}};function Gi(P,D,T,q,Y,Ae,De){return P=P.stateNode,typeof P.shouldComponentUpdate=="function"?P.shouldComponentUpdate(q,Ae,De):D.prototype&&D.prototype.isPureReactComponent?!Fn(T,q)||!Fn(Y,Ae):!0}function es(P,D,T){var q=!1,Y=Li,Ae=D.contextType;return typeof Ae=="object"&&Ae!==null?Ae=ms(Ae):(Y=ii(D)?rr:Mn.current,q=D.contextTypes,Ae=(q=q!=null)?Oe(P,Y):Li),D=new D(T,Ae),P.memoizedState=D.state!==null&&D.state!==void 0?D.state:null,D.updater=$r,P.stateNode=D,D._reactInternalFiber=P,q&&(P=P.stateNode,P.__reactInternalMemoizedUnmaskedChildContext=Y,P.__reactInternalMemoizedMaskedChildContext=Ae),D}function bi(P,D,T,q){P=D.state,typeof D.componentWillReceiveProps=="function"&&D.componentWillReceiveProps(T,q),typeof D.UNSAFE_componentWillReceiveProps=="function"&&D.UNSAFE_componentWillReceiveProps(T,q),D.state!==P&&$r.enqueueReplaceState(D,D.state,null)}function qo(P,D,T,q){var Y=P.stateNode;Y.props=T,Y.state=P.memoizedState,Y.refs=Tt;var Ae=D.contextType;typeof Ae=="object"&&Ae!==null?Y.context=ms(Ae):(Ae=ii(D)?rr:Mn.current,Y.context=Oe(P,Ae)),Ae=P.updateQueue,Ae!==null&&(ye(P,Ae,T,Y,q),Y.state=P.memoizedState),Ae=D.getDerivedStateFromProps,typeof Ae=="function"&&(er(P,D,Ae,T),Y.state=P.memoizedState),typeof D.getDerivedStateFromProps=="function"||typeof Y.getSnapshotBeforeUpdate=="function"||typeof Y.UNSAFE_componentWillMount!="function"&&typeof Y.componentWillMount!="function"||(D=Y.state,typeof Y.componentWillMount=="function"&&Y.componentWillMount(),typeof Y.UNSAFE_componentWillMount=="function"&&Y.UNSAFE_componentWillMount(),D!==Y.state&&$r.enqueueReplaceState(Y,Y.state,null),Ae=P.updateQueue,Ae!==null&&(ye(P,Ae,T,Y,q),Y.state=P.memoizedState)),typeof Y.componentDidMount=="function"&&(P.effectTag|=4)}var kA=Array.isArray;function QA(P,D,T){if(P=T.ref,P!==null&&typeof P!="function"&&typeof P!="object"){if(T._owner){if(T=T._owner,T){if(T.tag!==1)throw Error(n(309));var q=T.stateNode}if(!q)throw Error(n(147,P));var Y=""+P;return D!==null&&D.ref!==null&&typeof D.ref=="function"&&D.ref._stringRef===Y?D.ref:(D=function(Ae){var De=q.refs;De===Tt&&(De=q.refs={}),Ae===null?delete De[Y]:De[Y]=Ae},D._stringRef=Y,D)}if(typeof P!="string")throw Error(n(284));if(!T._owner)throw Error(n(290,P))}return P}function fp(P,D){if(P.type!=="textarea")throw Error(n(31,Object.prototype.toString.call(D)==="[object Object]"?"object with keys {"+Object.keys(D).join(", ")+"}":D,""))}function sg(P){function D(rt,ze){if(P){var ft=rt.lastEffect;ft!==null?(ft.nextEffect=ze,rt.lastEffect=ze):rt.firstEffect=rt.lastEffect=ze,ze.nextEffect=null,ze.effectTag=8}}function T(rt,ze){if(!P)return null;for(;ze!==null;)D(rt,ze),ze=ze.sibling;return null}function q(rt,ze){for(rt=new Map;ze!==null;)ze.key!==null?rt.set(ze.key,ze):rt.set(ze.index,ze),ze=ze.sibling;return rt}function Y(rt,ze,ft){return rt=WA(rt,ze,ft),rt.index=0,rt.sibling=null,rt}function Ae(rt,ze,ft){return rt.index=ft,P?(ft=rt.alternate,ft!==null?(ft=ft.index,ft<ze?(rt.effectTag=2,ze):ft):(rt.effectTag=2,ze)):ze}function De(rt){return P&&rt.alternate===null&&(rt.effectTag=2),rt}function vt(rt,ze,ft,Wt){return ze===null||ze.tag!==6?(ze=Fw(ft,rt.mode,Wt),ze.return=rt,ze):(ze=Y(ze,ft,Wt),ze.return=rt,ze)}function wt(rt,ze,ft,Wt){return ze!==null&&ze.elementType===ft.type?(Wt=Y(ze,ft.props,Wt),Wt.ref=QA(rt,ze,ft),Wt.return=rt,Wt):(Wt=qm(ft.type,ft.key,ft.props,null,rt.mode,Wt),Wt.ref=QA(rt,ze,ft),Wt.return=rt,Wt)}function xt(rt,ze,ft,Wt){return ze===null||ze.tag!==4||ze.stateNode.containerInfo!==ft.containerInfo||ze.stateNode.implementation!==ft.implementation?(ze=Rw(ft,rt.mode,Wt),ze.return=rt,ze):(ze=Y(ze,ft.children||[],Wt),ze.return=rt,ze)}function _r(rt,ze,ft,Wt,vr){return ze===null||ze.tag!==7?(ze=xu(ft,rt.mode,Wt,vr),ze.return=rt,ze):(ze=Y(ze,ft,Wt),ze.return=rt,ze)}function is(rt,ze,ft){if(typeof ze=="string"||typeof ze=="number")return ze=Fw(""+ze,rt.mode,ft),ze.return=rt,ze;if(typeof ze=="object"&&ze!==null){switch(ze.$$typeof){case p:return ft=qm(ze.type,ze.key,ze.props,null,rt.mode,ft),ft.ref=QA(rt,null,ze),ft.return=rt,ft;case h:return ze=Rw(ze,rt.mode,ft),ze.return=rt,ze}if(kA(ze)||ue(ze))return ze=xu(ze,rt.mode,ft,null),ze.return=rt,ze;fp(rt,ze)}return null}function di(rt,ze,ft,Wt){var vr=ze!==null?ze.key:null;if(typeof ft=="string"||typeof ft=="number")return vr!==null?null:vt(rt,ze,""+ft,Wt);if(typeof ft=="object"&&ft!==null){switch(ft.$$typeof){case p:return ft.key===vr?ft.type===E?_r(rt,ze,ft.props.children,Wt,vr):wt(rt,ze,ft,Wt):null;case h:return ft.key===vr?xt(rt,ze,ft,Wt):null}if(kA(ft)||ue(ft))return vr!==null?null:_r(rt,ze,ft,Wt,null);fp(rt,ft)}return null}function po(rt,ze,ft,Wt,vr){if(typeof Wt=="string"||typeof Wt=="number")return rt=rt.get(ft)||null,vt(ze,rt,""+Wt,vr);if(typeof Wt=="object"&&Wt!==null){switch(Wt.$$typeof){case p:return rt=rt.get(Wt.key===null?ft:Wt.key)||null,Wt.type===E?_r(ze,rt,Wt.props.children,vr,Wt.key):wt(ze,rt,Wt,vr);case h:return rt=rt.get(Wt.key===null?ft:Wt.key)||null,xt(ze,rt,Wt,vr)}if(kA(Wt)||ue(Wt))return rt=rt.get(ft)||null,_r(ze,rt,Wt,vr,null);fp(ze,Wt)}return null}function zA(rt,ze,ft,Wt){for(var vr=null,Sn=null,Fr=ze,bn=ze=0,ai=null;Fr!==null&&bn<ft.length;bn++){Fr.index>bn?(ai=Fr,Fr=null):ai=Fr.sibling;var tn=di(rt,Fr,ft[bn],Wt);if(tn===null){Fr===null&&(Fr=ai);break}P&&Fr&&tn.alternate===null&&D(rt,Fr),ze=Ae(tn,ze,bn),Sn===null?vr=tn:Sn.sibling=tn,Sn=tn,Fr=ai}if(bn===ft.length)return T(rt,Fr),vr;if(Fr===null){for(;bn<ft.length;bn++)Fr=is(rt,ft[bn],Wt),Fr!==null&&(ze=Ae(Fr,ze,bn),Sn===null?vr=Fr:Sn.sibling=Fr,Sn=Fr);return vr}for(Fr=q(rt,Fr);bn<ft.length;bn++)ai=po(Fr,rt,bn,ft[bn],Wt),ai!==null&&(P&&ai.alternate!==null&&Fr.delete(ai.key===null?bn:ai.key),ze=Ae(ai,ze,bn),Sn===null?vr=ai:Sn.sibling=ai,Sn=ai);return P&&Fr.forEach(function(ho){return D(rt,ho)}),vr}function Yo(rt,ze,ft,Wt){var vr=ue(ft);if(typeof vr!="function")throw Error(n(150));if(ft=vr.call(ft),ft==null)throw Error(n(151));for(var Sn=vr=null,Fr=ze,bn=ze=0,ai=null,tn=ft.next();Fr!==null&&!tn.done;bn++,tn=ft.next()){Fr.index>bn?(ai=Fr,Fr=null):ai=Fr.sibling;var ho=di(rt,Fr,tn.value,Wt);if(ho===null){Fr===null&&(Fr=ai);break}P&&Fr&&ho.alternate===null&&D(rt,Fr),ze=Ae(ho,ze,bn),Sn===null?vr=ho:Sn.sibling=ho,Sn=ho,Fr=ai}if(tn.done)return T(rt,Fr),vr;if(Fr===null){for(;!tn.done;bn++,tn=ft.next())tn=is(rt,tn.value,Wt),tn!==null&&(ze=Ae(tn,ze,bn),Sn===null?vr=tn:Sn.sibling=tn,Sn=tn);return vr}for(Fr=q(rt,Fr);!tn.done;bn++,tn=ft.next())tn=po(Fr,rt,bn,tn.value,Wt),tn!==null&&(P&&tn.alternate!==null&&Fr.delete(tn.key===null?bn:tn.key),ze=Ae(tn,ze,bn),Sn===null?vr=tn:Sn.sibling=tn,Sn=tn);return P&&Fr.forEach(function(vF){return D(rt,vF)}),vr}return function(rt,ze,ft,Wt){var vr=typeof ft=="object"&&ft!==null&&ft.type===E&&ft.key===null;vr&&(ft=ft.props.children);var Sn=typeof ft=="object"&&ft!==null;if(Sn)switch(ft.$$typeof){case p:e:{for(Sn=ft.key,vr=ze;vr!==null;){if(vr.key===Sn)if(vr.tag===7?ft.type===E:vr.elementType===ft.type){T(rt,vr.sibling),ze=Y(vr,ft.type===E?ft.props.children:ft.props,Wt),ze.ref=QA(rt,vr,ft),ze.return=rt,rt=ze;break e}else{T(rt,vr);break}else D(rt,vr);vr=vr.sibling}ft.type===E?(ze=xu(ft.props.children,rt.mode,Wt,ft.key),ze.return=rt,rt=ze):(Wt=qm(ft.type,ft.key,ft.props,null,rt.mode,Wt),Wt.ref=QA(rt,ze,ft),Wt.return=rt,rt=Wt)}return De(rt);case h:e:{for(vr=ft.key;ze!==null;){if(ze.key===vr)if(ze.tag===4&&ze.stateNode.containerInfo===ft.containerInfo&&ze.stateNode.implementation===ft.implementation){T(rt,ze.sibling),ze=Y(ze,ft.children||[],Wt),ze.return=rt,rt=ze;break e}else{T(rt,ze);break}else D(rt,ze);ze=ze.sibling}ze=Rw(ft,rt.mode,Wt),ze.return=rt,rt=ze}return De(rt)}if(typeof ft=="string"||typeof ft=="number")return ft=""+ft,ze!==null&&ze.tag===6?(T(rt,ze.sibling),ze=Y(ze,ft,Wt),ze.return=rt,rt=ze):(T(rt,ze),ze=Fw(ft,rt.mode,Wt),ze.return=rt,rt=ze),De(rt);if(kA(ft))return zA(rt,ze,ft,Wt);if(ue(ft))return Yo(rt,ze,ft,Wt);if(Sn&&fp(rt,ft),typeof ft>"u"&&!vr)switch(rt.tag){case 1:case 0:throw rt=rt.type,Error(n(152,rt.displayName||rt.name||"Component"))}return T(rt,ze)}}var du=sg(!0),og=sg(!1),mu={},uo={current:mu},FA={current:mu},yc={current:mu};function ca(P){if(P===mu)throw Error(n(174));return P}function ag(P,D){On(yc,D,P),On(FA,P,P),On(uo,mu,P),D=ne(D),zn(uo,P),On(uo,D,P)}function Ec(P){zn(uo,P),zn(FA,P),zn(yc,P)}function Sm(P){var D=ca(yc.current),T=ca(uo.current);D=ee(T,P.type,D),T!==D&&(On(FA,P,P),On(uo,D,P))}function lg(P){FA.current===P&&(zn(uo,P),zn(FA,P))}var ei={current:0};function pp(P){for(var D=P;D!==null;){if(D.tag===13){var T=D.memoizedState;if(T!==null&&(T=T.dehydrated,T===null||Ns(T)||so(T)))return D}else if(D.tag===19&&D.memoizedProps.revealOrder!==void 0){if((D.effectTag&64)!==0)return D}else if(D.child!==null){D.child.return=D,D=D.child;continue}if(D===P)break;for(;D.sibling===null;){if(D.return===null||D.return===P)return null;D=D.return}D.sibling.return=D.return,D=D.sibling}return null}function cg(P,D){return{responder:P,props:D}}var RA=u.ReactCurrentDispatcher,Hs=u.ReactCurrentBatchConfig,yu=0,qa=null,ji=null,ua=null,Eu=null,Es=null,Cc=null,wc=0,j=null,Dt=0,Il=!1,xi=null,Ic=0;function ct(){throw Error(n(321))}function Cu(P,D){if(D===null)return!1;for(var T=0;T<D.length&&T<P.length;T++)if(!hs(P[T],D[T]))return!1;return!0}function ug(P,D,T,q,Y,Ae){if(yu=Ae,qa=D,ua=P!==null?P.memoizedState:null,RA.current=ua===null?Ew:km,D=T(q,Y),Il){do Il=!1,Ic+=1,ua=P!==null?P.memoizedState:null,Cc=Eu,j=Es=ji=null,RA.current=km,D=T(q,Y);while(Il);xi=null,Ic=0}if(RA.current=Iu,P=qa,P.memoizedState=Eu,P.expirationTime=wc,P.updateQueue=j,P.effectTag|=Dt,P=ji!==null&&ji.next!==null,yu=0,Cc=Es=Eu=ua=ji=qa=null,wc=0,j=null,Dt=0,P)throw Error(n(300));return D}function yw(){RA.current=Iu,yu=0,Cc=Es=Eu=ua=ji=qa=null,wc=0,j=null,Dt=0,Il=!1,xi=null,Ic=0}function TA(){var P={memoizedState:null,baseState:null,queue:null,baseUpdate:null,next:null};return Es===null?Eu=Es=P:Es=Es.next=P,Es}function hp(){if(Cc!==null)Es=Cc,Cc=Es.next,ji=ua,ua=ji!==null?ji.next:null;else{if(ua===null)throw Error(n(310));ji=ua;var P={memoizedState:ji.memoizedState,baseState:ji.baseState,queue:ji.queue,baseUpdate:ji.baseUpdate,next:null};Es=Es===null?Eu=P:Es.next=P,ua=ji.next}return Es}function Br(P,D){return typeof D=="function"?D(P):D}function Cs(P){var D=hp(),T=D.queue;if(T===null)throw Error(n(311));if(T.lastRenderedReducer=P,0<Ic){var q=T.dispatch;if(xi!==null){var Y=xi.get(T);if(Y!==void 0){xi.delete(T);var Ae=D.memoizedState;do Ae=P(Ae,Y.action),Y=Y.next;while(Y!==null);return hs(Ae,D.memoizedState)||(Go=!0),D.memoizedState=Ae,D.baseUpdate===T.last&&(D.baseState=Ae),T.lastRenderedState=Ae,[Ae,q]}}return[D.memoizedState,q]}q=T.last;var De=D.baseUpdate;if(Ae=D.baseState,De!==null?(q!==null&&(q.next=null),q=De.next):q=q!==null?q.next:null,q!==null){var vt=Y=null,wt=q,xt=!1;do{var _r=wt.expirationTime;_r<yu?(xt||(xt=!0,vt=De,Y=Ae),_r>wc&&(wc=_r,Hm(wc))):(Sw(_r,wt.suspenseConfig),Ae=wt.eagerReducer===P?wt.eagerState:P(Ae,wt.action)),De=wt,wt=wt.next}while(wt!==null&&wt!==q);xt||(vt=De,Y=Ae),hs(Ae,D.memoizedState)||(Go=!0),D.memoizedState=Ae,D.baseUpdate=vt,D.baseState=Y,T.lastRenderedState=Ae}return[D.memoizedState,T.dispatch]}function Ag(P){var D=TA();return typeof P=="function"&&(P=P()),D.memoizedState=D.baseState=P,P=D.queue={last:null,dispatch:null,lastRenderedReducer:Br,lastRenderedState:P},P=P.dispatch=dg.bind(null,qa,P),[D.memoizedState,P]}function fg(P){return Cs(Br,P)}function pg(P,D,T,q){return P={tag:P,create:D,destroy:T,deps:q,next:null},j===null?(j={lastEffect:null},j.lastEffect=P.next=P):(D=j.lastEffect,D===null?j.lastEffect=P.next=P:(T=D.next,D.next=P,P.next=T,j.lastEffect=P)),P}function gp(P,D,T,q){var Y=TA();Dt|=P,Y.memoizedState=pg(D,T,void 0,q===void 0?null:q)}function Bc(P,D,T,q){var Y=hp();q=q===void 0?null:q;var Ae=void 0;if(ji!==null){var De=ji.memoizedState;if(Ae=De.destroy,q!==null&&Cu(q,De.deps)){pg(0,T,Ae,q);return}}Dt|=P,Y.memoizedState=pg(D,T,Ae,q)}function Ct(P,D){return gp(516,192,P,D)}function bm(P,D){return Bc(516,192,P,D)}function hg(P,D){if(typeof D=="function")return P=P(),D(P),function(){D(null)};if(D!=null)return P=P(),D.current=P,function(){D.current=null}}function gg(){}function wu(P,D){return TA().memoizedState=[P,D===void 0?null:D],P}function xm(P,D){var T=hp();D=D===void 0?null:D;var q=T.memoizedState;return q!==null&&D!==null&&Cu(D,q[1])?q[0]:(T.memoizedState=[P,D],P)}function dg(P,D,T){if(!(25>Ic))throw Error(n(301));var q=P.alternate;if(P===qa||q!==null&&q===qa)if(Il=!0,P={expirationTime:yu,suspenseConfig:null,action:T,eagerReducer:null,eagerState:null,next:null},xi===null&&(xi=new Map),T=xi.get(D),T===void 0)xi.set(D,P);else{for(D=T;D.next!==null;)D=D.next;D.next=P}else{var Y=ga(),Ae=ht.suspense;Y=qA(Y,P,Ae),Ae={expirationTime:Y,suspenseConfig:Ae,action:T,eagerReducer:null,eagerState:null,next:null};var De=D.last;if(De===null)Ae.next=Ae;else{var vt=De.next;vt!==null&&(Ae.next=vt),De.next=Ae}if(D.last=Ae,P.expirationTime===0&&(q===null||q.expirationTime===0)&&(q=D.lastRenderedReducer,q!==null))try{var wt=D.lastRenderedState,xt=q(wt,T);if(Ae.eagerReducer=q,Ae.eagerState=xt,hs(xt,wt))return}catch{}finally{}bc(P,Y)}}var Iu={readContext:ms,useCallback:ct,useContext:ct,useEffect:ct,useImperativeHandle:ct,useLayoutEffect:ct,useMemo:ct,useReducer:ct,useRef:ct,useState:ct,useDebugValue:ct,useResponder:ct,useDeferredValue:ct,useTransition:ct},Ew={readContext:ms,useCallback:wu,useContext:ms,useEffect:Ct,useImperativeHandle:function(P,D,T){return T=T!=null?T.concat([P]):null,gp(4,36,hg.bind(null,D,P),T)},useLayoutEffect:function(P,D){return gp(4,36,P,D)},useMemo:function(P,D){var T=TA();return D=D===void 0?null:D,P=P(),T.memoizedState=[P,D],P},useReducer:function(P,D,T){var q=TA();return D=T!==void 0?T(D):D,q.memoizedState=q.baseState=D,P=q.queue={last:null,dispatch:null,lastRenderedReducer:P,lastRenderedState:D},P=P.dispatch=dg.bind(null,qa,P),[q.memoizedState,P]},useRef:function(P){var D=TA();return P={current:P},D.memoizedState=P},useState:Ag,useDebugValue:gg,useResponder:cg,useDeferredValue:function(P,D){var T=Ag(P),q=T[0],Y=T[1];return Ct(function(){a.unstable_next(function(){var Ae=Hs.suspense;Hs.suspense=D===void 0?null:D;try{Y(P)}finally{Hs.suspense=Ae}})},[P,D]),q},useTransition:function(P){var D=Ag(!1),T=D[0],q=D[1];return[wu(function(Y){q(!0),a.unstable_next(function(){var Ae=Hs.suspense;Hs.suspense=P===void 0?null:P;try{q(!1),Y()}finally{Hs.suspense=Ae}})},[P,T]),T]}},km={readContext:ms,useCallback:xm,useContext:ms,useEffect:bm,useImperativeHandle:function(P,D,T){return T=T!=null?T.concat([P]):null,Bc(4,36,hg.bind(null,D,P),T)},useLayoutEffect:function(P,D){return Bc(4,36,P,D)},useMemo:function(P,D){var T=hp();D=D===void 0?null:D;var q=T.memoizedState;return q!==null&&D!==null&&Cu(D,q[1])?q[0]:(P=P(),T.memoizedState=[P,D],P)},useReducer:Cs,useRef:function(){return hp().memoizedState},useState:fg,useDebugValue:gg,useResponder:cg,useDeferredValue:function(P,D){var T=fg(P),q=T[0],Y=T[1];return bm(function(){a.unstable_next(function(){var Ae=Hs.suspense;Hs.suspense=D===void 0?null:D;try{Y(P)}finally{Hs.suspense=Ae}})},[P,D]),q},useTransition:function(P){var D=fg(!1),T=D[0],q=D[1];return[xm(function(Y){q(!0),a.unstable_next(function(){var Ae=Hs.suspense;Hs.suspense=P===void 0?null:P;try{q(!1),Y()}finally{Hs.suspense=Ae}})},[P,T]),T]}},Aa=null,vc=null,Bl=!1;function Bu(P,D){var T=Pl(5,null,null,0);T.elementType="DELETED",T.type="DELETED",T.stateNode=D,T.return=P,T.effectTag=8,P.lastEffect!==null?(P.lastEffect.nextEffect=T,P.lastEffect=T):P.firstEffect=P.lastEffect=T}function mg(P,D){switch(P.tag){case 5:return D=io(D,P.type,P.pendingProps),D!==null?(P.stateNode=D,!0):!1;case 6:return D=Si(D,P.pendingProps),D!==null?(P.stateNode=D,!0):!1;case 13:return!1;default:return!1}}function LA(P){if(Bl){var D=vc;if(D){var T=D;if(!mg(P,D)){if(D=uc(T),!D||!mg(P,D)){P.effectTag=P.effectTag&-1025|2,Bl=!1,Aa=P;return}Bu(Aa,T)}Aa=P,vc=uu(D)}else P.effectTag=P.effectTag&-1025|2,Bl=!1,Aa=P}}function dp(P){for(P=P.return;P!==null&&P.tag!==5&&P.tag!==3&&P.tag!==13;)P=P.return;Aa=P}function Ga(P){if(!y||P!==Aa)return!1;if(!Bl)return dp(P),Bl=!0,!1;var D=P.type;if(P.tag!==5||D!=="head"&&D!=="body"&&!ke(D,P.memoizedProps))for(D=vc;D;)Bu(P,D),D=uc(D);if(dp(P),P.tag===13){if(!y)throw Error(n(316));if(P=P.memoizedState,P=P!==null?P.dehydrated:null,!P)throw Error(n(317));vc=Os(P)}else vc=Aa?uc(P.stateNode):null;return!0}function yg(){y&&(vc=Aa=null,Bl=!1)}var mp=u.ReactCurrentOwner,Go=!1;function ws(P,D,T,q){D.child=P===null?og(D,null,T,q):du(D,P.child,T,q)}function Ii(P,D,T,q,Y){T=T.render;var Ae=D.ref;return ds(D,Y),q=ug(P,D,T,q,Ae,Y),P!==null&&!Go?(D.updateQueue=P.updateQueue,D.effectTag&=-517,P.expirationTime<=Y&&(P.expirationTime=0),si(P,D,Y)):(D.effectTag|=1,ws(P,D,q,Y),D.child)}function Qm(P,D,T,q,Y,Ae){if(P===null){var De=T.type;return typeof De=="function"&&!Qw(De)&&De.defaultProps===void 0&&T.compare===null&&T.defaultProps===void 0?(D.tag=15,D.type=De,Fm(P,D,De,q,Y,Ae)):(P=qm(T.type,null,q,null,D.mode,Ae),P.ref=D.ref,P.return=D,D.child=P)}return De=P.child,Y<Ae&&(Y=De.memoizedProps,T=T.compare,T=T!==null?T:Fn,T(Y,q)&&P.ref===D.ref)?si(P,D,Ae):(D.effectTag|=1,P=WA(De,q,Ae),P.ref=D.ref,P.return=D,D.child=P)}function Fm(P,D,T,q,Y,Ae){return P!==null&&Fn(P.memoizedProps,q)&&P.ref===D.ref&&(Go=!1,Y<Ae)?si(P,D,Ae):NA(P,D,T,q,Ae)}function jo(P,D){var T=D.ref;(P===null&&T!==null||P!==null&&P.ref!==T)&&(D.effectTag|=128)}function NA(P,D,T,q,Y){var Ae=ii(T)?rr:Mn.current;return Ae=Oe(D,Ae),ds(D,Y),T=ug(P,D,T,q,Ae,Y),P!==null&&!Go?(D.updateQueue=P.updateQueue,D.effectTag&=-517,P.expirationTime<=Y&&(P.expirationTime=0),si(P,D,Y)):(D.effectTag|=1,ws(P,D,T,Y),D.child)}function yp(P,D,T,q,Y){if(ii(T)){var Ae=!0;fc(D)}else Ae=!1;if(ds(D,Y),D.stateNode===null)P!==null&&(P.alternate=null,D.alternate=null,D.effectTag|=2),es(D,T,q,Y),qo(D,T,q,Y),q=!0;else if(P===null){var De=D.stateNode,vt=D.memoizedProps;De.props=vt;var wt=De.context,xt=T.contextType;typeof xt=="object"&&xt!==null?xt=ms(xt):(xt=ii(T)?rr:Mn.current,xt=Oe(D,xt));var _r=T.getDerivedStateFromProps,is=typeof _r=="function"||typeof De.getSnapshotBeforeUpdate=="function";is||typeof De.UNSAFE_componentWillReceiveProps!="function"&&typeof De.componentWillReceiveProps!="function"||(vt!==q||wt!==xt)&&bi(D,De,q,xt),_s=!1;var di=D.memoizedState;wt=De.state=di;var po=D.updateQueue;po!==null&&(ye(D,po,q,De,Y),wt=D.memoizedState),vt!==q||di!==wt||_i.current||_s?(typeof _r=="function"&&(er(D,T,_r,q),wt=D.memoizedState),(vt=_s||Gi(D,T,vt,q,di,wt,xt))?(is||typeof De.UNSAFE_componentWillMount!="function"&&typeof De.componentWillMount!="function"||(typeof De.componentWillMount=="function"&&De.componentWillMount(),typeof De.UNSAFE_componentWillMount=="function"&&De.UNSAFE_componentWillMount()),typeof De.componentDidMount=="function"&&(D.effectTag|=4)):(typeof De.componentDidMount=="function"&&(D.effectTag|=4),D.memoizedProps=q,D.memoizedState=wt),De.props=q,De.state=wt,De.context=xt,q=vt):(typeof De.componentDidMount=="function"&&(D.effectTag|=4),q=!1)}else De=D.stateNode,vt=D.memoizedProps,De.props=D.type===D.elementType?vt:Ci(D.type,vt),wt=De.context,xt=T.contextType,typeof xt=="object"&&xt!==null?xt=ms(xt):(xt=ii(T)?rr:Mn.current,xt=Oe(D,xt)),_r=T.getDerivedStateFromProps,(is=typeof _r=="function"||typeof De.getSnapshotBeforeUpdate=="function")||typeof De.UNSAFE_componentWillReceiveProps!="function"&&typeof De.componentWillReceiveProps!="function"||(vt!==q||wt!==xt)&&bi(D,De,q,xt),_s=!1,wt=D.memoizedState,di=De.state=wt,po=D.updateQueue,po!==null&&(ye(D,po,q,De,Y),di=D.memoizedState),vt!==q||wt!==di||_i.current||_s?(typeof _r=="function"&&(er(D,T,_r,q),di=D.memoizedState),(_r=_s||Gi(D,T,vt,q,wt,di,xt))?(is||typeof De.UNSAFE_componentWillUpdate!="function"&&typeof De.componentWillUpdate!="function"||(typeof De.componentWillUpdate=="function"&&De.componentWillUpdate(q,di,xt),typeof De.UNSAFE_componentWillUpdate=="function"&&De.UNSAFE_componentWillUpdate(q,di,xt)),typeof De.componentDidUpdate=="function"&&(D.effectTag|=4),typeof De.getSnapshotBeforeUpdate=="function"&&(D.effectTag|=256)):(typeof De.componentDidUpdate!="function"||vt===P.memoizedProps&&wt===P.memoizedState||(D.effectTag|=4),typeof De.getSnapshotBeforeUpdate!="function"||vt===P.memoizedProps&&wt===P.memoizedState||(D.effectTag|=256),D.memoizedProps=q,D.memoizedState=di),De.props=q,De.state=di,De.context=xt,q=_r):(typeof De.componentDidUpdate!="function"||vt===P.memoizedProps&&wt===P.memoizedState||(D.effectTag|=4),typeof De.getSnapshotBeforeUpdate!="function"||vt===P.memoizedProps&&wt===P.memoizedState||(D.effectTag|=256),q=!1);return Ep(P,D,T,q,Ae,Y)}function Ep(P,D,T,q,Y,Ae){jo(P,D);var De=(D.effectTag&64)!==0;if(!q&&!De)return Y&&Cl(D,T,!1),si(P,D,Ae);q=D.stateNode,mp.current=D;var vt=De&&typeof T.getDerivedStateFromError!="function"?null:q.render();return D.effectTag|=1,P!==null&&De?(D.child=du(D,P.child,null,Ae),D.child=du(D,null,vt,Ae)):ws(P,D,vt,Ae),D.memoizedState=q.state,Y&&Cl(D,T,!0),D.child}function Eg(P){var D=P.stateNode;D.pendingContext?Ac(P,D.pendingContext,D.pendingContext!==D.context):D.context&&Ac(P,D.context,!1),ag(P,D.containerInfo)}var fa={dehydrated:null,retryTime:0};function ln(P,D,T){var q=D.mode,Y=D.pendingProps,Ae=ei.current,De=!1,vt;if((vt=(D.effectTag&64)!==0)||(vt=(Ae&2)!==0&&(P===null||P.memoizedState!==null)),vt?(De=!0,D.effectTag&=-65):P!==null&&P.memoizedState===null||Y.fallback===void 0||Y.unstable_avoidThisFallback===!0||(Ae|=1),On(ei,Ae&1,D),P===null){if(Y.fallback!==void 0&&LA(D),De){if(De=Y.fallback,Y=xu(null,q,0,null),Y.return=D,(D.mode&2)===0)for(P=D.memoizedState!==null?D.child.child:D.child,Y.child=P;P!==null;)P.return=Y,P=P.sibling;return T=xu(De,q,T,null),T.return=D,Y.sibling=T,D.memoizedState=fa,D.child=Y,T}return q=Y.children,D.memoizedState=null,D.child=og(D,null,q,T)}if(P.memoizedState!==null){if(P=P.child,q=P.sibling,De){if(Y=Y.fallback,T=WA(P,P.pendingProps,0),T.return=D,(D.mode&2)===0&&(De=D.memoizedState!==null?D.child.child:D.child,De!==P.child))for(T.child=De;De!==null;)De.return=T,De=De.sibling;return q=WA(q,Y,q.expirationTime),q.return=D,T.sibling=q,T.childExpirationTime=0,D.memoizedState=fa,D.child=T,q}return T=du(D,P.child,Y.children,T),D.memoizedState=null,D.child=T}if(P=P.child,De){if(De=Y.fallback,Y=xu(null,q,0,null),Y.return=D,Y.child=P,P!==null&&(P.return=Y),(D.mode&2)===0)for(P=D.memoizedState!==null?D.child.child:D.child,Y.child=P;P!==null;)P.return=Y,P=P.sibling;return T=xu(De,q,T,null),T.return=D,Y.sibling=T,T.effectTag|=2,Y.childExpirationTime=0,D.memoizedState=fa,D.child=Y,T}return D.memoizedState=null,D.child=du(D,P,Y.children,T)}function Ao(P,D){P.expirationTime<D&&(P.expirationTime=D);var T=P.alternate;T!==null&&T.expirationTime<D&&(T.expirationTime=D),gs(P.return,D)}function OA(P,D,T,q,Y,Ae){var De=P.memoizedState;De===null?P.memoizedState={isBackwards:D,rendering:null,last:q,tail:T,tailExpiration:0,tailMode:Y,lastEffect:Ae}:(De.isBackwards=D,De.rendering=null,De.last=q,De.tail=T,De.tailExpiration=0,De.tailMode=Y,De.lastEffect=Ae)}function ja(P,D,T){var q=D.pendingProps,Y=q.revealOrder,Ae=q.tail;if(ws(P,D,q.children,T),q=ei.current,(q&2)!==0)q=q&1|2,D.effectTag|=64;else{if(P!==null&&(P.effectTag&64)!==0)e:for(P=D.child;P!==null;){if(P.tag===13)P.memoizedState!==null&&Ao(P,T);else if(P.tag===19)Ao(P,T);else if(P.child!==null){P.child.return=P,P=P.child;continue}if(P===D)break e;for(;P.sibling===null;){if(P.return===null||P.return===D)break e;P=P.return}P.sibling.return=P.return,P=P.sibling}q&=1}if(On(ei,q,D),(D.mode&2)===0)D.memoizedState=null;else switch(Y){case"forwards":for(T=D.child,Y=null;T!==null;)P=T.alternate,P!==null&&pp(P)===null&&(Y=T),T=T.sibling;T=Y,T===null?(Y=D.child,D.child=null):(Y=T.sibling,T.sibling=null),OA(D,!1,Y,T,Ae,D.lastEffect);break;case"backwards":for(T=null,Y=D.child,D.child=null;Y!==null;){if(P=Y.alternate,P!==null&&pp(P)===null){D.child=Y;break}P=Y.sibling,Y.sibling=T,T=Y,Y=P}OA(D,!0,T,null,Ae,D.lastEffect);break;case"together":OA(D,!1,null,null,void 0,D.lastEffect);break;default:D.memoizedState=null}return D.child}function si(P,D,T){P!==null&&(D.dependencies=P.dependencies);var q=D.expirationTime;if(q!==0&&Hm(q),D.childExpirationTime<T)return null;if(P!==null&&D.child!==P.child)throw Error(n(153));if(D.child!==null){for(P=D.child,T=WA(P,P.pendingProps,P.expirationTime),D.child=T,T.return=D;P.sibling!==null;)P=P.sibling,T=T.sibling=WA(P,P.pendingProps,P.expirationTime),T.return=D;T.sibling=null}return D.child}function pa(P){P.effectTag|=4}var Dc,vl,ts,jr;if(w)Dc=function(P,D){for(var T=D.child;T!==null;){if(T.tag===5||T.tag===6)H(P,T.stateNode);else if(T.tag!==4&&T.child!==null){T.child.return=T,T=T.child;continue}if(T===D)break;for(;T.sibling===null;){if(T.return===null||T.return===D)return;T=T.return}T.sibling.return=T.return,T=T.sibling}},vl=function(){},ts=function(P,D,T,q,Y){if(P=P.memoizedProps,P!==q){var Ae=D.stateNode,De=ca(uo.current);T=Re(Ae,T,P,q,Y,De),(D.updateQueue=T)&&pa(D)}},jr=function(P,D,T,q){T!==q&&pa(D)};else if(S){Dc=function(P,D,T,q){for(var Y=D.child;Y!==null;){if(Y.tag===5){var Ae=Y.stateNode;T&&q&&(Ae=Ti(Ae,Y.type,Y.memoizedProps,Y)),H(P,Ae)}else if(Y.tag===6)Ae=Y.stateNode,T&&q&&(Ae=ps(Ae,Y.memoizedProps,Y)),H(P,Ae);else if(Y.tag!==4){if(Y.tag===13&&(Y.effectTag&4)!==0&&(Ae=Y.memoizedState!==null)){var De=Y.child;if(De!==null&&(De.child!==null&&(De.child.return=De,Dc(P,De,!0,Ae)),Ae=De.sibling,Ae!==null)){Ae.return=Y,Y=Ae;continue}}if(Y.child!==null){Y.child.return=Y,Y=Y.child;continue}}if(Y===D)break;for(;Y.sibling===null;){if(Y.return===null||Y.return===D)return;Y=Y.return}Y.sibling.return=Y.return,Y=Y.sibling}};var Cp=function(P,D,T,q){for(var Y=D.child;Y!==null;){if(Y.tag===5){var Ae=Y.stateNode;T&&q&&(Ae=Ti(Ae,Y.type,Y.memoizedProps,Y)),Wr(P,Ae)}else if(Y.tag===6)Ae=Y.stateNode,T&&q&&(Ae=ps(Ae,Y.memoizedProps,Y)),Wr(P,Ae);else if(Y.tag!==4){if(Y.tag===13&&(Y.effectTag&4)!==0&&(Ae=Y.memoizedState!==null)){var De=Y.child;if(De!==null&&(De.child!==null&&(De.child.return=De,Cp(P,De,!0,Ae)),Ae=De.sibling,Ae!==null)){Ae.return=Y,Y=Ae;continue}}if(Y.child!==null){Y.child.return=Y,Y=Y.child;continue}}if(Y===D)break;for(;Y.sibling===null;){if(Y.return===null||Y.return===D)return;Y=Y.return}Y.sibling.return=Y.return,Y=Y.sibling}};vl=function(P){var D=P.stateNode;if(P.firstEffect!==null){var T=D.containerInfo,q=br(T);Cp(q,P,!1,!1),D.pendingChildren=q,pa(P),Kn(T,q)}},ts=function(P,D,T,q,Y){var Ae=P.stateNode,De=P.memoizedProps;if((P=D.firstEffect===null)&&De===q)D.stateNode=Ae;else{var vt=D.stateNode,wt=ca(uo.current),xt=null;De!==q&&(xt=Re(vt,T,De,q,Y,wt)),P&&xt===null?D.stateNode=Ae:(Ae=mr(Ae,xt,T,De,q,D,P,vt),at(Ae,T,q,Y,wt)&&pa(D),D.stateNode=Ae,P?pa(D):Dc(Ae,D,!1,!1))}},jr=function(P,D,T,q){T!==q&&(P=ca(yc.current),T=ca(uo.current),D.stateNode=He(q,P,T,D),pa(D))}}else vl=function(){},ts=function(){},jr=function(){};function Pc(P,D){switch(P.tailMode){case"hidden":D=P.tail;for(var T=null;D!==null;)D.alternate!==null&&(T=D),D=D.sibling;T===null?P.tail=null:T.sibling=null;break;case"collapsed":T=P.tail;for(var q=null;T!==null;)T.alternate!==null&&(q=T),T=T.sibling;q===null?D||P.tail===null?P.tail=null:P.tail.sibling=null:q.sibling=null}}function Cw(P){switch(P.tag){case 1:ii(P.type)&&Ua(P);var D=P.effectTag;return D&4096?(P.effectTag=D&-4097|64,P):null;case 3:if(Ec(P),hr(P),D=P.effectTag,(D&64)!==0)throw Error(n(285));return P.effectTag=D&-4097|64,P;case 5:return lg(P),null;case 13:return zn(ei,P),D=P.effectTag,D&4096?(P.effectTag=D&-4097|64,P):null;case 19:return zn(ei,P),null;case 4:return Ec(P),null;case 10:return wi(P),null;default:return null}}function Cg(P,D){return{value:P,source:D,stack:yl(D)}}var wg=typeof WeakSet=="function"?WeakSet:Set;function Ya(P,D){var T=D.source,q=D.stack;q===null&&T!==null&&(q=yl(T)),T!==null&&he(T.type),D=D.value,P!==null&&P.tag===1&&he(P.type);try{console.error(D)}catch(Y){setTimeout(function(){throw Y})}}function Rm(P,D){try{D.props=P.memoizedProps,D.state=P.memoizedState,D.componentWillUnmount()}catch(T){YA(P,T)}}function Ig(P){var D=P.ref;if(D!==null)if(typeof D=="function")try{D(null)}catch(T){YA(P,T)}else D.current=null}function Qt(P,D){switch(D.tag){case 0:case 11:case 15:L(2,0,D);break;case 1:if(D.effectTag&256&&P!==null){var T=P.memoizedProps,q=P.memoizedState;P=D.stateNode,D=P.getSnapshotBeforeUpdate(D.elementType===D.type?T:Ci(D.type,T),q),P.__reactInternalSnapshotBeforeUpdate=D}break;case 3:case 5:case 6:case 4:case 17:break;default:throw Error(n(163))}}function L(P,D,T){if(T=T.updateQueue,T=T!==null?T.lastEffect:null,T!==null){var q=T=T.next;do{if((q.tag&P)!==0){var Y=q.destroy;q.destroy=void 0,Y!==void 0&&Y()}(q.tag&D)!==0&&(Y=q.create,q.destroy=Y()),q=q.next}while(q!==T)}}function K(P,D,T){switch(typeof kw=="function"&&kw(D),D.tag){case 0:case 11:case 14:case 15:if(P=D.updateQueue,P!==null&&(P=P.lastEffect,P!==null)){var q=P.next;lo(97<T?97:T,function(){var Y=q;do{var Ae=Y.destroy;if(Ae!==void 0){var De=D;try{Ae()}catch(vt){YA(De,vt)}}Y=Y.next}while(Y!==q)})}break;case 1:Ig(D),T=D.stateNode,typeof T.componentWillUnmount=="function"&&Rm(D,T);break;case 5:Ig(D);break;case 4:w?Cr(P,D,T):S&&Je(D)}}function re(P,D,T){for(var q=D;;)if(K(P,q,T),q.child===null||w&&q.tag===4){if(q===D)break;for(;q.sibling===null;){if(q.return===null||q.return===D)return;q=q.return}q.sibling.return=q.return,q=q.sibling}else q.child.return=q,q=q.child}function pe(P){var D=P.alternate;P.return=null,P.child=null,P.memoizedState=null,P.updateQueue=null,P.dependencies=null,P.alternate=null,P.firstEffect=null,P.lastEffect=null,P.pendingProps=null,P.memoizedProps=null,D!==null&&pe(D)}function Je(P){if(S){P=P.stateNode.containerInfo;var D=br(P);Ls(P,D)}}function mt(P){return P.tag===5||P.tag===3||P.tag===4}function fr(P){if(w){e:{for(var D=P.return;D!==null;){if(mt(D)){var T=D;break e}D=D.return}throw Error(n(160))}switch(D=T.stateNode,T.tag){case 5:var q=!1;break;case 3:D=D.containerInfo,q=!0;break;case 4:D=D.containerInfo,q=!0;break;default:throw Error(n(161))}T.effectTag&16&&(Gt(D),T.effectTag&=-17);e:t:for(T=P;;){for(;T.sibling===null;){if(T.return===null||mt(T.return)){T=null;break e}T=T.return}for(T.sibling.return=T.return,T=T.sibling;T.tag!==5&&T.tag!==6&&T.tag!==18;){if(T.effectTag&2||T.child===null||T.tag===4)continue t;T.child.return=T,T=T.child}if(!(T.effectTag&2)){T=T.stateNode;break e}}for(var Y=P;;){var Ae=Y.tag===5||Y.tag===6;if(Ae)Ae=Ae?Y.stateNode:Y.stateNode.instance,T?q?Le(D,Ae,T):be(D,Ae,T):q?J(D,Ae):F(D,Ae);else if(Y.tag!==4&&Y.child!==null){Y.child.return=Y,Y=Y.child;continue}if(Y===P)break;for(;Y.sibling===null;){if(Y.return===null||Y.return===P)return;Y=Y.return}Y.sibling.return=Y.return,Y=Y.sibling}}}function Cr(P,D,T){for(var q=D,Y=!1,Ae,De;;){if(!Y){Y=q.return;e:for(;;){if(Y===null)throw Error(n(160));switch(Ae=Y.stateNode,Y.tag){case 5:De=!1;break e;case 3:Ae=Ae.containerInfo,De=!0;break e;case 4:Ae=Ae.containerInfo,De=!0;break e}Y=Y.return}Y=!0}if(q.tag===5||q.tag===6)re(P,q,T),De?dt(Ae,q.stateNode):ot(Ae,q.stateNode);else if(q.tag===4){if(q.child!==null){Ae=q.stateNode.containerInfo,De=!0,q.child.return=q,q=q.child;continue}}else if(K(P,q,T),q.child!==null){q.child.return=q,q=q.child;continue}if(q===D)break;for(;q.sibling===null;){if(q.return===null||q.return===D)return;q=q.return,q.tag===4&&(Y=!1)}q.sibling.return=q.return,q=q.sibling}}function yn(P,D){if(w)switch(D.tag){case 0:case 11:case 14:case 15:L(4,8,D);break;case 1:break;case 5:var T=D.stateNode;if(T!=null){var q=D.memoizedProps;P=P!==null?P.memoizedProps:q;var Y=D.type,Ae=D.updateQueue;D.updateQueue=null,Ae!==null&&ie(T,Ae,Y,P,q,D)}break;case 6:if(D.stateNode===null)throw Error(n(162));T=D.memoizedProps,X(D.stateNode,P!==null?P.memoizedProps:T,T);break;case 3:y&&(D=D.stateNode,D.hydrate&&(D.hydrate=!1,Dn(D.containerInfo)));break;case 12:break;case 13:oi(D),Oi(D);break;case 19:Oi(D);break;case 17:break;case 20:break;case 21:break;default:throw Error(n(163))}else{switch(D.tag){case 0:case 11:case 14:case 15:L(4,8,D);return;case 12:return;case 13:oi(D),Oi(D);return;case 19:Oi(D);return;case 3:y&&(T=D.stateNode,T.hydrate&&(T.hydrate=!1,Dn(T.containerInfo)))}e:if(S)switch(D.tag){case 1:case 5:case 6:case 20:break e;case 3:case 4:D=D.stateNode,Ls(D.containerInfo,D.pendingChildren);break e;default:throw Error(n(163))}}}function oi(P){var D=P;if(P.memoizedState===null)var T=!1;else T=!0,D=P.child,Bw=Ni();if(w&&D!==null){e:if(P=D,w)for(D=P;;){if(D.tag===5){var q=D.stateNode;T?$t(q):an(D.stateNode,D.memoizedProps)}else if(D.tag===6)q=D.stateNode,T?bt(q):Qr(q,D.memoizedProps);else if(D.tag===13&&D.memoizedState!==null&&D.memoizedState.dehydrated===null){q=D.child.sibling,q.return=D,D=q;continue}else if(D.child!==null){D.child.return=D,D=D.child;continue}if(D===P)break e;for(;D.sibling===null;){if(D.return===null||D.return===P)break e;D=D.return}D.sibling.return=D.return,D=D.sibling}}}function Oi(P){var D=P.updateQueue;if(D!==null){P.updateQueue=null;var T=P.stateNode;T===null&&(T=P.stateNode=new wg),D.forEach(function(q){var Y=yF.bind(null,P,q);T.has(q)||(T.add(q),q.then(Y,Y))})}}var Bg=typeof WeakMap=="function"?WeakMap:Map;function jv(P,D,T){T=ys(T,null),T.tag=3,T.payload={element:null};var q=D.value;return T.callback=function(){Du||(Du=!0,Mm=q),Ya(P,D)},T}function Yv(P,D,T){T=ys(T,null),T.tag=3;var q=P.type.getDerivedStateFromError;if(typeof q=="function"){var Y=D.value;T.payload=function(){return Ya(P,D),q(Y)}}var Ae=P.stateNode;return Ae!==null&&typeof Ae.componentDidCatch=="function"&&(T.callback=function(){typeof q!="function"&&(Pu===null?Pu=new Set([this]):Pu.add(this),Ya(P,D));var De=D.stack;this.componentDidCatch(D.value,{componentStack:De!==null?De:""})}),T}var ww=Math.ceil,wp=u.ReactCurrentDispatcher,Iw=u.ReactCurrentOwner,En=0,Tm=8,rs=16,qs=32,vu=0,Lm=1,Bi=2,ha=3,Dl=4,Sc=5,yr=En,gi=null,Or=null,ns=0,Yi=vu,Nm=null,Wa=1073741823,MA=1073741823,Om=null,Ip=0,UA=!1,Bw=0,vw=500,or=null,Du=!1,Mm=null,Pu=null,Bp=!1,vg=null,_A=90,HA=null,Dg=0,Dw=null,Um=0;function ga(){return(yr&(rs|qs))!==En?1073741821-(Ni()/10|0):Um!==0?Um:Um=1073741821-(Ni()/10|0)}function qA(P,D,T){if(D=D.mode,(D&2)===0)return 1073741823;var q=_o();if((D&4)===0)return q===99?1073741823:1073741822;if((yr&rs)!==En)return ns;if(T!==null)P=Ha(P,T.timeoutMs|0||5e3,250);else switch(q){case 99:P=1073741823;break;case 98:P=Ha(P,150,100);break;case 97:case 96:P=Ha(P,5e3,250);break;case 95:P=2;break;default:throw Error(n(326))}return gi!==null&&P===ns&&--P,P}function bc(P,D){if(50<Dg)throw Dg=0,Dw=null,Error(n(185));if(P=Pg(P,D),P!==null){var T=_o();D===1073741823?(yr&Tm)!==En&&(yr&(rs|qs))===En?Pw(P):(fo(P),yr===En&&qi()):fo(P),(yr&4)===En||T!==98&&T!==99||(HA===null?HA=new Map([[P,D]]):(T=HA.get(P),(T===void 0||T>D)&&HA.set(P,D)))}}function Pg(P,D){P.expirationTime<D&&(P.expirationTime=D);var T=P.alternate;T!==null&&T.expirationTime<D&&(T.expirationTime=D);var q=P.return,Y=null;if(q===null&&P.tag===3)Y=P.stateNode;else for(;q!==null;){if(T=q.alternate,q.childExpirationTime<D&&(q.childExpirationTime=D),T!==null&&T.childExpirationTime<D&&(T.childExpirationTime=D),q.return===null&&q.tag===3){Y=q.stateNode;break}q=q.return}return Y!==null&&(gi===Y&&(Hm(D),Yi===Dl&&KA(Y,ns)),eD(Y,D)),Y}function _m(P){var D=P.lastExpiredTime;return D!==0||(D=P.firstPendingTime,!$v(P,D))?D:(D=P.lastPingedTime,P=P.nextKnownPendingLevel,D>P?D:P)}function fo(P){if(P.lastExpiredTime!==0)P.callbackExpirationTime=1073741823,P.callbackPriority=99,P.callbackNode=hu(Pw.bind(null,P));else{var D=_m(P),T=P.callbackNode;if(D===0)T!==null&&(P.callbackNode=null,P.callbackExpirationTime=0,P.callbackPriority=90);else{var q=ga();if(D===1073741823?q=99:D===1||D===2?q=95:(q=10*(1073741821-D)-10*(1073741821-q),q=0>=q?99:250>=q?98:5250>=q?97:95),T!==null){var Y=P.callbackPriority;if(P.callbackExpirationTime===D&&Y>=q)return;T!==SA&&Ce(T)}P.callbackExpirationTime=D,P.callbackPriority=q,D=D===1073741823?hu(Pw.bind(null,P)):dc(q,Wv.bind(null,P),{timeout:10*(1073741821-D)-Ni()}),P.callbackNode=D}}}function Wv(P,D){if(Um=0,D)return D=ga(),Gm(P,D),fo(P),null;var T=_m(P);if(T!==0){if(D=P.callbackNode,(yr&(rs|qs))!==En)throw Error(n(327));if(vp(),P===gi&&T===ns||Su(P,T),Or!==null){var q=yr;yr|=rs;var Y=jA(P);do try{pF();break}catch(vt){GA(P,vt)}while(1);if(la(),yr=q,wp.current=Y,Yi===Lm)throw D=Nm,Su(P,T),KA(P,T),fo(P),D;if(Or===null)switch(Y=P.finishedWork=P.current.alternate,P.finishedExpirationTime=T,q=Yi,gi=null,q){case vu:case Lm:throw Error(n(345));case Bi:Gm(P,2<T?2:T);break;case ha:if(KA(P,T),q=P.lastSuspendedTime,T===q&&(P.nextKnownPendingLevel=bw(Y)),Wa===1073741823&&(Y=Bw+vw-Ni(),10<Y)){if(UA){var Ae=P.lastPingedTime;if(Ae===0||Ae>=T){P.lastPingedTime=T,Su(P,T);break}}if(Ae=_m(P),Ae!==0&&Ae!==T)break;if(q!==0&&q!==T){P.lastPingedTime=q;break}P.timeoutHandle=Te(bu.bind(null,P),Y);break}bu(P);break;case Dl:if(KA(P,T),q=P.lastSuspendedTime,T===q&&(P.nextKnownPendingLevel=bw(Y)),UA&&(Y=P.lastPingedTime,Y===0||Y>=T)){P.lastPingedTime=T,Su(P,T);break}if(Y=_m(P),Y!==0&&Y!==T)break;if(q!==0&&q!==T){P.lastPingedTime=q;break}if(MA!==1073741823?q=10*(1073741821-MA)-Ni():Wa===1073741823?q=0:(q=10*(1073741821-Wa)-5e3,Y=Ni(),T=10*(1073741821-T)-Y,q=Y-q,0>q&&(q=0),q=(120>q?120:480>q?480:1080>q?1080:1920>q?1920:3e3>q?3e3:4320>q?4320:1960*ww(q/1960))-q,T<q&&(q=T)),10<q){P.timeoutHandle=Te(bu.bind(null,P),q);break}bu(P);break;case Sc:if(Wa!==1073741823&&Om!==null){Ae=Wa;var De=Om;if(q=De.busyMinDurationMs|0,0>=q?q=0:(Y=De.busyDelayMs|0,Ae=Ni()-(10*(1073741821-Ae)-(De.timeoutMs|0||5e3)),q=Ae<=Y?0:Y+q-Ae),10<q){KA(P,T),P.timeoutHandle=Te(bu.bind(null,P),q);break}}bu(P);break;default:throw Error(n(329))}if(fo(P),P.callbackNode===D)return Wv.bind(null,P)}}return null}function Pw(P){var D=P.lastExpiredTime;if(D=D!==0?D:1073741823,P.finishedExpirationTime===D)bu(P);else{if((yr&(rs|qs))!==En)throw Error(n(327));if(vp(),P===gi&&D===ns||Su(P,D),Or!==null){var T=yr;yr|=rs;var q=jA(P);do try{fF();break}catch(Y){GA(P,Y)}while(1);if(la(),yr=T,wp.current=q,Yi===Lm)throw T=Nm,Su(P,D),KA(P,D),fo(P),T;if(Or!==null)throw Error(n(261));P.finishedWork=P.current.alternate,P.finishedExpirationTime=D,gi=null,bu(P),fo(P)}}return null}function Kv(P,D){Gm(P,D),fo(P),(yr&(rs|qs))===En&&qi()}function AF(){if(HA!==null){var P=HA;HA=null,P.forEach(function(D,T){Gm(T,D),fo(T)}),qi()}}function zv(P,D){if((yr&(rs|qs))!==En)throw Error(n(187));var T=yr;yr|=1;try{return lo(99,P.bind(null,D))}finally{yr=T,qi()}}function Su(P,D){P.finishedWork=null,P.finishedExpirationTime=0;var T=P.timeoutHandle;if(T!==qe&&(P.timeoutHandle=qe,Ve(T)),Or!==null)for(T=Or.return;T!==null;){var q=T;switch(q.tag){case 1:var Y=q.type.childContextTypes;Y!=null&&Ua(q);break;case 3:Ec(q),hr(q);break;case 5:lg(q);break;case 4:Ec(q);break;case 13:zn(ei,q);break;case 19:zn(ei,q);break;case 10:wi(q)}T=T.return}gi=P,Or=WA(P.current,null,D),ns=D,Yi=vu,Nm=null,MA=Wa=1073741823,Om=null,Ip=0,UA=!1}function GA(P,D){do{try{if(la(),yw(),Or===null||Or.return===null)return Yi=Lm,Nm=D,null;e:{var T=P,q=Or.return,Y=Or,Ae=D;if(D=ns,Y.effectTag|=2048,Y.firstEffect=Y.lastEffect=null,Ae!==null&&typeof Ae=="object"&&typeof Ae.then=="function"){var De=Ae,vt=(ei.current&1)!==0,wt=q;do{var xt;if(xt=wt.tag===13){var _r=wt.memoizedState;if(_r!==null)xt=_r.dehydrated!==null;else{var is=wt.memoizedProps;xt=is.fallback===void 0?!1:is.unstable_avoidThisFallback!==!0?!0:!vt}}if(xt){var di=wt.updateQueue;if(di===null){var po=new Set;po.add(De),wt.updateQueue=po}else di.add(De);if((wt.mode&2)===0){if(wt.effectTag|=64,Y.effectTag&=-2981,Y.tag===1)if(Y.alternate===null)Y.tag=17;else{var zA=ys(1073741823,null);zA.tag=2,tt(Y,zA)}Y.expirationTime=1073741823;break e}Ae=void 0,Y=D;var Yo=T.pingCache;if(Yo===null?(Yo=T.pingCache=new Bg,Ae=new Set,Yo.set(De,Ae)):(Ae=Yo.get(De),Ae===void 0&&(Ae=new Set,Yo.set(De,Ae))),!Ae.has(Y)){Ae.add(Y);var rt=mF.bind(null,T,De,Y);De.then(rt,rt)}wt.effectTag|=4096,wt.expirationTime=D;break e}wt=wt.return}while(wt!==null);Ae=Error((he(Y.type)||"A React component")+` suspended while rendering, but no fallback UI was specified.
-
-Add a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.`+yl(Y))}Yi!==Sc&&(Yi=Bi),Ae=Cg(Ae,Y),wt=q;do{switch(wt.tag){case 3:De=Ae,wt.effectTag|=4096,wt.expirationTime=D;var ze=jv(wt,De,D);It(wt,ze);break e;case 1:De=Ae;var ft=wt.type,Wt=wt.stateNode;if((wt.effectTag&64)===0&&(typeof ft.getDerivedStateFromError=="function"||Wt!==null&&typeof Wt.componentDidCatch=="function"&&(Pu===null||!Pu.has(Wt)))){wt.effectTag|=4096,wt.expirationTime=D;var vr=Yv(wt,De,D);It(wt,vr);break e}}wt=wt.return}while(wt!==null)}Or=Jv(Or)}catch(Sn){D=Sn;continue}break}while(1)}function jA(){var P=wp.current;return wp.current=Iu,P===null?Iu:P}function Sw(P,D){P<Wa&&2<P&&(Wa=P),D!==null&&P<MA&&2<P&&(MA=P,Om=D)}function Hm(P){P>Ip&&(Ip=P)}function fF(){for(;Or!==null;)Or=Vv(Or)}function pF(){for(;Or!==null&&!Rt();)Or=Vv(Or)}function Vv(P){var D=Zv(P.alternate,P,ns);return P.memoizedProps=P.pendingProps,D===null&&(D=Jv(P)),Iw.current=null,D}function Jv(P){Or=P;do{var D=Or.alternate;if(P=Or.return,(Or.effectTag&2048)===0){e:{var T=D;D=Or;var q=ns,Y=D.pendingProps;switch(D.tag){case 2:break;case 16:break;case 15:case 0:break;case 1:ii(D.type)&&Ua(D);break;case 3:Ec(D),hr(D),Y=D.stateNode,Y.pendingContext&&(Y.context=Y.pendingContext,Y.pendingContext=null),(T===null||T.child===null)&&Ga(D)&&pa(D),vl(D);break;case 5:lg(D);var Ae=ca(yc.current);if(q=D.type,T!==null&&D.stateNode!=null)ts(T,D,q,Y,Ae),T.ref!==D.ref&&(D.effectTag|=128);else if(Y){if(T=ca(uo.current),Ga(D)){if(Y=D,!y)throw Error(n(175));T=cp(Y.stateNode,Y.type,Y.memoizedProps,Ae,T,Y),Y.updateQueue=T,T=T!==null,T&&pa(D)}else{var De=At(q,Y,Ae,T,D);Dc(De,D,!1,!1),D.stateNode=De,at(De,q,Y,Ae,T)&&pa(D)}D.ref!==null&&(D.effectTag|=128)}else if(D.stateNode===null)throw Error(n(166));break;case 6:if(T&&D.stateNode!=null)jr(T,D,T.memoizedProps,Y);else{if(typeof Y!="string"&&D.stateNode===null)throw Error(n(166));if(T=ca(yc.current),Ae=ca(uo.current),Ga(D)){if(T=D,!y)throw Error(n(176));(T=up(T.stateNode,T.memoizedProps,T))&&pa(D)}else D.stateNode=He(Y,T,Ae,D)}break;case 11:break;case 13:if(zn(ei,D),Y=D.memoizedState,(D.effectTag&64)!==0){D.expirationTime=q;break e}Y=Y!==null,Ae=!1,T===null?D.memoizedProps.fallback!==void 0&&Ga(D):(q=T.memoizedState,Ae=q!==null,Y||q===null||(q=T.child.sibling,q!==null&&(De=D.firstEffect,De!==null?(D.firstEffect=q,q.nextEffect=De):(D.firstEffect=D.lastEffect=q,q.nextEffect=null),q.effectTag=8))),Y&&!Ae&&(D.mode&2)!==0&&(T===null&&D.memoizedProps.unstable_avoidThisFallback!==!0||(ei.current&1)!==0?Yi===vu&&(Yi=ha):((Yi===vu||Yi===ha)&&(Yi=Dl),Ip!==0&&gi!==null&&(KA(gi,ns),eD(gi,Ip)))),S&&Y&&(D.effectTag|=4),w&&(Y||Ae)&&(D.effectTag|=4);break;case 7:break;case 8:break;case 12:break;case 4:Ec(D),vl(D);break;case 10:wi(D);break;case 9:break;case 14:break;case 17:ii(D.type)&&Ua(D);break;case 19:if(zn(ei,D),Y=D.memoizedState,Y===null)break;if(Ae=(D.effectTag&64)!==0,De=Y.rendering,De===null){if(Ae)Pc(Y,!1);else if(Yi!==vu||T!==null&&(T.effectTag&64)!==0)for(T=D.child;T!==null;){if(De=pp(T),De!==null){for(D.effectTag|=64,Pc(Y,!1),T=De.updateQueue,T!==null&&(D.updateQueue=T,D.effectTag|=4),Y.lastEffect===null&&(D.firstEffect=null),D.lastEffect=Y.lastEffect,T=q,Y=D.child;Y!==null;)Ae=Y,q=T,Ae.effectTag&=2,Ae.nextEffect=null,Ae.firstEffect=null,Ae.lastEffect=null,De=Ae.alternate,De===null?(Ae.childExpirationTime=0,Ae.expirationTime=q,Ae.child=null,Ae.memoizedProps=null,Ae.memoizedState=null,Ae.updateQueue=null,Ae.dependencies=null):(Ae.childExpirationTime=De.childExpirationTime,Ae.expirationTime=De.expirationTime,Ae.child=De.child,Ae.memoizedProps=De.memoizedProps,Ae.memoizedState=De.memoizedState,Ae.updateQueue=De.updateQueue,q=De.dependencies,Ae.dependencies=q===null?null:{expirationTime:q.expirationTime,firstContext:q.firstContext,responders:q.responders}),Y=Y.sibling;On(ei,ei.current&1|2,D),D=D.child;break e}T=T.sibling}}else{if(!Ae)if(T=pp(De),T!==null){if(D.effectTag|=64,Ae=!0,T=T.updateQueue,T!==null&&(D.updateQueue=T,D.effectTag|=4),Pc(Y,!0),Y.tail===null&&Y.tailMode==="hidden"&&!De.alternate){D=D.lastEffect=Y.lastEffect,D!==null&&(D.nextEffect=null);break}}else Ni()>Y.tailExpiration&&1<q&&(D.effectTag|=64,Ae=!0,Pc(Y,!1),D.expirationTime=D.childExpirationTime=q-1);Y.isBackwards?(De.sibling=D.child,D.child=De):(T=Y.last,T!==null?T.sibling=De:D.child=De,Y.last=De)}if(Y.tail!==null){Y.tailExpiration===0&&(Y.tailExpiration=Ni()+500),T=Y.tail,Y.rendering=T,Y.tail=T.sibling,Y.lastEffect=D.lastEffect,T.sibling=null,Y=ei.current,Y=Ae?Y&1|2:Y&1,On(ei,Y,D),D=T;break e}break;case 20:break;case 21:break;default:throw Error(n(156,D.tag))}D=null}if(T=Or,ns===1||T.childExpirationTime!==1){for(Y=0,Ae=T.child;Ae!==null;)q=Ae.expirationTime,De=Ae.childExpirationTime,q>Y&&(Y=q),De>Y&&(Y=De),Ae=Ae.sibling;T.childExpirationTime=Y}if(D!==null)return D;P!==null&&(P.effectTag&2048)===0&&(P.firstEffect===null&&(P.firstEffect=Or.firstEffect),Or.lastEffect!==null&&(P.lastEffect!==null&&(P.lastEffect.nextEffect=Or.firstEffect),P.lastEffect=Or.lastEffect),1<Or.effectTag&&(P.lastEffect!==null?P.lastEffect.nextEffect=Or:P.firstEffect=Or,P.lastEffect=Or))}else{if(D=Cw(Or,ns),D!==null)return D.effectTag&=2047,D;P!==null&&(P.firstEffect=P.lastEffect=null,P.effectTag|=2048)}if(D=Or.sibling,D!==null)return D;Or=P}while(Or!==null);return Yi===vu&&(Yi=Sc),null}function bw(P){var D=P.expirationTime;return P=P.childExpirationTime,D>P?D:P}function bu(P){var D=_o();return lo(99,hF.bind(null,P,D)),null}function hF(P,D){do vp();while(vg!==null);if((yr&(rs|qs))!==En)throw Error(n(327));var T=P.finishedWork,q=P.finishedExpirationTime;if(T===null)return null;if(P.finishedWork=null,P.finishedExpirationTime=0,T===P.current)throw Error(n(177));P.callbackNode=null,P.callbackExpirationTime=0,P.callbackPriority=90,P.nextKnownPendingLevel=0;var Y=bw(T);if(P.firstPendingTime=Y,q<=P.lastSuspendedTime?P.firstSuspendedTime=P.lastSuspendedTime=P.nextKnownPendingLevel=0:q<=P.firstSuspendedTime&&(P.firstSuspendedTime=q-1),q<=P.lastPingedTime&&(P.lastPingedTime=0),q<=P.lastExpiredTime&&(P.lastExpiredTime=0),P===gi&&(Or=gi=null,ns=0),1<T.effectTag?T.lastEffect!==null?(T.lastEffect.nextEffect=T,Y=T.firstEffect):Y=T:Y=T.firstEffect,Y!==null){var Ae=yr;yr|=qs,Iw.current=null,Ie(P.containerInfo),or=Y;do try{gF()}catch(ho){if(or===null)throw Error(n(330));YA(or,ho),or=or.nextEffect}while(or!==null);or=Y;do try{for(var De=P,vt=D;or!==null;){var wt=or.effectTag;if(wt&16&&w&&Gt(or.stateNode),wt&128){var xt=or.alternate;if(xt!==null){var _r=xt.ref;_r!==null&&(typeof _r=="function"?_r(null):_r.current=null)}}switch(wt&1038){case 2:fr(or),or.effectTag&=-3;break;case 6:fr(or),or.effectTag&=-3,yn(or.alternate,or);break;case 1024:or.effectTag&=-1025;break;case 1028:or.effectTag&=-1025,yn(or.alternate,or);break;case 4:yn(or.alternate,or);break;case 8:var is=De,di=or,po=vt;w?Cr(is,di,po):re(is,di,po),pe(di)}or=or.nextEffect}}catch(ho){if(or===null)throw Error(n(330));YA(or,ho),or=or.nextEffect}while(or!==null);Fe(P.containerInfo),P.current=T,or=Y;do try{for(wt=q;or!==null;){var zA=or.effectTag;if(zA&36){var Yo=or.alternate;switch(xt=or,_r=wt,xt.tag){case 0:case 11:case 15:L(16,32,xt);break;case 1:var rt=xt.stateNode;if(xt.effectTag&4)if(Yo===null)rt.componentDidMount();else{var ze=xt.elementType===xt.type?Yo.memoizedProps:Ci(xt.type,Yo.memoizedProps);rt.componentDidUpdate(ze,Yo.memoizedState,rt.__reactInternalSnapshotBeforeUpdate)}var ft=xt.updateQueue;ft!==null&&Ne(xt,ft,rt,_r);break;case 3:var Wt=xt.updateQueue;if(Wt!==null){if(De=null,xt.child!==null)switch(xt.child.tag){case 5:De=ce(xt.child.stateNode);break;case 1:De=xt.child.stateNode}Ne(xt,Wt,De,_r)}break;case 5:var vr=xt.stateNode;Yo===null&&xt.effectTag&4&&Z(vr,xt.type,xt.memoizedProps,xt);break;case 6:break;case 4:break;case 12:break;case 13:if(y&&xt.memoizedState===null){var Sn=xt.alternate;if(Sn!==null){var Fr=Sn.memoizedState;if(Fr!==null){var bn=Fr.dehydrated;bn!==null&&oo(bn)}}}break;case 19:case 17:case 20:case 21:break;default:throw Error(n(163))}}if(zA&128){xt=void 0;var ai=or.ref;if(ai!==null){var tn=or.stateNode;switch(or.tag){case 5:xt=ce(tn);break;default:xt=tn}typeof ai=="function"?ai(xt):ai.current=xt}}or=or.nextEffect}}catch(ho){if(or===null)throw Error(n(330));YA(or,ho),or=or.nextEffect}while(or!==null);or=null,Qn(),yr=Ae}else P.current=T;if(Bp)Bp=!1,vg=P,_A=D;else for(or=Y;or!==null;)D=or.nextEffect,or.nextEffect=null,or=D;if(D=P.firstPendingTime,D===0&&(Pu=null),D===1073741823?P===Dw?Dg++:(Dg=0,Dw=P):Dg=0,typeof xw=="function"&&xw(T.stateNode,q),fo(P),Du)throw Du=!1,P=Mm,Mm=null,P;return(yr&Tm)!==En||qi(),null}function gF(){for(;or!==null;){var P=or.effectTag;(P&256)!==0&&Qt(or.alternate,or),(P&512)===0||Bp||(Bp=!0,dc(97,function(){return vp(),null})),or=or.nextEffect}}function vp(){if(_A!==90){var P=97<_A?97:_A;return _A=90,lo(P,dF)}}function dF(){if(vg===null)return!1;var P=vg;if(vg=null,(yr&(rs|qs))!==En)throw Error(n(331));var D=yr;for(yr|=qs,P=P.current.firstEffect;P!==null;){try{var T=P;if((T.effectTag&512)!==0)switch(T.tag){case 0:case 11:case 15:L(128,0,T),L(0,64,T)}}catch(q){if(P===null)throw Error(n(330));YA(P,q)}T=P.nextEffect,P.nextEffect=null,P=T}return yr=D,qi(),!0}function Xv(P,D,T){D=Cg(T,D),D=jv(P,D,1073741823),tt(P,D),P=Pg(P,1073741823),P!==null&&fo(P)}function YA(P,D){if(P.tag===3)Xv(P,P,D);else for(var T=P.return;T!==null;){if(T.tag===3){Xv(T,P,D);break}else if(T.tag===1){var q=T.stateNode;if(typeof T.type.getDerivedStateFromError=="function"||typeof q.componentDidCatch=="function"&&(Pu===null||!Pu.has(q))){P=Cg(D,P),P=Yv(T,P,1073741823),tt(T,P),T=Pg(T,1073741823),T!==null&&fo(T);break}}T=T.return}}function mF(P,D,T){var q=P.pingCache;q!==null&&q.delete(D),gi===P&&ns===T?Yi===Dl||Yi===ha&&Wa===1073741823&&Ni()-Bw<vw?Su(P,ns):UA=!0:$v(P,T)&&(D=P.lastPingedTime,D!==0&&D<T||(P.lastPingedTime=T,P.finishedExpirationTime===T&&(P.finishedExpirationTime=0,P.finishedWork=null),fo(P)))}function yF(P,D){var T=P.stateNode;T!==null&&T.delete(D),D=0,D===0&&(D=ga(),D=qA(D,P,null)),P=Pg(P,D),P!==null&&fo(P)}var Zv;Zv=function(P,D,T){var q=D.expirationTime;if(P!==null){var Y=D.pendingProps;if(P.memoizedProps!==Y||_i.current)Go=!0;else{if(q<T){switch(Go=!1,D.tag){case 3:Eg(D),yg();break;case 5:if(Sm(D),D.mode&4&&T!==1&&xe(D.type,Y))return D.expirationTime=D.childExpirationTime=1,null;break;case 1:ii(D.type)&&fc(D);break;case 4:ag(D,D.stateNode.containerInfo);break;case 10:Ho(D,D.memoizedProps.value);break;case 13:if(D.memoizedState!==null)return q=D.child.childExpirationTime,q!==0&&q>=T?ln(P,D,T):(On(ei,ei.current&1,D),D=si(P,D,T),D!==null?D.sibling:null);On(ei,ei.current&1,D);break;case 19:if(q=D.childExpirationTime>=T,(P.effectTag&64)!==0){if(q)return ja(P,D,T);D.effectTag|=64}if(Y=D.memoizedState,Y!==null&&(Y.rendering=null,Y.tail=null),On(ei,ei.current,D),!q)return null}return si(P,D,T)}Go=!1}}else Go=!1;switch(D.expirationTime=0,D.tag){case 2:if(q=D.type,P!==null&&(P.alternate=null,D.alternate=null,D.effectTag|=2),P=D.pendingProps,Y=Oe(D,Mn.current),ds(D,T),Y=ug(null,D,q,P,Y,T),D.effectTag|=1,typeof Y=="object"&&Y!==null&&typeof Y.render=="function"&&Y.$$typeof===void 0){if(D.tag=1,yw(),ii(q)){var Ae=!0;fc(D)}else Ae=!1;D.memoizedState=Y.state!==null&&Y.state!==void 0?Y.state:null;var De=q.getDerivedStateFromProps;typeof De=="function"&&er(D,q,De,P),Y.updater=$r,D.stateNode=Y,Y._reactInternalFiber=D,qo(D,q,P,T),D=Ep(null,D,q,!0,Ae,T)}else D.tag=0,ws(null,D,Y,T),D=D.child;return D;case 16:if(Y=D.elementType,P!==null&&(P.alternate=null,D.alternate=null,D.effectTag|=2),P=D.pendingProps,me(Y),Y._status!==1)throw Y._result;switch(Y=Y._result,D.type=Y,Ae=D.tag=wF(Y),P=Ci(Y,P),Ae){case 0:D=NA(null,D,Y,P,T);break;case 1:D=yp(null,D,Y,P,T);break;case 11:D=Ii(null,D,Y,P,T);break;case 14:D=Qm(null,D,Y,Ci(Y.type,P),q,T);break;default:throw Error(n(306,Y,""))}return D;case 0:return q=D.type,Y=D.pendingProps,Y=D.elementType===q?Y:Ci(q,Y),NA(P,D,q,Y,T);case 1:return q=D.type,Y=D.pendingProps,Y=D.elementType===q?Y:Ci(q,Y),yp(P,D,q,Y,T);case 3:if(Eg(D),q=D.updateQueue,q===null)throw Error(n(282));if(Y=D.memoizedState,Y=Y!==null?Y.element:null,ye(D,q,D.pendingProps,null,T),q=D.memoizedState.element,q===Y)yg(),D=si(P,D,T);else{if((Y=D.stateNode.hydrate)&&(y?(vc=uu(D.stateNode.containerInfo),Aa=D,Y=Bl=!0):Y=!1),Y)for(T=og(D,null,q,T),D.child=T;T;)T.effectTag=T.effectTag&-3|1024,T=T.sibling;else ws(P,D,q,T),yg();D=D.child}return D;case 5:return Sm(D),P===null&&LA(D),q=D.type,Y=D.pendingProps,Ae=P!==null?P.memoizedProps:null,De=Y.children,ke(q,Y)?De=null:Ae!==null&&ke(q,Ae)&&(D.effectTag|=16),jo(P,D),D.mode&4&&T!==1&&xe(q,Y)?(D.expirationTime=D.childExpirationTime=1,D=null):(ws(P,D,De,T),D=D.child),D;case 6:return P===null&&LA(D),null;case 13:return ln(P,D,T);case 4:return ag(D,D.stateNode.containerInfo),q=D.pendingProps,P===null?D.child=du(D,null,q,T):ws(P,D,q,T),D.child;case 11:return q=D.type,Y=D.pendingProps,Y=D.elementType===q?Y:Ci(q,Y),Ii(P,D,q,Y,T);case 7:return ws(P,D,D.pendingProps,T),D.child;case 8:return ws(P,D,D.pendingProps.children,T),D.child;case 12:return ws(P,D,D.pendingProps.children,T),D.child;case 10:e:{if(q=D.type._context,Y=D.pendingProps,De=D.memoizedProps,Ae=Y.value,Ho(D,Ae),De!==null){var vt=De.value;if(Ae=hs(vt,Ae)?0:(typeof q._calculateChangedBits=="function"?q._calculateChangedBits(vt,Ae):1073741823)|0,Ae===0){if(De.children===Y.children&&!_i.current){D=si(P,D,T);break e}}else for(vt=D.child,vt!==null&&(vt.return=D);vt!==null;){var wt=vt.dependencies;if(wt!==null){De=vt.child;for(var xt=wt.firstContext;xt!==null;){if(xt.context===q&&(xt.observedBits&Ae)!==0){vt.tag===1&&(xt=ys(T,null),xt.tag=2,tt(vt,xt)),vt.expirationTime<T&&(vt.expirationTime=T),xt=vt.alternate,xt!==null&&xt.expirationTime<T&&(xt.expirationTime=T),gs(vt.return,T),wt.expirationTime<T&&(wt.expirationTime=T);break}xt=xt.next}}else De=vt.tag===10&&vt.type===D.type?null:vt.child;if(De!==null)De.return=vt;else for(De=vt;De!==null;){if(De===D){De=null;break}if(vt=De.sibling,vt!==null){vt.return=De.return,De=vt;break}De=De.return}vt=De}}ws(P,D,Y.children,T),D=D.child}return D;case 9:return Y=D.type,Ae=D.pendingProps,q=Ae.children,ds(D,T),Y=ms(Y,Ae.unstable_observedBits),q=q(Y),D.effectTag|=1,ws(P,D,q,T),D.child;case 14:return Y=D.type,Ae=Ci(Y,D.pendingProps),Ae=Ci(Y.type,Ae),Qm(P,D,Y,Ae,q,T);case 15:return Fm(P,D,D.type,D.pendingProps,q,T);case 17:return q=D.type,Y=D.pendingProps,Y=D.elementType===q?Y:Ci(q,Y),P!==null&&(P.alternate=null,D.alternate=null,D.effectTag|=2),D.tag=1,ii(q)?(P=!0,fc(D)):P=!1,ds(D,T),es(D,q,Y,T),qo(D,q,Y,T),Ep(null,D,q,!0,P,T);case 19:return ja(P,D,T)}throw Error(n(156,D.tag))};var xw=null,kw=null;function EF(P){if(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u")return!1;var D=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(D.isDisabled||!D.supportsFiber)return!0;try{var T=D.inject(P);xw=function(q){try{D.onCommitFiberRoot(T,q,void 0,(q.current.effectTag&64)===64)}catch{}},kw=function(q){try{D.onCommitFiberUnmount(T,q)}catch{}}}catch{}return!0}function CF(P,D,T,q){this.tag=P,this.key=T,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=D,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=q,this.effectTag=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.childExpirationTime=this.expirationTime=0,this.alternate=null}function Pl(P,D,T,q){return new CF(P,D,T,q)}function Qw(P){return P=P.prototype,!(!P||!P.isReactComponent)}function wF(P){if(typeof P=="function")return Qw(P)?1:0;if(P!=null){if(P=P.$$typeof,P===N)return 11;if(P===te)return 14}return 2}function WA(P,D){var T=P.alternate;return T===null?(T=Pl(P.tag,D,P.key,P.mode),T.elementType=P.elementType,T.type=P.type,T.stateNode=P.stateNode,T.alternate=P,P.alternate=T):(T.pendingProps=D,T.effectTag=0,T.nextEffect=null,T.firstEffect=null,T.lastEffect=null),T.childExpirationTime=P.childExpirationTime,T.expirationTime=P.expirationTime,T.child=P.child,T.memoizedProps=P.memoizedProps,T.memoizedState=P.memoizedState,T.updateQueue=P.updateQueue,D=P.dependencies,T.dependencies=D===null?null:{expirationTime:D.expirationTime,firstContext:D.firstContext,responders:D.responders},T.sibling=P.sibling,T.index=P.index,T.ref=P.ref,T}function qm(P,D,T,q,Y,Ae){var De=2;if(q=P,typeof P=="function")Qw(P)&&(De=1);else if(typeof P=="string")De=5;else e:switch(P){case E:return xu(T.children,Y,Ae,D);case R:De=8,Y|=7;break;case I:De=8,Y|=1;break;case v:return P=Pl(12,T,D,Y|8),P.elementType=v,P.type=v,P.expirationTime=Ae,P;case U:return P=Pl(13,T,D,Y),P.type=U,P.elementType=U,P.expirationTime=Ae,P;case V:return P=Pl(19,T,D,Y),P.elementType=V,P.expirationTime=Ae,P;default:if(typeof P=="object"&&P!==null)switch(P.$$typeof){case x:De=10;break e;case C:De=9;break e;case N:De=11;break e;case te:De=14;break e;case ae:De=16,q=null;break e}throw Error(n(130,P==null?P:typeof P,""))}return D=Pl(De,T,D,Y),D.elementType=P,D.type=q,D.expirationTime=Ae,D}function xu(P,D,T,q){return P=Pl(7,P,q,D),P.expirationTime=T,P}function Fw(P,D,T){return P=Pl(6,P,null,D),P.expirationTime=T,P}function Rw(P,D,T){return D=Pl(4,P.children!==null?P.children:[],P.key,D),D.expirationTime=T,D.stateNode={containerInfo:P.containerInfo,pendingChildren:null,implementation:P.implementation},D}function IF(P,D,T){this.tag=D,this.current=null,this.containerInfo=P,this.pingCache=this.pendingChildren=null,this.finishedExpirationTime=0,this.finishedWork=null,this.timeoutHandle=qe,this.pendingContext=this.context=null,this.hydrate=T,this.callbackNode=null,this.callbackPriority=90,this.lastExpiredTime=this.lastPingedTime=this.nextKnownPendingLevel=this.lastSuspendedTime=this.firstSuspendedTime=this.firstPendingTime=0}function $v(P,D){var T=P.firstSuspendedTime;return P=P.lastSuspendedTime,T!==0&&T>=D&&P<=D}function KA(P,D){var T=P.firstSuspendedTime,q=P.lastSuspendedTime;T<D&&(P.firstSuspendedTime=D),(q>D||T===0)&&(P.lastSuspendedTime=D),D<=P.lastPingedTime&&(P.lastPingedTime=0),D<=P.lastExpiredTime&&(P.lastExpiredTime=0)}function eD(P,D){D>P.firstPendingTime&&(P.firstPendingTime=D);var T=P.firstSuspendedTime;T!==0&&(D>=T?P.firstSuspendedTime=P.lastSuspendedTime=P.nextKnownPendingLevel=0:D>=P.lastSuspendedTime&&(P.lastSuspendedTime=D+1),D>P.nextKnownPendingLevel&&(P.nextKnownPendingLevel=D))}function Gm(P,D){var T=P.lastExpiredTime;(T===0||T>D)&&(P.lastExpiredTime=D)}function tD(P){var D=P._reactInternalFiber;if(D===void 0)throw typeof P.render=="function"?Error(n(188)):Error(n(268,Object.keys(P)));return P=Ee(D),P===null?null:P.stateNode}function rD(P,D){P=P.memoizedState,P!==null&&P.dehydrated!==null&&P.retryTime<D&&(P.retryTime=D)}function jm(P,D){rD(P,D),(P=P.alternate)&&rD(P,D)}var nD={createContainer:function(P,D,T){return P=new IF(P,D,T),D=Pl(3,null,null,D===2?7:D===1?3:0),P.current=D,D.stateNode=P},updateContainer:function(P,D,T,q){var Y=D.current,Ae=ga(),De=ht.suspense;Ae=qA(Ae,Y,De);e:if(T){T=T._reactInternalFiber;t:{if(Be(T)!==T||T.tag!==1)throw Error(n(170));var vt=T;do{switch(vt.tag){case 3:vt=vt.stateNode.context;break t;case 1:if(ii(vt.type)){vt=vt.stateNode.__reactInternalMemoizedMergedChildContext;break t}}vt=vt.return}while(vt!==null);throw Error(n(171))}if(T.tag===1){var wt=T.type;if(ii(wt)){T=Au(T,wt,vt);break e}}T=vt}else T=Li;return D.context===null?D.context=T:D.pendingContext=T,D=ys(Ae,De),D.payload={element:P},q=q===void 0?null:q,q!==null&&(D.callback=q),tt(Y,D),bc(Y,Ae),Ae},batchedEventUpdates:function(P,D){var T=yr;yr|=2;try{return P(D)}finally{yr=T,yr===En&&qi()}},batchedUpdates:function(P,D){var T=yr;yr|=1;try{return P(D)}finally{yr=T,yr===En&&qi()}},unbatchedUpdates:function(P,D){var T=yr;yr&=-2,yr|=Tm;try{return P(D)}finally{yr=T,yr===En&&qi()}},deferredUpdates:function(P){return lo(97,P)},syncUpdates:function(P,D,T,q){return lo(99,P.bind(null,D,T,q))},discreteUpdates:function(P,D,T,q){var Y=yr;yr|=4;try{return lo(98,P.bind(null,D,T,q))}finally{yr=Y,yr===En&&qi()}},flushDiscreteUpdates:function(){(yr&(1|rs|qs))===En&&(AF(),vp())},flushControlled:function(P){var D=yr;yr|=1;try{lo(99,P)}finally{yr=D,yr===En&&qi()}},flushSync:zv,flushPassiveEffects:vp,IsThisRendererActing:{current:!1},getPublicRootInstance:function(P){if(P=P.current,!P.child)return null;switch(P.child.tag){case 5:return ce(P.child.stateNode);default:return P.child.stateNode}},attemptSynchronousHydration:function(P){switch(P.tag){case 3:var D=P.stateNode;D.hydrate&&Kv(D,D.firstPendingTime);break;case 13:zv(function(){return bc(P,1073741823)}),D=Ha(ga(),150,100),jm(P,D)}},attemptUserBlockingHydration:function(P){if(P.tag===13){var D=Ha(ga(),150,100);bc(P,D),jm(P,D)}},attemptContinuousHydration:function(P){if(P.tag===13){ga();var D=xA++;bc(P,D),jm(P,D)}},attemptHydrationAtCurrentPriority:function(P){if(P.tag===13){var D=ga();D=qA(D,P,null),bc(P,D),jm(P,D)}},findHostInstance:tD,findHostInstanceWithWarning:function(P){return tD(P)},findHostInstanceWithNoPortals:function(P){return P=Pe(P),P===null?null:P.tag===20?P.stateNode.instance:P.stateNode},shouldSuspend:function(){return!1},injectIntoDevTools:function(P){var D=P.findFiberByHostInstance;return EF(r({},P,{overrideHookState:null,overrideProps:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:u.ReactCurrentDispatcher,findHostInstanceByFiber:function(T){return T=Ee(T),T===null?null:T.stateNode},findFiberByHostInstance:function(T){return D?D(T):null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null}))}};lB.exports=nD.default||nD;var BF=lB.exports;return lB.exports=t,BF}});var bEe=_((yKt,SEe)=>{"use strict";SEe.exports=PEe()});var kEe=_((EKt,xEe)=>{"use strict";var qyt={ALIGN_COUNT:8,ALIGN_AUTO:0,ALIGN_FLEX_START:1,ALIGN_CENTER:2,ALIGN_FLEX_END:3,ALIGN_STRETCH:4,ALIGN_BASELINE:5,ALIGN_SPACE_BETWEEN:6,ALIGN_SPACE_AROUND:7,DIMENSION_COUNT:2,DIMENSION_WIDTH:0,DIMENSION_HEIGHT:1,DIRECTION_COUNT:3,DIRECTION_INHERIT:0,DIRECTION_LTR:1,DIRECTION_RTL:2,DISPLAY_COUNT:2,DISPLAY_FLEX:0,DISPLAY_NONE:1,EDGE_COUNT:9,EDGE_LEFT:0,EDGE_TOP:1,EDGE_RIGHT:2,EDGE_BOTTOM:3,EDGE_START:4,EDGE_END:5,EDGE_HORIZONTAL:6,EDGE_VERTICAL:7,EDGE_ALL:8,EXPERIMENTAL_FEATURE_COUNT:1,EXPERIMENTAL_FEATURE_WEB_FLEX_BASIS:0,FLEX_DIRECTION_COUNT:4,FLEX_DIRECTION_COLUMN:0,FLEX_DIRECTION_COLUMN_REVERSE:1,FLEX_DIRECTION_ROW:2,FLEX_DIRECTION_ROW_REVERSE:3,JUSTIFY_COUNT:6,JUSTIFY_FLEX_START:0,JUSTIFY_CENTER:1,JUSTIFY_FLEX_END:2,JUSTIFY_SPACE_BETWEEN:3,JUSTIFY_SPACE_AROUND:4,JUSTIFY_SPACE_EVENLY:5,LOG_LEVEL_COUNT:6,LOG_LEVEL_ERROR:0,LOG_LEVEL_WARN:1,LOG_LEVEL_INFO:2,LOG_LEVEL_DEBUG:3,LOG_LEVEL_VERBOSE:4,LOG_LEVEL_FATAL:5,MEASURE_MODE_COUNT:3,MEASURE_MODE_UNDEFINED:0,MEASURE_MODE_EXACTLY:1,MEASURE_MODE_AT_MOST:2,NODE_TYPE_COUNT:2,NODE_TYPE_DEFAULT:0,NODE_TYPE_TEXT:1,OVERFLOW_COUNT:3,OVERFLOW_VISIBLE:0,OVERFLOW_HIDDEN:1,OVERFLOW_SCROLL:2,POSITION_TYPE_COUNT:2,POSITION_TYPE_RELATIVE:0,POSITION_TYPE_ABSOLUTE:1,PRINT_OPTIONS_COUNT:3,PRINT_OPTIONS_LAYOUT:1,PRINT_OPTIONS_STYLE:2,PRINT_OPTIONS_CHILDREN:4,UNIT_COUNT:4,UNIT_UNDEFINED:0,UNIT_POINT:1,UNIT_PERCENT:2,UNIT_AUTO:3,WRAP_COUNT:3,WRAP_NO_WRAP:0,WRAP_WRAP:1,WRAP_WRAP_REVERSE:2};xEe.exports=qyt});var TEe=_((CKt,REe)=>{"use strict";var Gyt=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var o in r)Object.prototype.hasOwnProperty.call(r,o)&&(t[o]=r[o])}return t},Wk=function(){function t(e,r){for(var o=0;o<r.length;o++){var a=r[o];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}return function(e,r,o){return r&&t(e.prototype,r),o&&t(e,o),e}}();function S6(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function b6(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var ru=kEe(),jyt=function(){function t(e,r,o,a,n,u){b6(this,t),this.left=e,this.right=r,this.top=o,this.bottom=a,this.width=n,this.height=u}return Wk(t,[{key:"fromJS",value:function(r){r(this.left,this.right,this.top,this.bottom,this.width,this.height)}},{key:"toString",value:function(){return"<Layout#"+this.left+":"+this.right+";"+this.top+":"+this.bottom+";"+this.width+":"+this.height+">"}}]),t}(),QEe=function(){Wk(t,null,[{key:"fromJS",value:function(r){var o=r.width,a=r.height;return new t(o,a)}}]);function t(e,r){b6(this,t),this.width=e,this.height=r}return Wk(t,[{key:"fromJS",value:function(r){r(this.width,this.height)}},{key:"toString",value:function(){return"<Size#"+this.width+"x"+this.height+">"}}]),t}(),FEe=function(){function t(e,r){b6(this,t),this.unit=e,this.value=r}return Wk(t,[{key:"fromJS",value:function(r){r(this.unit,this.value)}},{key:"toString",value:function(){switch(this.unit){case ru.UNIT_POINT:return String(this.value);case ru.UNIT_PERCENT:return this.value+"%";case ru.UNIT_AUTO:return"auto";default:return this.value+"?"}}},{key:"valueOf",value:function(){return this.value}}]),t}();REe.exports=function(t,e){function r(u,A,p){var h=u[A];u[A]=function(){for(var E=arguments.length,I=Array(E),v=0;v<E;v++)I[v]=arguments[v];return p.call.apply(p,[this,h].concat(I))}}for(var o=["setPosition","setMargin","setFlexBasis","setWidth","setHeight","setMinWidth","setMinHeight","setMaxWidth","setMaxHeight","setPadding"],a=function(){var A,p=o[n],h=(A={},S6(A,ru.UNIT_POINT,e.Node.prototype[p]),S6(A,ru.UNIT_PERCENT,e.Node.prototype[p+"Percent"]),S6(A,ru.UNIT_AUTO,e.Node.prototype[p+"Auto"]),A);r(e.Node.prototype,p,function(E){for(var I=arguments.length,v=Array(I>1?I-1:0),x=1;x<I;x++)v[x-1]=arguments[x];var C=v.pop(),R=void 0,N=void 0;if(C==="auto")R=ru.UNIT_AUTO,N=void 0;else if(C instanceof FEe)R=C.unit,N=C.valueOf();else if(R=typeof C=="string"&&C.endsWith("%")?ru.UNIT_PERCENT:ru.UNIT_POINT,N=parseFloat(C),!Number.isNaN(C)&&Number.isNaN(N))throw new Error("Invalid value "+C+" for "+p);if(!h[R])throw new Error('Failed to execute "'+p+`": Unsupported unit '`+C+"'");if(N!==void 0){var U;return(U=h[R]).call.apply(U,[this].concat(v,[N]))}else{var V;return(V=h[R]).call.apply(V,[this].concat(v))}})},n=0;n<o.length;n++)a();return r(e.Config.prototype,"free",function(){e.Config.destroy(this)}),r(e.Node,"create",function(u,A){return A?e.Node.createWithConfig(A):e.Node.createDefault()}),r(e.Node.prototype,"free",function(){e.Node.destroy(this)}),r(e.Node.prototype,"freeRecursive",function(){for(var u=0,A=this.getChildCount();u<A;++u)this.getChild(0).freeRecursive();this.free()}),r(e.Node.prototype,"setMeasureFunc",function(u,A){return A?u.call(this,function(){return QEe.fromJS(A.apply(void 0,arguments))}):this.unsetMeasureFunc()}),r(e.Node.prototype,"calculateLayout",function(u){var A=arguments.length>1&&arguments[1]!==void 0?arguments[1]:NaN,p=arguments.length>2&&arguments[2]!==void 0?arguments[2]:NaN,h=arguments.length>3&&arguments[3]!==void 0?arguments[3]:ru.DIRECTION_LTR;return u.call(this,A,p,h)}),Gyt({Config:e.Config,Node:e.Node,Layout:t("Layout",jyt),Size:t("Size",QEe),Value:t("Value",FEe),getInstanceCount:function(){return e.getInstanceCount.apply(e,arguments)}},ru)}});var LEe=_((exports,module)=>{(function(t,e){typeof define=="function"&&define.amd?define([],function(){return e}):typeof module=="object"&&module.exports?module.exports=e:(t.nbind=t.nbind||{}).init=e})(exports,function(Module,cb){typeof Module=="function"&&(cb=Module,Module={}),Module.onRuntimeInitialized=function(t,e){return function(){t&&t.apply(this,arguments);try{Module.ccall("nbind_init")}catch(r){e(r);return}e(null,{bind:Module._nbind_value,reflect:Module.NBind.reflect,queryType:Module.NBind.queryType,toggleLightGC:Module.toggleLightGC,lib:Module})}}(Module.onRuntimeInitialized,cb);var Module;Module||(Module=(typeof Module<"u"?Module:null)||{});var moduleOverrides={};for(var key in Module)Module.hasOwnProperty(key)&&(moduleOverrides[key]=Module[key]);var ENVIRONMENT_IS_WEB=!1,ENVIRONMENT_IS_WORKER=!1,ENVIRONMENT_IS_NODE=!1,ENVIRONMENT_IS_SHELL=!1;if(Module.ENVIRONMENT)if(Module.ENVIRONMENT==="WEB")ENVIRONMENT_IS_WEB=!0;else if(Module.ENVIRONMENT==="WORKER")ENVIRONMENT_IS_WORKER=!0;else if(Module.ENVIRONMENT==="NODE")ENVIRONMENT_IS_NODE=!0;else if(Module.ENVIRONMENT==="SHELL")ENVIRONMENT_IS_SHELL=!0;else throw new Error("The provided Module['ENVIRONMENT'] value is not valid. It must be one of: WEB|WORKER|NODE|SHELL.");else ENVIRONMENT_IS_WEB=typeof window=="object",ENVIRONMENT_IS_WORKER=typeof importScripts=="function",ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof ve=="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER,ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){Module.print||(Module.print=console.log),Module.printErr||(Module.printErr=console.warn);var nodeFS,nodePath;Module.read=function(e,r){nodeFS||(nodeFS={}("")),nodePath||(nodePath={}("")),e=nodePath.normalize(e);var o=nodeFS.readFileSync(e);return r?o:o.toString()},Module.readBinary=function(e){var r=Module.read(e,!0);return r.buffer||(r=new Uint8Array(r)),assert(r.buffer),r},Module.load=function(e){globalEval(read(e))},Module.thisProgram||(process.argv.length>1?Module.thisProgram=process.argv[1].replace(/\\/g,"/"):Module.thisProgram="unknown-program"),Module.arguments=process.argv.slice(2),typeof module<"u"&&(module.exports=Module),Module.inspect=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL)Module.print||(Module.print=print),typeof printErr<"u"&&(Module.printErr=printErr),typeof read<"u"?Module.read=read:Module.read=function(){throw"no read() available"},Module.readBinary=function(e){if(typeof readbuffer=="function")return new Uint8Array(readbuffer(e));var r=read(e,"binary");return assert(typeof r=="object"),r},typeof scriptArgs<"u"?Module.arguments=scriptArgs:typeof arguments<"u"&&(Module.arguments=arguments),typeof quit=="function"&&(Module.quit=function(t,e){quit(t)});else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(Module.read=function(e){var r=new XMLHttpRequest;return r.open("GET",e,!1),r.send(null),r.responseText},ENVIRONMENT_IS_WORKER&&(Module.readBinary=function(e){var r=new XMLHttpRequest;return r.open("GET",e,!1),r.responseType="arraybuffer",r.send(null),new Uint8Array(r.response)}),Module.readAsync=function(e,r,o){var a=new XMLHttpRequest;a.open("GET",e,!0),a.responseType="arraybuffer",a.onload=function(){a.status==200||a.status==0&&a.response?r(a.response):o()},a.onerror=o,a.send(null)},typeof arguments<"u"&&(Module.arguments=arguments),typeof console<"u")Module.print||(Module.print=function(e){console.log(e)}),Module.printErr||(Module.printErr=function(e){console.warn(e)});else{var TRY_USE_DUMP=!1;Module.print||(Module.print=TRY_USE_DUMP&&typeof dump<"u"?function(t){dump(t)}:function(t){})}ENVIRONMENT_IS_WORKER&&(Module.load=importScripts),typeof Module.setWindowTitle>"u"&&(Module.setWindowTitle=function(t){document.title=t})}else throw"Unknown runtime environment. Where are we?";function globalEval(t){eval.call(null,t)}!Module.load&&Module.read&&(Module.load=function(e){globalEval(Module.read(e))}),Module.print||(Module.print=function(){}),Module.printErr||(Module.printErr=Module.print),Module.arguments||(Module.arguments=[]),Module.thisProgram||(Module.thisProgram="./this.program"),Module.quit||(Module.quit=function(t,e){throw e}),Module.print=Module.print,Module.printErr=Module.printErr,Module.preRun=[],Module.postRun=[];for(var key in moduleOverrides)moduleOverrides.hasOwnProperty(key)&&(Module[key]=moduleOverrides[key]);moduleOverrides=void 0;var Runtime={setTempRet0:function(t){return tempRet0=t,t},getTempRet0:function(){return tempRet0},stackSave:function(){return STACKTOP},stackRestore:function(t){STACKTOP=t},getNativeTypeSize:function(t){switch(t){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(t[t.length-1]==="*")return Runtime.QUANTUM_SIZE;if(t[0]==="i"){var e=parseInt(t.substr(1));return assert(e%8===0),e/8}else return 0}}},getNativeFieldSize:function(t){return Math.max(Runtime.getNativeTypeSize(t),Runtime.QUANTUM_SIZE)},STACK_ALIGN:16,prepVararg:function(t,e){return e==="double"||e==="i64"?t&7&&(assert((t&7)===4),t+=4):assert((t&3)===0),t},getAlignSize:function(t,e,r){return!r&&(t=="i64"||t=="double")?8:t?Math.min(e||(t?Runtime.getNativeFieldSize(t):0),Runtime.QUANTUM_SIZE):Math.min(e,8)},dynCall:function(t,e,r){return r&&r.length?Module["dynCall_"+t].apply(null,[e].concat(r)):Module["dynCall_"+t].call(null,e)},functionPointers:[],addFunction:function(t){for(var e=0;e<Runtime.functionPointers.length;e++)if(!Runtime.functionPointers[e])return Runtime.functionPointers[e]=t,2*(1+e);throw"Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS."},removeFunction:function(t){Runtime.functionPointers[(t-2)/2]=null},warnOnce:function(t){Runtime.warnOnce.shown||(Runtime.warnOnce.shown={}),Runtime.warnOnce.shown[t]||(Runtime.warnOnce.shown[t]=1,Module.printErr(t))},funcWrappers:{},getFuncWrapper:function(t,e){if(!!t){assert(e),Runtime.funcWrappers[e]||(Runtime.funcWrappers[e]={});var r=Runtime.funcWrappers[e];return r[t]||(e.length===1?r[t]=function(){return Runtime.dynCall(e,t)}:e.length===2?r[t]=function(a){return Runtime.dynCall(e,t,[a])}:r[t]=function(){return Runtime.dynCall(e,t,Array.prototype.slice.call(arguments))}),r[t]}},getCompilerSetting:function(t){throw"You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work"},stackAlloc:function(t){var e=STACKTOP;return STACKTOP=STACKTOP+t|0,STACKTOP=STACKTOP+15&-16,e},staticAlloc:function(t){var e=STATICTOP;return STATICTOP=STATICTOP+t|0,STATICTOP=STATICTOP+15&-16,e},dynamicAlloc:function(t){var e=HEAP32[DYNAMICTOP_PTR>>2],r=(e+t+15|0)&-16;if(HEAP32[DYNAMICTOP_PTR>>2]=r,r>=TOTAL_MEMORY){var o=enlargeMemory();if(!o)return HEAP32[DYNAMICTOP_PTR>>2]=e,0}return e},alignMemory:function(t,e){var r=t=Math.ceil(t/(e||16))*(e||16);return r},makeBigInt:function(t,e,r){var o=r?+(t>>>0)+ +(e>>>0)*4294967296:+(t>>>0)+ +(e|0)*4294967296;return o},GLOBAL_BASE:8,QUANTUM_SIZE:4,__dummy__:0};Module.Runtime=Runtime;var ABORT=0,EXITSTATUS=0;function assert(t,e){t||abort("Assertion failed: "+e)}function getCFunc(ident){var func=Module["_"+ident];if(!func)try{func=eval("_"+ident)}catch(t){}return assert(func,"Cannot call unknown function "+ident+" (perhaps LLVM optimizations or closure removed it?)"),func}var cwrap,ccall;(function(){var JSfuncs={stackSave:function(){Runtime.stackSave()},stackRestore:function(){Runtime.stackRestore()},arrayToC:function(t){var e=Runtime.stackAlloc(t.length);return writeArrayToMemory(t,e),e},stringToC:function(t){var e=0;if(t!=null&&t!==0){var r=(t.length<<2)+1;e=Runtime.stackAlloc(r),stringToUTF8(t,e,r)}return e}},toC={string:JSfuncs.stringToC,array:JSfuncs.arrayToC};ccall=function(e,r,o,a,n){var u=getCFunc(e),A=[],p=0;if(a)for(var h=0;h<a.length;h++){var E=toC[o[h]];E?(p===0&&(p=Runtime.stackSave()),A[h]=E(a[h])):A[h]=a[h]}var I=u.apply(null,A);if(r==="string"&&(I=Pointer_stringify(I)),p!==0){if(n&&n.async){EmterpreterAsync.asyncFinalizers.push(function(){Runtime.stackRestore(p)});return}Runtime.stackRestore(p)}return I};var sourceRegex=/^function\s*[a-zA-Z$_0-9]*\s*\(([^)]*)\)\s*{\s*([^*]*?)[\s;]*(?:return\s*(.*?)[;\s]*)?}$/;function parseJSFunc(t){var e=t.toString().match(sourceRegex).slice(1);return{arguments:e[0],body:e[1],returnValue:e[2]}}var JSsource=null;function ensureJSsource(){if(!JSsource){JSsource={};for(var t in JSfuncs)JSfuncs.hasOwnProperty(t)&&(JSsource[t]=parseJSFunc(JSfuncs[t]))}}cwrap=function cwrap(ident,returnType,argTypes){argTypes=argTypes||[];var cfunc=getCFunc(ident),numericArgs=argTypes.every(function(t){return t==="number"}),numericRet=returnType!=="string";if(numericRet&&numericArgs)return cfunc;var argNames=argTypes.map(function(t,e){return"$"+e}),funcstr="(function("+argNames.join(",")+") {",nargs=argTypes.length;if(!numericArgs){ensureJSsource(),funcstr+="var stack = "+JSsource.stackSave.body+";";for(var i=0;i<nargs;i++){var arg=argNames[i],type=argTypes[i];if(type!=="number"){var convertCode=JSsource[type+"ToC"];funcstr+="var "+convertCode.arguments+" = "+arg+";",funcstr+=convertCode.body+";",funcstr+=arg+"=("+convertCode.returnValue+");"}}}var cfuncname=parseJSFunc(function(){return cfunc}).returnValue;if(funcstr+="var ret = "+cfuncname+"("+argNames.join(",")+");",!numericRet){var strgfy=parseJSFunc(function(){return Pointer_stringify}).returnValue;funcstr+="ret = "+strgfy+"(ret);"}return numericArgs||(ensureJSsource(),funcstr+=JSsource.stackRestore.body.replace("()","(stack)")+";"),funcstr+="return ret})",eval(funcstr)}})(),Module.ccall=ccall,Module.cwrap=cwrap;function setValue(t,e,r,o){switch(r=r||"i8",r.charAt(r.length-1)==="*"&&(r="i32"),r){case"i1":HEAP8[t>>0]=e;break;case"i8":HEAP8[t>>0]=e;break;case"i16":HEAP16[t>>1]=e;break;case"i32":HEAP32[t>>2]=e;break;case"i64":tempI64=[e>>>0,(tempDouble=e,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[t>>2]=tempI64[0],HEAP32[t+4>>2]=tempI64[1];break;case"float":HEAPF32[t>>2]=e;break;case"double":HEAPF64[t>>3]=e;break;default:abort("invalid type for setValue: "+r)}}Module.setValue=setValue;function getValue(t,e,r){switch(e=e||"i8",e.charAt(e.length-1)==="*"&&(e="i32"),e){case"i1":return HEAP8[t>>0];case"i8":return HEAP8[t>>0];case"i16":return HEAP16[t>>1];case"i32":return HEAP32[t>>2];case"i64":return HEAP32[t>>2];case"float":return HEAPF32[t>>2];case"double":return HEAPF64[t>>3];default:abort("invalid type for setValue: "+e)}return null}Module.getValue=getValue;var ALLOC_NORMAL=0,ALLOC_STACK=1,ALLOC_STATIC=2,ALLOC_DYNAMIC=3,ALLOC_NONE=4;Module.ALLOC_NORMAL=ALLOC_NORMAL,Module.ALLOC_STACK=ALLOC_STACK,Module.ALLOC_STATIC=ALLOC_STATIC,Module.ALLOC_DYNAMIC=ALLOC_DYNAMIC,Module.ALLOC_NONE=ALLOC_NONE;function allocate(t,e,r,o){var a,n;typeof t=="number"?(a=!0,n=t):(a=!1,n=t.length);var u=typeof e=="string"?e:null,A;if(r==ALLOC_NONE?A=o:A=[typeof _malloc=="function"?_malloc:Runtime.staticAlloc,Runtime.stackAlloc,Runtime.staticAlloc,Runtime.dynamicAlloc][r===void 0?ALLOC_STATIC:r](Math.max(n,u?1:e.length)),a){var o=A,p;for(assert((A&3)==0),p=A+(n&-4);o<p;o+=4)HEAP32[o>>2]=0;for(p=A+n;o<p;)HEAP8[o++>>0]=0;return A}if(u==="i8")return t.subarray||t.slice?HEAPU8.set(t,A):HEAPU8.set(new Uint8Array(t),A),A;for(var h=0,E,I,v;h<n;){var x=t[h];if(typeof x=="function"&&(x=Runtime.getFunctionIndex(x)),E=u||e[h],E===0){h++;continue}E=="i64"&&(E="i32"),setValue(A+h,x,E),v!==E&&(I=Runtime.getNativeTypeSize(E),v=E),h+=I}return A}Module.allocate=allocate;function getMemory(t){return staticSealed?runtimeInitialized?_malloc(t):Runtime.dynamicAlloc(t):Runtime.staticAlloc(t)}Module.getMemory=getMemory;function Pointer_stringify(t,e){if(e===0||!t)return"";for(var r=0,o,a=0;o=HEAPU8[t+a>>0],r|=o,!(o==0&&!e||(a++,e&&a==e)););e||(e=a);var n="";if(r<128){for(var u=1024,A;e>0;)A=String.fromCharCode.apply(String,HEAPU8.subarray(t,t+Math.min(e,u))),n=n?n+A:A,t+=u,e-=u;return n}return Module.UTF8ToString(t)}Module.Pointer_stringify=Pointer_stringify;function AsciiToString(t){for(var e="";;){var r=HEAP8[t++>>0];if(!r)return e;e+=String.fromCharCode(r)}}Module.AsciiToString=AsciiToString;function stringToAscii(t,e){return writeAsciiToMemory(t,e,!1)}Module.stringToAscii=stringToAscii;var UTF8Decoder=typeof TextDecoder<"u"?new TextDecoder("utf8"):void 0;function UTF8ArrayToString(t,e){for(var r=e;t[r];)++r;if(r-e>16&&t.subarray&&UTF8Decoder)return UTF8Decoder.decode(t.subarray(e,r));for(var o,a,n,u,A,p,h="";;){if(o=t[e++],!o)return h;if(!(o&128)){h+=String.fromCharCode(o);continue}if(a=t[e++]&63,(o&224)==192){h+=String.fromCharCode((o&31)<<6|a);continue}if(n=t[e++]&63,(o&240)==224?o=(o&15)<<12|a<<6|n:(u=t[e++]&63,(o&248)==240?o=(o&7)<<18|a<<12|n<<6|u:(A=t[e++]&63,(o&252)==248?o=(o&3)<<24|a<<18|n<<12|u<<6|A:(p=t[e++]&63,o=(o&1)<<30|a<<24|n<<18|u<<12|A<<6|p))),o<65536)h+=String.fromCharCode(o);else{var E=o-65536;h+=String.fromCharCode(55296|E>>10,56320|E&1023)}}}Module.UTF8ArrayToString=UTF8ArrayToString;function UTF8ToString(t){return UTF8ArrayToString(HEAPU8,t)}Module.UTF8ToString=UTF8ToString;function stringToUTF8Array(t,e,r,o){if(!(o>0))return 0;for(var a=r,n=r+o-1,u=0;u<t.length;++u){var A=t.charCodeAt(u);if(A>=55296&&A<=57343&&(A=65536+((A&1023)<<10)|t.charCodeAt(++u)&1023),A<=127){if(r>=n)break;e[r++]=A}else if(A<=2047){if(r+1>=n)break;e[r++]=192|A>>6,e[r++]=128|A&63}else if(A<=65535){if(r+2>=n)break;e[r++]=224|A>>12,e[r++]=128|A>>6&63,e[r++]=128|A&63}else if(A<=2097151){if(r+3>=n)break;e[r++]=240|A>>18,e[r++]=128|A>>12&63,e[r++]=128|A>>6&63,e[r++]=128|A&63}else if(A<=67108863){if(r+4>=n)break;e[r++]=248|A>>24,e[r++]=128|A>>18&63,e[r++]=128|A>>12&63,e[r++]=128|A>>6&63,e[r++]=128|A&63}else{if(r+5>=n)break;e[r++]=252|A>>30,e[r++]=128|A>>24&63,e[r++]=128|A>>18&63,e[r++]=128|A>>12&63,e[r++]=128|A>>6&63,e[r++]=128|A&63}}return e[r]=0,r-a}Module.stringToUTF8Array=stringToUTF8Array;function stringToUTF8(t,e,r){return stringToUTF8Array(t,HEAPU8,e,r)}Module.stringToUTF8=stringToUTF8;function lengthBytesUTF8(t){for(var e=0,r=0;r<t.length;++r){var o=t.charCodeAt(r);o>=55296&&o<=57343&&(o=65536+((o&1023)<<10)|t.charCodeAt(++r)&1023),o<=127?++e:o<=2047?e+=2:o<=65535?e+=3:o<=2097151?e+=4:o<=67108863?e+=5:e+=6}return e}Module.lengthBytesUTF8=lengthBytesUTF8;var UTF16Decoder=typeof TextDecoder<"u"?new TextDecoder("utf-16le"):void 0;function demangle(t){var e=Module.___cxa_demangle||Module.__cxa_demangle;if(e){try{var r=t.substr(1),o=lengthBytesUTF8(r)+1,a=_malloc(o);stringToUTF8(r,a,o);var n=_malloc(4),u=e(a,0,0,n);if(getValue(n,"i32")===0&&u)return Pointer_stringify(u)}catch{}finally{a&&_free(a),n&&_free(n),u&&_free(u)}return t}return Runtime.warnOnce("warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling"),t}function demangleAll(t){var e=/__Z[\w\d_]+/g;return t.replace(e,function(r){var o=demangle(r);return r===o?r:r+" ["+o+"]"})}function jsStackTrace(){var t=new Error;if(!t.stack){try{throw new Error(0)}catch(e){t=e}if(!t.stack)return"(no stack trace available)"}return t.stack.toString()}function stackTrace(){var t=jsStackTrace();return Module.extraStackTrace&&(t+=`
-`+Module.extraStackTrace()),demangleAll(t)}Module.stackTrace=stackTrace;var HEAP,buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferViews(){Module.HEAP8=HEAP8=new Int8Array(buffer),Module.HEAP16=HEAP16=new Int16Array(buffer),Module.HEAP32=HEAP32=new Int32Array(buffer),Module.HEAPU8=HEAPU8=new Uint8Array(buffer),Module.HEAPU16=HEAPU16=new Uint16Array(buffer),Module.HEAPU32=HEAPU32=new Uint32Array(buffer),Module.HEAPF32=HEAPF32=new Float32Array(buffer),Module.HEAPF64=HEAPF64=new Float64Array(buffer)}var STATIC_BASE,STATICTOP,staticSealed,STACK_BASE,STACKTOP,STACK_MAX,DYNAMIC_BASE,DYNAMICTOP_PTR;STATIC_BASE=STATICTOP=STACK_BASE=STACKTOP=STACK_MAX=DYNAMIC_BASE=DYNAMICTOP_PTR=0,staticSealed=!1;function abortOnCannotGrowMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or (4) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}function enlargeMemory(){abortOnCannotGrowMemory()}var TOTAL_STACK=Module.TOTAL_STACK||5242880,TOTAL_MEMORY=Module.TOTAL_MEMORY||134217728;TOTAL_MEMORY<TOTAL_STACK&&Module.printErr("TOTAL_MEMORY should be larger than TOTAL_STACK, was "+TOTAL_MEMORY+"! (TOTAL_STACK="+TOTAL_STACK+")"),Module.buffer?buffer=Module.buffer:buffer=new ArrayBuffer(TOTAL_MEMORY),updateGlobalBufferViews();function getTotalMemory(){return TOTAL_MEMORY}if(HEAP32[0]=1668509029,HEAP16[1]=25459,HEAPU8[2]!==115||HEAPU8[3]!==99)throw"Runtime error: expected the system to be little-endian!";Module.HEAP=HEAP,Module.buffer=buffer,Module.HEAP8=HEAP8,Module.HEAP16=HEAP16,Module.HEAP32=HEAP32,Module.HEAPU8=HEAPU8,Module.HEAPU16=HEAPU16,Module.HEAPU32=HEAPU32,Module.HEAPF32=HEAPF32,Module.HEAPF64=HEAPF64;function callRuntimeCallbacks(t){for(;t.length>0;){var e=t.shift();if(typeof e=="function"){e();continue}var r=e.func;typeof r=="number"?e.arg===void 0?Module.dynCall_v(r):Module.dynCall_vi(r,e.arg):r(e.arg===void 0?null:e.arg)}}var __ATPRERUN__=[],__ATINIT__=[],__ATMAIN__=[],__ATEXIT__=[],__ATPOSTRUN__=[],runtimeInitialized=!1,runtimeExited=!1;function preRun(){if(Module.preRun)for(typeof Module.preRun=="function"&&(Module.preRun=[Module.preRun]);Module.preRun.length;)addOnPreRun(Module.preRun.shift());callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){runtimeInitialized||(runtimeInitialized=!0,callRuntimeCallbacks(__ATINIT__))}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__),runtimeExited=!0}function postRun(){if(Module.postRun)for(typeof Module.postRun=="function"&&(Module.postRun=[Module.postRun]);Module.postRun.length;)addOnPostRun(Module.postRun.shift());callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(t){__ATPRERUN__.unshift(t)}Module.addOnPreRun=addOnPreRun;function addOnInit(t){__ATINIT__.unshift(t)}Module.addOnInit=addOnInit;function addOnPreMain(t){__ATMAIN__.unshift(t)}Module.addOnPreMain=addOnPreMain;function addOnExit(t){__ATEXIT__.unshift(t)}Module.addOnExit=addOnExit;function addOnPostRun(t){__ATPOSTRUN__.unshift(t)}Module.addOnPostRun=addOnPostRun;function intArrayFromString(t,e,r){var o=r>0?r:lengthBytesUTF8(t)+1,a=new Array(o),n=stringToUTF8Array(t,a,0,a.length);return e&&(a.length=n),a}Module.intArrayFromString=intArrayFromString;function intArrayToString(t){for(var e=[],r=0;r<t.length;r++){var o=t[r];o>255&&(o&=255),e.push(String.fromCharCode(o))}return e.join("")}Module.intArrayToString=intArrayToString;function writeStringToMemory(t,e,r){Runtime.warnOnce("writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!");var o,a;r&&(a=e+lengthBytesUTF8(t),o=HEAP8[a]),stringToUTF8(t,e,1/0),r&&(HEAP8[a]=o)}Module.writeStringToMemory=writeStringToMemory;function writeArrayToMemory(t,e){HEAP8.set(t,e)}Module.writeArrayToMemory=writeArrayToMemory;function writeAsciiToMemory(t,e,r){for(var o=0;o<t.length;++o)HEAP8[e++>>0]=t.charCodeAt(o);r||(HEAP8[e>>0]=0)}if(Module.writeAsciiToMemory=writeAsciiToMemory,(!Math.imul||Math.imul(4294967295,5)!==-5)&&(Math.imul=function t(e,r){var o=e>>>16,a=e&65535,n=r>>>16,u=r&65535;return a*u+(o*u+a*n<<16)|0}),Math.imul=Math.imul,!Math.fround){var froundBuffer=new Float32Array(1);Math.fround=function(t){return froundBuffer[0]=t,froundBuffer[0]}}Math.fround=Math.fround,Math.clz32||(Math.clz32=function(t){t=t>>>0;for(var e=0;e<32;e++)if(t&1<<31-e)return e;return 32}),Math.clz32=Math.clz32,Math.trunc||(Math.trunc=function(t){return t<0?Math.ceil(t):Math.floor(t)}),Math.trunc=Math.trunc;var Math_abs=Math.abs,Math_cos=Math.cos,Math_sin=Math.sin,Math_tan=Math.tan,Math_acos=Math.acos,Math_asin=Math.asin,Math_atan=Math.atan,Math_atan2=Math.atan2,Math_exp=Math.exp,Math_log=Math.log,Math_sqrt=Math.sqrt,Math_ceil=Math.ceil,Math_floor=Math.floor,Math_pow=Math.pow,Math_imul=Math.imul,Math_fround=Math.fround,Math_round=Math.round,Math_min=Math.min,Math_clz32=Math.clz32,Math_trunc=Math.trunc,runDependencies=0,runDependencyWatcher=null,dependenciesFulfilled=null;function getUniqueRunDependency(t){return t}function addRunDependency(t){runDependencies++,Module.monitorRunDependencies&&Module.monitorRunDependencies(runDependencies)}Module.addRunDependency=addRunDependency;function removeRunDependency(t){if(runDependencies--,Module.monitorRunDependencies&&Module.monitorRunDependencies(runDependencies),runDependencies==0&&(runDependencyWatcher!==null&&(clearInterval(runDependencyWatcher),runDependencyWatcher=null),dependenciesFulfilled)){var e=dependenciesFulfilled;dependenciesFulfilled=null,e()}}Module.removeRunDependency=removeRunDependency,Module.preloadedImages={},Module.preloadedAudios={};var ASM_CONSTS=[function(t,e,r,o,a,n,u,A){return _nbind.callbackSignatureList[t].apply(this,arguments)}];function _emscripten_asm_const_iiiiiiii(t,e,r,o,a,n,u,A){return ASM_CONSTS[t](e,r,o,a,n,u,A)}function _emscripten_asm_const_iiiii(t,e,r,o,a){return ASM_CONSTS[t](e,r,o,a)}function _emscripten_asm_const_iiidddddd(t,e,r,o,a,n,u,A,p){return ASM_CONSTS[t](e,r,o,a,n,u,A,p)}function _emscripten_asm_const_iiididi(t,e,r,o,a,n,u){return ASM_CONSTS[t](e,r,o,a,n,u)}function _emscripten_asm_const_iiii(t,e,r,o){return ASM_CONSTS[t](e,r,o)}function _emscripten_asm_const_iiiid(t,e,r,o,a){return ASM_CONSTS[t](e,r,o,a)}function _emscripten_asm_const_iiiiii(t,e,r,o,a,n){return ASM_CONSTS[t](e,r,o,a,n)}STATIC_BASE=Runtime.GLOBAL_BASE,STATICTOP=STATIC_BASE+12800,__ATINIT__.push({func:function(){__GLOBAL__sub_I_Yoga_cpp()}},{func:function(){__GLOBAL__sub_I_nbind_cc()}},{func:function(){__GLOBAL__sub_I_common_cc()}},{func:function(){__GLOBAL__sub_I_Binding_cc()}}),allocate([0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,192,127,0,0,192,127,3,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,3,0,0,0,0,0,192,127,3,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,0,0,128,191,0,0,128,191,0,0,192,127,0,0,0,0,0,0,0,0,0,0,128,63,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,190,12,0,0,200,12,0,0,208,12,0,0,216,12,0,0,230,12,0,0,242,12,0,0,1,0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0,0,192,127,3,0,0,0,180,45,0,0,181,45,0,0,182,45,0,0,181,45,0,0,182,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,4,0,0,0,183,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,184,45,0,0,185,45,0,0,181,45,0,0,181,45,0,0,182,45,0,0,186,45,0,0,185,45,0,0,148,4,0,0,3,0,0,0,187,45,0,0,164,4,0,0,188,45,0,0,2,0,0,0,189,45,0,0,164,4,0,0,188,45,0,0,185,45,0,0,164,4,0,0,185,45,0,0,164,4,0,0,188,45,0,0,181,45,0,0,182,45,0,0,181,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,1,0,0,0,7,0,0,0,183,45,0,0,182,45,0,0,181,45,0,0,190,45,0,0,190,45,0,0,182,45,0,0,182,45,0,0,185,45,0,0,181,45,0,0,185,45,0,0,182,45,0,0,181,45,0,0,185,45,0,0,182,45,0,0,185,45,0,0,48,5,0,0,3,0,0,0,56,5,0,0,1,0,0,0,189,45,0,0,185,45,0,0,164,4,0,0,76,5,0,0,2,0,0,0,191,45,0,0,186,45,0,0,182,45,0,0,185,45,0,0,192,45,0,0,185,45,0,0,182,45,0,0,186,45,0,0,185,45,0,0,76,5,0,0,76,5,0,0,136,5,0,0,182,45,0,0,181,45,0,0,2,0,0,0,190,45,0,0,136,5,0,0,56,19,0,0,156,5,0,0,2,0,0,0,184,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8,0,0,0,9,0,0,0,1,0,0,0,10,0,0,0,204,5,0,0,181,45,0,0,181,45,0,0,2,0,0,0,180,45,0,0,204,5,0,0,2,0,0,0,195,45,0,0,236,5,0,0,97,19,0,0,198,45,0,0,211,45,0,0,212,45,0,0,213,45,0,0,214,45,0,0,215,45,0,0,188,45,0,0,182,45,0,0,216,45,0,0,217,45,0,0,218,45,0,0,219,45,0,0,192,45,0,0,181,45,0,0,0,0,0,0,185,45,0,0,110,19,0,0,186,45,0,0,115,19,0,0,221,45,0,0,120,19,0,0,148,4,0,0,132,19,0,0,96,6,0,0,145,19,0,0,222,45,0,0,164,19,0,0,223,45,0,0,173,19,0,0,0,0,0,0,3,0,0,0,104,6,0,0,1,0,0,0,187,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,11,0,0,0,12,0,0,0,1,0,0,0,13,0,0,0,185,45,0,0,224,45,0,0,164,6,0,0,188,45,0,0,172,6,0,0,180,6,0,0,2,0,0,0,188,6,0,0,7,0,0,0,224,45,0,0,7,0,0,0,164,6,0,0,1,0,0,0,213,45,0,0,185,45,0,0,224,45,0,0,172,6,0,0,185,45,0,0,224,45,0,0,164,6,0,0,185,45,0,0,224,45,0,0,211,45,0,0,211,45,0,0,222,45,0,0,211,45,0,0,224,45,0,0,222,45,0,0,211,45,0,0,224,45,0,0,172,6,0,0,222,45,0,0,211,45,0,0,224,45,0,0,188,45,0,0,222,45,0,0,211,45,0,0,40,7,0,0,188,45,0,0,2,0,0,0,224,45,0,0,185,45,0,0,188,45,0,0,188,45,0,0,188,45,0,0,188,45,0,0,222,45,0,0,224,45,0,0,148,4,0,0,185,45,0,0,148,4,0,0,148,4,0,0,148,4,0,0,148,4,0,0,148,4,0,0,185,45,0,0,164,6,0,0,148,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,14,0,0,0,15,0,0,0,1,0,0,0,16,0,0,0,148,7,0,0,2,0,0,0,225,45,0,0,183,45,0,0,188,45,0,0,168,7,0,0,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,234,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,148,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,9,0,0,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,2,0,0,0,242,45,0,0,0,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67,111,117,108,100,32,110,111,116,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,32,102,111,114,32,110,111,100,101,0,67,97,110,110,111,116,32,114,101,115,101,116,32,97,32,110,111,100,101,32,119,104,105,99,104,32,115,116,105,108,108,32,104,97,115,32,99,104,105,108,100,114,101,110,32,97,116,116,97,99,104,101,100,0,67,97,110,110,111,116,32,114,101,115,101,116,32,97,32,110,111,100,101,32,115,116,105,108,108,32,97,116,116,97,99,104,101,100,32,116,111,32,97,32,112,97,114,101,110,116,0,67,111,117,108,100,32,110,111,116,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,32,102,111,114,32,99,111,110,102,105,103,0,67,97,110,110,111,116,32,115,101,116,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,58,32,78,111,100,101,115,32,119,105,116,104,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,32,99,97,110,110,111,116,32,104,97,118,101,32,99,104,105,108,100,114,101,110,46,0,67,104,105,108,100,32,97,108,114,101,97,100,121,32,104,97,115,32,97,32,112,97,114,101,110,116,44,32,105,116,32,109,117,115,116,32,98,101,32,114,101,109,111,118,101,100,32,102,105,114,115,116,46,0,67,97,110,110,111,116,32,97,100,100,32,99,104,105,108,100,58,32,78,111,100,101,115,32,119,105,116,104,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,32,99,97,110,110,111,116,32,104,97,118,101,32,99,104,105,108,100,114,101,110,46,0,79,110,108,121,32,108,101,97,102,32,110,111,100,101,115,32,119,105,116,104,32,99,117,115,116,111,109,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,115,104,111,117,108,100,32,109,97,110,117,97,108,108,121,32,109,97,114,107,32,116,104,101,109,115,101,108,118,101,115,32,97,115,32,100,105,114,116,121,0,67,97,110,110,111,116,32,103,101,116,32,108,97,121,111,117,116,32,112,114,111,112,101,114,116,105,101,115,32,111,102,32,109,117,108,116,105,45,101,100,103,101,32,115,104,111,114,116,104,97,110,100,115,0,37,115,37,100,46,123,91,115,107,105,112,112,101,100,93,32,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,97,119,58,32,37,102,32,97,104,58,32,37,102,32,61,62,32,100,58,32,40,37,102,44,32,37,102,41,32,37,115,10,0,37,115,37,100,46,123,37,115,0,42,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,97,119,58,32,37,102,32,97,104,58,32,37,102,32,37,115,10,0,37,115,37,100,46,125,37,115,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,100,58,32,40,37,102,44,32,37,102,41,32,37,115,10,0,79,117,116,32,111,102,32,99,97,99,104,101,32,101,110,116,114,105,101,115,33,10,0,83,99,97,108,101,32,102,97,99,116,111,114,32,115,104,111,117,108,100,32,110,111,116,32,98,101,32,108,101,115,115,32,116,104,97,110,32,122,101,114,111,0,105,110,105,116,105,97,108,0,37,115,10,0,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,0,85,78,68,69,70,73,78,69,68,0,69,88,65,67,84,76,89,0,65,84,95,77,79,83,84,0,76,65,89,95,85,78,68,69,70,73,78,69,68,0,76,65,89,95,69,88,65,67,84,76,89,0,76,65,89,95,65,84,95,77,79,83,84,0,97,118,97,105,108,97,98,108,101,87,105,100,116,104,32,105,115,32,105,110,100,101,102,105,110,105,116,101,32,115,111,32,119,105,100,116,104,77,101,97,115,117,114,101,77,111,100,101,32,109,117,115,116,32,98,101,32,89,71,77,101,97,115,117,114,101,77,111,100,101,85,110,100,101,102,105,110,101,100,0,97,118,97,105,108,97,98,108,101,72,101,105,103,104,116,32,105,115,32,105,110,100,101,102,105,110,105,116,101,32,115,111,32,104,101,105,103,104,116,77,101,97,115,117,114,101,77,111,100,101,32,109,117,115,116,32,98,101,32,89,71,77,101,97,115,117,114,101,77,111,100,101,85,110,100,101,102,105,110,101,100,0,102,108,101,120,0,115,116,114,101,116,99,104,0,109,117,108,116,105,108,105,110,101,45,115,116,114,101,116,99,104,0,69,120,112,101,99,116,101,100,32,110,111,100,101,32,116,111,32,104,97,118,101,32,99,117,115,116,111,109,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,0,109,101,97,115,117,114,101,0,69,120,112,101,99,116,32,99,117,115,116,111,109,32,98,97,115,101,108,105,110,101,32,102,117,110,99,116,105,111,110,32,116,111,32,110,111,116,32,114,101,116,117,114,110,32,78,97,78,0,97,98,115,45,109,101,97,115,117,114,101,0,97,98,115,45,108,97,121,111,117,116,0,78,111,100,101,0,99,114,101,97,116,101,68,101,102,97,117,108,116,0,99,114,101,97,116,101,87,105,116,104,67,111,110,102,105,103,0,100,101,115,116,114,111,121,0,114,101,115,101,116,0,99,111,112,121,83,116,121,108,101,0,115,101,116,80,111,115,105,116,105,111,110,84,121,112,101,0,115,101,116,80,111,115,105,116,105,111,110,0,115,101,116,80,111,115,105,116,105,111,110,80,101,114,99,101,110,116,0,115,101,116,65,108,105,103,110,67,111,110,116,101,110,116,0,115,101,116,65,108,105,103,110,73,116,101,109,115,0,115,101,116,65,108,105,103,110,83,101,108,102,0,115,101,116,70,108,101,120,68,105,114,101,99,116,105,111,110,0,115,101,116,70,108,101,120,87,114,97,112,0,115,101,116,74,117,115,116,105,102,121,67,111,110,116,101,110,116,0,115,101,116,77,97,114,103,105,110,0,115,101,116,77,97,114,103,105,110,80,101,114,99,101,110,116,0,115,101,116,77,97,114,103,105,110,65,117,116,111,0,115,101,116,79,118,101,114,102,108,111,119,0,115,101,116,68,105,115,112,108,97,121,0,115,101,116,70,108,101,120,0,115,101,116,70,108,101,120,66,97,115,105,115,0,115,101,116,70,108,101,120,66,97,115,105,115,80,101,114,99,101,110,116,0,115,101,116,70,108,101,120,71,114,111,119,0,115,101,116,70,108,101,120,83,104,114,105,110,107,0,115,101,116,87,105,100,116,104,0,115,101,116,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,87,105,100,116,104,65,117,116,111,0,115,101,116,72,101,105,103,104,116,0,115,101,116,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,72,101,105,103,104,116,65,117,116,111,0,115,101,116,77,105,110,87,105,100,116,104,0,115,101,116,77,105,110,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,77,105,110,72,101,105,103,104,116,0,115,101,116,77,105,110,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,77,97,120,87,105,100,116,104,0,115,101,116,77,97,120,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,77,97,120,72,101,105,103,104,116,0,115,101,116,77,97,120,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,65,115,112,101,99,116,82,97,116,105,111,0,115,101,116,66,111,114,100,101,114,0,115,101,116,80,97,100,100,105,110,103,0,115,101,116,80,97,100,100,105,110,103,80,101,114,99,101,110,116,0,103,101,116,80,111,115,105,116,105,111,110,84,121,112,101,0,103,101,116,80,111,115,105,116,105,111,110,0,103,101,116,65,108,105,103,110,67,111,110,116,101,110,116,0,103,101,116,65,108,105,103,110,73,116,101,109,115,0,103,101,116,65,108,105,103,110,83,101,108,102,0,103,101,116,70,108,101,120,68,105,114,101,99,116,105,111,110,0,103,101,116,70,108,101,120,87,114,97,112,0,103,101,116,74,117,115,116,105,102,121,67,111,110,116,101,110,116,0,103,101,116,77,97,114,103,105,110,0,103,101,116,70,108,101,120,66,97,115,105,115,0,103,101,116,70,108,101,120,71,114,111,119,0,103,101,116,70,108,101,120,83,104,114,105,110,107,0,103,101,116,87,105,100,116,104,0,103,101,116,72,101,105,103,104,116,0,103,101,116,77,105,110,87,105,100,116,104,0,103,101,116,77,105,110,72,101,105,103,104,116,0,103,101,116,77,97,120,87,105,100,116,104,0,103,101,116,77,97,120,72,101,105,103,104,116,0,103,101,116,65,115,112,101,99,116,82,97,116,105,111,0,103,101,116,66,111,114,100,101,114,0,103,101,116,79,118,101,114,102,108,111,119,0,103,101,116,68,105,115,112,108,97,121,0,103,101,116,80,97,100,100,105,110,103,0,105,110,115,101,114,116,67,104,105,108,100,0,114,101,109,111,118,101,67,104,105,108,100,0,103,101,116,67,104,105,108,100,67,111,117,110,116,0,103,101,116,80,97,114,101,110,116,0,103,101,116,67,104,105,108,100,0,115,101,116,77,101,97,115,117,114,101,70,117,110,99,0,117,110,115,101,116,77,101,97,115,117,114,101,70,117,110,99,0,109,97,114,107,68,105,114,116,121,0,105,115,68,105,114,116,121,0,99,97,108,99,117,108,97,116,101,76,97,121,111,117,116,0,103,101,116,67,111,109,112,117,116,101,100,76,101,102,116,0,103,101,116,67,111,109,112,117,116,101,100,82,105,103,104,116,0,103,101,116,67,111,109,112,117,116,101,100,84,111,112,0,103,101,116,67,111,109,112,117,116,101,100,66,111,116,116,111,109,0,103,101,116,67,111,109,112,117,116,101,100,87,105,100,116,104,0,103,101,116,67,111,109,112,117,116,101,100,72,101,105,103,104,116,0,103,101,116,67,111,109,112,117,116,101,100,76,97,121,111,117,116,0,103,101,116,67,111,109,112,117,116,101,100,77,97,114,103,105,110,0,103,101,116,67,111,109,112,117,116,101,100,66,111,114,100,101,114,0,103,101,116,67,111,109,112,117,116,101,100,80,97,100,100,105,110,103,0,67,111,110,102,105,103,0,99,114,101,97,116,101,0,115,101,116,69,120,112,101,114,105,109,101,110,116,97,108,70,101,97,116,117,114,101,69,110,97,98,108,101,100,0,115,101,116,80,111,105,110,116,83,99,97,108,101,70,97,99,116,111,114,0,105,115,69,120,112,101,114,105,109,101,110,116,97,108,70,101,97,116,117,114,101,69,110,97,98,108,101,100,0,86,97,108,117,101,0,76,97,121,111,117,116,0,83,105,122,101,0,103,101,116,73,110,115,116,97,110,99,101,67,111,117,110,116,0,73,110,116,54,52,0,1,1,1,2,2,4,4,4,4,8,8,4,8,118,111,105,100,0,98,111,111,108,0,115,116,100,58,58,115,116,114,105,110,103,0,99,98,70,117,110,99,116,105,111,110,32,38,0,99,111,110,115,116,32,99,98,70,117,110,99,116,105,111,110,32,38,0,69,120,116,101,114,110,97,108,0,66,117,102,102,101,114,0,78,66,105,110,100,73,68,0,78,66,105,110,100,0,98,105,110,100,95,118,97,108,117,101,0,114,101,102,108,101,99,116,0,113,117,101,114,121,84,121,112,101,0,108,97,108,108,111,99,0,108,114,101,115,101,116,0,123,114,101,116,117,114,110,40,95,110,98,105,110,100,46,99,97,108,108,98,97,99,107,83,105,103,110,97,116,117,114,101,76,105,115,116,91,36,48,93,46,97,112,112,108,121,40,116,104,105,115,44,97,114,103,117,109,101,110,116,115,41,41,59,125,0,95,110,98,105,110,100,95,110,101,119,0,17,0,10,0,17,17,17,0,0,0,0,5,0,0,0,0,0,0,9,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,15,10,17,17,17,3,10,7,0,1,19,9,11,11,0,0,9,6,11,0,0,11,0,6,17,0,0,0,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,10,10,17,17,17,0,10,0,0,2,0,9,11,0,0,0,9,0,11,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,4,13,0,0,0,0,9,14,0,0,0,0,0,14,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,15,0,0,0,0,9,16,0,0,0,0,0,16,0,0,16,0,0,18,0,0,0,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,0,18,18,18,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,10,0,0,0,0,9,11,0,0,0,0,0,11,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,0,0,45,43,32,32,32,48,88,48,120,0,40,110,117,108,108,41,0,45,48,88,43,48,88,32,48,88,45,48,120,43,48,120,32,48,120,0,105,110,102,0,73,78,70,0,110,97,110,0,78,65,78,0,48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,46,0,84,33,34,25,13,1,2,3,17,75,28,12,16,4,11,29,18,30,39,104,110,111,112,113,98,32,5,6,15,19,20,21,26,8,22,7,40,36,23,24,9,10,14,27,31,37,35,131,130,125,38,42,43,60,61,62,63,67,71,74,77,88,89,90,91,92,93,94,95,96,97,99,100,101,102,103,105,106,107,108,114,115,116,121,122,123,124,0,73,108,108,101,103,97,108,32,98,121,116,101,32,115,101,113,117,101,110,99,101,0,68,111,109,97,105,110,32,101,114,114,111,114,0,82,101,115,117,108,116,32,110,111,116,32,114,101,112,114,101,115,101,110,116,97,98,108,101,0,78,111,116,32,97,32,116,116,121,0,80,101,114,109,105,115,115,105,111,110,32,100,101,110,105,101,100,0,79,112,101,114,97,116,105,111,110,32,110,111,116,32,112,101,114,109,105,116,116,101,100,0,78,111,32,115,117,99,104,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,0,78,111,32,115,117,99,104,32,112,114,111,99,101,115,115,0,70,105,108,101,32,101,120,105,115,116,115,0,86,97,108,117,101,32,116,111,111,32,108,97,114,103,101,32,102,111,114,32,100,97,116,97,32,116,121,112,101,0,78,111,32,115,112,97,99,101,32,108,101,102,116,32,111,110,32,100,101,118,105,99,101,0,79,117,116,32,111,102,32,109,101,109,111,114,121,0,82,101,115,111,117,114,99,101,32,98,117,115,121,0,73,110,116,101,114,114,117,112,116,101,100,32,115,121,115,116,101,109,32,99,97,108,108,0,82,101,115,111,117,114,99,101,32,116,101,109,112,111,114,97,114,105,108,121,32,117,110,97,118,97,105,108,97,98,108,101,0,73,110,118,97,108,105,100,32,115,101,101,107,0,67,114,111,115,115,45,100,101,118,105,99,101,32,108,105,110,107,0,82,101,97,100,45,111,110,108,121,32,102,105,108,101,32,115,121,115,116,101,109,0,68,105,114,101,99,116,111,114,121,32,110,111,116,32,101,109,112,116,121,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,112,101,101,114,0,79,112,101,114,97,116,105,111,110,32,116,105,109,101,100,32,111,117,116,0,67,111,110,110,101,99,116,105,111,110,32,114,101,102,117,115,101,100,0,72,111,115,116,32,105,115,32,100,111,119,110,0,72,111,115,116,32,105,115,32,117,110,114,101,97,99,104,97,98,108,101,0,65,100,100,114,101,115,115,32,105,110,32,117,115,101,0,66,114,111,107,101,110,32,112,105,112,101,0,73,47,79,32,101,114,114,111,114,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,32,111,114,32,97,100,100,114,101,115,115,0,66,108,111,99,107,32,100,101,118,105,99,101,32,114,101,113,117,105,114,101,100,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,0,78,111,116,32,97,32,100,105,114,101,99,116,111,114,121,0,73,115,32,97,32,100,105,114,101,99,116,111,114,121,0,84,101,120,116,32,102,105,108,101,32,98,117,115,121,0,69,120,101,99,32,102,111,114,109,97,116,32,101,114,114,111,114,0,73,110,118,97,108,105,100,32,97,114,103,117,109,101,110,116,0,65,114,103,117,109,101,110,116,32,108,105,115,116,32,116,111,111,32,108,111,110,103,0,83,121,109,98,111,108,105,99,32,108,105,110,107,32,108,111,111,112,0,70,105,108,101,110,97,109,101,32,116,111,111,32,108,111,110,103,0,84,111,111,32,109,97,110,121,32,111,112,101,110,32,102,105,108,101,115,32,105,110,32,115,121,115,116,101,109,0,78,111,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,97,118,97,105,108,97,98,108,101,0,66,97,100,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,0,78,111,32,99,104,105,108,100,32,112,114,111,99,101,115,115,0,66,97,100,32,97,100,100,114,101,115,115,0,70,105,108,101,32,116,111,111,32,108,97,114,103,101,0,84,111,111,32,109,97,110,121,32,108,105,110,107,115,0,78,111,32,108,111,99,107,115,32,97,118,97,105,108,97,98,108,101,0,82,101,115,111,117,114,99,101,32,100,101,97,100,108,111,99,107,32,119,111,117,108,100,32,111,99,99,117,114,0,83,116,97,116,101,32,110,111,116,32,114,101,99,111,118,101,114,97,98,108,101,0,80,114,101,118,105,111,117,115,32,111,119,110,101,114,32,100,105,101,100,0,79,112,101,114,97,116,105,111,110,32,99,97,110,99,101,108,101,100,0,70,117,110,99,116,105,111,110,32,110,111,116,32,105,109,112,108,101,109,101,110,116,101,100,0,78,111,32,109,101,115,115,97,103,101,32,111,102,32,100,101,115,105,114,101,100,32,116,121,112,101,0,73,100,101,110,116,105,102,105,101,114,32,114,101,109,111,118,101,100,0,68,101,118,105,99,101,32,110,111,116,32,97,32,115,116,114,101,97,109,0,78,111,32,100,97,116,97,32,97,118,97,105,108,97,98,108,101,0,68,101,118,105,99,101,32,116,105,109,101,111,117,116,0,79,117,116,32,111,102,32,115,116,114,101,97,109,115,32,114,101,115,111,117,114,99,101,115,0,76,105,110,107,32,104,97,115,32,98,101,101,110,32,115,101,118,101,114,101,100,0,80,114,111,116,111,99,111,108,32,101,114,114,111,114,0,66,97,100,32,109,101,115,115,97,103,101,0,70,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32,105,110,32,98,97,100,32,115,116,97,116,101,0,78,111,116,32,97,32,115,111,99,107,101,116,0,68,101,115,116,105,110,97,116,105,111,110,32,97,100,100,114,101,115,115,32,114,101,113,117,105,114,101,100,0,77,101,115,115,97,103,101,32,116,111,111,32,108,97,114,103,101,0,80,114,111,116,111,99,111,108,32,119,114,111,110,103,32,116,121,112,101,32,102,111,114,32,115,111,99,107,101,116,0,80,114,111,116,111,99,111,108,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,80,114,111,116,111,99,111,108,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,83,111,99,107,101,116,32,116,121,112,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,78,111,116,32,115,117,112,112,111,114,116,101,100,0,80,114,111,116,111,99,111,108,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,65,100,100,114,101,115,115,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32,112,114,111,116,111,99,111,108,0,65,100,100,114,101,115,115,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,78,101,116,119,111,114,107,32,105,115,32,100,111,119,110,0,78,101,116,119,111,114,107,32,117,110,114,101,97,99,104,97,98,108,101,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,110,101,116,119,111,114,107,0,67,111,110,110,101,99,116,105,111,110,32,97,98,111,114,116,101,100,0,78,111,32,98,117,102,102,101,114,32,115,112,97,99,101,32,97,118,97,105,108,97,98,108,101,0,83,111,99,107,101,116,32,105,115,32,99,111,110,110,101,99,116,101,100,0,83,111,99,107,101,116,32,110,111,116,32,99,111,110,110,101,99,116,101,100,0,67,97,110,110,111,116,32,115,101,110,100,32,97,102,116,101,114,32,115,111,99,107,101,116,32,115,104,117,116,100,111,119,110,0,79,112,101,114,97,116,105,111,110,32,97,108,114,101,97,100,121,32,105,110,32,112,114,111,103,114,101,115,115,0,79,112,101,114,97,116,105,111,110,32,105,110,32,112,114,111,103,114,101,115,115,0,83,116,97,108,101,32,102,105,108,101,32,104,97,110,100,108,101,0,82,101,109,111,116,101,32,73,47,79,32,101,114,114,111,114,0,81,117,111,116,97,32,101,120,99,101,101,100,101,100,0,78,111,32,109,101,100,105,117,109,32,102,111,117,110,100,0,87,114,111,110,103,32,109,101,100,105,117,109,32,116,121,112,101,0,78,111,32,101,114,114,111,114,32,105,110,102,111,114,109,97,116,105,111,110,0,0],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE);var tempDoublePtr=STATICTOP;STATICTOP+=16;function _atexit(t,e){__ATEXIT__.unshift({func:t,arg:e})}function ___cxa_atexit(){return _atexit.apply(null,arguments)}function _abort(){Module.abort()}function __ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj(){Module.printErr("missing function: _ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj"),abort(-1)}function __decorate(t,e,r,o){var a=arguments.length,n=a<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,r):o,u;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")n=Reflect.decorate(t,e,r,o);else for(var A=t.length-1;A>=0;A--)(u=t[A])&&(n=(a<3?u(n):a>3?u(e,r,n):u(e,r))||n);return a>3&&n&&Object.defineProperty(e,r,n),n}function _defineHidden(t){return function(e,r){Object.defineProperty(e,r,{configurable:!1,enumerable:!1,value:t,writable:!0})}}var _nbind={};function __nbind_free_external(t){_nbind.externalList[t].dereference(t)}function __nbind_reference_external(t){_nbind.externalList[t].reference()}function _llvm_stackrestore(t){var e=_llvm_stacksave,r=e.LLVM_SAVEDSTACKS[t];e.LLVM_SAVEDSTACKS.splice(t,1),Runtime.stackRestore(r)}function __nbind_register_pool(t,e,r,o){_nbind.Pool.pageSize=t,_nbind.Pool.usedPtr=e/4,_nbind.Pool.rootPtr=r,_nbind.Pool.pagePtr=o/4,HEAP32[e/4]=16909060,HEAP8[e]==1&&(_nbind.bigEndian=!0),HEAP32[e/4]=0,_nbind.makeTypeKindTbl=(n={},n[1024]=_nbind.PrimitiveType,n[64]=_nbind.Int64Type,n[2048]=_nbind.BindClass,n[3072]=_nbind.BindClassPtr,n[4096]=_nbind.SharedClassPtr,n[5120]=_nbind.ArrayType,n[6144]=_nbind.ArrayType,n[7168]=_nbind.CStringType,n[9216]=_nbind.CallbackType,n[10240]=_nbind.BindType,n),_nbind.makeTypeNameTbl={Buffer:_nbind.BufferType,External:_nbind.ExternalType,Int64:_nbind.Int64Type,_nbind_new:_nbind.CreateValueType,bool:_nbind.BooleanType,"cbFunction &":_nbind.CallbackType,"const cbFunction &":_nbind.CallbackType,"const std::string &":_nbind.StringType,"std::string":_nbind.StringType},Module.toggleLightGC=_nbind.toggleLightGC,_nbind.callUpcast=Module.dynCall_ii;var a=_nbind.makeType(_nbind.constructType,{flags:2048,id:0,name:""});a.proto=Module,_nbind.BindClass.list.push(a);var n}function _emscripten_set_main_loop_timing(t,e){if(Browser.mainLoop.timingMode=t,Browser.mainLoop.timingValue=e,!Browser.mainLoop.func)return 1;if(t==0)Browser.mainLoop.scheduler=function(){var u=Math.max(0,Browser.mainLoop.tickStartTime+e-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,u)},Browser.mainLoop.method="timeout";else if(t==1)Browser.mainLoop.scheduler=function(){Browser.requestAnimationFrame(Browser.mainLoop.runner)},Browser.mainLoop.method="rAF";else if(t==2){if(!window.setImmediate){let n=function(u){u.source===window&&u.data===o&&(u.stopPropagation(),r.shift()())};var a=n,r=[],o="setimmediate";window.addEventListener("message",n,!0),window.setImmediate=function(A){r.push(A),ENVIRONMENT_IS_WORKER?(Module.setImmediates===void 0&&(Module.setImmediates=[]),Module.setImmediates.push(A),window.postMessage({target:o})):window.postMessage(o,"*")}}Browser.mainLoop.scheduler=function(){window.setImmediate(Browser.mainLoop.runner)},Browser.mainLoop.method="immediate"}return 0}function _emscripten_get_now(){abort()}function _emscripten_set_main_loop(t,e,r,o,a){Module.noExitRuntime=!0,assert(!Browser.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters."),Browser.mainLoop.func=t,Browser.mainLoop.arg=o;var n;typeof o<"u"?n=function(){Module.dynCall_vi(t,o)}:n=function(){Module.dynCall_v(t)};var u=Browser.mainLoop.currentlyRunningMainloop;if(Browser.mainLoop.runner=function(){if(!ABORT){if(Browser.mainLoop.queue.length>0){var p=Date.now(),h=Browser.mainLoop.queue.shift();if(h.func(h.arg),Browser.mainLoop.remainingBlockers){var E=Browser.mainLoop.remainingBlockers,I=E%1==0?E-1:Math.floor(E);h.counted?Browser.mainLoop.remainingBlockers=I:(I=I+.5,Browser.mainLoop.remainingBlockers=(8*E+I)/9)}if(console.log('main loop blocker "'+h.name+'" took '+(Date.now()-p)+" ms"),Browser.mainLoop.updateStatus(),u<Browser.mainLoop.currentlyRunningMainloop)return;setTimeout(Browser.mainLoop.runner,0);return}if(!(u<Browser.mainLoop.currentlyRunningMainloop)){if(Browser.mainLoop.currentFrameNumber=Browser.mainLoop.currentFrameNumber+1|0,Browser.mainLoop.timingMode==1&&Browser.mainLoop.timingValue>1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else Browser.mainLoop.timingMode==0&&(Browser.mainLoop.tickStartTime=_emscripten_get_now());Browser.mainLoop.method==="timeout"&&Module.ctx&&(Module.printErr("Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!"),Browser.mainLoop.method=""),Browser.mainLoop.runIter(n),!(u<Browser.mainLoop.currentlyRunningMainloop)&&(typeof SDL=="object"&&SDL.audio&&SDL.audio.queueNewAudioData&&SDL.audio.queueNewAudioData(),Browser.mainLoop.scheduler())}}},a||(e&&e>0?_emscripten_set_main_loop_timing(0,1e3/e):_emscripten_set_main_loop_timing(1,1),Browser.mainLoop.scheduler()),r)throw"SimulateInfiniteLoop"}var Browser={mainLoop:{scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null,Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var t=Browser.mainLoop.timingMode,e=Browser.mainLoop.timingValue,r=Browser.mainLoop.func;Browser.mainLoop.func=null,_emscripten_set_main_loop(r,0,!1,Browser.mainLoop.arg,!0),_emscripten_set_main_loop_timing(t,e),Browser.mainLoop.scheduler()},updateStatus:function(){if(Module.setStatus){var t=Module.statusMessage||"Please wait...",e=Browser.mainLoop.remainingBlockers,r=Browser.mainLoop.expectedBlockers;e?e<r?Module.setStatus(t+" ("+(r-e)+"/"+r+")"):Module.setStatus(t):Module.setStatus("")}},runIter:function(t){if(!ABORT){if(Module.preMainLoop){var e=Module.preMainLoop();if(e===!1)return}try{t()}catch(r){if(r instanceof ExitStatus)return;throw r&&typeof r=="object"&&r.stack&&Module.printErr("exception thrown: "+[r,r.stack]),r}Module.postMainLoop&&Module.postMainLoop()}}},isFullscreen:!1,pointerLock:!1,moduleContextCreatedCallbacks:[],workers:[],init:function(){if(Module.preloadPlugins||(Module.preloadPlugins=[]),Browser.initted)return;Browser.initted=!0;try{new Blob,Browser.hasBlobConstructor=!0}catch{Browser.hasBlobConstructor=!1,console.log("warning: no blob constructor, cannot create blobs with mimetypes")}Browser.BlobBuilder=typeof MozBlobBuilder<"u"?MozBlobBuilder:typeof WebKitBlobBuilder<"u"?WebKitBlobBuilder:Browser.hasBlobConstructor?null:console.log("warning: no BlobBuilder"),Browser.URLObject=typeof window<"u"?window.URL?window.URL:window.webkitURL:void 0,!Module.noImageDecoding&&typeof Browser.URLObject>"u"&&(console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available."),Module.noImageDecoding=!0);var t={};t.canHandle=function(n){return!Module.noImageDecoding&&/\.(jpg|jpeg|png|bmp)$/i.test(n)},t.handle=function(n,u,A,p){var h=null;if(Browser.hasBlobConstructor)try{h=new Blob([n],{type:Browser.getMimetype(u)}),h.size!==n.length&&(h=new Blob([new Uint8Array(n).buffer],{type:Browser.getMimetype(u)}))}catch(x){Runtime.warnOnce("Blob constructor present but fails: "+x+"; falling back to blob builder")}if(!h){var E=new Browser.BlobBuilder;E.append(new Uint8Array(n).buffer),h=E.getBlob()}var I=Browser.URLObject.createObjectURL(h),v=new Image;v.onload=function(){assert(v.complete,"Image "+u+" could not be decoded");var C=document.createElement("canvas");C.width=v.width,C.height=v.height;var R=C.getContext("2d");R.drawImage(v,0,0),Module.preloadedImages[u]=C,Browser.URLObject.revokeObjectURL(I),A&&A(n)},v.onerror=function(C){console.log("Image "+I+" could not be decoded"),p&&p()},v.src=I},Module.preloadPlugins.push(t);var e={};e.canHandle=function(n){return!Module.noAudioDecoding&&n.substr(-4)in{".ogg":1,".wav":1,".mp3":1}},e.handle=function(n,u,A,p){var h=!1;function E(R){h||(h=!0,Module.preloadedAudios[u]=R,A&&A(n))}function I(){h||(h=!0,Module.preloadedAudios[u]=new Audio,p&&p())}if(Browser.hasBlobConstructor){try{var v=new Blob([n],{type:Browser.getMimetype(u)})}catch{return I()}var x=Browser.URLObject.createObjectURL(v),C=new Audio;C.addEventListener("canplaythrough",function(){E(C)},!1),C.onerror=function(N){if(h)return;console.log("warning: browser could not fully decode audio "+u+", trying slower base64 approach");function U(V){for(var te="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",ae="=",fe="",ue=0,me=0,he=0;he<V.length;he++)for(ue=ue<<8|V[he],me+=8;me>=6;){var Be=ue>>me-6&63;me-=6,fe+=te[Be]}return me==2?(fe+=te[(ue&3)<<4],fe+=ae+ae):me==4&&(fe+=te[(ue&15)<<2],fe+=ae),fe}C.src="data:audio/x-"+u.substr(-3)+";base64,"+U(n),E(C)},C.src=x,Browser.safeSetTimeout(function(){E(C)},1e4)}else return I()},Module.preloadPlugins.push(e);function r(){Browser.pointerLock=document.pointerLockElement===Module.canvas||document.mozPointerLockElement===Module.canvas||document.webkitPointerLockElement===Module.canvas||document.msPointerLockElement===Module.canvas}var o=Module.canvas;o&&(o.requestPointerLock=o.requestPointerLock||o.mozRequestPointerLock||o.webkitRequestPointerLock||o.msRequestPointerLock||function(){},o.exitPointerLock=document.exitPointerLock||document.mozExitPointerLock||document.webkitExitPointerLock||document.msExitPointerLock||function(){},o.exitPointerLock=o.exitPointerLock.bind(document),document.addEventListener("pointerlockchange",r,!1),document.addEventListener("mozpointerlockchange",r,!1),document.addEventListener("webkitpointerlockchange",r,!1),document.addEventListener("mspointerlockchange",r,!1),Module.elementPointerLock&&o.addEventListener("click",function(a){!Browser.pointerLock&&Module.canvas.requestPointerLock&&(Module.canvas.requestPointerLock(),a.preventDefault())},!1))},createContext:function(t,e,r,o){if(e&&Module.ctx&&t==Module.canvas)return Module.ctx;var a,n;if(e){var u={antialias:!1,alpha:!1};if(o)for(var A in o)u[A]=o[A];n=GL.createContext(t,u),n&&(a=GL.getContext(n).GLctx)}else a=t.getContext("2d");return a?(r&&(e||assert(typeof GLctx>"u","cannot set in module if GLctx is used, but we are a non-GL context that would replace it"),Module.ctx=a,e&&GL.makeContextCurrent(n),Module.useWebGL=e,Browser.moduleContextCreatedCallbacks.forEach(function(p){p()}),Browser.init()),a):null},destroyContext:function(t,e,r){},fullscreenHandlersInstalled:!1,lockPointer:void 0,resizeCanvas:void 0,requestFullscreen:function(t,e,r){Browser.lockPointer=t,Browser.resizeCanvas=e,Browser.vrDevice=r,typeof Browser.lockPointer>"u"&&(Browser.lockPointer=!0),typeof Browser.resizeCanvas>"u"&&(Browser.resizeCanvas=!1),typeof Browser.vrDevice>"u"&&(Browser.vrDevice=null);var o=Module.canvas;function a(){Browser.isFullscreen=!1;var u=o.parentNode;(document.fullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||document.webkitFullscreenElement||document.webkitCurrentFullScreenElement)===u?(o.exitFullscreen=document.exitFullscreen||document.cancelFullScreen||document.mozCancelFullScreen||document.msExitFullscreen||document.webkitCancelFullScreen||function(){},o.exitFullscreen=o.exitFullscreen.bind(document),Browser.lockPointer&&o.requestPointerLock(),Browser.isFullscreen=!0,Browser.resizeCanvas&&Browser.setFullscreenCanvasSize()):(u.parentNode.insertBefore(o,u),u.parentNode.removeChild(u),Browser.resizeCanvas&&Browser.setWindowedCanvasSize()),Module.onFullScreen&&Module.onFullScreen(Browser.isFullscreen),Module.onFullscreen&&Module.onFullscreen(Browser.isFullscreen),Browser.updateCanvasDimensions(o)}Browser.fullscreenHandlersInstalled||(Browser.fullscreenHandlersInstalled=!0,document.addEventListener("fullscreenchange",a,!1),document.addEventListener("mozfullscreenchange",a,!1),document.addEventListener("webkitfullscreenchange",a,!1),document.addEventListener("MSFullscreenChange",a,!1));var n=document.createElement("div");o.parentNode.insertBefore(n,o),n.appendChild(o),n.requestFullscreen=n.requestFullscreen||n.mozRequestFullScreen||n.msRequestFullscreen||(n.webkitRequestFullscreen?function(){n.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}:null)||(n.webkitRequestFullScreen?function(){n.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT)}:null),r?n.requestFullscreen({vrDisplay:r}):n.requestFullscreen()},requestFullScreen:function(t,e,r){return Module.printErr("Browser.requestFullScreen() is deprecated. Please call Browser.requestFullscreen instead."),Browser.requestFullScreen=function(o,a,n){return Browser.requestFullscreen(o,a,n)},Browser.requestFullscreen(t,e,r)},nextRAF:0,fakeRequestAnimationFrame:function(t){var e=Date.now();if(Browser.nextRAF===0)Browser.nextRAF=e+1e3/60;else for(;e+2>=Browser.nextRAF;)Browser.nextRAF+=1e3/60;var r=Math.max(Browser.nextRAF-e,0);setTimeout(t,r)},requestAnimationFrame:function t(e){typeof window>"u"?Browser.fakeRequestAnimationFrame(e):(window.requestAnimationFrame||(window.requestAnimationFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame||Browser.fakeRequestAnimationFrame),window.requestAnimationFrame(e))},safeCallback:function(t){return function(){if(!ABORT)return t.apply(null,arguments)}},allowAsyncCallbacks:!0,queuedAsyncCallbacks:[],pauseAsyncCallbacks:function(){Browser.allowAsyncCallbacks=!1},resumeAsyncCallbacks:function(){if(Browser.allowAsyncCallbacks=!0,Browser.queuedAsyncCallbacks.length>0){var t=Browser.queuedAsyncCallbacks;Browser.queuedAsyncCallbacks=[],t.forEach(function(e){e()})}},safeRequestAnimationFrame:function(t){return Browser.requestAnimationFrame(function(){ABORT||(Browser.allowAsyncCallbacks?t():Browser.queuedAsyncCallbacks.push(t))})},safeSetTimeout:function(t,e){return Module.noExitRuntime=!0,setTimeout(function(){ABORT||(Browser.allowAsyncCallbacks?t():Browser.queuedAsyncCallbacks.push(t))},e)},safeSetInterval:function(t,e){return Module.noExitRuntime=!0,setInterval(function(){ABORT||Browser.allowAsyncCallbacks&&t()},e)},getMimetype:function(t){return{jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",bmp:"image/bmp",ogg:"audio/ogg",wav:"audio/wav",mp3:"audio/mpeg"}[t.substr(t.lastIndexOf(".")+1)]},getUserMedia:function(t){window.getUserMedia||(window.getUserMedia=navigator.getUserMedia||navigator.mozGetUserMedia),window.getUserMedia(t)},getMovementX:function(t){return t.movementX||t.mozMovementX||t.webkitMovementX||0},getMovementY:function(t){return t.movementY||t.mozMovementY||t.webkitMovementY||0},getMouseWheelDelta:function(t){var e=0;switch(t.type){case"DOMMouseScroll":e=t.detail;break;case"mousewheel":e=t.wheelDelta;break;case"wheel":e=t.deltaY;break;default:throw"unrecognized mouse wheel event: "+t.type}return e},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseEvent:function(t){if(Browser.pointerLock)t.type!="mousemove"&&"mozMovementX"in t?Browser.mouseMovementX=Browser.mouseMovementY=0:(Browser.mouseMovementX=Browser.getMovementX(t),Browser.mouseMovementY=Browser.getMovementY(t)),typeof SDL<"u"?(Browser.mouseX=SDL.mouseX+Browser.mouseMovementX,Browser.mouseY=SDL.mouseY+Browser.mouseMovementY):(Browser.mouseX+=Browser.mouseMovementX,Browser.mouseY+=Browser.mouseMovementY);else{var e=Module.canvas.getBoundingClientRect(),r=Module.canvas.width,o=Module.canvas.height,a=typeof window.scrollX<"u"?window.scrollX:window.pageXOffset,n=typeof window.scrollY<"u"?window.scrollY:window.pageYOffset;if(t.type==="touchstart"||t.type==="touchend"||t.type==="touchmove"){var u=t.touch;if(u===void 0)return;var A=u.pageX-(a+e.left),p=u.pageY-(n+e.top);A=A*(r/e.width),p=p*(o/e.height);var h={x:A,y:p};if(t.type==="touchstart")Browser.lastTouches[u.identifier]=h,Browser.touches[u.identifier]=h;else if(t.type==="touchend"||t.type==="touchmove"){var E=Browser.touches[u.identifier];E||(E=h),Browser.lastTouches[u.identifier]=E,Browser.touches[u.identifier]=h}return}var I=t.pageX-(a+e.left),v=t.pageY-(n+e.top);I=I*(r/e.width),v=v*(o/e.height),Browser.mouseMovementX=I-Browser.mouseX,Browser.mouseMovementY=v-Browser.mouseY,Browser.mouseX=I,Browser.mouseY=v}},asyncLoad:function(t,e,r,o){var a=o?"":"al "+t;Module.readAsync(t,function(n){assert(n,'Loading data file "'+t+'" failed (no arrayBuffer).'),e(new Uint8Array(n)),a&&removeRunDependency(a)},function(n){if(r)r();else throw'Loading data file "'+t+'" failed.'}),a&&addRunDependency(a)},resizeListeners:[],updateResizeListeners:function(){var t=Module.canvas;Browser.resizeListeners.forEach(function(e){e(t.width,t.height)})},setCanvasSize:function(t,e,r){var o=Module.canvas;Browser.updateCanvasDimensions(o,t,e),r||Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL<"u"){var t=HEAPU32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2];t=t|8388608,HEAP32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2]=t}Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL<"u"){var t=HEAPU32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2];t=t&-8388609,HEAP32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2]=t}Browser.updateResizeListeners()},updateCanvasDimensions:function(t,e,r){e&&r?(t.widthNative=e,t.heightNative=r):(e=t.widthNative,r=t.heightNative);var o=e,a=r;if(Module.forcedAspectRatio&&Module.forcedAspectRatio>0&&(o/a<Module.forcedAspectRatio?o=Math.round(a*Module.forcedAspectRatio):a=Math.round(o/Module.forcedAspectRatio)),(document.fullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||document.webkitFullscreenElement||document.webkitCurrentFullScreenElement)===t.parentNode&&typeof screen<"u"){var n=Math.min(screen.width/o,screen.height/a);o=Math.round(o*n),a=Math.round(a*n)}Browser.resizeCanvas?(t.width!=o&&(t.width=o),t.height!=a&&(t.height=a),typeof t.style<"u"&&(t.style.removeProperty("width"),t.style.removeProperty("height"))):(t.width!=e&&(t.width=e),t.height!=r&&(t.height=r),typeof t.style<"u"&&(o!=e||a!=r?(t.style.setProperty("width",o+"px","important"),t.style.setProperty("height",a+"px","important")):(t.style.removeProperty("width"),t.style.removeProperty("height"))))},wgetRequests:{},nextWgetRequestHandle:0,getNextWgetRequestHandle:function(){var t=Browser.nextWgetRequestHandle;return Browser.nextWgetRequestHandle++,t}},SYSCALLS={varargs:0,get:function(t){SYSCALLS.varargs+=4;var e=HEAP32[SYSCALLS.varargs-4>>2];return e},getStr:function(){var t=Pointer_stringify(SYSCALLS.get());return t},get64:function(){var t=SYSCALLS.get(),e=SYSCALLS.get();return t>=0?assert(e===0):assert(e===-1),t},getZero:function(){assert(SYSCALLS.get()===0)}};function ___syscall6(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.getStreamFromFD();return FS.close(r),0}catch(o){return(typeof FS>"u"||!(o instanceof FS.ErrnoError))&&abort(o),-o.errno}}function ___syscall54(t,e){SYSCALLS.varargs=e;try{return 0}catch(r){return(typeof FS>"u"||!(r instanceof FS.ErrnoError))&&abort(r),-r.errno}}function _typeModule(t){var e=[[0,1,"X"],[1,1,"const X"],[128,1,"X *"],[256,1,"X &"],[384,1,"X &&"],[512,1,"std::shared_ptr<X>"],[640,1,"std::unique_ptr<X>"],[5120,1,"std::vector<X>"],[6144,2,"std::array<X, Y>"],[9216,-1,"std::function<X (Y)>"]];function r(p,h,E,I,v,x){if(h==1){var C=I&896;(C==128||C==256||C==384)&&(p="X const")}var R;return x?R=E.replace("X",p).replace("Y",v):R=p.replace("X",E).replace("Y",v),R.replace(/([*&]) (?=[*&])/g,"$1")}function o(p,h,E,I,v){throw new Error(p+" type "+E.replace("X",h+"?")+(I?" with flag "+I:"")+" in "+v)}function a(p,h,E,I,v,x,C,R){x===void 0&&(x="X"),R===void 0&&(R=1);var N=E(p);if(N)return N;var U=I(p),V=U.placeholderFlag,te=e[V];C&&te&&(x=r(C[2],C[0],x,te[0],"?",!0));var ae;V==0&&(ae="Unbound"),V>=10&&(ae="Corrupt"),R>20&&(ae="Deeply nested"),ae&&o(ae,p,x,V,v||"?");var fe=U.paramList[0],ue=a(fe,h,E,I,v,x,te,R+1),me,he={flags:te[0],id:p,name:"",paramList:[ue]},Be=[],we="?";switch(U.placeholderFlag){case 1:me=ue.spec;break;case 2:if((ue.flags&15360)==1024&&ue.spec.ptrSize==1){he.flags=7168;break}case 3:case 6:case 5:me=ue.spec,ue.flags&15360;break;case 8:we=""+U.paramList[1],he.paramList.push(U.paramList[1]);break;case 9:for(var g=0,Ee=U.paramList[1];g<Ee.length;g++){var Pe=Ee[g],ce=a(Pe,h,E,I,v,x,te,R+1);Be.push(ce.name),he.paramList.push(ce)}we=Be.join(", ");break;default:break}if(he.name=r(te[2],te[0],ue.name,ue.flags,we),me){for(var ne=0,ee=Object.keys(me);ne<ee.length;ne++){var Ie=ee[ne];he[Ie]=he[Ie]||me[Ie]}he.flags|=me.flags}return n(h,he)}function n(p,h){var E=h.flags,I=E&896,v=E&15360;return!h.name&&v==1024&&(h.ptrSize==1?h.name=(E&16?"":(E&8?"un":"")+"signed ")+"char":h.name=(E&8?"u":"")+(E&32?"float":"int")+(h.ptrSize*8+"_t")),h.ptrSize==8&&!(E&32)&&(v=64),v==2048&&(I==512||I==640?v=4096:I&&(v=3072)),p(v,h)}var u=function(){function p(h){this.id=h.id,this.name=h.name,this.flags=h.flags,this.spec=h}return p.prototype.toString=function(){return this.name},p}(),A={Type:u,getComplexType:a,makeType:n,structureList:e};return t.output=A,t.output||A}function __nbind_register_type(t,e){var r=_nbind.readAsciiString(e),o={flags:10240,id:t,name:r};_nbind.makeType(_nbind.constructType,o)}function __nbind_register_callback_signature(t,e){var r=_nbind.readTypeIdList(t,e),o=_nbind.callbackSignatureList.length;return _nbind.callbackSignatureList[o]=_nbind.makeJSCaller(r),o}function __extends(t,e){for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);function o(){this.constructor=t}o.prototype=e.prototype,t.prototype=new o}function __nbind_register_class(t,e,r,o,a,n,u){var A=_nbind.readAsciiString(u),p=_nbind.readPolicyList(e),h=HEAPU32.subarray(t/4,t/4+2),E={flags:2048|(p.Value?2:0),id:h[0],name:A},I=_nbind.makeType(_nbind.constructType,E);I.ptrType=_nbind.getComplexType(h[1],_nbind.constructType,_nbind.getType,_nbind.queryType),I.destroy=_nbind.makeMethodCaller(I.ptrType,{boundID:E.id,flags:0,name:"destroy",num:0,ptr:n,title:I.name+".free",typeList:["void","uint32_t","uint32_t"]}),a&&(I.superIdList=Array.prototype.slice.call(HEAPU32.subarray(r/4,r/4+a)),I.upcastList=Array.prototype.slice.call(HEAPU32.subarray(o/4,o/4+a))),Module[I.name]=I.makeBound(p),_nbind.BindClass.list.push(I)}function _removeAccessorPrefix(t){var e=/^[Gg]et_?([A-Z]?([A-Z]?))/;return t.replace(e,function(r,o,a){return a?o:o.toLowerCase()})}function __nbind_register_function(t,e,r,o,a,n,u,A,p,h){var E=_nbind.getType(t),I=_nbind.readPolicyList(e),v=_nbind.readTypeIdList(r,o),x;if(u==5)x=[{direct:a,name:"__nbindConstructor",ptr:0,title:E.name+" constructor",typeList:["uint32_t"].concat(v.slice(1))},{direct:n,name:"__nbindValueConstructor",ptr:0,title:E.name+" value constructor",typeList:["void","uint32_t"].concat(v.slice(1))}];else{var C=_nbind.readAsciiString(A),R=(E.name&&E.name+".")+C;(u==3||u==4)&&(C=_removeAccessorPrefix(C)),x=[{boundID:t,direct:n,name:C,ptr:a,title:R,typeList:v}]}for(var N=0,U=x;N<U.length;N++){var V=U[N];V.signatureType=u,V.policyTbl=I,V.num=p,V.flags=h,E.addMethod(V)}}function _nbind_value(t,e){_nbind.typeNameTbl[t]||_nbind.throwError("Unknown value type "+t),Module.NBind.bind_value(t,e),_defineHidden(_nbind.typeNameTbl[t].proto.prototype.__nbindValueConstructor)(e.prototype,"__nbindValueConstructor")}Module._nbind_value=_nbind_value;function __nbind_get_value_object(t,e){var r=_nbind.popValue(t);if(!r.fromJS)throw new Error("Object "+r+" has no fromJS function");r.fromJS(function(){r.__nbindValueConstructor.apply(this,Array.prototype.concat.apply([e],arguments))})}function _emscripten_memcpy_big(t,e,r){return HEAPU8.set(HEAPU8.subarray(e,e+r),t),t}function __nbind_register_primitive(t,e,r){var o={flags:1024|r,id:t,ptrSize:e};_nbind.makeType(_nbind.constructType,o)}var cttz_i8=allocate([8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0],"i8",ALLOC_STATIC);function ___setErrNo(t){return Module.___errno_location&&(HEAP32[Module.___errno_location()>>2]=t),t}function _llvm_stacksave(){var t=_llvm_stacksave;return t.LLVM_SAVEDSTACKS||(t.LLVM_SAVEDSTACKS=[]),t.LLVM_SAVEDSTACKS.push(Runtime.stackSave()),t.LLVM_SAVEDSTACKS.length-1}function ___syscall140(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.getStreamFromFD(),o=SYSCALLS.get(),a=SYSCALLS.get(),n=SYSCALLS.get(),u=SYSCALLS.get(),A=a;return FS.llseek(r,A,u),HEAP32[n>>2]=r.position,r.getdents&&A===0&&u===0&&(r.getdents=null),0}catch(p){return(typeof FS>"u"||!(p instanceof FS.ErrnoError))&&abort(p),-p.errno}}function ___syscall146(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.get(),o=SYSCALLS.get(),a=SYSCALLS.get(),n=0;___syscall146.buffer||(___syscall146.buffers=[null,[],[]],___syscall146.printChar=function(E,I){var v=___syscall146.buffers[E];assert(v),I===0||I===10?((E===1?Module.print:Module.printErr)(UTF8ArrayToString(v,0)),v.length=0):v.push(I)});for(var u=0;u<a;u++){for(var A=HEAP32[o+u*8>>2],p=HEAP32[o+(u*8+4)>>2],h=0;h<p;h++)___syscall146.printChar(r,HEAPU8[A+h]);n+=p}return n}catch(E){return(typeof FS>"u"||!(E instanceof FS.ErrnoError))&&abort(E),-E.errno}}function __nbind_finish(){for(var t=0,e=_nbind.BindClass.list;t<e.length;t++){var r=e[t];r.finish()}}var ___dso_handle=STATICTOP;STATICTOP+=16,function(_nbind){var typeIdTbl={};_nbind.typeNameTbl={};var Pool=function(){function t(){}return t.lalloc=function(e){e=e+7&-8;var r=HEAPU32[t.usedPtr];if(e>t.pageSize/2||e>t.pageSize-r){var o=_nbind.typeNameTbl.NBind.proto;return o.lalloc(e)}else return HEAPU32[t.usedPtr]=r+e,t.rootPtr+r},t.lreset=function(e,r){var o=HEAPU32[t.pagePtr];if(o){var a=_nbind.typeNameTbl.NBind.proto;a.lreset(e,r)}else HEAPU32[t.usedPtr]=e},t}();_nbind.Pool=Pool;function constructType(t,e){var r=t==10240?_nbind.makeTypeNameTbl[e.name]||_nbind.BindType:_nbind.makeTypeKindTbl[t],o=new r(e);return typeIdTbl[e.id]=o,_nbind.typeNameTbl[e.name]=o,o}_nbind.constructType=constructType;function getType(t){return typeIdTbl[t]}_nbind.getType=getType;function queryType(t){var e=HEAPU8[t],r=_nbind.structureList[e][1];t/=4,r<0&&(++t,r=HEAPU32[t]+1);var o=Array.prototype.slice.call(HEAPU32.subarray(t+1,t+1+r));return e==9&&(o=[o[0],o.slice(1)]),{paramList:o,placeholderFlag:e}}_nbind.queryType=queryType;function getTypes(t,e){return t.map(function(r){return typeof r=="number"?_nbind.getComplexType(r,constructType,getType,queryType,e):_nbind.typeNameTbl[r]})}_nbind.getTypes=getTypes;function readTypeIdList(t,e){return Array.prototype.slice.call(HEAPU32,t/4,t/4+e)}_nbind.readTypeIdList=readTypeIdList;function readAsciiString(t){for(var e=t;HEAPU8[e++];);return String.fromCharCode.apply("",HEAPU8.subarray(t,e-1))}_nbind.readAsciiString=readAsciiString;function readPolicyList(t){var e={};if(t)for(;;){var r=HEAPU32[t/4];if(!r)break;e[readAsciiString(r)]=!0,t+=4}return e}_nbind.readPolicyList=readPolicyList;function getDynCall(t,e){var r={float32_t:"d",float64_t:"d",int64_t:"d",uint64_t:"d",void:"v"},o=t.map(function(n){return r[n.name]||"i"}).join(""),a=Module["dynCall_"+o];if(!a)throw new Error("dynCall_"+o+" not found for "+e+"("+t.map(function(n){return n.name}).join(", ")+")");return a}_nbind.getDynCall=getDynCall;function addMethod(t,e,r,o){var a=t[e];t.hasOwnProperty(e)&&a?((a.arity||a.arity===0)&&(a=_nbind.makeOverloader(a,a.arity),t[e]=a),a.addMethod(r,o)):(r.arity=o,t[e]=r)}_nbind.addMethod=addMethod;function throwError(t){throw new Error(t)}_nbind.throwError=throwError,_nbind.bigEndian=!1,_a=_typeModule(_typeModule),_nbind.Type=_a.Type,_nbind.makeType=_a.makeType,_nbind.getComplexType=_a.getComplexType,_nbind.structureList=_a.structureList;var BindType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.heap=HEAPU32,r.ptrSize=4,r}return e.prototype.needsWireRead=function(r){return!!this.wireRead||!!this.makeWireRead},e.prototype.needsWireWrite=function(r){return!!this.wireWrite||!!this.makeWireWrite},e}(_nbind.Type);_nbind.BindType=BindType;var PrimitiveType=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this,a=r.flags&32?{32:HEAPF32,64:HEAPF64}:r.flags&8?{8:HEAPU8,16:HEAPU16,32:HEAPU32}:{8:HEAP8,16:HEAP16,32:HEAP32};return o.heap=a[r.ptrSize*8],o.ptrSize=r.ptrSize,o}return e.prototype.needsWireWrite=function(r){return!!r&&!!r.Strict},e.prototype.makeWireWrite=function(r,o){return o&&o.Strict&&function(a){if(typeof a=="number")return a;throw new Error("Type mismatch")}},e}(BindType);_nbind.PrimitiveType=PrimitiveType;function pushCString(t,e){if(t==null){if(e&&e.Nullable)return 0;throw new Error("Type mismatch")}if(e&&e.Strict){if(typeof t!="string")throw new Error("Type mismatch")}else t=t.toString();var r=Module.lengthBytesUTF8(t)+1,o=_nbind.Pool.lalloc(r);return Module.stringToUTF8Array(t,HEAPU8,o,r),o}_nbind.pushCString=pushCString;function popCString(t){return t===0?null:Module.Pointer_stringify(t)}_nbind.popCString=popCString;var CStringType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=popCString,r.wireWrite=pushCString,r.readResources=[_nbind.resources.pool],r.writeResources=[_nbind.resources.pool],r}return e.prototype.makeWireWrite=function(r,o){return function(a){return pushCString(a,o)}},e}(BindType);_nbind.CStringType=CStringType;var BooleanType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=function(o){return!!o},r}return e.prototype.needsWireWrite=function(r){return!!r&&!!r.Strict},e.prototype.makeWireRead=function(r){return"!!("+r+")"},e.prototype.makeWireWrite=function(r,o){return o&&o.Strict&&function(a){if(typeof a=="boolean")return a;throw new Error("Type mismatch")}||r},e}(BindType);_nbind.BooleanType=BooleanType;var Wrapper=function(){function t(){}return t.prototype.persist=function(){this.__nbindState|=1},t}();_nbind.Wrapper=Wrapper;function makeBound(t,e){var r=function(o){__extends(a,o);function a(n,u,A,p){var h=o.call(this)||this;if(!(h instanceof a))return new(Function.prototype.bind.apply(a,Array.prototype.concat.apply([null],arguments)));var E=u,I=A,v=p;if(n!==_nbind.ptrMarker){var x=h.__nbindConstructor.apply(h,arguments);E=4608,v=HEAPU32[x/4],I=HEAPU32[x/4+1]}var C={configurable:!0,enumerable:!1,value:null,writable:!1},R={__nbindFlags:E,__nbindPtr:I};v&&(R.__nbindShared=v,_nbind.mark(h));for(var N=0,U=Object.keys(R);N<U.length;N++){var V=U[N];C.value=R[V],Object.defineProperty(h,V,C)}return _defineHidden(0)(h,"__nbindState"),h}return a.prototype.free=function(){e.destroy.call(this,this.__nbindShared,this.__nbindFlags),this.__nbindState|=2,disableMember(this,"__nbindShared"),disableMember(this,"__nbindPtr")},a}(Wrapper);return __decorate([_defineHidden()],r.prototype,"__nbindConstructor",void 0),__decorate([_defineHidden()],r.prototype,"__nbindValueConstructor",void 0),__decorate([_defineHidden(t)],r.prototype,"__nbindPolicies",void 0),r}_nbind.makeBound=makeBound;function disableMember(t,e){function r(){throw new Error("Accessing deleted object")}Object.defineProperty(t,e,{configurable:!1,enumerable:!1,get:r,set:r})}_nbind.ptrMarker={};var BindClass=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this;return o.wireRead=function(a){return _nbind.popValue(a,o.ptrType)},o.wireWrite=function(a){return pushPointer(a,o.ptrType,!0)},o.pendingSuperCount=0,o.ready=!1,o.methodTbl={},r.paramList?(o.classType=r.paramList[0].classType,o.proto=o.classType.proto):o.classType=o,o}return e.prototype.makeBound=function(r){var o=_nbind.makeBound(r,this);return this.proto=o,this.ptrType.proto=o,o},e.prototype.addMethod=function(r){var o=this.methodTbl[r.name]||[];o.push(r),this.methodTbl[r.name]=o},e.prototype.registerMethods=function(r,o){for(var a,n=0,u=Object.keys(r.methodTbl);n<u.length;n++)for(var A=u[n],p=r.methodTbl[A],h=0,E=p;h<E.length;h++){var I=E[h],v=void 0,x=void 0;if(v=this.proto.prototype,!(o&&I.signatureType!=1))switch(I.signatureType){case 1:v=this.proto;case 5:x=_nbind.makeCaller(I),_nbind.addMethod(v,I.name,x,I.typeList.length-1);break;case 4:a=_nbind.makeMethodCaller(r.ptrType,I);break;case 3:Object.defineProperty(v,I.name,{configurable:!0,enumerable:!1,get:_nbind.makeMethodCaller(r.ptrType,I),set:a});break;case 2:x=_nbind.makeMethodCaller(r.ptrType,I),_nbind.addMethod(v,I.name,x,I.typeList.length-1);break;default:break}}},e.prototype.registerSuperMethods=function(r,o,a){if(!a[r.name]){a[r.name]=!0;for(var n=0,u,A=0,p=r.superIdList||[];A<p.length;A++){var h=p[A],E=_nbind.getType(h);n++<o||o<0?u=-1:u=0,this.registerSuperMethods(E,u,a)}this.registerMethods(r,o<0)}},e.prototype.finish=function(){if(this.ready)return this;this.ready=!0,this.superList=(this.superIdList||[]).map(function(a){return _nbind.getType(a).finish()});var r=this.proto;if(this.superList.length){var o=function(){this.constructor=r};o.prototype=this.superList[0].proto.prototype,r.prototype=new o}return r!=Module&&(r.prototype.__nbindType=this),this.registerSuperMethods(this,1,{}),this},e.prototype.upcastStep=function(r,o){if(r==this)return o;for(var a=0;a<this.superList.length;++a){var n=this.superList[a].upcastStep(r,_nbind.callUpcast(this.upcastList[a],o));if(n)return n}return 0},e}(_nbind.BindType);BindClass.list=[],_nbind.BindClass=BindClass;function popPointer(t,e){return t?new e.proto(_nbind.ptrMarker,e.flags,t):null}_nbind.popPointer=popPointer;function pushPointer(t,e,r){if(!(t instanceof _nbind.Wrapper)){if(r)return _nbind.pushValue(t);throw new Error("Type mismatch")}var o=t.__nbindPtr,a=t.__nbindType.classType,n=e.classType;if(t instanceof e.proto)for(;a!=n;)o=_nbind.callUpcast(a.upcastList[0],o),a=a.superList[0];else if(o=a.upcastStep(n,o),!o)throw new Error("Type mismatch");return o}_nbind.pushPointer=pushPointer;function pushMutablePointer(t,e){var r=pushPointer(t,e);if(t.__nbindFlags&1)throw new Error("Passing a const value as a non-const argument");return r}var BindClassPtr=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this;o.classType=r.paramList[0].classType,o.proto=o.classType.proto;var a=r.flags&1,n=(o.flags&896)==256&&r.flags&2,u=a?pushPointer:pushMutablePointer,A=n?_nbind.popValue:popPointer;return o.makeWireWrite=function(p,h){return h.Nullable?function(E){return E?u(E,o):0}:function(E){return u(E,o)}},o.wireRead=function(p){return A(p,o)},o.wireWrite=function(p){return u(p,o)},o}return e}(_nbind.BindType);_nbind.BindClassPtr=BindClassPtr;function popShared(t,e){var r=HEAPU32[t/4],o=HEAPU32[t/4+1];return o?new e.proto(_nbind.ptrMarker,e.flags,o,r):null}_nbind.popShared=popShared;function pushShared(t,e){if(!(t instanceof e.proto))throw new Error("Type mismatch");return t.__nbindShared}function pushMutableShared(t,e){if(!(t instanceof e.proto))throw new Error("Type mismatch");if(t.__nbindFlags&1)throw new Error("Passing a const value as a non-const argument");return t.__nbindShared}var SharedClassPtr=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this;o.readResources=[_nbind.resources.pool],o.classType=r.paramList[0].classType,o.proto=o.classType.proto;var a=r.flags&1,n=a?pushShared:pushMutableShared;return o.wireRead=function(u){return popShared(u,o)},o.wireWrite=function(u){return n(u,o)},o}return e}(_nbind.BindType);_nbind.SharedClassPtr=SharedClassPtr,_nbind.externalList=[0];var firstFreeExternal=0,External=function(){function t(e){this.refCount=1,this.data=e}return t.prototype.register=function(){var e=firstFreeExternal;return e?firstFreeExternal=_nbind.externalList[e]:e=_nbind.externalList.length,_nbind.externalList[e]=this,e},t.prototype.reference=function(){++this.refCount},t.prototype.dereference=function(e){--this.refCount==0&&(this.free&&this.free(),_nbind.externalList[e]=firstFreeExternal,firstFreeExternal=e)},t}();_nbind.External=External;function popExternal(t){var e=_nbind.externalList[t];return e.dereference(t),e.data}function pushExternal(t){var e=new External(t);return e.reference(),e.register()}var ExternalType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=popExternal,r.wireWrite=pushExternal,r}return e}(_nbind.BindType);_nbind.ExternalType=ExternalType,_nbind.callbackSignatureList=[];var CallbackType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireWrite=function(o){return typeof o!="function"&&_nbind.throwError("Type mismatch"),new _nbind.External(o).register()},r}return e}(_nbind.BindType);_nbind.CallbackType=CallbackType,_nbind.valueList=[0];var firstFreeValue=0;function pushValue(t){var e=firstFreeValue;return e?firstFreeValue=_nbind.valueList[e]:e=_nbind.valueList.length,_nbind.valueList[e]=t,e*2+1}_nbind.pushValue=pushValue;function popValue(t,e){if(t||_nbind.throwError("Value type JavaScript class is missing or not registered"),t&1){t>>=1;var r=_nbind.valueList[t];return _nbind.valueList[t]=firstFreeValue,firstFreeValue=t,r}else{if(e)return _nbind.popShared(t,e);throw new Error("Invalid value slot "+t)}}_nbind.popValue=popValue;var valueBase=18446744073709552e3;function push64(t){return typeof t=="number"?t:pushValue(t)*4096+valueBase}function pop64(t){return t<valueBase?t:popValue((t-valueBase)/4096)}var CreateValueType=function(t){__extends(e,t);function e(){return t!==null&&t.apply(this,arguments)||this}return e.prototype.makeWireWrite=function(r){return"(_nbind.pushValue(new "+r+"))"},e}(_nbind.BindType);_nbind.CreateValueType=CreateValueType;var Int64Type=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireWrite=push64,r.wireRead=pop64,r}return e}(_nbind.BindType);_nbind.Int64Type=Int64Type;function pushArray(t,e){if(!t)return 0;var r=t.length;if((e.size||e.size===0)&&r<e.size)throw new Error("Type mismatch");var o=e.memberType.ptrSize,a=_nbind.Pool.lalloc(4+r*o);HEAPU32[a/4]=r;var n=e.memberType.heap,u=(a+4)/o,A=e.memberType.wireWrite,p=0;if(A)for(;p<r;)n[u++]=A(t[p++]);else for(;p<r;)n[u++]=t[p++];return a}_nbind.pushArray=pushArray;function popArray(t,e){if(t===0)return null;var r=HEAPU32[t/4],o=new Array(r),a=e.memberType.heap;t=(t+4)/e.memberType.ptrSize;var n=e.memberType.wireRead,u=0;if(n)for(;u<r;)o[u++]=n(a[t++]);else for(;u<r;)o[u++]=a[t++];return o}_nbind.popArray=popArray;var ArrayType=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this;return o.wireRead=function(a){return popArray(a,o)},o.wireWrite=function(a){return pushArray(a,o)},o.readResources=[_nbind.resources.pool],o.writeResources=[_nbind.resources.pool],o.memberType=r.paramList[0],r.paramList[1]&&(o.size=r.paramList[1]),o}return e}(_nbind.BindType);_nbind.ArrayType=ArrayType;function pushString(t,e){if(t==null)if(e&&e.Nullable)t="";else throw new Error("Type mismatch");if(e&&e.Strict){if(typeof t!="string")throw new Error("Type mismatch")}else t=t.toString();var r=Module.lengthBytesUTF8(t),o=_nbind.Pool.lalloc(4+r+1);return HEAPU32[o/4]=r,Module.stringToUTF8Array(t,HEAPU8,o+4,r+1),o}_nbind.pushString=pushString;function popString(t){if(t===0)return null;var e=HEAPU32[t/4];return Module.Pointer_stringify(t+4,e)}_nbind.popString=popString;var StringType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=popString,r.wireWrite=pushString,r.readResources=[_nbind.resources.pool],r.writeResources=[_nbind.resources.pool],r}return e.prototype.makeWireWrite=function(r,o){return function(a){return pushString(a,o)}},e}(_nbind.BindType);_nbind.StringType=StringType;function makeArgList(t){return Array.apply(null,Array(t)).map(function(e,r){return"a"+(r+1)})}function anyNeedsWireWrite(t,e){return t.reduce(function(r,o){return r||o.needsWireWrite(e)},!1)}function anyNeedsWireRead(t,e){return t.reduce(function(r,o){return r||!!o.needsWireRead(e)},!1)}function makeWireRead(t,e,r,o){var a=t.length;return r.makeWireRead?r.makeWireRead(o,t,a):r.wireRead?(t[a]=r.wireRead,"(convertParamList["+a+"]("+o+"))"):o}function makeWireWrite(t,e,r,o){var a,n=t.length;return r.makeWireWrite?a=r.makeWireWrite(o,e,t,n):a=r.wireWrite,a?typeof a=="string"?a:(t[n]=a,"(convertParamList["+n+"]("+o+"))"):o}function buildCallerFunction(dynCall,ptrType,ptr,num,policyTbl,needsWireWrite,prefix,returnType,argTypeList,mask,err){var argList=makeArgList(argTypeList.length),convertParamList=[],callExpression=makeWireRead(convertParamList,policyTbl,returnType,"dynCall("+[prefix].concat(argList.map(function(t,e){return makeWireWrite(convertParamList,policyTbl,argTypeList[e],t)})).join(",")+")"),resourceSet=_nbind.listResources([returnType],argTypeList),sourceCode="function("+argList.join(",")+"){"+(mask?"this.__nbindFlags&mask&&err();":"")+resourceSet.makeOpen()+"var r="+callExpression+";"+resourceSet.makeClose()+"return r;}";return eval("("+sourceCode+")")}function buildJSCallerFunction(returnType,argTypeList){var argList=makeArgList(argTypeList.length),convertParamList=[],callExpression=makeWireWrite(convertParamList,null,returnType,"_nbind.externalList[num].data("+argList.map(function(t,e){return makeWireRead(convertParamList,null,argTypeList[e],t)}).join(",")+")"),resourceSet=_nbind.listResources(argTypeList,[returnType]);resourceSet.remove(_nbind.resources.pool);var sourceCode="function("+["dummy","num"].concat(argList).join(",")+"){"+resourceSet.makeOpen()+"var r="+callExpression+";"+resourceSet.makeClose()+"return r;}";return eval("("+sourceCode+")")}_nbind.buildJSCallerFunction=buildJSCallerFunction;function makeJSCaller(t){var e=t.length-1,r=_nbind.getTypes(t,"callback"),o=r[0],a=r.slice(1),n=anyNeedsWireRead(a,null),u=o.needsWireWrite(null);if(!u&&!n)switch(e){case 0:return function(A,p){return _nbind.externalList[p].data()};case 1:return function(A,p,h){return _nbind.externalList[p].data(h)};case 2:return function(A,p,h,E){return _nbind.externalList[p].data(h,E)};case 3:return function(A,p,h,E,I){return _nbind.externalList[p].data(h,E,I)};default:break}return buildJSCallerFunction(o,a)}_nbind.makeJSCaller=makeJSCaller;function makeMethodCaller(t,e){var r=e.typeList.length-1,o=e.typeList.slice(0);o.splice(1,0,"uint32_t",e.boundID);var a=_nbind.getTypes(o,e.title),n=a[0],u=a.slice(3),A=n.needsWireRead(e.policyTbl),p=anyNeedsWireWrite(u,e.policyTbl),h=e.ptr,E=e.num,I=_nbind.getDynCall(a,e.title),v=~e.flags&1;function x(){throw new Error("Calling a non-const method on a const object")}if(!A&&!p)switch(r){case 0:return function(){return this.__nbindFlags&v?x():I(h,E,_nbind.pushPointer(this,t))};case 1:return function(C){return this.__nbindFlags&v?x():I(h,E,_nbind.pushPointer(this,t),C)};case 2:return function(C,R){return this.__nbindFlags&v?x():I(h,E,_nbind.pushPointer(this,t),C,R)};case 3:return function(C,R,N){return this.__nbindFlags&v?x():I(h,E,_nbind.pushPointer(this,t),C,R,N)};default:break}return buildCallerFunction(I,t,h,E,e.policyTbl,p,"ptr,num,pushPointer(this,ptrType)",n,u,v,x)}_nbind.makeMethodCaller=makeMethodCaller;function makeCaller(t){var e=t.typeList.length-1,r=_nbind.getTypes(t.typeList,t.title),o=r[0],a=r.slice(1),n=o.needsWireRead(t.policyTbl),u=anyNeedsWireWrite(a,t.policyTbl),A=t.direct,p=t.ptr;if(t.direct&&!n&&!u){var h=_nbind.getDynCall(r,t.title);switch(e){case 0:return function(){return h(A)};case 1:return function(x){return h(A,x)};case 2:return function(x,C){return h(A,x,C)};case 3:return function(x,C,R){return h(A,x,C,R)};default:break}p=0}var E;if(p){var I=t.typeList.slice(0);I.splice(1,0,"uint32_t"),r=_nbind.getTypes(I,t.title),E="ptr,num"}else p=A,E="ptr";var v=_nbind.getDynCall(r,t.title);return buildCallerFunction(v,null,p,t.num,t.policyTbl,u,E,o,a)}_nbind.makeCaller=makeCaller;function makeOverloader(t,e){var r=[];function o(){return r[arguments.length].apply(this,arguments)}return o.addMethod=function(a,n){r[n]=a},o.addMethod(t,e),o}_nbind.makeOverloader=makeOverloader;var Resource=function(){function t(e,r){var o=this;this.makeOpen=function(){return Object.keys(o.openTbl).join("")},this.makeClose=function(){return Object.keys(o.closeTbl).join("")},this.openTbl={},this.closeTbl={},e&&(this.openTbl[e]=!0),r&&(this.closeTbl[r]=!0)}return t.prototype.add=function(e){for(var r=0,o=Object.keys(e.openTbl);r<o.length;r++){var a=o[r];this.openTbl[a]=!0}for(var n=0,u=Object.keys(e.closeTbl);n<u.length;n++){var a=u[n];this.closeTbl[a]=!0}},t.prototype.remove=function(e){for(var r=0,o=Object.keys(e.openTbl);r<o.length;r++){var a=o[r];delete this.openTbl[a]}for(var n=0,u=Object.keys(e.closeTbl);n<u.length;n++){var a=u[n];delete this.closeTbl[a]}},t}();_nbind.Resource=Resource;function listResources(t,e){for(var r=new Resource,o=0,a=t;o<a.length;o++)for(var n=a[o],u=0,A=n.readResources||[];u<A.length;u++){var p=A[u];r.add(p)}for(var h=0,E=e;h<E.length;h++)for(var n=E[h],I=0,v=n.writeResources||[];I<v.length;I++){var p=v[I];r.add(p)}return r}_nbind.listResources=listResources,_nbind.resources={pool:new Resource("var used=HEAPU32[_nbind.Pool.usedPtr],page=HEAPU32[_nbind.Pool.pagePtr];","_nbind.Pool.lreset(used,page);")};var ExternalBuffer=function(t){__extends(e,t);function e(r,o){var a=t.call(this,r)||this;return a.ptr=o,a}return e.prototype.free=function(){_free(this.ptr)},e}(_nbind.External);function getBuffer(t){return t instanceof ArrayBuffer?new Uint8Array(t):t instanceof DataView?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):t}function pushBuffer(t,e){if(t==null&&e&&e.Nullable&&(t=[]),typeof t!="object")throw new Error("Type mismatch");var r=t,o=r.byteLength||r.length;if(!o&&o!==0&&r.byteLength!==0)throw new Error("Type mismatch");var a=_nbind.Pool.lalloc(8),n=_malloc(o),u=a/4;return HEAPU32[u++]=o,HEAPU32[u++]=n,HEAPU32[u++]=new ExternalBuffer(t,n).register(),HEAPU8.set(getBuffer(t),n),a}var BufferType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireWrite=pushBuffer,r.readResources=[_nbind.resources.pool],r.writeResources=[_nbind.resources.pool],r}return e.prototype.makeWireWrite=function(r,o){return function(a){return pushBuffer(a,o)}},e}(_nbind.BindType);_nbind.BufferType=BufferType;function commitBuffer(t,e,r){var o=_nbind.externalList[t].data,a=Buffer;if(typeof Buffer!="function"&&(a=function(){}),!(o instanceof Array)){var n=HEAPU8.subarray(e,e+r);if(o instanceof a){var u=void 0;typeof Buffer.from=="function"&&Buffer.from.length>=3?u=Buffer.from(n):u=new Buffer(n),u.copy(o)}else getBuffer(o).set(n)}}_nbind.commitBuffer=commitBuffer;var dirtyList=[],gcTimer=0;function sweep(){for(var t=0,e=dirtyList;t<e.length;t++){var r=e[t];r.__nbindState&3||r.free()}dirtyList=[],gcTimer=0}_nbind.mark=function(t){};function toggleLightGC(t){t?_nbind.mark=function(e){dirtyList.push(e),gcTimer||(gcTimer=setTimeout(sweep,0))}:_nbind.mark=function(e){}}_nbind.toggleLightGC=toggleLightGC}(_nbind),Module.requestFullScreen=function t(e,r,o){Module.printErr("Module.requestFullScreen is deprecated. Please call Module.requestFullscreen instead."),Module.requestFullScreen=Module.requestFullscreen,Browser.requestFullScreen(e,r,o)},Module.requestFullscreen=function t(e,r,o){Browser.requestFullscreen(e,r,o)},Module.requestAnimationFrame=function t(e){Browser.requestAnimationFrame(e)},Module.setCanvasSize=function t(e,r,o){Browser.setCanvasSize(e,r,o)},Module.pauseMainLoop=function t(){Browser.mainLoop.pause()},Module.resumeMainLoop=function t(){Browser.mainLoop.resume()},Module.getUserMedia=function t(){Browser.getUserMedia()},Module.createContext=function t(e,r,o,a){return Browser.createContext(e,r,o,a)},ENVIRONMENT_IS_NODE?_emscripten_get_now=function(){var e=process.hrtime();return e[0]*1e3+e[1]/1e6}:typeof dateNow<"u"?_emscripten_get_now=dateNow:typeof self=="object"&&self.performance&&typeof self.performance.now=="function"?_emscripten_get_now=function(){return self.performance.now()}:typeof performance=="object"&&typeof performance.now=="function"?_emscripten_get_now=function(){return performance.now()}:_emscripten_get_now=Date.now,__ATEXIT__.push(function(){var t=Module._fflush;t&&t(0);var e=___syscall146.printChar;if(!!e){var r=___syscall146.buffers;r[1].length&&e(1,10),r[2].length&&e(2,10)}}),DYNAMICTOP_PTR=allocate(1,"i32",ALLOC_STATIC),STACK_BASE=STACKTOP=Runtime.alignMemory(STATICTOP),STACK_MAX=STACK_BASE+TOTAL_STACK,DYNAMIC_BASE=Runtime.alignMemory(STACK_MAX),HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE,staticSealed=!0;function invoke_viiiii(t,e,r,o,a,n){try{Module.dynCall_viiiii(t,e,r,o,a,n)}catch(u){if(typeof u!="number"&&u!=="longjmp")throw u;Module.setThrew(1,0)}}function invoke_vif(t,e,r){try{Module.dynCall_vif(t,e,r)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_vid(t,e,r){try{Module.dynCall_vid(t,e,r)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_fiff(t,e,r,o){try{return Module.dynCall_fiff(t,e,r,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_vi(t,e){try{Module.dynCall_vi(t,e)}catch(r){if(typeof r!="number"&&r!=="longjmp")throw r;Module.setThrew(1,0)}}function invoke_vii(t,e,r){try{Module.dynCall_vii(t,e,r)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_ii(t,e){try{return Module.dynCall_ii(t,e)}catch(r){if(typeof r!="number"&&r!=="longjmp")throw r;Module.setThrew(1,0)}}function invoke_viddi(t,e,r,o,a){try{Module.dynCall_viddi(t,e,r,o,a)}catch(n){if(typeof n!="number"&&n!=="longjmp")throw n;Module.setThrew(1,0)}}function invoke_vidd(t,e,r,o){try{Module.dynCall_vidd(t,e,r,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_iiii(t,e,r,o){try{return Module.dynCall_iiii(t,e,r,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_diii(t,e,r,o){try{return Module.dynCall_diii(t,e,r,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_di(t,e){try{return Module.dynCall_di(t,e)}catch(r){if(typeof r!="number"&&r!=="longjmp")throw r;Module.setThrew(1,0)}}function invoke_iid(t,e,r){try{return Module.dynCall_iid(t,e,r)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_iii(t,e,r){try{return Module.dynCall_iii(t,e,r)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_viiddi(t,e,r,o,a,n){try{Module.dynCall_viiddi(t,e,r,o,a,n)}catch(u){if(typeof u!="number"&&u!=="longjmp")throw u;Module.setThrew(1,0)}}function invoke_viiiiii(t,e,r,o,a,n,u){try{Module.dynCall_viiiiii(t,e,r,o,a,n,u)}catch(A){if(typeof A!="number"&&A!=="longjmp")throw A;Module.setThrew(1,0)}}function invoke_dii(t,e,r){try{return Module.dynCall_dii(t,e,r)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_i(t){try{return Module.dynCall_i(t)}catch(e){if(typeof e!="number"&&e!=="longjmp")throw e;Module.setThrew(1,0)}}function invoke_iiiiii(t,e,r,o,a,n){try{return Module.dynCall_iiiiii(t,e,r,o,a,n)}catch(u){if(typeof u!="number"&&u!=="longjmp")throw u;Module.setThrew(1,0)}}function invoke_viiid(t,e,r,o,a){try{Module.dynCall_viiid(t,e,r,o,a)}catch(n){if(typeof n!="number"&&n!=="longjmp")throw n;Module.setThrew(1,0)}}function invoke_viififi(t,e,r,o,a,n,u){try{Module.dynCall_viififi(t,e,r,o,a,n,u)}catch(A){if(typeof A!="number"&&A!=="longjmp")throw A;Module.setThrew(1,0)}}function invoke_viii(t,e,r,o){try{Module.dynCall_viii(t,e,r,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_v(t){try{Module.dynCall_v(t)}catch(e){if(typeof e!="number"&&e!=="longjmp")throw e;Module.setThrew(1,0)}}function invoke_viid(t,e,r,o){try{Module.dynCall_viid(t,e,r,o)}catch(a){if(typeof a!="number"&&a!=="longjmp")throw a;Module.setThrew(1,0)}}function invoke_idd(t,e,r){try{return Module.dynCall_idd(t,e,r)}catch(o){if(typeof o!="number"&&o!=="longjmp")throw o;Module.setThrew(1,0)}}function invoke_viiii(t,e,r,o,a){try{Module.dynCall_viiii(t,e,r,o,a)}catch(n){if(typeof n!="number"&&n!=="longjmp")throw n;Module.setThrew(1,0)}}Module.asmGlobalArg={Math,Int8Array,Int16Array,Int32Array,Uint8Array,Uint16Array,Uint32Array,Float32Array,Float64Array,NaN:NaN,Infinity:1/0},Module.asmLibraryArg={abort,assert,enlargeMemory,getTotalMemory,abortOnCannotGrowMemory,invoke_viiiii,invoke_vif,invoke_vid,invoke_fiff,invoke_vi,invoke_vii,invoke_ii,invoke_viddi,invoke_vidd,invoke_iiii,invoke_diii,invoke_di,invoke_iid,invoke_iii,invoke_viiddi,invoke_viiiiii,invoke_dii,invoke_i,invoke_iiiiii,invoke_viiid,invoke_viififi,invoke_viii,invoke_v,invoke_viid,invoke_idd,invoke_viiii,_emscripten_asm_const_iiiii,_emscripten_asm_const_iiidddddd,_emscripten_asm_const_iiiid,__nbind_reference_external,_emscripten_asm_const_iiiiiiii,_removeAccessorPrefix,_typeModule,__nbind_register_pool,__decorate,_llvm_stackrestore,___cxa_atexit,__extends,__nbind_get_value_object,__ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj,_emscripten_set_main_loop_timing,__nbind_register_primitive,__nbind_register_type,_emscripten_memcpy_big,__nbind_register_function,___setErrNo,__nbind_register_class,__nbind_finish,_abort,_nbind_value,_llvm_stacksave,___syscall54,_defineHidden,_emscripten_set_main_loop,_emscripten_get_now,__nbind_register_callback_signature,_emscripten_asm_const_iiiiii,__nbind_free_external,_emscripten_asm_const_iiii,_emscripten_asm_const_iiididi,___syscall6,_atexit,___syscall140,___syscall146,DYNAMICTOP_PTR,tempDoublePtr,ABORT,STACKTOP,STACK_MAX,cttz_i8,___dso_handle};var asm=function(t,e,r){var o=new t.Int8Array(r),a=new t.Int16Array(r),n=new t.Int32Array(r),u=new t.Uint8Array(r),A=new t.Uint16Array(r),p=new t.Uint32Array(r),h=new t.Float32Array(r),E=new t.Float64Array(r),I=e.DYNAMICTOP_PTR|0,v=e.tempDoublePtr|0,x=e.ABORT|0,C=e.STACKTOP|0,R=e.STACK_MAX|0,N=e.cttz_i8|0,U=e.___dso_handle|0,V=0,te=0,ae=0,fe=0,ue=t.NaN,me=t.Infinity,he=0,Be=0,we=0,g=0,Ee=0,Pe=0,ce=t.Math.floor,ne=t.Math.abs,ee=t.Math.sqrt,Ie=t.Math.pow,Fe=t.Math.cos,At=t.Math.sin,H=t.Math.tan,at=t.Math.acos,Re=t.Math.asin,ke=t.Math.atan,xe=t.Math.atan2,He=t.Math.exp,Te=t.Math.log,Ve=t.Math.ceil,qe=t.Math.imul,b=t.Math.min,w=t.Math.max,S=t.Math.clz32,y=t.Math.fround,F=e.abort,J=e.assert,X=e.enlargeMemory,Z=e.getTotalMemory,ie=e.abortOnCannotGrowMemory,be=e.invoke_viiiii,Le=e.invoke_vif,ot=e.invoke_vid,dt=e.invoke_fiff,Gt=e.invoke_vi,$t=e.invoke_vii,bt=e.invoke_ii,an=e.invoke_viddi,Qr=e.invoke_vidd,mr=e.invoke_iiii,br=e.invoke_diii,Wr=e.invoke_di,Kn=e.invoke_iid,Ls=e.invoke_iii,Ti=e.invoke_viiddi,ps=e.invoke_viiiiii,io=e.invoke_dii,Si=e.invoke_i,Ns=e.invoke_iiiiii,so=e.invoke_viiid,uc=e.invoke_viififi,uu=e.invoke_viii,cp=e.invoke_v,up=e.invoke_viid,Os=e.invoke_idd,Dn=e.invoke_viiii,oo=e._emscripten_asm_const_iiiii,Ms=e._emscripten_asm_const_iiidddddd,yl=e._emscripten_asm_const_iiiid,El=e.__nbind_reference_external,ao=e._emscripten_asm_const_iiiiiiii,zn=e._removeAccessorPrefix,On=e._typeModule,Li=e.__nbind_register_pool,Mn=e.__decorate,_i=e._llvm_stackrestore,rr=e.___cxa_atexit,Oe=e.__extends,ii=e.__nbind_get_value_object,Ua=e.__ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj,hr=e._emscripten_set_main_loop_timing,Ac=e.__nbind_register_primitive,Au=e.__nbind_register_type,fc=e._emscripten_memcpy_big,Cl=e.__nbind_register_function,DA=e.___setErrNo,fu=e.__nbind_register_class,Ce=e.__nbind_finish,Rt=e._abort,pc=e._nbind_value,Hi=e._llvm_stacksave,pu=e.___syscall54,Yt=e._defineHidden,wl=e._emscripten_set_main_loop,PA=e._emscripten_get_now,Ap=e.__nbind_register_callback_signature,hc=e._emscripten_asm_const_iiiiii,SA=e.__nbind_free_external,Qn=e._emscripten_asm_const_iiii,hi=e._emscripten_asm_const_iiididi,gc=e.___syscall6,bA=e._atexit,sa=e.___syscall140,Ni=e.___syscall146,_o=y(0);let Ze=y(0);function lo(s){s=s|0;var l=0;return l=C,C=C+s|0,C=C+15&-16,l|0}function dc(){return C|0}function hu(s){s=s|0,C=s}function qi(s,l){s=s|0,l=l|0,C=s,R=l}function gu(s,l){s=s|0,l=l|0,V||(V=s,te=l)}function xA(s){s=s|0,Pe=s}function Ha(){return Pe|0}function mc(){var s=0,l=0;Dr(8104,8,400)|0,Dr(8504,408,540)|0,s=9044,l=s+44|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));o[9088]=0,o[9089]=1,n[2273]=0,n[2274]=948,n[2275]=948,rr(17,8104,U|0)|0}function hs(s){s=s|0,pt(s+948|0)}function Ht(s){return s=y(s),((Pu(s)|0)&2147483647)>>>0>2139095040|0}function Fn(s,l,c){s=s|0,l=l|0,c=c|0;e:do if(n[s+(l<<3)+4>>2]|0)s=s+(l<<3)|0;else{if((l|2|0)==3&&n[s+60>>2]|0){s=s+56|0;break}switch(l|0){case 0:case 2:case 4:case 5:{if(n[s+52>>2]|0){s=s+48|0;break e}break}default:}if(n[s+68>>2]|0){s=s+64|0;break}else{s=(l|1|0)==5?948:c;break}}while(0);return s|0}function Ci(s){s=s|0;var l=0;return l=pD(1e3)|0,oa(s,(l|0)!=0,2456),n[2276]=(n[2276]|0)+1,Dr(l|0,8104,1e3)|0,o[s+2>>0]|0&&(n[l+4>>2]=2,n[l+12>>2]=4),n[l+976>>2]=s,l|0}function oa(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;d=C,C=C+16|0,f=d,l||(n[f>>2]=c,Cg(s,5,3197,f)),C=d}function co(){return Ci(956)|0}function Us(s){s=s|0;var l=0;return l=Kt(1e3)|0,aa(l,s),oa(n[s+976>>2]|0,1,2456),n[2276]=(n[2276]|0)+1,n[l+944>>2]=0,l|0}function aa(s,l){s=s|0,l=l|0;var c=0;Dr(s|0,l|0,948)|0,Rm(s+948|0,l+948|0),c=s+960|0,s=l+960|0,l=c+40|0;do n[c>>2]=n[s>>2],c=c+4|0,s=s+4|0;while((c|0)<(l|0))}function la(s){s=s|0;var l=0,c=0,f=0,d=0;if(l=s+944|0,c=n[l>>2]|0,c|0&&(Ho(c+948|0,s)|0,n[l>>2]=0),c=wi(s)|0,c|0){l=0;do n[(gs(s,l)|0)+944>>2]=0,l=l+1|0;while((l|0)!=(c|0))}c=s+948|0,f=n[c>>2]|0,d=s+952|0,l=n[d>>2]|0,(l|0)!=(f|0)&&(n[d>>2]=l+(~((l+-4-f|0)>>>2)<<2)),ds(c),hD(s),n[2276]=(n[2276]|0)+-1}function Ho(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0;f=n[s>>2]|0,k=s+4|0,c=n[k>>2]|0,m=c;e:do if((f|0)==(c|0))d=f,B=4;else for(s=f;;){if((n[s>>2]|0)==(l|0)){d=s,B=4;break e}if(s=s+4|0,(s|0)==(c|0)){s=0;break}}while(0);return(B|0)==4&&((d|0)!=(c|0)?(f=d+4|0,s=m-f|0,l=s>>2,l&&(Mw(d|0,f|0,s|0)|0,c=n[k>>2]|0),s=d+(l<<2)|0,(c|0)==(s|0)||(n[k>>2]=c+(~((c+-4-s|0)>>>2)<<2)),s=1):s=0),s|0}function wi(s){return s=s|0,(n[s+952>>2]|0)-(n[s+948>>2]|0)>>2|0}function gs(s,l){s=s|0,l=l|0;var c=0;return c=n[s+948>>2]|0,(n[s+952>>2]|0)-c>>2>>>0>l>>>0?s=n[c+(l<<2)>>2]|0:s=0,s|0}function ds(s){s=s|0;var l=0,c=0,f=0,d=0;f=C,C=C+32|0,l=f,d=n[s>>2]|0,c=(n[s+4>>2]|0)-d|0,((n[s+8>>2]|0)-d|0)>>>0>c>>>0&&(d=c>>2,Bp(l,d,d,s+8|0),vg(s,l),_A(l)),C=f}function ms(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0;M=wi(s)|0;do if(M|0){if((n[(gs(s,0)|0)+944>>2]|0)==(s|0)){if(!(Ho(s+948|0,l)|0))break;Dr(l+400|0,8504,540)|0,n[l+944>>2]=0,Ne(s);break}B=n[(n[s+976>>2]|0)+12>>2]|0,k=s+948|0,Q=(B|0)==0,c=0,m=0;do f=n[(n[k>>2]|0)+(m<<2)>>2]|0,(f|0)==(l|0)?Ne(s):(d=Us(f)|0,n[(n[k>>2]|0)+(c<<2)>>2]=d,n[d+944>>2]=s,Q||TR[B&15](f,d,s,c),c=c+1|0),m=m+1|0;while((m|0)!=(M|0));if(c>>>0<M>>>0){Q=s+948|0,k=s+952|0,B=c,c=n[k>>2]|0;do m=(n[Q>>2]|0)+(B<<2)|0,f=m+4|0,d=c-f|0,l=d>>2,l&&(Mw(m|0,f|0,d|0)|0,c=n[k>>2]|0),d=c,f=m+(l<<2)|0,(d|0)!=(f|0)&&(c=d+(~((d+-4-f|0)>>>2)<<2)|0,n[k>>2]=c),B=B+1|0;while((B|0)!=(M|0))}}while(0)}function _s(s){s=s|0;var l=0,c=0,f=0,d=0;Un(s,(wi(s)|0)==0,2491),Un(s,(n[s+944>>2]|0)==0,2545),l=s+948|0,c=n[l>>2]|0,f=s+952|0,d=n[f>>2]|0,(d|0)!=(c|0)&&(n[f>>2]=d+(~((d+-4-c|0)>>>2)<<2)),ds(l),l=s+976|0,c=n[l>>2]|0,Dr(s|0,8104,1e3)|0,o[c+2>>0]|0&&(n[s+4>>2]=2,n[s+12>>2]=4),n[l>>2]=c}function Un(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;d=C,C=C+16|0,f=d,l||(n[f>>2]=c,Ao(s,5,3197,f)),C=d}function Pn(){return n[2276]|0}function ys(){var s=0;return s=pD(20)|0,We((s|0)!=0,2592),n[2277]=(n[2277]|0)+1,n[s>>2]=n[239],n[s+4>>2]=n[240],n[s+8>>2]=n[241],n[s+12>>2]=n[242],n[s+16>>2]=n[243],s|0}function We(s,l){s=s|0,l=l|0;var c=0,f=0;f=C,C=C+16|0,c=f,s||(n[c>>2]=l,Ao(0,5,3197,c)),C=f}function tt(s){s=s|0,hD(s),n[2277]=(n[2277]|0)+-1}function It(s,l){s=s|0,l=l|0;var c=0;l?(Un(s,(wi(s)|0)==0,2629),c=1):(c=0,l=0),n[s+964>>2]=l,n[s+988>>2]=c}function ir(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,m=f+8|0,d=f+4|0,B=f,n[d>>2]=l,Un(s,(n[l+944>>2]|0)==0,2709),Un(s,(n[s+964>>2]|0)==0,2763),$(s),l=s+948|0,n[B>>2]=(n[l>>2]|0)+(c<<2),n[m>>2]=n[B>>2],ye(l,m,d)|0,n[(n[d>>2]|0)+944>>2]=s,Ne(s),C=f}function $(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;if(c=wi(s)|0,c|0&&(n[(gs(s,0)|0)+944>>2]|0)!=(s|0)){f=n[(n[s+976>>2]|0)+12>>2]|0,d=s+948|0,m=(f|0)==0,l=0;do B=n[(n[d>>2]|0)+(l<<2)>>2]|0,k=Us(B)|0,n[(n[d>>2]|0)+(l<<2)>>2]=k,n[k+944>>2]=s,m||TR[f&15](B,k,s,l),l=l+1|0;while((l|0)!=(c|0))}}function ye(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0,et=0,Xe=0;et=C,C=C+64|0,G=et+52|0,k=et+48|0,se=et+28|0,je=et+24|0,Me=et+20|0,Qe=et,f=n[s>>2]|0,m=f,l=f+((n[l>>2]|0)-m>>2<<2)|0,f=s+4|0,d=n[f>>2]|0,B=s+8|0;do if(d>>>0<(n[B>>2]|0)>>>0){if((l|0)==(d|0)){n[l>>2]=n[c>>2],n[f>>2]=(n[f>>2]|0)+4;break}HA(s,l,d,l+4|0),l>>>0<=c>>>0&&(c=(n[f>>2]|0)>>>0>c>>>0?c+4|0:c),n[l>>2]=n[c>>2]}else{f=(d-m>>2)+1|0,d=L(s)|0,d>>>0<f>>>0&&Jr(s),O=n[s>>2]|0,M=(n[B>>2]|0)-O|0,m=M>>1,Bp(Qe,M>>2>>>0<d>>>1>>>0?m>>>0<f>>>0?f:m:d,l-O>>2,s+8|0),O=Qe+8|0,f=n[O>>2]|0,m=Qe+12|0,M=n[m>>2]|0,B=M,Q=f;do if((f|0)==(M|0)){if(M=Qe+4|0,f=n[M>>2]|0,Xe=n[Qe>>2]|0,d=Xe,f>>>0<=Xe>>>0){f=B-d>>1,f=(f|0)==0?1:f,Bp(se,f,f>>>2,n[Qe+16>>2]|0),n[je>>2]=n[M>>2],n[Me>>2]=n[O>>2],n[k>>2]=n[je>>2],n[G>>2]=n[Me>>2],Dw(se,k,G),f=n[Qe>>2]|0,n[Qe>>2]=n[se>>2],n[se>>2]=f,f=se+4|0,Xe=n[M>>2]|0,n[M>>2]=n[f>>2],n[f>>2]=Xe,f=se+8|0,Xe=n[O>>2]|0,n[O>>2]=n[f>>2],n[f>>2]=Xe,f=se+12|0,Xe=n[m>>2]|0,n[m>>2]=n[f>>2],n[f>>2]=Xe,_A(se),f=n[O>>2]|0;break}m=f,B=((m-d>>2)+1|0)/-2|0,k=f+(B<<2)|0,d=Q-m|0,m=d>>2,m&&(Mw(k|0,f|0,d|0)|0,f=n[M>>2]|0),Xe=k+(m<<2)|0,n[O>>2]=Xe,n[M>>2]=f+(B<<2),f=Xe}while(0);n[f>>2]=n[c>>2],n[O>>2]=(n[O>>2]|0)+4,l=Dg(s,Qe,l)|0,_A(Qe)}while(0);return C=et,l|0}function Ne(s){s=s|0;var l=0;do{if(l=s+984|0,o[l>>0]|0)break;o[l>>0]=1,h[s+504>>2]=y(ue),s=n[s+944>>2]|0}while((s|0)!=0)}function pt(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-4-f|0)>>>2)<<2)),gt(c))}function ht(s){return s=s|0,n[s+944>>2]|0}function Tt(s){s=s|0,Un(s,(n[s+964>>2]|0)!=0,2832),Ne(s)}function er(s){return s=s|0,(o[s+984>>0]|0)!=0|0}function $r(s,l){s=s|0,l=l|0,FUe(s,l,400)|0&&(Dr(s|0,l|0,400)|0,Ne(s))}function Gi(s){s=s|0;var l=Ze;return l=y(h[s+44>>2]),s=Ht(l)|0,y(s?y(0):l)}function es(s){s=s|0;var l=Ze;return l=y(h[s+48>>2]),Ht(l)|0&&(l=o[(n[s+976>>2]|0)+2>>0]|0?y(1):y(0)),y(l)}function bi(s,l){s=s|0,l=l|0,n[s+980>>2]=l}function qo(s){return s=s|0,n[s+980>>2]|0}function kA(s,l){s=s|0,l=l|0;var c=0;c=s+4|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function QA(s){return s=s|0,n[s+4>>2]|0}function fp(s,l){s=s|0,l=l|0;var c=0;c=s+8|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function sg(s){return s=s|0,n[s+8>>2]|0}function du(s,l){s=s|0,l=l|0;var c=0;c=s+12|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function og(s){return s=s|0,n[s+12>>2]|0}function mu(s,l){s=s|0,l=l|0;var c=0;c=s+16|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function uo(s){return s=s|0,n[s+16>>2]|0}function FA(s,l){s=s|0,l=l|0;var c=0;c=s+20|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function yc(s){return s=s|0,n[s+20>>2]|0}function ca(s,l){s=s|0,l=l|0;var c=0;c=s+24|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function ag(s){return s=s|0,n[s+24>>2]|0}function Ec(s,l){s=s|0,l=l|0;var c=0;c=s+28|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function Sm(s){return s=s|0,n[s+28>>2]|0}function lg(s,l){s=s|0,l=l|0;var c=0;c=s+32|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function ei(s){return s=s|0,n[s+32>>2]|0}function pp(s,l){s=s|0,l=l|0;var c=0;c=s+36|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function cg(s){return s=s|0,n[s+36>>2]|0}function RA(s,l){s=s|0,l=y(l);var c=0;c=s+40|0,y(h[c>>2])!=l&&(h[c>>2]=l,Ne(s))}function Hs(s,l){s=s|0,l=y(l);var c=0;c=s+44|0,y(h[c>>2])!=l&&(h[c>>2]=l,Ne(s))}function yu(s,l){s=s|0,l=y(l);var c=0;c=s+48|0,y(h[c>>2])!=l&&(h[c>>2]=l,Ne(s))}function qa(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=(m^1)&1,f=s+52|0,d=s+56|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function ji(s,l){s=s|0,l=y(l);var c=0,f=0;f=s+52|0,c=s+56|0,y(h[f>>2])==l&&(n[c>>2]|0)==2||(h[f>>2]=l,f=Ht(l)|0,n[c>>2]=f?3:2,Ne(s))}function ua(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+52|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Eu(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=Ht(c)|0,f=(m^1)&1,d=s+132+(l<<3)|0,l=s+132+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Ne(s))}function Es(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=Ht(c)|0,f=m?0:2,d=s+132+(l<<3)|0,l=s+132+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Ne(s))}function Cc(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=l+132+(c<<3)|0,l=n[f+4>>2]|0,c=s,n[c>>2]=n[f>>2],n[c+4>>2]=l}function wc(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=Ht(c)|0,f=(m^1)&1,d=s+60+(l<<3)|0,l=s+60+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Ne(s))}function j(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=Ht(c)|0,f=m?0:2,d=s+60+(l<<3)|0,l=s+60+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Ne(s))}function Dt(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=l+60+(c<<3)|0,l=n[f+4>>2]|0,c=s,n[c>>2]=n[f>>2],n[c+4>>2]=l}function Il(s,l){s=s|0,l=l|0;var c=0;c=s+60+(l<<3)+4|0,(n[c>>2]|0)!=3&&(h[s+60+(l<<3)>>2]=y(ue),n[c>>2]=3,Ne(s))}function xi(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=Ht(c)|0,f=(m^1)&1,d=s+204+(l<<3)|0,l=s+204+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Ne(s))}function Ic(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=Ht(c)|0,f=m?0:2,d=s+204+(l<<3)|0,l=s+204+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Ne(s))}function ct(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=l+204+(c<<3)|0,l=n[f+4>>2]|0,c=s,n[c>>2]=n[f>>2],n[c+4>>2]=l}function Cu(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=Ht(c)|0,f=(m^1)&1,d=s+276+(l<<3)|0,l=s+276+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Ne(s))}function ug(s,l){return s=s|0,l=l|0,y(h[s+276+(l<<3)>>2])}function yw(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=(m^1)&1,f=s+348|0,d=s+352|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function TA(s,l){s=s|0,l=y(l);var c=0,f=0;f=s+348|0,c=s+352|0,y(h[f>>2])==l&&(n[c>>2]|0)==2||(h[f>>2]=l,f=Ht(l)|0,n[c>>2]=f?3:2,Ne(s))}function hp(s){s=s|0;var l=0;l=s+352|0,(n[l>>2]|0)!=3&&(h[s+348>>2]=y(ue),n[l>>2]=3,Ne(s))}function Br(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+348|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Cs(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=(m^1)&1,f=s+356|0,d=s+360|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function Ag(s,l){s=s|0,l=y(l);var c=0,f=0;f=s+356|0,c=s+360|0,y(h[f>>2])==l&&(n[c>>2]|0)==2||(h[f>>2]=l,f=Ht(l)|0,n[c>>2]=f?3:2,Ne(s))}function fg(s){s=s|0;var l=0;l=s+360|0,(n[l>>2]|0)!=3&&(h[s+356>>2]=y(ue),n[l>>2]=3,Ne(s))}function pg(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+356|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function gp(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=(m^1)&1,f=s+364|0,d=s+368|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function Bc(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=m?0:2,f=s+364|0,d=s+368|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function Ct(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+364|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function bm(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=(m^1)&1,f=s+372|0,d=s+376|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function hg(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=m?0:2,f=s+372|0,d=s+376|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function gg(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+372|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function wu(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=(m^1)&1,f=s+380|0,d=s+384|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function xm(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=m?0:2,f=s+380|0,d=s+384|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function dg(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+380|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Iu(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=(m^1)&1,f=s+388|0,d=s+392|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function Ew(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=m?0:2,f=s+388|0,d=s+392|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function km(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+388|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Aa(s,l){s=s|0,l=y(l);var c=0;c=s+396|0,y(h[c>>2])!=l&&(h[c>>2]=l,Ne(s))}function vc(s){return s=s|0,y(h[s+396>>2])}function Bl(s){return s=s|0,y(h[s+400>>2])}function Bu(s){return s=s|0,y(h[s+404>>2])}function mg(s){return s=s|0,y(h[s+408>>2])}function LA(s){return s=s|0,y(h[s+412>>2])}function dp(s){return s=s|0,y(h[s+416>>2])}function Ga(s){return s=s|0,y(h[s+420>>2])}function yg(s,l){switch(s=s|0,l=l|0,Un(s,(l|0)<6,2918),l|0){case 0:{l=(n[s+496>>2]|0)==2?5:4;break}case 2:{l=(n[s+496>>2]|0)==2?4:5;break}default:}return y(h[s+424+(l<<2)>>2])}function mp(s,l){switch(s=s|0,l=l|0,Un(s,(l|0)<6,2918),l|0){case 0:{l=(n[s+496>>2]|0)==2?5:4;break}case 2:{l=(n[s+496>>2]|0)==2?4:5;break}default:}return y(h[s+448+(l<<2)>>2])}function Go(s,l){switch(s=s|0,l=l|0,Un(s,(l|0)<6,2918),l|0){case 0:{l=(n[s+496>>2]|0)==2?5:4;break}case 2:{l=(n[s+496>>2]|0)==2?4:5;break}default:}return y(h[s+472+(l<<2)>>2])}function ws(s,l){s=s|0,l=l|0;var c=0,f=Ze;return c=n[s+4>>2]|0,(c|0)==(n[l+4>>2]|0)?c?(f=y(h[s>>2]),s=y(ne(y(f-y(h[l>>2]))))<y(999999974e-13)):s=1:s=0,s|0}function Ii(s,l){s=y(s),l=y(l);var c=0;return Ht(s)|0?c=Ht(l)|0:c=y(ne(y(s-l)))<y(999999974e-13),c|0}function Qm(s,l){s=s|0,l=l|0,Fm(s,l)}function Fm(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c+4|0,n[f>>2]=0,n[f+4>>2]=0,n[f+8>>2]=0,Ua(f|0,s|0,l|0,0),Ao(s,3,(o[f+11>>0]|0)<0?n[f>>2]|0:f,c),t3e(f),C=c}function jo(s,l,c,f){s=y(s),l=y(l),c=c|0,f=f|0;var d=Ze;s=y(s*l),d=y(bR(s,y(1)));do if(Ii(d,y(0))|0)s=y(s-d);else{if(s=y(s-d),Ii(d,y(1))|0){s=y(s+y(1));break}if(c){s=y(s+y(1));break}f||(d>y(.5)?d=y(1):(f=Ii(d,y(.5))|0,d=y(f?1:0)),s=y(s+d))}while(0);return y(s/l)}function NA(s,l,c,f,d,m,B,k,Q,M,O,G,se){s=s|0,l=y(l),c=c|0,f=y(f),d=d|0,m=y(m),B=B|0,k=y(k),Q=y(Q),M=y(M),O=y(O),G=y(G),se=se|0;var je=0,Me=Ze,Qe=Ze,et=Ze,Xe=Ze,lt=Ze,Ue=Ze;return Q<y(0)|M<y(0)?se=0:((se|0)!=0&&(Me=y(h[se+4>>2]),Me!=y(0))?(et=y(jo(l,Me,0,0)),Xe=y(jo(f,Me,0,0)),Qe=y(jo(m,Me,0,0)),Me=y(jo(k,Me,0,0))):(Qe=m,et=l,Me=k,Xe=f),(d|0)==(s|0)?je=Ii(Qe,et)|0:je=0,(B|0)==(c|0)?se=Ii(Me,Xe)|0:se=0,!je&&(lt=y(l-O),!(yp(s,lt,Q)|0))&&!(Ep(s,lt,d,Q)|0)?je=Eg(s,lt,d,m,Q)|0:je=1,!se&&(Ue=y(f-G),!(yp(c,Ue,M)|0))&&!(Ep(c,Ue,B,M)|0)?se=Eg(c,Ue,B,k,M)|0:se=1,se=je&se),se|0}function yp(s,l,c){return s=s|0,l=y(l),c=y(c),(s|0)==1?s=Ii(l,c)|0:s=0,s|0}function Ep(s,l,c,f){return s=s|0,l=y(l),c=c|0,f=y(f),(s|0)==2&(c|0)==0?l>=f?s=1:s=Ii(l,f)|0:s=0,s|0}function Eg(s,l,c,f,d){return s=s|0,l=y(l),c=c|0,f=y(f),d=y(d),(s|0)==2&(c|0)==2&f>l?d<=l?s=1:s=Ii(l,d)|0:s=0,s|0}function fa(s,l,c,f,d,m,B,k,Q,M,O){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=m|0,B=y(B),k=y(k),Q=Q|0,M=M|0,O=O|0;var G=0,se=0,je=0,Me=0,Qe=Ze,et=Ze,Xe=0,lt=0,Ue=0,Ge=0,Nt=0,Mr=0,ar=0,Xt=0,Pr=0,Lr=0,sr=0,xn=Ze,go=Ze,mo=Ze,yo=0,ya=0;sr=C,C=C+160|0,Xt=sr+152|0,ar=sr+120|0,Mr=sr+104|0,Ue=sr+72|0,Me=sr+56|0,Nt=sr+8|0,lt=sr,Ge=(n[2279]|0)+1|0,n[2279]=Ge,Pr=s+984|0,(o[Pr>>0]|0)!=0&&(n[s+512>>2]|0)!=(n[2278]|0)?Xe=4:(n[s+516>>2]|0)==(f|0)?Lr=0:Xe=4,(Xe|0)==4&&(n[s+520>>2]=0,n[s+924>>2]=-1,n[s+928>>2]=-1,h[s+932>>2]=y(-1),h[s+936>>2]=y(-1),Lr=1);e:do if(n[s+964>>2]|0)if(Qe=y(ln(s,2,B)),et=y(ln(s,0,B)),G=s+916|0,mo=y(h[G>>2]),go=y(h[s+920>>2]),xn=y(h[s+932>>2]),NA(d,l,m,c,n[s+924>>2]|0,mo,n[s+928>>2]|0,go,xn,y(h[s+936>>2]),Qe,et,O)|0)Xe=22;else if(je=n[s+520>>2]|0,!je)Xe=21;else for(se=0;;){if(G=s+524+(se*24|0)|0,xn=y(h[G>>2]),go=y(h[s+524+(se*24|0)+4>>2]),mo=y(h[s+524+(se*24|0)+16>>2]),NA(d,l,m,c,n[s+524+(se*24|0)+8>>2]|0,xn,n[s+524+(se*24|0)+12>>2]|0,go,mo,y(h[s+524+(se*24|0)+20>>2]),Qe,et,O)|0){Xe=22;break e}if(se=se+1|0,se>>>0>=je>>>0){Xe=21;break}}else{if(Q){if(G=s+916|0,!(Ii(y(h[G>>2]),l)|0)){Xe=21;break}if(!(Ii(y(h[s+920>>2]),c)|0)){Xe=21;break}if((n[s+924>>2]|0)!=(d|0)){Xe=21;break}G=(n[s+928>>2]|0)==(m|0)?G:0,Xe=22;break}if(je=n[s+520>>2]|0,!je)Xe=21;else for(se=0;;){if(G=s+524+(se*24|0)|0,Ii(y(h[G>>2]),l)|0&&Ii(y(h[s+524+(se*24|0)+4>>2]),c)|0&&(n[s+524+(se*24|0)+8>>2]|0)==(d|0)&&(n[s+524+(se*24|0)+12>>2]|0)==(m|0)){Xe=22;break e}if(se=se+1|0,se>>>0>=je>>>0){Xe=21;break}}}while(0);do if((Xe|0)==21)o[11697]|0?(G=0,Xe=28):(G=0,Xe=31);else if((Xe|0)==22){if(se=(o[11697]|0)!=0,!((G|0)!=0&(Lr^1)))if(se){Xe=28;break}else{Xe=31;break}Me=G+16|0,n[s+908>>2]=n[Me>>2],je=G+20|0,n[s+912>>2]=n[je>>2],(o[11698]|0)==0|se^1||(n[lt>>2]=OA(Ge)|0,n[lt+4>>2]=Ge,Ao(s,4,2972,lt),se=n[s+972>>2]|0,se|0&&tf[se&127](s),d=ja(d,Q)|0,m=ja(m,Q)|0,ya=+y(h[Me>>2]),yo=+y(h[je>>2]),n[Nt>>2]=d,n[Nt+4>>2]=m,E[Nt+8>>3]=+l,E[Nt+16>>3]=+c,E[Nt+24>>3]=ya,E[Nt+32>>3]=yo,n[Nt+40>>2]=M,Ao(s,4,2989,Nt))}while(0);return(Xe|0)==28&&(se=OA(Ge)|0,n[Me>>2]=se,n[Me+4>>2]=Ge,n[Me+8>>2]=Lr?3047:11699,Ao(s,4,3038,Me),se=n[s+972>>2]|0,se|0&&tf[se&127](s),Nt=ja(d,Q)|0,Xe=ja(m,Q)|0,n[Ue>>2]=Nt,n[Ue+4>>2]=Xe,E[Ue+8>>3]=+l,E[Ue+16>>3]=+c,n[Ue+24>>2]=M,Ao(s,4,3049,Ue),Xe=31),(Xe|0)==31&&(si(s,l,c,f,d,m,B,k,Q,O),o[11697]|0&&(se=n[2279]|0,Nt=OA(se)|0,n[Mr>>2]=Nt,n[Mr+4>>2]=se,n[Mr+8>>2]=Lr?3047:11699,Ao(s,4,3083,Mr),se=n[s+972>>2]|0,se|0&&tf[se&127](s),Nt=ja(d,Q)|0,Mr=ja(m,Q)|0,yo=+y(h[s+908>>2]),ya=+y(h[s+912>>2]),n[ar>>2]=Nt,n[ar+4>>2]=Mr,E[ar+8>>3]=yo,E[ar+16>>3]=ya,n[ar+24>>2]=M,Ao(s,4,3092,ar)),n[s+516>>2]=f,G||(se=s+520|0,G=n[se>>2]|0,(G|0)==16&&(o[11697]|0&&Ao(s,4,3124,Xt),n[se>>2]=0,G=0),Q?G=s+916|0:(n[se>>2]=G+1,G=s+524+(G*24|0)|0),h[G>>2]=l,h[G+4>>2]=c,n[G+8>>2]=d,n[G+12>>2]=m,n[G+16>>2]=n[s+908>>2],n[G+20>>2]=n[s+912>>2],G=0)),Q&&(n[s+416>>2]=n[s+908>>2],n[s+420>>2]=n[s+912>>2],o[s+985>>0]=1,o[Pr>>0]=0),n[2279]=(n[2279]|0)+-1,n[s+512>>2]=n[2278],C=sr,Lr|(G|0)==0|0}function ln(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return f=y(K(s,l,c)),y(f+y(re(s,l,c)))}function Ao(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=C,C=C+16|0,d=m,n[d>>2]=f,s?f=n[s+976>>2]|0:f=0,wg(f,s,l,c,d),C=m}function OA(s){return s=s|0,(s>>>0>60?3201:3201+(60-s)|0)|0}function ja(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;return d=C,C=C+32|0,c=d+12|0,f=d,n[c>>2]=n[254],n[c+4>>2]=n[255],n[c+8>>2]=n[256],n[f>>2]=n[257],n[f+4>>2]=n[258],n[f+8>>2]=n[259],(s|0)>2?s=11699:s=n[(l?f:c)+(s<<2)>>2]|0,C=d,s|0}function si(s,l,c,f,d,m,B,k,Q,M){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=m|0,B=y(B),k=y(k),Q=Q|0,M=M|0;var O=0,G=0,se=0,je=0,Me=Ze,Qe=Ze,et=Ze,Xe=Ze,lt=Ze,Ue=Ze,Ge=Ze,Nt=0,Mr=0,ar=0,Xt=Ze,Pr=Ze,Lr=0,sr=Ze,xn=0,go=0,mo=0,yo=0,ya=0,Rp=0,Tp=0,xl=0,Lp=0,Ru=0,Tu=0,Np=0,Op=0,Mp=0,Xr=0,kl=0,Up=0,kc=0,_p=Ze,Hp=Ze,Lu=Ze,Nu=Ze,Qc=Ze,Gs=0,Xa=0,Wo=0,Ql=0,nf=0,sf=Ze,Ou=Ze,of=Ze,af=Ze,js=Ze,vs=Ze,Fl=0,Rn=Ze,lf=Ze,Eo=Ze,Fc=Ze,Co=Ze,Rc=Ze,cf=0,uf=0,Tc=Ze,Ys=Ze,Rl=0,Af=0,ff=0,pf=0,xr=Ze,Vn=0,Ds=0,wo=0,Ws=0,Rr=0,ur=0,Tl=0,Vt=Ze,hf=0,li=0;Tl=C,C=C+16|0,Gs=Tl+12|0,Xa=Tl+8|0,Wo=Tl+4|0,Ql=Tl,Un(s,(d|0)==0|(Ht(l)|0)^1,3326),Un(s,(m|0)==0|(Ht(c)|0)^1,3406),Ds=mt(s,f)|0,n[s+496>>2]=Ds,Rr=fr(2,Ds)|0,ur=fr(0,Ds)|0,h[s+440>>2]=y(K(s,Rr,B)),h[s+444>>2]=y(re(s,Rr,B)),h[s+428>>2]=y(K(s,ur,B)),h[s+436>>2]=y(re(s,ur,B)),h[s+464>>2]=y(Cr(s,Rr)),h[s+468>>2]=y(yn(s,Rr)),h[s+452>>2]=y(Cr(s,ur)),h[s+460>>2]=y(yn(s,ur)),h[s+488>>2]=y(oi(s,Rr,B)),h[s+492>>2]=y(Oi(s,Rr,B)),h[s+476>>2]=y(oi(s,ur,B)),h[s+484>>2]=y(Oi(s,ur,B));do if(n[s+964>>2]|0)Bg(s,l,c,d,m,B,k);else{if(wo=s+948|0,Ws=(n[s+952>>2]|0)-(n[wo>>2]|0)>>2,!Ws){jv(s,l,c,d,m,B,k);break}if(!Q&&Yv(s,l,c,d,m,B,k)|0)break;$(s),kl=s+508|0,o[kl>>0]=0,Rr=fr(n[s+4>>2]|0,Ds)|0,ur=ww(Rr,Ds)|0,Vn=pe(Rr)|0,Up=n[s+8>>2]|0,Af=s+28|0,kc=(n[Af>>2]|0)!=0,Co=Vn?B:k,Tc=Vn?k:B,_p=y(wp(s,Rr,B)),Hp=y(Iw(s,Rr,B)),Me=y(wp(s,ur,B)),Rc=y(En(s,Rr,B)),Ys=y(En(s,ur,B)),ar=Vn?d:m,Rl=Vn?m:d,xr=Vn?Rc:Ys,lt=Vn?Ys:Rc,Fc=y(ln(s,2,B)),Xe=y(ln(s,0,B)),Qe=y(y(jr(s+364|0,B))-xr),et=y(y(jr(s+380|0,B))-xr),Ue=y(y(jr(s+372|0,k))-lt),Ge=y(y(jr(s+388|0,k))-lt),Lu=Vn?Qe:Ue,Nu=Vn?et:Ge,Fc=y(l-Fc),l=y(Fc-xr),Ht(l)|0?xr=l:xr=y(_n(y(Lg(l,et)),Qe)),lf=y(c-Xe),l=y(lf-lt),Ht(l)|0?Eo=l:Eo=y(_n(y(Lg(l,Ge)),Ue)),Qe=Vn?xr:Eo,Rn=Vn?Eo:xr;e:do if((ar|0)==1)for(f=0,G=0;;){if(O=gs(s,G)|0,!f)y(rs(O))>y(0)&&y(qs(O))>y(0)?f=O:f=0;else if(Tm(O)|0){je=0;break e}if(G=G+1|0,G>>>0>=Ws>>>0){je=f;break}}else je=0;while(0);Nt=je+500|0,Mr=je+504|0,f=0,O=0,l=y(0),se=0;do{if(G=n[(n[wo>>2]|0)+(se<<2)>>2]|0,(n[G+36>>2]|0)==1)vu(G),o[G+985>>0]=1,o[G+984>>0]=0;else{vl(G),Q&&Cp(G,mt(G,Ds)|0,Qe,Rn,xr);do if((n[G+24>>2]|0)!=1)if((G|0)==(je|0)){n[Nt>>2]=n[2278],h[Mr>>2]=y(0);break}else{Lm(s,G,xr,d,Eo,xr,Eo,m,Ds,M);break}else O|0&&(n[O+960>>2]=G),n[G+960>>2]=0,O=G,f=(f|0)==0?G:f;while(0);vs=y(h[G+504>>2]),l=y(l+y(vs+y(ln(G,Rr,xr))))}se=se+1|0}while((se|0)!=(Ws|0));for(mo=l>Qe,Fl=kc&((ar|0)==2&mo)?1:ar,xn=(Rl|0)==1,ya=xn&(Q^1),Rp=(Fl|0)==1,Tp=(Fl|0)==2,xl=976+(Rr<<2)|0,Lp=(Rl|2|0)==2,Mp=xn&(kc^1),Ru=1040+(ur<<2)|0,Tu=1040+(Rr<<2)|0,Np=976+(ur<<2)|0,Op=(Rl|0)!=1,mo=kc&((ar|0)!=0&mo),go=s+976|0,xn=xn^1,l=Qe,Lr=0,yo=0,vs=y(0),Qc=y(0);;){e:do if(Lr>>>0<Ws>>>0)for(Mr=n[wo>>2]|0,se=0,Ge=y(0),Ue=y(0),et=y(0),Qe=y(0),G=0,O=0,je=Lr;;){if(Nt=n[Mr+(je<<2)>>2]|0,(n[Nt+36>>2]|0)!=1&&(n[Nt+940>>2]=yo,(n[Nt+24>>2]|0)!=1)){if(Xe=y(ln(Nt,Rr,xr)),Xr=n[xl>>2]|0,c=y(jr(Nt+380+(Xr<<3)|0,Co)),lt=y(h[Nt+504>>2]),c=y(Lg(c,lt)),c=y(_n(y(jr(Nt+364+(Xr<<3)|0,Co)),c)),kc&(se|0)!=0&y(Xe+y(Ue+c))>l){m=se,Xe=Ge,ar=je;break e}Xe=y(Xe+c),c=y(Ue+Xe),Xe=y(Ge+Xe),Tm(Nt)|0&&(et=y(et+y(rs(Nt))),Qe=y(Qe-y(lt*y(qs(Nt))))),O|0&&(n[O+960>>2]=Nt),n[Nt+960>>2]=0,se=se+1|0,O=Nt,G=(G|0)==0?Nt:G}else Xe=Ge,c=Ue;if(je=je+1|0,je>>>0<Ws>>>0)Ge=Xe,Ue=c;else{m=se,ar=je;break}}else m=0,Xe=y(0),et=y(0),Qe=y(0),G=0,ar=Lr;while(0);Xr=et>y(0)&et<y(1),Xt=Xr?y(1):et,Xr=Qe>y(0)&Qe<y(1),Ge=Xr?y(1):Qe;do if(Rp)Xr=51;else if(Xe<Lu&((Ht(Lu)|0)^1))l=Lu,Xr=51;else if(Xe>Nu&((Ht(Nu)|0)^1))l=Nu,Xr=51;else if(o[(n[go>>2]|0)+3>>0]|0)Xr=51;else{if(Xt!=y(0)&&y(rs(s))!=y(0)){Xr=53;break}l=Xe,Xr=53}while(0);if((Xr|0)==51&&(Xr=0,Ht(l)|0?Xr=53:(Pr=y(l-Xe),sr=l)),(Xr|0)==53&&(Xr=0,Xe<y(0)?(Pr=y(-Xe),sr=l):(Pr=y(0),sr=l)),!ya&&(nf=(G|0)==0,!nf)){se=n[xl>>2]|0,je=Pr<y(0),lt=y(Pr/Ge),Nt=Pr>y(0),Ue=y(Pr/Xt),et=y(0),Xe=y(0),l=y(0),O=G;do c=y(jr(O+380+(se<<3)|0,Co)),Qe=y(jr(O+364+(se<<3)|0,Co)),Qe=y(Lg(c,y(_n(Qe,y(h[O+504>>2]))))),je?(c=y(Qe*y(qs(O))),c!=y(-0)&&(Vt=y(Qe-y(lt*c)),sf=y(Bi(O,Rr,Vt,sr,xr)),Vt!=sf)&&(et=y(et-y(sf-Qe)),l=y(l+c))):Nt&&(Ou=y(rs(O)),Ou!=y(0))&&(Vt=y(Qe+y(Ue*Ou)),of=y(Bi(O,Rr,Vt,sr,xr)),Vt!=of)&&(et=y(et-y(of-Qe)),Xe=y(Xe-Ou)),O=n[O+960>>2]|0;while((O|0)!=0);if(l=y(Ge+l),Qe=y(Pr+et),nf)l=y(0);else{lt=y(Xt+Xe),je=n[xl>>2]|0,Nt=Qe<y(0),Mr=l==y(0),Ue=y(Qe/l),se=Qe>y(0),lt=y(Qe/lt),l=y(0);do{Vt=y(jr(G+380+(je<<3)|0,Co)),et=y(jr(G+364+(je<<3)|0,Co)),et=y(Lg(Vt,y(_n(et,y(h[G+504>>2]))))),Nt?(Vt=y(et*y(qs(G))),Qe=y(-Vt),Vt!=y(-0)?(Vt=y(Ue*Qe),Qe=y(Bi(G,Rr,y(et+(Mr?Qe:Vt)),sr,xr))):Qe=et):se&&(af=y(rs(G)),af!=y(0))?Qe=y(Bi(G,Rr,y(et+y(lt*af)),sr,xr)):Qe=et,l=y(l-y(Qe-et)),Xe=y(ln(G,Rr,xr)),c=y(ln(G,ur,xr)),Qe=y(Qe+Xe),h[Xa>>2]=Qe,n[Ql>>2]=1,et=y(h[G+396>>2]);e:do if(Ht(et)|0){O=Ht(Rn)|0;do if(!O){if(mo|(ts(G,ur,Rn)|0|xn)||(ha(s,G)|0)!=4||(n[(Dl(G,ur)|0)+4>>2]|0)==3||(n[(Sc(G,ur)|0)+4>>2]|0)==3)break;h[Gs>>2]=Rn,n[Wo>>2]=1;break e}while(0);if(ts(G,ur,Rn)|0){O=n[G+992+(n[Np>>2]<<2)>>2]|0,Vt=y(c+y(jr(O,Rn))),h[Gs>>2]=Vt,O=Op&(n[O+4>>2]|0)==2,n[Wo>>2]=((Ht(Vt)|0|O)^1)&1;break}else{h[Gs>>2]=Rn,n[Wo>>2]=O?0:2;break}}else Vt=y(Qe-Xe),Xt=y(Vt/et),Vt=y(et*Vt),n[Wo>>2]=1,h[Gs>>2]=y(c+(Vn?Xt:Vt));while(0);yr(G,Rr,sr,xr,Ql,Xa),yr(G,ur,Rn,xr,Wo,Gs);do if(!(ts(G,ur,Rn)|0)&&(ha(s,G)|0)==4){if((n[(Dl(G,ur)|0)+4>>2]|0)==3){O=0;break}O=(n[(Sc(G,ur)|0)+4>>2]|0)!=3}else O=0;while(0);Vt=y(h[Xa>>2]),Xt=y(h[Gs>>2]),hf=n[Ql>>2]|0,li=n[Wo>>2]|0,fa(G,Vn?Vt:Xt,Vn?Xt:Vt,Ds,Vn?hf:li,Vn?li:hf,xr,Eo,Q&(O^1),3488,M)|0,o[kl>>0]=o[kl>>0]|o[G+508>>0],G=n[G+960>>2]|0}while((G|0)!=0)}}else l=y(0);if(l=y(Pr+l),li=l<y(0)&1,o[kl>>0]=li|u[kl>>0],Tp&l>y(0)?(O=n[xl>>2]|0,(n[s+364+(O<<3)+4>>2]|0)!=0&&(js=y(jr(s+364+(O<<3)|0,Co)),js>=y(0))?Qe=y(_n(y(0),y(js-y(sr-l)))):Qe=y(0)):Qe=l,Nt=Lr>>>0<ar>>>0,Nt){je=n[wo>>2]|0,se=Lr,O=0;do G=n[je+(se<<2)>>2]|0,n[G+24>>2]|0||(O=((n[(Dl(G,Rr)|0)+4>>2]|0)==3&1)+O|0,O=O+((n[(Sc(G,Rr)|0)+4>>2]|0)==3&1)|0),se=se+1|0;while((se|0)!=(ar|0));O?(Xe=y(0),c=y(0)):Xr=101}else Xr=101;e:do if((Xr|0)==101)switch(Xr=0,Up|0){case 1:{O=0,Xe=y(Qe*y(.5)),c=y(0);break e}case 2:{O=0,Xe=Qe,c=y(0);break e}case 3:{if(m>>>0<=1){O=0,Xe=y(0),c=y(0);break e}c=y((m+-1|0)>>>0),O=0,Xe=y(0),c=y(y(_n(Qe,y(0)))/c);break e}case 5:{c=y(Qe/y((m+1|0)>>>0)),O=0,Xe=c;break e}case 4:{c=y(Qe/y(m>>>0)),O=0,Xe=y(c*y(.5));break e}default:{O=0,Xe=y(0),c=y(0);break e}}while(0);if(l=y(_p+Xe),Nt){et=y(Qe/y(O|0)),se=n[wo>>2]|0,G=Lr,Qe=y(0);do{O=n[se+(G<<2)>>2]|0;e:do if((n[O+36>>2]|0)!=1){switch(n[O+24>>2]|0){case 1:{if(gi(O,Rr)|0){if(!Q)break e;Vt=y(Or(O,Rr,sr)),Vt=y(Vt+y(Cr(s,Rr))),Vt=y(Vt+y(K(O,Rr,xr))),h[O+400+(n[Tu>>2]<<2)>>2]=Vt;break e}break}case 0:if(li=(n[(Dl(O,Rr)|0)+4>>2]|0)==3,Vt=y(et+l),l=li?Vt:l,Q&&(li=O+400+(n[Tu>>2]<<2)|0,h[li>>2]=y(l+y(h[li>>2]))),li=(n[(Sc(O,Rr)|0)+4>>2]|0)==3,Vt=y(et+l),l=li?Vt:l,ya){Vt=y(c+y(ln(O,Rr,xr))),Qe=Rn,l=y(l+y(Vt+y(h[O+504>>2])));break e}else{l=y(l+y(c+y(ns(O,Rr,xr)))),Qe=y(_n(Qe,y(ns(O,ur,xr))));break e}default:}Q&&(Vt=y(Xe+y(Cr(s,Rr))),li=O+400+(n[Tu>>2]<<2)|0,h[li>>2]=y(Vt+y(h[li>>2])))}while(0);G=G+1|0}while((G|0)!=(ar|0))}else Qe=y(0);if(c=y(Hp+l),Lp?Xe=y(y(Bi(s,ur,y(Ys+Qe),Tc,B))-Ys):Xe=Rn,et=y(y(Bi(s,ur,y(Ys+(Mp?Rn:Qe)),Tc,B))-Ys),Nt&Q){G=Lr;do{se=n[(n[wo>>2]|0)+(G<<2)>>2]|0;do if((n[se+36>>2]|0)!=1){if((n[se+24>>2]|0)==1){if(gi(se,ur)|0){if(Vt=y(Or(se,ur,Rn)),Vt=y(Vt+y(Cr(s,ur))),Vt=y(Vt+y(K(se,ur,xr))),O=n[Ru>>2]|0,h[se+400+(O<<2)>>2]=Vt,!(Ht(Vt)|0))break}else O=n[Ru>>2]|0;Vt=y(Cr(s,ur)),h[se+400+(O<<2)>>2]=y(Vt+y(K(se,ur,xr)));break}O=ha(s,se)|0;do if((O|0)==4){if((n[(Dl(se,ur)|0)+4>>2]|0)==3){Xr=139;break}if((n[(Sc(se,ur)|0)+4>>2]|0)==3){Xr=139;break}if(ts(se,ur,Rn)|0){l=Me;break}hf=n[se+908+(n[xl>>2]<<2)>>2]|0,n[Gs>>2]=hf,l=y(h[se+396>>2]),li=Ht(l)|0,Qe=(n[v>>2]=hf,y(h[v>>2])),li?l=et:(Pr=y(ln(se,ur,xr)),Vt=y(Qe/l),l=y(l*Qe),l=y(Pr+(Vn?Vt:l))),h[Xa>>2]=l,h[Gs>>2]=y(y(ln(se,Rr,xr))+Qe),n[Wo>>2]=1,n[Ql>>2]=1,yr(se,Rr,sr,xr,Wo,Gs),yr(se,ur,Rn,xr,Ql,Xa),l=y(h[Gs>>2]),Pr=y(h[Xa>>2]),Vt=Vn?l:Pr,l=Vn?Pr:l,li=((Ht(Vt)|0)^1)&1,fa(se,Vt,l,Ds,li,((Ht(l)|0)^1)&1,xr,Eo,1,3493,M)|0,l=Me}else Xr=139;while(0);e:do if((Xr|0)==139){Xr=0,l=y(Xe-y(ns(se,ur,xr)));do if((n[(Dl(se,ur)|0)+4>>2]|0)==3){if((n[(Sc(se,ur)|0)+4>>2]|0)!=3)break;l=y(Me+y(_n(y(0),y(l*y(.5)))));break e}while(0);if((n[(Sc(se,ur)|0)+4>>2]|0)==3){l=Me;break}if((n[(Dl(se,ur)|0)+4>>2]|0)==3){l=y(Me+y(_n(y(0),l)));break}switch(O|0){case 1:{l=Me;break e}case 2:{l=y(Me+y(l*y(.5)));break e}default:{l=y(Me+l);break e}}}while(0);Vt=y(vs+l),li=se+400+(n[Ru>>2]<<2)|0,h[li>>2]=y(Vt+y(h[li>>2]))}while(0);G=G+1|0}while((G|0)!=(ar|0))}if(vs=y(vs+et),Qc=y(_n(Qc,c)),m=yo+1|0,ar>>>0>=Ws>>>0)break;l=sr,Lr=ar,yo=m}do if(Q){if(O=m>>>0>1,!O&&!(Yi(s)|0))break;if(!(Ht(Rn)|0)){l=y(Rn-vs);e:do switch(n[s+12>>2]|0){case 3:{Me=y(Me+l),Ue=y(0);break}case 2:{Me=y(Me+y(l*y(.5))),Ue=y(0);break}case 4:{Rn>vs?Ue=y(l/y(m>>>0)):Ue=y(0);break}case 7:if(Rn>vs){Me=y(Me+y(l/y(m<<1>>>0))),Ue=y(l/y(m>>>0)),Ue=O?Ue:y(0);break e}else{Me=y(Me+y(l*y(.5))),Ue=y(0);break e}case 6:{Ue=y(l/y(yo>>>0)),Ue=Rn>vs&O?Ue:y(0);break}default:Ue=y(0)}while(0);if(m|0)for(Nt=1040+(ur<<2)|0,Mr=976+(ur<<2)|0,je=0,G=0;;){e:do if(G>>>0<Ws>>>0)for(Qe=y(0),et=y(0),l=y(0),se=G;;){O=n[(n[wo>>2]|0)+(se<<2)>>2]|0;do if((n[O+36>>2]|0)!=1&&(n[O+24>>2]|0)==0){if((n[O+940>>2]|0)!=(je|0))break e;if(Nm(O,ur)|0&&(Vt=y(h[O+908+(n[Mr>>2]<<2)>>2]),l=y(_n(l,y(Vt+y(ln(O,ur,xr)))))),(ha(s,O)|0)!=5)break;js=y(Wa(O)),js=y(js+y(K(O,0,xr))),Vt=y(h[O+912>>2]),Vt=y(y(Vt+y(ln(O,0,xr)))-js),js=y(_n(et,js)),Vt=y(_n(Qe,Vt)),Qe=Vt,et=js,l=y(_n(l,y(js+Vt)))}while(0);if(O=se+1|0,O>>>0<Ws>>>0)se=O;else{se=O;break}}else et=y(0),l=y(0),se=G;while(0);if(lt=y(Ue+l),c=Me,Me=y(Me+lt),G>>>0<se>>>0){Xe=y(c+et),O=G;do{G=n[(n[wo>>2]|0)+(O<<2)>>2]|0;e:do if((n[G+36>>2]|0)!=1&&(n[G+24>>2]|0)==0)switch(ha(s,G)|0){case 1:{Vt=y(c+y(K(G,ur,xr))),h[G+400+(n[Nt>>2]<<2)>>2]=Vt;break e}case 3:{Vt=y(y(Me-y(re(G,ur,xr)))-y(h[G+908+(n[Mr>>2]<<2)>>2])),h[G+400+(n[Nt>>2]<<2)>>2]=Vt;break e}case 2:{Vt=y(c+y(y(lt-y(h[G+908+(n[Mr>>2]<<2)>>2]))*y(.5))),h[G+400+(n[Nt>>2]<<2)>>2]=Vt;break e}case 4:{if(Vt=y(c+y(K(G,ur,xr))),h[G+400+(n[Nt>>2]<<2)>>2]=Vt,ts(G,ur,Rn)|0||(Vn?(Qe=y(h[G+908>>2]),l=y(Qe+y(ln(G,Rr,xr))),et=lt):(et=y(h[G+912>>2]),et=y(et+y(ln(G,ur,xr))),l=lt,Qe=y(h[G+908>>2])),Ii(l,Qe)|0&&Ii(et,y(h[G+912>>2]))|0))break e;fa(G,l,et,Ds,1,1,xr,Eo,1,3501,M)|0;break e}case 5:{h[G+404>>2]=y(y(Xe-y(Wa(G)))+y(Or(G,0,Rn)));break e}default:break e}while(0);O=O+1|0}while((O|0)!=(se|0))}if(je=je+1|0,(je|0)==(m|0))break;G=se}}}while(0);if(h[s+908>>2]=y(Bi(s,2,Fc,B,B)),h[s+912>>2]=y(Bi(s,0,lf,k,B)),(Fl|0)!=0&&(cf=n[s+32>>2]|0,uf=(Fl|0)==2,!(uf&(cf|0)!=2))?uf&(cf|0)==2&&(l=y(Rc+sr),l=y(_n(y(Lg(l,y(MA(s,Rr,Qc,Co)))),Rc)),Xr=198):(l=y(Bi(s,Rr,Qc,Co,B)),Xr=198),(Xr|0)==198&&(h[s+908+(n[976+(Rr<<2)>>2]<<2)>>2]=l),(Rl|0)!=0&&(ff=n[s+32>>2]|0,pf=(Rl|0)==2,!(pf&(ff|0)!=2))?pf&(ff|0)==2&&(l=y(Ys+Rn),l=y(_n(y(Lg(l,y(MA(s,ur,y(Ys+vs),Tc)))),Ys)),Xr=204):(l=y(Bi(s,ur,y(Ys+vs),Tc,B)),Xr=204),(Xr|0)==204&&(h[s+908+(n[976+(ur<<2)>>2]<<2)>>2]=l),Q){if((n[Af>>2]|0)==2){G=976+(ur<<2)|0,se=1040+(ur<<2)|0,O=0;do je=gs(s,O)|0,n[je+24>>2]|0||(hf=n[G>>2]|0,Vt=y(h[s+908+(hf<<2)>>2]),li=je+400+(n[se>>2]<<2)|0,Vt=y(Vt-y(h[li>>2])),h[li>>2]=y(Vt-y(h[je+908+(hf<<2)>>2]))),O=O+1|0;while((O|0)!=(Ws|0))}if(f|0){O=Vn?Fl:d;do Om(s,f,xr,O,Eo,Ds,M),f=n[f+960>>2]|0;while((f|0)!=0)}if(O=(Rr|2|0)==3,G=(ur|2|0)==3,O|G){f=0;do se=n[(n[wo>>2]|0)+(f<<2)>>2]|0,(n[se+36>>2]|0)!=1&&(O&&Ip(s,se,Rr),G&&Ip(s,se,ur)),f=f+1|0;while((f|0)!=(Ws|0))}}}while(0);C=Tl}function pa(s,l){s=s|0,l=y(l);var c=0;oa(s,l>=y(0),3147),c=l==y(0),h[s+4>>2]=c?y(0):l}function Dc(s,l,c,f){s=s|0,l=y(l),c=y(c),f=f|0;var d=Ze,m=Ze,B=0,k=0,Q=0;n[2278]=(n[2278]|0)+1,vl(s),ts(s,2,l)|0?(d=y(jr(n[s+992>>2]|0,l)),Q=1,d=y(d+y(ln(s,2,l)))):(d=y(jr(s+380|0,l)),d>=y(0)?Q=2:(Q=((Ht(l)|0)^1)&1,d=l)),ts(s,0,c)|0?(m=y(jr(n[s+996>>2]|0,c)),k=1,m=y(m+y(ln(s,0,l)))):(m=y(jr(s+388|0,c)),m>=y(0)?k=2:(k=((Ht(c)|0)^1)&1,m=c)),B=s+976|0,fa(s,d,m,f,Q,k,l,c,1,3189,n[B>>2]|0)|0&&(Cp(s,n[s+496>>2]|0,l,c,l),Pc(s,y(h[(n[B>>2]|0)+4>>2]),y(0),y(0)),o[11696]|0)&&Qm(s,7)}function vl(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;k=C,C=C+32|0,B=k+24|0,m=k+16|0,f=k+8|0,d=k,c=0;do l=s+380+(c<<3)|0,(n[s+380+(c<<3)+4>>2]|0)!=0&&(Q=l,M=n[Q+4>>2]|0,O=f,n[O>>2]=n[Q>>2],n[O+4>>2]=M,O=s+364+(c<<3)|0,M=n[O+4>>2]|0,Q=d,n[Q>>2]=n[O>>2],n[Q+4>>2]=M,n[m>>2]=n[f>>2],n[m+4>>2]=n[f+4>>2],n[B>>2]=n[d>>2],n[B+4>>2]=n[d+4>>2],ws(m,B)|0)||(l=s+348+(c<<3)|0),n[s+992+(c<<2)>>2]=l,c=c+1|0;while((c|0)!=2);C=k}function ts(s,l,c){s=s|0,l=l|0,c=y(c);var f=0;switch(s=n[s+992+(n[976+(l<<2)>>2]<<2)>>2]|0,n[s+4>>2]|0){case 0:case 3:{s=0;break}case 1:{y(h[s>>2])<y(0)?s=0:f=5;break}case 2:{y(h[s>>2])<y(0)?s=0:s=(Ht(c)|0)^1;break}default:f=5}return(f|0)==5&&(s=1),s|0}function jr(s,l){switch(s=s|0,l=y(l),n[s+4>>2]|0){case 2:{l=y(y(y(h[s>>2])*l)/y(100));break}case 1:{l=y(h[s>>2]);break}default:l=y(ue)}return y(l)}function Cp(s,l,c,f,d){s=s|0,l=l|0,c=y(c),f=y(f),d=y(d);var m=0,B=Ze;l=n[s+944>>2]|0?l:1,m=fr(n[s+4>>2]|0,l)|0,l=ww(m,l)|0,c=y(Mm(s,m,c)),f=y(Mm(s,l,f)),B=y(c+y(K(s,m,d))),h[s+400+(n[1040+(m<<2)>>2]<<2)>>2]=B,c=y(c+y(re(s,m,d))),h[s+400+(n[1e3+(m<<2)>>2]<<2)>>2]=c,c=y(f+y(K(s,l,d))),h[s+400+(n[1040+(l<<2)>>2]<<2)>>2]=c,d=y(f+y(re(s,l,d))),h[s+400+(n[1e3+(l<<2)>>2]<<2)>>2]=d}function Pc(s,l,c,f){s=s|0,l=y(l),c=y(c),f=y(f);var d=0,m=0,B=Ze,k=Ze,Q=0,M=0,O=Ze,G=0,se=Ze,je=Ze,Me=Ze,Qe=Ze;if(l!=y(0)&&(d=s+400|0,Qe=y(h[d>>2]),m=s+404|0,Me=y(h[m>>2]),G=s+416|0,je=y(h[G>>2]),M=s+420|0,B=y(h[M>>2]),se=y(Qe+c),O=y(Me+f),f=y(se+je),k=y(O+B),Q=(n[s+988>>2]|0)==1,h[d>>2]=y(jo(Qe,l,0,Q)),h[m>>2]=y(jo(Me,l,0,Q)),c=y(bR(y(je*l),y(1))),Ii(c,y(0))|0?m=0:m=(Ii(c,y(1))|0)^1,c=y(bR(y(B*l),y(1))),Ii(c,y(0))|0?d=0:d=(Ii(c,y(1))|0)^1,Qe=y(jo(f,l,Q&m,Q&(m^1))),h[G>>2]=y(Qe-y(jo(se,l,0,Q))),Qe=y(jo(k,l,Q&d,Q&(d^1))),h[M>>2]=y(Qe-y(jo(O,l,0,Q))),m=(n[s+952>>2]|0)-(n[s+948>>2]|0)>>2,m|0)){d=0;do Pc(gs(s,d)|0,l,se,O),d=d+1|0;while((d|0)!=(m|0))}}function Cw(s,l,c,f,d){switch(s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,c|0){case 5:case 0:{s=i7(n[489]|0,f,d)|0;break}default:s=XUe(f,d)|0}return s|0}function Cg(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;d=C,C=C+16|0,m=d,n[m>>2]=f,wg(s,0,l,c,m),C=d}function wg(s,l,c,f,d){if(s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,s=s|0?s:956,D7[n[s+8>>2]&1](s,l,c,f,d)|0,(c|0)==5)Rt();else return}function Ya(s,l,c){s=s|0,l=l|0,c=c|0,o[s+l>>0]=c&1}function Rm(s,l){s=s|0,l=l|0;var c=0,f=0;n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,c=l+4|0,f=(n[c>>2]|0)-(n[l>>2]|0)>>2,f|0&&(Ig(s,f),Qt(s,n[l>>2]|0,n[c>>2]|0,f))}function Ig(s,l){s=s|0,l=l|0;var c=0;if((L(s)|0)>>>0<l>>>0&&Jr(s),l>>>0>1073741823)Rt();else{c=Kt(l<<2)|0,n[s+4>>2]=c,n[s>>2]=c,n[s+8>>2]=c+(l<<2);return}}function Qt(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,f=s+4|0,s=c-l|0,(s|0)>0&&(Dr(n[f>>2]|0,l|0,s|0)|0,n[f>>2]=(n[f>>2]|0)+(s>>>2<<2))}function L(s){return s=s|0,1073741823}function K(s,l,c){return s=s|0,l=l|0,c=y(c),pe(l)|0&&(n[s+96>>2]|0)!=0?s=s+92|0:s=Fn(s+60|0,n[1040+(l<<2)>>2]|0,992)|0,y(Je(s,c))}function re(s,l,c){return s=s|0,l=l|0,c=y(c),pe(l)|0&&(n[s+104>>2]|0)!=0?s=s+100|0:s=Fn(s+60|0,n[1e3+(l<<2)>>2]|0,992)|0,y(Je(s,c))}function pe(s){return s=s|0,(s|1|0)==3|0}function Je(s,l){return s=s|0,l=y(l),(n[s+4>>2]|0)==3?l=y(0):l=y(jr(s,l)),y(l)}function mt(s,l){return s=s|0,l=l|0,s=n[s>>2]|0,((s|0)==0?(l|0)>1?l:1:s)|0}function fr(s,l){s=s|0,l=l|0;var c=0;e:do if((l|0)==2){switch(s|0){case 2:{s=3;break e}case 3:break;default:{c=4;break e}}s=2}else c=4;while(0);return s|0}function Cr(s,l){s=s|0,l=l|0;var c=Ze;return pe(l)|0&&(n[s+312>>2]|0)!=0&&(c=y(h[s+308>>2]),c>=y(0))||(c=y(_n(y(h[(Fn(s+276|0,n[1040+(l<<2)>>2]|0,992)|0)>>2]),y(0)))),y(c)}function yn(s,l){s=s|0,l=l|0;var c=Ze;return pe(l)|0&&(n[s+320>>2]|0)!=0&&(c=y(h[s+316>>2]),c>=y(0))||(c=y(_n(y(h[(Fn(s+276|0,n[1e3+(l<<2)>>2]|0,992)|0)>>2]),y(0)))),y(c)}function oi(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return pe(l)|0&&(n[s+240>>2]|0)!=0&&(f=y(jr(s+236|0,c)),f>=y(0))||(f=y(_n(y(jr(Fn(s+204|0,n[1040+(l<<2)>>2]|0,992)|0,c)),y(0)))),y(f)}function Oi(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return pe(l)|0&&(n[s+248>>2]|0)!=0&&(f=y(jr(s+244|0,c)),f>=y(0))||(f=y(_n(y(jr(Fn(s+204|0,n[1e3+(l<<2)>>2]|0,992)|0,c)),y(0)))),y(f)}function Bg(s,l,c,f,d,m,B){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=y(m),B=y(B);var k=Ze,Q=Ze,M=Ze,O=Ze,G=Ze,se=Ze,je=0,Me=0,Qe=0;Qe=C,C=C+16|0,je=Qe,Me=s+964|0,Un(s,(n[Me>>2]|0)!=0,3519),k=y(En(s,2,l)),Q=y(En(s,0,l)),M=y(ln(s,2,l)),O=y(ln(s,0,l)),Ht(l)|0?G=l:G=y(_n(y(0),y(y(l-M)-k))),Ht(c)|0?se=c:se=y(_n(y(0),y(y(c-O)-Q))),(f|0)==1&(d|0)==1?(h[s+908>>2]=y(Bi(s,2,y(l-M),m,m)),l=y(Bi(s,0,y(c-O),B,m))):(P7[n[Me>>2]&1](je,s,G,f,se,d),G=y(k+y(h[je>>2])),se=y(l-M),h[s+908>>2]=y(Bi(s,2,(f|2|0)==2?G:se,m,m)),se=y(Q+y(h[je+4>>2])),l=y(c-O),l=y(Bi(s,0,(d|2|0)==2?se:l,B,m))),h[s+912>>2]=l,C=Qe}function jv(s,l,c,f,d,m,B){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=y(m),B=y(B);var k=Ze,Q=Ze,M=Ze,O=Ze;M=y(En(s,2,m)),k=y(En(s,0,m)),O=y(ln(s,2,m)),Q=y(ln(s,0,m)),l=y(l-O),h[s+908>>2]=y(Bi(s,2,(f|2|0)==2?M:l,m,m)),c=y(c-Q),h[s+912>>2]=y(Bi(s,0,(d|2|0)==2?k:c,B,m))}function Yv(s,l,c,f,d,m,B){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=y(m),B=y(B);var k=0,Q=Ze,M=Ze;return k=(f|0)==2,!(l<=y(0)&k)&&!(c<=y(0)&(d|0)==2)&&!((f|0)==1&(d|0)==1)?s=0:(Q=y(ln(s,0,m)),M=y(ln(s,2,m)),k=l<y(0)&k|(Ht(l)|0),l=y(l-M),h[s+908>>2]=y(Bi(s,2,k?y(0):l,m,m)),l=y(c-Q),k=c<y(0)&(d|0)==2|(Ht(c)|0),h[s+912>>2]=y(Bi(s,0,k?y(0):l,B,m)),s=1),s|0}function ww(s,l){return s=s|0,l=l|0,UA(s)|0?s=fr(2,l)|0:s=0,s|0}function wp(s,l,c){return s=s|0,l=l|0,c=y(c),c=y(oi(s,l,c)),y(c+y(Cr(s,l)))}function Iw(s,l,c){return s=s|0,l=l|0,c=y(c),c=y(Oi(s,l,c)),y(c+y(yn(s,l)))}function En(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return f=y(wp(s,l,c)),y(f+y(Iw(s,l,c)))}function Tm(s){return s=s|0,n[s+24>>2]|0?s=0:y(rs(s))!=y(0)?s=1:s=y(qs(s))!=y(0),s|0}function rs(s){s=s|0;var l=Ze;if(n[s+944>>2]|0){if(l=y(h[s+44>>2]),Ht(l)|0)return l=y(h[s+40>>2]),s=l>y(0)&((Ht(l)|0)^1),y(s?l:y(0))}else l=y(0);return y(l)}function qs(s){s=s|0;var l=Ze,c=0,f=Ze;do if(n[s+944>>2]|0){if(l=y(h[s+48>>2]),Ht(l)|0){if(c=o[(n[s+976>>2]|0)+2>>0]|0,c<<24>>24==0&&(f=y(h[s+40>>2]),f<y(0)&((Ht(f)|0)^1))){l=y(-f);break}l=c<<24>>24?y(1):y(0)}}else l=y(0);while(0);return y(l)}function vu(s){s=s|0;var l=0,c=0;if(Xm(s+400|0,0,540)|0,o[s+985>>0]=1,$(s),c=wi(s)|0,c|0){l=s+948|0,s=0;do vu(n[(n[l>>2]|0)+(s<<2)>>2]|0),s=s+1|0;while((s|0)!=(c|0))}}function Lm(s,l,c,f,d,m,B,k,Q,M){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=y(m),B=y(B),k=k|0,Q=Q|0,M=M|0;var O=0,G=Ze,se=0,je=0,Me=Ze,Qe=Ze,et=0,Xe=Ze,lt=0,Ue=Ze,Ge=0,Nt=0,Mr=0,ar=0,Xt=0,Pr=0,Lr=0,sr=0,xn=0,go=0;xn=C,C=C+16|0,Mr=xn+12|0,ar=xn+8|0,Xt=xn+4|0,Pr=xn,sr=fr(n[s+4>>2]|0,Q)|0,Ge=pe(sr)|0,G=y(jr(Bw(l)|0,Ge?m:B)),Nt=ts(l,2,m)|0,Lr=ts(l,0,B)|0;do if(!(Ht(G)|0)&&!(Ht(Ge?c:d)|0)){if(O=l+504|0,!(Ht(y(h[O>>2]))|0)&&(!(vw(n[l+976>>2]|0,0)|0)||(n[l+500>>2]|0)==(n[2278]|0)))break;h[O>>2]=y(_n(G,y(En(l,sr,m))))}else se=7;while(0);do if((se|0)==7){if(lt=Ge^1,!(lt|Nt^1)){B=y(jr(n[l+992>>2]|0,m)),h[l+504>>2]=y(_n(B,y(En(l,2,m))));break}if(!(Ge|Lr^1)){B=y(jr(n[l+996>>2]|0,B)),h[l+504>>2]=y(_n(B,y(En(l,0,m))));break}h[Mr>>2]=y(ue),h[ar>>2]=y(ue),n[Xt>>2]=0,n[Pr>>2]=0,Xe=y(ln(l,2,m)),Ue=y(ln(l,0,m)),Nt?(Me=y(Xe+y(jr(n[l+992>>2]|0,m))),h[Mr>>2]=Me,n[Xt>>2]=1,je=1):(je=0,Me=y(ue)),Lr?(G=y(Ue+y(jr(n[l+996>>2]|0,B))),h[ar>>2]=G,n[Pr>>2]=1,O=1):(O=0,G=y(ue)),se=n[s+32>>2]|0,Ge&(se|0)==2?se=2:Ht(Me)|0&&!(Ht(c)|0)&&(h[Mr>>2]=c,n[Xt>>2]=2,je=2,Me=c),!((se|0)==2&lt)&&Ht(G)|0&&!(Ht(d)|0)&&(h[ar>>2]=d,n[Pr>>2]=2,O=2,G=d),Qe=y(h[l+396>>2]),et=Ht(Qe)|0;do if(et)se=je;else{if((je|0)==1&lt){h[ar>>2]=y(y(Me-Xe)/Qe),n[Pr>>2]=1,O=1,se=1;break}Ge&(O|0)==1?(h[Mr>>2]=y(Qe*y(G-Ue)),n[Xt>>2]=1,O=1,se=1):se=je}while(0);go=Ht(c)|0,je=(ha(s,l)|0)!=4,!(Ge|Nt|((f|0)!=1|go)|(je|(se|0)==1))&&(h[Mr>>2]=c,n[Xt>>2]=1,!et)&&(h[ar>>2]=y(y(c-Xe)/Qe),n[Pr>>2]=1,O=1),!(Lr|lt|((k|0)!=1|(Ht(d)|0))|(je|(O|0)==1))&&(h[ar>>2]=d,n[Pr>>2]=1,!et)&&(h[Mr>>2]=y(Qe*y(d-Ue)),n[Xt>>2]=1),yr(l,2,m,m,Xt,Mr),yr(l,0,B,m,Pr,ar),c=y(h[Mr>>2]),d=y(h[ar>>2]),fa(l,c,d,Q,n[Xt>>2]|0,n[Pr>>2]|0,m,B,0,3565,M)|0,B=y(h[l+908+(n[976+(sr<<2)>>2]<<2)>>2]),h[l+504>>2]=y(_n(B,y(En(l,sr,m))))}while(0);n[l+500>>2]=n[2278],C=xn}function Bi(s,l,c,f,d){return s=s|0,l=l|0,c=y(c),f=y(f),d=y(d),f=y(MA(s,l,c,f)),y(_n(f,y(En(s,l,d))))}function ha(s,l){return s=s|0,l=l|0,l=l+20|0,l=n[((n[l>>2]|0)==0?s+16|0:l)>>2]|0,(l|0)==5&&UA(n[s+4>>2]|0)|0&&(l=1),l|0}function Dl(s,l){return s=s|0,l=l|0,pe(l)|0&&(n[s+96>>2]|0)!=0?l=4:l=n[1040+(l<<2)>>2]|0,s+60+(l<<3)|0}function Sc(s,l){return s=s|0,l=l|0,pe(l)|0&&(n[s+104>>2]|0)!=0?l=5:l=n[1e3+(l<<2)>>2]|0,s+60+(l<<3)|0}function yr(s,l,c,f,d,m){switch(s=s|0,l=l|0,c=y(c),f=y(f),d=d|0,m=m|0,c=y(jr(s+380+(n[976+(l<<2)>>2]<<3)|0,c)),c=y(c+y(ln(s,l,f))),n[d>>2]|0){case 2:case 1:{d=Ht(c)|0,f=y(h[m>>2]),h[m>>2]=d|f<c?f:c;break}case 0:{Ht(c)|0||(n[d>>2]=2,h[m>>2]=c);break}default:}}function gi(s,l){return s=s|0,l=l|0,s=s+132|0,pe(l)|0&&(n[(Fn(s,4,948)|0)+4>>2]|0)!=0?s=1:s=(n[(Fn(s,n[1040+(l<<2)>>2]|0,948)|0)+4>>2]|0)!=0,s|0}function Or(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0;return s=s+132|0,pe(l)|0&&(f=Fn(s,4,948)|0,(n[f+4>>2]|0)!=0)?d=4:(f=Fn(s,n[1040+(l<<2)>>2]|0,948)|0,n[f+4>>2]|0?d=4:c=y(0)),(d|0)==4&&(c=y(jr(f,c))),y(c)}function ns(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return f=y(h[s+908+(n[976+(l<<2)>>2]<<2)>>2]),f=y(f+y(K(s,l,c))),y(f+y(re(s,l,c)))}function Yi(s){s=s|0;var l=0,c=0,f=0;e:do if(UA(n[s+4>>2]|0)|0)l=0;else if((n[s+16>>2]|0)!=5)if(c=wi(s)|0,!c)l=0;else for(l=0;;){if(f=gs(s,l)|0,(n[f+24>>2]|0)==0&&(n[f+20>>2]|0)==5){l=1;break e}if(l=l+1|0,l>>>0>=c>>>0){l=0;break}}else l=1;while(0);return l|0}function Nm(s,l){s=s|0,l=l|0;var c=Ze;return c=y(h[s+908+(n[976+(l<<2)>>2]<<2)>>2]),c>=y(0)&((Ht(c)|0)^1)|0}function Wa(s){s=s|0;var l=Ze,c=0,f=0,d=0,m=0,B=0,k=0,Q=Ze;if(c=n[s+968>>2]|0,c)Q=y(h[s+908>>2]),l=y(h[s+912>>2]),l=y(w7[c&0](s,Q,l)),Un(s,(Ht(l)|0)^1,3573);else{m=wi(s)|0;do if(m|0){for(c=0,d=0;;){if(f=gs(s,d)|0,n[f+940>>2]|0){B=8;break}if((n[f+24>>2]|0)!=1)if(k=(ha(s,f)|0)==5,k){c=f;break}else c=(c|0)==0?f:c;if(d=d+1|0,d>>>0>=m>>>0){B=8;break}}if((B|0)==8&&!c)break;return l=y(Wa(c)),y(l+y(h[c+404>>2]))}while(0);l=y(h[s+912>>2])}return y(l)}function MA(s,l,c,f){s=s|0,l=l|0,c=y(c),f=y(f);var d=Ze,m=0;return UA(l)|0?(l=1,m=3):pe(l)|0?(l=0,m=3):(f=y(ue),d=y(ue)),(m|0)==3&&(d=y(jr(s+364+(l<<3)|0,f)),f=y(jr(s+380+(l<<3)|0,f))),m=f<c&(f>=y(0)&((Ht(f)|0)^1)),c=m?f:c,m=d>=y(0)&((Ht(d)|0)^1)&c<d,y(m?d:c)}function Om(s,l,c,f,d,m,B){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=m|0,B=B|0;var k=Ze,Q=Ze,M=0,O=0,G=Ze,se=Ze,je=Ze,Me=0,Qe=0,et=0,Xe=0,lt=Ze,Ue=0;et=fr(n[s+4>>2]|0,m)|0,Me=ww(et,m)|0,Qe=pe(et)|0,G=y(ln(l,2,c)),se=y(ln(l,0,c)),ts(l,2,c)|0?k=y(G+y(jr(n[l+992>>2]|0,c))):gi(l,2)|0&&or(l,2)|0?(k=y(h[s+908>>2]),Q=y(Cr(s,2)),Q=y(k-y(Q+y(yn(s,2)))),k=y(Or(l,2,c)),k=y(Bi(l,2,y(Q-y(k+y(Du(l,2,c)))),c,c))):k=y(ue),ts(l,0,d)|0?Q=y(se+y(jr(n[l+996>>2]|0,d))):gi(l,0)|0&&or(l,0)|0?(Q=y(h[s+912>>2]),lt=y(Cr(s,0)),lt=y(Q-y(lt+y(yn(s,0)))),Q=y(Or(l,0,d)),Q=y(Bi(l,0,y(lt-y(Q+y(Du(l,0,d)))),d,c))):Q=y(ue),M=Ht(k)|0,O=Ht(Q)|0;do if(M^O&&(je=y(h[l+396>>2]),!(Ht(je)|0)))if(M){k=y(G+y(y(Q-se)*je));break}else{lt=y(se+y(y(k-G)/je)),Q=O?lt:Q;break}while(0);O=Ht(k)|0,M=Ht(Q)|0,O|M&&(Ue=(O^1)&1,f=c>y(0)&((f|0)!=0&O),k=Qe?k:f?c:k,fa(l,k,Q,m,Qe?Ue:f?2:Ue,O&(M^1)&1,k,Q,0,3623,B)|0,k=y(h[l+908>>2]),k=y(k+y(ln(l,2,c))),Q=y(h[l+912>>2]),Q=y(Q+y(ln(l,0,c)))),fa(l,k,Q,m,1,1,k,Q,1,3635,B)|0,or(l,et)|0&&!(gi(l,et)|0)?(Ue=n[976+(et<<2)>>2]|0,lt=y(h[s+908+(Ue<<2)>>2]),lt=y(lt-y(h[l+908+(Ue<<2)>>2])),lt=y(lt-y(yn(s,et))),lt=y(lt-y(re(l,et,c))),lt=y(lt-y(Du(l,et,Qe?c:d))),h[l+400+(n[1040+(et<<2)>>2]<<2)>>2]=lt):Xe=21;do if((Xe|0)==21){if(!(gi(l,et)|0)&&(n[s+8>>2]|0)==1){Ue=n[976+(et<<2)>>2]|0,lt=y(h[s+908+(Ue<<2)>>2]),lt=y(y(lt-y(h[l+908+(Ue<<2)>>2]))*y(.5)),h[l+400+(n[1040+(et<<2)>>2]<<2)>>2]=lt;break}!(gi(l,et)|0)&&(n[s+8>>2]|0)==2&&(Ue=n[976+(et<<2)>>2]|0,lt=y(h[s+908+(Ue<<2)>>2]),lt=y(lt-y(h[l+908+(Ue<<2)>>2])),h[l+400+(n[1040+(et<<2)>>2]<<2)>>2]=lt)}while(0);or(l,Me)|0&&!(gi(l,Me)|0)?(Ue=n[976+(Me<<2)>>2]|0,lt=y(h[s+908+(Ue<<2)>>2]),lt=y(lt-y(h[l+908+(Ue<<2)>>2])),lt=y(lt-y(yn(s,Me))),lt=y(lt-y(re(l,Me,c))),lt=y(lt-y(Du(l,Me,Qe?d:c))),h[l+400+(n[1040+(Me<<2)>>2]<<2)>>2]=lt):Xe=30;do if((Xe|0)==30&&!(gi(l,Me)|0)){if((ha(s,l)|0)==2){Ue=n[976+(Me<<2)>>2]|0,lt=y(h[s+908+(Ue<<2)>>2]),lt=y(y(lt-y(h[l+908+(Ue<<2)>>2]))*y(.5)),h[l+400+(n[1040+(Me<<2)>>2]<<2)>>2]=lt;break}Ue=(ha(s,l)|0)==3,Ue^(n[s+28>>2]|0)==2&&(Ue=n[976+(Me<<2)>>2]|0,lt=y(h[s+908+(Ue<<2)>>2]),lt=y(lt-y(h[l+908+(Ue<<2)>>2])),h[l+400+(n[1040+(Me<<2)>>2]<<2)>>2]=lt)}while(0)}function Ip(s,l,c){s=s|0,l=l|0,c=c|0;var f=Ze,d=0;d=n[976+(c<<2)>>2]|0,f=y(h[l+908+(d<<2)>>2]),f=y(y(h[s+908+(d<<2)>>2])-f),f=y(f-y(h[l+400+(n[1040+(c<<2)>>2]<<2)>>2])),h[l+400+(n[1e3+(c<<2)>>2]<<2)>>2]=f}function UA(s){return s=s|0,(s|1|0)==1|0}function Bw(s){s=s|0;var l=Ze;switch(n[s+56>>2]|0){case 0:case 3:{l=y(h[s+40>>2]),l>y(0)&((Ht(l)|0)^1)?s=o[(n[s+976>>2]|0)+2>>0]|0?1056:992:s=1056;break}default:s=s+52|0}return s|0}function vw(s,l){return s=s|0,l=l|0,(o[s+l>>0]|0)!=0|0}function or(s,l){return s=s|0,l=l|0,s=s+132|0,pe(l)|0&&(n[(Fn(s,5,948)|0)+4>>2]|0)!=0?s=1:s=(n[(Fn(s,n[1e3+(l<<2)>>2]|0,948)|0)+4>>2]|0)!=0,s|0}function Du(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0;return s=s+132|0,pe(l)|0&&(f=Fn(s,5,948)|0,(n[f+4>>2]|0)!=0)?d=4:(f=Fn(s,n[1e3+(l<<2)>>2]|0,948)|0,n[f+4>>2]|0?d=4:c=y(0)),(d|0)==4&&(c=y(jr(f,c))),y(c)}function Mm(s,l,c){return s=s|0,l=l|0,c=y(c),gi(s,l)|0?c=y(Or(s,l,c)):c=y(-y(Du(s,l,c))),y(c)}function Pu(s){return s=y(s),h[v>>2]=s,n[v>>2]|0|0}function Bp(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>1073741823)Rt();else{d=Kt(l<<2)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<2)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<2)}function vg(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function _A(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-4-l|0)>>>2)<<2)),s=n[s>>2]|0,s|0&&gt(s)}function HA(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;if(B=s+4|0,k=n[B>>2]|0,d=k-f|0,m=d>>2,s=l+(m<<2)|0,s>>>0<c>>>0){f=k;do n[f>>2]=n[s>>2],s=s+4|0,f=(n[B>>2]|0)+4|0,n[B>>2]=f;while(s>>>0<c>>>0)}m|0&&Mw(k+(0-m<<2)|0,l|0,d|0)|0}function Dg(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0;return k=l+4|0,Q=n[k>>2]|0,d=n[s>>2]|0,B=c,m=B-d|0,f=Q+(0-(m>>2)<<2)|0,n[k>>2]=f,(m|0)>0&&Dr(f|0,d|0,m|0)|0,d=s+4|0,m=l+8|0,f=(n[d>>2]|0)-B|0,(f|0)>0&&(Dr(n[m>>2]|0,c|0,f|0)|0,n[m>>2]=(n[m>>2]|0)+(f>>>2<<2)),B=n[s>>2]|0,n[s>>2]=n[k>>2],n[k>>2]=B,B=n[d>>2]|0,n[d>>2]=n[m>>2],n[m>>2]=B,B=s+8|0,c=l+12|0,s=n[B>>2]|0,n[B>>2]=n[c>>2],n[c>>2]=s,n[l>>2]=n[k>>2],Q|0}function Dw(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;if(B=n[l>>2]|0,m=n[c>>2]|0,(B|0)!=(m|0)){d=s+8|0,c=((m+-4-B|0)>>>2)+1|0,s=B,f=n[d>>2]|0;do n[f>>2]=n[s>>2],f=(n[d>>2]|0)+4|0,n[d>>2]=f,s=s+4|0;while((s|0)!=(m|0));n[l>>2]=B+(c<<2)}}function Um(){mc()}function ga(){var s=0;return s=Kt(4)|0,qA(s),s|0}function qA(s){s=s|0,n[s>>2]=ys()|0}function bc(s){s=s|0,s|0&&(Pg(s),gt(s))}function Pg(s){s=s|0,tt(n[s>>2]|0)}function _m(s,l,c){s=s|0,l=l|0,c=c|0,Ya(n[s>>2]|0,l,c)}function fo(s,l){s=s|0,l=y(l),pa(n[s>>2]|0,l)}function Wv(s,l){return s=s|0,l=l|0,vw(n[s>>2]|0,l)|0}function Pw(){var s=0;return s=Kt(8)|0,Kv(s,0),s|0}function Kv(s,l){s=s|0,l=l|0,l?l=Ci(n[l>>2]|0)|0:l=co()|0,n[s>>2]=l,n[s+4>>2]=0,bi(l,s)}function AF(s){s=s|0;var l=0;return l=Kt(8)|0,Kv(l,s),l|0}function zv(s){s=s|0,s|0&&(Su(s),gt(s))}function Su(s){s=s|0;var l=0;la(n[s>>2]|0),l=s+4|0,s=n[l>>2]|0,n[l>>2]=0,s|0&&(GA(s),gt(s))}function GA(s){s=s|0,jA(s)}function jA(s){s=s|0,s=n[s>>2]|0,s|0&&SA(s|0)}function Sw(s){return s=s|0,qo(s)|0}function Hm(s){s=s|0;var l=0,c=0;c=s+4|0,l=n[c>>2]|0,n[c>>2]=0,l|0&&(GA(l),gt(l)),_s(n[s>>2]|0)}function fF(s,l){s=s|0,l=l|0,$r(n[s>>2]|0,n[l>>2]|0)}function pF(s,l){s=s|0,l=l|0,ca(n[s>>2]|0,l)}function Vv(s,l,c){s=s|0,l=l|0,c=+c,Eu(n[s>>2]|0,l,y(c))}function Jv(s,l,c){s=s|0,l=l|0,c=+c,Es(n[s>>2]|0,l,y(c))}function bw(s,l){s=s|0,l=l|0,du(n[s>>2]|0,l)}function bu(s,l){s=s|0,l=l|0,mu(n[s>>2]|0,l)}function hF(s,l){s=s|0,l=l|0,FA(n[s>>2]|0,l)}function gF(s,l){s=s|0,l=l|0,kA(n[s>>2]|0,l)}function vp(s,l){s=s|0,l=l|0,Ec(n[s>>2]|0,l)}function dF(s,l){s=s|0,l=l|0,fp(n[s>>2]|0,l)}function Xv(s,l,c){s=s|0,l=l|0,c=+c,wc(n[s>>2]|0,l,y(c))}function YA(s,l,c){s=s|0,l=l|0,c=+c,j(n[s>>2]|0,l,y(c))}function mF(s,l){s=s|0,l=l|0,Il(n[s>>2]|0,l)}function yF(s,l){s=s|0,l=l|0,lg(n[s>>2]|0,l)}function Zv(s,l){s=s|0,l=l|0,pp(n[s>>2]|0,l)}function xw(s,l){s=s|0,l=+l,RA(n[s>>2]|0,y(l))}function kw(s,l){s=s|0,l=+l,qa(n[s>>2]|0,y(l))}function EF(s,l){s=s|0,l=+l,ji(n[s>>2]|0,y(l))}function CF(s,l){s=s|0,l=+l,Hs(n[s>>2]|0,y(l))}function Pl(s,l){s=s|0,l=+l,yu(n[s>>2]|0,y(l))}function Qw(s,l){s=s|0,l=+l,yw(n[s>>2]|0,y(l))}function wF(s,l){s=s|0,l=+l,TA(n[s>>2]|0,y(l))}function WA(s){s=s|0,hp(n[s>>2]|0)}function qm(s,l){s=s|0,l=+l,Cs(n[s>>2]|0,y(l))}function xu(s,l){s=s|0,l=+l,Ag(n[s>>2]|0,y(l))}function Fw(s){s=s|0,fg(n[s>>2]|0)}function Rw(s,l){s=s|0,l=+l,gp(n[s>>2]|0,y(l))}function IF(s,l){s=s|0,l=+l,Bc(n[s>>2]|0,y(l))}function $v(s,l){s=s|0,l=+l,bm(n[s>>2]|0,y(l))}function KA(s,l){s=s|0,l=+l,hg(n[s>>2]|0,y(l))}function eD(s,l){s=s|0,l=+l,wu(n[s>>2]|0,y(l))}function Gm(s,l){s=s|0,l=+l,xm(n[s>>2]|0,y(l))}function tD(s,l){s=s|0,l=+l,Iu(n[s>>2]|0,y(l))}function rD(s,l){s=s|0,l=+l,Ew(n[s>>2]|0,y(l))}function jm(s,l){s=s|0,l=+l,Aa(n[s>>2]|0,y(l))}function nD(s,l,c){s=s|0,l=l|0,c=+c,Cu(n[s>>2]|0,l,y(c))}function BF(s,l,c){s=s|0,l=l|0,c=+c,xi(n[s>>2]|0,l,y(c))}function P(s,l,c){s=s|0,l=l|0,c=+c,Ic(n[s>>2]|0,l,y(c))}function D(s){return s=s|0,ag(n[s>>2]|0)|0}function T(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=C,C=C+16|0,d=f,Cc(d,n[l>>2]|0,c),q(s,d),C=f}function q(s,l){s=s|0,l=l|0,Y(s,n[l+4>>2]|0,+y(h[l>>2]))}function Y(s,l,c){s=s|0,l=l|0,c=+c,n[s>>2]=l,E[s+8>>3]=c}function Ae(s){return s=s|0,og(n[s>>2]|0)|0}function De(s){return s=s|0,uo(n[s>>2]|0)|0}function vt(s){return s=s|0,yc(n[s>>2]|0)|0}function wt(s){return s=s|0,QA(n[s>>2]|0)|0}function xt(s){return s=s|0,Sm(n[s>>2]|0)|0}function _r(s){return s=s|0,sg(n[s>>2]|0)|0}function is(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=C,C=C+16|0,d=f,Dt(d,n[l>>2]|0,c),q(s,d),C=f}function di(s){return s=s|0,ei(n[s>>2]|0)|0}function po(s){return s=s|0,cg(n[s>>2]|0)|0}function zA(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,ua(f,n[l>>2]|0),q(s,f),C=c}function Yo(s){return s=s|0,+ +y(Gi(n[s>>2]|0))}function rt(s){return s=s|0,+ +y(es(n[s>>2]|0))}function ze(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,Br(f,n[l>>2]|0),q(s,f),C=c}function ft(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,pg(f,n[l>>2]|0),q(s,f),C=c}function Wt(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,Ct(f,n[l>>2]|0),q(s,f),C=c}function vr(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,gg(f,n[l>>2]|0),q(s,f),C=c}function Sn(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,dg(f,n[l>>2]|0),q(s,f),C=c}function Fr(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,km(f,n[l>>2]|0),q(s,f),C=c}function bn(s){return s=s|0,+ +y(vc(n[s>>2]|0))}function ai(s,l){return s=s|0,l=l|0,+ +y(ug(n[s>>2]|0,l))}function tn(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=C,C=C+16|0,d=f,ct(d,n[l>>2]|0,c),q(s,d),C=f}function ho(s,l,c){s=s|0,l=l|0,c=c|0,ir(n[s>>2]|0,n[l>>2]|0,c)}function vF(s,l){s=s|0,l=l|0,ms(n[s>>2]|0,n[l>>2]|0)}function tve(s){return s=s|0,wi(n[s>>2]|0)|0}function rve(s){return s=s|0,s=ht(n[s>>2]|0)|0,s?s=Sw(s)|0:s=0,s|0}function nve(s,l){return s=s|0,l=l|0,s=gs(n[s>>2]|0,l)|0,s?s=Sw(s)|0:s=0,s|0}function ive(s,l){s=s|0,l=l|0;var c=0,f=0;f=Kt(4)|0,Jj(f,l),c=s+4|0,l=n[c>>2]|0,n[c>>2]=f,l|0&&(GA(l),gt(l)),It(n[s>>2]|0,1)}function Jj(s,l){s=s|0,l=l|0,dve(s,l)}function sve(s,l,c,f,d,m){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=m|0;var B=0,k=0;B=C,C=C+16|0,k=B,ove(k,qo(l)|0,+c,f,+d,m),h[s>>2]=y(+E[k>>3]),h[s+4>>2]=y(+E[k+8>>3]),C=B}function ove(s,l,c,f,d,m){s=s|0,l=l|0,c=+c,f=f|0,d=+d,m=m|0;var B=0,k=0,Q=0,M=0,O=0;B=C,C=C+32|0,O=B+8|0,M=B+20|0,Q=B,k=B+16|0,E[O>>3]=c,n[M>>2]=f,E[Q>>3]=d,n[k>>2]=m,ave(s,n[l+4>>2]|0,O,M,Q,k),C=B}function ave(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0;B=C,C=C+16|0,k=B,za(k),l=da(l)|0,lve(s,l,+E[c>>3],n[f>>2]|0,+E[d>>3],n[m>>2]|0),Va(k),C=B}function da(s){return s=s|0,n[s>>2]|0}function lve(s,l,c,f,d,m){s=s|0,l=l|0,c=+c,f=f|0,d=+d,m=m|0;var B=0;B=Sl(cve()|0)|0,c=+VA(c),f=DF(f)|0,d=+VA(d),uve(s,hi(0,B|0,l|0,+c,f|0,+d,DF(m)|0)|0)}function cve(){var s=0;return o[7608]|0||(hve(9120),s=7608,n[s>>2]=1,n[s+4>>2]=0),9120}function Sl(s){return s=s|0,n[s+8>>2]|0}function VA(s){return s=+s,+ +PF(s)}function DF(s){return s=s|0,Zj(s)|0}function uve(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;d=C,C=C+32|0,c=d,f=l,f&1?(Ave(c,0),ii(f|0,c|0)|0,fve(s,c),pve(c)):(n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=n[l+8>>2],n[s+12>>2]=n[l+12>>2]),C=d}function Ave(s,l){s=s|0,l=l|0,Xj(s,l),n[s+8>>2]=0,o[s+24>>0]=0}function fve(s,l){s=s|0,l=l|0,l=l+8|0,n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=n[l+8>>2],n[s+12>>2]=n[l+12>>2]}function pve(s){s=s|0,o[s+24>>0]=0}function Xj(s,l){s=s|0,l=l|0,n[s>>2]=l}function Zj(s){return s=s|0,s|0}function PF(s){return s=+s,+s}function hve(s){s=s|0,bl(s,gve()|0,4)}function gve(){return 1064}function bl(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c,n[s+8>>2]=Ap(l|0,c+1|0)|0}function dve(s,l){s=s|0,l=l|0,l=n[l>>2]|0,n[s>>2]=l,El(l|0)}function mve(s){s=s|0;var l=0,c=0;c=s+4|0,l=n[c>>2]|0,n[c>>2]=0,l|0&&(GA(l),gt(l)),It(n[s>>2]|0,0)}function yve(s){s=s|0,Tt(n[s>>2]|0)}function Eve(s){return s=s|0,er(n[s>>2]|0)|0}function Cve(s,l,c,f){s=s|0,l=+l,c=+c,f=f|0,Dc(n[s>>2]|0,y(l),y(c),f)}function wve(s){return s=s|0,+ +y(Bl(n[s>>2]|0))}function Ive(s){return s=s|0,+ +y(mg(n[s>>2]|0))}function Bve(s){return s=s|0,+ +y(Bu(n[s>>2]|0))}function vve(s){return s=s|0,+ +y(LA(n[s>>2]|0))}function Dve(s){return s=s|0,+ +y(dp(n[s>>2]|0))}function Pve(s){return s=s|0,+ +y(Ga(n[s>>2]|0))}function Sve(s,l){s=s|0,l=l|0,E[s>>3]=+y(Bl(n[l>>2]|0)),E[s+8>>3]=+y(mg(n[l>>2]|0)),E[s+16>>3]=+y(Bu(n[l>>2]|0)),E[s+24>>3]=+y(LA(n[l>>2]|0)),E[s+32>>3]=+y(dp(n[l>>2]|0)),E[s+40>>3]=+y(Ga(n[l>>2]|0))}function bve(s,l){return s=s|0,l=l|0,+ +y(yg(n[s>>2]|0,l))}function xve(s,l){return s=s|0,l=l|0,+ +y(mp(n[s>>2]|0,l))}function kve(s,l){return s=s|0,l=l|0,+ +y(Go(n[s>>2]|0,l))}function Qve(){return Pn()|0}function Fve(){Rve(),Tve(),Lve(),Nve(),Ove(),Mve()}function Rve(){OLe(11713,4938,1)}function Tve(){rLe(10448)}function Lve(){OTe(10408)}function Nve(){oTe(10324)}function Ove(){hFe(10096)}function Mve(){Uve(9132)}function Uve(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0,et=0,Xe=0,lt=0,Ue=0,Ge=0,Nt=0,Mr=0,ar=0,Xt=0,Pr=0,Lr=0,sr=0,xn=0,go=0,mo=0,yo=0,ya=0,Rp=0,Tp=0,xl=0,Lp=0,Ru=0,Tu=0,Np=0,Op=0,Mp=0,Xr=0,kl=0,Up=0,kc=0,_p=0,Hp=0,Lu=0,Nu=0,Qc=0,Gs=0,Xa=0,Wo=0,Ql=0,nf=0,sf=0,Ou=0,of=0,af=0,js=0,vs=0,Fl=0,Rn=0,lf=0,Eo=0,Fc=0,Co=0,Rc=0,cf=0,uf=0,Tc=0,Ys=0,Rl=0,Af=0,ff=0,pf=0,xr=0,Vn=0,Ds=0,wo=0,Ws=0,Rr=0,ur=0,Tl=0;l=C,C=C+672|0,c=l+656|0,Tl=l+648|0,ur=l+640|0,Rr=l+632|0,Ws=l+624|0,wo=l+616|0,Ds=l+608|0,Vn=l+600|0,xr=l+592|0,pf=l+584|0,ff=l+576|0,Af=l+568|0,Rl=l+560|0,Ys=l+552|0,Tc=l+544|0,uf=l+536|0,cf=l+528|0,Rc=l+520|0,Co=l+512|0,Fc=l+504|0,Eo=l+496|0,lf=l+488|0,Rn=l+480|0,Fl=l+472|0,vs=l+464|0,js=l+456|0,af=l+448|0,of=l+440|0,Ou=l+432|0,sf=l+424|0,nf=l+416|0,Ql=l+408|0,Wo=l+400|0,Xa=l+392|0,Gs=l+384|0,Qc=l+376|0,Nu=l+368|0,Lu=l+360|0,Hp=l+352|0,_p=l+344|0,kc=l+336|0,Up=l+328|0,kl=l+320|0,Xr=l+312|0,Mp=l+304|0,Op=l+296|0,Np=l+288|0,Tu=l+280|0,Ru=l+272|0,Lp=l+264|0,xl=l+256|0,Tp=l+248|0,Rp=l+240|0,ya=l+232|0,yo=l+224|0,mo=l+216|0,go=l+208|0,xn=l+200|0,sr=l+192|0,Lr=l+184|0,Pr=l+176|0,Xt=l+168|0,ar=l+160|0,Mr=l+152|0,Nt=l+144|0,Ge=l+136|0,Ue=l+128|0,lt=l+120|0,Xe=l+112|0,et=l+104|0,Qe=l+96|0,Me=l+88|0,je=l+80|0,se=l+72|0,G=l+64|0,O=l+56|0,M=l+48|0,Q=l+40|0,k=l+32|0,B=l+24|0,m=l+16|0,d=l+8|0,f=l,_ve(s,3646),Hve(s,3651,2)|0,qve(s,3665,2)|0,Gve(s,3682,18)|0,n[Tl>>2]=19,n[Tl+4>>2]=0,n[c>>2]=n[Tl>>2],n[c+4>>2]=n[Tl+4>>2],Tw(s,3690,c)|0,n[ur>>2]=1,n[ur+4>>2]=0,n[c>>2]=n[ur>>2],n[c+4>>2]=n[ur+4>>2],jve(s,3696,c)|0,n[Rr>>2]=2,n[Rr+4>>2]=0,n[c>>2]=n[Rr>>2],n[c+4>>2]=n[Rr+4>>2],ku(s,3706,c)|0,n[Ws>>2]=1,n[Ws+4>>2]=0,n[c>>2]=n[Ws>>2],n[c+4>>2]=n[Ws+4>>2],Sg(s,3722,c)|0,n[wo>>2]=2,n[wo+4>>2]=0,n[c>>2]=n[wo>>2],n[c+4>>2]=n[wo+4>>2],Sg(s,3734,c)|0,n[Ds>>2]=3,n[Ds+4>>2]=0,n[c>>2]=n[Ds>>2],n[c+4>>2]=n[Ds+4>>2],ku(s,3753,c)|0,n[Vn>>2]=4,n[Vn+4>>2]=0,n[c>>2]=n[Vn>>2],n[c+4>>2]=n[Vn+4>>2],ku(s,3769,c)|0,n[xr>>2]=5,n[xr+4>>2]=0,n[c>>2]=n[xr>>2],n[c+4>>2]=n[xr+4>>2],ku(s,3783,c)|0,n[pf>>2]=6,n[pf+4>>2]=0,n[c>>2]=n[pf>>2],n[c+4>>2]=n[pf+4>>2],ku(s,3796,c)|0,n[ff>>2]=7,n[ff+4>>2]=0,n[c>>2]=n[ff>>2],n[c+4>>2]=n[ff+4>>2],ku(s,3813,c)|0,n[Af>>2]=8,n[Af+4>>2]=0,n[c>>2]=n[Af>>2],n[c+4>>2]=n[Af+4>>2],ku(s,3825,c)|0,n[Rl>>2]=3,n[Rl+4>>2]=0,n[c>>2]=n[Rl>>2],n[c+4>>2]=n[Rl+4>>2],Sg(s,3843,c)|0,n[Ys>>2]=4,n[Ys+4>>2]=0,n[c>>2]=n[Ys>>2],n[c+4>>2]=n[Ys+4>>2],Sg(s,3853,c)|0,n[Tc>>2]=9,n[Tc+4>>2]=0,n[c>>2]=n[Tc>>2],n[c+4>>2]=n[Tc+4>>2],ku(s,3870,c)|0,n[uf>>2]=10,n[uf+4>>2]=0,n[c>>2]=n[uf>>2],n[c+4>>2]=n[uf+4>>2],ku(s,3884,c)|0,n[cf>>2]=11,n[cf+4>>2]=0,n[c>>2]=n[cf>>2],n[c+4>>2]=n[cf+4>>2],ku(s,3896,c)|0,n[Rc>>2]=1,n[Rc+4>>2]=0,n[c>>2]=n[Rc>>2],n[c+4>>2]=n[Rc+4>>2],Is(s,3907,c)|0,n[Co>>2]=2,n[Co+4>>2]=0,n[c>>2]=n[Co>>2],n[c+4>>2]=n[Co+4>>2],Is(s,3915,c)|0,n[Fc>>2]=3,n[Fc+4>>2]=0,n[c>>2]=n[Fc>>2],n[c+4>>2]=n[Fc+4>>2],Is(s,3928,c)|0,n[Eo>>2]=4,n[Eo+4>>2]=0,n[c>>2]=n[Eo>>2],n[c+4>>2]=n[Eo+4>>2],Is(s,3948,c)|0,n[lf>>2]=5,n[lf+4>>2]=0,n[c>>2]=n[lf>>2],n[c+4>>2]=n[lf+4>>2],Is(s,3960,c)|0,n[Rn>>2]=6,n[Rn+4>>2]=0,n[c>>2]=n[Rn>>2],n[c+4>>2]=n[Rn+4>>2],Is(s,3974,c)|0,n[Fl>>2]=7,n[Fl+4>>2]=0,n[c>>2]=n[Fl>>2],n[c+4>>2]=n[Fl+4>>2],Is(s,3983,c)|0,n[vs>>2]=20,n[vs+4>>2]=0,n[c>>2]=n[vs>>2],n[c+4>>2]=n[vs+4>>2],Tw(s,3999,c)|0,n[js>>2]=8,n[js+4>>2]=0,n[c>>2]=n[js>>2],n[c+4>>2]=n[js+4>>2],Is(s,4012,c)|0,n[af>>2]=9,n[af+4>>2]=0,n[c>>2]=n[af>>2],n[c+4>>2]=n[af+4>>2],Is(s,4022,c)|0,n[of>>2]=21,n[of+4>>2]=0,n[c>>2]=n[of>>2],n[c+4>>2]=n[of+4>>2],Tw(s,4039,c)|0,n[Ou>>2]=10,n[Ou+4>>2]=0,n[c>>2]=n[Ou>>2],n[c+4>>2]=n[Ou+4>>2],Is(s,4053,c)|0,n[sf>>2]=11,n[sf+4>>2]=0,n[c>>2]=n[sf>>2],n[c+4>>2]=n[sf+4>>2],Is(s,4065,c)|0,n[nf>>2]=12,n[nf+4>>2]=0,n[c>>2]=n[nf>>2],n[c+4>>2]=n[nf+4>>2],Is(s,4084,c)|0,n[Ql>>2]=13,n[Ql+4>>2]=0,n[c>>2]=n[Ql>>2],n[c+4>>2]=n[Ql+4>>2],Is(s,4097,c)|0,n[Wo>>2]=14,n[Wo+4>>2]=0,n[c>>2]=n[Wo>>2],n[c+4>>2]=n[Wo+4>>2],Is(s,4117,c)|0,n[Xa>>2]=15,n[Xa+4>>2]=0,n[c>>2]=n[Xa>>2],n[c+4>>2]=n[Xa+4>>2],Is(s,4129,c)|0,n[Gs>>2]=16,n[Gs+4>>2]=0,n[c>>2]=n[Gs>>2],n[c+4>>2]=n[Gs+4>>2],Is(s,4148,c)|0,n[Qc>>2]=17,n[Qc+4>>2]=0,n[c>>2]=n[Qc>>2],n[c+4>>2]=n[Qc+4>>2],Is(s,4161,c)|0,n[Nu>>2]=18,n[Nu+4>>2]=0,n[c>>2]=n[Nu>>2],n[c+4>>2]=n[Nu+4>>2],Is(s,4181,c)|0,n[Lu>>2]=5,n[Lu+4>>2]=0,n[c>>2]=n[Lu>>2],n[c+4>>2]=n[Lu+4>>2],Sg(s,4196,c)|0,n[Hp>>2]=6,n[Hp+4>>2]=0,n[c>>2]=n[Hp>>2],n[c+4>>2]=n[Hp+4>>2],Sg(s,4206,c)|0,n[_p>>2]=7,n[_p+4>>2]=0,n[c>>2]=n[_p>>2],n[c+4>>2]=n[_p+4>>2],Sg(s,4217,c)|0,n[kc>>2]=3,n[kc+4>>2]=0,n[c>>2]=n[kc>>2],n[c+4>>2]=n[kc+4>>2],JA(s,4235,c)|0,n[Up>>2]=1,n[Up+4>>2]=0,n[c>>2]=n[Up>>2],n[c+4>>2]=n[Up+4>>2],SF(s,4251,c)|0,n[kl>>2]=4,n[kl+4>>2]=0,n[c>>2]=n[kl>>2],n[c+4>>2]=n[kl+4>>2],JA(s,4263,c)|0,n[Xr>>2]=5,n[Xr+4>>2]=0,n[c>>2]=n[Xr>>2],n[c+4>>2]=n[Xr+4>>2],JA(s,4279,c)|0,n[Mp>>2]=6,n[Mp+4>>2]=0,n[c>>2]=n[Mp>>2],n[c+4>>2]=n[Mp+4>>2],JA(s,4293,c)|0,n[Op>>2]=7,n[Op+4>>2]=0,n[c>>2]=n[Op>>2],n[c+4>>2]=n[Op+4>>2],JA(s,4306,c)|0,n[Np>>2]=8,n[Np+4>>2]=0,n[c>>2]=n[Np>>2],n[c+4>>2]=n[Np+4>>2],JA(s,4323,c)|0,n[Tu>>2]=9,n[Tu+4>>2]=0,n[c>>2]=n[Tu>>2],n[c+4>>2]=n[Tu+4>>2],JA(s,4335,c)|0,n[Ru>>2]=2,n[Ru+4>>2]=0,n[c>>2]=n[Ru>>2],n[c+4>>2]=n[Ru+4>>2],SF(s,4353,c)|0,n[Lp>>2]=12,n[Lp+4>>2]=0,n[c>>2]=n[Lp>>2],n[c+4>>2]=n[Lp+4>>2],bg(s,4363,c)|0,n[xl>>2]=1,n[xl+4>>2]=0,n[c>>2]=n[xl>>2],n[c+4>>2]=n[xl+4>>2],XA(s,4376,c)|0,n[Tp>>2]=2,n[Tp+4>>2]=0,n[c>>2]=n[Tp>>2],n[c+4>>2]=n[Tp+4>>2],XA(s,4388,c)|0,n[Rp>>2]=13,n[Rp+4>>2]=0,n[c>>2]=n[Rp>>2],n[c+4>>2]=n[Rp+4>>2],bg(s,4402,c)|0,n[ya>>2]=14,n[ya+4>>2]=0,n[c>>2]=n[ya>>2],n[c+4>>2]=n[ya+4>>2],bg(s,4411,c)|0,n[yo>>2]=15,n[yo+4>>2]=0,n[c>>2]=n[yo>>2],n[c+4>>2]=n[yo+4>>2],bg(s,4421,c)|0,n[mo>>2]=16,n[mo+4>>2]=0,n[c>>2]=n[mo>>2],n[c+4>>2]=n[mo+4>>2],bg(s,4433,c)|0,n[go>>2]=17,n[go+4>>2]=0,n[c>>2]=n[go>>2],n[c+4>>2]=n[go+4>>2],bg(s,4446,c)|0,n[xn>>2]=18,n[xn+4>>2]=0,n[c>>2]=n[xn>>2],n[c+4>>2]=n[xn+4>>2],bg(s,4458,c)|0,n[sr>>2]=3,n[sr+4>>2]=0,n[c>>2]=n[sr>>2],n[c+4>>2]=n[sr+4>>2],XA(s,4471,c)|0,n[Lr>>2]=1,n[Lr+4>>2]=0,n[c>>2]=n[Lr>>2],n[c+4>>2]=n[Lr+4>>2],iD(s,4486,c)|0,n[Pr>>2]=10,n[Pr+4>>2]=0,n[c>>2]=n[Pr>>2],n[c+4>>2]=n[Pr+4>>2],JA(s,4496,c)|0,n[Xt>>2]=11,n[Xt+4>>2]=0,n[c>>2]=n[Xt>>2],n[c+4>>2]=n[Xt+4>>2],JA(s,4508,c)|0,n[ar>>2]=3,n[ar+4>>2]=0,n[c>>2]=n[ar>>2],n[c+4>>2]=n[ar+4>>2],SF(s,4519,c)|0,n[Mr>>2]=4,n[Mr+4>>2]=0,n[c>>2]=n[Mr>>2],n[c+4>>2]=n[Mr+4>>2],Yve(s,4530,c)|0,n[Nt>>2]=19,n[Nt+4>>2]=0,n[c>>2]=n[Nt>>2],n[c+4>>2]=n[Nt+4>>2],Wve(s,4542,c)|0,n[Ge>>2]=12,n[Ge+4>>2]=0,n[c>>2]=n[Ge>>2],n[c+4>>2]=n[Ge+4>>2],Kve(s,4554,c)|0,n[Ue>>2]=13,n[Ue+4>>2]=0,n[c>>2]=n[Ue>>2],n[c+4>>2]=n[Ue+4>>2],zve(s,4568,c)|0,n[lt>>2]=2,n[lt+4>>2]=0,n[c>>2]=n[lt>>2],n[c+4>>2]=n[lt+4>>2],Vve(s,4578,c)|0,n[Xe>>2]=20,n[Xe+4>>2]=0,n[c>>2]=n[Xe>>2],n[c+4>>2]=n[Xe+4>>2],Jve(s,4587,c)|0,n[et>>2]=22,n[et+4>>2]=0,n[c>>2]=n[et>>2],n[c+4>>2]=n[et+4>>2],Tw(s,4602,c)|0,n[Qe>>2]=23,n[Qe+4>>2]=0,n[c>>2]=n[Qe>>2],n[c+4>>2]=n[Qe+4>>2],Tw(s,4619,c)|0,n[Me>>2]=14,n[Me+4>>2]=0,n[c>>2]=n[Me>>2],n[c+4>>2]=n[Me+4>>2],Xve(s,4629,c)|0,n[je>>2]=1,n[je+4>>2]=0,n[c>>2]=n[je>>2],n[c+4>>2]=n[je+4>>2],Zve(s,4637,c)|0,n[se>>2]=4,n[se+4>>2]=0,n[c>>2]=n[se>>2],n[c+4>>2]=n[se+4>>2],XA(s,4653,c)|0,n[G>>2]=5,n[G+4>>2]=0,n[c>>2]=n[G>>2],n[c+4>>2]=n[G+4>>2],XA(s,4669,c)|0,n[O>>2]=6,n[O+4>>2]=0,n[c>>2]=n[O>>2],n[c+4>>2]=n[O+4>>2],XA(s,4686,c)|0,n[M>>2]=7,n[M+4>>2]=0,n[c>>2]=n[M>>2],n[c+4>>2]=n[M+4>>2],XA(s,4701,c)|0,n[Q>>2]=8,n[Q+4>>2]=0,n[c>>2]=n[Q>>2],n[c+4>>2]=n[Q+4>>2],XA(s,4719,c)|0,n[k>>2]=9,n[k+4>>2]=0,n[c>>2]=n[k>>2],n[c+4>>2]=n[k+4>>2],XA(s,4736,c)|0,n[B>>2]=21,n[B+4>>2]=0,n[c>>2]=n[B>>2],n[c+4>>2]=n[B+4>>2],$ve(s,4754,c)|0,n[m>>2]=2,n[m+4>>2]=0,n[c>>2]=n[m>>2],n[c+4>>2]=n[m+4>>2],iD(s,4772,c)|0,n[d>>2]=3,n[d+4>>2]=0,n[c>>2]=n[d>>2],n[c+4>>2]=n[d+4>>2],iD(s,4790,c)|0,n[f>>2]=4,n[f+4>>2]=0,n[c>>2]=n[f>>2],n[c+4>>2]=n[f+4>>2],iD(s,4808,c)|0,C=l}function _ve(s,l){s=s|0,l=l|0;var c=0;c=sFe()|0,n[s>>2]=c,oFe(c,l),kp(n[s>>2]|0)}function Hve(s,l,c){return s=s|0,l=l|0,c=c|0,YQe(s,pn(l)|0,c,0),s|0}function qve(s,l,c){return s=s|0,l=l|0,c=c|0,xQe(s,pn(l)|0,c,0),s|0}function Gve(s,l,c){return s=s|0,l=l|0,c=c|0,gQe(s,pn(l)|0,c,0),s|0}function Tw(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],$ke(s,l,d),C=f,s|0}function jve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Tke(s,l,d),C=f,s|0}function ku(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],yke(s,l,d),C=f,s|0}function Sg(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],rke(s,l,d),C=f,s|0}function Is(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],_xe(s,l,d),C=f,s|0}function JA(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],vxe(s,l,d),C=f,s|0}function SF(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],lxe(s,l,d),C=f,s|0}function bg(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Tbe(s,l,d),C=f,s|0}function XA(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ybe(s,l,d),C=f,s|0}function iD(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],rbe(s,l,d),C=f,s|0}function Yve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],_Se(s,l,d),C=f,s|0}function Wve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],vSe(s,l,d),C=f,s|0}function Kve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],cSe(s,l,d),C=f,s|0}function zve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],zPe(s,l,d),C=f,s|0}function Vve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],QPe(s,l,d),C=f,s|0}function Jve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],hPe(s,l,d),C=f,s|0}function Xve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ZDe(s,l,d),C=f,s|0}function Zve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],TDe(s,l,d),C=f,s|0}function $ve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],eDe(s,l,d),C=f,s|0}function eDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],tDe(s,c,d,1),C=f}function pn(s){return s=s|0,s|0}function tDe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=bF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=rDe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,nDe(m,f)|0,f),C=d}function bF(){var s=0,l=0;if(o[7616]|0||(t9(9136),rr(24,9136,U|0)|0,l=7616,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9136)|0)){s=9136,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));t9(9136)}return 9136}function rDe(s){return s=s|0,0}function nDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=bF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],e9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(oDe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function hn(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0;B=C,C=C+32|0,se=B+24|0,G=B+20|0,Q=B+16|0,O=B+12|0,M=B+8|0,k=B+4|0,je=B,n[G>>2]=l,n[Q>>2]=c,n[O>>2]=f,n[M>>2]=d,n[k>>2]=m,m=s+28|0,n[je>>2]=n[m>>2],n[se>>2]=n[je>>2],iDe(s+24|0,se,G,O,M,Q,k)|0,n[m>>2]=n[n[m>>2]>>2],C=B}function iDe(s,l,c,f,d,m,B){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0,s=sDe(l)|0,l=Kt(24)|0,$j(l+4|0,n[c>>2]|0,n[f>>2]|0,n[d>>2]|0,n[m>>2]|0,n[B>>2]|0),n[l>>2]=n[s>>2],n[s>>2]=l,l|0}function sDe(s){return s=s|0,n[s>>2]|0}function $j(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,n[s>>2]=l,n[s+4>>2]=c,n[s+8>>2]=f,n[s+12>>2]=d,n[s+16>>2]=m}function gr(s,l){return s=s|0,l=l|0,l|s|0}function e9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function oDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=aDe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,lDe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],e9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,cDe(s,k),uDe(k),C=M;return}}function aDe(s){return s=s|0,357913941}function lDe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function cDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function uDe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function t9(s){s=s|0,pDe(s)}function ADe(s){s=s|0,fDe(s+24|0)}function Tr(s){return s=s|0,n[s>>2]|0}function fDe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function pDe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,3,l,hDe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Kr(){return 9228}function hDe(){return 1140}function gDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=dDe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=mDe(l,f)|0,C=c,l|0}function zr(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,n[s>>2]=l,n[s+4>>2]=c,n[s+8>>2]=f,n[s+12>>2]=d,n[s+16>>2]=m}function dDe(s){return s=s|0,(n[(bF()|0)+24>>2]|0)+(s*12|0)|0}function mDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;return d=C,C=C+48|0,f=d,c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),rf[c&31](f,s),f=yDe(f)|0,C=d,f|0}function yDe(s){s=s|0;var l=0,c=0,f=0,d=0;return d=C,C=C+32|0,l=d+12|0,c=d,f=xF(r9()|0)|0,f?(kF(l,f),QF(c,l),EDe(s,c),s=FF(l)|0):s=CDe(s)|0,C=d,s|0}function r9(){var s=0;return o[7632]|0||(kDe(9184),rr(25,9184,U|0)|0,s=7632,n[s>>2]=1,n[s+4>>2]=0),9184}function xF(s){return s=s|0,n[s+36>>2]|0}function kF(s,l){s=s|0,l=l|0,n[s>>2]=l,n[s+4>>2]=s,n[s+8>>2]=0}function QF(s,l){s=s|0,l=l|0,n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=0}function EDe(s,l){s=s|0,l=l|0,vDe(l,s,s+8|0,s+16|0,s+24|0,s+32|0,s+40|0)|0}function FF(s){return s=s|0,n[(n[s+4>>2]|0)+8>>2]|0}function CDe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0;Q=C,C=C+16|0,c=Q+4|0,f=Q,d=Ka(8)|0,m=d,B=Kt(48)|0,k=B,l=k+48|0;do n[k>>2]=n[s>>2],k=k+4|0,s=s+4|0;while((k|0)<(l|0));return l=m+4|0,n[l>>2]=B,k=Kt(8)|0,B=n[l>>2]|0,n[f>>2]=0,n[c>>2]=n[f>>2],n9(k,B,c),n[d>>2]=k,C=Q,m|0}function n9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1092,n[c+12>>2]=l,n[s+4>>2]=c}function wDe(s){s=s|0,Jm(s),gt(s)}function IDe(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function BDe(s){s=s|0,gt(s)}function vDe(s,l,c,f,d,m,B){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0,m=DDe(n[s>>2]|0,l,c,f,d,m,B)|0,B=s+4|0,n[(n[B>>2]|0)+8>>2]=m,n[(n[B>>2]|0)+8>>2]|0}function DDe(s,l,c,f,d,m,B){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0;var k=0,Q=0;return k=C,C=C+16|0,Q=k,za(Q),s=da(s)|0,B=PDe(s,+E[l>>3],+E[c>>3],+E[f>>3],+E[d>>3],+E[m>>3],+E[B>>3])|0,Va(Q),C=k,B|0}function PDe(s,l,c,f,d,m,B){s=s|0,l=+l,c=+c,f=+f,d=+d,m=+m,B=+B;var k=0;return k=Sl(SDe()|0)|0,l=+VA(l),c=+VA(c),f=+VA(f),d=+VA(d),m=+VA(m),Ms(0,k|0,s|0,+l,+c,+f,+d,+m,+ +VA(B))|0}function SDe(){var s=0;return o[7624]|0||(bDe(9172),s=7624,n[s>>2]=1,n[s+4>>2]=0),9172}function bDe(s){s=s|0,bl(s,xDe()|0,6)}function xDe(){return 1112}function kDe(s){s=s|0,Dp(s)}function QDe(s){s=s|0,i9(s+24|0),s9(s+16|0)}function i9(s){s=s|0,RDe(s)}function s9(s){s=s|0,FDe(s)}function FDe(s){s=s|0;var l=0,c=0;if(l=n[s>>2]|0,l|0)do c=l,l=n[l>>2]|0,gt(c);while((l|0)!=0);n[s>>2]=0}function RDe(s){s=s|0;var l=0,c=0;if(l=n[s>>2]|0,l|0)do c=l,l=n[l>>2]|0,gt(c);while((l|0)!=0);n[s>>2]=0}function Dp(s){s=s|0;var l=0;n[s+16>>2]=0,n[s+20>>2]=0,l=s+24|0,n[l>>2]=0,n[s+28>>2]=l,n[s+36>>2]=0,o[s+40>>0]=0,o[s+41>>0]=0}function TDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],LDe(s,c,d,0),C=f}function LDe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=RF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=NDe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,ODe(m,f)|0,f),C=d}function RF(){var s=0,l=0;if(o[7640]|0||(a9(9232),rr(26,9232,U|0)|0,l=7640,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9232)|0)){s=9232,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));a9(9232)}return 9232}function NDe(s){return s=s|0,0}function ODe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=RF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],o9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(MDe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function o9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function MDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=UDe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,_De(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],o9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,HDe(s,k),qDe(k),C=M;return}}function UDe(s){return s=s|0,357913941}function _De(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function HDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function qDe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function a9(s){s=s|0,YDe(s)}function GDe(s){s=s|0,jDe(s+24|0)}function jDe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function YDe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,1,l,WDe()|0,3),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function WDe(){return 1144}function KDe(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0;var m=0,B=0,k=0,Q=0;m=C,C=C+16|0,B=m+8|0,k=m,Q=zDe(s)|0,s=n[Q+4>>2]|0,n[k>>2]=n[Q>>2],n[k+4>>2]=s,n[B>>2]=n[k>>2],n[B+4>>2]=n[k+4>>2],VDe(l,B,c,f,d),C=m}function zDe(s){return s=s|0,(n[(RF()|0)+24>>2]|0)+(s*12|0)|0}function VDe(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0;var m=0,B=0,k=0,Q=0,M=0;M=C,C=C+16|0,B=M+2|0,k=M+1|0,Q=M,m=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(m=n[(n[s>>2]|0)+m>>2]|0),Qu(B,c),c=+Fu(B,c),Qu(k,f),f=+Fu(k,f),ZA(Q,d),Q=$A(Q,d)|0,I7[m&1](s,c,f,Q),C=M}function Qu(s,l){s=s|0,l=+l}function Fu(s,l){return s=s|0,l=+l,+ +XDe(l)}function ZA(s,l){s=s|0,l=l|0}function $A(s,l){return s=s|0,l=l|0,JDe(l)|0}function JDe(s){return s=s|0,s|0}function XDe(s){return s=+s,+s}function ZDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],$De(s,c,d,1),C=f}function $De(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=TF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=ePe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,tPe(m,f)|0,f),C=d}function TF(){var s=0,l=0;if(o[7648]|0||(c9(9268),rr(27,9268,U|0)|0,l=7648,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9268)|0)){s=9268,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));c9(9268)}return 9268}function ePe(s){return s=s|0,0}function tPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=TF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],l9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(rPe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function l9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function rPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=nPe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,iPe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],l9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,sPe(s,k),oPe(k),C=M;return}}function nPe(s){return s=s|0,357913941}function iPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function sPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function oPe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function c9(s){s=s|0,cPe(s)}function aPe(s){s=s|0,lPe(s+24|0)}function lPe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function cPe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,4,l,uPe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function uPe(){return 1160}function APe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=fPe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=pPe(l,f)|0,C=c,l|0}function fPe(s){return s=s|0,(n[(TF()|0)+24>>2]|0)+(s*12|0)|0}function pPe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),u9(Og[c&31](s)|0)|0}function u9(s){return s=s|0,s&1|0}function hPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],gPe(s,c,d,0),C=f}function gPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=LF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=dPe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,mPe(m,f)|0,f),C=d}function LF(){var s=0,l=0;if(o[7656]|0||(f9(9304),rr(28,9304,U|0)|0,l=7656,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9304)|0)){s=9304,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));f9(9304)}return 9304}function dPe(s){return s=s|0,0}function mPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=LF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],A9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(yPe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function A9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function yPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=EPe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,CPe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],A9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,wPe(s,k),IPe(k),C=M;return}}function EPe(s){return s=s|0,357913941}function CPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function wPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function IPe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function f9(s){s=s|0,DPe(s)}function BPe(s){s=s|0,vPe(s+24|0)}function vPe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function DPe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,5,l,PPe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function PPe(){return 1164}function SPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=bPe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],xPe(l,d,c),C=f}function bPe(s){return s=s|0,(n[(LF()|0)+24>>2]|0)+(s*12|0)|0}function xPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),Pp(d,c),c=Sp(d,c)|0,rf[f&31](s,c),bp(d),C=m}function Pp(s,l){s=s|0,l=l|0,kPe(s,l)}function Sp(s,l){return s=s|0,l=l|0,s|0}function bp(s){s=s|0,GA(s)}function kPe(s,l){s=s|0,l=l|0,NF(s,l)}function NF(s,l){s=s|0,l=l|0,n[s>>2]=l}function QPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],FPe(s,c,d,0),C=f}function FPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=OF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=RPe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,TPe(m,f)|0,f),C=d}function OF(){var s=0,l=0;if(o[7664]|0||(h9(9340),rr(29,9340,U|0)|0,l=7664,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9340)|0)){s=9340,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));h9(9340)}return 9340}function RPe(s){return s=s|0,0}function TPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=OF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],p9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(LPe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function p9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function LPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=NPe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,OPe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],p9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,MPe(s,k),UPe(k),C=M;return}}function NPe(s){return s=s|0,357913941}function OPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function MPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function UPe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function h9(s){s=s|0,qPe(s)}function _Pe(s){s=s|0,HPe(s+24|0)}function HPe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function qPe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,4,l,GPe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function GPe(){return 1180}function jPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=YPe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=WPe(l,d,c)|0,C=f,c|0}function YPe(s){return s=s|0,(n[(OF()|0)+24>>2]|0)+(s*12|0)|0}function WPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;return m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),xg(d,c),d=kg(d,c)|0,d=sD(RR[f&15](s,d)|0)|0,C=m,d|0}function xg(s,l){s=s|0,l=l|0}function kg(s,l){return s=s|0,l=l|0,KPe(l)|0}function sD(s){return s=s|0,s|0}function KPe(s){return s=s|0,s|0}function zPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],VPe(s,c,d,0),C=f}function VPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=MF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=JPe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,XPe(m,f)|0,f),C=d}function MF(){var s=0,l=0;if(o[7672]|0||(d9(9376),rr(30,9376,U|0)|0,l=7672,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9376)|0)){s=9376,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));d9(9376)}return 9376}function JPe(s){return s=s|0,0}function XPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=MF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],g9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(ZPe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function g9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function ZPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=$Pe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,eSe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],g9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,tSe(s,k),rSe(k),C=M;return}}function $Pe(s){return s=s|0,357913941}function eSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function tSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function rSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function d9(s){s=s|0,sSe(s)}function nSe(s){s=s|0,iSe(s+24|0)}function iSe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function sSe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,5,l,m9()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function m9(){return 1196}function oSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=aSe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=lSe(l,f)|0,C=c,l|0}function aSe(s){return s=s|0,(n[(MF()|0)+24>>2]|0)+(s*12|0)|0}function lSe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),sD(Og[c&31](s)|0)|0}function cSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],uSe(s,c,d,1),C=f}function uSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=UF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=ASe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,fSe(m,f)|0,f),C=d}function UF(){var s=0,l=0;if(o[7680]|0||(E9(9412),rr(31,9412,U|0)|0,l=7680,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9412)|0)){s=9412,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));E9(9412)}return 9412}function ASe(s){return s=s|0,0}function fSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=UF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],y9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(pSe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function y9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function pSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=hSe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,gSe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],y9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,dSe(s,k),mSe(k),C=M;return}}function hSe(s){return s=s|0,357913941}function gSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function dSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function mSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function E9(s){s=s|0,CSe(s)}function ySe(s){s=s|0,ESe(s+24|0)}function ESe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function CSe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,6,l,C9()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function C9(){return 1200}function wSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=ISe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=BSe(l,f)|0,C=c,l|0}function ISe(s){return s=s|0,(n[(UF()|0)+24>>2]|0)+(s*12|0)|0}function BSe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),oD(Og[c&31](s)|0)|0}function oD(s){return s=s|0,s|0}function vSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],DSe(s,c,d,0),C=f}function DSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=_F()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=PSe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,SSe(m,f)|0,f),C=d}function _F(){var s=0,l=0;if(o[7688]|0||(I9(9448),rr(32,9448,U|0)|0,l=7688,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9448)|0)){s=9448,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));I9(9448)}return 9448}function PSe(s){return s=s|0,0}function SSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=_F()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],w9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(bSe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function w9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function bSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=xSe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,kSe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],w9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,QSe(s,k),FSe(k),C=M;return}}function xSe(s){return s=s|0,357913941}function kSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function QSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function FSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function I9(s){s=s|0,LSe(s)}function RSe(s){s=s|0,TSe(s+24|0)}function TSe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function LSe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,6,l,B9()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function B9(){return 1204}function NSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=OSe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],MSe(l,d,c),C=f}function OSe(s){return s=s|0,(n[(_F()|0)+24>>2]|0)+(s*12|0)|0}function MSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),HF(d,c),d=qF(d,c)|0,rf[f&31](s,d),C=m}function HF(s,l){s=s|0,l=l|0}function qF(s,l){return s=s|0,l=l|0,USe(l)|0}function USe(s){return s=s|0,s|0}function _Se(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],HSe(s,c,d,0),C=f}function HSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=GF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=qSe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,GSe(m,f)|0,f),C=d}function GF(){var s=0,l=0;if(o[7696]|0||(D9(9484),rr(33,9484,U|0)|0,l=7696,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9484)|0)){s=9484,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));D9(9484)}return 9484}function qSe(s){return s=s|0,0}function GSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=GF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],v9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(jSe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function v9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function jSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=YSe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,WSe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],v9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,KSe(s,k),zSe(k),C=M;return}}function YSe(s){return s=s|0,357913941}function WSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function KSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function zSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function D9(s){s=s|0,XSe(s)}function VSe(s){s=s|0,JSe(s+24|0)}function JSe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function XSe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,1,l,ZSe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function ZSe(){return 1212}function $Se(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,m=d+8|0,B=d,k=ebe(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],tbe(l,m,c,f),C=d}function ebe(s){return s=s|0,(n[(GF()|0)+24>>2]|0)+(s*12|0)|0}function tbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;k=C,C=C+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(d=n[(n[s>>2]|0)+d>>2]|0),HF(m,c),m=qF(m,c)|0,xg(B,f),B=kg(B,f)|0,Hw[d&15](s,m,B),C=k}function rbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],nbe(s,c,d,1),C=f}function nbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=jF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=ibe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,sbe(m,f)|0,f),C=d}function jF(){var s=0,l=0;if(o[7704]|0||(S9(9520),rr(34,9520,U|0)|0,l=7704,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9520)|0)){s=9520,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));S9(9520)}return 9520}function ibe(s){return s=s|0,0}function sbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=jF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],P9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(obe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function P9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function obe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=abe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,lbe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],P9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,cbe(s,k),ube(k),C=M;return}}function abe(s){return s=s|0,357913941}function lbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function cbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function ube(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function S9(s){s=s|0,pbe(s)}function Abe(s){s=s|0,fbe(s+24|0)}function fbe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function pbe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,1,l,hbe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function hbe(){return 1224}function gbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;return d=C,C=C+16|0,m=d+8|0,B=d,k=dbe(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],f=+mbe(l,m,c),C=d,+f}function dbe(s){return s=s|0,(n[(jF()|0)+24>>2]|0)+(s*12|0)|0}function mbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),ZA(d,c),d=$A(d,c)|0,B=+PF(+v7[f&7](s,d)),C=m,+B}function ybe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Ebe(s,c,d,1),C=f}function Ebe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=YF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=Cbe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,wbe(m,f)|0,f),C=d}function YF(){var s=0,l=0;if(o[7712]|0||(x9(9556),rr(35,9556,U|0)|0,l=7712,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9556)|0)){s=9556,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));x9(9556)}return 9556}function Cbe(s){return s=s|0,0}function wbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=YF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],b9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Ibe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function b9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Ibe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Bbe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,vbe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],b9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Dbe(s,k),Pbe(k),C=M;return}}function Bbe(s){return s=s|0,357913941}function vbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Dbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Pbe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function x9(s){s=s|0,xbe(s)}function Sbe(s){s=s|0,bbe(s+24|0)}function bbe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function xbe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,5,l,kbe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function kbe(){return 1232}function Qbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=Fbe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=+Rbe(l,d),C=f,+c}function Fbe(s){return s=s|0,(n[(YF()|0)+24>>2]|0)+(s*12|0)|0}function Rbe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),+ +PF(+B7[c&15](s))}function Tbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Lbe(s,c,d,1),C=f}function Lbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=WF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=Nbe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Obe(m,f)|0,f),C=d}function WF(){var s=0,l=0;if(o[7720]|0||(Q9(9592),rr(36,9592,U|0)|0,l=7720,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9592)|0)){s=9592,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));Q9(9592)}return 9592}function Nbe(s){return s=s|0,0}function Obe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=WF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],k9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Mbe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function k9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Mbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Ube(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,_be(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],k9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Hbe(s,k),qbe(k),C=M;return}}function Ube(s){return s=s|0,357913941}function _be(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Hbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function qbe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function Q9(s){s=s|0,Ybe(s)}function Gbe(s){s=s|0,jbe(s+24|0)}function jbe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Ybe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,7,l,Wbe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Wbe(){return 1276}function Kbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=zbe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=Vbe(l,f)|0,C=c,l|0}function zbe(s){return s=s|0,(n[(WF()|0)+24>>2]|0)+(s*12|0)|0}function Vbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;return d=C,C=C+16|0,f=d,c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),rf[c&31](f,s),f=F9(f)|0,C=d,f|0}function F9(s){s=s|0;var l=0,c=0,f=0,d=0;return d=C,C=C+32|0,l=d+12|0,c=d,f=xF(R9()|0)|0,f?(kF(l,f),QF(c,l),Jbe(s,c),s=FF(l)|0):s=Xbe(s)|0,C=d,s|0}function R9(){var s=0;return o[7736]|0||(axe(9640),rr(25,9640,U|0)|0,s=7736,n[s>>2]=1,n[s+4>>2]=0),9640}function Jbe(s,l){s=s|0,l=l|0,txe(l,s,s+8|0)|0}function Xbe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;return c=C,C=C+16|0,d=c+4|0,B=c,f=Ka(8)|0,l=f,k=Kt(16)|0,n[k>>2]=n[s>>2],n[k+4>>2]=n[s+4>>2],n[k+8>>2]=n[s+8>>2],n[k+12>>2]=n[s+12>>2],m=l+4|0,n[m>>2]=k,s=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],KF(s,m,d),n[f>>2]=s,C=c,l|0}function KF(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1244,n[c+12>>2]=l,n[s+4>>2]=c}function Zbe(s){s=s|0,Jm(s),gt(s)}function $be(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function exe(s){s=s|0,gt(s)}function txe(s,l,c){return s=s|0,l=l|0,c=c|0,l=rxe(n[s>>2]|0,l,c)|0,c=s+4|0,n[(n[c>>2]|0)+8>>2]=l,n[(n[c>>2]|0)+8>>2]|0}function rxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;return f=C,C=C+16|0,d=f,za(d),s=da(s)|0,c=nxe(s,n[l>>2]|0,+E[c>>3])|0,Va(d),C=f,c|0}function nxe(s,l,c){s=s|0,l=l|0,c=+c;var f=0;return f=Sl(ixe()|0)|0,l=DF(l)|0,yl(0,f|0,s|0,l|0,+ +VA(c))|0}function ixe(){var s=0;return o[7728]|0||(sxe(9628),s=7728,n[s>>2]=1,n[s+4>>2]=0),9628}function sxe(s){s=s|0,bl(s,oxe()|0,2)}function oxe(){return 1264}function axe(s){s=s|0,Dp(s)}function lxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],cxe(s,c,d,1),C=f}function cxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=zF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=uxe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Axe(m,f)|0,f),C=d}function zF(){var s=0,l=0;if(o[7744]|0||(L9(9684),rr(37,9684,U|0)|0,l=7744,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9684)|0)){s=9684,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));L9(9684)}return 9684}function uxe(s){return s=s|0,0}function Axe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=zF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],T9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(fxe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function T9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function fxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=pxe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,hxe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],T9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,gxe(s,k),dxe(k),C=M;return}}function pxe(s){return s=s|0,357913941}function hxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function gxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function dxe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function L9(s){s=s|0,Exe(s)}function mxe(s){s=s|0,yxe(s+24|0)}function yxe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Exe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,5,l,Cxe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Cxe(){return 1280}function wxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=Ixe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=Bxe(l,d,c)|0,C=f,c|0}function Ixe(s){return s=s|0,(n[(zF()|0)+24>>2]|0)+(s*12|0)|0}function Bxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return B=C,C=C+32|0,d=B,m=B+16|0,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),ZA(m,c),m=$A(m,c)|0,Hw[f&15](d,s,m),m=F9(d)|0,C=B,m|0}function vxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Dxe(s,c,d,1),C=f}function Dxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=VF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=Pxe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Sxe(m,f)|0,f),C=d}function VF(){var s=0,l=0;if(o[7752]|0||(O9(9720),rr(38,9720,U|0)|0,l=7752,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9720)|0)){s=9720,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));O9(9720)}return 9720}function Pxe(s){return s=s|0,0}function Sxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=VF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],N9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(bxe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function N9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function bxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=xxe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,kxe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],N9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Qxe(s,k),Fxe(k),C=M;return}}function xxe(s){return s=s|0,357913941}function kxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Qxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Fxe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function O9(s){s=s|0,Lxe(s)}function Rxe(s){s=s|0,Txe(s+24|0)}function Txe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Lxe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,8,l,Nxe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Nxe(){return 1288}function Oxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=Mxe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=Uxe(l,f)|0,C=c,l|0}function Mxe(s){return s=s|0,(n[(VF()|0)+24>>2]|0)+(s*12|0)|0}function Uxe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),Zj(Og[c&31](s)|0)|0}function _xe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Hxe(s,c,d,0),C=f}function Hxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=JF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=qxe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Gxe(m,f)|0,f),C=d}function JF(){var s=0,l=0;if(o[7760]|0||(U9(9756),rr(39,9756,U|0)|0,l=7760,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9756)|0)){s=9756,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));U9(9756)}return 9756}function qxe(s){return s=s|0,0}function Gxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=JF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],M9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(jxe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function M9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function jxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Yxe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,Wxe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],M9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Kxe(s,k),zxe(k),C=M;return}}function Yxe(s){return s=s|0,357913941}function Wxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Kxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function zxe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function U9(s){s=s|0,Xxe(s)}function Vxe(s){s=s|0,Jxe(s+24|0)}function Jxe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Xxe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,8,l,Zxe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Zxe(){return 1292}function $xe(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=eke(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],tke(l,d,c),C=f}function eke(s){return s=s|0,(n[(JF()|0)+24>>2]|0)+(s*12|0)|0}function tke(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),Qu(d,c),c=+Fu(d,c),C7[f&31](s,c),C=m}function rke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],nke(s,c,d,0),C=f}function nke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=XF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=ike(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,ske(m,f)|0,f),C=d}function XF(){var s=0,l=0;if(o[7768]|0||(H9(9792),rr(40,9792,U|0)|0,l=7768,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9792)|0)){s=9792,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));H9(9792)}return 9792}function ike(s){return s=s|0,0}function ske(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=XF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],_9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(oke(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function _9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function oke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=ake(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,lke(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],_9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,cke(s,k),uke(k),C=M;return}}function ake(s){return s=s|0,357913941}function lke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function cke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function uke(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function H9(s){s=s|0,pke(s)}function Ake(s){s=s|0,fke(s+24|0)}function fke(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function pke(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,1,l,hke()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function hke(){return 1300}function gke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,m=d+8|0,B=d,k=dke(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],mke(l,m,c,f),C=d}function dke(s){return s=s|0,(n[(XF()|0)+24>>2]|0)+(s*12|0)|0}function mke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f;var d=0,m=0,B=0,k=0;k=C,C=C+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(d=n[(n[s>>2]|0)+d>>2]|0),ZA(m,c),m=$A(m,c)|0,Qu(B,f),f=+Fu(B,f),b7[d&15](s,m,f),C=k}function yke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Eke(s,c,d,0),C=f}function Eke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=ZF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=Cke(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,wke(m,f)|0,f),C=d}function ZF(){var s=0,l=0;if(o[7776]|0||(G9(9828),rr(41,9828,U|0)|0,l=7776,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9828)|0)){s=9828,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));G9(9828)}return 9828}function Cke(s){return s=s|0,0}function wke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=ZF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],q9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Ike(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function q9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Ike(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Bke(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,vke(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],q9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Dke(s,k),Pke(k),C=M;return}}function Bke(s){return s=s|0,357913941}function vke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Dke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Pke(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function G9(s){s=s|0,xke(s)}function Ske(s){s=s|0,bke(s+24|0)}function bke(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function xke(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,7,l,kke()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function kke(){return 1312}function Qke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=Fke(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Rke(l,d,c),C=f}function Fke(s){return s=s|0,(n[(ZF()|0)+24>>2]|0)+(s*12|0)|0}function Rke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),ZA(d,c),d=$A(d,c)|0,rf[f&31](s,d),C=m}function Tke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Lke(s,c,d,0),C=f}function Lke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=$F()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=Nke(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Oke(m,f)|0,f),C=d}function $F(){var s=0,l=0;if(o[7784]|0||(Y9(9864),rr(42,9864,U|0)|0,l=7784,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9864)|0)){s=9864,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));Y9(9864)}return 9864}function Nke(s){return s=s|0,0}function Oke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=$F()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],j9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Mke(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function j9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Mke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Uke(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,_ke(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],j9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Hke(s,k),qke(k),C=M;return}}function Uke(s){return s=s|0,357913941}function _ke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Hke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function qke(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function Y9(s){s=s|0,Yke(s)}function Gke(s){s=s|0,jke(s+24|0)}function jke(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Yke(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,8,l,Wke()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Wke(){return 1320}function Kke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=zke(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Vke(l,d,c),C=f}function zke(s){return s=s|0,(n[($F()|0)+24>>2]|0)+(s*12|0)|0}function Vke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),Jke(d,c),d=Xke(d,c)|0,rf[f&31](s,d),C=m}function Jke(s,l){s=s|0,l=l|0}function Xke(s,l){return s=s|0,l=l|0,Zke(l)|0}function Zke(s){return s=s|0,s|0}function $ke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],eQe(s,c,d,0),C=f}function eQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=eR()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=tQe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,rQe(m,f)|0,f),C=d}function eR(){var s=0,l=0;if(o[7792]|0||(K9(9900),rr(43,9900,U|0)|0,l=7792,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9900)|0)){s=9900,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));K9(9900)}return 9900}function tQe(s){return s=s|0,0}function rQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=eR()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],W9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(nQe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function W9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function nQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=iQe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,sQe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],W9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,oQe(s,k),aQe(k),C=M;return}}function iQe(s){return s=s|0,357913941}function sQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function oQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function aQe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function K9(s){s=s|0,uQe(s)}function lQe(s){s=s|0,cQe(s+24|0)}function cQe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function uQe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,22,l,AQe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function AQe(){return 1344}function fQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;c=C,C=C+16|0,f=c+8|0,d=c,m=pQe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],hQe(l,f),C=c}function pQe(s){return s=s|0,(n[(eR()|0)+24>>2]|0)+(s*12|0)|0}function hQe(s,l){s=s|0,l=l|0;var c=0;c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),tf[c&127](s)}function gQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=tR()|0,s=dQe(c)|0,hn(m,l,d,s,mQe(c,f)|0,f)}function tR(){var s=0,l=0;if(o[7800]|0||(V9(9936),rr(44,9936,U|0)|0,l=7800,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9936)|0)){s=9936,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));V9(9936)}return 9936}function dQe(s){return s=s|0,s|0}function mQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=tR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(z9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(yQe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function z9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function yQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=EQe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,CQe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,z9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,wQe(s,d),IQe(d),C=k;return}}function EQe(s){return s=s|0,536870911}function CQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function wQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function IQe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function V9(s){s=s|0,DQe(s)}function BQe(s){s=s|0,vQe(s+24|0)}function vQe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function DQe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,23,l,B9()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function PQe(s,l){s=s|0,l=l|0,bQe(n[(SQe(s)|0)>>2]|0,l)}function SQe(s){return s=s|0,(n[(tR()|0)+24>>2]|0)+(s<<3)|0}function bQe(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,HF(f,l),l=qF(f,l)|0,tf[s&127](l),C=c}function xQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=rR()|0,s=kQe(c)|0,hn(m,l,d,s,QQe(c,f)|0,f)}function rR(){var s=0,l=0;if(o[7808]|0||(X9(9972),rr(45,9972,U|0)|0,l=7808,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9972)|0)){s=9972,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));X9(9972)}return 9972}function kQe(s){return s=s|0,s|0}function QQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=rR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(J9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(FQe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function J9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function FQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=RQe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,TQe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,J9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,LQe(s,d),NQe(d),C=k;return}}function RQe(s){return s=s|0,536870911}function TQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function LQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function NQe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function X9(s){s=s|0,UQe(s)}function OQe(s){s=s|0,MQe(s+24|0)}function MQe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function UQe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,9,l,_Qe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function _Qe(){return 1348}function HQe(s,l){return s=s|0,l=l|0,GQe(n[(qQe(s)|0)>>2]|0,l)|0}function qQe(s){return s=s|0,(n[(rR()|0)+24>>2]|0)+(s<<3)|0}function GQe(s,l){s=s|0,l=l|0;var c=0,f=0;return c=C,C=C+16|0,f=c,Z9(f,l),l=$9(f,l)|0,l=sD(Og[s&31](l)|0)|0,C=c,l|0}function Z9(s,l){s=s|0,l=l|0}function $9(s,l){return s=s|0,l=l|0,jQe(l)|0}function jQe(s){return s=s|0,s|0}function YQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=nR()|0,s=WQe(c)|0,hn(m,l,d,s,KQe(c,f)|0,f)}function nR(){var s=0,l=0;if(o[7816]|0||(t5(10008),rr(46,10008,U|0)|0,l=7816,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10008)|0)){s=10008,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));t5(10008)}return 10008}function WQe(s){return s=s|0,s|0}function KQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=nR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(e5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(zQe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function e5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function zQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=VQe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,JQe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,e5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,XQe(s,d),ZQe(d),C=k;return}}function VQe(s){return s=s|0,536870911}function JQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function XQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function ZQe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function t5(s){s=s|0,tFe(s)}function $Qe(s){s=s|0,eFe(s+24|0)}function eFe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function tFe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,15,l,m9()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function rFe(s){return s=s|0,iFe(n[(nFe(s)|0)>>2]|0)|0}function nFe(s){return s=s|0,(n[(nR()|0)+24>>2]|0)+(s<<3)|0}function iFe(s){return s=s|0,sD(CD[s&7]()|0)|0}function sFe(){var s=0;return o[7832]|0||(pFe(10052),rr(25,10052,U|0)|0,s=7832,n[s>>2]=1,n[s+4>>2]=0),10052}function oFe(s,l){s=s|0,l=l|0,n[s>>2]=aFe()|0,n[s+4>>2]=lFe()|0,n[s+12>>2]=l,n[s+8>>2]=cFe()|0,n[s+32>>2]=2}function aFe(){return 11709}function lFe(){return 1188}function cFe(){return aD()|0}function uFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&(AFe(c),gt(c)):l|0&&(Su(l),gt(l))}function xp(s,l){return s=s|0,l=l|0,l&s|0}function AFe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function aD(){var s=0;return o[7824]|0||(n[2511]=fFe()|0,n[2512]=0,s=7824,n[s>>2]=1,n[s+4>>2]=0),10044}function fFe(){return 0}function pFe(s){s=s|0,Dp(s)}function hFe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0;l=C,C=C+32|0,c=l+24|0,m=l+16|0,d=l+8|0,f=l,gFe(s,4827),dFe(s,4834,3)|0,mFe(s,3682,47)|0,n[m>>2]=9,n[m+4>>2]=0,n[c>>2]=n[m>>2],n[c+4>>2]=n[m+4>>2],yFe(s,4841,c)|0,n[d>>2]=1,n[d+4>>2]=0,n[c>>2]=n[d>>2],n[c+4>>2]=n[d+4>>2],EFe(s,4871,c)|0,n[f>>2]=10,n[f+4>>2]=0,n[c>>2]=n[f>>2],n[c+4>>2]=n[f+4>>2],CFe(s,4891,c)|0,C=l}function gFe(s,l){s=s|0,l=l|0;var c=0;c=ZRe()|0,n[s>>2]=c,$Re(c,l),kp(n[s>>2]|0)}function dFe(s,l,c){return s=s|0,l=l|0,c=c|0,NRe(s,pn(l)|0,c,0),s|0}function mFe(s,l,c){return s=s|0,l=l|0,c=c|0,wRe(s,pn(l)|0,c,0),s|0}function yFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],rRe(s,l,d),C=f,s|0}function EFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],OFe(s,l,d),C=f,s|0}function CFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],wFe(s,l,d),C=f,s|0}function wFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],IFe(s,c,d,1),C=f}function IFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=iR()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=BFe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,vFe(m,f)|0,f),C=d}function iR(){var s=0,l=0;if(o[7840]|0||(n5(10100),rr(48,10100,U|0)|0,l=7840,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10100)|0)){s=10100,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));n5(10100)}return 10100}function BFe(s){return s=s|0,0}function vFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=iR()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],r5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(DFe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function r5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function DFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=PFe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,SFe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],r5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,bFe(s,k),xFe(k),C=M;return}}function PFe(s){return s=s|0,357913941}function SFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function bFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function xFe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function n5(s){s=s|0,FFe(s)}function kFe(s){s=s|0,QFe(s+24|0)}function QFe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function FFe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,6,l,RFe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function RFe(){return 1364}function TFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=LFe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=NFe(l,d,c)|0,C=f,c|0}function LFe(s){return s=s|0,(n[(iR()|0)+24>>2]|0)+(s*12|0)|0}function NFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;return m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),ZA(d,c),d=$A(d,c)|0,d=u9(RR[f&15](s,d)|0)|0,C=m,d|0}function OFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],MFe(s,c,d,0),C=f}function MFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=sR()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=UFe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,_Fe(m,f)|0,f),C=d}function sR(){var s=0,l=0;if(o[7848]|0||(s5(10136),rr(49,10136,U|0)|0,l=7848,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10136)|0)){s=10136,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));s5(10136)}return 10136}function UFe(s){return s=s|0,0}function _Fe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=sR()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],i5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(HFe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function i5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function HFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=qFe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,GFe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],i5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,jFe(s,k),YFe(k),C=M;return}}function qFe(s){return s=s|0,357913941}function GFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function jFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function YFe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function s5(s){s=s|0,zFe(s)}function WFe(s){s=s|0,KFe(s+24|0)}function KFe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function zFe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,9,l,VFe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function VFe(){return 1372}function JFe(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=XFe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ZFe(l,d,c),C=f}function XFe(s){return s=s|0,(n[(sR()|0)+24>>2]|0)+(s*12|0)|0}function ZFe(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=Ze;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),$Fe(d,c),B=y(eRe(d,c)),E7[f&1](s,B),C=m}function $Fe(s,l){s=s|0,l=+l}function eRe(s,l){return s=s|0,l=+l,y(tRe(l))}function tRe(s){return s=+s,y(s)}function rRe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],nRe(s,c,d,0),C=f}function nRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=oR()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=iRe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,sRe(m,f)|0,f),C=d}function oR(){var s=0,l=0;if(o[7856]|0||(a5(10172),rr(50,10172,U|0)|0,l=7856,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10172)|0)){s=10172,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));a5(10172)}return 10172}function iRe(s){return s=s|0,0}function sRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=oR()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],o5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(oRe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function o5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function oRe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=aRe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,lRe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],o5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,cRe(s,k),uRe(k),C=M;return}}function aRe(s){return s=s|0,357913941}function lRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function cRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function uRe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function a5(s){s=s|0,pRe(s)}function ARe(s){s=s|0,fRe(s+24|0)}function fRe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function pRe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,3,l,hRe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function hRe(){return 1380}function gRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,m=d+8|0,B=d,k=dRe(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],mRe(l,m,c,f),C=d}function dRe(s){return s=s|0,(n[(oR()|0)+24>>2]|0)+(s*12|0)|0}function mRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;k=C,C=C+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(d=n[(n[s>>2]|0)+d>>2]|0),ZA(m,c),m=$A(m,c)|0,yRe(B,f),B=ERe(B,f)|0,Hw[d&15](s,m,B),C=k}function yRe(s,l){s=s|0,l=l|0}function ERe(s,l){return s=s|0,l=l|0,CRe(l)|0}function CRe(s){return s=s|0,(s|0)!=0|0}function wRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=aR()|0,s=IRe(c)|0,hn(m,l,d,s,BRe(c,f)|0,f)}function aR(){var s=0,l=0;if(o[7864]|0||(c5(10208),rr(51,10208,U|0)|0,l=7864,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10208)|0)){s=10208,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));c5(10208)}return 10208}function IRe(s){return s=s|0,s|0}function BRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=aR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(l5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(vRe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function l5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function vRe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=DRe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,PRe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,l5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,SRe(s,d),bRe(d),C=k;return}}function DRe(s){return s=s|0,536870911}function PRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function SRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function bRe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function c5(s){s=s|0,QRe(s)}function xRe(s){s=s|0,kRe(s+24|0)}function kRe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function QRe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,24,l,FRe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function FRe(){return 1392}function RRe(s,l){s=s|0,l=l|0,LRe(n[(TRe(s)|0)>>2]|0,l)}function TRe(s){return s=s|0,(n[(aR()|0)+24>>2]|0)+(s<<3)|0}function LRe(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,Z9(f,l),l=$9(f,l)|0,tf[s&127](l),C=c}function NRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=lR()|0,s=ORe(c)|0,hn(m,l,d,s,MRe(c,f)|0,f)}function lR(){var s=0,l=0;if(o[7872]|0||(A5(10244),rr(52,10244,U|0)|0,l=7872,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10244)|0)){s=10244,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));A5(10244)}return 10244}function ORe(s){return s=s|0,s|0}function MRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=lR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(u5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(URe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function u5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function URe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=_Re(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,HRe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,u5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,qRe(s,d),GRe(d),C=k;return}}function _Re(s){return s=s|0,536870911}function HRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function qRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function GRe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function A5(s){s=s|0,WRe(s)}function jRe(s){s=s|0,YRe(s+24|0)}function YRe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function WRe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,16,l,KRe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function KRe(){return 1400}function zRe(s){return s=s|0,JRe(n[(VRe(s)|0)>>2]|0)|0}function VRe(s){return s=s|0,(n[(lR()|0)+24>>2]|0)+(s<<3)|0}function JRe(s){return s=s|0,XRe(CD[s&7]()|0)|0}function XRe(s){return s=s|0,s|0}function ZRe(){var s=0;return o[7880]|0||(sTe(10280),rr(25,10280,U|0)|0,s=7880,n[s>>2]=1,n[s+4>>2]=0),10280}function $Re(s,l){s=s|0,l=l|0,n[s>>2]=eTe()|0,n[s+4>>2]=tTe()|0,n[s+12>>2]=l,n[s+8>>2]=rTe()|0,n[s+32>>2]=4}function eTe(){return 11711}function tTe(){return 1356}function rTe(){return aD()|0}function nTe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&(iTe(c),gt(c)):l|0&&(Pg(l),gt(l))}function iTe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function sTe(s){s=s|0,Dp(s)}function oTe(s){s=s|0,aTe(s,4920),lTe(s)|0,cTe(s)|0}function aTe(s,l){s=s|0,l=l|0;var c=0;c=R9()|0,n[s>>2]=c,kTe(c,l),kp(n[s>>2]|0)}function lTe(s){s=s|0;var l=0;return l=n[s>>2]|0,Qg(l,CTe()|0),s|0}function cTe(s){s=s|0;var l=0;return l=n[s>>2]|0,Qg(l,uTe()|0),s|0}function uTe(){var s=0;return o[7888]|0||(f5(10328),rr(53,10328,U|0)|0,s=7888,n[s>>2]=1,n[s+4>>2]=0),Tr(10328)|0||f5(10328),10328}function Qg(s,l){s=s|0,l=l|0,hn(s,0,l,0,0,0)}function f5(s){s=s|0,pTe(s),Fg(s,10)}function ATe(s){s=s|0,fTe(s+24|0)}function fTe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function pTe(s){s=s|0;var l=0;l=Kr()|0,zr(s,5,1,l,mTe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function hTe(s,l,c){s=s|0,l=l|0,c=+c,gTe(s,l,c)}function Fg(s,l){s=s|0,l=l|0,n[s+20>>2]=l}function gTe(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,m=f+8|0,k=f+13|0,d=f,B=f+12|0,ZA(k,l),n[m>>2]=$A(k,l)|0,Qu(B,c),E[d>>3]=+Fu(B,c),dTe(s,m,d),C=f}function dTe(s,l,c){s=s|0,l=l|0,c=c|0,Y(s+8|0,n[l>>2]|0,+E[c>>3]),o[s+24>>0]=1}function mTe(){return 1404}function yTe(s,l){return s=s|0,l=+l,ETe(s,l)|0}function ETe(s,l){s=s|0,l=+l;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return f=C,C=C+16|0,m=f+4|0,B=f+8|0,k=f,d=Ka(8)|0,c=d,Q=Kt(16)|0,ZA(m,s),s=$A(m,s)|0,Qu(B,l),Y(Q,s,+Fu(B,l)),B=c+4|0,n[B>>2]=Q,s=Kt(8)|0,B=n[B>>2]|0,n[k>>2]=0,n[m>>2]=n[k>>2],KF(s,B,m),n[d>>2]=s,C=f,c|0}function CTe(){var s=0;return o[7896]|0||(p5(10364),rr(54,10364,U|0)|0,s=7896,n[s>>2]=1,n[s+4>>2]=0),Tr(10364)|0||p5(10364),10364}function p5(s){s=s|0,BTe(s),Fg(s,55)}function wTe(s){s=s|0,ITe(s+24|0)}function ITe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function BTe(s){s=s|0;var l=0;l=Kr()|0,zr(s,5,4,l,STe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function vTe(s){s=s|0,DTe(s)}function DTe(s){s=s|0,PTe(s)}function PTe(s){s=s|0,h5(s+8|0),o[s+24>>0]=1}function h5(s){s=s|0,n[s>>2]=0,E[s+8>>3]=0}function STe(){return 1424}function bTe(){return xTe()|0}function xTe(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0;return l=C,C=C+16|0,d=l+4|0,B=l,c=Ka(8)|0,s=c,f=Kt(16)|0,h5(f),m=s+4|0,n[m>>2]=f,f=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],KF(f,m,d),n[c>>2]=f,C=l,s|0}function kTe(s,l){s=s|0,l=l|0,n[s>>2]=QTe()|0,n[s+4>>2]=FTe()|0,n[s+12>>2]=l,n[s+8>>2]=RTe()|0,n[s+32>>2]=5}function QTe(){return 11710}function FTe(){return 1416}function RTe(){return lD()|0}function TTe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&(LTe(c),gt(c)):l|0&&gt(l)}function LTe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function lD(){var s=0;return o[7904]|0||(n[2600]=NTe()|0,n[2601]=0,s=7904,n[s>>2]=1,n[s+4>>2]=0),10400}function NTe(){return n[357]|0}function OTe(s){s=s|0,MTe(s,4926),UTe(s)|0}function MTe(s,l){s=s|0,l=l|0;var c=0;c=r9()|0,n[s>>2]=c,JTe(c,l),kp(n[s>>2]|0)}function UTe(s){s=s|0;var l=0;return l=n[s>>2]|0,Qg(l,_Te()|0),s|0}function _Te(){var s=0;return o[7912]|0||(g5(10412),rr(56,10412,U|0)|0,s=7912,n[s>>2]=1,n[s+4>>2]=0),Tr(10412)|0||g5(10412),10412}function g5(s){s=s|0,GTe(s),Fg(s,57)}function HTe(s){s=s|0,qTe(s+24|0)}function qTe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function GTe(s){s=s|0;var l=0;l=Kr()|0,zr(s,5,5,l,KTe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function jTe(s){s=s|0,YTe(s)}function YTe(s){s=s|0,WTe(s)}function WTe(s){s=s|0;var l=0,c=0;l=s+8|0,c=l+48|0;do n[l>>2]=0,l=l+4|0;while((l|0)<(c|0));o[s+56>>0]=1}function KTe(){return 1432}function zTe(){return VTe()|0}function VTe(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0,k=0;B=C,C=C+16|0,s=B+4|0,l=B,c=Ka(8)|0,f=c,d=Kt(48)|0,m=d,k=m+48|0;do n[m>>2]=0,m=m+4|0;while((m|0)<(k|0));return m=f+4|0,n[m>>2]=d,k=Kt(8)|0,m=n[m>>2]|0,n[l>>2]=0,n[s>>2]=n[l>>2],n9(k,m,s),n[c>>2]=k,C=B,f|0}function JTe(s,l){s=s|0,l=l|0,n[s>>2]=XTe()|0,n[s+4>>2]=ZTe()|0,n[s+12>>2]=l,n[s+8>>2]=$Te()|0,n[s+32>>2]=6}function XTe(){return 11704}function ZTe(){return 1436}function $Te(){return lD()|0}function eLe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&(tLe(c),gt(c)):l|0&&gt(l)}function tLe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function rLe(s){s=s|0,nLe(s,4933),iLe(s)|0,sLe(s)|0}function nLe(s,l){s=s|0,l=l|0;var c=0;c=xLe()|0,n[s>>2]=c,kLe(c,l),kp(n[s>>2]|0)}function iLe(s){s=s|0;var l=0;return l=n[s>>2]|0,Qg(l,ELe()|0),s|0}function sLe(s){s=s|0;var l=0;return l=n[s>>2]|0,Qg(l,oLe()|0),s|0}function oLe(){var s=0;return o[7920]|0||(d5(10452),rr(58,10452,U|0)|0,s=7920,n[s>>2]=1,n[s+4>>2]=0),Tr(10452)|0||d5(10452),10452}function d5(s){s=s|0,cLe(s),Fg(s,1)}function aLe(s){s=s|0,lLe(s+24|0)}function lLe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function cLe(s){s=s|0;var l=0;l=Kr()|0,zr(s,5,1,l,pLe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function uLe(s,l,c){s=s|0,l=+l,c=+c,ALe(s,l,c)}function ALe(s,l,c){s=s|0,l=+l,c=+c;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+32|0,m=f+8|0,k=f+17|0,d=f,B=f+16|0,Qu(k,l),E[m>>3]=+Fu(k,l),Qu(B,c),E[d>>3]=+Fu(B,c),fLe(s,m,d),C=f}function fLe(s,l,c){s=s|0,l=l|0,c=c|0,m5(s+8|0,+E[l>>3],+E[c>>3]),o[s+24>>0]=1}function m5(s,l,c){s=s|0,l=+l,c=+c,E[s>>3]=l,E[s+8>>3]=c}function pLe(){return 1472}function hLe(s,l){return s=+s,l=+l,gLe(s,l)|0}function gLe(s,l){s=+s,l=+l;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return f=C,C=C+16|0,B=f+4|0,k=f+8|0,Q=f,d=Ka(8)|0,c=d,m=Kt(16)|0,Qu(B,s),s=+Fu(B,s),Qu(k,l),m5(m,s,+Fu(k,l)),k=c+4|0,n[k>>2]=m,m=Kt(8)|0,k=n[k>>2]|0,n[Q>>2]=0,n[B>>2]=n[Q>>2],y5(m,k,B),n[d>>2]=m,C=f,c|0}function y5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1452,n[c+12>>2]=l,n[s+4>>2]=c}function dLe(s){s=s|0,Jm(s),gt(s)}function mLe(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function yLe(s){s=s|0,gt(s)}function ELe(){var s=0;return o[7928]|0||(E5(10488),rr(59,10488,U|0)|0,s=7928,n[s>>2]=1,n[s+4>>2]=0),Tr(10488)|0||E5(10488),10488}function E5(s){s=s|0,ILe(s),Fg(s,60)}function CLe(s){s=s|0,wLe(s+24|0)}function wLe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function ILe(s){s=s|0;var l=0;l=Kr()|0,zr(s,5,6,l,PLe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function BLe(s){s=s|0,vLe(s)}function vLe(s){s=s|0,DLe(s)}function DLe(s){s=s|0,C5(s+8|0),o[s+24>>0]=1}function C5(s){s=s|0,n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,n[s+12>>2]=0}function PLe(){return 1492}function SLe(){return bLe()|0}function bLe(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0;return l=C,C=C+16|0,d=l+4|0,B=l,c=Ka(8)|0,s=c,f=Kt(16)|0,C5(f),m=s+4|0,n[m>>2]=f,f=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],y5(f,m,d),n[c>>2]=f,C=l,s|0}function xLe(){var s=0;return o[7936]|0||(NLe(10524),rr(25,10524,U|0)|0,s=7936,n[s>>2]=1,n[s+4>>2]=0),10524}function kLe(s,l){s=s|0,l=l|0,n[s>>2]=QLe()|0,n[s+4>>2]=FLe()|0,n[s+12>>2]=l,n[s+8>>2]=RLe()|0,n[s+32>>2]=7}function QLe(){return 11700}function FLe(){return 1484}function RLe(){return lD()|0}function TLe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&(LLe(c),gt(c)):l|0&&gt(l)}function LLe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function NLe(s){s=s|0,Dp(s)}function OLe(s,l,c){s=s|0,l=l|0,c=c|0,s=pn(l)|0,l=MLe(c)|0,c=ULe(c,0)|0,gNe(s,l,c,cR()|0,0)}function MLe(s){return s=s|0,s|0}function ULe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=cR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(I5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(WLe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function cR(){var s=0,l=0;if(o[7944]|0||(w5(10568),rr(61,10568,U|0)|0,l=7944,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10568)|0)){s=10568,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));w5(10568)}return 10568}function w5(s){s=s|0,qLe(s)}function _Le(s){s=s|0,HLe(s+24|0)}function HLe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function qLe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,17,l,C9()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function GLe(s){return s=s|0,YLe(n[(jLe(s)|0)>>2]|0)|0}function jLe(s){return s=s|0,(n[(cR()|0)+24>>2]|0)+(s<<3)|0}function YLe(s){return s=s|0,oD(CD[s&7]()|0)|0}function I5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function WLe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=KLe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,zLe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,I5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,VLe(s,d),JLe(d),C=k;return}}function KLe(s){return s=s|0,536870911}function zLe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function VLe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function JLe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function XLe(){ZLe()}function ZLe(){$Le(10604)}function $Le(s){s=s|0,eNe(s,4955)}function eNe(s,l){s=s|0,l=l|0;var c=0;c=tNe()|0,n[s>>2]=c,rNe(c,l),kp(n[s>>2]|0)}function tNe(){var s=0;return o[7952]|0||(ANe(10612),rr(25,10612,U|0)|0,s=7952,n[s>>2]=1,n[s+4>>2]=0),10612}function rNe(s,l){s=s|0,l=l|0,n[s>>2]=oNe()|0,n[s+4>>2]=aNe()|0,n[s+12>>2]=l,n[s+8>>2]=lNe()|0,n[s+32>>2]=8}function kp(s){s=s|0;var l=0,c=0;l=C,C=C+16|0,c=l,Ym()|0,n[c>>2]=s,nNe(10608,c),C=l}function Ym(){return o[11714]|0||(n[2652]=0,rr(62,10608,U|0)|0,o[11714]=1),10608}function nNe(s,l){s=s|0,l=l|0;var c=0;c=Kt(8)|0,n[c+4>>2]=n[l>>2],n[c>>2]=n[s>>2],n[s>>2]=c}function iNe(s){s=s|0,sNe(s)}function sNe(s){s=s|0;var l=0,c=0;if(l=n[s>>2]|0,l|0)do c=l,l=n[l>>2]|0,gt(c);while((l|0)!=0);n[s>>2]=0}function oNe(){return 11715}function aNe(){return 1496}function lNe(){return aD()|0}function cNe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&(uNe(c),gt(c)):l|0&&gt(l)}function uNe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function ANe(s){s=s|0,Dp(s)}function fNe(s,l){s=s|0,l=l|0;var c=0,f=0;Ym()|0,c=n[2652]|0;e:do if(c|0){for(;f=n[c+4>>2]|0,!(f|0&&(n7(uR(f)|0,s)|0)==0);)if(c=n[c>>2]|0,!c)break e;pNe(f,l)}while(0)}function uR(s){return s=s|0,n[s+12>>2]|0}function pNe(s,l){s=s|0,l=l|0;var c=0;s=s+36|0,c=n[s>>2]|0,c|0&&(GA(c),gt(c)),c=Kt(4)|0,Jj(c,l),n[s>>2]=c}function AR(){return o[11716]|0||(n[2664]=0,rr(63,10656,U|0)|0,o[11716]=1),10656}function B5(){var s=0;return o[11717]|0?s=n[2665]|0:(hNe(),n[2665]=1504,o[11717]=1,s=1504),s|0}function hNe(){o[11740]|0||(o[11718]=gr(gr(8,0)|0,0)|0,o[11719]=gr(gr(0,0)|0,0)|0,o[11720]=gr(gr(0,16)|0,0)|0,o[11721]=gr(gr(8,0)|0,0)|0,o[11722]=gr(gr(0,0)|0,0)|0,o[11723]=gr(gr(8,0)|0,0)|0,o[11724]=gr(gr(0,0)|0,0)|0,o[11725]=gr(gr(8,0)|0,0)|0,o[11726]=gr(gr(0,0)|0,0)|0,o[11727]=gr(gr(8,0)|0,0)|0,o[11728]=gr(gr(0,0)|0,0)|0,o[11729]=gr(gr(0,0)|0,32)|0,o[11730]=gr(gr(0,0)|0,32)|0,o[11740]=1)}function v5(){return 1572}function gNe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0,O=0;m=C,C=C+32|0,O=m+16|0,M=m+12|0,Q=m+8|0,k=m+4|0,B=m,n[O>>2]=s,n[M>>2]=l,n[Q>>2]=c,n[k>>2]=f,n[B>>2]=d,AR()|0,dNe(10656,O,M,Q,k,B),C=m}function dNe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0;B=Kt(24)|0,$j(B+4|0,n[l>>2]|0,n[c>>2]|0,n[f>>2]|0,n[d>>2]|0,n[m>>2]|0),n[B>>2]=n[s>>2],n[s>>2]=B}function D5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0,et=0,Xe=0,lt=0;if(lt=C,C=C+32|0,Me=lt+20|0,Qe=lt+8|0,et=lt+4|0,Xe=lt,l=n[l>>2]|0,l|0){je=Me+4|0,Q=Me+8|0,M=Qe+4|0,O=Qe+8|0,G=Qe+8|0,se=Me+8|0;do{if(B=l+4|0,k=fR(B)|0,k|0){if(d=Lw(k)|0,n[Me>>2]=0,n[je>>2]=0,n[Q>>2]=0,f=(Nw(k)|0)+1|0,mNe(Me,f),f|0)for(;f=f+-1|0,xc(Qe,n[d>>2]|0),m=n[je>>2]|0,m>>>0<(n[se>>2]|0)>>>0?(n[m>>2]=n[Qe>>2],n[je>>2]=(n[je>>2]|0)+4):pR(Me,Qe),f;)d=d+4|0;f=Ow(k)|0,n[Qe>>2]=0,n[M>>2]=0,n[O>>2]=0;e:do if(n[f>>2]|0)for(d=0,m=0;;){if((d|0)==(m|0)?yNe(Qe,f):(n[d>>2]=n[f>>2],n[M>>2]=(n[M>>2]|0)+4),f=f+4|0,!(n[f>>2]|0))break e;d=n[M>>2]|0,m=n[G>>2]|0}while(0);n[et>>2]=cD(B)|0,n[Xe>>2]=Tr(k)|0,ENe(c,s,et,Xe,Me,Qe),hR(Qe),ef(Me)}l=n[l>>2]|0}while((l|0)!=0)}C=lt}function fR(s){return s=s|0,n[s+12>>2]|0}function Lw(s){return s=s|0,n[s+12>>2]|0}function Nw(s){return s=s|0,n[s+16>>2]|0}function mNe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;d=C,C=C+32|0,c=d,f=n[s>>2]|0,(n[s+8>>2]|0)-f>>2>>>0<l>>>0&&(R5(c,l,(n[s+4>>2]|0)-f>>2,s+8|0),T5(s,c),L5(c)),C=d}function pR(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0;if(B=C,C=C+32|0,c=B,f=s+4|0,d=((n[f>>2]|0)-(n[s>>2]|0)>>2)+1|0,m=F5(s)|0,m>>>0<d>>>0)Jr(s);else{k=n[s>>2]|0,M=(n[s+8>>2]|0)-k|0,Q=M>>1,R5(c,M>>2>>>0<m>>>1>>>0?Q>>>0<d>>>0?d:Q:m,(n[f>>2]|0)-k>>2,s+8|0),m=c+8|0,n[n[m>>2]>>2]=n[l>>2],n[m>>2]=(n[m>>2]|0)+4,T5(s,c),L5(c),C=B;return}}function Ow(s){return s=s|0,n[s+8>>2]|0}function yNe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0;if(B=C,C=C+32|0,c=B,f=s+4|0,d=((n[f>>2]|0)-(n[s>>2]|0)>>2)+1|0,m=Q5(s)|0,m>>>0<d>>>0)Jr(s);else{k=n[s>>2]|0,M=(n[s+8>>2]|0)-k|0,Q=M>>1,MNe(c,M>>2>>>0<m>>>1>>>0?Q>>>0<d>>>0?d:Q:m,(n[f>>2]|0)-k>>2,s+8|0),m=c+8|0,n[n[m>>2]>>2]=n[l>>2],n[m>>2]=(n[m>>2]|0)+4,UNe(s,c),_Ne(c),C=B;return}}function cD(s){return s=s|0,n[s>>2]|0}function ENe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,CNe(s,l,c,f,d,m)}function hR(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-4-f|0)>>>2)<<2)),gt(c))}function ef(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-4-f|0)>>>2)<<2)),gt(c))}function CNe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,G=0;B=C,C=C+48|0,O=B+40|0,k=B+32|0,G=B+24|0,Q=B+12|0,M=B,za(k),s=da(s)|0,n[G>>2]=n[l>>2],c=n[c>>2]|0,f=n[f>>2]|0,gR(Q,d),wNe(M,m),n[O>>2]=n[G>>2],INe(s,O,c,f,Q,M),hR(M),ef(Q),Va(k),C=B}function gR(s,l){s=s|0,l=l|0;var c=0,f=0;n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,c=l+4|0,f=(n[c>>2]|0)-(n[l>>2]|0)>>2,f|0&&(NNe(s,f),ONe(s,n[l>>2]|0,n[c>>2]|0,f))}function wNe(s,l){s=s|0,l=l|0;var c=0,f=0;n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,c=l+4|0,f=(n[c>>2]|0)-(n[l>>2]|0)>>2,f|0&&(TNe(s,f),LNe(s,n[l>>2]|0,n[c>>2]|0,f))}function INe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,G=0;B=C,C=C+32|0,O=B+28|0,G=B+24|0,k=B+12|0,Q=B,M=Sl(BNe()|0)|0,n[G>>2]=n[l>>2],n[O>>2]=n[G>>2],l=Rg(O)|0,c=P5(c)|0,f=dR(f)|0,n[k>>2]=n[d>>2],O=d+4|0,n[k+4>>2]=n[O>>2],G=d+8|0,n[k+8>>2]=n[G>>2],n[G>>2]=0,n[O>>2]=0,n[d>>2]=0,d=mR(k)|0,n[Q>>2]=n[m>>2],O=m+4|0,n[Q+4>>2]=n[O>>2],G=m+8|0,n[Q+8>>2]=n[G>>2],n[G>>2]=0,n[O>>2]=0,n[m>>2]=0,ao(0,M|0,s|0,l|0,c|0,f|0,d|0,vNe(Q)|0)|0,hR(Q),ef(k),C=B}function BNe(){var s=0;return o[7968]|0||(FNe(10708),s=7968,n[s>>2]=1,n[s+4>>2]=0),10708}function Rg(s){return s=s|0,b5(s)|0}function P5(s){return s=s|0,S5(s)|0}function dR(s){return s=s|0,oD(s)|0}function mR(s){return s=s|0,PNe(s)|0}function vNe(s){return s=s|0,DNe(s)|0}function DNe(s){s=s|0;var l=0,c=0,f=0;if(f=(n[s+4>>2]|0)-(n[s>>2]|0)|0,c=f>>2,f=Ka(f+4|0)|0,n[f>>2]=c,c|0){l=0;do n[f+4+(l<<2)>>2]=S5(n[(n[s>>2]|0)+(l<<2)>>2]|0)|0,l=l+1|0;while((l|0)!=(c|0))}return f|0}function S5(s){return s=s|0,s|0}function PNe(s){s=s|0;var l=0,c=0,f=0;if(f=(n[s+4>>2]|0)-(n[s>>2]|0)|0,c=f>>2,f=Ka(f+4|0)|0,n[f>>2]=c,c|0){l=0;do n[f+4+(l<<2)>>2]=b5((n[s>>2]|0)+(l<<2)|0)|0,l=l+1|0;while((l|0)!=(c|0))}return f|0}function b5(s){s=s|0;var l=0,c=0,f=0,d=0;return d=C,C=C+32|0,l=d+12|0,c=d,f=xF(x5()|0)|0,f?(kF(l,f),QF(c,l),lUe(s,c),s=FF(l)|0):s=SNe(s)|0,C=d,s|0}function x5(){var s=0;return o[7960]|0||(QNe(10664),rr(25,10664,U|0)|0,s=7960,n[s>>2]=1,n[s+4>>2]=0),10664}function SNe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;return c=C,C=C+16|0,d=c+4|0,B=c,f=Ka(8)|0,l=f,k=Kt(4)|0,n[k>>2]=n[s>>2],m=l+4|0,n[m>>2]=k,s=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],k5(s,m,d),n[f>>2]=s,C=c,l|0}function k5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1656,n[c+12>>2]=l,n[s+4>>2]=c}function bNe(s){s=s|0,Jm(s),gt(s)}function xNe(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function kNe(s){s=s|0,gt(s)}function QNe(s){s=s|0,Dp(s)}function FNe(s){s=s|0,bl(s,RNe()|0,5)}function RNe(){return 1676}function TNe(s,l){s=s|0,l=l|0;var c=0;if((Q5(s)|0)>>>0<l>>>0&&Jr(s),l>>>0>1073741823)Rt();else{c=Kt(l<<2)|0,n[s+4>>2]=c,n[s>>2]=c,n[s+8>>2]=c+(l<<2);return}}function LNe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,f=s+4|0,s=c-l|0,(s|0)>0&&(Dr(n[f>>2]|0,l|0,s|0)|0,n[f>>2]=(n[f>>2]|0)+(s>>>2<<2))}function Q5(s){return s=s|0,1073741823}function NNe(s,l){s=s|0,l=l|0;var c=0;if((F5(s)|0)>>>0<l>>>0&&Jr(s),l>>>0>1073741823)Rt();else{c=Kt(l<<2)|0,n[s+4>>2]=c,n[s>>2]=c,n[s+8>>2]=c+(l<<2);return}}function ONe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,f=s+4|0,s=c-l|0,(s|0)>0&&(Dr(n[f>>2]|0,l|0,s|0)|0,n[f>>2]=(n[f>>2]|0)+(s>>>2<<2))}function F5(s){return s=s|0,1073741823}function MNe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>1073741823)Rt();else{d=Kt(l<<2)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<2)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<2)}function UNe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function _Ne(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-4-l|0)>>>2)<<2)),s=n[s>>2]|0,s|0&&gt(s)}function R5(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>1073741823)Rt();else{d=Kt(l<<2)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<2)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<2)}function T5(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function L5(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-4-l|0)>>>2)<<2)),s=n[s>>2]|0,s|0&&gt(s)}function HNe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0;if(Qe=C,C=C+32|0,O=Qe+20|0,G=Qe+12|0,M=Qe+16|0,se=Qe+4|0,je=Qe,Me=Qe+8|0,k=B5()|0,m=n[k>>2]|0,B=n[m>>2]|0,B|0)for(Q=n[k+8>>2]|0,k=n[k+4>>2]|0;xc(O,B),qNe(s,O,k,Q),m=m+4|0,B=n[m>>2]|0,B;)Q=Q+1|0,k=k+1|0;if(m=v5()|0,B=n[m>>2]|0,B|0)do xc(O,B),n[G>>2]=n[m+4>>2],GNe(l,O,G),m=m+8|0,B=n[m>>2]|0;while((B|0)!=0);if(m=n[(Ym()|0)>>2]|0,m|0)do l=n[m+4>>2]|0,xc(O,n[(Wm(l)|0)>>2]|0),n[G>>2]=uR(l)|0,jNe(c,O,G),m=n[m>>2]|0;while((m|0)!=0);if(xc(M,0),m=AR()|0,n[O>>2]=n[M>>2],D5(O,m,d),m=n[(Ym()|0)>>2]|0,m|0){s=O+4|0,l=O+8|0,c=O+8|0;do{if(Q=n[m+4>>2]|0,xc(G,n[(Wm(Q)|0)>>2]|0),YNe(se,N5(Q)|0),B=n[se>>2]|0,B|0){n[O>>2]=0,n[s>>2]=0,n[l>>2]=0;do xc(je,n[(Wm(n[B+4>>2]|0)|0)>>2]|0),k=n[s>>2]|0,k>>>0<(n[c>>2]|0)>>>0?(n[k>>2]=n[je>>2],n[s>>2]=(n[s>>2]|0)+4):pR(O,je),B=n[B>>2]|0;while((B|0)!=0);WNe(f,G,O),ef(O)}n[Me>>2]=n[G>>2],M=O5(Q)|0,n[O>>2]=n[Me>>2],D5(O,M,d),s9(se),m=n[m>>2]|0}while((m|0)!=0)}C=Qe}function qNe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,iOe(s,l,c,f)}function GNe(s,l,c){s=s|0,l=l|0,c=c|0,nOe(s,l,c)}function Wm(s){return s=s|0,s|0}function jNe(s,l,c){s=s|0,l=l|0,c=c|0,$Ne(s,l,c)}function N5(s){return s=s|0,s+16|0}function YNe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;if(m=C,C=C+16|0,d=m+8|0,c=m,n[s>>2]=0,f=n[l>>2]|0,n[d>>2]=f,n[c>>2]=s,c=ZNe(c)|0,f|0){if(f=Kt(12)|0,B=(M5(d)|0)+4|0,s=n[B+4>>2]|0,l=f+4|0,n[l>>2]=n[B>>2],n[l+4>>2]=s,l=n[n[d>>2]>>2]|0,n[d>>2]=l,!l)s=f;else for(l=f;s=Kt(12)|0,Q=(M5(d)|0)+4|0,k=n[Q+4>>2]|0,B=s+4|0,n[B>>2]=n[Q>>2],n[B+4>>2]=k,n[l>>2]=s,B=n[n[d>>2]>>2]|0,n[d>>2]=B,B;)l=s;n[s>>2]=n[c>>2],n[c>>2]=f}C=m}function WNe(s,l,c){s=s|0,l=l|0,c=c|0,KNe(s,l,c)}function O5(s){return s=s|0,s+24|0}function KNe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+32|0,B=f+24|0,d=f+16|0,k=f+12|0,m=f,za(d),s=da(s)|0,n[k>>2]=n[l>>2],gR(m,c),n[B>>2]=n[k>>2],zNe(s,B,m),ef(m),Va(d),C=f}function zNe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+32|0,B=f+16|0,k=f+12|0,d=f,m=Sl(VNe()|0)|0,n[k>>2]=n[l>>2],n[B>>2]=n[k>>2],l=Rg(B)|0,n[d>>2]=n[c>>2],B=c+4|0,n[d+4>>2]=n[B>>2],k=c+8|0,n[d+8>>2]=n[k>>2],n[k>>2]=0,n[B>>2]=0,n[c>>2]=0,oo(0,m|0,s|0,l|0,mR(d)|0)|0,ef(d),C=f}function VNe(){var s=0;return o[7976]|0||(JNe(10720),s=7976,n[s>>2]=1,n[s+4>>2]=0),10720}function JNe(s){s=s|0,bl(s,XNe()|0,2)}function XNe(){return 1732}function ZNe(s){return s=s|0,n[s>>2]|0}function M5(s){return s=s|0,n[s>>2]|0}function $Ne(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+32|0,m=f+16|0,d=f+8|0,B=f,za(d),s=da(s)|0,n[B>>2]=n[l>>2],c=n[c>>2]|0,n[m>>2]=n[B>>2],U5(s,m,c),Va(d),C=f}function U5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,m=f+4|0,B=f,d=Sl(eOe()|0)|0,n[B>>2]=n[l>>2],n[m>>2]=n[B>>2],l=Rg(m)|0,oo(0,d|0,s|0,l|0,P5(c)|0)|0,C=f}function eOe(){var s=0;return o[7984]|0||(tOe(10732),s=7984,n[s>>2]=1,n[s+4>>2]=0),10732}function tOe(s){s=s|0,bl(s,rOe()|0,2)}function rOe(){return 1744}function nOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+32|0,m=f+16|0,d=f+8|0,B=f,za(d),s=da(s)|0,n[B>>2]=n[l>>2],c=n[c>>2]|0,n[m>>2]=n[B>>2],U5(s,m,c),Va(d),C=f}function iOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+32|0,B=d+16|0,m=d+8|0,k=d,za(m),s=da(s)|0,n[k>>2]=n[l>>2],c=o[c>>0]|0,f=o[f>>0]|0,n[B>>2]=n[k>>2],sOe(s,B,c,f),Va(m),C=d}function sOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,B=d+4|0,k=d,m=Sl(oOe()|0)|0,n[k>>2]=n[l>>2],n[B>>2]=n[k>>2],l=Rg(B)|0,c=Km(c)|0,hc(0,m|0,s|0,l|0,c|0,Km(f)|0)|0,C=d}function oOe(){var s=0;return o[7992]|0||(lOe(10744),s=7992,n[s>>2]=1,n[s+4>>2]=0),10744}function Km(s){return s=s|0,aOe(s)|0}function aOe(s){return s=s|0,s&255|0}function lOe(s){s=s|0,bl(s,cOe()|0,3)}function cOe(){return 1756}function uOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;switch(se=C,C=C+32|0,k=se+8|0,Q=se+4|0,M=se+20|0,O=se,NF(s,0),f=aUe(l)|0,n[k>>2]=0,G=k+4|0,n[G>>2]=0,n[k+8>>2]=0,f<<24>>24){case 0:{o[M>>0]=0,AOe(Q,c,M),uD(s,Q)|0,jA(Q);break}case 8:{G=BR(l)|0,o[M>>0]=8,xc(O,n[G+4>>2]|0),fOe(Q,c,M,O,G+8|0),uD(s,Q)|0,jA(Q);break}case 9:{if(m=BR(l)|0,l=n[m+4>>2]|0,l|0)for(B=k+8|0,d=m+12|0;l=l+-1|0,xc(Q,n[d>>2]|0),f=n[G>>2]|0,f>>>0<(n[B>>2]|0)>>>0?(n[f>>2]=n[Q>>2],n[G>>2]=(n[G>>2]|0)+4):pR(k,Q),l;)d=d+4|0;o[M>>0]=9,xc(O,n[m+8>>2]|0),pOe(Q,c,M,O,k),uD(s,Q)|0,jA(Q);break}default:G=BR(l)|0,o[M>>0]=f,xc(O,n[G+4>>2]|0),hOe(Q,c,M,O),uD(s,Q)|0,jA(Q)}ef(k),C=se}function AOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=C,C=C+16|0,d=f,za(d),l=da(l)|0,SOe(s,l,o[c>>0]|0),Va(d),C=f}function uD(s,l){s=s|0,l=l|0;var c=0;return c=n[s>>2]|0,c|0&&SA(c|0),n[s>>2]=n[l>>2],n[l>>2]=0,s|0}function fOe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0;m=C,C=C+32|0,k=m+16|0,B=m+8|0,Q=m,za(B),l=da(l)|0,c=o[c>>0]|0,n[Q>>2]=n[f>>2],d=n[d>>2]|0,n[k>>2]=n[Q>>2],BOe(s,l,c,k,d),Va(B),C=m}function pOe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0;m=C,C=C+32|0,Q=m+24|0,B=m+16|0,M=m+12|0,k=m,za(B),l=da(l)|0,c=o[c>>0]|0,n[M>>2]=n[f>>2],gR(k,d),n[Q>>2]=n[M>>2],EOe(s,l,c,Q,k),ef(k),Va(B),C=m}function hOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+32|0,B=d+16|0,m=d+8|0,k=d,za(m),l=da(l)|0,c=o[c>>0]|0,n[k>>2]=n[f>>2],n[B>>2]=n[k>>2],gOe(s,l,c,B),Va(m),C=d}function gOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,m=d+4|0,k=d,B=Sl(dOe()|0)|0,c=Km(c)|0,n[k>>2]=n[f>>2],n[m>>2]=n[k>>2],AD(s,oo(0,B|0,l|0,c|0,Rg(m)|0)|0),C=d}function dOe(){var s=0;return o[8e3]|0||(mOe(10756),s=8e3,n[s>>2]=1,n[s+4>>2]=0),10756}function AD(s,l){s=s|0,l=l|0,NF(s,l)}function mOe(s){s=s|0,bl(s,yOe()|0,2)}function yOe(){return 1772}function EOe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0;m=C,C=C+32|0,Q=m+16|0,M=m+12|0,B=m,k=Sl(COe()|0)|0,c=Km(c)|0,n[M>>2]=n[f>>2],n[Q>>2]=n[M>>2],f=Rg(Q)|0,n[B>>2]=n[d>>2],Q=d+4|0,n[B+4>>2]=n[Q>>2],M=d+8|0,n[B+8>>2]=n[M>>2],n[M>>2]=0,n[Q>>2]=0,n[d>>2]=0,AD(s,hc(0,k|0,l|0,c|0,f|0,mR(B)|0)|0),ef(B),C=m}function COe(){var s=0;return o[8008]|0||(wOe(10768),s=8008,n[s>>2]=1,n[s+4>>2]=0),10768}function wOe(s){s=s|0,bl(s,IOe()|0,3)}function IOe(){return 1784}function BOe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0;m=C,C=C+16|0,k=m+4|0,Q=m,B=Sl(vOe()|0)|0,c=Km(c)|0,n[Q>>2]=n[f>>2],n[k>>2]=n[Q>>2],f=Rg(k)|0,AD(s,hc(0,B|0,l|0,c|0,f|0,dR(d)|0)|0),C=m}function vOe(){var s=0;return o[8016]|0||(DOe(10780),s=8016,n[s>>2]=1,n[s+4>>2]=0),10780}function DOe(s){s=s|0,bl(s,POe()|0,3)}function POe(){return 1800}function SOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=Sl(bOe()|0)|0,AD(s,Qn(0,f|0,l|0,Km(c)|0)|0)}function bOe(){var s=0;return o[8024]|0||(xOe(10792),s=8024,n[s>>2]=1,n[s+4>>2]=0),10792}function xOe(s){s=s|0,bl(s,kOe()|0,1)}function kOe(){return 1816}function QOe(){FOe(),ROe(),TOe()}function FOe(){n[2702]=p7(65536)|0}function ROe(){eMe(10856)}function TOe(){LOe(10816)}function LOe(s){s=s|0,NOe(s,5044),OOe(s)|0}function NOe(s,l){s=s|0,l=l|0;var c=0;c=x5()|0,n[s>>2]=c,zOe(c,l),kp(n[s>>2]|0)}function OOe(s){s=s|0;var l=0;return l=n[s>>2]|0,Qg(l,MOe()|0),s|0}function MOe(){var s=0;return o[8032]|0||(_5(10820),rr(64,10820,U|0)|0,s=8032,n[s>>2]=1,n[s+4>>2]=0),Tr(10820)|0||_5(10820),10820}function _5(s){s=s|0,HOe(s),Fg(s,25)}function UOe(s){s=s|0,_Oe(s+24|0)}function _Oe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function HOe(s){s=s|0;var l=0;l=Kr()|0,zr(s,5,18,l,YOe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function qOe(s,l){s=s|0,l=l|0,GOe(s,l)}function GOe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;c=C,C=C+16|0,f=c,d=c+4|0,xg(d,l),n[f>>2]=kg(d,l)|0,jOe(s,f),C=c}function jOe(s,l){s=s|0,l=l|0,H5(s+4|0,n[l>>2]|0),o[s+8>>0]=1}function H5(s,l){s=s|0,l=l|0,n[s>>2]=l}function YOe(){return 1824}function WOe(s){return s=s|0,KOe(s)|0}function KOe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;return c=C,C=C+16|0,d=c+4|0,B=c,f=Ka(8)|0,l=f,k=Kt(4)|0,xg(d,s),H5(k,kg(d,s)|0),m=l+4|0,n[m>>2]=k,s=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],k5(s,m,d),n[f>>2]=s,C=c,l|0}function Ka(s){s=s|0;var l=0,c=0;return s=s+7&-8,s>>>0<=32768&&(l=n[2701]|0,s>>>0<=(65536-l|0)>>>0)?(c=(n[2702]|0)+l|0,n[2701]=l+s,s=c):(s=p7(s+8|0)|0,n[s>>2]=n[2703],n[2703]=s,s=s+8|0),s|0}function zOe(s,l){s=s|0,l=l|0,n[s>>2]=VOe()|0,n[s+4>>2]=JOe()|0,n[s+12>>2]=l,n[s+8>>2]=XOe()|0,n[s+32>>2]=9}function VOe(){return 11744}function JOe(){return 1832}function XOe(){return lD()|0}function ZOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&($Oe(c),gt(c)):l|0&&gt(l)}function $Oe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function eMe(s){s=s|0,tMe(s,5052),rMe(s)|0,nMe(s,5058,26)|0,iMe(s,5069,1)|0,sMe(s,5077,10)|0,oMe(s,5087,19)|0,aMe(s,5094,27)|0}function tMe(s,l){s=s|0,l=l|0;var c=0;c=$4e()|0,n[s>>2]=c,eUe(c,l),kp(n[s>>2]|0)}function rMe(s){s=s|0;var l=0;return l=n[s>>2]|0,Qg(l,U4e()|0),s|0}function nMe(s,l,c){return s=s|0,l=l|0,c=c|0,w4e(s,pn(l)|0,c,0),s|0}function iMe(s,l,c){return s=s|0,l=l|0,c=c|0,o4e(s,pn(l)|0,c,0),s|0}function sMe(s,l,c){return s=s|0,l=l|0,c=c|0,MMe(s,pn(l)|0,c,0),s|0}function oMe(s,l,c){return s=s|0,l=l|0,c=c|0,BMe(s,pn(l)|0,c,0),s|0}function q5(s,l){s=s|0,l=l|0;var c=0,f=0;e:for(;;){for(c=n[2703]|0;;){if((c|0)==(l|0))break e;if(f=n[c>>2]|0,n[2703]=f,!c)c=f;else break}gt(c)}n[2701]=s}function aMe(s,l,c){return s=s|0,l=l|0,c=c|0,lMe(s,pn(l)|0,c,0),s|0}function lMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=yR()|0,s=cMe(c)|0,hn(m,l,d,s,uMe(c,f)|0,f)}function yR(){var s=0,l=0;if(o[8040]|0||(j5(10860),rr(65,10860,U|0)|0,l=8040,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10860)|0)){s=10860,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));j5(10860)}return 10860}function cMe(s){return s=s|0,s|0}function uMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=yR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(G5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(AMe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function G5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function AMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=fMe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,pMe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,G5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,hMe(s,d),gMe(d),C=k;return}}function fMe(s){return s=s|0,536870911}function pMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function hMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function gMe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function j5(s){s=s|0,yMe(s)}function dMe(s){s=s|0,mMe(s+24|0)}function mMe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function yMe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,11,l,EMe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function EMe(){return 1840}function CMe(s,l,c){s=s|0,l=l|0,c=c|0,IMe(n[(wMe(s)|0)>>2]|0,l,c)}function wMe(s){return s=s|0,(n[(yR()|0)+24>>2]|0)+(s<<3)|0}function IMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;f=C,C=C+16|0,m=f+1|0,d=f,xg(m,l),l=kg(m,l)|0,xg(d,c),c=kg(d,c)|0,rf[s&31](l,c),C=f}function BMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=ER()|0,s=vMe(c)|0,hn(m,l,d,s,DMe(c,f)|0,f)}function ER(){var s=0,l=0;if(o[8048]|0||(W5(10896),rr(66,10896,U|0)|0,l=8048,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10896)|0)){s=10896,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));W5(10896)}return 10896}function vMe(s){return s=s|0,s|0}function DMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=ER()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(Y5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(PMe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function Y5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function PMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=SMe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,bMe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,Y5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,xMe(s,d),kMe(d),C=k;return}}function SMe(s){return s=s|0,536870911}function bMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function xMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function kMe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function W5(s){s=s|0,RMe(s)}function QMe(s){s=s|0,FMe(s+24|0)}function FMe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function RMe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,11,l,TMe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function TMe(){return 1852}function LMe(s,l){return s=s|0,l=l|0,OMe(n[(NMe(s)|0)>>2]|0,l)|0}function NMe(s){return s=s|0,(n[(ER()|0)+24>>2]|0)+(s<<3)|0}function OMe(s,l){s=s|0,l=l|0;var c=0,f=0;return c=C,C=C+16|0,f=c,xg(f,l),l=kg(f,l)|0,l=oD(Og[s&31](l)|0)|0,C=c,l|0}function MMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=CR()|0,s=UMe(c)|0,hn(m,l,d,s,_Me(c,f)|0,f)}function CR(){var s=0,l=0;if(o[8056]|0||(z5(10932),rr(67,10932,U|0)|0,l=8056,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10932)|0)){s=10932,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));z5(10932)}return 10932}function UMe(s){return s=s|0,s|0}function _Me(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=CR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(K5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(HMe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function K5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function HMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=qMe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,GMe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,K5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,jMe(s,d),YMe(d),C=k;return}}function qMe(s){return s=s|0,536870911}function GMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function jMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function YMe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function z5(s){s=s|0,zMe(s)}function WMe(s){s=s|0,KMe(s+24|0)}function KMe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function zMe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,7,l,VMe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function VMe(){return 1860}function JMe(s,l,c){return s=s|0,l=l|0,c=c|0,ZMe(n[(XMe(s)|0)>>2]|0,l,c)|0}function XMe(s){return s=s|0,(n[(CR()|0)+24>>2]|0)+(s<<3)|0}function ZMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0;return f=C,C=C+32|0,B=f+12|0,m=f+8|0,k=f,Q=f+16|0,d=f+4|0,$Me(Q,l),e4e(k,Q,l),Pp(d,c),c=Sp(d,c)|0,n[B>>2]=n[k>>2],Hw[s&15](m,B,c),c=t4e(m)|0,jA(m),bp(d),C=f,c|0}function $Me(s,l){s=s|0,l=l|0}function e4e(s,l,c){s=s|0,l=l|0,c=c|0,r4e(s,c)}function t4e(s){return s=s|0,da(s)|0}function r4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;d=C,C=C+16|0,c=d,f=l,f&1?(n4e(c,0),ii(f|0,c|0)|0,i4e(s,c),s4e(c)):n[s>>2]=n[l>>2],C=d}function n4e(s,l){s=s|0,l=l|0,Xj(s,l),n[s+4>>2]=0,o[s+8>>0]=0}function i4e(s,l){s=s|0,l=l|0,n[s>>2]=n[l+4>>2]}function s4e(s){s=s|0,o[s+8>>0]=0}function o4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=wR()|0,s=a4e(c)|0,hn(m,l,d,s,l4e(c,f)|0,f)}function wR(){var s=0,l=0;if(o[8064]|0||(J5(10968),rr(68,10968,U|0)|0,l=8064,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10968)|0)){s=10968,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));J5(10968)}return 10968}function a4e(s){return s=s|0,s|0}function l4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=wR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(V5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(c4e(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function V5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function c4e(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=u4e(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,A4e(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,V5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,f4e(s,d),p4e(d),C=k;return}}function u4e(s){return s=s|0,536870911}function A4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function f4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function p4e(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function J5(s){s=s|0,d4e(s)}function h4e(s){s=s|0,g4e(s+24|0)}function g4e(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function d4e(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,1,l,m4e()|0,5),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function m4e(){return 1872}function y4e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,C4e(n[(E4e(s)|0)>>2]|0,l,c,f,d,m)}function E4e(s){return s=s|0,(n[(wR()|0)+24>>2]|0)+(s<<3)|0}function C4e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,G=0;B=C,C=C+32|0,k=B+16|0,Q=B+12|0,M=B+8|0,O=B+4|0,G=B,Pp(k,l),l=Sp(k,l)|0,Pp(Q,c),c=Sp(Q,c)|0,Pp(M,f),f=Sp(M,f)|0,Pp(O,d),d=Sp(O,d)|0,Pp(G,m),m=Sp(G,m)|0,y7[s&1](l,c,f,d,m),bp(G),bp(O),bp(M),bp(Q),bp(k),C=B}function w4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=IR()|0,s=I4e(c)|0,hn(m,l,d,s,B4e(c,f)|0,f)}function IR(){var s=0,l=0;if(o[8072]|0||(Z5(11004),rr(69,11004,U|0)|0,l=8072,n[l>>2]=1,n[l+4>>2]=0),!(Tr(11004)|0)){s=11004,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));Z5(11004)}return 11004}function I4e(s){return s=s|0,s|0}function B4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=IR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(X5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(v4e(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function X5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function v4e(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=D4e(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,P4e(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,X5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,S4e(s,d),b4e(d),C=k;return}}function D4e(s){return s=s|0,536870911}function P4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function S4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function b4e(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function Z5(s){s=s|0,Q4e(s)}function x4e(s){s=s|0,k4e(s+24|0)}function k4e(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function Q4e(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,12,l,F4e()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function F4e(){return 1896}function R4e(s,l,c){s=s|0,l=l|0,c=c|0,L4e(n[(T4e(s)|0)>>2]|0,l,c)}function T4e(s){return s=s|0,(n[(IR()|0)+24>>2]|0)+(s<<3)|0}function L4e(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;f=C,C=C+16|0,m=f+4|0,d=f,N4e(m,l),l=O4e(m,l)|0,Pp(d,c),c=Sp(d,c)|0,rf[s&31](l,c),bp(d),C=f}function N4e(s,l){s=s|0,l=l|0}function O4e(s,l){return s=s|0,l=l|0,M4e(l)|0}function M4e(s){return s=s|0,s|0}function U4e(){var s=0;return o[8080]|0||($5(11040),rr(70,11040,U|0)|0,s=8080,n[s>>2]=1,n[s+4>>2]=0),Tr(11040)|0||$5(11040),11040}function $5(s){s=s|0,q4e(s),Fg(s,71)}function _4e(s){s=s|0,H4e(s+24|0)}function H4e(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function q4e(s){s=s|0;var l=0;l=Kr()|0,zr(s,5,7,l,W4e()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function G4e(s){s=s|0,j4e(s)}function j4e(s){s=s|0,Y4e(s)}function Y4e(s){s=s|0,o[s+8>>0]=1}function W4e(){return 1936}function K4e(){return z4e()|0}function z4e(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0;return l=C,C=C+16|0,d=l+4|0,B=l,c=Ka(8)|0,s=c,m=s+4|0,n[m>>2]=Kt(1)|0,f=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],V4e(f,m,d),n[c>>2]=f,C=l,s|0}function V4e(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1916,n[c+12>>2]=l,n[s+4>>2]=c}function J4e(s){s=s|0,Jm(s),gt(s)}function X4e(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function Z4e(s){s=s|0,gt(s)}function $4e(){var s=0;return o[8088]|0||(oUe(11076),rr(25,11076,U|0)|0,s=8088,n[s>>2]=1,n[s+4>>2]=0),11076}function eUe(s,l){s=s|0,l=l|0,n[s>>2]=tUe()|0,n[s+4>>2]=rUe()|0,n[s+12>>2]=l,n[s+8>>2]=nUe()|0,n[s+32>>2]=10}function tUe(){return 11745}function rUe(){return 1940}function nUe(){return aD()|0}function iUe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&(sUe(c),gt(c)):l|0&&gt(l)}function sUe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function oUe(s){s=s|0,Dp(s)}function xc(s,l){s=s|0,l=l|0,n[s>>2]=l}function BR(s){return s=s|0,n[s>>2]|0}function aUe(s){return s=s|0,o[n[s>>2]>>0]|0}function lUe(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,n[f>>2]=n[s>>2],cUe(l,f)|0,C=c}function cUe(s,l){s=s|0,l=l|0;var c=0;return c=uUe(n[s>>2]|0,l)|0,l=s+4|0,n[(n[l>>2]|0)+8>>2]=c,n[(n[l>>2]|0)+8>>2]|0}function uUe(s,l){s=s|0,l=l|0;var c=0,f=0;return c=C,C=C+16|0,f=c,za(f),s=da(s)|0,l=AUe(s,n[l>>2]|0)|0,Va(f),C=c,l|0}function za(s){s=s|0,n[s>>2]=n[2701],n[s+4>>2]=n[2703]}function AUe(s,l){s=s|0,l=l|0;var c=0;return c=Sl(fUe()|0)|0,Qn(0,c|0,s|0,dR(l)|0)|0}function Va(s){s=s|0,q5(n[s>>2]|0,n[s+4>>2]|0)}function fUe(){var s=0;return o[8096]|0||(pUe(11120),s=8096,n[s>>2]=1,n[s+4>>2]=0),11120}function pUe(s){s=s|0,bl(s,hUe()|0,1)}function hUe(){return 1948}function gUe(){dUe()}function dUe(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0;if(Me=C,C=C+16|0,O=Me+4|0,G=Me,Li(65536,10804,n[2702]|0,10812),c=B5()|0,l=n[c>>2]|0,s=n[l>>2]|0,s|0)for(f=n[c+8>>2]|0,c=n[c+4>>2]|0;Ac(s|0,u[c>>0]|0|0,o[f>>0]|0),l=l+4|0,s=n[l>>2]|0,s;)f=f+1|0,c=c+1|0;if(s=v5()|0,l=n[s>>2]|0,l|0)do Au(l|0,n[s+4>>2]|0),s=s+8|0,l=n[s>>2]|0;while((l|0)!=0);Au(mUe()|0,5167),M=Ym()|0,s=n[M>>2]|0;e:do if(s|0){do yUe(n[s+4>>2]|0),s=n[s>>2]|0;while((s|0)!=0);if(s=n[M>>2]|0,s|0){Q=M;do{for(;d=s,s=n[s>>2]|0,d=n[d+4>>2]|0,!!(EUe(d)|0);)if(n[G>>2]=Q,n[O>>2]=n[G>>2],CUe(M,O)|0,!s)break e;if(wUe(d),Q=n[Q>>2]|0,l=e7(d)|0,m=Hi()|0,B=C,C=C+((1*(l<<2)|0)+15&-16)|0,k=C,C=C+((1*(l<<2)|0)+15&-16)|0,l=n[(N5(d)|0)>>2]|0,l|0)for(c=B,f=k;n[c>>2]=n[(Wm(n[l+4>>2]|0)|0)>>2],n[f>>2]=n[l+8>>2],l=n[l>>2]|0,l;)c=c+4|0,f=f+4|0;Qe=Wm(d)|0,l=IUe(d)|0,c=e7(d)|0,f=BUe(d)|0,fu(Qe|0,l|0,B|0,k|0,c|0,f|0,uR(d)|0),_i(m|0)}while((s|0)!=0)}}while(0);if(s=n[(AR()|0)>>2]|0,s|0)do Qe=s+4|0,M=fR(Qe)|0,d=Ow(M)|0,m=Lw(M)|0,B=(Nw(M)|0)+1|0,k=fD(M)|0,Q=t7(Qe)|0,M=Tr(M)|0,O=cD(Qe)|0,G=vR(Qe)|0,Cl(0,d|0,m|0,B|0,k|0,Q|0,M|0,O|0,G|0,DR(Qe)|0),s=n[s>>2]|0;while((s|0)!=0);s=n[(Ym()|0)>>2]|0;e:do if(s|0){t:for(;;){if(l=n[s+4>>2]|0,l|0&&(se=n[(Wm(l)|0)>>2]|0,je=n[(O5(l)|0)>>2]|0,je|0)){c=je;do{l=c+4|0,f=fR(l)|0;r:do if(f|0)switch(Tr(f)|0){case 0:break t;case 4:case 3:case 2:{k=Ow(f)|0,Q=Lw(f)|0,M=(Nw(f)|0)+1|0,O=fD(f)|0,G=Tr(f)|0,Qe=cD(l)|0,Cl(se|0,k|0,Q|0,M|0,O|0,0,G|0,Qe|0,vR(l)|0,DR(l)|0);break r}case 1:{B=Ow(f)|0,k=Lw(f)|0,Q=(Nw(f)|0)+1|0,M=fD(f)|0,O=t7(l)|0,G=Tr(f)|0,Qe=cD(l)|0,Cl(se|0,B|0,k|0,Q|0,M|0,O|0,G|0,Qe|0,vR(l)|0,DR(l)|0);break r}case 5:{M=Ow(f)|0,O=Lw(f)|0,G=(Nw(f)|0)+1|0,Qe=fD(f)|0,Cl(se|0,M|0,O|0,G|0,Qe|0,vUe(f)|0,Tr(f)|0,0,0,0);break r}default:break r}while(0);c=n[c>>2]|0}while((c|0)!=0)}if(s=n[s>>2]|0,!s)break e}Rt()}while(0);Ce(),C=Me}function mUe(){return 11703}function yUe(s){s=s|0,o[s+40>>0]=0}function EUe(s){return s=s|0,(o[s+40>>0]|0)!=0|0}function CUe(s,l){return s=s|0,l=l|0,l=DUe(l)|0,s=n[l>>2]|0,n[l>>2]=n[s>>2],gt(s),n[l>>2]|0}function wUe(s){s=s|0,o[s+40>>0]=1}function e7(s){return s=s|0,n[s+20>>2]|0}function IUe(s){return s=s|0,n[s+8>>2]|0}function BUe(s){return s=s|0,n[s+32>>2]|0}function fD(s){return s=s|0,n[s+4>>2]|0}function t7(s){return s=s|0,n[s+4>>2]|0}function vR(s){return s=s|0,n[s+8>>2]|0}function DR(s){return s=s|0,n[s+16>>2]|0}function vUe(s){return s=s|0,n[s+20>>2]|0}function DUe(s){return s=s|0,n[s>>2]|0}function pD(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0,et=0,Xe=0,lt=0,Ue=0,Ge=0,Nt=0;Nt=C,C=C+16|0,se=Nt;do if(s>>>0<245){if(M=s>>>0<11?16:s+11&-8,s=M>>>3,G=n[2783]|0,c=G>>>s,c&3|0)return l=(c&1^1)+s|0,s=11172+(l<<1<<2)|0,c=s+8|0,f=n[c>>2]|0,d=f+8|0,m=n[d>>2]|0,(s|0)==(m|0)?n[2783]=G&~(1<<l):(n[m+12>>2]=s,n[c>>2]=m),Ge=l<<3,n[f+4>>2]=Ge|3,Ge=f+Ge+4|0,n[Ge>>2]=n[Ge>>2]|1,Ge=d,C=Nt,Ge|0;if(O=n[2785]|0,M>>>0>O>>>0){if(c|0)return l=2<<s,l=c<<s&(l|0-l),l=(l&0-l)+-1|0,B=l>>>12&16,l=l>>>B,c=l>>>5&8,l=l>>>c,d=l>>>2&4,l=l>>>d,s=l>>>1&2,l=l>>>s,f=l>>>1&1,f=(c|B|d|s|f)+(l>>>f)|0,l=11172+(f<<1<<2)|0,s=l+8|0,d=n[s>>2]|0,B=d+8|0,c=n[B>>2]|0,(l|0)==(c|0)?(s=G&~(1<<f),n[2783]=s):(n[c+12>>2]=l,n[s>>2]=c,s=G),m=(f<<3)-M|0,n[d+4>>2]=M|3,f=d+M|0,n[f+4>>2]=m|1,n[f+m>>2]=m,O|0&&(d=n[2788]|0,l=O>>>3,c=11172+(l<<1<<2)|0,l=1<<l,s&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=d,n[l+12>>2]=d,n[d+8>>2]=l,n[d+12>>2]=c),n[2785]=m,n[2788]=f,Ge=B,C=Nt,Ge|0;if(k=n[2784]|0,k){if(c=(k&0-k)+-1|0,B=c>>>12&16,c=c>>>B,m=c>>>5&8,c=c>>>m,Q=c>>>2&4,c=c>>>Q,f=c>>>1&2,c=c>>>f,s=c>>>1&1,s=n[11436+((m|B|Q|f|s)+(c>>>s)<<2)>>2]|0,c=(n[s+4>>2]&-8)-M|0,f=n[s+16+(((n[s+16>>2]|0)==0&1)<<2)>>2]|0,!f)Q=s,m=c;else{do B=(n[f+4>>2]&-8)-M|0,Q=B>>>0<c>>>0,c=Q?B:c,s=Q?f:s,f=n[f+16+(((n[f+16>>2]|0)==0&1)<<2)>>2]|0;while((f|0)!=0);Q=s,m=c}if(B=Q+M|0,Q>>>0<B>>>0){d=n[Q+24>>2]|0,l=n[Q+12>>2]|0;do if((l|0)==(Q|0)){if(s=Q+20|0,l=n[s>>2]|0,!l&&(s=Q+16|0,l=n[s>>2]|0,!l)){c=0;break}for(;;){if(c=l+20|0,f=n[c>>2]|0,f|0){l=f,s=c;continue}if(c=l+16|0,f=n[c>>2]|0,f)l=f,s=c;else break}n[s>>2]=0,c=l}else c=n[Q+8>>2]|0,n[c+12>>2]=l,n[l+8>>2]=c,c=l;while(0);do if(d|0){if(l=n[Q+28>>2]|0,s=11436+(l<<2)|0,(Q|0)==(n[s>>2]|0)){if(n[s>>2]=c,!c){n[2784]=k&~(1<<l);break}}else if(n[d+16+(((n[d+16>>2]|0)!=(Q|0)&1)<<2)>>2]=c,!c)break;n[c+24>>2]=d,l=n[Q+16>>2]|0,l|0&&(n[c+16>>2]=l,n[l+24>>2]=c),l=n[Q+20>>2]|0,l|0&&(n[c+20>>2]=l,n[l+24>>2]=c)}while(0);return m>>>0<16?(Ge=m+M|0,n[Q+4>>2]=Ge|3,Ge=Q+Ge+4|0,n[Ge>>2]=n[Ge>>2]|1):(n[Q+4>>2]=M|3,n[B+4>>2]=m|1,n[B+m>>2]=m,O|0&&(f=n[2788]|0,l=O>>>3,c=11172+(l<<1<<2)|0,l=1<<l,G&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=G|l,l=c,s=c+8|0),n[s>>2]=f,n[l+12>>2]=f,n[f+8>>2]=l,n[f+12>>2]=c),n[2785]=m,n[2788]=B),Ge=Q+8|0,C=Nt,Ge|0}else G=M}else G=M}else G=M}else if(s>>>0<=4294967231)if(s=s+11|0,M=s&-8,Q=n[2784]|0,Q){f=0-M|0,s=s>>>8,s?M>>>0>16777215?k=31:(G=(s+1048320|0)>>>16&8,Ue=s<<G,O=(Ue+520192|0)>>>16&4,Ue=Ue<<O,k=(Ue+245760|0)>>>16&2,k=14-(O|G|k)+(Ue<<k>>>15)|0,k=M>>>(k+7|0)&1|k<<1):k=0,c=n[11436+(k<<2)>>2]|0;e:do if(!c)c=0,s=0,Ue=57;else for(s=0,B=M<<((k|0)==31?0:25-(k>>>1)|0),m=0;;){if(d=(n[c+4>>2]&-8)-M|0,d>>>0<f>>>0)if(d)s=c,f=d;else{s=c,f=0,d=c,Ue=61;break e}if(d=n[c+20>>2]|0,c=n[c+16+(B>>>31<<2)>>2]|0,m=(d|0)==0|(d|0)==(c|0)?m:d,d=(c|0)==0,d){c=m,Ue=57;break}else B=B<<((d^1)&1)}while(0);if((Ue|0)==57){if((c|0)==0&(s|0)==0){if(s=2<<k,s=Q&(s|0-s),!s){G=M;break}G=(s&0-s)+-1|0,B=G>>>12&16,G=G>>>B,m=G>>>5&8,G=G>>>m,k=G>>>2&4,G=G>>>k,O=G>>>1&2,G=G>>>O,c=G>>>1&1,s=0,c=n[11436+((m|B|k|O|c)+(G>>>c)<<2)>>2]|0}c?(d=c,Ue=61):(k=s,B=f)}if((Ue|0)==61)for(;;)if(Ue=0,c=(n[d+4>>2]&-8)-M|0,G=c>>>0<f>>>0,c=G?c:f,s=G?d:s,d=n[d+16+(((n[d+16>>2]|0)==0&1)<<2)>>2]|0,d)f=c,Ue=61;else{k=s,B=c;break}if((k|0)!=0&&B>>>0<((n[2785]|0)-M|0)>>>0){if(m=k+M|0,k>>>0>=m>>>0)return Ge=0,C=Nt,Ge|0;d=n[k+24>>2]|0,l=n[k+12>>2]|0;do if((l|0)==(k|0)){if(s=k+20|0,l=n[s>>2]|0,!l&&(s=k+16|0,l=n[s>>2]|0,!l)){l=0;break}for(;;){if(c=l+20|0,f=n[c>>2]|0,f|0){l=f,s=c;continue}if(c=l+16|0,f=n[c>>2]|0,f)l=f,s=c;else break}n[s>>2]=0}else Ge=n[k+8>>2]|0,n[Ge+12>>2]=l,n[l+8>>2]=Ge;while(0);do if(d){if(s=n[k+28>>2]|0,c=11436+(s<<2)|0,(k|0)==(n[c>>2]|0)){if(n[c>>2]=l,!l){f=Q&~(1<<s),n[2784]=f;break}}else if(n[d+16+(((n[d+16>>2]|0)!=(k|0)&1)<<2)>>2]=l,!l){f=Q;break}n[l+24>>2]=d,s=n[k+16>>2]|0,s|0&&(n[l+16>>2]=s,n[s+24>>2]=l),s=n[k+20>>2]|0,s&&(n[l+20>>2]=s,n[s+24>>2]=l),f=Q}else f=Q;while(0);do if(B>>>0>=16){if(n[k+4>>2]=M|3,n[m+4>>2]=B|1,n[m+B>>2]=B,l=B>>>3,B>>>0<256){c=11172+(l<<1<<2)|0,s=n[2783]|0,l=1<<l,s&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=m,n[l+12>>2]=m,n[m+8>>2]=l,n[m+12>>2]=c;break}if(l=B>>>8,l?B>>>0>16777215?l=31:(Ue=(l+1048320|0)>>>16&8,Ge=l<<Ue,lt=(Ge+520192|0)>>>16&4,Ge=Ge<<lt,l=(Ge+245760|0)>>>16&2,l=14-(lt|Ue|l)+(Ge<<l>>>15)|0,l=B>>>(l+7|0)&1|l<<1):l=0,c=11436+(l<<2)|0,n[m+28>>2]=l,s=m+16|0,n[s+4>>2]=0,n[s>>2]=0,s=1<<l,!(f&s)){n[2784]=f|s,n[c>>2]=m,n[m+24>>2]=c,n[m+12>>2]=m,n[m+8>>2]=m;break}for(s=B<<((l|0)==31?0:25-(l>>>1)|0),c=n[c>>2]|0;;){if((n[c+4>>2]&-8|0)==(B|0)){Ue=97;break}if(f=c+16+(s>>>31<<2)|0,l=n[f>>2]|0,l)s=s<<1,c=l;else{Ue=96;break}}if((Ue|0)==96){n[f>>2]=m,n[m+24>>2]=c,n[m+12>>2]=m,n[m+8>>2]=m;break}else if((Ue|0)==97){Ue=c+8|0,Ge=n[Ue>>2]|0,n[Ge+12>>2]=m,n[Ue>>2]=m,n[m+8>>2]=Ge,n[m+12>>2]=c,n[m+24>>2]=0;break}}else Ge=B+M|0,n[k+4>>2]=Ge|3,Ge=k+Ge+4|0,n[Ge>>2]=n[Ge>>2]|1;while(0);return Ge=k+8|0,C=Nt,Ge|0}else G=M}else G=M;else G=-1;while(0);if(c=n[2785]|0,c>>>0>=G>>>0)return l=c-G|0,s=n[2788]|0,l>>>0>15?(Ge=s+G|0,n[2788]=Ge,n[2785]=l,n[Ge+4>>2]=l|1,n[Ge+l>>2]=l,n[s+4>>2]=G|3):(n[2785]=0,n[2788]=0,n[s+4>>2]=c|3,Ge=s+c+4|0,n[Ge>>2]=n[Ge>>2]|1),Ge=s+8|0,C=Nt,Ge|0;if(B=n[2786]|0,B>>>0>G>>>0)return lt=B-G|0,n[2786]=lt,Ge=n[2789]|0,Ue=Ge+G|0,n[2789]=Ue,n[Ue+4>>2]=lt|1,n[Ge+4>>2]=G|3,Ge=Ge+8|0,C=Nt,Ge|0;if(n[2901]|0?s=n[2903]|0:(n[2903]=4096,n[2902]=4096,n[2904]=-1,n[2905]=-1,n[2906]=0,n[2894]=0,s=se&-16^1431655768,n[se>>2]=s,n[2901]=s,s=4096),k=G+48|0,Q=G+47|0,m=s+Q|0,d=0-s|0,M=m&d,M>>>0<=G>>>0||(s=n[2893]|0,s|0&&(O=n[2891]|0,se=O+M|0,se>>>0<=O>>>0|se>>>0>s>>>0)))return Ge=0,C=Nt,Ge|0;e:do if(n[2894]&4)l=0,Ue=133;else{c=n[2789]|0;t:do if(c){for(f=11580;s=n[f>>2]|0,!(s>>>0<=c>>>0&&(Qe=f+4|0,(s+(n[Qe>>2]|0)|0)>>>0>c>>>0));)if(s=n[f+8>>2]|0,s)f=s;else{Ue=118;break t}if(l=m-B&d,l>>>0<2147483647)if(s=Fp(l|0)|0,(s|0)==((n[f>>2]|0)+(n[Qe>>2]|0)|0)){if((s|0)!=-1){B=l,m=s,Ue=135;break e}}else f=s,Ue=126;else l=0}else Ue=118;while(0);do if((Ue|0)==118)if(c=Fp(0)|0,(c|0)!=-1&&(l=c,je=n[2902]|0,Me=je+-1|0,l=((Me&l|0)==0?0:(Me+l&0-je)-l|0)+M|0,je=n[2891]|0,Me=l+je|0,l>>>0>G>>>0&l>>>0<2147483647)){if(Qe=n[2893]|0,Qe|0&&Me>>>0<=je>>>0|Me>>>0>Qe>>>0){l=0;break}if(s=Fp(l|0)|0,(s|0)==(c|0)){B=l,m=c,Ue=135;break e}else f=s,Ue=126}else l=0;while(0);do if((Ue|0)==126){if(c=0-l|0,!(k>>>0>l>>>0&(l>>>0<2147483647&(f|0)!=-1)))if((f|0)==-1){l=0;break}else{B=l,m=f,Ue=135;break e}if(s=n[2903]|0,s=Q-l+s&0-s,s>>>0>=2147483647){B=l,m=f,Ue=135;break e}if((Fp(s|0)|0)==-1){Fp(c|0)|0,l=0;break}else{B=s+l|0,m=f,Ue=135;break e}}while(0);n[2894]=n[2894]|4,Ue=133}while(0);if((Ue|0)==133&&M>>>0<2147483647&&(lt=Fp(M|0)|0,Qe=Fp(0)|0,et=Qe-lt|0,Xe=et>>>0>(G+40|0)>>>0,!((lt|0)==-1|Xe^1|lt>>>0<Qe>>>0&((lt|0)!=-1&(Qe|0)!=-1)^1))&&(B=Xe?et:l,m=lt,Ue=135),(Ue|0)==135){l=(n[2891]|0)+B|0,n[2891]=l,l>>>0>(n[2892]|0)>>>0&&(n[2892]=l),Q=n[2789]|0;do if(Q){for(l=11580;;){if(s=n[l>>2]|0,c=l+4|0,f=n[c>>2]|0,(m|0)==(s+f|0)){Ue=145;break}if(d=n[l+8>>2]|0,d)l=d;else break}if((Ue|0)==145&&(n[l+12>>2]&8|0)==0&&Q>>>0<m>>>0&Q>>>0>=s>>>0){n[c>>2]=f+B,Ge=Q+8|0,Ge=(Ge&7|0)==0?0:0-Ge&7,Ue=Q+Ge|0,Ge=(n[2786]|0)+(B-Ge)|0,n[2789]=Ue,n[2786]=Ge,n[Ue+4>>2]=Ge|1,n[Ue+Ge+4>>2]=40,n[2790]=n[2905];break}for(m>>>0<(n[2787]|0)>>>0&&(n[2787]=m),c=m+B|0,l=11580;;){if((n[l>>2]|0)==(c|0)){Ue=153;break}if(s=n[l+8>>2]|0,s)l=s;else break}if((Ue|0)==153&&(n[l+12>>2]&8|0)==0){n[l>>2]=m,O=l+4|0,n[O>>2]=(n[O>>2]|0)+B,O=m+8|0,O=m+((O&7|0)==0?0:0-O&7)|0,l=c+8|0,l=c+((l&7|0)==0?0:0-l&7)|0,M=O+G|0,k=l-O-G|0,n[O+4>>2]=G|3;do if((l|0)!=(Q|0)){if((l|0)==(n[2788]|0)){Ge=(n[2785]|0)+k|0,n[2785]=Ge,n[2788]=M,n[M+4>>2]=Ge|1,n[M+Ge>>2]=Ge;break}if(s=n[l+4>>2]|0,(s&3|0)==1){B=s&-8,f=s>>>3;e:do if(s>>>0<256)if(s=n[l+8>>2]|0,c=n[l+12>>2]|0,(c|0)==(s|0)){n[2783]=n[2783]&~(1<<f);break}else{n[s+12>>2]=c,n[c+8>>2]=s;break}else{m=n[l+24>>2]|0,s=n[l+12>>2]|0;do if((s|0)==(l|0)){if(f=l+16|0,c=f+4|0,s=n[c>>2]|0,!s)if(s=n[f>>2]|0,s)c=f;else{s=0;break}for(;;){if(f=s+20|0,d=n[f>>2]|0,d|0){s=d,c=f;continue}if(f=s+16|0,d=n[f>>2]|0,d)s=d,c=f;else break}n[c>>2]=0}else Ge=n[l+8>>2]|0,n[Ge+12>>2]=s,n[s+8>>2]=Ge;while(0);if(!m)break;c=n[l+28>>2]|0,f=11436+(c<<2)|0;do if((l|0)!=(n[f>>2]|0)){if(n[m+16+(((n[m+16>>2]|0)!=(l|0)&1)<<2)>>2]=s,!s)break e}else{if(n[f>>2]=s,s|0)break;n[2784]=n[2784]&~(1<<c);break e}while(0);if(n[s+24>>2]=m,c=l+16|0,f=n[c>>2]|0,f|0&&(n[s+16>>2]=f,n[f+24>>2]=s),c=n[c+4>>2]|0,!c)break;n[s+20>>2]=c,n[c+24>>2]=s}while(0);l=l+B|0,d=B+k|0}else d=k;if(l=l+4|0,n[l>>2]=n[l>>2]&-2,n[M+4>>2]=d|1,n[M+d>>2]=d,l=d>>>3,d>>>0<256){c=11172+(l<<1<<2)|0,s=n[2783]|0,l=1<<l,s&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=M,n[l+12>>2]=M,n[M+8>>2]=l,n[M+12>>2]=c;break}l=d>>>8;do if(!l)l=0;else{if(d>>>0>16777215){l=31;break}Ue=(l+1048320|0)>>>16&8,Ge=l<<Ue,lt=(Ge+520192|0)>>>16&4,Ge=Ge<<lt,l=(Ge+245760|0)>>>16&2,l=14-(lt|Ue|l)+(Ge<<l>>>15)|0,l=d>>>(l+7|0)&1|l<<1}while(0);if(f=11436+(l<<2)|0,n[M+28>>2]=l,s=M+16|0,n[s+4>>2]=0,n[s>>2]=0,s=n[2784]|0,c=1<<l,!(s&c)){n[2784]=s|c,n[f>>2]=M,n[M+24>>2]=f,n[M+12>>2]=M,n[M+8>>2]=M;break}for(s=d<<((l|0)==31?0:25-(l>>>1)|0),c=n[f>>2]|0;;){if((n[c+4>>2]&-8|0)==(d|0)){Ue=194;break}if(f=c+16+(s>>>31<<2)|0,l=n[f>>2]|0,l)s=s<<1,c=l;else{Ue=193;break}}if((Ue|0)==193){n[f>>2]=M,n[M+24>>2]=c,n[M+12>>2]=M,n[M+8>>2]=M;break}else if((Ue|0)==194){Ue=c+8|0,Ge=n[Ue>>2]|0,n[Ge+12>>2]=M,n[Ue>>2]=M,n[M+8>>2]=Ge,n[M+12>>2]=c,n[M+24>>2]=0;break}}else Ge=(n[2786]|0)+k|0,n[2786]=Ge,n[2789]=M,n[M+4>>2]=Ge|1;while(0);return Ge=O+8|0,C=Nt,Ge|0}for(l=11580;s=n[l>>2]|0,!(s>>>0<=Q>>>0&&(Ge=s+(n[l+4>>2]|0)|0,Ge>>>0>Q>>>0));)l=n[l+8>>2]|0;d=Ge+-47|0,s=d+8|0,s=d+((s&7|0)==0?0:0-s&7)|0,d=Q+16|0,s=s>>>0<d>>>0?Q:s,l=s+8|0,c=m+8|0,c=(c&7|0)==0?0:0-c&7,Ue=m+c|0,c=B+-40-c|0,n[2789]=Ue,n[2786]=c,n[Ue+4>>2]=c|1,n[Ue+c+4>>2]=40,n[2790]=n[2905],c=s+4|0,n[c>>2]=27,n[l>>2]=n[2895],n[l+4>>2]=n[2896],n[l+8>>2]=n[2897],n[l+12>>2]=n[2898],n[2895]=m,n[2896]=B,n[2898]=0,n[2897]=l,l=s+24|0;do Ue=l,l=l+4|0,n[l>>2]=7;while((Ue+8|0)>>>0<Ge>>>0);if((s|0)!=(Q|0)){if(m=s-Q|0,n[c>>2]=n[c>>2]&-2,n[Q+4>>2]=m|1,n[s>>2]=m,l=m>>>3,m>>>0<256){c=11172+(l<<1<<2)|0,s=n[2783]|0,l=1<<l,s&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=Q,n[l+12>>2]=Q,n[Q+8>>2]=l,n[Q+12>>2]=c;break}if(l=m>>>8,l?m>>>0>16777215?c=31:(Ue=(l+1048320|0)>>>16&8,Ge=l<<Ue,lt=(Ge+520192|0)>>>16&4,Ge=Ge<<lt,c=(Ge+245760|0)>>>16&2,c=14-(lt|Ue|c)+(Ge<<c>>>15)|0,c=m>>>(c+7|0)&1|c<<1):c=0,f=11436+(c<<2)|0,n[Q+28>>2]=c,n[Q+20>>2]=0,n[d>>2]=0,l=n[2784]|0,s=1<<c,!(l&s)){n[2784]=l|s,n[f>>2]=Q,n[Q+24>>2]=f,n[Q+12>>2]=Q,n[Q+8>>2]=Q;break}for(s=m<<((c|0)==31?0:25-(c>>>1)|0),c=n[f>>2]|0;;){if((n[c+4>>2]&-8|0)==(m|0)){Ue=216;break}if(f=c+16+(s>>>31<<2)|0,l=n[f>>2]|0,l)s=s<<1,c=l;else{Ue=215;break}}if((Ue|0)==215){n[f>>2]=Q,n[Q+24>>2]=c,n[Q+12>>2]=Q,n[Q+8>>2]=Q;break}else if((Ue|0)==216){Ue=c+8|0,Ge=n[Ue>>2]|0,n[Ge+12>>2]=Q,n[Ue>>2]=Q,n[Q+8>>2]=Ge,n[Q+12>>2]=c,n[Q+24>>2]=0;break}}}else{Ge=n[2787]|0,(Ge|0)==0|m>>>0<Ge>>>0&&(n[2787]=m),n[2895]=m,n[2896]=B,n[2898]=0,n[2792]=n[2901],n[2791]=-1,l=0;do Ge=11172+(l<<1<<2)|0,n[Ge+12>>2]=Ge,n[Ge+8>>2]=Ge,l=l+1|0;while((l|0)!=32);Ge=m+8|0,Ge=(Ge&7|0)==0?0:0-Ge&7,Ue=m+Ge|0,Ge=B+-40-Ge|0,n[2789]=Ue,n[2786]=Ge,n[Ue+4>>2]=Ge|1,n[Ue+Ge+4>>2]=40,n[2790]=n[2905]}while(0);if(l=n[2786]|0,l>>>0>G>>>0)return lt=l-G|0,n[2786]=lt,Ge=n[2789]|0,Ue=Ge+G|0,n[2789]=Ue,n[Ue+4>>2]=lt|1,n[Ge+4>>2]=G|3,Ge=Ge+8|0,C=Nt,Ge|0}return n[(zm()|0)>>2]=12,Ge=0,C=Nt,Ge|0}function hD(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0;if(!!s){c=s+-8|0,d=n[2787]|0,s=n[s+-4>>2]|0,l=s&-8,Q=c+l|0;do if(s&1)k=c,B=c;else{if(f=n[c>>2]|0,!(s&3)||(B=c+(0-f)|0,m=f+l|0,B>>>0<d>>>0))return;if((B|0)==(n[2788]|0)){if(s=Q+4|0,l=n[s>>2]|0,(l&3|0)!=3){k=B,l=m;break}n[2785]=m,n[s>>2]=l&-2,n[B+4>>2]=m|1,n[B+m>>2]=m;return}if(c=f>>>3,f>>>0<256)if(s=n[B+8>>2]|0,l=n[B+12>>2]|0,(l|0)==(s|0)){n[2783]=n[2783]&~(1<<c),k=B,l=m;break}else{n[s+12>>2]=l,n[l+8>>2]=s,k=B,l=m;break}d=n[B+24>>2]|0,s=n[B+12>>2]|0;do if((s|0)==(B|0)){if(c=B+16|0,l=c+4|0,s=n[l>>2]|0,!s)if(s=n[c>>2]|0,s)l=c;else{s=0;break}for(;;){if(c=s+20|0,f=n[c>>2]|0,f|0){s=f,l=c;continue}if(c=s+16|0,f=n[c>>2]|0,f)s=f,l=c;else break}n[l>>2]=0}else k=n[B+8>>2]|0,n[k+12>>2]=s,n[s+8>>2]=k;while(0);if(d){if(l=n[B+28>>2]|0,c=11436+(l<<2)|0,(B|0)==(n[c>>2]|0)){if(n[c>>2]=s,!s){n[2784]=n[2784]&~(1<<l),k=B,l=m;break}}else if(n[d+16+(((n[d+16>>2]|0)!=(B|0)&1)<<2)>>2]=s,!s){k=B,l=m;break}n[s+24>>2]=d,l=B+16|0,c=n[l>>2]|0,c|0&&(n[s+16>>2]=c,n[c+24>>2]=s),l=n[l+4>>2]|0,l?(n[s+20>>2]=l,n[l+24>>2]=s,k=B,l=m):(k=B,l=m)}else k=B,l=m}while(0);if(!(B>>>0>=Q>>>0)&&(s=Q+4|0,f=n[s>>2]|0,!!(f&1))){if(f&2)n[s>>2]=f&-2,n[k+4>>2]=l|1,n[B+l>>2]=l,d=l;else{if(s=n[2788]|0,(Q|0)==(n[2789]|0)){if(Q=(n[2786]|0)+l|0,n[2786]=Q,n[2789]=k,n[k+4>>2]=Q|1,(k|0)!=(s|0))return;n[2788]=0,n[2785]=0;return}if((Q|0)==(s|0)){Q=(n[2785]|0)+l|0,n[2785]=Q,n[2788]=B,n[k+4>>2]=Q|1,n[B+Q>>2]=Q;return}d=(f&-8)+l|0,c=f>>>3;do if(f>>>0<256)if(l=n[Q+8>>2]|0,s=n[Q+12>>2]|0,(s|0)==(l|0)){n[2783]=n[2783]&~(1<<c);break}else{n[l+12>>2]=s,n[s+8>>2]=l;break}else{m=n[Q+24>>2]|0,s=n[Q+12>>2]|0;do if((s|0)==(Q|0)){if(c=Q+16|0,l=c+4|0,s=n[l>>2]|0,!s)if(s=n[c>>2]|0,s)l=c;else{c=0;break}for(;;){if(c=s+20|0,f=n[c>>2]|0,f|0){s=f,l=c;continue}if(c=s+16|0,f=n[c>>2]|0,f)s=f,l=c;else break}n[l>>2]=0,c=s}else c=n[Q+8>>2]|0,n[c+12>>2]=s,n[s+8>>2]=c,c=s;while(0);if(m|0){if(s=n[Q+28>>2]|0,l=11436+(s<<2)|0,(Q|0)==(n[l>>2]|0)){if(n[l>>2]=c,!c){n[2784]=n[2784]&~(1<<s);break}}else if(n[m+16+(((n[m+16>>2]|0)!=(Q|0)&1)<<2)>>2]=c,!c)break;n[c+24>>2]=m,s=Q+16|0,l=n[s>>2]|0,l|0&&(n[c+16>>2]=l,n[l+24>>2]=c),s=n[s+4>>2]|0,s|0&&(n[c+20>>2]=s,n[s+24>>2]=c)}}while(0);if(n[k+4>>2]=d|1,n[B+d>>2]=d,(k|0)==(n[2788]|0)){n[2785]=d;return}}if(s=d>>>3,d>>>0<256){c=11172+(s<<1<<2)|0,l=n[2783]|0,s=1<<s,l&s?(l=c+8|0,s=n[l>>2]|0):(n[2783]=l|s,s=c,l=c+8|0),n[l>>2]=k,n[s+12>>2]=k,n[k+8>>2]=s,n[k+12>>2]=c;return}s=d>>>8,s?d>>>0>16777215?s=31:(B=(s+1048320|0)>>>16&8,Q=s<<B,m=(Q+520192|0)>>>16&4,Q=Q<<m,s=(Q+245760|0)>>>16&2,s=14-(m|B|s)+(Q<<s>>>15)|0,s=d>>>(s+7|0)&1|s<<1):s=0,f=11436+(s<<2)|0,n[k+28>>2]=s,n[k+20>>2]=0,n[k+16>>2]=0,l=n[2784]|0,c=1<<s;do if(l&c){for(l=d<<((s|0)==31?0:25-(s>>>1)|0),c=n[f>>2]|0;;){if((n[c+4>>2]&-8|0)==(d|0)){s=73;break}if(f=c+16+(l>>>31<<2)|0,s=n[f>>2]|0,s)l=l<<1,c=s;else{s=72;break}}if((s|0)==72){n[f>>2]=k,n[k+24>>2]=c,n[k+12>>2]=k,n[k+8>>2]=k;break}else if((s|0)==73){B=c+8|0,Q=n[B>>2]|0,n[Q+12>>2]=k,n[B>>2]=k,n[k+8>>2]=Q,n[k+12>>2]=c,n[k+24>>2]=0;break}}else n[2784]=l|c,n[f>>2]=k,n[k+24>>2]=f,n[k+12>>2]=k,n[k+8>>2]=k;while(0);if(Q=(n[2791]|0)+-1|0,n[2791]=Q,!Q)s=11588;else return;for(;s=n[s>>2]|0,s;)s=s+8|0;n[2791]=-1}}}function PUe(){return 11628}function SUe(s){s=s|0;var l=0,c=0;return l=C,C=C+16|0,c=l,n[c>>2]=kUe(n[s+60>>2]|0)|0,s=gD(gc(6,c|0)|0)|0,C=l,s|0}function r7(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0;G=C,C=C+48|0,M=G+16|0,m=G,d=G+32|0,k=s+28|0,f=n[k>>2]|0,n[d>>2]=f,Q=s+20|0,f=(n[Q>>2]|0)-f|0,n[d+4>>2]=f,n[d+8>>2]=l,n[d+12>>2]=c,f=f+c|0,B=s+60|0,n[m>>2]=n[B>>2],n[m+4>>2]=d,n[m+8>>2]=2,m=gD(Ni(146,m|0)|0)|0;e:do if((f|0)!=(m|0)){for(l=2;!((m|0)<0);)if(f=f-m|0,je=n[d+4>>2]|0,se=m>>>0>je>>>0,d=se?d+8|0:d,l=(se<<31>>31)+l|0,je=m-(se?je:0)|0,n[d>>2]=(n[d>>2]|0)+je,se=d+4|0,n[se>>2]=(n[se>>2]|0)-je,n[M>>2]=n[B>>2],n[M+4>>2]=d,n[M+8>>2]=l,m=gD(Ni(146,M|0)|0)|0,(f|0)==(m|0)){O=3;break e}n[s+16>>2]=0,n[k>>2]=0,n[Q>>2]=0,n[s>>2]=n[s>>2]|32,(l|0)==2?c=0:c=c-(n[d+4>>2]|0)|0}else O=3;while(0);return(O|0)==3&&(je=n[s+44>>2]|0,n[s+16>>2]=je+(n[s+48>>2]|0),n[k>>2]=je,n[Q>>2]=je),C=G,c|0}function bUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;return d=C,C=C+32|0,m=d,f=d+20|0,n[m>>2]=n[s+60>>2],n[m+4>>2]=0,n[m+8>>2]=l,n[m+12>>2]=f,n[m+16>>2]=c,(gD(sa(140,m|0)|0)|0)<0?(n[f>>2]=-1,s=-1):s=n[f>>2]|0,C=d,s|0}function gD(s){return s=s|0,s>>>0>4294963200&&(n[(zm()|0)>>2]=0-s,s=-1),s|0}function zm(){return(xUe()|0)+64|0}function xUe(){return PR()|0}function PR(){return 2084}function kUe(s){return s=s|0,s|0}function QUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;return d=C,C=C+32|0,f=d,n[s+36>>2]=1,(n[s>>2]&64|0)==0&&(n[f>>2]=n[s+60>>2],n[f+4>>2]=21523,n[f+8>>2]=d+16,pu(54,f|0)|0)&&(o[s+75>>0]=-1),f=r7(s,l,c)|0,C=d,f|0}function n7(s,l){s=s|0,l=l|0;var c=0,f=0;if(c=o[s>>0]|0,f=o[l>>0]|0,c<<24>>24==0||c<<24>>24!=f<<24>>24)s=f;else{do s=s+1|0,l=l+1|0,c=o[s>>0]|0,f=o[l>>0]|0;while(!(c<<24>>24==0||c<<24>>24!=f<<24>>24));s=f}return(c&255)-(s&255)|0}function FUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;e:do if(!c)s=0;else{for(;f=o[s>>0]|0,d=o[l>>0]|0,f<<24>>24==d<<24>>24;)if(c=c+-1|0,c)s=s+1|0,l=l+1|0;else{s=0;break e}s=(f&255)-(d&255)|0}while(0);return s|0}function i7(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0;Qe=C,C=C+224|0,O=Qe+120|0,G=Qe+80|0,je=Qe,Me=Qe+136|0,f=G,d=f+40|0;do n[f>>2]=0,f=f+4|0;while((f|0)<(d|0));return n[O>>2]=n[c>>2],(SR(0,l,O,je,G)|0)<0?c=-1:((n[s+76>>2]|0)>-1?se=RUe(s)|0:se=0,c=n[s>>2]|0,M=c&32,(o[s+74>>0]|0)<1&&(n[s>>2]=c&-33),f=s+48|0,n[f>>2]|0?c=SR(s,l,O,je,G)|0:(d=s+44|0,m=n[d>>2]|0,n[d>>2]=Me,B=s+28|0,n[B>>2]=Me,k=s+20|0,n[k>>2]=Me,n[f>>2]=80,Q=s+16|0,n[Q>>2]=Me+80,c=SR(s,l,O,je,G)|0,m&&(ED[n[s+36>>2]&7](s,0,0)|0,c=(n[k>>2]|0)==0?-1:c,n[d>>2]=m,n[f>>2]=0,n[Q>>2]=0,n[B>>2]=0,n[k>>2]=0)),f=n[s>>2]|0,n[s>>2]=f|M,se|0&&TUe(s),c=(f&32|0)==0?c:-1),C=Qe,c|0}function SR(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0,et=0,Xe=0,lt=0,Ue=0,Ge=0,Nt=0,Mr=0,ar=0,Xt=0,Pr=0,Lr=0,sr=0;sr=C,C=C+64|0,ar=sr+16|0,Xt=sr,Nt=sr+24|0,Pr=sr+8|0,Lr=sr+20|0,n[ar>>2]=l,lt=(s|0)!=0,Ue=Nt+40|0,Ge=Ue,Nt=Nt+39|0,Mr=Pr+4|0,B=0,m=0,O=0;e:for(;;){do if((m|0)>-1)if((B|0)>(2147483647-m|0)){n[(zm()|0)>>2]=75,m=-1;break}else{m=B+m|0;break}while(0);if(B=o[l>>0]|0,B<<24>>24)k=l;else{Xe=87;break}t:for(;;){switch(B<<24>>24){case 37:{B=k,Xe=9;break t}case 0:{B=k;break t}default:}et=k+1|0,n[ar>>2]=et,B=o[et>>0]|0,k=et}t:do if((Xe|0)==9)for(;;){if(Xe=0,(o[k+1>>0]|0)!=37)break t;if(B=B+1|0,k=k+2|0,n[ar>>2]=k,(o[k>>0]|0)==37)Xe=9;else break}while(0);if(B=B-l|0,lt&&ss(s,l,B),B|0){l=k;continue}Q=k+1|0,B=(o[Q>>0]|0)+-48|0,B>>>0<10?(et=(o[k+2>>0]|0)==36,Qe=et?B:-1,O=et?1:O,Q=et?k+3|0:Q):Qe=-1,n[ar>>2]=Q,B=o[Q>>0]|0,k=(B<<24>>24)+-32|0;t:do if(k>>>0<32)for(M=0,G=B;;){if(B=1<<k,!(B&75913)){B=G;break t}if(M=B|M,Q=Q+1|0,n[ar>>2]=Q,B=o[Q>>0]|0,k=(B<<24>>24)+-32|0,k>>>0>=32)break;G=B}else M=0;while(0);if(B<<24>>24==42){if(k=Q+1|0,B=(o[k>>0]|0)+-48|0,B>>>0<10&&(o[Q+2>>0]|0)==36)n[d+(B<<2)>>2]=10,B=n[f+((o[k>>0]|0)+-48<<3)>>2]|0,O=1,Q=Q+3|0;else{if(O|0){m=-1;break}lt?(O=(n[c>>2]|0)+(4-1)&~(4-1),B=n[O>>2]|0,n[c>>2]=O+4,O=0,Q=k):(B=0,O=0,Q=k)}n[ar>>2]=Q,et=(B|0)<0,B=et?0-B|0:B,M=et?M|8192:M}else{if(B=s7(ar)|0,(B|0)<0){m=-1;break}Q=n[ar>>2]|0}do if((o[Q>>0]|0)==46){if((o[Q+1>>0]|0)!=42){n[ar>>2]=Q+1,k=s7(ar)|0,Q=n[ar>>2]|0;break}if(G=Q+2|0,k=(o[G>>0]|0)+-48|0,k>>>0<10&&(o[Q+3>>0]|0)==36){n[d+(k<<2)>>2]=10,k=n[f+((o[G>>0]|0)+-48<<3)>>2]|0,Q=Q+4|0,n[ar>>2]=Q;break}if(O|0){m=-1;break e}lt?(et=(n[c>>2]|0)+(4-1)&~(4-1),k=n[et>>2]|0,n[c>>2]=et+4):k=0,n[ar>>2]=G,Q=G}else k=-1;while(0);for(Me=0;;){if(((o[Q>>0]|0)+-65|0)>>>0>57){m=-1;break e}if(et=Q+1|0,n[ar>>2]=et,G=o[(o[Q>>0]|0)+-65+(5178+(Me*58|0))>>0]|0,se=G&255,(se+-1|0)>>>0<8)Me=se,Q=et;else break}if(!(G<<24>>24)){m=-1;break}je=(Qe|0)>-1;do if(G<<24>>24==19)if(je){m=-1;break e}else Xe=49;else{if(je){n[d+(Qe<<2)>>2]=se,je=f+(Qe<<3)|0,Qe=n[je+4>>2]|0,Xe=Xt,n[Xe>>2]=n[je>>2],n[Xe+4>>2]=Qe,Xe=49;break}if(!lt){m=0;break e}o7(Xt,se,c)}while(0);if((Xe|0)==49&&(Xe=0,!lt)){B=0,l=et;continue}Q=o[Q>>0]|0,Q=(Me|0)!=0&(Q&15|0)==3?Q&-33:Q,je=M&-65537,Qe=(M&8192|0)==0?M:je;t:do switch(Q|0){case 110:switch((Me&255)<<24>>24){case 0:{n[n[Xt>>2]>>2]=m,B=0,l=et;continue e}case 1:{n[n[Xt>>2]>>2]=m,B=0,l=et;continue e}case 2:{B=n[Xt>>2]|0,n[B>>2]=m,n[B+4>>2]=((m|0)<0)<<31>>31,B=0,l=et;continue e}case 3:{a[n[Xt>>2]>>1]=m,B=0,l=et;continue e}case 4:{o[n[Xt>>2]>>0]=m,B=0,l=et;continue e}case 6:{n[n[Xt>>2]>>2]=m,B=0,l=et;continue e}case 7:{B=n[Xt>>2]|0,n[B>>2]=m,n[B+4>>2]=((m|0)<0)<<31>>31,B=0,l=et;continue e}default:{B=0,l=et;continue e}}case 112:{Q=120,k=k>>>0>8?k:8,l=Qe|8,Xe=61;break}case 88:case 120:{l=Qe,Xe=61;break}case 111:{Q=Xt,l=n[Q>>2]|0,Q=n[Q+4>>2]|0,se=NUe(l,Q,Ue)|0,je=Ge-se|0,M=0,G=5642,k=(Qe&8|0)==0|(k|0)>(je|0)?k:je+1|0,je=Qe,Xe=67;break}case 105:case 100:if(Q=Xt,l=n[Q>>2]|0,Q=n[Q+4>>2]|0,(Q|0)<0){l=dD(0,0,l|0,Q|0)|0,Q=Pe,M=Xt,n[M>>2]=l,n[M+4>>2]=Q,M=1,G=5642,Xe=66;break t}else{M=(Qe&2049|0)!=0&1,G=(Qe&2048|0)==0?(Qe&1|0)==0?5642:5644:5643,Xe=66;break t}case 117:{Q=Xt,M=0,G=5642,l=n[Q>>2]|0,Q=n[Q+4>>2]|0,Xe=66;break}case 99:{o[Nt>>0]=n[Xt>>2],l=Nt,M=0,G=5642,se=Ue,Q=1,k=je;break}case 109:{Q=OUe(n[(zm()|0)>>2]|0)|0,Xe=71;break}case 115:{Q=n[Xt>>2]|0,Q=Q|0?Q:5652,Xe=71;break}case 67:{n[Pr>>2]=n[Xt>>2],n[Mr>>2]=0,n[Xt>>2]=Pr,se=-1,Q=Pr,Xe=75;break}case 83:{l=n[Xt>>2]|0,k?(se=k,Q=l,Xe=75):(Bs(s,32,B,0,Qe),l=0,Xe=84);break}case 65:case 71:case 70:case 69:case 97:case 103:case 102:case 101:{B=UUe(s,+E[Xt>>3],B,k,Qe,Q)|0,l=et;continue e}default:M=0,G=5642,se=Ue,Q=k,k=Qe}while(0);t:do if((Xe|0)==61)Qe=Xt,Me=n[Qe>>2]|0,Qe=n[Qe+4>>2]|0,se=LUe(Me,Qe,Ue,Q&32)|0,G=(l&8|0)==0|(Me|0)==0&(Qe|0)==0,M=G?0:2,G=G?5642:5642+(Q>>4)|0,je=l,l=Me,Q=Qe,Xe=67;else if((Xe|0)==66)se=Vm(l,Q,Ue)|0,je=Qe,Xe=67;else if((Xe|0)==71)Xe=0,Qe=MUe(Q,0,k)|0,Me=(Qe|0)==0,l=Q,M=0,G=5642,se=Me?Q+k|0:Qe,Q=Me?k:Qe-Q|0,k=je;else if((Xe|0)==75){for(Xe=0,G=Q,l=0,k=0;M=n[G>>2]|0,!(!M||(k=a7(Lr,M)|0,(k|0)<0|k>>>0>(se-l|0)>>>0));)if(l=k+l|0,se>>>0>l>>>0)G=G+4|0;else break;if((k|0)<0){m=-1;break e}if(Bs(s,32,B,l,Qe),!l)l=0,Xe=84;else for(M=0;;){if(k=n[Q>>2]|0,!k){Xe=84;break t}if(k=a7(Lr,k)|0,M=k+M|0,(M|0)>(l|0)){Xe=84;break t}if(ss(s,Lr,k),M>>>0>=l>>>0){Xe=84;break}else Q=Q+4|0}}while(0);if((Xe|0)==67)Xe=0,Q=(l|0)!=0|(Q|0)!=0,Qe=(k|0)!=0|Q,Q=((Q^1)&1)+(Ge-se)|0,l=Qe?se:Ue,se=Ue,Q=Qe?(k|0)>(Q|0)?k:Q:k,k=(k|0)>-1?je&-65537:je;else if((Xe|0)==84){Xe=0,Bs(s,32,B,l,Qe^8192),B=(B|0)>(l|0)?B:l,l=et;continue}Me=se-l|0,je=(Q|0)<(Me|0)?Me:Q,Qe=je+M|0,B=(B|0)<(Qe|0)?Qe:B,Bs(s,32,B,Qe,k),ss(s,G,M),Bs(s,48,B,Qe,k^65536),Bs(s,48,je,Me,0),ss(s,l,Me),Bs(s,32,B,Qe,k^8192),l=et}e:do if((Xe|0)==87&&!s)if(!O)m=0;else{for(m=1;l=n[d+(m<<2)>>2]|0,!!l;)if(o7(f+(m<<3)|0,l,c),m=m+1|0,(m|0)>=10){m=1;break e}for(;;){if(n[d+(m<<2)>>2]|0){m=-1;break e}if(m=m+1|0,(m|0)>=10){m=1;break}}}while(0);return C=sr,m|0}function RUe(s){return s=s|0,0}function TUe(s){s=s|0}function ss(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]&32||zUe(l,c,s)|0}function s7(s){s=s|0;var l=0,c=0,f=0;if(c=n[s>>2]|0,f=(o[c>>0]|0)+-48|0,f>>>0<10){l=0;do l=f+(l*10|0)|0,c=c+1|0,n[s>>2]=c,f=(o[c>>0]|0)+-48|0;while(f>>>0<10)}else l=0;return l|0}function o7(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;e:do if(l>>>0<=20)do switch(l|0){case 9:{f=(n[c>>2]|0)+(4-1)&~(4-1),l=n[f>>2]|0,n[c>>2]=f+4,n[s>>2]=l;break e}case 10:{f=(n[c>>2]|0)+(4-1)&~(4-1),l=n[f>>2]|0,n[c>>2]=f+4,f=s,n[f>>2]=l,n[f+4>>2]=((l|0)<0)<<31>>31;break e}case 11:{f=(n[c>>2]|0)+(4-1)&~(4-1),l=n[f>>2]|0,n[c>>2]=f+4,f=s,n[f>>2]=l,n[f+4>>2]=0;break e}case 12:{f=(n[c>>2]|0)+(8-1)&~(8-1),l=f,d=n[l>>2]|0,l=n[l+4>>2]|0,n[c>>2]=f+8,f=s,n[f>>2]=d,n[f+4>>2]=l;break e}case 13:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,f=(f&65535)<<16>>16,d=s,n[d>>2]=f,n[d+4>>2]=((f|0)<0)<<31>>31;break e}case 14:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,d=s,n[d>>2]=f&65535,n[d+4>>2]=0;break e}case 15:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,f=(f&255)<<24>>24,d=s,n[d>>2]=f,n[d+4>>2]=((f|0)<0)<<31>>31;break e}case 16:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,d=s,n[d>>2]=f&255,n[d+4>>2]=0;break e}case 17:{d=(n[c>>2]|0)+(8-1)&~(8-1),m=+E[d>>3],n[c>>2]=d+8,E[s>>3]=m;break e}case 18:{d=(n[c>>2]|0)+(8-1)&~(8-1),m=+E[d>>3],n[c>>2]=d+8,E[s>>3]=m;break e}default:break e}while(0);while(0)}function LUe(s,l,c,f){if(s=s|0,l=l|0,c=c|0,f=f|0,!((s|0)==0&(l|0)==0))do c=c+-1|0,o[c>>0]=u[5694+(s&15)>>0]|0|f,s=mD(s|0,l|0,4)|0,l=Pe;while(!((s|0)==0&(l|0)==0));return c|0}function NUe(s,l,c){if(s=s|0,l=l|0,c=c|0,!((s|0)==0&(l|0)==0))do c=c+-1|0,o[c>>0]=s&7|48,s=mD(s|0,l|0,3)|0,l=Pe;while(!((s|0)==0&(l|0)==0));return c|0}function Vm(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;if(l>>>0>0|(l|0)==0&s>>>0>4294967295){for(;f=QR(s|0,l|0,10,0)|0,c=c+-1|0,o[c>>0]=f&255|48,f=s,s=kR(s|0,l|0,10,0)|0,l>>>0>9|(l|0)==9&f>>>0>4294967295;)l=Pe;l=s}else l=s;if(l)for(;c=c+-1|0,o[c>>0]=(l>>>0)%10|0|48,!(l>>>0<10);)l=(l>>>0)/10|0;return c|0}function OUe(s){return s=s|0,jUe(s,n[(GUe()|0)+188>>2]|0)|0}function MUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;m=l&255,f=(c|0)!=0;e:do if(f&(s&3|0)!=0)for(d=l&255;;){if((o[s>>0]|0)==d<<24>>24){B=6;break e}if(s=s+1|0,c=c+-1|0,f=(c|0)!=0,!(f&(s&3|0)!=0)){B=5;break}}else B=5;while(0);(B|0)==5&&(f?B=6:c=0);e:do if((B|0)==6&&(d=l&255,(o[s>>0]|0)!=d<<24>>24)){f=qe(m,16843009)|0;t:do if(c>>>0>3){for(;m=n[s>>2]^f,!((m&-2139062144^-2139062144)&m+-16843009|0);)if(s=s+4|0,c=c+-4|0,c>>>0<=3){B=11;break t}}else B=11;while(0);if((B|0)==11&&!c){c=0;break}for(;;){if((o[s>>0]|0)==d<<24>>24)break e;if(s=s+1|0,c=c+-1|0,!c){c=0;break}}}while(0);return(c|0?s:0)|0}function Bs(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0;if(B=C,C=C+256|0,m=B,(c|0)>(f|0)&(d&73728|0)==0){if(d=c-f|0,Xm(m|0,l|0,(d>>>0<256?d:256)|0)|0,d>>>0>255){l=c-f|0;do ss(s,m,256),d=d+-256|0;while(d>>>0>255);d=l&255}ss(s,m,d)}C=B}function a7(s,l){return s=s|0,l=l|0,s?s=HUe(s,l,0)|0:s=0,s|0}function UUe(s,l,c,f,d,m){s=s|0,l=+l,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0,et=0,Xe=0,lt=0,Ue=0,Ge=0,Nt=0,Mr=0,ar=0,Xt=0,Pr=0,Lr=0,sr=0,xn=0;xn=C,C=C+560|0,Q=xn+8|0,et=xn,sr=xn+524|0,Lr=sr,M=xn+512|0,n[et>>2]=0,Pr=M+12|0,l7(l)|0,(Pe|0)<0?(l=-l,ar=1,Mr=5659):(ar=(d&2049|0)!=0&1,Mr=(d&2048|0)==0?(d&1|0)==0?5660:5665:5662),l7(l)|0,Xt=Pe&2146435072;do if(Xt>>>0<2146435072|(Xt|0)==2146435072&0<0){if(je=+_Ue(l,et)*2,B=je!=0,B&&(n[et>>2]=(n[et>>2]|0)+-1),lt=m|32,(lt|0)==97){Me=m&32,se=(Me|0)==0?Mr:Mr+9|0,G=ar|2,B=12-f|0;do if(f>>>0>11|(B|0)==0)l=je;else{l=8;do B=B+-1|0,l=l*16;while((B|0)!=0);if((o[se>>0]|0)==45){l=-(l+(-je-l));break}else{l=je+l-l;break}}while(0);k=n[et>>2]|0,B=(k|0)<0?0-k|0:k,B=Vm(B,((B|0)<0)<<31>>31,Pr)|0,(B|0)==(Pr|0)&&(B=M+11|0,o[B>>0]=48),o[B+-1>>0]=(k>>31&2)+43,O=B+-2|0,o[O>>0]=m+15,M=(f|0)<1,Q=(d&8|0)==0,B=sr;do Xt=~~l,k=B+1|0,o[B>>0]=u[5694+Xt>>0]|Me,l=(l-+(Xt|0))*16,(k-Lr|0)==1&&!(Q&(M&l==0))?(o[k>>0]=46,B=B+2|0):B=k;while(l!=0);Xt=B-Lr|0,Lr=Pr-O|0,Pr=(f|0)!=0&(Xt+-2|0)<(f|0)?f+2|0:Xt,B=Lr+G+Pr|0,Bs(s,32,c,B,d),ss(s,se,G),Bs(s,48,c,B,d^65536),ss(s,sr,Xt),Bs(s,48,Pr-Xt|0,0,0),ss(s,O,Lr),Bs(s,32,c,B,d^8192);break}k=(f|0)<0?6:f,B?(B=(n[et>>2]|0)+-28|0,n[et>>2]=B,l=je*268435456):(l=je,B=n[et>>2]|0),Xt=(B|0)<0?Q:Q+288|0,Q=Xt;do Ge=~~l>>>0,n[Q>>2]=Ge,Q=Q+4|0,l=(l-+(Ge>>>0))*1e9;while(l!=0);if((B|0)>0)for(M=Xt,G=Q;;){if(O=(B|0)<29?B:29,B=G+-4|0,B>>>0>=M>>>0){Q=0;do Ue=h7(n[B>>2]|0,0,O|0)|0,Ue=xR(Ue|0,Pe|0,Q|0,0)|0,Ge=Pe,Xe=QR(Ue|0,Ge|0,1e9,0)|0,n[B>>2]=Xe,Q=kR(Ue|0,Ge|0,1e9,0)|0,B=B+-4|0;while(B>>>0>=M>>>0);Q&&(M=M+-4|0,n[M>>2]=Q)}for(Q=G;!(Q>>>0<=M>>>0);)if(B=Q+-4|0,!(n[B>>2]|0))Q=B;else break;if(B=(n[et>>2]|0)-O|0,n[et>>2]=B,(B|0)>0)G=Q;else break}else M=Xt;if((B|0)<0){f=((k+25|0)/9|0)+1|0,Qe=(lt|0)==102;do{if(Me=0-B|0,Me=(Me|0)<9?Me:9,M>>>0<Q>>>0){O=(1<<Me)+-1|0,G=1e9>>>Me,se=0,B=M;do Ge=n[B>>2]|0,n[B>>2]=(Ge>>>Me)+se,se=qe(Ge&O,G)|0,B=B+4|0;while(B>>>0<Q>>>0);B=(n[M>>2]|0)==0?M+4|0:M,se?(n[Q>>2]=se,M=B,B=Q+4|0):(M=B,B=Q)}else M=(n[M>>2]|0)==0?M+4|0:M,B=Q;Q=Qe?Xt:M,Q=(B-Q>>2|0)>(f|0)?Q+(f<<2)|0:B,B=(n[et>>2]|0)+Me|0,n[et>>2]=B}while((B|0)<0);B=M,f=Q}else B=M,f=Q;if(Ge=Xt,B>>>0<f>>>0){if(Q=(Ge-B>>2)*9|0,O=n[B>>2]|0,O>>>0>=10){M=10;do M=M*10|0,Q=Q+1|0;while(O>>>0>=M>>>0)}}else Q=0;if(Qe=(lt|0)==103,Xe=(k|0)!=0,M=k-((lt|0)!=102?Q:0)+((Xe&Qe)<<31>>31)|0,(M|0)<(((f-Ge>>2)*9|0)+-9|0)){if(M=M+9216|0,Me=Xt+4+(((M|0)/9|0)+-1024<<2)|0,M=((M|0)%9|0)+1|0,(M|0)<9){O=10;do O=O*10|0,M=M+1|0;while((M|0)!=9)}else O=10;if(G=n[Me>>2]|0,se=(G>>>0)%(O>>>0)|0,M=(Me+4|0)==(f|0),M&(se|0)==0)M=Me;else if(je=(((G>>>0)/(O>>>0)|0)&1|0)==0?9007199254740992:9007199254740994,Ue=(O|0)/2|0,l=se>>>0<Ue>>>0?.5:M&(se|0)==(Ue|0)?1:1.5,ar&&(Ue=(o[Mr>>0]|0)==45,l=Ue?-l:l,je=Ue?-je:je),M=G-se|0,n[Me>>2]=M,je+l!=je){if(Ue=M+O|0,n[Me>>2]=Ue,Ue>>>0>999999999)for(Q=Me;M=Q+-4|0,n[Q>>2]=0,M>>>0<B>>>0&&(B=B+-4|0,n[B>>2]=0),Ue=(n[M>>2]|0)+1|0,n[M>>2]=Ue,Ue>>>0>999999999;)Q=M;else M=Me;if(Q=(Ge-B>>2)*9|0,G=n[B>>2]|0,G>>>0>=10){O=10;do O=O*10|0,Q=Q+1|0;while(G>>>0>=O>>>0)}}else M=Me;M=M+4|0,M=f>>>0>M>>>0?M:f,Ue=B}else M=f,Ue=B;for(lt=M;;){if(lt>>>0<=Ue>>>0){et=0;break}if(B=lt+-4|0,!(n[B>>2]|0))lt=B;else{et=1;break}}f=0-Q|0;do if(Qe)if(B=((Xe^1)&1)+k|0,(B|0)>(Q|0)&(Q|0)>-5?(O=m+-1|0,k=B+-1-Q|0):(O=m+-2|0,k=B+-1|0),B=d&8,B)Me=B;else{if(et&&(Nt=n[lt+-4>>2]|0,(Nt|0)!=0))if((Nt>>>0)%10|0)M=0;else{M=0,B=10;do B=B*10|0,M=M+1|0;while(!((Nt>>>0)%(B>>>0)|0|0))}else M=9;if(B=((lt-Ge>>2)*9|0)+-9|0,(O|32|0)==102){Me=B-M|0,Me=(Me|0)>0?Me:0,k=(k|0)<(Me|0)?k:Me,Me=0;break}else{Me=B+Q-M|0,Me=(Me|0)>0?Me:0,k=(k|0)<(Me|0)?k:Me,Me=0;break}}else O=m,Me=d&8;while(0);if(Qe=k|Me,G=(Qe|0)!=0&1,se=(O|32|0)==102,se)Xe=0,B=(Q|0)>0?Q:0;else{if(B=(Q|0)<0?f:Q,B=Vm(B,((B|0)<0)<<31>>31,Pr)|0,M=Pr,(M-B|0)<2)do B=B+-1|0,o[B>>0]=48;while((M-B|0)<2);o[B+-1>>0]=(Q>>31&2)+43,B=B+-2|0,o[B>>0]=O,Xe=B,B=M-B|0}if(B=ar+1+k+G+B|0,Bs(s,32,c,B,d),ss(s,Mr,ar),Bs(s,48,c,B,d^65536),se){O=Ue>>>0>Xt>>>0?Xt:Ue,Me=sr+9|0,G=Me,se=sr+8|0,M=O;do{if(Q=Vm(n[M>>2]|0,0,Me)|0,(M|0)==(O|0))(Q|0)==(Me|0)&&(o[se>>0]=48,Q=se);else if(Q>>>0>sr>>>0){Xm(sr|0,48,Q-Lr|0)|0;do Q=Q+-1|0;while(Q>>>0>sr>>>0)}ss(s,Q,G-Q|0),M=M+4|0}while(M>>>0<=Xt>>>0);if(Qe|0&&ss(s,5710,1),M>>>0<lt>>>0&(k|0)>0)for(;;){if(Q=Vm(n[M>>2]|0,0,Me)|0,Q>>>0>sr>>>0){Xm(sr|0,48,Q-Lr|0)|0;do Q=Q+-1|0;while(Q>>>0>sr>>>0)}if(ss(s,Q,(k|0)<9?k:9),M=M+4|0,Q=k+-9|0,M>>>0<lt>>>0&(k|0)>9)k=Q;else{k=Q;break}}Bs(s,48,k+9|0,9,0)}else{if(Qe=et?lt:Ue+4|0,(k|0)>-1){et=sr+9|0,Me=(Me|0)==0,f=et,G=0-Lr|0,se=sr+8|0,O=Ue;do{Q=Vm(n[O>>2]|0,0,et)|0,(Q|0)==(et|0)&&(o[se>>0]=48,Q=se);do if((O|0)==(Ue|0)){if(M=Q+1|0,ss(s,Q,1),Me&(k|0)<1){Q=M;break}ss(s,5710,1),Q=M}else{if(Q>>>0<=sr>>>0)break;Xm(sr|0,48,Q+G|0)|0;do Q=Q+-1|0;while(Q>>>0>sr>>>0)}while(0);Lr=f-Q|0,ss(s,Q,(k|0)>(Lr|0)?Lr:k),k=k-Lr|0,O=O+4|0}while(O>>>0<Qe>>>0&(k|0)>-1)}Bs(s,48,k+18|0,18,0),ss(s,Xe,Pr-Xe|0)}Bs(s,32,c,B,d^8192)}else sr=(m&32|0)!=0,B=ar+3|0,Bs(s,32,c,B,d&-65537),ss(s,Mr,ar),ss(s,l!=l|!1?sr?5686:5690:sr?5678:5682,3),Bs(s,32,c,B,d^8192);while(0);return C=xn,((B|0)<(c|0)?c:B)|0}function l7(s){s=+s;var l=0;return E[v>>3]=s,l=n[v>>2]|0,Pe=n[v+4>>2]|0,l|0}function _Ue(s,l){return s=+s,l=l|0,+ +c7(s,l)}function c7(s,l){s=+s,l=l|0;var c=0,f=0,d=0;switch(E[v>>3]=s,c=n[v>>2]|0,f=n[v+4>>2]|0,d=mD(c|0,f|0,52)|0,d&2047){case 0:{s!=0?(s=+c7(s*18446744073709552e3,l),c=(n[l>>2]|0)+-64|0):c=0,n[l>>2]=c;break}case 2047:break;default:n[l>>2]=(d&2047)+-1022,n[v>>2]=c,n[v+4>>2]=f&-2146435073|1071644672,s=+E[v>>3]}return+s}function HUe(s,l,c){s=s|0,l=l|0,c=c|0;do if(s){if(l>>>0<128){o[s>>0]=l,s=1;break}if(!(n[n[(qUe()|0)+188>>2]>>2]|0))if((l&-128|0)==57216){o[s>>0]=l,s=1;break}else{n[(zm()|0)>>2]=84,s=-1;break}if(l>>>0<2048){o[s>>0]=l>>>6|192,o[s+1>>0]=l&63|128,s=2;break}if(l>>>0<55296|(l&-8192|0)==57344){o[s>>0]=l>>>12|224,o[s+1>>0]=l>>>6&63|128,o[s+2>>0]=l&63|128,s=3;break}if((l+-65536|0)>>>0<1048576){o[s>>0]=l>>>18|240,o[s+1>>0]=l>>>12&63|128,o[s+2>>0]=l>>>6&63|128,o[s+3>>0]=l&63|128,s=4;break}else{n[(zm()|0)>>2]=84,s=-1;break}}else s=1;while(0);return s|0}function qUe(){return PR()|0}function GUe(){return PR()|0}function jUe(s,l){s=s|0,l=l|0;var c=0,f=0;for(f=0;;){if((u[5712+f>>0]|0)==(s|0)){s=2;break}if(c=f+1|0,(c|0)==87){c=5800,f=87,s=5;break}else f=c}if((s|0)==2&&(f?(c=5800,s=5):c=5800),(s|0)==5)for(;;){do s=c,c=c+1|0;while((o[s>>0]|0)!=0);if(f=f+-1|0,f)s=5;else break}return YUe(c,n[l+20>>2]|0)|0}function YUe(s,l){return s=s|0,l=l|0,WUe(s,l)|0}function WUe(s,l){return s=s|0,l=l|0,l?l=KUe(n[l>>2]|0,n[l+4>>2]|0,s)|0:l=0,(l|0?l:s)|0}function KUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;se=(n[s>>2]|0)+1794895138|0,m=Tg(n[s+8>>2]|0,se)|0,f=Tg(n[s+12>>2]|0,se)|0,d=Tg(n[s+16>>2]|0,se)|0;e:do if(m>>>0<l>>>2>>>0&&(G=l-(m<<2)|0,f>>>0<G>>>0&d>>>0<G>>>0)&&((d|f)&3|0)==0){for(G=f>>>2,O=d>>>2,M=0;;){if(k=m>>>1,Q=M+k|0,B=Q<<1,d=B+G|0,f=Tg(n[s+(d<<2)>>2]|0,se)|0,d=Tg(n[s+(d+1<<2)>>2]|0,se)|0,!(d>>>0<l>>>0&f>>>0<(l-d|0)>>>0)){f=0;break e}if(o[s+(d+f)>>0]|0){f=0;break e}if(f=n7(c,s+d|0)|0,!f)break;if(f=(f|0)<0,(m|0)==1){f=0;break e}else M=f?M:Q,m=f?k:m-k|0}f=B+O|0,d=Tg(n[s+(f<<2)>>2]|0,se)|0,f=Tg(n[s+(f+1<<2)>>2]|0,se)|0,f>>>0<l>>>0&d>>>0<(l-f|0)>>>0?f=(o[s+(f+d)>>0]|0)==0?s+f|0:0:f=0}else f=0;while(0);return f|0}function Tg(s,l){s=s|0,l=l|0;var c=0;return c=m7(s|0)|0,((l|0)==0?s:c)|0}function zUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=c+16|0,d=n[f>>2]|0,d?m=5:VUe(c)|0?f=0:(d=n[f>>2]|0,m=5);e:do if((m|0)==5){if(k=c+20|0,B=n[k>>2]|0,f=B,(d-B|0)>>>0<l>>>0){f=ED[n[c+36>>2]&7](c,s,l)|0;break}t:do if((o[c+75>>0]|0)>-1){for(B=l;;){if(!B){m=0,d=s;break t}if(d=B+-1|0,(o[s+d>>0]|0)==10)break;B=d}if(f=ED[n[c+36>>2]&7](c,s,B)|0,f>>>0<B>>>0)break e;m=B,d=s+B|0,l=l-B|0,f=n[k>>2]|0}else m=0,d=s;while(0);Dr(f|0,d|0,l|0)|0,n[k>>2]=(n[k>>2]|0)+l,f=m+l|0}while(0);return f|0}function VUe(s){s=s|0;var l=0,c=0;return l=s+74|0,c=o[l>>0]|0,o[l>>0]=c+255|c,l=n[s>>2]|0,l&8?(n[s>>2]=l|32,s=-1):(n[s+8>>2]=0,n[s+4>>2]=0,c=n[s+44>>2]|0,n[s+28>>2]=c,n[s+20>>2]=c,n[s+16>>2]=c+(n[s+48>>2]|0),s=0),s|0}function _n(s,l){s=y(s),l=y(l);var c=0,f=0;c=u7(s)|0;do if((c&2147483647)>>>0<=2139095040){if(f=u7(l)|0,(f&2147483647)>>>0<=2139095040)if((f^c|0)<0){s=(c|0)<0?l:s;break}else{s=s<l?l:s;break}}else s=l;while(0);return y(s)}function u7(s){return s=y(s),h[v>>2]=s,n[v>>2]|0|0}function Lg(s,l){s=y(s),l=y(l);var c=0,f=0;c=A7(s)|0;do if((c&2147483647)>>>0<=2139095040){if(f=A7(l)|0,(f&2147483647)>>>0<=2139095040)if((f^c|0)<0){s=(c|0)<0?s:l;break}else{s=s<l?s:l;break}}else s=l;while(0);return y(s)}function A7(s){return s=y(s),h[v>>2]=s,n[v>>2]|0|0}function bR(s,l){s=y(s),l=y(l);var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0;m=(h[v>>2]=s,n[v>>2]|0),k=(h[v>>2]=l,n[v>>2]|0),c=m>>>23&255,B=k>>>23&255,Q=m&-2147483648,d=k<<1;e:do if((d|0)!=0&&!((c|0)==255|((JUe(l)|0)&2147483647)>>>0>2139095040)){if(f=m<<1,f>>>0<=d>>>0)return l=y(s*y(0)),y((f|0)==(d|0)?l:s);if(c)f=m&8388607|8388608;else{if(c=m<<9,(c|0)>-1){f=c,c=0;do c=c+-1|0,f=f<<1;while((f|0)>-1)}else c=0;f=m<<1-c}if(B)k=k&8388607|8388608;else{if(m=k<<9,(m|0)>-1){d=0;do d=d+-1|0,m=m<<1;while((m|0)>-1)}else d=0;B=d,k=k<<1-d}d=f-k|0,m=(d|0)>-1;t:do if((c|0)>(B|0)){for(;;){if(m)if(d)f=d;else break;if(f=f<<1,c=c+-1|0,d=f-k|0,m=(d|0)>-1,(c|0)<=(B|0))break t}l=y(s*y(0));break e}while(0);if(m)if(d)f=d;else{l=y(s*y(0));break}if(f>>>0<8388608)do f=f<<1,c=c+-1|0;while(f>>>0<8388608);(c|0)>0?c=f+-8388608|c<<23:c=f>>>(1-c|0),l=(n[v>>2]=c|Q,y(h[v>>2]))}else M=3;while(0);return(M|0)==3&&(l=y(s*l),l=y(l/l)),y(l)}function JUe(s){return s=y(s),h[v>>2]=s,n[v>>2]|0|0}function XUe(s,l){return s=s|0,l=l|0,i7(n[582]|0,s,l)|0}function Jr(s){s=s|0,Rt()}function Jm(s){s=s|0}function ZUe(s,l){return s=s|0,l=l|0,0}function $Ue(s){return s=s|0,(f7(s+4|0)|0)==-1?(tf[n[(n[s>>2]|0)+8>>2]&127](s),s=1):s=0,s|0}function f7(s){s=s|0;var l=0;return l=n[s>>2]|0,n[s>>2]=l+-1,l+-1|0}function Qp(s){s=s|0,$Ue(s)|0&&e3e(s)}function e3e(s){s=s|0;var l=0;l=s+8|0,(n[l>>2]|0)!=0&&(f7(l)|0)!=-1||tf[n[(n[s>>2]|0)+16>>2]&127](s)}function Kt(s){s=s|0;var l=0;for(l=(s|0)==0?1:s;s=pD(l)|0,!(s|0);){if(s=r3e()|0,!s){s=0;break}S7[s&0]()}return s|0}function p7(s){return s=s|0,Kt(s)|0}function gt(s){s=s|0,hD(s)}function t3e(s){s=s|0,(o[s+11>>0]|0)<0&&gt(n[s>>2]|0)}function r3e(){var s=0;return s=n[2923]|0,n[2923]=s+0,s|0}function n3e(){}function dD(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,f=l-f-(c>>>0>s>>>0|0)>>>0,Pe=f,s-c>>>0|0|0}function xR(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,c=s+c>>>0,Pe=l+f+(c>>>0<s>>>0|0)>>>0,c|0|0}function Xm(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;if(m=s+c|0,l=l&255,(c|0)>=67){for(;s&3;)o[s>>0]=l,s=s+1|0;for(f=m&-4|0,d=f-64|0,B=l|l<<8|l<<16|l<<24;(s|0)<=(d|0);)n[s>>2]=B,n[s+4>>2]=B,n[s+8>>2]=B,n[s+12>>2]=B,n[s+16>>2]=B,n[s+20>>2]=B,n[s+24>>2]=B,n[s+28>>2]=B,n[s+32>>2]=B,n[s+36>>2]=B,n[s+40>>2]=B,n[s+44>>2]=B,n[s+48>>2]=B,n[s+52>>2]=B,n[s+56>>2]=B,n[s+60>>2]=B,s=s+64|0;for(;(s|0)<(f|0);)n[s>>2]=B,s=s+4|0}for(;(s|0)<(m|0);)o[s>>0]=l,s=s+1|0;return m-c|0}function h7(s,l,c){return s=s|0,l=l|0,c=c|0,(c|0)<32?(Pe=l<<c|(s&(1<<c)-1<<32-c)>>>32-c,s<<c):(Pe=s<<c-32,0)}function mD(s,l,c){return s=s|0,l=l|0,c=c|0,(c|0)<32?(Pe=l>>>c,s>>>c|(l&(1<<c)-1)<<32-c):(Pe=0,l>>>c-32|0)}function Dr(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;if((c|0)>=8192)return fc(s|0,l|0,c|0)|0;if(m=s|0,d=s+c|0,(s&3)==(l&3)){for(;s&3;){if(!c)return m|0;o[s>>0]=o[l>>0]|0,s=s+1|0,l=l+1|0,c=c-1|0}for(c=d&-4|0,f=c-64|0;(s|0)<=(f|0);)n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=n[l+8>>2],n[s+12>>2]=n[l+12>>2],n[s+16>>2]=n[l+16>>2],n[s+20>>2]=n[l+20>>2],n[s+24>>2]=n[l+24>>2],n[s+28>>2]=n[l+28>>2],n[s+32>>2]=n[l+32>>2],n[s+36>>2]=n[l+36>>2],n[s+40>>2]=n[l+40>>2],n[s+44>>2]=n[l+44>>2],n[s+48>>2]=n[l+48>>2],n[s+52>>2]=n[l+52>>2],n[s+56>>2]=n[l+56>>2],n[s+60>>2]=n[l+60>>2],s=s+64|0,l=l+64|0;for(;(s|0)<(c|0);)n[s>>2]=n[l>>2],s=s+4|0,l=l+4|0}else for(c=d-4|0;(s|0)<(c|0);)o[s>>0]=o[l>>0]|0,o[s+1>>0]=o[l+1>>0]|0,o[s+2>>0]=o[l+2>>0]|0,o[s+3>>0]=o[l+3>>0]|0,s=s+4|0,l=l+4|0;for(;(s|0)<(d|0);)o[s>>0]=o[l>>0]|0,s=s+1|0,l=l+1|0;return m|0}function g7(s){s=s|0;var l=0;return l=o[N+(s&255)>>0]|0,(l|0)<8?l|0:(l=o[N+(s>>8&255)>>0]|0,(l|0)<8?l+8|0:(l=o[N+(s>>16&255)>>0]|0,(l|0)<8?l+16|0:(o[N+(s>>>24)>>0]|0)+24|0))}function d7(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0;if(O=s,Q=l,M=Q,B=c,se=f,k=se,!M)return m=(d|0)!=0,k?m?(n[d>>2]=s|0,n[d+4>>2]=l&0,se=0,d=0,Pe=se,d|0):(se=0,d=0,Pe=se,d|0):(m&&(n[d>>2]=(O>>>0)%(B>>>0),n[d+4>>2]=0),se=0,d=(O>>>0)/(B>>>0)>>>0,Pe=se,d|0);m=(k|0)==0;do if(B){if(!m){if(m=(S(k|0)|0)-(S(M|0)|0)|0,m>>>0<=31){G=m+1|0,k=31-m|0,l=m-31>>31,B=G,s=O>>>(G>>>0)&l|M<<k,l=M>>>(G>>>0)&l,m=0,k=O<<k;break}return d?(n[d>>2]=s|0,n[d+4>>2]=Q|l&0,se=0,d=0,Pe=se,d|0):(se=0,d=0,Pe=se,d|0)}if(m=B-1|0,m&B|0){k=(S(B|0)|0)+33-(S(M|0)|0)|0,Me=64-k|0,G=32-k|0,Q=G>>31,je=k-32|0,l=je>>31,B=k,s=G-1>>31&M>>>(je>>>0)|(M<<G|O>>>(k>>>0))&l,l=l&M>>>(k>>>0),m=O<<Me&Q,k=(M<<Me|O>>>(je>>>0))&Q|O<<G&k-33>>31;break}return d|0&&(n[d>>2]=m&O,n[d+4>>2]=0),(B|0)==1?(je=Q|l&0,Me=s|0|0,Pe=je,Me|0):(Me=g7(B|0)|0,je=M>>>(Me>>>0)|0,Me=M<<32-Me|O>>>(Me>>>0)|0,Pe=je,Me|0)}else{if(m)return d|0&&(n[d>>2]=(M>>>0)%(B>>>0),n[d+4>>2]=0),je=0,Me=(M>>>0)/(B>>>0)>>>0,Pe=je,Me|0;if(!O)return d|0&&(n[d>>2]=0,n[d+4>>2]=(M>>>0)%(k>>>0)),je=0,Me=(M>>>0)/(k>>>0)>>>0,Pe=je,Me|0;if(m=k-1|0,!(m&k))return d|0&&(n[d>>2]=s|0,n[d+4>>2]=m&M|l&0),je=0,Me=M>>>((g7(k|0)|0)>>>0),Pe=je,Me|0;if(m=(S(k|0)|0)-(S(M|0)|0)|0,m>>>0<=30){l=m+1|0,k=31-m|0,B=l,s=M<<k|O>>>(l>>>0),l=M>>>(l>>>0),m=0,k=O<<k;break}return d?(n[d>>2]=s|0,n[d+4>>2]=Q|l&0,je=0,Me=0,Pe=je,Me|0):(je=0,Me=0,Pe=je,Me|0)}while(0);if(!B)M=k,Q=0,k=0;else{G=c|0|0,O=se|f&0,M=xR(G|0,O|0,-1,-1)|0,c=Pe,Q=k,k=0;do f=Q,Q=m>>>31|Q<<1,m=k|m<<1,f=s<<1|f>>>31|0,se=s>>>31|l<<1|0,dD(M|0,c|0,f|0,se|0)|0,Me=Pe,je=Me>>31|((Me|0)<0?-1:0)<<1,k=je&1,s=dD(f|0,se|0,je&G|0,(((Me|0)<0?-1:0)>>31|((Me|0)<0?-1:0)<<1)&O|0)|0,l=Pe,B=B-1|0;while((B|0)!=0);M=Q,Q=0}return B=0,d|0&&(n[d>>2]=s,n[d+4>>2]=l),je=(m|0)>>>31|(M|B)<<1|(B<<1|m>>>31)&0|Q,Me=(m<<1|0>>>31)&-2|k,Pe=je,Me|0}function kR(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,d7(s,l,c,f,0)|0}function Fp(s){s=s|0;var l=0,c=0;return c=s+15&-16|0,l=n[I>>2]|0,s=l+c|0,(c|0)>0&(s|0)<(l|0)|(s|0)<0?(ie()|0,DA(12),-1):(n[I>>2]=s,(s|0)>(Z()|0)&&(X()|0)==0?(n[I>>2]=l,DA(12),-1):l|0)}function Mw(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;if((l|0)<(s|0)&(s|0)<(l+c|0)){for(f=s,l=l+c|0,s=s+c|0;(c|0)>0;)s=s-1|0,l=l-1|0,c=c-1|0,o[s>>0]=o[l>>0]|0;s=f}else Dr(s,l,c)|0;return s|0}function QR(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;return m=C,C=C+16|0,d=m|0,d7(s,l,c,f,d)|0,C=m,Pe=n[d+4>>2]|0,n[d>>2]|0|0}function m7(s){return s=s|0,(s&255)<<24|(s>>8&255)<<16|(s>>16&255)<<8|s>>>24|0}function i3e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,y7[s&1](l|0,c|0,f|0,d|0,m|0)}function s3e(s,l,c){s=s|0,l=l|0,c=y(c),E7[s&1](l|0,y(c))}function o3e(s,l,c){s=s|0,l=l|0,c=+c,C7[s&31](l|0,+c)}function a3e(s,l,c,f){return s=s|0,l=l|0,c=y(c),f=y(f),y(w7[s&0](l|0,y(c),y(f)))}function l3e(s,l){s=s|0,l=l|0,tf[s&127](l|0)}function c3e(s,l,c){s=s|0,l=l|0,c=c|0,rf[s&31](l|0,c|0)}function u3e(s,l){return s=s|0,l=l|0,Og[s&31](l|0)|0}function A3e(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0,I7[s&1](l|0,+c,+f,d|0)}function f3e(s,l,c,f){s=s|0,l=l|0,c=+c,f=+f,W3e[s&1](l|0,+c,+f)}function p3e(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,ED[s&7](l|0,c|0,f|0)|0}function h3e(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,+K3e[s&1](l|0,c|0,f|0)}function g3e(s,l){return s=s|0,l=l|0,+B7[s&15](l|0)}function d3e(s,l,c){return s=s|0,l=l|0,c=+c,z3e[s&1](l|0,+c)|0}function m3e(s,l,c){return s=s|0,l=l|0,c=c|0,RR[s&15](l|0,c|0)|0}function y3e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=+f,d=+d,m=m|0,V3e[s&1](l|0,c|0,+f,+d,m|0)}function E3e(s,l,c,f,d,m,B){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0,J3e[s&1](l|0,c|0,f|0,d|0,m|0,B|0)}function C3e(s,l,c){return s=s|0,l=l|0,c=c|0,+v7[s&7](l|0,c|0)}function w3e(s){return s=s|0,CD[s&7]()|0}function I3e(s,l,c,f,d,m){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,D7[s&1](l|0,c|0,f|0,d|0,m|0)|0}function B3e(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=+d,X3e[s&1](l|0,c|0,f|0,+d)}function v3e(s,l,c,f,d,m,B){s=s|0,l=l|0,c=c|0,f=y(f),d=d|0,m=y(m),B=B|0,P7[s&1](l|0,c|0,y(f),d|0,y(m),B|0)}function D3e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,Hw[s&15](l|0,c|0,f|0)}function P3e(s){s=s|0,S7[s&0]()}function S3e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f,b7[s&15](l|0,c|0,+f)}function b3e(s,l,c){return s=s|0,l=+l,c=+c,Z3e[s&1](+l,+c)|0}function x3e(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,TR[s&15](l|0,c|0,f|0,d|0)}function k3e(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,F(0)}function Q3e(s,l){s=s|0,l=y(l),F(1)}function ma(s,l){s=s|0,l=+l,F(2)}function F3e(s,l,c){return s=s|0,l=y(l),c=y(c),F(3),Ze}function Er(s){s=s|0,F(4)}function Uw(s,l){s=s|0,l=l|0,F(5)}function Ja(s){return s=s|0,F(6),0}function R3e(s,l,c,f){s=s|0,l=+l,c=+c,f=f|0,F(7)}function T3e(s,l,c){s=s|0,l=+l,c=+c,F(8)}function L3e(s,l,c){return s=s|0,l=l|0,c=c|0,F(9),0}function N3e(s,l,c){return s=s|0,l=l|0,c=c|0,F(10),0}function Ng(s){return s=s|0,F(11),0}function O3e(s,l){return s=s|0,l=+l,F(12),0}function _w(s,l){return s=s|0,l=l|0,F(13),0}function M3e(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0,F(14)}function U3e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,F(15)}function FR(s,l){return s=s|0,l=l|0,F(16),0}function _3e(){return F(17),0}function H3e(s,l,c,f,d){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,F(18),0}function q3e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f,F(19)}function G3e(s,l,c,f,d,m){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=m|0,F(20)}function yD(s,l,c){s=s|0,l=l|0,c=c|0,F(21)}function j3e(){F(22)}function Zm(s,l,c){s=s|0,l=l|0,c=+c,F(23)}function Y3e(s,l){return s=+s,l=+l,F(24),0}function $m(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,F(25)}var y7=[k3e,HNe],E7=[Q3e,fo],C7=[ma,xw,kw,EF,CF,Pl,Qw,wF,qm,xu,Rw,IF,$v,KA,eD,Gm,tD,rD,jm,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma],w7=[F3e],tf=[Er,Jm,wDe,IDe,BDe,Zbe,$be,exe,dLe,mLe,yLe,bNe,xNe,kNe,J4e,X4e,Z4e,hs,zv,Hm,WA,Fw,mve,yve,ADe,QDe,GDe,aPe,BPe,_Pe,nSe,ySe,RSe,VSe,Abe,Sbe,Gbe,mxe,Rxe,Vxe,Ake,Ske,Gke,lQe,BQe,OQe,$Qe,bc,kFe,WFe,ARe,xRe,jRe,ATe,wTe,vTe,HTe,jTe,aLe,CLe,BLe,_Le,iNe,i9,UOe,dMe,QMe,WMe,h4e,x4e,_4e,G4e,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er],rf=[Uw,fF,pF,bw,bu,hF,gF,vp,dF,mF,yF,Zv,zA,ze,ft,Wt,vr,Sn,Fr,vF,ive,Sve,fQe,PQe,RRe,qOe,fNe,q5,Uw,Uw,Uw,Uw],Og=[Ja,SUe,AF,D,Ae,De,vt,wt,xt,_r,di,po,tve,rve,Eve,rFe,zRe,GLe,WOe,Ka,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja],I7=[R3e,Cve],W3e=[T3e,uLe],ED=[L3e,r7,bUe,QUe,jPe,wxe,TFe,JMe],K3e=[N3e,gbe],B7=[Ng,Yo,rt,bn,wve,Ive,Bve,vve,Dve,Pve,Ng,Ng,Ng,Ng,Ng,Ng],z3e=[O3e,yTe],RR=[_w,ZUe,nve,gDe,APe,oSe,wSe,Kbe,Oxe,HQe,Wv,LMe,_w,_w,_w,_w],V3e=[M3e,KDe],J3e=[U3e,y4e],v7=[FR,ai,bve,xve,kve,Qbe,FR,FR],CD=[_3e,Qve,Pw,ga,bTe,zTe,SLe,K4e],D7=[H3e,Cw],X3e=[q3e,gke],P7=[G3e,sve],Hw=[yD,T,is,tn,ho,SPe,NSe,Qke,Kke,_m,uOe,CMe,R4e,yD,yD,yD],S7=[j3e],b7=[Zm,Vv,Jv,Xv,YA,nD,BF,P,$xe,JFe,hTe,Zm,Zm,Zm,Zm,Zm],Z3e=[Y3e,hLe],TR=[$m,$Se,uFe,gRe,nTe,TTe,eLe,TLe,cNe,ZOe,iUe,$m,$m,$m,$m,$m];return{_llvm_bswap_i32:m7,dynCall_idd:b3e,dynCall_i:w3e,_i64Subtract:dD,___udivdi3:kR,dynCall_vif:s3e,setThrew:gu,dynCall_viii:D3e,_bitshift64Lshr:mD,_bitshift64Shl:h7,dynCall_vi:l3e,dynCall_viiddi:y3e,dynCall_diii:h3e,dynCall_iii:m3e,_memset:Xm,_sbrk:Fp,_memcpy:Dr,__GLOBAL__sub_I_Yoga_cpp:Um,dynCall_vii:c3e,___uremdi3:QR,dynCall_vid:o3e,stackAlloc:lo,_nbind_init:gUe,getTempRet0:Ha,dynCall_di:g3e,dynCall_iid:d3e,setTempRet0:xA,_i64Add:xR,dynCall_fiff:a3e,dynCall_iiii:p3e,_emscripten_get_global_libc:PUe,dynCall_viid:S3e,dynCall_viiid:B3e,dynCall_viififi:v3e,dynCall_ii:u3e,__GLOBAL__sub_I_Binding_cc:QOe,dynCall_viiii:x3e,dynCall_iiiiii:I3e,stackSave:dc,dynCall_viiiii:i3e,__GLOBAL__sub_I_nbind_cc:Fve,dynCall_vidd:f3e,_free:hD,runPostSets:n3e,dynCall_viiiiii:E3e,establishStackSpace:qi,_memmove:Mw,stackRestore:hu,_malloc:pD,__GLOBAL__sub_I_common_cc:XLe,dynCall_viddi:A3e,dynCall_dii:C3e,dynCall_v:P3e}}(Module.asmGlobalArg,Module.asmLibraryArg,buffer),_llvm_bswap_i32=Module._llvm_bswap_i32=asm._llvm_bswap_i32,getTempRet0=Module.getTempRet0=asm.getTempRet0,___udivdi3=Module.___udivdi3=asm.___udivdi3,setThrew=Module.setThrew=asm.setThrew,_bitshift64Lshr=Module._bitshift64Lshr=asm._bitshift64Lshr,_bitshift64Shl=Module._bitshift64Shl=asm._bitshift64Shl,_memset=Module._memset=asm._memset,_sbrk=Module._sbrk=asm._sbrk,_memcpy=Module._memcpy=asm._memcpy,stackAlloc=Module.stackAlloc=asm.stackAlloc,___uremdi3=Module.___uremdi3=asm.___uremdi3,_nbind_init=Module._nbind_init=asm._nbind_init,_i64Subtract=Module._i64Subtract=asm._i64Subtract,setTempRet0=Module.setTempRet0=asm.setTempRet0,_i64Add=Module._i64Add=asm._i64Add,_emscripten_get_global_libc=Module._emscripten_get_global_libc=asm._emscripten_get_global_libc,__GLOBAL__sub_I_Yoga_cpp=Module.__GLOBAL__sub_I_Yoga_cpp=asm.__GLOBAL__sub_I_Yoga_cpp,__GLOBAL__sub_I_Binding_cc=Module.__GLOBAL__sub_I_Binding_cc=asm.__GLOBAL__sub_I_Binding_cc,stackSave=Module.stackSave=asm.stackSave,__GLOBAL__sub_I_nbind_cc=Module.__GLOBAL__sub_I_nbind_cc=asm.__GLOBAL__sub_I_nbind_cc,_free=Module._free=asm._free,runPostSets=Module.runPostSets=asm.runPostSets,establishStackSpace=Module.establishStackSpace=asm.establishStackSpace,_memmove=Module._memmove=asm._memmove,stackRestore=Module.stackRestore=asm.stackRestore,_malloc=Module._malloc=asm._malloc,__GLOBAL__sub_I_common_cc=Module.__GLOBAL__sub_I_common_cc=asm.__GLOBAL__sub_I_common_cc,dynCall_viiiii=Module.dynCall_viiiii=asm.dynCall_viiiii,dynCall_vif=Module.dynCall_vif=asm.dynCall_vif,dynCall_vid=Module.dynCall_vid=asm.dynCall_vid,dynCall_fiff=Module.dynCall_fiff=asm.dynCall_fiff,dynCall_vi=Module.dynCall_vi=asm.dynCall_vi,dynCall_vii=Module.dynCall_vii=asm.dynCall_vii,dynCall_ii=Module.dynCall_ii=asm.dynCall_ii,dynCall_viddi=Module.dynCall_viddi=asm.dynCall_viddi,dynCall_vidd=Module.dynCall_vidd=asm.dynCall_vidd,dynCall_iiii=Module.dynCall_iiii=asm.dynCall_iiii,dynCall_diii=Module.dynCall_diii=asm.dynCall_diii,dynCall_di=Module.dynCall_di=asm.dynCall_di,dynCall_iid=Module.dynCall_iid=asm.dynCall_iid,dynCall_iii=Module.dynCall_iii=asm.dynCall_iii,dynCall_viiddi=Module.dynCall_viiddi=asm.dynCall_viiddi,dynCall_viiiiii=Module.dynCall_viiiiii=asm.dynCall_viiiiii,dynCall_dii=Module.dynCall_dii=asm.dynCall_dii,dynCall_i=Module.dynCall_i=asm.dynCall_i,dynCall_iiiiii=Module.dynCall_iiiiii=asm.dynCall_iiiiii,dynCall_viiid=Module.dynCall_viiid=asm.dynCall_viiid,dynCall_viififi=Module.dynCall_viififi=asm.dynCall_viififi,dynCall_viii=Module.dynCall_viii=asm.dynCall_viii,dynCall_v=Module.dynCall_v=asm.dynCall_v,dynCall_viid=Module.dynCall_viid=asm.dynCall_viid,dynCall_idd=Module.dynCall_idd=asm.dynCall_idd,dynCall_viiii=Module.dynCall_viiii=asm.dynCall_viiii;Runtime.stackAlloc=Module.stackAlloc,Runtime.stackSave=Module.stackSave,Runtime.stackRestore=Module.stackRestore,Runtime.establishStackSpace=Module.establishStackSpace,Runtime.setTempRet0=Module.setTempRet0,Runtime.getTempRet0=Module.getTempRet0,Module.asm=asm;function ExitStatus(t){this.name="ExitStatus",this.message="Program terminated with exit("+t+")",this.status=t}ExitStatus.prototype=new Error,ExitStatus.prototype.constructor=ExitStatus;var initialStackTop,preloadStartTime=null,calledMain=!1;dependenciesFulfilled=function t(){Module.calledRun||run(),Module.calledRun||(dependenciesFulfilled=t)},Module.callMain=Module.callMain=function t(e){e=e||[],ensureInitRuntime();var r=e.length+1;function o(){for(var p=0;p<4-1;p++)a.push(0)}var a=[allocate(intArrayFromString(Module.thisProgram),"i8",ALLOC_NORMAL)];o();for(var n=0;n<r-1;n=n+1)a.push(allocate(intArrayFromString(e[n]),"i8",ALLOC_NORMAL)),o();a.push(0),a=allocate(a,"i32",ALLOC_NORMAL);try{var u=Module._main(r,a,0);exit(u,!0)}catch(p){if(p instanceof ExitStatus)return;if(p=="SimulateInfiniteLoop"){Module.noExitRuntime=!0;return}else{var A=p;p&&typeof p=="object"&&p.stack&&(A=[p,p.stack]),Module.printErr("exception thrown: "+A),Module.quit(1,p)}}finally{calledMain=!0}};function run(t){if(t=t||Module.arguments,preloadStartTime===null&&(preloadStartTime=Date.now()),runDependencies>0||(preRun(),runDependencies>0)||Module.calledRun)return;function e(){Module.calledRun||(Module.calledRun=!0,!ABORT&&(ensureInitRuntime(),preMain(),Module.onRuntimeInitialized&&Module.onRuntimeInitialized(),Module._main&&shouldRunNow&&Module.callMain(t),postRun()))}Module.setStatus?(Module.setStatus("Running..."),setTimeout(function(){setTimeout(function(){Module.setStatus("")},1),e()},1)):e()}Module.run=Module.run=run;function exit(t,e){e&&Module.noExitRuntime||(Module.noExitRuntime||(ABORT=!0,EXITSTATUS=t,STACKTOP=initialStackTop,exitRuntime(),Module.onExit&&Module.onExit(t)),ENVIRONMENT_IS_NODE&&process.exit(t),Module.quit(t,new ExitStatus(t)))}Module.exit=Module.exit=exit;var abortDecorators=[];function abort(t){Module.onAbort&&Module.onAbort(t),t!==void 0?(Module.print(t),Module.printErr(t),t=JSON.stringify(t)):t="",ABORT=!0,EXITSTATUS=1;var e=`
-If this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.`,r="abort("+t+") at "+stackTrace()+e;throw abortDecorators&&abortDecorators.forEach(function(o){r=o(r,t)}),r}if(Module.abort=Module.abort=abort,Module.preInit)for(typeof Module.preInit=="function"&&(Module.preInit=[Module.preInit]);Module.preInit.length>0;)Module.preInit.pop()();var shouldRunNow=!0;Module.noInitialRun&&(shouldRunNow=!1),run()})});var lm=_((IKt,NEe)=>{"use strict";var Yyt=TEe(),Wyt=LEe(),x6=!1,k6=null;Wyt({},function(t,e){if(!x6){if(x6=!0,t)throw t;k6=e}});if(!x6)throw new Error("Failed to load the yoga module - it needed to be loaded synchronously, but didn't");NEe.exports=Yyt(k6.bind,k6.lib)});var F6=_((BKt,Q6)=>{"use strict";var OEe=t=>Number.isNaN(t)?!1:t>=4352&&(t<=4447||t===9001||t===9002||11904<=t&&t<=12871&&t!==12351||12880<=t&&t<=19903||19968<=t&&t<=42182||43360<=t&&t<=43388||44032<=t&&t<=55203||63744<=t&&t<=64255||65040<=t&&t<=65049||65072<=t&&t<=65131||65281<=t&&t<=65376||65504<=t&&t<=65510||110592<=t&&t<=110593||127488<=t&&t<=127569||131072<=t&&t<=262141);Q6.exports=OEe;Q6.exports.default=OEe});var UEe=_((vKt,MEe)=>{"use strict";MEe.exports=function(){return/\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F|\uD83D\uDC68(?:\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68\uD83C\uDFFB|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|[\u2695\u2696\u2708]\uFE0F|\uD83D[\uDC66\uDC67]|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708])\uFE0F|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C[\uDFFB-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)\uD83C\uDFFB|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB\uDFFC])|\uD83D\uDC69(?:\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB-\uDFFD])|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|(?:(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)\uFE0F|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD6-\uDDDD])(?:(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\u200D[\u2640\u2642])|\uD83C\uDFF4\u200D\u2620)\uFE0F|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF6\uD83C\uDDE6|[#\*0-9]\uFE0F\u20E3|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270A-\u270D]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC70\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDCAA\uDD74\uDD7A\uDD90\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD36\uDDB5\uDDB6\uDDBB\uDDD2-\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5\uDEEB\uDEEC\uDEF4-\uDEFA\uDFE0-\uDFEB]|\uD83E[\uDD0D-\uDD3A\uDD3C-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDCA\uDDCD-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFA\uDFE0-\uDFEB]|\uD83E[\uDD0D-\uDD3A\uDD3C-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDCA\uDDCD-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g}});var Kk=_((DKt,R6)=>{"use strict";var Kyt=NP(),zyt=F6(),Vyt=UEe(),_Ee=t=>{if(typeof t!="string"||t.length===0||(t=Kyt(t),t.length===0))return 0;t=t.replace(Vyt()," ");let e=0;for(let r=0;r<t.length;r++){let o=t.codePointAt(r);o<=31||o>=127&&o<=159||o>=768&&o<=879||(o>65535&&r++,e+=zyt(o)?2:1)}return e};R6.exports=_Ee;R6.exports.default=_Ee});var L6=_((PKt,T6)=>{"use strict";var Jyt=Kk(),HEe=t=>{let e=0;for(let r of t.split(`
-`))e=Math.max(e,Jyt(r));return e};T6.exports=HEe;T6.exports.default=HEe});var qEe=_(cB=>{"use strict";var Xyt=cB&&cB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(cB,"__esModule",{value:!0});var Zyt=Xyt(L6()),N6={};cB.default=t=>{if(t.length===0)return{width:0,height:0};if(N6[t])return N6[t];let e=Zyt.default(t),r=t.split(`
-`).length;return N6[t]={width:e,height:r},{width:e,height:r}}});var GEe=_(uB=>{"use strict";var $yt=uB&&uB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(uB,"__esModule",{value:!0});var dn=$yt(lm()),eEt=(t,e)=>{"position"in e&&t.setPositionType(e.position==="absolute"?dn.default.POSITION_TYPE_ABSOLUTE:dn.default.POSITION_TYPE_RELATIVE)},tEt=(t,e)=>{"marginLeft"in e&&t.setMargin(dn.default.EDGE_START,e.marginLeft||0),"marginRight"in e&&t.setMargin(dn.default.EDGE_END,e.marginRight||0),"marginTop"in e&&t.setMargin(dn.default.EDGE_TOP,e.marginTop||0),"marginBottom"in e&&t.setMargin(dn.default.EDGE_BOTTOM,e.marginBottom||0)},rEt=(t,e)=>{"paddingLeft"in e&&t.setPadding(dn.default.EDGE_LEFT,e.paddingLeft||0),"paddingRight"in e&&t.setPadding(dn.default.EDGE_RIGHT,e.paddingRight||0),"paddingTop"in e&&t.setPadding(dn.default.EDGE_TOP,e.paddingTop||0),"paddingBottom"in e&&t.setPadding(dn.default.EDGE_BOTTOM,e.paddingBottom||0)},nEt=(t,e)=>{var r;"flexGrow"in e&&t.setFlexGrow((r=e.flexGrow)!==null&&r!==void 0?r:0),"flexShrink"in e&&t.setFlexShrink(typeof e.flexShrink=="number"?e.flexShrink:1),"flexDirection"in e&&(e.flexDirection==="row"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_ROW),e.flexDirection==="row-reverse"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_ROW_REVERSE),e.flexDirection==="column"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_COLUMN),e.flexDirection==="column-reverse"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_COLUMN_REVERSE)),"flexBasis"in e&&(typeof e.flexBasis=="number"?t.setFlexBasis(e.flexBasis):typeof e.flexBasis=="string"?t.setFlexBasisPercent(Number.parseInt(e.flexBasis,10)):t.setFlexBasis(NaN)),"alignItems"in e&&((e.alignItems==="stretch"||!e.alignItems)&&t.setAlignItems(dn.default.ALIGN_STRETCH),e.alignItems==="flex-start"&&t.setAlignItems(dn.default.ALIGN_FLEX_START),e.alignItems==="center"&&t.setAlignItems(dn.default.ALIGN_CENTER),e.alignItems==="flex-end"&&t.setAlignItems(dn.default.ALIGN_FLEX_END)),"alignSelf"in e&&((e.alignSelf==="auto"||!e.alignSelf)&&t.setAlignSelf(dn.default.ALIGN_AUTO),e.alignSelf==="flex-start"&&t.setAlignSelf(dn.default.ALIGN_FLEX_START),e.alignSelf==="center"&&t.setAlignSelf(dn.default.ALIGN_CENTER),e.alignSelf==="flex-end"&&t.setAlignSelf(dn.default.ALIGN_FLEX_END)),"justifyContent"in e&&((e.justifyContent==="flex-start"||!e.justifyContent)&&t.setJustifyContent(dn.default.JUSTIFY_FLEX_START),e.justifyContent==="center"&&t.setJustifyContent(dn.default.JUSTIFY_CENTER),e.justifyContent==="flex-end"&&t.setJustifyContent(dn.default.JUSTIFY_FLEX_END),e.justifyContent==="space-between"&&t.setJustifyContent(dn.default.JUSTIFY_SPACE_BETWEEN),e.justifyContent==="space-around"&&t.setJustifyContent(dn.default.JUSTIFY_SPACE_AROUND))},iEt=(t,e)=>{var r,o;"width"in e&&(typeof e.width=="number"?t.setWidth(e.width):typeof e.width=="string"?t.setWidthPercent(Number.parseInt(e.width,10)):t.setWidthAuto()),"height"in e&&(typeof e.height=="number"?t.setHeight(e.height):typeof e.height=="string"?t.setHeightPercent(Number.parseInt(e.height,10)):t.setHeightAuto()),"minWidth"in e&&(typeof e.minWidth=="string"?t.setMinWidthPercent(Number.parseInt(e.minWidth,10)):t.setMinWidth((r=e.minWidth)!==null&&r!==void 0?r:0)),"minHeight"in e&&(typeof e.minHeight=="string"?t.setMinHeightPercent(Number.parseInt(e.minHeight,10)):t.setMinHeight((o=e.minHeight)!==null&&o!==void 0?o:0))},sEt=(t,e)=>{"display"in e&&t.setDisplay(e.display==="flex"?dn.default.DISPLAY_FLEX:dn.default.DISPLAY_NONE)},oEt=(t,e)=>{if("borderStyle"in e){let r=typeof e.borderStyle=="string"?1:0;t.setBorder(dn.default.EDGE_TOP,r),t.setBorder(dn.default.EDGE_BOTTOM,r),t.setBorder(dn.default.EDGE_LEFT,r),t.setBorder(dn.default.EDGE_RIGHT,r)}};uB.default=(t,e={})=>{eEt(t,e),tEt(t,e),rEt(t,e),nEt(t,e),iEt(t,e),sEt(t,e),oEt(t,e)}});var WEe=_((xKt,YEe)=>{"use strict";var AB=Kk(),aEt=NP(),lEt=DI(),M6=new Set(["\x1B","\x9B"]),cEt=39,jEe=t=>`${M6.values().next().value}[${t}m`,uEt=t=>t.split(" ").map(e=>AB(e)),O6=(t,e,r)=>{let o=[...e],a=!1,n=AB(aEt(t[t.length-1]));for(let[u,A]of o.entries()){let p=AB(A);if(n+p<=r?t[t.length-1]+=A:(t.push(A),n=0),M6.has(A))a=!0;else if(a&&A==="m"){a=!1;continue}a||(n+=p,n===r&&u<o.length-1&&(t.push(""),n=0))}!n&&t[t.length-1].length>0&&t.length>1&&(t[t.length-2]+=t.pop())},AEt=t=>{let e=t.split(" "),r=e.length;for(;r>0&&!(AB(e[r-1])>0);)r--;return r===e.length?t:e.slice(0,r).join(" ")+e.slice(r).join("")},fEt=(t,e,r={})=>{if(r.trim!==!1&&t.trim()==="")return"";let o="",a="",n,u=uEt(t),A=[""];for(let[p,h]of t.split(" ").entries()){r.trim!==!1&&(A[A.length-1]=A[A.length-1].trimLeft());let E=AB(A[A.length-1]);if(p!==0&&(E>=e&&(r.wordWrap===!1||r.trim===!1)&&(A.push(""),E=0),(E>0||r.trim===!1)&&(A[A.length-1]+=" ",E++)),r.hard&&u[p]>e){let I=e-E,v=1+Math.floor((u[p]-I-1)/e);Math.floor((u[p]-1)/e)<v&&A.push(""),O6(A,h,e);continue}if(E+u[p]>e&&E>0&&u[p]>0){if(r.wordWrap===!1&&E<e){O6(A,h,e);continue}A.push("")}if(E+u[p]>e&&r.wordWrap===!1){O6(A,h,e);continue}A[A.length-1]+=h}r.trim!==!1&&(A=A.map(AEt)),o=A.join(`
-`);for(let[p,h]of[...o].entries()){if(a+=h,M6.has(h)){let I=parseFloat(/\d[^m]*/.exec(o.slice(p,p+4)));n=I===cEt?null:I}let E=lEt.codes.get(Number(n));n&&E&&(o[p+1]===`
-`?a+=jEe(E):h===`
-`&&(a+=jEe(n)))}return a};YEe.exports=(t,e,r)=>String(t).normalize().replace(/\r\n/g,`
-`).split(`
-`).map(o=>fEt(o,e,r)).join(`
-`)});var VEe=_((kKt,zEe)=>{"use strict";var KEe="[\uD800-\uDBFF][\uDC00-\uDFFF]",pEt=t=>t&&t.exact?new RegExp(`^${KEe}$`):new RegExp(KEe,"g");zEe.exports=pEt});var U6=_((QKt,$Ee)=>{"use strict";var hEt=F6(),gEt=VEe(),JEe=DI(),ZEe=["\x1B","\x9B"],zk=t=>`${ZEe[0]}[${t}m`,XEe=(t,e,r)=>{let o=[];t=[...t];for(let a of t){let n=a;a.match(";")&&(a=a.split(";")[0][0]+"0");let u=JEe.codes.get(parseInt(a,10));if(u){let A=t.indexOf(u.toString());A>=0?t.splice(A,1):o.push(zk(e?u:n))}else if(e){o.push(zk(0));break}else o.push(zk(n))}if(e&&(o=o.filter((a,n)=>o.indexOf(a)===n),r!==void 0)){let a=zk(JEe.codes.get(parseInt(r,10)));o=o.reduce((n,u)=>u===a?[u,...n]:[...n,u],[])}return o.join("")};$Ee.exports=(t,e,r)=>{let o=[...t.normalize()],a=[];r=typeof r=="number"?r:o.length;let n=!1,u,A=0,p="";for(let[h,E]of o.entries()){let I=!1;if(ZEe.includes(E)){let v=/\d[^m]*/.exec(t.slice(h,h+18));u=v&&v.length>0?v[0]:void 0,A<r&&(n=!0,u!==void 0&&a.push(u))}else n&&E==="m"&&(n=!1,I=!0);if(!n&&!I&&++A,!gEt({exact:!0}).test(E)&&hEt(E.codePointAt())&&++A,A>e&&A<=r)p+=E;else if(A===e&&!n&&u!==void 0)p=XEe(a);else if(A>=r){p+=XEe(a,!0,u);break}}return p}});var tCe=_((FKt,eCe)=>{"use strict";var C0=U6(),dEt=Kk();function Vk(t,e,r){if(t.charAt(e)===" ")return e;for(let o=1;o<=3;o++)if(r){if(t.charAt(e+o)===" ")return e+o}else if(t.charAt(e-o)===" ")return e-o;return e}eCe.exports=(t,e,r)=>{r={position:"end",preferTruncationOnSpace:!1,...r};let{position:o,space:a,preferTruncationOnSpace:n}=r,u="\u2026",A=1;if(typeof t!="string")throw new TypeError(`Expected \`input\` to be a string, got ${typeof t}`);if(typeof e!="number")throw new TypeError(`Expected \`columns\` to be a number, got ${typeof e}`);if(e<1)return"";if(e===1)return u;let p=dEt(t);if(p<=e)return t;if(o==="start"){if(n){let h=Vk(t,p-e+1,!0);return u+C0(t,h,p).trim()}return a===!0&&(u+=" ",A=2),u+C0(t,p-e+A,p)}if(o==="middle"){a===!0&&(u=" "+u+" ",A=3);let h=Math.floor(e/2);if(n){let E=Vk(t,h),I=Vk(t,p-(e-h)+1,!0);return C0(t,0,E)+u+C0(t,I,p).trim()}return C0(t,0,h)+u+C0(t,p-(e-h)+A,p)}if(o==="end"){if(n){let h=Vk(t,e-1);return C0(t,0,h)+u}return a===!0&&(u=" "+u,A=2),C0(t,0,e-A)+u}throw new Error(`Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${o}`)}});var H6=_(fB=>{"use strict";var rCe=fB&&fB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(fB,"__esModule",{value:!0});var mEt=rCe(WEe()),yEt=rCe(tCe()),_6={};fB.default=(t,e,r)=>{let o=t+String(e)+String(r);if(_6[o])return _6[o];let a=t;if(r==="wrap"&&(a=mEt.default(t,e,{trim:!1,hard:!0})),r.startsWith("truncate")){let n="end";r==="truncate-middle"&&(n="middle"),r==="truncate-start"&&(n="start"),a=yEt.default(t,e,{position:n})}return _6[o]=a,a}});var G6=_(q6=>{"use strict";Object.defineProperty(q6,"__esModule",{value:!0});var nCe=t=>{let e="";if(t.childNodes.length>0)for(let r of t.childNodes){let o="";r.nodeName==="#text"?o=r.nodeValue:((r.nodeName==="ink-text"||r.nodeName==="ink-virtual-text")&&(o=nCe(r)),o.length>0&&typeof r.internal_transform=="function"&&(o=r.internal_transform(o))),e+=o}return e};q6.default=nCe});var j6=_(pi=>{"use strict";var pB=pi&&pi.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(pi,"__esModule",{value:!0});pi.setTextNodeValue=pi.createTextNode=pi.setStyle=pi.setAttribute=pi.removeChildNode=pi.insertBeforeNode=pi.appendChildNode=pi.createNode=pi.TEXT_NAME=void 0;var EEt=pB(lm()),iCe=pB(qEe()),CEt=pB(GEe()),wEt=pB(H6()),IEt=pB(G6());pi.TEXT_NAME="#text";pi.createNode=t=>{var e;let r={nodeName:t,style:{},attributes:{},childNodes:[],parentNode:null,yogaNode:t==="ink-virtual-text"?void 0:EEt.default.Node.create()};return t==="ink-text"&&((e=r.yogaNode)===null||e===void 0||e.setMeasureFunc(BEt.bind(null,r))),r};pi.appendChildNode=(t,e)=>{var r;e.parentNode&&pi.removeChildNode(e.parentNode,e),e.parentNode=t,t.childNodes.push(e),e.yogaNode&&((r=t.yogaNode)===null||r===void 0||r.insertChild(e.yogaNode,t.yogaNode.getChildCount())),(t.nodeName==="ink-text"||t.nodeName==="ink-virtual-text")&&Jk(t)};pi.insertBeforeNode=(t,e,r)=>{var o,a;e.parentNode&&pi.removeChildNode(e.parentNode,e),e.parentNode=t;let n=t.childNodes.indexOf(r);if(n>=0){t.childNodes.splice(n,0,e),e.yogaNode&&((o=t.yogaNode)===null||o===void 0||o.insertChild(e.yogaNode,n));return}t.childNodes.push(e),e.yogaNode&&((a=t.yogaNode)===null||a===void 0||a.insertChild(e.yogaNode,t.yogaNode.getChildCount())),(t.nodeName==="ink-text"||t.nodeName==="ink-virtual-text")&&Jk(t)};pi.removeChildNode=(t,e)=>{var r,o;e.yogaNode&&((o=(r=e.parentNode)===null||r===void 0?void 0:r.yogaNode)===null||o===void 0||o.removeChild(e.yogaNode)),e.parentNode=null;let a=t.childNodes.indexOf(e);a>=0&&t.childNodes.splice(a,1),(t.nodeName==="ink-text"||t.nodeName==="ink-virtual-text")&&Jk(t)};pi.setAttribute=(t,e,r)=>{t.attributes[e]=r};pi.setStyle=(t,e)=>{t.style=e,t.yogaNode&&CEt.default(t.yogaNode,e)};pi.createTextNode=t=>{let e={nodeName:"#text",nodeValue:t,yogaNode:void 0,parentNode:null,style:{}};return pi.setTextNodeValue(e,t),e};var BEt=function(t,e){var r,o;let a=t.nodeName==="#text"?t.nodeValue:IEt.default(t),n=iCe.default(a);if(n.width<=e||n.width>=1&&e>0&&e<1)return n;let u=(o=(r=t.style)===null||r===void 0?void 0:r.textWrap)!==null&&o!==void 0?o:"wrap",A=wEt.default(a,e,u);return iCe.default(A)},sCe=t=>{var e;if(!(!t||!t.parentNode))return(e=t.yogaNode)!==null&&e!==void 0?e:sCe(t.parentNode)},Jk=t=>{let e=sCe(t);e?.markDirty()};pi.setTextNodeValue=(t,e)=>{typeof e!="string"&&(e=String(e)),t.nodeValue=e,Jk(t)}});var uCe=_(hB=>{"use strict";var cCe=hB&&hB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(hB,"__esModule",{value:!0});var oCe=P6(),vEt=cCe(bEe()),aCe=cCe(lm()),Oo=j6(),lCe=t=>{t?.unsetMeasureFunc(),t?.freeRecursive()};hB.default=vEt.default({schedulePassiveEffects:oCe.unstable_scheduleCallback,cancelPassiveEffects:oCe.unstable_cancelCallback,now:Date.now,getRootHostContext:()=>({isInsideText:!1}),prepareForCommit:()=>{},resetAfterCommit:t=>{if(t.isStaticDirty){t.isStaticDirty=!1,typeof t.onImmediateRender=="function"&&t.onImmediateRender();return}typeof t.onRender=="function"&&t.onRender()},getChildHostContext:(t,e)=>{let r=t.isInsideText,o=e==="ink-text"||e==="ink-virtual-text";return r===o?t:{isInsideText:o}},shouldSetTextContent:()=>!1,createInstance:(t,e,r,o)=>{if(o.isInsideText&&t==="ink-box")throw new Error("<Box> can\u2019t be nested inside <Text> component");let a=t==="ink-text"&&o.isInsideText?"ink-virtual-text":t,n=Oo.createNode(a);for(let[u,A]of Object.entries(e))u!=="children"&&(u==="style"?Oo.setStyle(n,A):u==="internal_transform"?n.internal_transform=A:u==="internal_static"?n.internal_static=!0:Oo.setAttribute(n,u,A));return n},createTextInstance:(t,e,r)=>{if(!r.isInsideText)throw new Error(`Text string "${t}" must be rendered inside <Text> component`);return Oo.createTextNode(t)},resetTextContent:()=>{},hideTextInstance:t=>{Oo.setTextNodeValue(t,"")},unhideTextInstance:(t,e)=>{Oo.setTextNodeValue(t,e)},getPublicInstance:t=>t,hideInstance:t=>{var e;(e=t.yogaNode)===null||e===void 0||e.setDisplay(aCe.default.DISPLAY_NONE)},unhideInstance:t=>{var e;(e=t.yogaNode)===null||e===void 0||e.setDisplay(aCe.default.DISPLAY_FLEX)},appendInitialChild:Oo.appendChildNode,appendChild:Oo.appendChildNode,insertBefore:Oo.insertBeforeNode,finalizeInitialChildren:(t,e,r,o)=>(t.internal_static&&(o.isStaticDirty=!0,o.staticNode=t),!1),supportsMutation:!0,appendChildToContainer:Oo.appendChildNode,insertInContainerBefore:Oo.insertBeforeNode,removeChildFromContainer:(t,e)=>{Oo.removeChildNode(t,e),lCe(e.yogaNode)},prepareUpdate:(t,e,r,o,a)=>{t.internal_static&&(a.isStaticDirty=!0);let n={},u=Object.keys(o);for(let A of u)if(o[A]!==r[A]){if(A==="style"&&typeof o.style=="object"&&typeof r.style=="object"){let h=o.style,E=r.style,I=Object.keys(h);for(let v of I){if(v==="borderStyle"||v==="borderColor"){if(typeof n.style!="object"){let x={};n.style=x}n.style.borderStyle=h.borderStyle,n.style.borderColor=h.borderColor}if(h[v]!==E[v]){if(typeof n.style!="object"){let x={};n.style=x}n.style[v]=h[v]}}continue}n[A]=o[A]}return n},commitUpdate:(t,e)=>{for(let[r,o]of Object.entries(e))r!=="children"&&(r==="style"?Oo.setStyle(t,o):r==="internal_transform"?t.internal_transform=o:r==="internal_static"?t.internal_static=!0:Oo.setAttribute(t,r,o))},commitTextUpdate:(t,e,r)=>{Oo.setTextNodeValue(t,r)},removeChild:(t,e)=>{Oo.removeChildNode(t,e),lCe(e.yogaNode)}})});var fCe=_((OKt,ACe)=>{"use strict";ACe.exports=(t,e=1,r)=>{if(r={indent:" ",includeEmptyLines:!1,...r},typeof t!="string")throw new TypeError(`Expected \`input\` to be a \`string\`, got \`${typeof t}\``);if(typeof e!="number")throw new TypeError(`Expected \`count\` to be a \`number\`, got \`${typeof e}\``);if(typeof r.indent!="string")throw new TypeError(`Expected \`options.indent\` to be a \`string\`, got \`${typeof r.indent}\``);if(e===0)return t;let o=r.includeEmptyLines?/^/gm:/^(?!\s*$)/gm;return t.replace(o,r.indent.repeat(e))}});var pCe=_(gB=>{"use strict";var DEt=gB&&gB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(gB,"__esModule",{value:!0});var Xk=DEt(lm());gB.default=t=>t.getComputedWidth()-t.getComputedPadding(Xk.default.EDGE_LEFT)-t.getComputedPadding(Xk.default.EDGE_RIGHT)-t.getComputedBorder(Xk.default.EDGE_LEFT)-t.getComputedBorder(Xk.default.EDGE_RIGHT)});var hCe=_((UKt,PEt)=>{PEt.exports={single:{topLeft:"\u250C",topRight:"\u2510",bottomRight:"\u2518",bottomLeft:"\u2514",vertical:"\u2502",horizontal:"\u2500"},double:{topLeft:"\u2554",topRight:"\u2557",bottomRight:"\u255D",bottomLeft:"\u255A",vertical:"\u2551",horizontal:"\u2550"},round:{topLeft:"\u256D",topRight:"\u256E",bottomRight:"\u256F",bottomLeft:"\u2570",vertical:"\u2502",horizontal:"\u2500"},bold:{topLeft:"\u250F",topRight:"\u2513",bottomRight:"\u251B",bottomLeft:"\u2517",vertical:"\u2503",horizontal:"\u2501"},singleDouble:{topLeft:"\u2553",topRight:"\u2556",bottomRight:"\u255C",bottomLeft:"\u2559",vertical:"\u2551",horizontal:"\u2500"},doubleSingle:{topLeft:"\u2552",topRight:"\u2555",bottomRight:"\u255B",bottomLeft:"\u2558",vertical:"\u2502",horizontal:"\u2550"},classic:{topLeft:"+",topRight:"+",bottomRight:"+",bottomLeft:"+",vertical:"|",horizontal:"-"}}});var dCe=_((_Kt,Y6)=>{"use strict";var gCe=hCe();Y6.exports=gCe;Y6.exports.default=gCe});var yCe=_((HKt,mCe)=>{"use strict";var SEt=(t,e,r)=>{let o=t.indexOf(e);if(o===-1)return t;let a=e.length,n=0,u="";do u+=t.substr(n,o-n)+e+r,n=o+a,o=t.indexOf(e,n);while(o!==-1);return u+=t.substr(n),u},bEt=(t,e,r,o)=>{let a=0,n="";do{let u=t[o-1]==="\r";n+=t.substr(a,(u?o-1:o)-a)+e+(u?`\r
-`:`
-`)+r,a=o+1,o=t.indexOf(`
-`,a)}while(o!==-1);return n+=t.substr(a),n};mCe.exports={stringReplaceAll:SEt,stringEncaseCRLFWithFirstIndex:bEt}});var BCe=_((qKt,ICe)=>{"use strict";var xEt=/(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi,ECe=/(?:^|\.)(\w+)(?:\(([^)]*)\))?/g,kEt=/^(['"])((?:\\.|(?!\1)[^\\])*)\1$/,QEt=/\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi,FEt=new Map([["n",`
-`],["r","\r"],["t"," "],["b","\b"],["f","\f"],["v","\v"],["0","\0"],["\\","\\"],["e","\x1B"],["a","\x07"]]);function wCe(t){let e=t[0]==="u",r=t[1]==="{";return e&&!r&&t.length===5||t[0]==="x"&&t.length===3?String.fromCharCode(parseInt(t.slice(1),16)):e&&r?String.fromCodePoint(parseInt(t.slice(2,-1),16)):FEt.get(t)||t}function REt(t,e){let r=[],o=e.trim().split(/\s*,\s*/g),a;for(let n of o){let u=Number(n);if(!Number.isNaN(u))r.push(u);else if(a=n.match(kEt))r.push(a[2].replace(QEt,(A,p,h)=>p?wCe(p):h));else throw new Error(`Invalid Chalk template style argument: ${n} (in style '${t}')`)}return r}function TEt(t){ECe.lastIndex=0;let e=[],r;for(;(r=ECe.exec(t))!==null;){let o=r[1];if(r[2]){let a=REt(o,r[2]);e.push([o].concat(a))}else e.push([o])}return e}function CCe(t,e){let r={};for(let a of e)for(let n of a.styles)r[n[0]]=a.inverse?null:n.slice(1);let o=t;for(let[a,n]of Object.entries(r))if(!!Array.isArray(n)){if(!(a in o))throw new Error(`Unknown Chalk style: ${a}`);o=n.length>0?o[a](...n):o[a]}return o}ICe.exports=(t,e)=>{let r=[],o=[],a=[];if(e.replace(xEt,(n,u,A,p,h,E)=>{if(u)a.push(wCe(u));else if(p){let I=a.join("");a=[],o.push(r.length===0?I:CCe(t,r)(I)),r.push({inverse:A,styles:TEt(p)})}else if(h){if(r.length===0)throw new Error("Found extraneous } in Chalk template literal");o.push(CCe(t,r)(a.join(""))),a=[],r.pop()}else a.push(E)}),o.push(a.join("")),r.length>0){let n=`Chalk template literal is missing ${r.length} closing bracket${r.length===1?"":"s"} (\`}\`)`;throw new Error(n)}return o.join("")}});var rQ=_((GKt,xCe)=>{"use strict";var dB=DI(),{stdout:K6,stderr:z6}=dL(),{stringReplaceAll:LEt,stringEncaseCRLFWithFirstIndex:NEt}=yCe(),{isArray:Zk}=Array,DCe=["ansi","ansi","ansi256","ansi16m"],HC=Object.create(null),OEt=(t,e={})=>{if(e.level&&!(Number.isInteger(e.level)&&e.level>=0&&e.level<=3))throw new Error("The `level` option should be an integer from 0 to 3");let r=K6?K6.level:0;t.level=e.level===void 0?r:e.level},V6=class{constructor(e){return PCe(e)}},PCe=t=>{let e={};return OEt(e,t),e.template=(...r)=>bCe(e.template,...r),Object.setPrototypeOf(e,$k.prototype),Object.setPrototypeOf(e.template,e),e.template.constructor=()=>{throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.")},e.template.Instance=V6,e.template};function $k(t){return PCe(t)}for(let[t,e]of Object.entries(dB))HC[t]={get(){let r=eQ(this,J6(e.open,e.close,this._styler),this._isEmpty);return Object.defineProperty(this,t,{value:r}),r}};HC.visible={get(){let t=eQ(this,this._styler,!0);return Object.defineProperty(this,"visible",{value:t}),t}};var SCe=["rgb","hex","keyword","hsl","hsv","hwb","ansi","ansi256"];for(let t of SCe)HC[t]={get(){let{level:e}=this;return function(...r){let o=J6(dB.color[DCe[e]][t](...r),dB.color.close,this._styler);return eQ(this,o,this._isEmpty)}}};for(let t of SCe){let e="bg"+t[0].toUpperCase()+t.slice(1);HC[e]={get(){let{level:r}=this;return function(...o){let a=J6(dB.bgColor[DCe[r]][t](...o),dB.bgColor.close,this._styler);return eQ(this,a,this._isEmpty)}}}}var MEt=Object.defineProperties(()=>{},{...HC,level:{enumerable:!0,get(){return this._generator.level},set(t){this._generator.level=t}}}),J6=(t,e,r)=>{let o,a;return r===void 0?(o=t,a=e):(o=r.openAll+t,a=e+r.closeAll),{open:t,close:e,openAll:o,closeAll:a,parent:r}},eQ=(t,e,r)=>{let o=(...a)=>Zk(a[0])&&Zk(a[0].raw)?vCe(o,bCe(o,...a)):vCe(o,a.length===1?""+a[0]:a.join(" "));return Object.setPrototypeOf(o,MEt),o._generator=t,o._styler=e,o._isEmpty=r,o},vCe=(t,e)=>{if(t.level<=0||!e)return t._isEmpty?"":e;let r=t._styler;if(r===void 0)return e;let{openAll:o,closeAll:a}=r;if(e.indexOf("\x1B")!==-1)for(;r!==void 0;)e=LEt(e,r.close,r.open),r=r.parent;let n=e.indexOf(`
-`);return n!==-1&&(e=NEt(e,a,o,n)),o+e+a},W6,bCe=(t,...e)=>{let[r]=e;if(!Zk(r)||!Zk(r.raw))return e.join(" ");let o=e.slice(1),a=[r.raw[0]];for(let n=1;n<r.length;n++)a.push(String(o[n-1]).replace(/[{}\\]/g,"\\$&"),String(r.raw[n]));return W6===void 0&&(W6=BCe()),W6(t,a.join(""))};Object.defineProperties($k.prototype,HC);var tQ=$k();tQ.supportsColor=K6;tQ.stderr=$k({level:z6?z6.level:0});tQ.stderr.supportsColor=z6;xCe.exports=tQ});var X6=_(yB=>{"use strict";var UEt=yB&&yB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(yB,"__esModule",{value:!0});var mB=UEt(rQ()),_Et=/^(rgb|hsl|hsv|hwb)\(\s?(\d+),\s?(\d+),\s?(\d+)\s?\)$/,HEt=/^(ansi|ansi256)\(\s?(\d+)\s?\)$/,nQ=(t,e)=>e==="foreground"?t:"bg"+t[0].toUpperCase()+t.slice(1);yB.default=(t,e,r)=>{if(!e)return t;if(e in mB.default){let a=nQ(e,r);return mB.default[a](t)}if(e.startsWith("#")){let a=nQ("hex",r);return mB.default[a](e)(t)}if(e.startsWith("ansi")){let a=HEt.exec(e);if(!a)return t;let n=nQ(a[1],r),u=Number(a[2]);return mB.default[n](u)(t)}if(e.startsWith("rgb")||e.startsWith("hsl")||e.startsWith("hsv")||e.startsWith("hwb")){let a=_Et.exec(e);if(!a)return t;let n=nQ(a[1],r),u=Number(a[2]),A=Number(a[3]),p=Number(a[4]);return mB.default[n](u,A,p)(t)}return t}});var QCe=_(EB=>{"use strict";var kCe=EB&&EB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(EB,"__esModule",{value:!0});var qEt=kCe(dCe()),Z6=kCe(X6());EB.default=(t,e,r,o)=>{if(typeof r.style.borderStyle=="string"){let a=r.yogaNode.getComputedWidth(),n=r.yogaNode.getComputedHeight(),u=r.style.borderColor,A=qEt.default[r.style.borderStyle],p=Z6.default(A.topLeft+A.horizontal.repeat(a-2)+A.topRight,u,"foreground"),h=(Z6.default(A.vertical,u,"foreground")+`
-`).repeat(n-2),E=Z6.default(A.bottomLeft+A.horizontal.repeat(a-2)+A.bottomRight,u,"foreground");o.write(t,e,p,{transformers:[]}),o.write(t,e+1,h,{transformers:[]}),o.write(t+a-1,e+1,h,{transformers:[]}),o.write(t,e+n-1,E,{transformers:[]})}}});var RCe=_(CB=>{"use strict";var cm=CB&&CB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(CB,"__esModule",{value:!0});var GEt=cm(lm()),jEt=cm(L6()),YEt=cm(fCe()),WEt=cm(H6()),KEt=cm(pCe()),zEt=cm(G6()),VEt=cm(QCe()),JEt=(t,e)=>{var r;let o=(r=t.childNodes[0])===null||r===void 0?void 0:r.yogaNode;if(o){let a=o.getComputedLeft(),n=o.getComputedTop();e=`
-`.repeat(n)+YEt.default(e,a)}return e},FCe=(t,e,r)=>{var o;let{offsetX:a=0,offsetY:n=0,transformers:u=[],skipStaticElements:A}=r;if(A&&t.internal_static)return;let{yogaNode:p}=t;if(p){if(p.getDisplay()===GEt.default.DISPLAY_NONE)return;let h=a+p.getComputedLeft(),E=n+p.getComputedTop(),I=u;if(typeof t.internal_transform=="function"&&(I=[t.internal_transform,...u]),t.nodeName==="ink-text"){let v=zEt.default(t);if(v.length>0){let x=jEt.default(v),C=KEt.default(p);if(x>C){let R=(o=t.style.textWrap)!==null&&o!==void 0?o:"wrap";v=WEt.default(v,C,R)}v=JEt(t,v),e.write(h,E,v,{transformers:I})}return}if(t.nodeName==="ink-box"&&VEt.default(h,E,t,e),t.nodeName==="ink-root"||t.nodeName==="ink-box")for(let v of t.childNodes)FCe(v,e,{offsetX:h,offsetY:E,transformers:I,skipStaticElements:A})}};CB.default=FCe});var LCe=_((KKt,TCe)=>{"use strict";TCe.exports=t=>{t=Object.assign({onlyFirst:!1},t);let e=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(e,t.onlyFirst?void 0:"g")}});var OCe=_((zKt,$6)=>{"use strict";var XEt=LCe(),NCe=t=>typeof t=="string"?t.replace(XEt(),""):t;$6.exports=NCe;$6.exports.default=NCe});var _Ce=_((VKt,UCe)=>{"use strict";var MCe="[\uD800-\uDBFF][\uDC00-\uDFFF]";UCe.exports=t=>t&&t.exact?new RegExp(`^${MCe}$`):new RegExp(MCe,"g")});var qCe=_((JKt,eq)=>{"use strict";var ZEt=OCe(),$Et=_Ce(),HCe=t=>ZEt(t).replace($Et()," ").length;eq.exports=HCe;eq.exports.default=HCe});var YCe=_(wB=>{"use strict";var jCe=wB&&wB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(wB,"__esModule",{value:!0});var GCe=jCe(U6()),eCt=jCe(qCe()),tq=class{constructor(e){this.writes=[];let{width:r,height:o}=e;this.width=r,this.height=o}write(e,r,o,a){let{transformers:n}=a;!o||this.writes.push({x:e,y:r,text:o,transformers:n})}get(){let e=[];for(let o=0;o<this.height;o++)e.push(" ".repeat(this.width));for(let o of this.writes){let{x:a,y:n,text:u,transformers:A}=o,p=u.split(`
-`),h=0;for(let E of p){let I=e[n+h];if(!I)continue;let v=eCt.default(E);for(let x of A)E=x(E);e[n+h]=GCe.default(I,0,a)+E+GCe.default(I,a+v),h++}}return{output:e.map(o=>o.trimRight()).join(`
-`),height:e.length}}};wB.default=tq});var zCe=_(IB=>{"use strict";var rq=IB&&IB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(IB,"__esModule",{value:!0});var tCt=rq(lm()),WCe=rq(RCe()),KCe=rq(YCe());IB.default=(t,e)=>{var r;if(t.yogaNode.setWidth(e),t.yogaNode){t.yogaNode.calculateLayout(void 0,void 0,tCt.default.DIRECTION_LTR);let o=new KCe.default({width:t.yogaNode.getComputedWidth(),height:t.yogaNode.getComputedHeight()});WCe.default(t,o,{skipStaticElements:!0});let a;!((r=t.staticNode)===null||r===void 0)&&r.yogaNode&&(a=new KCe.default({width:t.staticNode.yogaNode.getComputedWidth(),height:t.staticNode.yogaNode.getComputedHeight()}),WCe.default(t.staticNode,a,{skipStaticElements:!1}));let{output:n,height:u}=o.get();return{output:n,outputHeight:u,staticOutput:a?`${a.get().output}
-`:""}}return{output:"",outputHeight:0,staticOutput:""}}});var ZCe=_(($Kt,XCe)=>{"use strict";var VCe=ve("stream"),JCe=["assert","count","countReset","debug","dir","dirxml","error","group","groupCollapsed","groupEnd","info","log","table","time","timeEnd","timeLog","trace","warn"],nq={},rCt=t=>{let e=new VCe.PassThrough,r=new VCe.PassThrough;e.write=a=>t("stdout",a),r.write=a=>t("stderr",a);let o=new console.Console(e,r);for(let a of JCe)nq[a]=console[a],console[a]=o[a];return()=>{for(let a of JCe)console[a]=nq[a];nq={}}};XCe.exports=rCt});var sq=_(iq=>{"use strict";Object.defineProperty(iq,"__esModule",{value:!0});iq.default=new WeakMap});var aq=_(oq=>{"use strict";Object.defineProperty(oq,"__esModule",{value:!0});var nCt=on(),$Ce=nCt.createContext({exit:()=>{}});$Ce.displayName="InternalAppContext";oq.default=$Ce});var cq=_(lq=>{"use strict";Object.defineProperty(lq,"__esModule",{value:!0});var iCt=on(),ewe=iCt.createContext({stdin:void 0,setRawMode:()=>{},isRawModeSupported:!1,internal_exitOnCtrlC:!0});ewe.displayName="InternalStdinContext";lq.default=ewe});var Aq=_(uq=>{"use strict";Object.defineProperty(uq,"__esModule",{value:!0});var sCt=on(),twe=sCt.createContext({stdout:void 0,write:()=>{}});twe.displayName="InternalStdoutContext";uq.default=twe});var pq=_(fq=>{"use strict";Object.defineProperty(fq,"__esModule",{value:!0});var oCt=on(),rwe=oCt.createContext({stderr:void 0,write:()=>{}});rwe.displayName="InternalStderrContext";fq.default=rwe});var iQ=_(hq=>{"use strict";Object.defineProperty(hq,"__esModule",{value:!0});var aCt=on(),nwe=aCt.createContext({activeId:void 0,add:()=>{},remove:()=>{},activate:()=>{},deactivate:()=>{},enableFocus:()=>{},disableFocus:()=>{},focusNext:()=>{},focusPrevious:()=>{}});nwe.displayName="InternalFocusContext";hq.default=nwe});var swe=_((ozt,iwe)=>{"use strict";var lCt=/[|\\{}()[\]^$+*?.-]/g;iwe.exports=t=>{if(typeof t!="string")throw new TypeError("Expected a string");return t.replace(lCt,"\\$&")}});var cwe=_((azt,lwe)=>{"use strict";var cCt=swe(),uCt=typeof process=="object"&&process&&typeof process.cwd=="function"?process.cwd():".",awe=[].concat(ve("module").builtinModules,"bootstrap_node","node").map(t=>new RegExp(`(?:\\((?:node:)?${t}(?:\\.js)?:\\d+:\\d+\\)$|^\\s*at (?:node:)?${t}(?:\\.js)?:\\d+:\\d+$)`));awe.push(/\((?:node:)?internal\/[^:]+:\d+:\d+\)$/,/\s*at (?:node:)?internal\/[^:]+:\d+:\d+$/,/\/\.node-spawn-wrap-\w+-\w+\/node:\d+:\d+\)?$/);var BB=class{constructor(e){e={ignoredPackages:[],...e},"internals"in e||(e.internals=BB.nodeInternals()),"cwd"in e||(e.cwd=uCt),this._cwd=e.cwd.replace(/\\/g,"/"),this._internals=[].concat(e.internals,ACt(e.ignoredPackages)),this._wrapCallSite=e.wrapCallSite||!1}static nodeInternals(){return[...awe]}clean(e,r=0){r=" ".repeat(r),Array.isArray(e)||(e=e.split(`
-`)),!/^\s*at /.test(e[0])&&/^\s*at /.test(e[1])&&(e=e.slice(1));let o=!1,a=null,n=[];return e.forEach(u=>{if(u=u.replace(/\\/g,"/"),this._internals.some(p=>p.test(u)))return;let A=/^\s*at /.test(u);o?u=u.trimEnd().replace(/^(\s+)at /,"$1"):(u=u.trim(),A&&(u=u.slice(3))),u=u.replace(`${this._cwd}/`,""),u&&(A?(a&&(n.push(a),a=null),n.push(u)):(o=!0,a=u))}),n.map(u=>`${r}${u}
-`).join("")}captureString(e,r=this.captureString){typeof e=="function"&&(r=e,e=1/0);let{stackTraceLimit:o}=Error;e&&(Error.stackTraceLimit=e);let a={};Error.captureStackTrace(a,r);let{stack:n}=a;return Error.stackTraceLimit=o,this.clean(n)}capture(e,r=this.capture){typeof e=="function"&&(r=e,e=1/0);let{prepareStackTrace:o,stackTraceLimit:a}=Error;Error.prepareStackTrace=(A,p)=>this._wrapCallSite?p.map(this._wrapCallSite):p,e&&(Error.stackTraceLimit=e);let n={};Error.captureStackTrace(n,r);let{stack:u}=n;return Object.assign(Error,{prepareStackTrace:o,stackTraceLimit:a}),u}at(e=this.at){let[r]=this.capture(1,e);if(!r)return{};let o={line:r.getLineNumber(),column:r.getColumnNumber()};owe(o,r.getFileName(),this._cwd),r.isConstructor()&&(o.constructor=!0),r.isEval()&&(o.evalOrigin=r.getEvalOrigin()),r.isNative()&&(o.native=!0);let a;try{a=r.getTypeName()}catch{}a&&a!=="Object"&&a!=="[object Object]"&&(o.type=a);let n=r.getFunctionName();n&&(o.function=n);let u=r.getMethodName();return u&&n!==u&&(o.method=u),o}parseLine(e){let r=e&&e.match(fCt);if(!r)return null;let o=r[1]==="new",a=r[2],n=r[3],u=r[4],A=Number(r[5]),p=Number(r[6]),h=r[7],E=r[8],I=r[9],v=r[10]==="native",x=r[11]===")",C,R={};if(E&&(R.line=Number(E)),I&&(R.column=Number(I)),x&&h){let N=0;for(let U=h.length-1;U>0;U--)if(h.charAt(U)===")")N++;else if(h.charAt(U)==="("&&h.charAt(U-1)===" "&&(N--,N===-1&&h.charAt(U-1)===" ")){let V=h.slice(0,U-1);h=h.slice(U+1),a+=` (${V}`;break}}if(a){let N=a.match(pCt);N&&(a=N[1],C=N[2])}return owe(R,h,this._cwd),o&&(R.constructor=!0),n&&(R.evalOrigin=n,R.evalLine=A,R.evalColumn=p,R.evalFile=u&&u.replace(/\\/g,"/")),v&&(R.native=!0),a&&(R.function=a),C&&a!==C&&(R.method=C),R}};function owe(t,e,r){e&&(e=e.replace(/\\/g,"/"),e.startsWith(`${r}/`)&&(e=e.slice(r.length+1)),t.file=e)}function ACt(t){if(t.length===0)return[];let e=t.map(r=>cCt(r));return new RegExp(`[/\\\\]node_modules[/\\\\](?:${e.join("|")})[/\\\\][^:]+:\\d+:\\d+`)}var fCt=new RegExp("^(?:\\s*at )?(?:(new) )?(?:(.*?) \\()?(?:eval at ([^ ]+) \\((.+?):(\\d+):(\\d+)\\), )?(?:(.+?):(\\d+):(\\d+)|(native))(\\)?)$"),pCt=/^(.*?) \[as (.*?)\]$/;lwe.exports=BB});var Awe=_((lzt,uwe)=>{"use strict";uwe.exports=(t,e)=>t.replace(/^\t+/gm,r=>" ".repeat(r.length*(e||2)))});var pwe=_((czt,fwe)=>{"use strict";var hCt=Awe(),gCt=(t,e)=>{let r=[],o=t-e,a=t+e;for(let n=o;n<=a;n++)r.push(n);return r};fwe.exports=(t,e,r)=>{if(typeof t!="string")throw new TypeError("Source code is missing.");if(!e||e<1)throw new TypeError("Line number must start from `1`.");if(t=hCt(t).split(/\r?\n/),!(e>t.length))return r={around:3,...r},gCt(e,r.around).filter(o=>t[o-1]!==void 0).map(o=>({line:o,value:t[o-1]}))}});var sQ=_(nu=>{"use strict";var dCt=nu&&nu.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),mCt=nu&&nu.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),yCt=nu&&nu.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&dCt(e,t,r);return mCt(e,t),e},ECt=nu&&nu.__rest||function(t,e){var r={};for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&e.indexOf(o)<0&&(r[o]=t[o]);if(t!=null&&typeof Object.getOwnPropertySymbols=="function")for(var a=0,o=Object.getOwnPropertySymbols(t);a<o.length;a++)e.indexOf(o[a])<0&&Object.prototype.propertyIsEnumerable.call(t,o[a])&&(r[o[a]]=t[o[a]]);return r};Object.defineProperty(nu,"__esModule",{value:!0});var hwe=yCt(on()),gq=hwe.forwardRef((t,e)=>{var{children:r}=t,o=ECt(t,["children"]);let a=Object.assign(Object.assign({},o),{marginLeft:o.marginLeft||o.marginX||o.margin||0,marginRight:o.marginRight||o.marginX||o.margin||0,marginTop:o.marginTop||o.marginY||o.margin||0,marginBottom:o.marginBottom||o.marginY||o.margin||0,paddingLeft:o.paddingLeft||o.paddingX||o.padding||0,paddingRight:o.paddingRight||o.paddingX||o.padding||0,paddingTop:o.paddingTop||o.paddingY||o.padding||0,paddingBottom:o.paddingBottom||o.paddingY||o.padding||0});return hwe.default.createElement("ink-box",{ref:e,style:a},r)});gq.displayName="Box";gq.defaultProps={flexDirection:"row",flexGrow:0,flexShrink:1};nu.default=gq});var yq=_(vB=>{"use strict";var dq=vB&&vB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(vB,"__esModule",{value:!0});var CCt=dq(on()),qC=dq(rQ()),gwe=dq(X6()),mq=({color:t,backgroundColor:e,dimColor:r,bold:o,italic:a,underline:n,strikethrough:u,inverse:A,wrap:p,children:h})=>{if(h==null)return null;let E=I=>(r&&(I=qC.default.dim(I)),t&&(I=gwe.default(I,t,"foreground")),e&&(I=gwe.default(I,e,"background")),o&&(I=qC.default.bold(I)),a&&(I=qC.default.italic(I)),n&&(I=qC.default.underline(I)),u&&(I=qC.default.strikethrough(I)),A&&(I=qC.default.inverse(I)),I);return CCt.default.createElement("ink-text",{style:{flexGrow:0,flexShrink:1,flexDirection:"row",textWrap:p},internal_transform:E},h)};mq.displayName="Text";mq.defaultProps={dimColor:!1,bold:!1,italic:!1,underline:!1,strikethrough:!1,wrap:"wrap"};vB.default=mq});var Ewe=_(iu=>{"use strict";var wCt=iu&&iu.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),ICt=iu&&iu.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),BCt=iu&&iu.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&wCt(e,t,r);return ICt(e,t),e},DB=iu&&iu.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(iu,"__esModule",{value:!0});var dwe=BCt(ve("fs")),fs=DB(on()),mwe=DB(cwe()),vCt=DB(pwe()),Zf=DB(sQ()),gA=DB(yq()),ywe=new mwe.default({cwd:process.cwd(),internals:mwe.default.nodeInternals()}),DCt=({error:t})=>{let e=t.stack?t.stack.split(`
-`).slice(1):void 0,r=e?ywe.parseLine(e[0]):void 0,o,a=0;if(r?.file&&r?.line&&dwe.existsSync(r.file)){let n=dwe.readFileSync(r.file,"utf8");if(o=vCt.default(n,r.line),o)for(let{line:u}of o)a=Math.max(a,String(u).length)}return fs.default.createElement(Zf.default,{flexDirection:"column",padding:1},fs.default.createElement(Zf.default,null,fs.default.createElement(gA.default,{backgroundColor:"red",color:"white"}," ","ERROR"," "),fs.default.createElement(gA.default,null," ",t.message)),r&&fs.default.createElement(Zf.default,{marginTop:1},fs.default.createElement(gA.default,{dimColor:!0},r.file,":",r.line,":",r.column)),r&&o&&fs.default.createElement(Zf.default,{marginTop:1,flexDirection:"column"},o.map(({line:n,value:u})=>fs.default.createElement(Zf.default,{key:n},fs.default.createElement(Zf.default,{width:a+1},fs.default.createElement(gA.default,{dimColor:n!==r.line,backgroundColor:n===r.line?"red":void 0,color:n===r.line?"white":void 0},String(n).padStart(a," "),":")),fs.default.createElement(gA.default,{key:n,backgroundColor:n===r.line?"red":void 0,color:n===r.line?"white":void 0}," "+u)))),t.stack&&fs.default.createElement(Zf.default,{marginTop:1,flexDirection:"column"},t.stack.split(`
-`).slice(1).map(n=>{let u=ywe.parseLine(n);return u?fs.default.createElement(Zf.default,{key:n},fs.default.createElement(gA.default,{dimColor:!0},"- "),fs.default.createElement(gA.default,{dimColor:!0,bold:!0},u.function),fs.default.createElement(gA.default,{dimColor:!0,color:"gray"}," ","(",u.file,":",u.line,":",u.column,")")):fs.default.createElement(Zf.default,{key:n},fs.default.createElement(gA.default,{dimColor:!0},"- "),fs.default.createElement(gA.default,{dimColor:!0,bold:!0},n))})))};iu.default=DCt});var wwe=_(su=>{"use strict";var PCt=su&&su.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),SCt=su&&su.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),bCt=su&&su.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&PCt(e,t,r);return SCt(e,t),e},Am=su&&su.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(su,"__esModule",{value:!0});var um=bCt(on()),Cwe=Am(g6()),xCt=Am(aq()),kCt=Am(cq()),QCt=Am(Aq()),FCt=Am(pq()),RCt=Am(iQ()),TCt=Am(Ewe()),LCt=" ",NCt="\x1B[Z",OCt="\x1B",oQ=class extends um.PureComponent{constructor(){super(...arguments),this.state={isFocusEnabled:!0,activeFocusId:void 0,focusables:[],error:void 0},this.rawModeEnabledCount=0,this.handleSetRawMode=e=>{let{stdin:r}=this.props;if(!this.isRawModeSupported())throw r===process.stdin?new Error(`Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default.
-Read about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`):new Error(`Raw mode is not supported on the stdin provided to Ink.
-Read about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`);if(r.setEncoding("utf8"),e){this.rawModeEnabledCount===0&&(r.addListener("data",this.handleInput),r.resume(),r.setRawMode(!0)),this.rawModeEnabledCount++;return}--this.rawModeEnabledCount===0&&(r.setRawMode(!1),r.removeListener("data",this.handleInput),r.pause())},this.handleInput=e=>{e===""&&this.props.exitOnCtrlC&&this.handleExit(),e===OCt&&this.state.activeFocusId&&this.setState({activeFocusId:void 0}),this.state.isFocusEnabled&&this.state.focusables.length>0&&(e===LCt&&this.focusNext(),e===NCt&&this.focusPrevious())},this.handleExit=e=>{this.isRawModeSupported()&&this.handleSetRawMode(!1),this.props.onExit(e)},this.enableFocus=()=>{this.setState({isFocusEnabled:!0})},this.disableFocus=()=>{this.setState({isFocusEnabled:!1})},this.focusNext=()=>{this.setState(e=>{let r=e.focusables[0].id;return{activeFocusId:this.findNextFocusable(e)||r}})},this.focusPrevious=()=>{this.setState(e=>{let r=e.focusables[e.focusables.length-1].id;return{activeFocusId:this.findPreviousFocusable(e)||r}})},this.addFocusable=(e,{autoFocus:r})=>{this.setState(o=>{let a=o.activeFocusId;return!a&&r&&(a=e),{activeFocusId:a,focusables:[...o.focusables,{id:e,isActive:!0}]}})},this.removeFocusable=e=>{this.setState(r=>({activeFocusId:r.activeFocusId===e?void 0:r.activeFocusId,focusables:r.focusables.filter(o=>o.id!==e)}))},this.activateFocusable=e=>{this.setState(r=>({focusables:r.focusables.map(o=>o.id!==e?o:{id:e,isActive:!0})}))},this.deactivateFocusable=e=>{this.setState(r=>({activeFocusId:r.activeFocusId===e?void 0:r.activeFocusId,focusables:r.focusables.map(o=>o.id!==e?o:{id:e,isActive:!1})}))},this.findNextFocusable=e=>{let r=e.focusables.findIndex(o=>o.id===e.activeFocusId);for(let o=r+1;o<e.focusables.length;o++)if(e.focusables[o].isActive)return e.focusables[o].id},this.findPreviousFocusable=e=>{let r=e.focusables.findIndex(o=>o.id===e.activeFocusId);for(let o=r-1;o>=0;o--)if(e.focusables[o].isActive)return e.focusables[o].id}}static getDerivedStateFromError(e){return{error:e}}isRawModeSupported(){return this.props.stdin.isTTY}render(){return um.default.createElement(xCt.default.Provider,{value:{exit:this.handleExit}},um.default.createElement(kCt.default.Provider,{value:{stdin:this.props.stdin,setRawMode:this.handleSetRawMode,isRawModeSupported:this.isRawModeSupported(),internal_exitOnCtrlC:this.props.exitOnCtrlC}},um.default.createElement(QCt.default.Provider,{value:{stdout:this.props.stdout,write:this.props.writeToStdout}},um.default.createElement(FCt.default.Provider,{value:{stderr:this.props.stderr,write:this.props.writeToStderr}},um.default.createElement(RCt.default.Provider,{value:{activeId:this.state.activeFocusId,add:this.addFocusable,remove:this.removeFocusable,activate:this.activateFocusable,deactivate:this.deactivateFocusable,enableFocus:this.enableFocus,disableFocus:this.disableFocus,focusNext:this.focusNext,focusPrevious:this.focusPrevious}},this.state.error?um.default.createElement(TCt.default,{error:this.state.error}):this.props.children)))))}componentDidMount(){Cwe.default.hide(this.props.stdout)}componentWillUnmount(){Cwe.default.show(this.props.stdout),this.isRawModeSupported()&&this.handleSetRawMode(!1)}componentDidCatch(e){this.handleExit(e)}};su.default=oQ;oQ.displayName="InternalApp"});var vwe=_(ou=>{"use strict";var MCt=ou&&ou.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),UCt=ou&&ou.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),_Ct=ou&&ou.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&MCt(e,t,r);return UCt(e,t),e},au=ou&&ou.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(ou,"__esModule",{value:!0});var HCt=au(on()),Iwe=lM(),qCt=au(cEe()),GCt=au(u6()),jCt=au(gEe()),YCt=au(mEe()),Eq=au(uCe()),WCt=au(zCe()),KCt=au(h6()),zCt=au(ZCe()),VCt=_Ct(j6()),JCt=au(sq()),XCt=au(wwe()),GC=process.env.CI==="false"?!1:jCt.default,Bwe=()=>{},Cq=class{constructor(e){this.resolveExitPromise=()=>{},this.rejectExitPromise=()=>{},this.unsubscribeExit=()=>{},this.onRender=()=>{if(this.isUnmounted)return;let{output:r,outputHeight:o,staticOutput:a}=WCt.default(this.rootNode,this.options.stdout.columns||80),n=a&&a!==`
-`;if(this.options.debug){n&&(this.fullStaticOutput+=a),this.options.stdout.write(this.fullStaticOutput+r);return}if(GC){n&&this.options.stdout.write(a),this.lastOutput=r;return}if(n&&(this.fullStaticOutput+=a),o>=this.options.stdout.rows){this.options.stdout.write(GCt.default.clearTerminal+this.fullStaticOutput+r),this.lastOutput=r;return}n&&(this.log.clear(),this.options.stdout.write(a),this.log(r)),!n&&r!==this.lastOutput&&this.throttledLog(r),this.lastOutput=r},YCt.default(this),this.options=e,this.rootNode=VCt.createNode("ink-root"),this.rootNode.onRender=e.debug?this.onRender:Iwe(this.onRender,32,{leading:!0,trailing:!0}),this.rootNode.onImmediateRender=this.onRender,this.log=qCt.default.create(e.stdout),this.throttledLog=e.debug?this.log:Iwe(this.log,void 0,{leading:!0,trailing:!0}),this.isUnmounted=!1,this.lastOutput="",this.fullStaticOutput="",this.container=Eq.default.createContainer(this.rootNode,!1,!1),this.unsubscribeExit=KCt.default(this.unmount,{alwaysLast:!1}),e.patchConsole&&this.patchConsole(),GC||(e.stdout.on("resize",this.onRender),this.unsubscribeResize=()=>{e.stdout.off("resize",this.onRender)})}render(e){let r=HCt.default.createElement(XCt.default,{stdin:this.options.stdin,stdout:this.options.stdout,stderr:this.options.stderr,writeToStdout:this.writeToStdout,writeToStderr:this.writeToStderr,exitOnCtrlC:this.options.exitOnCtrlC,onExit:this.unmount},e);Eq.default.updateContainer(r,this.container,null,Bwe)}writeToStdout(e){if(!this.isUnmounted){if(this.options.debug){this.options.stdout.write(e+this.fullStaticOutput+this.lastOutput);return}if(GC){this.options.stdout.write(e);return}this.log.clear(),this.options.stdout.write(e),this.log(this.lastOutput)}}writeToStderr(e){if(!this.isUnmounted){if(this.options.debug){this.options.stderr.write(e),this.options.stdout.write(this.fullStaticOutput+this.lastOutput);return}if(GC){this.options.stderr.write(e);return}this.log.clear(),this.options.stderr.write(e),this.log(this.lastOutput)}}unmount(e){this.isUnmounted||(this.onRender(),this.unsubscribeExit(),typeof this.restoreConsole=="function"&&this.restoreConsole(),typeof this.unsubscribeResize=="function"&&this.unsubscribeResize(),GC?this.options.stdout.write(this.lastOutput+`
-`):this.options.debug||this.log.done(),this.isUnmounted=!0,Eq.default.updateContainer(null,this.container,null,Bwe),JCt.default.delete(this.options.stdout),e instanceof Error?this.rejectExitPromise(e):this.resolveExitPromise())}waitUntilExit(){return this.exitPromise||(this.exitPromise=new Promise((e,r)=>{this.resolveExitPromise=e,this.rejectExitPromise=r})),this.exitPromise}clear(){!GC&&!this.options.debug&&this.log.clear()}patchConsole(){this.options.debug||(this.restoreConsole=zCt.default((e,r)=>{e==="stdout"&&this.writeToStdout(r),e==="stderr"&&(r.startsWith("The above error occurred")||this.writeToStderr(r))}))}};ou.default=Cq});var Pwe=_(PB=>{"use strict";var Dwe=PB&&PB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(PB,"__esModule",{value:!0});var ZCt=Dwe(vwe()),aQ=Dwe(sq()),$Ct=ve("stream"),ewt=(t,e)=>{let r=Object.assign({stdout:process.stdout,stdin:process.stdin,stderr:process.stderr,debug:!1,exitOnCtrlC:!0,patchConsole:!0},twt(e)),o=rwt(r.stdout,()=>new ZCt.default(r));return o.render(t),{rerender:o.render,unmount:()=>o.unmount(),waitUntilExit:o.waitUntilExit,cleanup:()=>aQ.default.delete(r.stdout),clear:o.clear}};PB.default=ewt;var twt=(t={})=>t instanceof $Ct.Stream?{stdout:t,stdin:process.stdin}:t,rwt=(t,e)=>{let r;return aQ.default.has(t)?r=aQ.default.get(t):(r=e(),aQ.default.set(t,r)),r}});var bwe=_($f=>{"use strict";var nwt=$f&&$f.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),iwt=$f&&$f.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),swt=$f&&$f.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!=="default"&&Object.hasOwnProperty.call(t,r)&&nwt(e,t,r);return iwt(e,t),e};Object.defineProperty($f,"__esModule",{value:!0});var SB=swt(on()),Swe=t=>{let{items:e,children:r,style:o}=t,[a,n]=SB.useState(0),u=SB.useMemo(()=>e.slice(a),[e,a]);SB.useLayoutEffect(()=>{n(e.length)},[e.length]);let A=u.map((h,E)=>r(h,a+E)),p=SB.useMemo(()=>Object.assign({position:"absolute",flexDirection:"column"},o),[o]);return SB.default.createElement("ink-box",{internal_static:!0,style:p},A)};Swe.displayName="Static";$f.default=Swe});var kwe=_(bB=>{"use strict";var owt=bB&&bB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(bB,"__esModule",{value:!0});var awt=owt(on()),xwe=({children:t,transform:e})=>t==null?null:awt.default.createElement("ink-text",{style:{flexGrow:0,flexShrink:1,flexDirection:"row"},internal_transform:e},t);xwe.displayName="Transform";bB.default=xwe});var Fwe=_(xB=>{"use strict";var lwt=xB&&xB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(xB,"__esModule",{value:!0});var cwt=lwt(on()),Qwe=({count:t=1})=>cwt.default.createElement("ink-text",null,`
-`.repeat(t));Qwe.displayName="Newline";xB.default=Qwe});var Lwe=_(kB=>{"use strict";var Rwe=kB&&kB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(kB,"__esModule",{value:!0});var uwt=Rwe(on()),Awt=Rwe(sQ()),Twe=()=>uwt.default.createElement(Awt.default,{flexGrow:1});Twe.displayName="Spacer";kB.default=Twe});var lQ=_(QB=>{"use strict";var fwt=QB&&QB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(QB,"__esModule",{value:!0});var pwt=on(),hwt=fwt(cq()),gwt=()=>pwt.useContext(hwt.default);QB.default=gwt});var Owe=_(FB=>{"use strict";var dwt=FB&&FB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(FB,"__esModule",{value:!0});var Nwe=on(),mwt=dwt(lQ()),ywt=(t,e={})=>{let{stdin:r,setRawMode:o,internal_exitOnCtrlC:a}=mwt.default();Nwe.useEffect(()=>{if(e.isActive!==!1)return o(!0),()=>{o(!1)}},[e.isActive,o]),Nwe.useEffect(()=>{if(e.isActive===!1)return;let n=u=>{let A=String(u),p={upArrow:A==="\x1B[A",downArrow:A==="\x1B[B",leftArrow:A==="\x1B[D",rightArrow:A==="\x1B[C",pageDown:A==="\x1B[6~",pageUp:A==="\x1B[5~",return:A==="\r",escape:A==="\x1B",ctrl:!1,shift:!1,tab:A===" "||A==="\x1B[Z",backspace:A==="\b",delete:A==="\x7F"||A==="\x1B[3~",meta:!1};A<=""&&!p.return&&(A=String.fromCharCode(A.charCodeAt(0)+"a".charCodeAt(0)-1),p.ctrl=!0),A.startsWith("\x1B")&&(A=A.slice(1),p.meta=!0);let h=A>="A"&&A<="Z",E=A>="\u0410"&&A<="\u042F";A.length===1&&(h||E)&&(p.shift=!0),p.tab&&A==="[Z"&&(p.shift=!0),(p.tab||p.backspace||p.delete)&&(A=""),(!(A==="c"&&p.ctrl)||!a)&&t(A,p)};return r?.on("data",n),()=>{r?.off("data",n)}},[e.isActive,r,a,t])};FB.default=ywt});var Mwe=_(RB=>{"use strict";var Ewt=RB&&RB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(RB,"__esModule",{value:!0});var Cwt=on(),wwt=Ewt(aq()),Iwt=()=>Cwt.useContext(wwt.default);RB.default=Iwt});var Uwe=_(TB=>{"use strict";var Bwt=TB&&TB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(TB,"__esModule",{value:!0});var vwt=on(),Dwt=Bwt(Aq()),Pwt=()=>vwt.useContext(Dwt.default);TB.default=Pwt});var _we=_(LB=>{"use strict";var Swt=LB&&LB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(LB,"__esModule",{value:!0});var bwt=on(),xwt=Swt(pq()),kwt=()=>bwt.useContext(xwt.default);LB.default=kwt});var qwe=_(OB=>{"use strict";var Hwe=OB&&OB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(OB,"__esModule",{value:!0});var NB=on(),Qwt=Hwe(iQ()),Fwt=Hwe(lQ()),Rwt=({isActive:t=!0,autoFocus:e=!1}={})=>{let{isRawModeSupported:r,setRawMode:o}=Fwt.default(),{activeId:a,add:n,remove:u,activate:A,deactivate:p}=NB.useContext(Qwt.default),h=NB.useMemo(()=>Math.random().toString().slice(2,7),[]);return NB.useEffect(()=>(n(h,{autoFocus:e}),()=>{u(h)}),[h,e]),NB.useEffect(()=>{t?A(h):p(h)},[t,h]),NB.useEffect(()=>{if(!(!r||!t))return o(!0),()=>{o(!1)}},[t]),{isFocused:Boolean(h)&&a===h}};OB.default=Rwt});var Gwe=_(MB=>{"use strict";var Twt=MB&&MB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(MB,"__esModule",{value:!0});var Lwt=on(),Nwt=Twt(iQ()),Owt=()=>{let t=Lwt.useContext(Nwt.default);return{enableFocus:t.enableFocus,disableFocus:t.disableFocus,focusNext:t.focusNext,focusPrevious:t.focusPrevious}};MB.default=Owt});var jwe=_(wq=>{"use strict";Object.defineProperty(wq,"__esModule",{value:!0});wq.default=t=>{var e,r,o,a;return{width:(r=(e=t.yogaNode)===null||e===void 0?void 0:e.getComputedWidth())!==null&&r!==void 0?r:0,height:(a=(o=t.yogaNode)===null||o===void 0?void 0:o.getComputedHeight())!==null&&a!==void 0?a:0}}});var sc=_(ro=>{"use strict";Object.defineProperty(ro,"__esModule",{value:!0});var Mwt=Pwe();Object.defineProperty(ro,"render",{enumerable:!0,get:function(){return Mwt.default}});var Uwt=sQ();Object.defineProperty(ro,"Box",{enumerable:!0,get:function(){return Uwt.default}});var _wt=yq();Object.defineProperty(ro,"Text",{enumerable:!0,get:function(){return _wt.default}});var Hwt=bwe();Object.defineProperty(ro,"Static",{enumerable:!0,get:function(){return Hwt.default}});var qwt=kwe();Object.defineProperty(ro,"Transform",{enumerable:!0,get:function(){return qwt.default}});var Gwt=Fwe();Object.defineProperty(ro,"Newline",{enumerable:!0,get:function(){return Gwt.default}});var jwt=Lwe();Object.defineProperty(ro,"Spacer",{enumerable:!0,get:function(){return jwt.default}});var Ywt=Owe();Object.defineProperty(ro,"useInput",{enumerable:!0,get:function(){return Ywt.default}});var Wwt=Mwe();Object.defineProperty(ro,"useApp",{enumerable:!0,get:function(){return Wwt.default}});var Kwt=lQ();Object.defineProperty(ro,"useStdin",{enumerable:!0,get:function(){return Kwt.default}});var zwt=Uwe();Object.defineProperty(ro,"useStdout",{enumerable:!0,get:function(){return zwt.default}});var Vwt=_we();Object.defineProperty(ro,"useStderr",{enumerable:!0,get:function(){return Vwt.default}});var Jwt=qwe();Object.defineProperty(ro,"useFocus",{enumerable:!0,get:function(){return Jwt.default}});var Xwt=Gwe();Object.defineProperty(ro,"useFocusManager",{enumerable:!0,get:function(){return Xwt.default}});var Zwt=jwe();Object.defineProperty(ro,"measureElement",{enumerable:!0,get:function(){return Zwt.default}})});var Bq={};zt(Bq,{Gem:()=>Iq});var Ywe,fm,Iq,cQ=Et(()=>{Ywe=$e(sc()),fm=$e(on()),Iq=(0,fm.memo)(({active:t})=>{let e=(0,fm.useMemo)(()=>t?"\u25C9":"\u25EF",[t]),r=(0,fm.useMemo)(()=>t?"green":"yellow",[t]);return fm.default.createElement(Ywe.Text,{color:r},e)})});var Kwe={};zt(Kwe,{useKeypress:()=>pm});function pm({active:t},e,r){let{stdin:o}=(0,Wwe.useStdin)(),a=(0,uQ.useCallback)((n,u)=>e(n,u),r);(0,uQ.useEffect)(()=>{if(!(!t||!o))return o.on("keypress",a),()=>{o.off("keypress",a)}},[t,a,o])}var Wwe,uQ,UB=Et(()=>{Wwe=$e(sc()),uQ=$e(on())});var Vwe={};zt(Vwe,{FocusRequest:()=>zwe,useFocusRequest:()=>vq});var zwe,vq,Dq=Et(()=>{UB();zwe=(r=>(r.BEFORE="before",r.AFTER="after",r))(zwe||{}),vq=function({active:t},e,r){pm({active:t},(o,a)=>{a.name==="tab"&&(a.shift?e("before"):e("after"))},r)}});var Jwe={};zt(Jwe,{useListInput:()=>_B});var _B,AQ=Et(()=>{UB();_B=function(t,e,{active:r,minus:o,plus:a,set:n,loop:u=!0}){pm({active:r},(A,p)=>{let h=e.indexOf(t);switch(p.name){case o:{let E=h-1;if(u){n(e[(e.length+E)%e.length]);return}if(E<0)return;n(e[E])}break;case a:{let E=h+1;if(u){n(e[E%e.length]);return}if(E>=e.length)return;n(e[E])}break}},[e,t,a,n,u])}});var fQ={};zt(fQ,{ScrollableItems:()=>$wt});var w0,Na,$wt,pQ=Et(()=>{w0=$e(sc()),Na=$e(on());Dq();AQ();$wt=({active:t=!0,children:e=[],radius:r=10,size:o=1,loop:a=!0,onFocusRequest:n,willReachEnd:u})=>{let A=N=>{if(N.key===null)throw new Error("Expected all children to have a key");return N.key},p=Na.default.Children.map(e,N=>A(N)),h=p[0],[E,I]=(0,Na.useState)(h),v=p.indexOf(E);(0,Na.useEffect)(()=>{p.includes(E)||I(h)},[e]),(0,Na.useEffect)(()=>{u&&v>=p.length-2&&u()},[v]),vq({active:t&&!!n},N=>{n?.(N)},[n]),_B(E,p,{active:t,minus:"up",plus:"down",set:I,loop:a});let x=v-r,C=v+r;C>p.length&&(x-=C-p.length,C=p.length),x<0&&(C+=-x,x=0),C>=p.length&&(C=p.length-1);let R=[];for(let N=x;N<=C;++N){let U=p[N],V=t&&U===E;R.push(Na.default.createElement(w0.Box,{key:U,height:o},Na.default.createElement(w0.Box,{marginLeft:1,marginRight:1},Na.default.createElement(w0.Text,null,V?Na.default.createElement(w0.Text,{color:"cyan",bold:!0},">"):" ")),Na.default.createElement(w0.Box,null,Na.default.cloneElement(e[N],{active:V}))))}return Na.default.createElement(w0.Box,{flexDirection:"column",width:"100%"},R)}});var Xwe,ep,Zwe,Pq,$we,Sq=Et(()=>{Xwe=$e(sc()),ep=$e(on()),Zwe=ve("readline"),Pq=ep.default.createContext(null),$we=({children:t})=>{let{stdin:e,setRawMode:r}=(0,Xwe.useStdin)();(0,ep.useEffect)(()=>{r&&r(!0),e&&(0,Zwe.emitKeypressEvents)(e)},[e,r]);let[o,a]=(0,ep.useState)(new Map),n=(0,ep.useMemo)(()=>({getAll:()=>o,get:u=>o.get(u),set:(u,A)=>a(new Map([...o,[u,A]]))}),[o,a]);return ep.default.createElement(Pq.Provider,{value:n,children:t})}});var bq={};zt(bq,{useMinistore:()=>eIt});function eIt(t,e){let r=(0,hQ.useContext)(Pq);if(r===null)throw new Error("Expected this hook to run with a ministore context attached");if(typeof t>"u")return r.getAll();let o=(0,hQ.useCallback)(n=>{r.set(t,n)},[t,r.set]),a=r.get(t);return typeof a>"u"&&(a=e),[a,o]}var hQ,xq=Et(()=>{hQ=$e(on());Sq()});var dQ={};zt(dQ,{renderForm:()=>tIt});async function tIt(t,e,{stdin:r,stdout:o,stderr:a}){let n,u=p=>{let{exit:h}=(0,gQ.useApp)();pm({active:!0},(E,I)=>{I.name==="return"&&(n=p,h())},[h,p])},{waitUntilExit:A}=(0,gQ.render)(kq.default.createElement($we,null,kq.default.createElement(t,{...e,useSubmit:u})),{stdin:r,stdout:o,stderr:a});return await A(),n}var gQ,kq,mQ=Et(()=>{gQ=$e(sc()),kq=$e(on());Sq();UB()});var nIe=_(HB=>{"use strict";Object.defineProperty(HB,"__esModule",{value:!0});HB.UncontrolledTextInput=void 0;var tIe=on(),Qq=on(),eIe=sc(),hm=rQ(),rIe=({value:t,placeholder:e="",focus:r=!0,mask:o,highlightPastedText:a=!1,showCursor:n=!0,onChange:u,onSubmit:A})=>{let[{cursorOffset:p,cursorWidth:h},E]=Qq.useState({cursorOffset:(t||"").length,cursorWidth:0});Qq.useEffect(()=>{E(R=>{if(!r||!n)return R;let N=t||"";return R.cursorOffset>N.length-1?{cursorOffset:N.length,cursorWidth:0}:R})},[t,r,n]);let I=a?h:0,v=o?o.repeat(t.length):t,x=v,C=e?hm.grey(e):void 0;if(n&&r){C=e.length>0?hm.inverse(e[0])+hm.grey(e.slice(1)):hm.inverse(" "),x=v.length>0?"":hm.inverse(" ");let R=0;for(let N of v)R>=p-I&&R<=p?x+=hm.inverse(N):x+=N,R++;v.length>0&&p===v.length&&(x+=hm.inverse(" "))}return eIe.useInput((R,N)=>{if(N.upArrow||N.downArrow||N.ctrl&&R==="c"||N.tab||N.shift&&N.tab)return;if(N.return){A&&A(t);return}let U=p,V=t,te=0;N.leftArrow?n&&U--:N.rightArrow?n&&U++:N.backspace||N.delete?p>0&&(V=t.slice(0,p-1)+t.slice(p,t.length),U--):(V=t.slice(0,p)+R+t.slice(p,t.length),U+=R.length,R.length>1&&(te=R.length)),p<0&&(U=0),p>t.length&&(U=t.length),E({cursorOffset:U,cursorWidth:te}),V!==t&&u(V)},{isActive:r}),tIe.createElement(eIe.Text,null,e?v.length>0?x:C:x)};HB.default=rIe;HB.UncontrolledTextInput=t=>{let[e,r]=Qq.useState("");return tIe.createElement(rIe,Object.assign({},t,{value:e,onChange:r}))}});var oIe={};zt(oIe,{Pad:()=>Fq});var iIe,sIe,Fq,Rq=Et(()=>{iIe=$e(sc()),sIe=$e(on()),Fq=({length:t,active:e})=>{if(t===0)return null;let r=t>1?` ${"-".repeat(t-1)}`:" ";return sIe.default.createElement(iIe.Text,{dimColor:!e},r)}});var aIe={};zt(aIe,{ItemOptions:()=>rIt});var GB,B0,rIt,lIe=Et(()=>{GB=$e(sc()),B0=$e(on());AQ();cQ();Rq();rIt=function({active:t,skewer:e,options:r,value:o,onChange:a,sizes:n=[]}){let u=r.filter(({label:p})=>!!p).map(({value:p})=>p),A=r.findIndex(p=>p.value===o&&p.label!="");return _B(o,u,{active:t,minus:"left",plus:"right",set:a}),B0.default.createElement(B0.default.Fragment,null,r.map(({label:p},h)=>{let E=h===A,I=n[h]-1||0,v=p.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,""),x=Math.max(0,I-v.length-2);return p?B0.default.createElement(GB.Box,{key:p,width:I,marginLeft:1},B0.default.createElement(GB.Text,{wrap:"truncate"},B0.default.createElement(Iq,{active:E})," ",p),e?B0.default.createElement(Fq,{active:t,length:x}):null):B0.default.createElement(GB.Box,{key:`spacer-${h}`,width:I,marginLeft:1})}))}});var vIe=_((XVt,BIe)=>{var qq;BIe.exports=()=>(typeof qq>"u"&&(qq=ve("zlib").brotliDecompressSync(Buffer.from("W+94VqNs2wWroLyB16aprZ1SqBPiGBuovDK7hpe9UNWCwn5B2fapBEG5q+GLtoZ2wLihqpqXVMbYBrKfIwpmlllKJHMYqhBBjRwNzis7OszQG2/Y9mGQsTByLBpWtDG6WqLPmIiZrIlGLnQaouOor5hHHLkn3kvPi+zzRUC4f+Qt/ylgxV9kSpxw68X1SjPI2J2kXLuKX0uYkEgQiYbSNz13ci61Z1j+20CEcau/CIaIWra43JP2VJ/jFZ/49f9t2ru2N6trDYklynt2Siek1xWykagmo2E4xvwmK1otFd8SJLvLL98Hv9wIj3dmM7w0mFtNzX8+rzM7TGeS8kCgG27R15ovdVB27JwyicTp0qH+t6b/qzWmMTK+smU83PdLqalX0YQ00ZQmmznrv59X9rBZwraHqi1ndXEkj+SUDnRAP6LT35v99+dr+sxYnThV9p6O1IhA2GcSGkh7twjZLDjEXYI5TPaW0+FrK31EraAdZZraz7cWJQWwZdH0ONGByv4nYpv9S7pqERSMP7aSnfnv5s60UPFhp13FRiT/E9J3wa56v2bv7fqT7pDmEXxx8Bf2CyojN5U8tjikbDHrl6+mX79wJ8cQbSedSpNbUTQ8JV19SboAT5i3eyJ4M7RULftvKr2zbDqWMbUxzB0H0CrsAEsSNg8QD//Vu7VczOfHHN3eet2dfkUCVCBK3GnQasgh+s84A9vN0RAm4Af4Wnv94xUwdMpR0uqEGemTPFnqrV+JLglTFUU/vrF1POxBKtu145vPgINCPZCKbobLh9wNE3e/BM/T77fnPz/uIysrzufaw4yAkG5p8PGXaJNCUXE6Y/lRQ60/Hnb/D7aVHfn4XnU1FALsRkGJfJPlSTVRJlhGCdL40Y/mP31+7O5eoibPfJ6qrm6KAbTAHmX+Jsy1IKjjDZOg8cNi84+HHkzR77fHN5NJNsCC2RCR3pDW2RAR1bZL9P10Oq4Jt+OVVQK7+pu+dM8OFhxfAB6xdP3x8NsAW49PspKIbrYfqbLw9sxfY3h4ynf75eL9qlatyzPJtI0Q9CJVyw6CjBi1avVdAEo3tW7h+icwbMmMmt+/b1pKnmacrMtcqCBeB3LkbBBtrpPjV9V9d9C/zbK70Rw2QHKEcWeHa8dK/lW99xvdDYACObNLs8Z5RdYEQaAsIkfGhbL65VdSGQcF6RkkeS4EtN0vO3f3ZuacoYKC4opflVUvx345j4SoAAbdszJzTPf3fWn2bs99L5FIECwWyGJLoEotUer/7aL0R/UPb50YSqqxh7F63HlebMR7z7nX9e69L1v5Xia+Ml8mLOSAEDJB+jMzAQcBkPkyASqBYslgVakNUlIHS60OU0P/oMYe5iLIihCLpQiRrPpDSfIgyaM8jCtHVP9hnFa2V2Psh2lY/b13Xuy99HrhnZfLv1p6sbT//75pvWkPZmb1//KZcZGSxNhuWR8pCohzz3l7GoUqaAhDrSaa/I7fGHv32ee+KhQKGBDkOPbYb1wm+SByNoykWGkCkjLjIimSgjQTRLVsdvtDz5KmXngK489aUkrGpGA1OO6b+7Szg335dMRKLyTHrFyzl8NWSBKmwgKhrJDVtsKYQkonf6yKF4s19mMd0kDHGHCu4ciDjDoEdqL2746+IDWu6r6T6pLFJ7ipzPfbVKMdJUF4lA53pN2qEt1lzCcdK9fheAhVW+o/Dqa1B1/1TUAhBZSAZ6ot04lYYSmtY6not+Pav3nYZvxjE7kz5o+7bU5RJA3CQgxAxZ5iYvTsVagLL34Mzzb7ezt1flH80SuDeI9UEVGxNquWbrfDmGJg5eLCvX+tgg8YtFsQPIEzvxP66xXkW6GwsBAIzHs/EAgMBAILJ1CYndY/WOa/nPcUUxhiggsTlGCCCkNUuFBhiJYViwrBqlDhhVc82BwXz9vu3iIIPgQ7HwZBvjr/n5q+Jw2e/c7ngoKCgoCCgoAAaxVgrQIMAgyslYHBWcnA4FnTvn/w75yT+vPfYIMJJphgAgUKBBZGGAXCCNyBsDtQoAcK2tBB8eigg/FnsM2s2Epl4g0eoCZ25q9PEq6FkMn8v5v9/0mF9iLl3idzKuARQowiHsSKBpUqVGxkvfdlkS0jA7jt///hJbwq+n6dkpQFsI0RGyNHjkilYkNaUvvEz/OX8CKtUP5GKAvgV408T49FcQxOfHeQ2GTmz5HH0PYWMuvMvFp58urWWHGQHWfHIpLv+4eZ8D09vGumt3B038w6M7/PdTXHI7GhKTm45W50cG7hl0GWscYBI2+Vbqu9qWzBDPnWA2vul6l7P1nrjgTNOjuShJbYc86TbWbGrWPckVmLCeBwunL8tk35lI1T+T3QOTzoFBkqQRM+1hzpDhbJEz7hPREN8JIG5xzRx7UImC1hbgpOSkqeSgbWl9F8WlcibjFc943P6qq86nRdqkHZCDxXzDmifjpgsYv9njWkQNpmpgbSukfSht6uuEz2DGP+OIhApYBkdpOPr2afp7Td0Eyiy5fif6Yldt6WCfsHUC3lf8s5PGzMkxXBPSCsIkpdGzTsbmIgmRKlRO6sYY8KqKLk8n/bX3A62ws/9+MnAwbTX3atD/6BlziR9H0y6xtdXz6l7mPyJ46Hb+OHRB4ze3P04jGLyK1YL8q/SEKCXlDgzXo4yUaZpE86JODT8SI5EvRSJl8kwQxPRW6wSNKeis8TFkvWcET5wSKp2VGWZbzVD6c01DefNcSMd5gLkVS+loSWfZ9i91qKjPq+zP17GXfg3IOE/rjZYv5cHln9UeQgUpzpZNX5Bz7OTUcZZQocyHy6vSkfHlix95CRRB58eFoMYXlkKqVKGrltyBj09Qt6pUbbTHzyDLWCMnptiag9YGRoYN/PBazEbZiNWxJmXydzo3C9sY6+RA0vIU/cMBQBJiNaLqnCUOvNh6YgJp26EMO8hnRrjGzhWGv51IwgV9BQxDie1Bminp2vOAmkHvrQ0mokBYFhxnfdgH1528l022Q6aLb4dPUL8Fbv9fwVMxQBNLLQjmQVzFroQ1NJBqgLMYkbvWmLUDxEq6g+NvTJ2LtCcCVmvuNLrVzX+nZOiv4QbSxFRzQ54k5XUk2vjrRnqUdS/y88WfvdI4mvrJ9YP+QuqJ+gVwKvqNIY79m657uFM0I2+tstCvyVqhHAq3Jo76BwwqbetiVzLaZyjd+fKjDNDVpvrFIviMB3VK3PML2y+v8LfShn9jOL1mtKcPClUelFj4/TgD17P1uB7/Xwtwu8MHY7g7WWtptVxFMO22sbcFL85bYHjF5onavvMKymNh91dWyruTIefdOMrrgQo7tLil6IsSRDNuiX5m1bm0cZnpH7UMJ3STyUBSyLc+/XKHZfklinZ22QLYs7NqeG6+K8/cHM/WBknqc9t/4WfTq6Kg4EdpB0DqdwSEE0lpWLlqKSlYGz9zNJWfmquTj75dkvH9zyjMu7Pw+IGUReUIaD3NHocob1LUiUFXZ2uJEF5hWewt2fZ4A+pDcDYYsc5Oq24L64jxzlv2EL1rOBHGbYgr5hYs0my2t8FUFlkWX3KlYtdASuYWu7rBldu8WYI0S7yYxmzo830N2gDnuEOGQIyOcw+acPalvp+iDTHGSDhrBo0PvS6besOkNyXKmIE4i3D6yj+FtYW2/QM02UKBe7BdrqrigT07QNbw/DvPIFQLmjBNFlOHwcoQ19mojZ8BiRrEE1u/A4R2XMv/zELYJRihoQ2df4qfeW0QRzOa4cEVdixTAnPoziwnPy8R3kEA52Mg/azywPWnxRWIYrk4N8AjMW0x2mtqPbFfpe3ms0p0MbMarVHDZWB7IcEshkizhoXY+HVRscm1UtMoo6GOxctWFVaDya0KcluyLKz9VIP6gmAlQDP2iwAlRPGchKauDIYMr4VBFOnIRr441lO8nRtoULpTgo4EIdHaU6ABzXAV66acb5njkW58QVHNTJrWX9ILGerqNFSVQPHpyb+mdmO1ttXhqT7VFGMM9snb6N3kn8rN7oBP6o5QDe5lQ2avAOl/muEeaFInmib+AP1jeQBykspEgCF6vJuAFTdrake9RqV8OVmpvKq57uETZDL2179jTZUKxc2JSz7dBWi9RLkQhCP3ZR1Kf/lzLTBq62NBer6e4JVIfxvOvGYLBZ7tfvGyX/EA1bw/Zeg83D5+k3jLhoxHZVnd00xumet3dF17BL/Flsz/szuCSgbOKQQBnSNSZgd3et51vpJHi7t/6BUxpfj/aEw2d0Bf9vNTjv8ALTTHJe9bc9wdEAnR8oSv1UWU/SgrCH/Fk0tvId9XHO5V/93AbI0GsttlIRW/qyT0dpeNsqSn/opeEKz01N6ZpByWQVSd9CWJ82lSTRag+snDZuMIlD6N4m2pGg1vmeVQmTgzSBYnOtR/2hRmxmul4IMWTyibmZZ4LayEsM+W+iMKzxLZqqMmr8uq64A9VOMqHp0pQMP5tQ8Gkls0dPIjkZFEC1arbo1HYlaM/c6AJQz17KTfCzQcPBiqjRtDqU6qLsydTbOZd7JZT9ks3wXyRTGWME7dS1CvDpaHLT4xOaTlwxoXhHTh3to3aR4Mqxjw7opVcbDU+KfibIIYadSlSy1yJGxlekic5ENlQkHr7GQc9fKanvXxlB+g//xbMs7ezNs9n25TJjtWXUD+qXCY7+lpo1S02DW9VdmtNzQ5W+1XpZS2BnReHtLa3sexJBDbDL9L0fyjvdFPxoRwNvV/fmonmzNoJJchCjioxiQleRZYhYb0YJych15pfQCAMHVV6BL9XenRPdTCOPN3b7dajLJ+iLY2CJCShPmDWKQSeymhLS2Wyk0lOaeUgcRP0pL2WvGDC6HbHTusc6ix9MCwt0mMYW64BYNEBSq4T2EJuEi7y4j5k4ZKLK0MVDkdZ2dgSKoUHkeDgzlzFgYEwwz4143q0kLMbQnLTvUsRC+Xzm6e4DXNeakceVgPBiQouDGZxfv+jQ0VLdRrWNolLHNriVY992F2Fo0JSDkmkFqfUtR2W7eTUU5em6pJM6G/3w+hj88fV+8A3t+c5mp1KekRqPTlbOw2E7Db+rzHw631ao8gtJGOLAHvnrOsfU3cVL6zEJ8ChHuQcH8ktxDq8ZOaRs8ywGYKOGoNnN8e360HMWehibSycyobEMzm/wdy2wgYWtoOVG3S1jTRNkSAijWtBw7W2N1Nzyo8EZhB7a5RLvfUgRCCAHkfc8X0rDlkRVxDbr0uBwTnXKSnt5Y+truFA+tJGZ15oc3nwb2xr516cww9kgifhoL0tLGMjmS6L6yU1Pdlcmd6zUJelsFJsx5tpC3dULZNHyR/MD4ZcxUAizC1UZPAPzAu5IiMhUq5muI6qTQIUspJt6nu1fWnKo0oGX5DDg3TZQiHXMeO89Um0KlmwHVURzE7TAp+pkikx1pypJzlW6fGOys1ywhUU9KSpQkWUeUkYg6Lg6vSxDswzC8LeJfBtOsl50dIZxVYrdnE3EdNBp3WIzlgMXoULX2EKCpFgvNybf2bYQvzXn0iF2l4eMU5BJP16R8/gAIwNn/+YpQJjGJgt7bpKR91LbD2+ZWM1bqJyaeiTUaR3Qdjk4otqqnqzlKc5kjU1divMRhYe7KCUX1zOE8BW0KGz6y062pV+rAeqj2sl0ZTxntBt4dirkUWdXPZimJCix+iiSSpezVSpgpACOpMa65ihU00fsqxomuZ4ELbSb+m53S5FAIauLnC0ycOdkelI2lT3q5E/f4wjHhcuRuwTIDA0Re7SM0ogV4rTUZi6CQr5VrjDfBiPgi1qFmJW7LD81Nouxf6+Q7q/lBCiUEimoTI9ytYrOtMmPETAYLAJKMoArHktgFt0h06avbUdDe7SXihMukxrar88ECFitHscQHZytrX6WdKLWyd4EhDLPBQZOymbsIIsOvTjj0teSpqMmBJcFN1ugDB7xDDwtpqtRqLrgSvlY5ZHRqQhmucYjC51kdZ5yTawoeS8VSNXVeLSajzhNiZlXo2S97NIcFF3PFYGSh+qmaANauCpf1zSTuWA+3o2bA1iGLZAwJ3RNnpLzYsL5xA3bOH2ctgcitqrsQaj2A0NPIP7GlksDL3O8Q2FghYrFd4kfss+HE1zOaWBhQtjvZ5FDdXPnTztUSu6CQr/BXDXJNZPMlSwJFWdsnc84d5d4zBTOOih3W+G5ZJnyJ89ZideetJtxezZ5OvAecOXSnVi6aqJw0i57/GRBRsb8cDw3+JADegaWyd20T47T5dDqrSvf0J1VL59OmCNOYJkADC9cocmMK0h8SHrTsB/bVOUBnWfmtBS8wFxHSv3yPLNFcGuvNj3YI0OdICY/2IWrYDLtfjhVzacZ563lHtGoNcLoot7AbER/viaLG4/RfQzdrosZBQmAS3qnRjh5fxh22bbkzfg9poHD1BA4rwU6D2BEy6BIZyNUh0WAdRHp1xosgNU5U+p+WvorR1tdjnbw7Y1ZYdUpUEERFnkszHsRljnP9mgariiJE+4UiTipCS54zCpYXOJgMG9x3JdrkHcWVA/FUBnygaZqJJsJIytZSZJXzOO1zRCbmEGdW3B8PzD2oHvBeHyh/8sbo0BbR6Jj5GyPMi3OkH0zWruc5PDcjuqkWgsgw5HZ9VYeofbbq9kiYRnEJBqFf6MYPUBVidfpFZvhNGuVtWsq1raeia6FpmUWjGWa1uRHCpGpzVdQUwt9IZBetC+SsUUJeOQPXl8POqSBrZYytGTilGpaMJdbKTn05nAX5Ja1rTrNv/MNiFzq1K5bRoQI6dxOFUVdfkZZCwiha2s9i2rh7FSq6UF7kbSwCIrnBn3wsljbail71OrklaeVWKVIYWKuDcRMRsDC9GTByI4FfbXSPjQfj0PnzOOrfamXONZssZ8lnjqMlpgsUOjUDIcRiXr39ptA7HY8arMzD0JlitUhU1xVG4uhk39nKL5U3gvGwmYKk0cqrfM7Kc8I1AB0+q9SYipzAMxVtQ24bh8YF6gKE6ZdkqQ7gGxZK9jNXxUMTIt0MxNJoVnLzuXwRljdyGFsg8oVzKpDJWZ62/2CdV0JkePgiaHGV9AHcWgJNo3LP7+wAuNbG8bftcy889VHq2ss2wD18b+boi9hmKsrd7IFXicyf1nDP9782tpQUvXqAdbO9uV/LqQwROrjddqDdoD0ka3H4t4UZPzsrWl+6EjnemKblS/rmnKLa6iBPIjBLuSQ03PpnGyCA5d0gkT1+EM5GiFZiwQGORfMfvqz3n8RJ91DBThTXVoAs18JZBBY8Y9neMrSZ88sDbHHlwLeFBLduIVpHy7DlSoco/LqgUROnz2nwL8crVqAeeUo72tA+4BxH3YpWmCSV6CjvGkOKEl3tAqdvsyYMoZud00izDWrZN9pZPXd4UM/j40Hd1fHMueryuls8hwTxdYhsj+gL55ePy3HRzUmOVLpc5byKIDBjyviiBd6fcxtzTb4kcD1BAwif/bp44GsZRfh46YdqhLe5+iOONbZtmfo7WWnHllHYzbM9UO5G8Q5gQ1D/5Mv/HXDQJ+0zS/SpaoPF6eaAfm5sTmKretnD062o+mWgprhGdicaZjd9hOSW9vsN5Rl1ZywFghK4ZEWJRQDaT/mcJcAXVxLOvKCyNY+xlwRF35OORO0tIsWjL2Mo6tIzVjLcRkvgsLSOSWjhgJuvATnsXUg6SqiFRswGmRnaS7GUb6BoyuMOiUmWvh5vNq2lGpOwBP2TRF4VozGEKRLaW5fnG7sujRuQ5uwMX6z5FH+NtrE0zKv6viKtUy/sf/5LAALizi8SpUHt7xpARkc1AsdIfe8FBNZREiY7IuVIV9kh/m22gmykxWR+ZA9Bx1oQwv5dJRunbIKfIehRe/Xh930wHEemulVUKPSlRXSh94oKPfAOTLRJ5I3wowcu5izeIy06ipBL7YuvQQLsZ1Pa4ggRv1nYYGjQmEHA73trmTVTIC3aBmniPP5mDnKlsZeogge6dMv4G90usuH0y3iVv2yZBt3P/qCGBu9zKREqQpUInQ4VlzJ1VZL5qE5LogMWZYA1Jsdu+iWWqQllspyEF5dY5WPhKpUZf+6LMlldYTZksP8Xgqf9+OF2sdxEE5YSfjEUnRXdmcZ5QL13eIgUvh3fIFyRZEtc6ELomWBZCaiB3WhIa/rAN3YWCAATAHUe46cUO8k90G+wiwqcVyt2XOrHpYAh/lQjZO72qMqR3W6dyKjbYtBzSdtJmENbKhmsErZBa3ph2RKiewmeiOpr/Jk7+GMrvVqNHGk8rJ/JGclHJpxSvhkyZz2SJ90BnQdIxxz1Zeni3Te50sQ7JbNWR+P0HhwyfXZNRhF6GWh2S5KhmY/FtNqyvQRoWL2U8Z/P5fIfpfmg4IR85FO6RZZrDXFOkSZd1xQ7bGAvKZRxVqQZ+xe+tC6Chnd6lYaLkcpSferZCyUmhCu6+ElHZBZB60e2cKdLBWsudDn/U/Qsm9Ru1E3OT0CL9c4V7WSRPBNtFqcDe6QiyVVSR7lXV8XRQxFM3l1UIj3uRfq7wMF77oo9+WZNtsdqbjorxNZhhZdIsZuqVMb2ilfGyOMm9W/ZtFR/LSBSCK/A0Q+eWJsTPk4/baq3YSROz49XykoFPRqQXYhq6N8CYaobqQLd825777z7XBOA10eqe/Ggh5imNgej5h1bnDKc2wGlAnEUS6MRz7sHLQj87sNqCgToVZxkIi6KU8Wd+UREOWOuJXfVt+1LjWSLOvRdn+wHyOFJFOcRCp+8aYJAPzA3wqepeY6ZU4AaRcOcM/kSj+b6CT0F7x4O3LvRltcJ/1H3TV8A3U6XdaK1PXZZdLznj0dcNcR+Tg5GalI4vqLabN2xwyUefJBdRhCIKNat9d7rZomLN/nh0xot2BJ/t7tM7H93oSmH9GvMqL6rtJpu4Ts3Gk28kgZkAD6+kw2epWu17GOA/PhrwrWa+1RLsyR33mQJgtNedgpmIrQ02SSXsrpkrnoml3aXY7ZnilyTZlkWNOJk4PCVOcL9ZoYjl9athCWQ/cA8vJyqmGmU4pVU14OtSyuAcTw2d9Cqssk/9II/7A16BMuzJ7QX0TLKptC50FmjTpWUTNIMzme5onehNMbSfBrJ60BOMym982Oypgvx/5JgbsKyGSkGI6bpZNgXeLH63UeH9JAO0r0pxbUKXgDjGRNpFzLjBdS6w1LF7w05iKB8VASWQqUo6ho9MqLlKudnOWTRabTPHMa9ZfZE+jL84y8Cf4lMru/GLmLSVm59DMCC4F2CQuUYkGMTRAcoOP3BrTBQRS/wzkGyWjettbO8aNHhTUUIAQmFIYonUZPb8AlNVDcni8iOiHdhpjhdlhMLINj/nLycMKcvJgPvH7bplu/atun7dhzCzQWj5vWKlwlpsKeG99nA/xXgeVkfmYgqSw8/6ofZZtugLag8bFHsdB6xMgTQEUesYF6rBKGR9I7BBOIOo+APiXNqKZtokrSVeFsKDFxdSCrt/H0jJd7J3o6jCCuU7t/UvySilFQBMQwwHGme899Bjlb+/zu2pzOvq6p0o7b97zAku9/PznpcoBAf3066VN+RMQaTigdJXjXn9qh5M2XsZM6h3dfsaN8L60/1U2MXcYNDNzP+xzjydH8yrU6sLVqKACeZxaD7Kg+iI0TmE1ng+gNFoluWIg9YitjZxU0x83bFhNriIxSF5YJxsn0aqx7wP2TnjuEiQoKHpU6XP10Ysi1JYDJjtNJPKYUuI4qqeDNoWuxOdFc8wSybv8Z7sEdXNV7bUNFFD7c/Sq7o7p00eMSmbQr37qtis4ScbGbqhV0rfS04wIHuQklsWCCLgrh1Hjd56wT6CULAjdIz6Z2ORZBtPFudsKTRLQkJqrddiqbefUJ+ZDOU7fx00nDbXyUftOwU0/xvnPlhyrWPwSlLDc92fOX2Lm8E5HedKAn+bc/r+ZG04gfUuO84XEP88T0zytMSpeznVIH5x5LDPnacoSsTUtuyMJ+HuQo9KHIRoXQuskabp+J9CA4POUNZBHco48CtwaFx2TXaP2KtOsvwCY3utRDKckDyoGXyaMe7EdxVk4PtxwWkzwWkp9oMfILIf4xymrHP57lmA83ufIzTiH8DSAvNuU9XzvDZU7uK/t3FKKTixYmOfLMYZTS01EV4RRZ+p2+bIPdGvEgWMdlEei4q0rK8ua+3uX0qcvjeqqsh6nOiKgmry9D6oh69Suijg0iM5JF0kBEWxL4IC39K8fpcrZmdTdBYnbt8xOKuNTlPnJT50SrjdzDQ8FdHqxrHzXY/m/U4urCId6Ey/Wf6GaC5kda61xrOISE0LIS0/0w+PfpYQy4XtcwzamvLUSuH469v+lHYaypLQ/9xXSPqgsbE833jR3i3re1GrDTOoaz0/lC3+LUC/0o+ZWSYTz3JkdpV9I7JXZJVmr/vrtiMYU0DAWIUmrvj5uYBe4gnUIHnJI1rEFuW+n8Y9SEEAs827LE1fjyKzxixPjLswNyBqujCIJXPpLg9OV/sM7heOcbWmPOQEQ3NdYkxyODcRyt5U4+GZzNORhCVWcjCDVxOKl4WfR191liEvXgGh15M689peqTZvI3vE9meyGMDX70nbaR8lLu+eA9mHgZTbnZxsq08Kxr5nK1kiZu2Etw+UNGfK/pBnQpxpT4MlaRuM1s2kHq0pgLkBmdfjEsb+OFhs6GkQ2hjlXc2GG8iaEF5BHbVNx9zw7qI2WXX7oxW553lF5iDxq/p+vnnfm8ivSQEn5sxZXCh6trL7+/IsJaQmXsIO0jxjIuQr7edi/mAgFvfz8CkWbazI/cYVmJm6UP56Z1qna4R+WI3pyHEB7quGO4qpTOLXAomt4qQ7s/3TvTl9HHtZPCpc/4HMfPyA9dleNi2YUlntzH2flNMAYGgv3o/IQi/rnnVYlDfhrX7TyUlOv2I0vmTEdwjEj+CKoNhkR72egsXGo9m3T93UG1i3/SnLZGuetuq3C1M8ioYvF7Q2QrGLPmjy309Ymebg/axMkVqz3+BbKnlGe77ClN6eVcfVTwbj8V0h2c1nJ5eljrLw/r65lJzSJIx1lw6gQS8lmreYPrGW99oinDaW6OfAv68i1lmqZNus6T8h3/DCdpxjkcgyiFzmoK4pC8jSxhYSy1kg+cTStqFZJYhtdb3Rh6vB8c6Do9oZG76JGpI2nDaIyI6WnbOhmgR171ooNINJKLSSKLUkQnOuNb5sKsDeZVoaYhRRpZSo6taF+mqW7iwWFVGYFAKvzNkSCRF89IlVMg4b6PR8lCE0B2gCwOq8DskEKAYC2wgFgKoTGwwnV9OAFC8HlTkJQL0JmIQxZZW2HMS+WCPi7M2EmAbapAGZdCLnOJ5/2bzBYockOafVxUduaGTCyB4HlkmqMmgGu9egh2+IiPbK2ktUJizW8FCNJd4pF7wreUYCDYDDxiQ3YHVE1wmTvVtw0p5TRwIXFoZSyt58dK4JgjVEXJPZ+MvPBbCbnCcg8W9DMO1umMzzPDuwVjHvQy5E/MgTsllcJJrYSxGCPyyG2nFYuBTBUNfhxfj9ftYBHdCYxHp80/6pTpoYqPaWh9Ne4VrHCpHbpMHa5p68PR6wxnuOVpxly6layyOMqbjQkMCgrS8f6iFIj5couR9kr6Vz0vbarKJTsjTwzVs8F8Lmc+K8ybpi+xn3QPfa64JsZ2Fm3Cym0majQ9TE00aQVnaORkCgw/l3GCH7ND8/LSGP97r608LBIg0jif8utDaPeZ6NH0cDXRpJWuUMnVNLiC8msSJc8Xf3YMZXSTe9/oCJ4VBnLPfHbGSp58nDzFmwMPr3PxqFkq9PBerDS2LqM7taUnV1Uk0NOhQOrKuTLb7gajlicb7zyCgZgRh7LCQe+XNbmqvAlCY1ip3yybBBkpUxQQgs+mCwAyfTy/+XIEftAx2AAm24BbbNlLclVYuOtVF4e9B2CrA4ib3uONkwCWmUUauTOjSUnY+DqRKQh08fhlv8WnvwKYz+/M54eZnfIm1fHosQ340skUmFlHf7xmk4Ae24C9HfswU4+mWSdZ51hnWUPess0Js1kVKGZJJNirDzAXmiUAPFtwSJ/pBh9bofK+ptbdyfOnl5uC7UOJnISJL6qmnRY4n4uNDXqqaunImZYt27BDJAh7u00b+ltrUy647lVR61rLtvMKNoFLX8LY3p+ZPpfsEDD4Mg0IBGjKLgiXKwvqD90FDh7t4OuVF0eotXGkctUUZJuzauNJQa++TJo8Cpoa02DheRY+sUCk674D9ikO2GY50J3H1rgLam0AT7MByPTB0vzwCrtlSsf6pUI1GOm6JM0gtiFuHodEbSi6reO8z0PR6GxB1jzzHk8QqEtceyW+vsWQC9VjWSU5vCD3FUrAaVf2z2/VpgRxuTz7qPDmQf7NFcf3bkH4nMOudDaEmJuoL+Du9DMFi3M8qT9Vi3yEZ2VBjz9GrrhKZskBIxWxncqlP48jKYzzk8HtcMpaqCRPDVcL6QU3d1o4yHUkGvpoTMi9vdDe+bPPEo2dtC2PPlqeCI1B8W8v8+gpDuNPEuPPCNOsKYme8ly3JUcIjuVAw3LtksSK2QfxTIeGR7Xp7ofebrFQGz0LluWt4xUWiZK21jgdHHpbB1XOcIuts7VHyB9AhUeDFolJcTFlr4RzTTa4SkMZQlWdK+VJIcwcwwI/kSkidXnFfkvajkHEDurLfIzWZXEtkCOHWazFBfoG72i2v3D/6yoN4Nqn8/LMmv+NW+OQz953PEI8uWCTJB3yLhUB9nbzH/p8qZkX48XvRK2aTswG7JktFfi2ESkuS27RFm2BpWqZ1vxpefy/tRsZ/9zajjyD/5PZMWtcBOq3WbmkVt1hiEVCIAOR+l7AzXDW+zBh+UE4OZAI81679hblcjDgz6nrzZ20xHAo3JVF92GrspmfZX+OrDEGCY0ABHcLbBnDSn7FZteBZPMzQlkAZyJ+GbL72OarUGag7ddwqmjI2W+M+lpq++cUHERsels2W8zYmJQL9T9eDIkGlayFdsDAub7BGi43Yn2tOk1R+BOk6n7tatn1g74W5IN42Q5yDI15TerAEKAquaFpnTe5DUYt8aYdtZsv5uHRkVOzKaC5ZA8kU5kt8Ae5u4q4H683dZTBoSONhDpyiaWxkfhGtaxVufvYsDInW3+0Rxa2MI6tQmc7IqV+eGoqOto+X+ur9nME81OF+VfnzE8L5vPDXG+16y/PBivCTC+4+i2BgW4Fbv8PUy1CTArptzKOPNWThqG1sV1eg12EciSRfgtm8uEHfnkMUy2SjArqt47OeSsnG0srab9joJWEhKZz5cyVr/nKbLfEJojAwLe5ZbY/6MG85IAwVWdsRT0tEsytv6M0ABaJnK3BjeGzrQ5kHP4KHqTwi+TwUK57X6VfSTvx341CAPrRU01zsPZh3Tbzu5N5btEWcKg/q9qfh+792CAxrwxJGL7bua3P2Hzf/jGJwRDPbAPVyTbdLcNf7A0Y/43ieUKXjyhGtawydP1wy2gwrIIogkFZjV4XmrtqqLl7lfjl+NRhPqMznx/mfqcVf+itjr00DJ0vdIiJPFWV1e8Ys/+GtBX9EAD4HkH/xR+KZAmvI1kPY92ndY61arX0cvJnMdUSnhzsr/Gg35MqOglMolt6VvlDHSwrTogQ5qn9aRKx/KlCwHQ8GhzPjYz+S0baGUjsx1+e7jHHvxHL2z6oO3cGYnrU1V/e2Zn/dDIIwlQCqVS5+0oApwfG0UiXCWqbc+DPaS3r0FsCu6x0L6LJ6HZUNi5xzXqrH+FvnByGh9OeCUsaShJILAIPyLFsJRO57vcx7edep6b2pO19Ify1BiC1vg51xu2+pZrSp9QidZyta+f60XXiK0e5X4zSqFtGNvpRzkJmjw4wqTqO2BIPIjoASFWBoTOkT+kbKIIVflrwT+xomfNVVZShw6VbZkQDE4Ni2p046TADkIygpGB/Z06iE9R58HfqJIigBh87d9YjMsKuL3tcUP/lorqHOXOKl0Bqd//2j6osYQ4ezVpHXz/NFR/A+tn4Pj9Lmrk2Mad7U7zA7pXZKKqaNqx35nSS7U7oAIPm62ZSH131XnMhJ3p5/zJE2UJn9jK/SRFZVt7ORfXmzPOZP4y9/n+75cfXt066EVR9oTMdxPS24yvR0mHCVSJ9Q6JYRixSLU/04ivfG2jLp91Kzm16FfyfzhedZ8rUh3pcX+G/xdD8J8XIwYkpd//5rN1qbyCsHh1vAHJHjte7rL2psDH15cdXXiUM0uEUpLElfLdVG6bgZO48gzTMJ68XGshZzk+ZmCqxhtpv8IP2dpN5TFr5C1ngmq7TlXGmbrprTBZH+zE/0jetTU+1JfAUtUMSPdeFdS+Qp4YF570rihpOYOVOUiqxH3M4J8USYm+TY5g0rSAJvvdnMAbPzGM/ejifAd2F3IVLczybsr79X0O/+zL35Q3tiRlMsjLbnQXKuQSSULiQGyHpB4WJE0gi440gD4ezVNFl4b4xLBByPg8hJXwgcD/KU6Iw4uL6+Q5WxNZoljplgzvz1nR5ui9rIUCB999Z7BlfTjC8OK90S18ik4yMe+GKdtbmjkimq0azxTyPfO/PCR4uvTC/1VkqZXRuJg5tNevSmmP712vf1xhJw8+UuKN++Vr2qG+SOH03itOjOChAGqNQ4RAC//MCgLDnpFy36QSgcuBRh4qeaKIkD6sS4CTLRuBNfRP440eBtSVuqCQgFrWRMSM1bNb2+dXOl1tM7b798r0/eeQsZicNeAmkTUHgH+8DhcEyXuL1/q3AqOSe5HVfZrsaGySfkVPIS7+sv73PIz9tnqQNdWssg3bd9OoNxfA0P16v69YRMlfaw4WMr1HCQcI97ok/appjpBw/QiDY9EiBi5PADZcH0SXQjxaDDgGboZh4vMdj1rR2HVtWbufhfYXrtE3F1LHYLNFK2j8Zz/4TqW3ynnhsOD56rASve42ZjEWEbidHA0HrgBf+GkLGZudlzwoPPKDgehJOW/WAgSNWGiHKX7aT+v5Dksg7Cs0YlCHx9ocs4fSh4iSXUybOYtXdfE1QZ5PfFGCj/qOiX7hFyJa3D0I5S323cAkaHDxRfymhdQlLPtPFvAEJ/pTDt/jDDWT9WBnKeg2n6evbuPn6ZPy37TlTfcPej6ucYcBC/9LzNJJc0mi/5j+ndME85kQ5vaLuw9xTM8Cal1sh8OvwJqGKB4yUubySMir4slYNqZ3r8oyPwFSgmC6b+nnM6SWjzmTz2MaZmoSPZ0xhAon+yXE9eNLec5oU1t8YGBFoq+se8qeEQNxUPgSKWSA8Qz751aYZ+yMPbFIAtKZOLX9EKgYWdUbC2meOvqr8KlXQfntE6dRpFnf7erQOCDtOqhqfYLDTf9um2ez87m0VwPaoNUowXPcNk/pDDzCHwq2Pp0mQmOy4dJx844nCfCaYn54zPxWYHwZzv68rP6ahdo4NEWxY9Aew/vi7fowox1KeNQ8hSWDOgcb8QCP7gZ6vJeB6g5T5P+cILkC6dX+1B0TzXxJFuJ2njCFGlir+oTeWLOv5mT+G15mTS/tDEkgHw8GFUZEhQ/EPSefPWEro/swFjHJAyP6Qdv5MRqP4MhrQrvrRNISeVjO8584+nQVVgnpMqQnP+22aOi+n2h6RvPXtVMPemh8e2cX0gIWW72cWD6/mZN9IPqx5v/F64ZClGHs9fWe+En++2IWvW3n796325Rua126R5zFU1ux2o4Rkt3dp+p0qY75x2y7hbVH4tpdYdpk0DejI3ISelFM7FvIJaBrr1ynp0FdQL/UYFHOcy+VVJJ2kl8godQy4Y5hR6GZAj7jCuuY113M5XuEKoZcLD7pbI53iDEJt0e/txV/f54tIlNEThSyMnkQDzoD9TERLX9OH0YT5aqGBpuBgR77GIOmPt7q/C2afI+MScLtLx/CLJgSqY/oW0tKbjEVM/uUJuGAHs3ai+zZZVdvOUpbuHqkZlAP2seMcyPTs9Gat4Q38lBed1g8C7KbMb52zzPY/6MYsJF9qnpzDwiCc6y48h6tu4NTgBC9zsX6KL9Y13jD4UlAVhJkFR/ZFLgEuiELKzbrcG8ZfivcZmpSG3JCHG0nRUKgzOGOB9Jr4G8FEcaXMJ1fGbo/jElkRAfFJlkDGAZ7zoufVt8xJ56L8mJc0eSED6R5RPJYt8FEfjxlaCIX+TQoR+1gzpYYMz1BW2IuJXvngDiZXSbDfQmB/uf9GNcYHR7bv15nvb9BsimG/v6lhQShnbBiu3nfPs8bO+UQ2R+lLH3t2HTCBQIg928Bytg00dmsTzPw2wBhs7cHe/UkhhfVHPBBa7SGHm70AEHcCUJTAq4/er76GAP7IJLsIJGq/T3t/RBcZ2dROiL6PqRV1xETw5GE+O8xP2ZmfHsxngdkyIoA/Dmhkv9rBpK8Vt3raFwCCH5BuH3xhmk2dGtkPwKQPVk/7AkDwgx/guB3FukvrFOverPuwFq2+iQ/6bRD6UVkVwR6uRTSQ842TkD9Z7oZ1iZUpykm9GlCzAQZ/ym2IYA//IiSAwSiD69KusrKoXyPkwGPYwR/tZcZ+PEcDlYRl36CDX+UlKBMeqbcCGlV+nOqUZr0Xde9IjxvI7wsoFs54sL+jIzzKypn6HWDRdcDLbhygbnaAqHaYhs33R2GFtV+NORQAmDX73fdHqGJhitZIuiZZf4h/f7eDEqOdY+TD1nspD8gg0F80ml+Rkc3RcG8HMBKlszzegj91xZEZbmAOVNfs3y9rk+eqy1nC0Ucuj//glwcQJstEsyFtrEsLYtNv/XElPCBH6PB+PIFXOIKEzgxVYRXDdR/Sz3JqW6zdJKvg0nOWuyCGxZPlUUDGQOD5mmQujzYSCFehM/zsaO22FZbtG1TY0+tzg6Od+zHeAiSBt+ZSoLaskr3nK1dn3/JFrON/ioSOEfVPkxX3LfydoEdUdwV3/kV0U7K745H8SlDvHYpYrdIkMltIF3AOx+HoQxAkCwHsR4vwHa/oTvh2ft7b1fsOgHXGHNrQQ1hZUKyXhXd5CNFiyrItKbcplx16fmtrb+z2zHOiTTujxdGKkSuUMYvLkNWRFzZZPWNHNSSVx5sAepim6dxNEjJhSSOe2KqC4XkrG1kOo50oT2HRG3BBu8WcMEbV4J3V2QEHRAB0rCpMjHxzOtTqFrPRhhwRoH3agSt6k4D5cgQBpVXFniPUJRe6762eTX+VeZtTrn2gCZ1MDmoArnr8XlGspB/VZByab8E9Ml4bW6PSP2KSW+4yrA7Ixp+Id0Nz4KUrc3dBGXUB5v2RHjwTwg25AI8ljgghY5nmB4lbc9RH/3hEOpGsFnzYoc5kECSCayLjzadtDKVgZalqCmF/5zePdUmkdKzkPc/7ggHMVdg7aHzlAoL8MDkcxkExSS3N9x29N9JNEjqPekg2McCKZZFmxgM7btEWXltXeRImysTC//h3LREemsRgXrGNA4Z9Z9DQMN85Dp4+Zii+Bg/WYNyQVNlTd/gRURdPVHeQXKlLtkl4rX85rf2ttFo2kp+4DZe9jVrlFYZm6Eq4jhV/J8UdU8hXCxxDvZ69LPTQW0sZvUpaZHcsrxli1o81fb4I6WC78M09f1GukLLuwUU6a8rZzEblnWq7PJq2YJWxSRjd+kwT8BUby17fkpQB13zGEfctFyxZ2aHJIIs+VFmAqrlEqcy3IQnBCJfgNF2aUl2ADyT1MWajhonEcD2YSJe8LMd9F3D1wMTFIt/VI1XR7cLLf+XXryxY8hHsshDGVSYt2gLLa8VVFbFqOH3oGN7Ob2BI+fUkHYIMp8i4eDw+dxvnsYPEgx0b6VGjgLolmUHt4aHGUR2n0TGa3bFYPk+p33NABbVe/NpElu6jMkcTo9r3qNftVN1nKQ83szXtax1+xMDu/D9LapbFJ/fMp8ldUKcieN0ftTgEwOX/dwRwrng8dfMwmZ+ZqXtpZz27vjpPrSfUpjZv5yieL5ObNz/LFP2H7WBmTxjcIzL7vzmpcXQfybW8sx1HVzVjRzjs/iOE0ogQFyP/io6PD8opDUmp66yuBNiNrt9iwboJVtsvtyVDpnpqP0b8FCITKA9SCx/pRQ/0eDlCuEaoe08RV+R+wNboFEXN1W6FI/3Mqe8a/rkMWDDnW6asG26HoOHGS41r9j1t/7P5fEORqmxHJ+0FYANGEcusTgd6Z8e6L8xYpTwtdsa1KQ5E0BrbuP+B+koJzT4jMhtx1j/AmWVeo5g/kOTKq5WA84vsg3wev1Jo2AOAOKHZJk6Nom2FoIf3DX4hkyhR45EmnOFG0NZt9hovyDxcItML5brI/jpP8yVLc1yvXI/4DuljACPcqJxgBwkmuXNdgYFysBLBC80lKp832sNH0POQ6pF6lXskJz9cY6aHi63Hou3xc4s7J2x+LmMqHqx2D7CnoGt+jd0iBDfIBLcehR8SzNR8C2KsiM3/VhgN3dJw8etMftfHJgsIMsNJdCK1D3NtuqcSgVnxgbh+Jsn7SPCjk3GsP+TGJ+RYmwIHke5ycBJMbuzlVjF+Gp1if3xdMX6Z8hUfpx7I3r7vCBLS+C8/AP6Fg4yhXGNkzYM+LYCJ/w1CbHv+lvKn68GZ1VrrfE31pl82Z6hpVhzp8KXl3U7ju8v4NL4nPA68+2k3MEy0d809Tquv3xOMfHgM+fexB5lLuXJ6V1f9xVRfxfdPKctTTo8Jg4AcpddMMD53ig28qszk+UCDHa9fbhnqNm1rBUdhtCcclES2gmTQY/H55MGOfxxqxqi7Wso78TDGdAWJMPyG14WUbWp5yvaDlB3wD0szPqRt7OcuceseU4tNtuM6fwutGn62XMRrhB/uxDMGs9PluAfWsq+Yr2+fq1m9PBlm9L4wnb3Xhucxpfg4tMt6nFVeAnQpzpKQkY8s42e/ZEp+kVGb6YMsd5rWmSwqYiN9hZ2xNBrlVQQiINVUwNzNSx7pkiH3cmD/M7eFNRFPwZs7kQeW163TfnhqfX+yPtkM2zrebPVcaey/FvdArCUs4Pia19nh8dfZ0fKL29U5BOckRO03OVUI4LgEyPoooQEOcsMt79kFSW0Ch5EuP771E7ojOW9my62yHqPQtvImbS/mb8ifkB09SX/azZb+4r97NbaaAOf8STRv30ZY2UXOAYHFa+83+1wB3I9E3S+8lQbDiGVGxmFvl5Zue5CG5mFWbnV0kq/opx1/X+FymRhksyPCOSv91xtLaqd/VhdyKVWOEEy1FQyt8rItJwZtL+emf7Vtm3N2ep2jkIHHkx2yZy8+a07o1h2VY3N/VRZA6LXmwAFblw98Pqj2Nf8w983tOGjuctBYzs55brSQkyqESjhKCbSna7FFjU6rzZlgaojeOY9FOA5PJObEWkJd6RYm6eLMP9RcK477N0XYLQF0bZS4w0AcCvb5jjvxi6O+DscgI886thyJ6yhpTSfjhp/SZxe1bR/YiM/SMFFu6uqQn9g/TdaG3bYku3taGFIrWn6aVbCPyG3IRwE/zZC3NkU37FCo+jydZ+Tk3rCNSc732yFhCzmXBBacRPhMftxs6wHdWmYDM8pfibgyOSGm/moGhQZvS4jMWlp8yu3jkxFr8WEB37CEZT05KxYhNldZGt5fdnvwJeygPLucDKF9UJpCfor9SY+cFN9d1wmq7Tt75J+1QiHU2paH2j40zpGY2k1trDUjNB5d5nK8BDRXua0hzgvyDkGWQoc5n7yOcz/huQ8MenZbLDKSdHessXSKIbnWUE8NKi+FTSo7xBmsna4rsRiztn+znyPLSkHcSNBeUw9KZPt+ehnh5CBp0UVlKCO22xKjZI48248PTbMjQm4k6+d6Fg5JCPdfV4yyih8WZ16oxAqlQLHIRTBY9CW0LCzvLN9XwS4kUK0gl/tuH2Pa4FI7u4quHmh0nCOUzwE0Xi/RKteu4jVJoUbej8Hl4MPF/LSmWcpyJiz8OqTkFCcr32TZB+YalbNZ4QGJM4cNvJ0x4wdru6MjYD/9eqQwpTrJ0YHxLeHal2pGSUr3qfix56hw2t9c09L25U1UX70jZZ6I7xYLe2ZK8EaKCvU+LjtnxOkgqKb7PcrxnT1BV5H4BzBFWoCL+VT8iA2DHlXlca8x7qicXBumKFWT6X6PayE+aBQVAPbBcxQlqQb9mczun3/LvtUjgPNqoR0pZMecP6uUlXXoEBWtr5x1SE1+XwMGBLivBestEdtm+ZGaD80MEcmhdOcjDpHpdIVqbmU7sLJ9FxzYH3oHN2d3dDTeOJE/okD8VunQh6lmNiVhw5wD3N75ilWfivDwfiUpOEjJh2bfI/dxfnzj4F/a9rB2/2NbTiyZ209PVGrDjtLMNmxc0ew7tWDkbQrtwroe1A5L79AfKY+yIy7rTDPWSICBM5JAOLjAzQKTmWvO2bE9AJMzeIdckcFbkzUC3XBwugEBkeDcgFXUeCH7FviP6/skILXS8sgoXOQKqTzhwlwYowhThzztXPllcnkRbp/fZu/Jn9AzuYRyhBY4cCLmL8Y6yJk/Khy5NOnlj3ZoCdwSS+C4YO1X5sylMR3REhs8AiSsYOvHYgTS2pWQXzPFiSkv0hIZ/Lc4AiCyBJwlEGYRBpLrT0oCDRvP5WTJPtrWS/Sk4JlWX0nmdk7KzqKcykYeuHckZTKuX7WiF7ZOOFVL97Au/9xB8RbeyTPAc0pjL8W0MsNZizGnFq4aocBNSyp7pds+Ai6abvgFPtXVi5wP9fjaWw+r9f69TA9wAuE4IfflbhtzlZroju4HCshvTdOSf40UBFs7F+SH7Pnu+1wUZ3sBFr0XJ1LzxCcE87TXQ/O5qhv8494HhMyikj8McYABUSk8fgTut9McROgjsJecwmMsmVCJqqs0OQOOo5sUlOPAMreY4m9oYR99+LxOZMxrL5A082iSKwfvz+EdO8s49FImAl0cHua5bIFNvY4e0mUt1dcw5fc1xqGSYh/QScVQn2BKQz2+TwcuvNnv6hj8VSfpXdqE27xyN6UpH6x5WKtry38UJvoqr0iGpJyyISL9tPFAmOMzj01Lm/Of9gyKyyGeVuCJJPmwvSlZDedwGATYVO6oxXmv9K8RptUqxGy83KzIlyBycq/P4Bnu91m1qzE7uUoJ3r5Zn0jPMCYraxQtuyjLXfy7SBlSW0xPrJm+4UsG3QN5nf/y4oMi1E9zFMr6R+3Evoitnm3iqx7EVBvC05WWZVZDCYmCZehkGURJvPJRFtspiMSJw+O/Av9dcIb6eq+WsVT41poG/Fq9Ki0W5xhL7tjej35pDDaNJfLEchgiTDNLwfG5E09LwFCelUsxMnWkMiuLDrgylCxBHAyPplfPp+frHt3cuJz5SXr5m5Gi+dTJDZY4qeUIcBpzBQSZJpRwN5XQZW/n+CUrXD1CiQtcg/KCPdogpskDgCAXY0z78mv/E1khaKDzMPb9ZCKtvmvchn4iVJSemz2Y23eLo+wul0NefqM/UqpC+14PHwiVy6bJSMn3i23QFc2JMW6DJQU3VOGBi/kX05FIiw+Q9gCwH3PLYlDeajJiRz2vBOj6bYTYGhkr6azHHacYHAxO7tEIjyYb0WdZt7ha0tpnGymkNQHauW12aDf4kszuXXB2nr/7x9/Jre34n0kZzP2qQPDx//Ghui6foC+/iUMEybRnIungaIDIlkqLLMP+usW+gnAFlHAxRCSIcv4VOy8wsYwzHyJUzm8w/uBphwfx/4PNXAyfkib46JX2Z2UA/AmmpJ5Rhr3RaCcM7sAqb0VYfE7b1iSsl6T9QN3tVr6Fi867sANOuTkwDvB5YZ2fVtv5eVLcD6ffeWL5Oan5ZWTy8CJNjlbuuIy3cz2CDWuT5hf6E2x7xNByPdROVzVVyUH6A8jhx8gO+2JBx+C/PdAMB4MZ2Jp73D4Qbsd9wiVacpPps6BYEpIDLtzpjOQqzq/XrPiez+wTTsBPMAIyWwB8mdXAuBZu40AkgF+tohYL6aKsDHXmHcBWK/NEP9+nadfdwjZAKRoyhBe7na2mohkLyiJmajbYC4+xXf5IAC9CfSkzn2VlyDlEfrvdICKw4YvRknkGosSn7Z/V4vXPyykAC7qNizyFj2H3AYpaOTmeO1o60bDIyGIIbNsX2+EzOP7xhQaw/I+GKESrUTWHRdUIbk2AKPf0T4V5fWSeE+mNT25jSLOWUCHPi5bDSkIMsbG+QfkTD5Cc27fUhGOWwhqqIiYFHsC/oNMyfBp2zJFHnh+2sdtcg8WI6w/dFrm0uNjLYEZzYzneLOpzDnSV0ohnEhdW9MdRh+zqyq8D+j+mUWr8lmILOxW6hFTjMJJTcUjzr4jwVVLIWb28y3dReA8bFLm43etx7Za/JHuXRosEsPEFr13O1I8Zkpt1oeTzoXksKr/l9DfUOQf+JGlZqnNpP7mnBxCubRv4QxftQn3jE+ezHBpTTjyV26zZfcfvqKsA+nw7zH6DwjGy2ykrP/0rCu/Qk6qjEIPrA4bZNA9dnFPJCggypgSHC1Vt1g/T6p2Cx4+doGcFKmBnzkgEmEiJRaSgiN+KJzd6kY3tG4Z9MdG44vXuFy3/4fErVmKtA8Vp4F3YZ+1xZxIjaPTJ4TgNdPBsRUvbPSWSfNLHKrHiF8RY1tq9xcslB12hyy8EDFWFOMtlGH+QZGXm77MqomdnuzTQ7gggrtDFcddg/BoE41uiqVhQwEeIxieHpYS4wdtXUKZXrR2YG9I5rLtxvNnrSSXAwkf071fzLBCdTmNDYp7s+zTlFTGSD1Nx5zkcTGHf6GH4u1DYGHQvEx5+1AbBO6/M0WTJvXA/Ob0spyc6kL+IQ5LSnxKpBpjUqFThjrEyLdvXI8/S95ufKdG6e54+Q6TSiZ91WA5xKtq/M8LCiQtJ2Fi1IChOAjWp8Zz/OriMQV73HfQrQp619CRxRaEUIwhmBS9GBDxLfP0GjR3mwdepIxMkLGqgfOheOawv3R8nayVKNhLcrsE3tsr5Sy/32oI2IMTdpLfdV/Ij+n9wRZD3/617PdsY0Raf5IeKxfUGoorM0rwDngkniH5jb9igPurMq+QGoHY9Ml8IInfTp/qXzQipfWf4DOfvvbL1+tWzWUNBoJ6W6I91mpJviYBbXOSSS6gWrcx7ZjMplNpWHla/FE9Pq6DAf54J1Qz1FuSnidKRmIxjIFWzGNbawoNlaPcErNxR8lGHaSY2Vn5Y+KEY8XRIZA4f6gNgtJrovNZ5V6qLxv5zRyRYDCz0sYKG6XjZujfmz1i5r6tAGL5XzbXU4xVf0SEus89plveK9Rcf/zeKcYS5Dh0/MejZD6W7lIYNO/ScWCDp7YJbDlKFe52Z5Er+eudBclceiOeNp29T9Lad3hjIEwJ25+1ypMijWm5ac/QYH2+fnQChQjYBOGFsINQODk3e4IHtZKeiYJQ+4w6AzxXppHHptNTAAtHSj581MGJHDP0t9CYuQvWKE+iZUuzXihRO1vC+tftwzBVsWaRWd5RhSlabM6s3z/B+JldlhYrL+/omV/fiB/WHzKdIfdA8Bp8QC/Va2VY0WK9g85u0+XzJ1Om9PfKqu3yaaAyOr0k0eDj0i3Yq0CSk+tHqRc1onSKckJhf7BYozXsLiTy3ba7EZEl3VX0fGmVTuikzOs4lSRwkYxcWEx7O9AtCcqcGLXM0qOL5waxe4Yu79ox86jy/5+E2kB9zbbfyyiudUB8Z10mHusWklb3lyF979Kbx5hvtWkQ5EwTr3Bsml/VyASyhy7cm8v4RPrWHrLHtWkHypV/fbxUt7MHej6HEz1Pu6NDr+4583FNtUoPHfUABiu8uSxxevyfRf4AUNvxOfQhDRw3lKeHhH06zreogG17eiCW+I4oJS1i3CGQCFPdps3UJ3E9148+Twnv9X88kfX7nwAaKarVPNMylwQNpdhwhkL4D9UH1EUq3CfmwbvxZwg8D9jYKQIQOnO+HPyv99bOl32P8YAvBh/GOFgCLkpiE6MPlHyCYUZKndMvlLItreC86U87b6FNV4YgCupJkmSErkBQj0QWffdPlfyIXbIvKsYo5HvOwctYFvRVly27BbTHbyfX9MHc3y3jFjF9C3kAL9g9hKouYylE55XW4qOIEh11Vjm3WPV2ld/r0NHpb8KTo4mAK9bWS2E5rTC0xsYgqbbmlKFZpGkDWuDPv8JjXHr4mrP6I6ZtDevilH/k0qCRcekUPzmoHeRLu5biBXSnbHVZNlK07q4HGKPkERc06kLST608XoYIvCVdG281X+3R57Yrijof4YYFlMTaZ9qsThQMLgXvaxxBczA4/pZd7o7oiztGUymCKPnw3KFNnnJwGCMTNqIPx553jl3GF7xinduL6irqQAHdA7WbsjyAwOxqXE9B73VbazfgLXNnP+c2KQzn4X+bR9//AHtbW/6eQyExI9DfoYRFnF/+MafVlLYo68hhdCc6R+FA2yaEDhjiymWGPhW6uRlRhuNvsuqFuPxARovTQDIQnvnMldiVMhbZgkkvZF1gCEL0z0iux3OEVvoCMreat2ptNjARHr0ua4n6NQ75XFFDnXR6qgRCrcSORyibdLvnK+ABsvZEYnY200Eg79UY6rjca4NH3N1aYlMtGLw7HpDa7KN2h7z/0iP1KnHLIzV7PeOxuYkSEFgambOGlfK8hqOa+7moUW4O7xBl62cLthhd+KkwMhsZMLe/J3jSgdTqEbtqSAGHyw6EgrtljBfLYCVh39LS+1wP7U7uYIGCFgrsLgPtxrDUyVNRy9MWNfDfLpuzatXjqk0PxKqz6HSn1WbR9mkX7TXsN1iSusnP9ytL3qY9R9H3JYShWFGpz/XjwARDbNXxhAoidKaiRW1wNw6OlwTwOmpNEI9ArNx2O1ifUhP3vHzA+2dD0Mxc8M0OdDv8OHwk+Au9q1SGHT87jeuIHvACz0amgsWoy3RBVbG7WEeYKfTstyv4YDxIQOb9Sfz3G5xzfem3T18KQTY5v+53NMW3r3fSquDWa7LmvreRpYZZVGAUhI5MWcxGQTv2SfF36P38TAAAWx3++/TIyfPzx3bp8hPPi4xaCG3h2/FidjqED/Cj6hZvF8waWx2/aLa4aJc9WHhh1Wi5Mf1w+smnIQY/6zw/ryy+J8gjr2ZcUVGHVyK0e/GIJqttn2JoBlAEwPR3+zKgBIAwpCWFOxHXoIGLmVXx5hCkHbEWUcD8Kk91wizl6YcmR8qkMthOollB9BoAzNtIw6YHmAYMj8OEAjo7AH0fh7/8HTwn3S/WCmAObWmzaxfDg/LETVxuXbYStgiIbNiNMrnw9KSwX4RSxtRYdWNAA7g0FBTbY1Cebhr0HBZJvN4loKeG44+sKBK8IynA8IxrDzScVoIYZKIm3Dl40uhURVjM4j2HIAJJQWVgHF+YtXK3QSpgqA+xIhYEchBxHwXYiTEm8evF7EFQIlqpRAXSABEetYKgcj4QpOz8BNE8wJWxguLHQQAEL8UsFIMCNhSrEJGCz+iRsiQHsDSz+xOclkrfXGkAIY/efxi/r1oAbcCrPmn6i7pNyFNYjUa3sMR+o+8s8COupjyiyj9yjLjKvhI1lwEobeI+6XyqEjfIdRA5q7qi7YUc5RHtC3VQVhE3HJYocgzWoE6pO8DnfWNHIDK8YdY75VvBb/kaRVTQ31OWUXvAdf7FSB/OLupIyF3xkVCtPaiLqFsyTgk/8w4rHfKNuxXxSaHK+sOIjzzSKia5hrkKzpQpugyJrzBfqdswHoRm4BJFNTB1qOyoV3twrZVJ4K14pp4W3x1fKSTGbIFgr5vf+xLGSc/BK87E/Tm77Hv2B5ngsm+tpaN2u6dctu0HedLZl10offMNOpYu+ZmflPrKBY0t3Les5qkwje+GI3LbswCHSTcv2bL3cRLbl0NJ1yxoOKpPMag5WJrIl7VR+NatoR/JDfwCa682y6OKmW5X3aZ3HkLJbaigoiQmHiB6nWQOJpNOEopDj8rgNOKY5LFBkoTYZKKLgOiYx1dFgN1Coxw/Tjq4WZQNFz4gGOLZjAyOwHQ29F8io0YHYrbljCUUzoj5SILK4Ne8J173cmcm+7/cOdTQX64xK38Pet4Kcogw5o6RuRE4PegVHj212FKjw1hvEcdyzwyY8w26gg1nj6BAMzYguI3nU6BA2UFU3xaZxsQMZ9AruLWyS6BBYll+mdkZRBAUUrWgakxICNgkUASvFkBoFHMU6gw1kycd03kChnlZgEEv5smiO5EXYJBC14USExgGrsw4rWAZF49FcOmdMZlH6/c7jcUxhL5BBzUEUcgWHIkbk+2jIaZloAr8oVo0s6VlChBHK/nI2XS/nFj47ElLhbZcqNaKsPZJWlMHbaPJmCYmjbZ8uP6UKqV18tENm+m+kWUI7SChDAXu/KXqg9QZFduT4o93tnDgEAwme7AqeFIywT9B6Qwizo8HtQgE7UDO3QMUS3taIwpnLPMUte1GSb4tiaG7hpGBR2ArHDgaO6SBoXi9C7Y842VUdinKV4SrNSmnPNbhtDHuZ2XOiaFhAKLwF8yqJVQEKNvzeyI3tOUjgWcoFfKHmELneapZwGF2MRZQON8XjqfQDnIktc4OatlJycoGusNelsztcnR8ZWhvYX8+ZvHinCQuUyQ9NI3aiWHWyM2a7TfXBLQdHP1PE/xTvfxzoDH7XX5P75HGC3Zuclqfgp+hmJjsULbtSKNiUInQiE4iv96W3EtrccrNfBlzBsTSQLEKyEoVDSKXRmrEB1YLvt8h5kjoeOfDYmiZaIjJ8tfulYCPPwA6qPCsb4Pjas3PgBtsWRwPGPNS8hNuG5SqjYOlxjQkKKReLxWo+hsMkbt2wdL0m/vF0+04p38StdUa9vcDlDl85Aq/jwpCvcQgpvH3JpSslvtt7JHA7IuM/80gWOgigiJK8nO4Tk+vxpIdDGtfghWC57ap80O6YPb5bVCYqYCH9KyIO68o9+CChbIcspqQWnIyyAoAm9DQo2iC/5CQQORgqwdPb2VDJOtq/v4mwQc4oRsQCCpmFvZDOodL5QnYv9bXpkcBkEpmZk0FkeT2kdyzlCxnoqhHdxuTFCinaR9NMgPVYDWs6UlTHbzV2kAjwA0aBNrGC4KDQxMMp7yvrf97icRqRuDDwo1MDh9+FIKG7gdlAHkIPBRwJrNCjA/duBhTVl8Xc0QGK+J1ice1jCSxQiITU/DcwG1YLqlIFa2GChog7DGyv/QLgG/DnMr5PI6gaj2NSrfy8gL9KbRYTtQs1FK10lcwiJSBLBwYbOmE6puS1A1oo1JG8DB2Yx5t0HVmgDVSHsxQ2WOM6IieQzfhIWVxwlblZLZFzsPpJb16PKX8mbrzhXjzh6eaINZ0tqqNGHKexYV8k0nOOZU8xNTCcQSROyoikKwvSMwKHKrtbssxE4WBl/h5IferkOE36UFDAf40tQY8OOiUCfk5g3rDmsRuQ+zA+OwpUs0BhZgB4kYXsaezL9N9Bgjl2wNoEoE49FOigwAUQMQfsoCIYtgaY+Lk55wvG69UPiNh+Wp8BTFTA8hC4kXc62nVfJbYFRbIY+45q9987cYjUVTmNymnLrNZXrJ9Xjos2Umq34H26JYvIPNK9mez39WUZ+7NFMB1EHObKNmPwtuh57u13b9g+pgn08dXJ6MzheqPGEiR0IsPvt2t5H3NyEfn553vRWnToQaJgqrChisxJYOB4ZI4EPlQyIwIFnY+D0H4aFCTx+k201JnXfSFLPJw0jNsARTUbxNEVGDsyPo5QQLfA5mkHAro+A5w6YX7JlE3P9PZl2hGu0wDvASQeqCWlBOxjPZFhvt2dOf4w2rvjNkSpYgLiWoAjXsMRcEEDUzMTxkNkKDBBBAn6VSWTeccb4vQjjwGfyE4ULnWzazSVIb/xSFQLYy/oQQcJtEtO9LVIiKaEDsYJNGu6E0wgMJH8Z+MRi5NBQeBOJMNgZoRcjq3jqFwSjUrwhSQSztPlmmJyNoVCpDmcNLZbqluebxP7a2nT61QsGy5pakZTc/rTNf55J956urdhEV8V2kDFXvurYfqwmHskZRRgOvAGauZ0onCUEOcMHSOh6W5IqZm2GXPm9tSI+87vGeXcO9wMmnCGUykXHXfDwSTRkEy7fQKTYBBTaFxPs1hdiBU4pIR4yrQRTaHOLP1Y1jrYRMBdnA5aiGAwkATc+FtDwNrE11UWBuz98VMVCvCpOCUSckzU3kc5/GxVyQhGuPgpY+KdXjy/GEnAcupAJ3YzgnWfrhbh0FjiKHjfMgPs9VtmAB6BSTEJLlwBnYSOxTxKljq5+ErtRFXEwTtJTLikjIfSCvF2bw8TjuVDmd6lHrEAFiiKmOGCWztD+xRTY0Bg1BMmPRFkzUwgfZCLRydZc1HWr0MFFLPApzKUGl9RXvYcxNd9Kjk78CNn3EEC/p+lw19uhperKV3M3DO1W7lQYhtYHaJJFwzRrQu0Yk4Zna2NxzhnYNB2T5ERz5jKc5Gkeixmng1yEklHE2P/CznvQEtQMC/ihjLwu0WDjYyemSAKMz8JGaC1urQcA7yF2gqys4kvKy+5ydgEY/TUphH7Q4eFiQ1AOZBoL4BPjBUUPlxpK8/oSOzxVm5LgR1qynwNYfV0gd7YyqWalJCRMhHIJdEuxnXtzLg6ZqPYDIaNqvSwi2oi1Czp/12Dh+eRRVs+mZh6hPyhhBQaFwbtK3FA6omh6CwLInC4KXNTQKGk7AxgOG/iPd2PqnzBaWu2emBxmzwXZT408z209V0MHTuZHvhcP3jH6wqjqhvDEZ/s46YCPmjTEw+Vk9vNeffuuy/osb2GQPD1yk66m2zg0oz26Y6EYzuNcq2j1jww2vD3rBi6RkhJ7m3UyC9tqzhNSULYMWoM4pS143DhnY1cEjCW1xBrJips2OgE9lANhmA1GRicW0OPXfp3Q7uNmW+/oZ083nW7ILybRuqKfSEDbPYsR1NA0+lcC4PaNLyOhuP7910L7fkoIsIaibFLS8NeFv+ZP/smv65CEuOvXaY+0OAairaId+urAulDUbkZTvk4wqAyFIzhTUB2nmbntc6Syx+LxWIh0dxRVUNG+Bj9Zeu1UIVMwCrRAfb6UMaEi8h2SNyOEeytMpyrybA4t5fzfMcvV9M4hhSGgFaJbeq4KIPd8YjhpSRATRuHC8GI+ye8lbpEngHEcGzxi3IAqa3EVnGkdY5Qo3llIS6qQl7i9AcWUL4qhgqz+8uMjFeh4Mlqm0qJxC2CYsY8+sFap0L+EY1HJqhV/blAF80xECnMYc+KWdLPZ5Uy0Ye0RhfEAgonK4eJJKqgXs+yhdDnLaMzuvicyNLnitc+GlRn6xAiK4r8AGKZugPI/Y1vzISvK+c2aOZ50dS+MmFOtTAk28aIfmRo/UI5ne2a/vkYwpAtWCvi/VSAI37tz3Kes3z11IyR7pCxK/tziodr2UyhFd8+Rg8oIo/TmMn4OxfxWtGSPZx8rrDL0l4XF+CDvNYWjGAQqZtxJJQ7RlDAUXD7xzadw55o4tJw+gATMv5cRvXYtWv7zxE/psinSlzqJFgk4pgq/GSpJ/KRCeW+6/mw2EGknNrRBhBfM5fWRtyK0oNMqb9czk8etTJ50RGKTHYlw37IwkY1VrAgOt/KEYKK2ptz7ELhcKkrA4e5oEm5odFU9MKyV0UNME1tzSJ7IYf0fXOgqS83m1ITdA//0q/kt4L3i5btIFBU4tIT6U5/HNKdwV22Y8ppzig4w8lLTDmkcdpQwBY4Kd0EKuloaUrNBp0QZSr6HsECjoTzNAUs2nG1BRJG62zINWStGFu5R9R4Os5DDYjx+I1nMji39oCFvHQXeohB5ugjAEdCwcR74njoYxVtGH6r4GDdx0WcQxA8qiCwbZHlC4cqIBuHCkNZZAWda88Wa0ehM+A0QbOn7pdai02FYUZpQqswwKQcrgTX+0WRcFDjdEk07grbBTBqROa8sN99L0LRw0AmapcQxprB4MW0uYORyIHBO5JwJ1Jzu7Cbl4ii4BWvr2Oyv7+KJPzz8XBOg9iHfGcKozekKxOvfQ6W/RskTeLDvUEc1+bosrMpCU/0KMDK56+3k1L7bS7rdGzA6iyg9XYwHBxCK8IAKZc2ooJW6+Ba0rrkv8S1IQoGNPm4HMvKOoRhoKZUoaZbPeKt6S1jpe5XqLXd3Jupq3NJoEZVj85MLCBBkXn6LEhuI4DUJIkB3E520dvsitil4Xg/5OQEOQpMXP6HK9Dr2q+U/I/bU2QmfNt9sQVLOslmCJPFI7y9XFHXfzosdhFsxenVtKb0u6fA7ATdHOcSj+FtO2u5yosqB0J7y6+Am7sTMcTFg7eVyv68U1UY2z2NRNRUO2TaMsMuQw2qzTwfgA26QvHcf/owtc1RQZBlOp+X4ERMVJdYN6EDDD26OsSAg+oEuCMwwf6oyddXjvTZIpzG0AaLgF2LnKa8hepJXh8KOdkGyRI+gVmX59QME+hrkcAQ3BGYZoe6IUoSYGJzJ4UJaJISeC0c5ZjdQM3jARLdq0fHEZjoDo5OFpKWVjoUIme9BEuHv9BW78WLhsZkuA0rwGa8kgZG95gsu2RGGJlaZylcOAAXf7P6WSffE+wwlTACkBY3F+GSoAuBo1LbvLyeEmkaGrgIXKFkBCxQ8jZPzkcwpPM9ygRDKWbCXf/F/xdn3YiSIw2WIomECMK3palBsWSNUVVKkzs/DUxtCMwHGNpk2Dar7U5P+IgqjN5va9U8mhHpQjIGZ2/7glSOmRcb+MkSYRWN4EMsP4bb/zbCfCN5TAzJkhySPAfG/f+nvjXELPS8GMC7yLMyLc4P4E8SmA7Vbu+Vx/ug3InjdG2CHQ+apswk53QDSdRRSkLTdZqSt8lHqMkoZIGQPchl0zaak6EeeIZnlALu1wt8aEhJGqVNE/cQl+Eh47YEubaX8moy6nRJtyGbIOniCvl/E+9WlQwNn9SqlM6jMnbpGeMmMpM7JcHlfc+Nl+1EpEkKqig7nxGvYU7IkAEOMtgHo4G1Xd8FBTyQbNA1WV2D1yvQSI1V+H0M09CZHRiP0JijAqKPCrRXpnXt+XIKmzSclxjn+XeqXTrQwMHyp4m6A7TBTPU14hB7cVy6comrj4yAed8EZtWzKZ4WXK0kL8SZq6/NlyvJ60rowN3TceaIQizNMlno6mQQvaqwl0DTOAkemNWExmsveKMlxSQVhYMkdgFJqgyTxzdr4lzcO1Cq0lLnYpWsbpyKejLMVYI3ZWWDoRf0W4jwJnUXUxu4zf49lZyxLi2RdPRQUkx0FYWxtrifQns1dejBmdwYgmHrbibF24rdUl8xbRY1Ue1/x2UhVw87/3ip0eFtGSlgx9weUdDNgBHfABKwHHGkNDHjEcRXClyENhoaj/3duZkADpcMrb9hsxKiggIXBMdX4mMQNubn3dfHeDXudABrm/LeUocuDSPAbdPdEMliLx4r3XUMEu4+7bIX9yT3E3rxEh4d4NUisGxhkaRpGoUJLCBX9w7hvC/fU0yufXw2FqejpAICSqYOVivi5zpciUL9DQzAMi6AqVgGQdeGGAgr11G8hvNYmtfc3ZmFl9mKpNMTB8VPLyJgRVmhnrLN6NjDfU5PXkKLY0RjwSHukucxgnodrRgy/VjSTApc8haChvWWTxnhqF48kw7vykkj2pOEyfFXd1h2hKmT/TkacOOceElzyOuKSb+t6u/3jnb3vHTf4hrDU0R1aNZ+zTPnYGRigboODlRYU1zbbz49eMV7SItPoA7VmRgFA/7g96BlXoR7KzO9Z7fFdHmAjuzhkROCd7bhTWZ6T27/exV6h+TNlnu/3LszxR0ZfuDMfKTcrRJWmKjdZp9elQ8S4j6RCbO2RtbZVzNVFc1VnVl0/Gf6g98V0WURyeutoeBJ9s29kMcMDdQxmoVz1fgyL1zkqPGuD0U0xCRm3YifHVXdPl3U2hbbhei1dHOgEs6DA7co5bg5TTX3gILkgW9f6nTmputILrBfuAR9ZSqPEv4Fg9+Zt64KSUz+Tk0ZsDe+7NMGA8kHf35ZPBCsyfBByI2aSslmlAB7t3hDUQn3Wzzx+aZzFHCyqgIuzdZ89y79HN/iCUmFWpNKu+9osVgN7TbcG77cc8OdsHgTtoYzaTKXI2/rLFSyDh961SdXDanV1SIUF8P3wMJz2K88mdXOhqB4KS316ICLCB/KN37x4ct0ryxvCBHaP86Mg65O6sQEM1Jnz/VSPNU+zKMU/DaoN3hJT5PCiIlaXxldIkqCT12wGaUxKkTGVMrgA6rPg47aGfIPaboyeJY4eWDcdSHWexYp9zab/iBiwkl/VH6tvuwBf/3l/8NkJg6Ojv6Q9cK7YR1LVdqnL/F2g1CwZ1jUjpz2W51Lw+oexKeZqgztsoRw4j5sfYU9h/e5vzS4r0KBNBBISdBrNIwujKr0BdMBKKbBJxyW3T5d2vX/a+Xj+BoG57TBYupxZXT2QM8y2VXl1Ex8FyPevAjUGtfdIB1LGPNearmANVYDyTFzg7t0yhfON5EZLg1zDgmqdmwCNg81jkQ7k4+363tJOPPPL3h9pM7AmvHTPt8QKJCOi7rJKO/em0kRiGMd4JCUJn+Ri0gI7KWww/6h4YG1Xj6/TIzucr/ZHhfdSst9l3ca8XO4it+uwAe1+Ds0sJPjTxH/XhTKFTV16Fusaq6qfQ9VCiKd9F7vh4sc7OXK3dD9fTfqWvYwdzknUWj7gqYagFvHRqpcYwE5+atVIunpOfKfuGHq0EMUp8qSW0MreD1fbDAHH8NJbnJkYIedb4oTWXyZvvE+aoD+edIlj+RJpI+hdbT9qxkaPloIpxBboPO9EIoxp0saI9oWEPnXkVw6Cl4I5vSs3lgLdN7vfAx2B8ARAXEJQZvyZYny9DJlNiS2gCKeP/aaVWcHoy/C02472MoX9x/+Okh8K7Am3oDcGhYlN74+ttKL5k/6P//tAx1xsP67LdQckyVRAiiVKUvAy/dJbgO84qtERNtVJJhRu+PV7p7+2ITUjX8/TL1ZyiQAju2/dVTp3Qwo2fUQUuvCqDcEVqd4msLbZ7i9imL+YF1eGFpGo0RpqnZL/e0mWF6Ux2U4PDg9S95DoSgv4wiM4jNDCE3Q+h2o/3S/x19nGzInlWbjeAZHoXrXdf07SmoqgCHHV/emXe4p8r/DmDMTqrNIb9jL4zJ36BHPW8mKvcjLeBqsdS3kaWTTYyLPcMQ+qH79EQ/l+53gushqLFpXimMQnjH81J37w9LoUShoZUTuLh9guo5yYpbnES3HNWn3YyAYjDx+4N81HBblGCHcrg9GVWq0Ue3ySd6Mhv8yGYte1bnc83bEtDZQsivQNbacBIMWG2XxBsmIb/EL0rgCtGOwOvGxJbBmealQ5NbyNYmeC3Q0bRT2oQpndKpPNLI+kPnCIDv9tDZPHIUw9zuGcuhFj0xIZSgAsMYXD2CcoSOO0H6HJO2GNY2uz/0H/wKUXI5WEL3wb40NiGPqNdTzC/6ERhH5+gUD8br/xNJDXDitb6iQnMtd6usqktrmNB3AwQ81+5AICD62rSY5mw5H4/dh/zzReoX7J8SOj8P2o0C9F685cLFxtDgUdDTa+0/DmzHAtorWNTAwTzKk7WEYkE5YTsbqEEHrmV0CNmpcp/klD7C5BkIyTqVEgwFp/bkQlv1QeDup9DL2HVBNYoIlbDA9N4DtL1ihB5mIdZmBpImE6Yo18SVQHFhDX2DZXqtRwAIB3ebd2yFhQ/uQqBYPLvb5+E3pv+L06PiePteOBlvT9MwzJEsWcwiGbmXeKl6mc/hCDnP9FCMzrLsbTA8NPBgB3OasoXnNvw/2g6n16/MxcOI7GEMZIaxLmzziI0QwPGDwbiwBag6HHxOKWIyi9sVV7v4w3QGkNuMnAZcBHm2Qn0BXxTtzUzwg7P91jsiXE/LGhKyq1/hI7f7UnO6n01+LcndrYaWcTdsKiQtTOlo7ogADgiKKU4y2oelxhZQyiokaco0NuFaxJ0mPNVFCVXwZ8cfqFVaHUdtnhcK2z8G482jlkr8eoqxjhmwEQ7h6fo1ssPvNwHhasrsBpAC8HXIV5tVbilbh4o+UU3mu9wPOwg5HeeJtRoE4XadpA6zYmgoEA976QmCpVPUnhOnEbsTdTJ+KxSAWF93dWUXBfEaoFZIKKnMr4rDFC7yLXlE1jATdsWlDbgpJ13VolELJRvBHo7/vENEfrPX1gcq5KdsM7nf1mPdOlEK3OUQG61zDG3+Mfg+UK7NuY5lAw2p+DbcxXwM5O2hlSJxhLz5dTeiIH+W6WEj9WbLGJyti+WThuVmniFesEJ9Gsrr2qrZiBC3oWQQBU9pPoDS4RAS0cKgtcU0uzqfzRyUIPFnTFuKZNmF/mZtE/H6hnIYMvqFOf8kuRQitcw+Z7stV4uqlQ2rKF64sZ82lkzc2ibx+lMXQxE/dFP20ad+U/Fjy4pb7lFLOkkF434Q0vdRFKdqvaehvppY+MIFux69hId7+l5GQKWBRIU4L8jU+PMlCig+KE0t6g/E9ZxyzNH1d1efttKR5WtR25jWIltygj3AIxFhXTkSzyhAx5A6/9ry7nKljKugOJhhfBePtWHqMV5UvyJJbMzg08vJDiO/D1p5A7n5NrCvcLNeef1s1+8GfjJCdtb56Li/RP/c313v0Z+kizwkpuc5nWypuGvOeu7tAVIzCsMa6BGBmhTPi5Ql4gDVSNfjDmtKKCSkMLPKdTY3FIeJAr8XhwudlbuYQXm4O/VX2YmVj0WSAUqofTcP3Tt8BlHjbn1XXs3VT6NT+ZhOroKNNeQQNUfJj3I5yf2XkAJLU1wT2I3BSXkP04xF4xucPRFb1ylsc4eFmtPfPL+I4XcCAWAsO8w3sywbXfsJFUgZp7sG1w4Jo1s/PQlcmXO0IaIXwtJKal7lDt+DrKhocyEDs9bB6S87G8R0n5VGnDL2eZqxAPKCHqQdZ97IJLxxxDziy3kD+Yo521f88Nny3Jq7XDlbK1mV+bJOUmVk3MKfVShEWA2NbzoFsCQM7Xh/+NbQMvcLlmnZO/HR1E0ILqRCMpYyxCY5j3bq8LECvIXnvSMqGxuSBXNlPzfVi5NYrh4gDI4kMtNNWECHzJVVxVgpXRpNtFS2UUcGdezKWe73XV/Ikukp3B5XhMLAFo8XmTUfKacLnqR5/QddyKoC3tXQ3MH9D7dABeTDaHY2HUVLGIrMrul540t2yL4uFgDXRod6yo1Y3eEpkhbgWJRGnHCMrrOD4lYsvaWpJ1GZ/inzMvynQrDvMuC1BbEHt4IE8dljUmtFTCyjyBagkwF3TDlSGQgxLB0bcEqGBQ2GPaSepN3RVmk7uPsCbr3aIzpUOcBmg4kl6SYTjD1HF8KC9SmOKSL7urfm2QhvYhYvxKPOepdPRyY2vgh74td/10A4Ky+atn3LUdcbk3FkUu6H7AbtgQkLk68MmMDml2fbLQHLHu4CS4L+9jz0KtCXqKCdIEkHl2PJ09XFl1uwM62YfU5okzDuv1TzcNWpsof2ivMuBWFPpRBSvJNZtsgyKaH/Q6PLUtSBZvh33hJ11UFEfCBunZ17RbqU07GU6tD08b62J4WXQ6wQB5u3DTPJk450gV8ncJ2vBgjinoR2T1AC/qFlrCZHl1fBOhcvS2/e6lRykb8M+kaGubWpkMPHa/FxtP82fVsCVHUPLIBFi61AXK9PyVErE0j6vVq/Jk7L0hOPfAaGqvJwtcmuwrWIZxQwtekRSnVmous5ZqkLtWcCaUMCZUO7TLN7WTgSd1OoKtlBXrfJ5DvOS7Tpyg6ZY9Wo13lPFSgwRvN2uiStmgRERKPWKV4cUrsO/Bf92lc8XerqL4uFmHT11L7iaToPVbqfpDe8V3Wakrn0a77tCcPXLZtQkgXMs28GIgcp332X0bixS5IxXlWl1NZPjezjL8x2tGyUuk+gUbcTXz8bLVmDlgqVNjFmsAH2FXlAoVGhRt6LoNJDMrnVKOjbicZwIRlKixCPhYj8kOqTLJmqmNS25RZYnTNFUML8SmDVirwujeff8Bxlx5ezQy29iElhoH+cUh4pVQxe1kKO4hjrMwstVhiiLkFwyUpgbtQRmOtdyVRmlV/zc+ijQuedFj2DbMp+Mpwckx9rbeZEP/l3JCXidOvBbYEoWAJJm+6InPgjJcQ+a+38VWHVjMJF4frEx4EfoFjmymAdXWLZyB4h3KCibi6mfy/JP+yVSyVwFLWqK6PIacwblmc0loE7yOeDu4BsjvD2yN6GptErEafse747bwEdgAzWbE0LTaVewUqIzlaKhSKREo9KWlxJXDZtKkWXr1GCvq6YIUEi10BGUKMcFHheJG5uybvHTlWH1gE93iH7DbpwcQiXg91fk7UXVgFBFJmgmBLjMU7QUwzLlgaZO9ulm2KVF81E4dLdp35T/q/0Yie0SBQ8jNEBKPmceGUx3pWt4s83HN73HUhhpzwI417v+kb9eiTguXT6KYcbc4aOTKvXv/XE3btZ2bxXvd2vzpPie/P2GAqa0PEprox0EuqaaXKfTF1fC296yyoN9WUhcWbwKLP19tQSac0DiVFUnZqNixFxYq10k4QdbiQ8QiDoHECMma8ydJtZynRgCT17S6KHaXrvhWy3o0S0MO8dJE7DdjwqqIBx+30D1VeTM2yo5dIIkbscLUA85YREgbvuqBNpSNnYotdbR2TfIOeJkQNhfeSo67Ew5LVdEvL7EgaWlsxRAhdc+yb3fO8oy1i4y5LTiWUOw+1gZ7RSeLvHfTxuOBVoDzwWkSHR5ZUankyhhUVdHkg5YQ6fktNHGeXXjqb6xY6ddRAGG9IyktObHBiDKtCI5jj3F2FpnXtcF42FwxTkgoORq2hn+dERNESdsSzrqvf7YEbjnncr8iQV5pZaqxpX9+2EqGyT50tx2UQLTOoBH5RxCzKlbCSaKyzHdaZw7rT8pRXa0yxM+HdzHi0tNdYZXf9qm7u8itPoo/9XNc4XfCO8DyH/BtJ9RDNisDB4vQC1zUJsstgpAzZJsV6FOI3AsS2djx+GmkWpc4fZpziAVbx+ndcdmdM71eY/CXpwK7cdKYGA3Q2wP7RNnEIuarw7AoUPcTKTVNkMm2sORoosCqVAa5JhbNmJE29ViEc36mN/yZZwcr71lhehmcOJcu8MCrMtvRhJ4bwJTOIMvbqeMiLHztSefxmf8RAi4CM13WQAGbwmqXXPpAVzhJfUw6VH2Cfs7IB0cIW11p/UAK6LWU/PhbNq7mORoqzM18pTXo/ITPkQRrJ3M1mquwqB5xZnWkpc+9RR0IOVDBRB0q4q0aMFxqYf77REDLl8isCeDhKe22p+EFUuHlKzUxtT0yUAg8l7n1E1TdOiXw4thisTisZoRARKX1xJ5t1U6Qrxe2Md8jwVLd18IzForaOEjBzVE6O/nnKNyZf3CBB/g/60z8YhJHSeW8o2toFBDV73lXHB1eRbtURBO8zkNhQhGALqcKqzjXVsGTwnONj25RtrnWZBkiZv3VFSvMK5bq1OC+WwovUvqkucjJyhEnt7Wu0u3dSk5JUbeXWtAW4doLXrb223RnJha7yB2KBdeBRszL1LLDa5chz82SpFHvoiYWZouZlbgRO/vDfMkEO7s83EXE5Y46N9B8mTXcfwPD7RykvvDNqc+j1ZznP+eXWy7Pp/qK6nK5OA27lxv2ygOIqXipnH3k8Mun3IoCd9tdaKrcY4Tk+ACca/PV2AJR5Z637O81UReaj+rN8TRNMqWmCqHd+hXZ5QpY4714Co7TWoJkkNS+eKEomP++WgEVbnDdPAL0zJPQkrM7EVNsBeo08HEyaVkMdWZ+tcmV8NhTjFLS7y8zWFis+gJ42DLU6wLtVAaLurY3o4D1CEP5mQgQdqJRzG7WJEOpPak3AhRH1wOQaoUHJO/TTi7GAhHeFucDpHtO4jmw0Cw0SGLdYzfhUdpqNyqdR9+IZ508bUmvJ3l7U9IIJuqrM24VkGIPB/35fwWgdS49ACB7S82RcEnlG5JJmCVXOa+tM4R0aJi79IR3nSFHuHUKtV9cSq801PvBgYxjO3K5PV4ovBqYYTJajC3TSdM4G3kA9c7aU13OROU7jiqkii3qA+vDhYCuHs03FB9Oq8aFXY4RaNsAtpiQM63J1+BqBkLPZwxJJKjzvTORoZeXEMvbmFBVEpmOMaMuGWCl3MmS/wujKiarymZyumtHDN2ZZxBZMk1npqmfEHglRrypDC47q4vaszgdAQmF7FywEdOpqieRNgOeLOeZgI2sPz9Db16OlIsMP3d2VklEP4nkdcwqw1am9sZgj7z0Rt0fXjHWyuQuDo98cXvZI25N1c2MOUIjkl0obrOqmoitjkt1z+TEq5NNprcQqArAA8MxaMotO5Gk2MseO6jqelaIbld5pWwF9iUWTUr7t8kyWLOWObltdFmSAdNtmRMFII2BilG2TNBe+VuGxoPHVo7NxPJIUXf12blQqQeOzAkfPDpB0mDhUMRQum3e5YMv9XdDOFfA8GyxUFslSNQykJhnXhjwdYpWz6qXNifNTwGEfcMTnJQxOsrwbiprKjVRKTfx7lY9+nl7I2SeJgbELOHIKidHq6ar+qDPoyO85iF1nuYcBFrogH6GV7S0j0sLfynM/7J/oBEHNP9YS6eFd+ABMJP0x1heSFhab1JhNkn+bk0PXgJkIsXiTF7Rstx9N3QceV27Tq0DdqzgbU/ZlqGQR4r3UT36R+u9X+wK8EaDe1iqg9/Q4D0PsZC45spIjDhLthc5BpOIADBA+xbvPDHcd+W7kHnGsYGjExNcy6xCXAjf31qcaQV63O5QNZDYvQoY9Qm72hZDszMg3NuSccQpD5O8+MArNRAzq9PoA0Ls2pjsbp5xsRLHRvl/ZKABEWWwjyxhZKgfUUtwZ+RvFXXGnZWq0pLx7b26Kx2UGoXTGa5TzLm3u0ywyqFljh15NdqwsWjijeVwVw5+Yg7cz/jCxSr1BhOqk/vtOGoLgRDsYQxbB35ocGILLmgrsOj61UkWlefK+kObgyJLATrdSFnDdIOUWzJF9ND+OJz5bZAGNw8R3cnGwbr1zGpCUjy1M7lEoPROZwim/oCdqQ6OQLQ/TDshAscPZanOTsxsJzVtdh4VC+cANFZ7JmWZraAHQcnVzwGUEh1P9/vxmalnDzeHCasboX+Wt/hU5sfr+aJ03XEikpoP/gLQF13JHGBoMBr2KQzqnbDhqwfzuMi9DoqGyc6nb8PH+O4EfgaU35oLc/mJHZvt6FMIxXh4GzdJRgWfS70wiXnAiMvKoql31BiuWAVRYP8QRxP86KmxRXC04Z756rPRfUBYxQJLrlPS4/WMLw4Dv1kCK55kKd0rMcks4qfqP9hsCxJewbfFCkJ9W+K8U/BreJEE0kJb9NgN6tUm9qTvB5RtbJKfSjPd8BqOvwzNUlQX4JlEIitb+e0L0CIL2R9i/nQwW6M13j/Y0tRktVV69hnp43HyfPuirTegOEfDRLmQLmz/gf3Du5FYZFYQBLz/UJxoZJJtyyBvbtuv/Z+vP1pmZPMy9+x8tBq38vWbkJYxIL/uP8RmZCYVL7akmLkp8e6dMf38g2DOVGOg+duzNOe/vhSBxWqBfSI8tEycHffF3HkBpUKGfFkXSMOX5HcfIaYwpruBeDx05fgAkCeR+yGOaVW8BVPFulxQVB00rk+Q9bZtuahs2FTx8VuZ8gwropskDRd6saYQQhtkaAFZwKXxyDO/OBUiPH0HuarKsSaWvDgC9G/r5StceHzTRduhmdN5xpw0UsHyxaGXABM0FDLIERFT5hbx4eWwnaGZnIV9RYsiHozwAXZvVzpnSS3r7Xx54i4d7lxd7HI5Cpg7OcLoFiOMoBiVXvkX949dEaAJ1E57hThbGr6MYqsLN9jRaqSgrH3h4RHSOzm7txTEmmbSVo11Lz3Vh6zg7OxVIEpa/vXJ/nhliUD0H0i/4mpj2ICmQ7bj9dotfP9VULx5LSWUfWAnpNpF4tj0NQ4l93gRmrukJ8Aqcub9awzS+gJ9C3iOIso0yoafJfn46ike2h/XdwomxZ+p/YAoXdTYKRZ7xYG74q1+UB0eFqxI10s84erUSBgSPYzIZwLqMyvMlSZz1Z8CbTXrWD++tYEnHHDPZpNsvGSN3ZTlh74nmTIjnngQ/XLHdjIIM4HvpvqNT68CbATJnc8NGpoobARhWJ/FztQeN6elToJ9JXLw0l4XNWSJIMUyzj4YEHqlYCOKf3Kj7vc6uCu0BssG9NR0eUi4/58GM/FgI0KN1gR7BNVaoTqd0yJAzEam7iqQaHNOVmEaNE9zWAr+nneWcUyBmYSiJ6b9PsYvAN4NoS4kAnF/5vCdIil0YIwgwa7LLRYU6UJGrVdNDBr9ByiYqCyG2oD6mEspCze0ruEGeaN58ZQK9/R3g5EB8W6VBmlFB+O99PwJmEa+zB3UzIWRS7gSQy4/hds28Dvqtl3CgxQtxwwfcVCAkmKh7ixULahT8LBgfQowNykJ5XFBQxunHGbNh9+I42H9TMW7Xcx9C1Cq0IjqwCLVyx/MgQDWx/QNRQ+/juESThiAlieS6ThtrQBBNGREVVHRNEKiWqMTUqYBXh93oh/E9NQvmsOH43SPLQlLKyhIIOSYUHjAKRWiZ/1cx7t4QKrkh/0oOzRN6klySePAUF2UcSLlEMOIwX3GryCyjVFj0DUMoYYFIUhyBw3LfBypLu83jxUh9f+BiGmCpSsSsC1D0IxQPim9PTC9THdeHZDDQDYl5Cw8VChwxyCl1wemmHIqQKDsamNUT1g9m0fhfM9j2QW4rnnBCGoWoaKAkBixCzfuADzoNICf/uqpAH8GgL3o/PpZmQgkXUm3iA9I6RjvDLEUU3Hk8OrNCPZS7UQ7iYqc6fA7fxcDFI6NgGoGdTmk53KD3Gh4CRGESbaq3470lT/uAt9A+NRDufwjzPNAxiQuDnhv/gUDb9XQqnzHWpG2YdSpn5tywIvksdTVjq6reVqF86gq2B+phL8nk/K4fkPr4L92TS6mGZmRUprj2M5gTYAUKstek2iz2ZC0pz7ceNxgyxyHKsIKMPVkDeGEWCpQEDi5tOkVtvmmko+E6RUeGYbBs8GQR0xc3GIYo1TFrwRdThK3G9lZ8w9YANgTmmy+J+1DXaKBeleDO8LZLlUkQOITFV0EaErgV0ICsDLvHKQgKEiJDnVEKftICtQRg7dyJU+tM5zuj+4+5Imz9yZU1y4HgpInA1J/vv4zqUkgIILNiAPYOuhSULO0xfrkbjHuJ9KVBTp5sdwUES8r0miuQv1CGej9VK6r+KwJ7TZl1D6MOrXoJSWFf3PO5Du8BkLrheo9O4V6jzzlCCMVZH4I64xInt+lf/Qer1NWTV3Bb9rtub7YixrxuQX+FpFOhWBdP0HCqVsOXzygRaTrlZQBcAEZbf2jSBktfzEaHp0W7HcNGUr0LPg8ahR/KdWHICSt1fg4GcXufSopFTe5mi1BgSr3N8pMOKPo7dWZD0YjIp+VI2xy1LPKva2i+CMYgPjGSrDAzcIbXPTK871d0Za3xejwVcoZkO+fDWYUwvu1qM08OW7BPKVMhqq7k0+DpJciAxq7UWpG36SW6dYf7w/q1tlEpSJzD2OpvUcBFx1kyQdQtEVMcafupV4gNVGgielKPLHHP3eBGt0M5ybDQqcKVe8RalWXhPb+YcdftkMa/Pk3Ow0Zs8oMCPDZKqUYUWDb//rSPEsGFYCrRLfa94xQfEY8gpjPWDJiDHkaYTfJ9XKzfA+dCCu8cNHHGWh2Xq3zXUkNGKWtTT0SIKRq84fxowDqadHUuTuIsd7sVgWi1QasVETfZ4a5bIcI1t80mF+E2/NkSG3weC/BcNa7saDznQz6yb9IArd8/O2gyyZWmvADbtEPv0B4FxiWF+GI0wj1J/GCt8A1EFmqYAQkA/S96ZpFgcJV5BtqO1u0CC1W4kkJkwdi8ZWdJbhOXQd7Zp52ihxG6LDcsPEIJXNw26UUXtaJ27nUPiSDiv+QUTnTP17fZLLcmAEEK7QuJsj8fRAjT+Gu6KhcScMI6e7/A/mHaYEzYhUpCDYJ/xW6Hx/DhI1/CrlbKBLgV7h809/fks0eV523yySlgh8SAZy2qk2avQmCDIi/ChWnHA4J9QX/RBpa/4yvnX7xIfLChOaTNImTbIdDhNMokXblbMcdpcU4i+vxBuMZ07zvEjZRqWZsFnCkll5N2klDuKDk2TTslTcJYGPzcHPNrdnPwy3ogF/mWXuVKKegtbaO0uyXuGBxwR7gXVsHBYX1n+7+O/VRbrPZVS/rODiLnO03E8eG8bP6N+oPxPCYdIRQOrB5lVMNhAmPUy0yaZakITbQSsQIYPa3uaLWkskeNfW1bG+itFs+anSV5T94eS3BnlFXSSQdxtLRwqIU7Qbp7LNOEPduCE/AdnLmmTID0DgBlPckVocFgltb05oKLqUu4+ueWsJl6bhTPtXqU804CtHiH4P+Uha/jdYUGBloy9GQ6/1UKr/QNUH2VNJ7Vtv8R74PFCAZY/Lf9NvZYcKi8RRIDprFr9g5Z6fy3PpsWFmeBc8hVEL7eEeZgzYnHfbUDoQ9Fs1QDlPOhore5ngtial9Fj9RulWe1EBxYNjm6HLtR7nQLGszF1hLjZ0GbMBPlAZP8yGQTs+ba+jY3w8kbgP2YY3FjEbY93ZHVPaV+dkN8Iqmu105MI6wd7VIBl0+1J79i6+W0s3nsEOwHGaywA9ma17KTuiuJ2attSuN0PqilLHq++MYoEiQ5zcejjNjuyGztHq065xQJK/dKOad8e0dZLrp6HKzY8ZMWeeYzTzuu3e40kU4SxVq+pGZxmlRmaN2SzqS+9qyaj6+nIBomT12KFHNERjllLr77DcMDbb+kaz9QbPSGhYPacLp30mZ1tUqbh6AykvG4O0cfVSxdQJsj9HALJsh0V3u1CER6Bi+hI+QVuAuJOzxQei184QBVeTNPgJceCbYJbn7uo1fT4xgAOWhpscEhDoXXNusShBMCCZiLmTf6LDJ1w/uwGOkTeJOoVGE6OxqoUNQ8iF1vCaX3cOQb/lXXKhlXM3qlhbNuP2Xkfc+mlwnWG5EqyKBYoUALZdxNF8oXU0IxAFHKJHNNypO2YgI336YEHe+qWRTG5ZTItZRrs3z+pLqFOcEQbKFdt1lXcujstiI5CghulM8fRsiTFXGW0JZoWgchjRSVEgAe7c44W8enmryCIKcqIdgu+K4LHWtyjkeSbS1qlAu0SKJGTk7RogRXQfNZmQOX3uVXVcW1wMovOiCJfZnKUhWBMDpU2CUq5asG+8NncdZmigFTPcuZhNZJxkexQvMS6pTiUpOpoOTwzTW6biemXISIRgTTGG9lSRGQjnSgUG5ask6ShM1eQF/udiloTYkZj0CBvqgGjkyIQpWYU01l83nV9esmTECzpQKJawBCE9fXVYqzgu+nUbiupZRs5iV4OsACYWFmQ9B4m703zo5fNfoC89F7xQF9z0oIkym0xp6yGJ2fgg0uTpaTMvTCyiI8efLHC1OvIaBRqBj3BeRw5jgzniyKaa2m8dlxBUEwgx4VLrHuVtnnx649S7b1fTxYWp+SNUf1h8E7C23NegtnJlVf+TPvo7xVpUo5j5lYnPD1eDOLLcWzDdM/9W+nQ24sGxH6tMsl6nf0C88l786in05j9v5ObwYcmVRjqZ2P85YqstJ1Rxb0utkuJfGS30MY+tGJ2xY4heHkQYS/9lKSplQMCNgjpgFkTaSP1xbiF0xXPb14UqQrEPgz5p0371ftxf4RCAbTgf+wt2H90EdPiEYg1pffBt1o2hII8lIqBi33hiuQco2MSjmS+QldyMaNY6svhxK40hv8Ng3jiBDEypAZ/r6HFxoL2LMj0DRzVrG7zilrL5x69mY0RRmVWy4qzNxO01ZMzcswph8ROkJXfd13BMuydtCngeRKvdB5bxyG1oMbBqQn7P5A1sD7A3p02EodETy8o8N+AgY4trtdxPW4FWiEv2180CLtslaHk9ZoVS+WBTukbBBUMStOidJZ50pZy4HyrcfwnUG5Qd1MowNRNgtE2jg7tGzSFrVwcoSrUGGt97WWeEacfu8/Pje/E2CunCjw4PzciOB+voiUm8jLi/HWXqgSIRI9TxNY3u3kfvydN8uCvGfXl/mmBjBNbScO5PFPbQtFMY+AGS6fW8okSJvF1CGo6Zn2Ozc3Px6NC7PgxTF8jwYhSWYyz0/mYWctroDKWzdSRcBvlprsqG+f7kChoUW2aBJCmF5VrDlCUG4xlzm3pRxCZsisQtZ11Nyu3AKLrQmzx2FC/FGTZ7VDdYCOzTR9tpsJ4YTqh5XAz9pq9QG0K5gDH9fjfgNsTUlw6M0rA4tpcm1w0SWPgU8EzJqXKThc/5+WjkAUV0M2AVXBrIMDCbQaFebUIMjLaeAe26QwGXDb1QlowID7IieOF/5kfI6srKoMoXNMC5hivolJcu9TlY1MVFlHaNxDhxfJVaYgN9K7ePLRMX46+5b74LfypCB8XqkpAMUUB6AivFsG3XLQGrSIkOaGLMki7SgTD+YYQ8SjnE1TPQgv8rZTaPhVEZFg/ir6bvZ1N3aQiKy8bPRgZ3jng1wEPDSnnpENkM4sJIbBxonTObAdvBpdCTsGwGFKMHwu9voAmOGOgJ96sA73MPKeUoUag/8paigzVC7fJSEg5NhLYzpUYN8+s0b8ucmMnfAxoqz0v36wxFhEsFnfMRJcQ7tYr1MUP1QQyvkqGzXTOytlFZDJUttcEZtMYtoCHI3I+JJbHZfRQqtJGGe4GXhGcdqvyMAk+T2EIcV3Xd6BcTTLj0+jIV+AoftaOmfyOwMj2doDFWveCOh7OJcW0peVGUvQHGlItpeVY4bM1lMu6yq59uyoa9w1PI3DrUGiUaYiAaiDFT+fuWxiAdLo32iOrAvwB/47fecn6p+jN8Hqe8Tm8xVS9EJJKyNiYG6hJim8iTyvdYlEuUbnuZbYds7GQgW6o/raLj+oiGsYfTxWy2hk5pHBIGnNAZoDWwfqMrUdKY+8rCUhWdsuYVuzYywgUJutGY4kLxnNa41LOogdUFKQiCI7YN7w9NVeNa9Q7LtvEYRxcj7au2LGipvaDI/sJSD++4C74Df8kVkbb6K1LK+kFOf+83weiRFCjgZJTnYbnAtliZ0YuWyCPQokHR+edrf6QcNt9MOaVV/SdzSjZewHaglA0sXo6XA9Tjo+Rg0b/OLGAHZFf6mLl08+ewDJhfp1R3Tz/zYOOZk+dMxnKqq4ULa9CLPE+BoV32DubkzvoNSJc5RabrLM2YUGSu+CfikBtoAmbr2IA1hEIWwUDXeJHDymRmfoKuZLDmrnPyfrwFv759SLFeodze5twfyCKkthNpDMMFEErNgc6ZQoC0xhc2fR+t3+Cr+tOyo357TsfkrpmmYy6aa0ABx02krGlbio95SPDJMs+t0jjK2u3zcRtTBfandiF3d9oK+ruTo0q/Bz4sbBQrGCUK1Mlbg8ghUfEbAYsArXvX/XsMfGoGb4Zga8HUwBfgaHlYjsH/8/+t1vwWfgwYWggJplSEtEMU5PJrCeHW/F1iTm3oobxckrs5L6xV0iQ3Ah70SDhUgx350ovVQ4kIAJI+O13QhTou2WJqc4GLTZ3lZPBNd9XEmFQNSFnXC4/LCocdxnaFpwoPihMFBO4F3IjIFkkQiHWbur7DJZen1HdpxeRuHXOazoDIBHSqvfFPRgbPnuDTN5/S1jwnZF6AjxDQWuS7ivTKiSG576YaSF9BQ37nBuAChnMiyTMHyoxfPx/EW331DUXrjTQYKVGCOTuUplEikUAwLXUXI/FN5QF+0iFBetpyoeIIycrmhuQqS0O3DfrNXnUFtCak5dhELrMMpzq9RlvzCQWM0fVN3waKxE5rw/gHG99BpDabroIUhdcRTddVaKpFDm3xb0eGIgWNxcYr8dzFJzbKRKkMeEIQmirMG6CCykrJUiBZcwfIiLK7JqwFF15h1L3cOidlbZ1WFTrQiEModticJNQHmLqUce++PFANiERSBorPKUSS1zEZIuJXqugRr44X18f2Ze6QRd5q4WCM+5v6mww00aPg/jXsoDB4Co+QUaDCtcPuCj52YiGdCC81YoO+Pxhz428fZ+tsD39LvFzboMTsOPngP8GUuR6jGcr2OI9sw7ZuzY8Io55eqm3/CANdhbsxzx16VEaXJnQnglUVJyJMxExnuP0LRs+GeyP5Mt3/D2s8G7xR9iFeChmllCDPsuS3Tgc5iMkfoVy56eDLySPcS3cDlxJkivf+Tt/g7zSAZZybPChUrfNIULIbbDvRRwcXnCPQVqUCK9HwzrCSwV2BVnERoVaXvEvuDm2FichMhf1ZzM6m+8VTXlfP5wnkMKOPiuVfPqO3iuVvzQm+TcLdpuAZc6PJy3HOIUs2Z78Lj4Y8a7EdiUldm04Ebwxw4zeD0ZKnxrIQn8KkUob7hKmU9Ds+tGSd+VWrhcvBtiQuhpz5rgUYs7UoGkTbq1Txha5ewaDWHu1BwsOWyA9hw3q5tRoTWk3MLSCAx6x1tUB7k+vGqpJVi4fZnOPkpQcx94WDRAxbXp74HoLtl0gCOm7VzgAv0cI8puRv1X6DVVo7hsoyyjjXMmXh99vWOHko3B9G6/m68nidehb2nibLUreEzX6zfllym9A9bspGR49fE+hxMOAbABcU4EiZu3ApzJpGk6oPvKbnVCi+XkNELQ1G3lXJSo4SZ0n7pTixLiuEjtBrtPS4uAMPScUwi8w1L6WlbcZz6Xm5qTNdURXgCyxXC4VDVZOQt89MqkvCvaHwcJnHwtbGaxpRWoSOu5E03O+n9oYlCyqNcTodK/kyTO2EMAlWusgJyz7Lhft9emjHXqItkyZIoXA2EnyxwBy79bGjC96aQzLBqPFqKoperiGWRjLMGLZB0cNmINDEwGcN6XR68pgUpwvxhnuT1XAJAE5HEx1mEYJrcR7iCRatkwS4UvKJAA+XEhIoMVrAK5hkQ9d/7xFDWxOzhsNRZp4UmDeOqynL8s+uYoi/2wZQBXlnlSPbs2myalPnsZb1HEDuzSiqS9byiplj8Gokcr3u78/YjDvvrtjEGcJ3hvOF94t5q2OzzcB8FGiWjIpfhYL7FOAm9dAk3rTw3opJujHWsp4j6oT4k+HD3SeQxkMm9c7ZdMHxu1uTaI9fjwfnmJSHQHmYOD4Ayh2EuoHaDomJlTu9Tm8BzJIg9RgoOryGn5u7nEjf1iUHmr8DqzUoWL+sSMxIeHojy+uCa3zDe4qYoDxW0Ch638O6ku2vCYMn7FkWzZKiJ7MxsJ692jcJULT5vx378a2iaFc4Tu98l5dzimy30BDSuTNIPTMynCqlMskj3M3Z4mpNuWxexqbpAZ0QoHATz5gXnZXIyI51fglteIfUHaneLEeMUOV7q3v5GWdTBHmpQOK+hitnKZ3tFXBh0Fn4iEqPm75H/Ryol415zrmiioluPbCtKIr8q8dFKvrQvf7LxYABQOUgUvmVEhpXExcvluXuLN/4wV/nvWdkGVmtGaQiAun5JjJONbkVKF7OaR/vh7SVYegZx+ZVNN9+w4lKUFAT1hAKwQNh2UiIqX8vmKPv+tpZsKfpZlg0IvXgjOvAX+YYSYhOW0xblZlwNB0NMS1gVuWG4KtZiF2UVEIVRR21p4d8XWGMOV1g4Ip5MS4Fa3HMxAyai9CH4hIz5zGqEzavk0xy8K7xBrY0cvdIgUHRiuHyO6/l2CSJDlXWUn3osDdLTX0ho0M4NXHeCLHp4mwnI9Bc+YGiWGTNxF9Er1wRcoFQgYj7h9S2JG1CTlqlXHZQbgYDqwoDneSci0JmZzGmQdArxTIqheLJ7tNhi9U52a/VC3llaKiKAh5suDV0A3Ewo2g2AUR6XJAgpME/YGnwaVOU0dV+QGSxkcCyRJdErsOlMdy2/dC3ukR719Wkai5qbFbLWC4E6YC3ub6PGc2PKBc95Lqc0ph6DvPiqOKbvOgdfvxVPEn9DD5pgvyOxtCgO4jB7nH/NAc1duEqiE389lcsE1Is+ktBSd5aNP1DlJR71yT1CRxE1x1nskLdVBJ2PX3hbDuDutT5NcXk60kBRXYeZ2JGFCLYilT4zRQp85/p7M28MgqMynYEHduGT5hKLytGHqXzpPLQ2BI9NM1CKgNAKPhgtvy5r6RcN+KJ6+fN1OLW/1TWvyi1L25NqFyviFzoCPlc70lQgtW8fXtT3Cl84PFCeYAkCz0CN82dYzF9gY2iAQTmqglXc1BrFwDH23kXhJZgwN7Ct303tNRV/vDXWQ9nDS/Iwym9V6oKEIT7zVyUTsdJCr9ekcXellLL/6ln3WG/KkK3LPmsSl2rb6kY8dBV1z+IffCtxnQiN/QarHYunW3dLThZr+uso+v8xTVUbLV82nU70KhcCsuREsFYbb/Pny7vYehUJXXFAPx68TrRsD5+u2Lv+osCmQsN93VBNSRBJT/oN/6CC77YeTOxlqsa3wtVlNyrSJlwiB3JWtjUHyCn8wqhOjF9qLC0yQYl7+p7poSP077eyQhXSsWUjBlrtDn2AaTBsy+MyF41NZSR7Fx0aIvn+/gAes4GYEuaKeuDP+Z5rjXDy8boDFqJ9dhjHRaFK3RUZsPHecmgVdIMfmZkSIOj/Hr9qEIOeZRWSxajmVGWV0aNg6kT3liaMJnzcGPSEbOBnBYUN73hKPDLalP7934S5FJSh7+UdbJOa6w1VlRF1ZnoTPSmelPuud3Xwx8MwbE9/Re6e4IVVRAhWqEn0yYGlvnJUoE0JTg33ykZwj9uj5d0Lt8w7ZyzSfRd4Gn8j54CDycLw1A4v1/oLPSDg4b3olpgo858++qkl3Q+id5En0+bGKbMxMcct9ybpueT7YaTX9Tnm9B+m4syaH+016EfBh5kDMYpHHuig6eNqLYzhBS4UGVWBpnE4IW/Wx+qHhDVXiGE+BoI30JMoSYGuZK5TlE6f7rMiozRubMhUk/LBkeeGXb+lkK4HeW6xgZyK4+wcmFQIQWWoZyiZdNThEJ5U24VdBbemU68+74WJEDxkQ+ovNv6Ij06s/ACprWMqV+D6cDcv/nYen63WMtpM5szavmdlUaDTEDbxlgQww/LGUVcUP8z072fslcuhQjpCsCt62pid396mSQlThdFeuJ8YUNYm3a23fspEb/9vYgHxib5k406rvpvY+b1X1s19IzowjGUXAYMCSNgKDH/NQwawNXE7v70kp7iRx1ZNGebcEOdGIf8CtpIZIV9DUbKCGR+PlqXDiJD14Q7ntf6MdovInuKPLjbwVcYAklvMDb+lLVRq3Sz1jj96Xz4NlUBsFKmT3PGbcZS+ELhlPL6KRZTGiQ6+o5g0zPDEAp7CNS/TYtG9KkuMqDD0EOoz5AF21S/t+kghR+2OHXA2OJFRgnHKrM/2FWpwUe0zyfHb+/nQ5oookhaQTxSnrFNUbcNMrlV5SyXNRSzLrOVhI0Bg7WcEFJXr21D4odScDNVnfA5Dlxh4YfAANZ+bc/q16uqi9bByLngCwosvs3R6XQKcAd+aSCfBpkeaCvf4CKzUjpUvmPn8cgeyYebNwryXCigiFjHp+RL+FHXtBQq6VHeJDbX7anjWbdGIn6pP2zIXzgKeLxCK/HfOUeGZFuDwYcglXbW1HTi28LQ1Q4XnBD4cDBj5ued4x3OtbpRZeX07rr9iLFMsCVYuQp0UNv1AY1hgaJ3e0aRO8wymGJh5d5UAJfKBrg9cbr/ZZRdhahgHglDp6iMAuvqhVXLouaDjJSXeZ7ikZtA4VUCnfc67va3rq9RplNsDfGXke6EMdGtfLUT/Ogg4UJIU8wB704S/P5Jlbs8WZqS4UJ6A9MkhFQ8CKdrCuNk2F1GlZNbQiV0PFjvVxYZdaKu0q3tjSLn4kbi5ZPqdP5l1F+FMWuMFIuHKg9X00RRldJoTis2zTujZ4GDMP+bdgQY8mu/8+W5jmXBGTrB9cs5xcMYWO7efCPaVDYEhf7izuDo3JnjidAqN7A2GUEBp5RA4ZEnA2agm+UHjHDP1smulO6he8V4nqng3QdkUJa+ORwvADgOgckHjcz8+Inm+yqOPOEXbu4xNQT2C22mbkPThCv6mQ33kCDW2F7k1/v8slW0gPA4yBYNz3gsKM3h/d5Il9TUOkaVBquKVeIrdZhysfCozfzwyjH82UREpzBm6WblL8of1C3an/fB6LK26fd3i/Wg3d1cX34N4d6vPFcJZHT4YOSJx5Yws0e7B9fXfrr4w+2XaX8f0/In3NVXOkuda+Wov+LvZ01VPl+VdB9SEeLRVYY1M4a4CPrroBCgqx/Oh8TiXz/4UIu1jeHGebqcYXpxJU5Lp3k8KXqmZItFEasC0kU5LB/3+eLWsf23t3EKvhfjtmHvdBn8bPufN/M6L9i291jTnAJ5vdV6py0YdILFXnU20yjUBgazsUEsH+7YshLx29SizEx8XjIaA+/FuHstxp0DrIvb/DOgglLwqnAwuoe78lMqkknhZdN9N18UTeO2mn7fBk/6NZiPd8k/WZseU5nSjqFDL1ocpcPHLbwDGfQdhGvQBdMVQekkoYxmkWMFHkZZ/PlDD4KnmjFkZ6vdpPZwXFlqGwEI4PXYUryAZWwENicWLipjiFGlSe7I5iqe4kCwc4ePRHDi99Jv2Gc/jdNlFa7Es7JugGVkW+15N+oLEa1/rhPACMDLxW4ry0l10VTPyeddfhJORovXDA6SIenuZJ9G7Dx0lZRhGS7vxAv7M/S/JO/D61B2z+DldZGr+vGD5DvsImsZVF+I0l00eSXErA7FvGHLgO902hqEDPxmG9rCIB4aaP9qGbcFf96GH0ZjlN/T+wrl9Kdt4Q4eQAFPUM23zNNktZxEinEu+BFZQ/R0ErI8v20DNZTam2VNxMs33DvSxcbPjzZdkyXSjSoOf4bRaOkV49+PCwSzZocOSlNOtRafbJzQ9UcXjYMF6jQEf7Pn3lQFPdJBh5wJHuoAHU4/qWMt8sO6sXZBPH/4OWn8UXsURBltZ3FLUC311Ea7AgkwuEOW5QLXufGG3h4OxlW2bqvDUEQVSwaiER+J0TMHDxudx78WM7j1MU20RycZwzL8Lt3Nfuy5IBN5tpNp7ilRtuwPN2NfNR9ErkELcrJvaKMHHR9k2ZCo6zYM3m2JN7Mu/3IwujxaF7zUF+TxUntWySkPJZkrMXIdDeo/uUYb9pyx4hgIwRGZNLWyuphXbZ/qUIB7Hs6GtYVOKNJPYwWG1zF5giBI2HP+wlhhGZ3XwmCNIdWeFhSZDUM8Bb1pDIq9dMU7ptiLDtQcodp+CTnpmnykSzA32hjRY6UdZeRy+t7OdTT+WxJVFNYVCNQSsEoOD8cESrU8P5svypUry0AtAavUGqCWgFVOOCgyYJVaA9SSEJBUpe2RQ54q4FkV4FkV4DkRYPx7IWUniSvBJtcnyJPvJ5fpeMyYO0LGkmLhhSjru0GNrxJ4zAcGlDYgTX71vw/bMA4omID1p4p4scRiht4LD6KLhMAZfjij57BiOa8/C0vTC56ugpt22H3n5btkHfkMCTVxhQeSJF+1MkbdNjwnZdJeP4c0/QV7FJOni9Fi7RobgbNnwnJYYLweGkkmJASvso89mD5YfroR4ivUEjK1V89gGTnW8fHrqH/NNX1adtrjGLHGAU3jU3t6wmP11GxouIbgu4290pAGs+pO1vIgXv+pGD++b2U0OqWBd4gYKPBOLniS6oPktjQRV8U2Pt/rzTMvUFZ2TTlXnjMaWmvIrS63pxu4aRLnXiv5dFPmhQRmrRNVpl0c7gkiTfiHhCEHLfp/FOkYt62RCMr8XMJh8o6tXeeMidLUw7JNLRkbY4KcVWFC6L7wWTlsL8yloaBh6JEQzXIvSdNCHyMjVlncjrdcBXSul5EfCtk5zeseMX1R9oytxr7azI7ZnKrRn94GzrfHMsZtFI3HhHtU5Bd6lx2iyPbkpsXepgDRnktkPFYGtUvCuaU1wLKr2l0/I4Y4n9s0S4cqV/ipRVJWIGlBTst0rPKClT6nU5W/OOhbuqxyi7Me8Jhm7HJmEqmiJFMLCZU8YVqH2sJMk53M/DOt5+fYriaRCZLZVlyG5cG3x4IWE6hx6p982W6DkCIoJjDy8fvjUdaoWJEO48qrttZ7vN71UzQgQ0cppE5dIEqlXVLF4ED5RdcpidNT3wj6E2ZJedUZ5Y39u8IIGlYZOrs0deqKngSml8V2j6Lc6uIsFWMzdfYAHCMxPVmVsqn6kKc/GKpz2uWuPiAgltqX7d+pltsL15fDFDOcgwGjV7laGHzJp/qqb/ofGCq5H62HEDUeRW785AlEsJKIBDJ38VlAOR4Lgw56TeEir2/l+FbsLZWlBWN+cd7oaQM2gTsQ3Cy9S1KIFhUTAOyN4l46VLnCTy2TsgJJC3L6nI5VXrDSt3Sq8hcHPaTLKrc4ux5zpyCXdER4gk1xl4zEl08JPxNYClvK4waR1diJJ9NZKi2UAgWd/ITGwOTRdek11uGPluAREwn6+QtZWvPxZikrRrynOsNQjKYyNLqkFwRtpTjJkc2k8PPfAwCBkg8mwngnLt0jQDOrhismCIsAh4E/Nyk/dbeqEQwuFnpNKfxabnsJUds+aj/rqmrDT8FOg+j1/nO8+lga/T59fsAryCo25B+mO5fbP9nPqvYGo63VuWj9erb4JuD+aTjzlsi6AhObMZ0DWXmp3linzB/4yRana1lr5j0UnQFdiFFVeDRdUoQX1lYrNUBt9Drt2S4crRNZPHNxZuyCWqsQlKXC1WJmjliRAKXQ8QdrUcjkz0GVDbFw1ZTBsskf0WA68MKcDuUDeDcSV2uC5Ra/ujly+hRNp1GHV5h17/tUsPC/+GKw1y/bNRea2GwbWnjWL6/kdY5LjEYg1WS4REF2e+JWFriTyfzpVcsXkG2DhLblAsRUVvX7+EZzYxCPr66PSazZpq4q8paEy5TqQiRk0YemjKQZbmKSojUtOnpKTSpDjxAITBQNiMsEi4BYLEa1HU0ay3qBF+QXZVCNYrZIrvCeUXJJub+sEzG5nyS6wz46TvLmzsNl8k6pxPik23/AZdZ5vrI8mXwHXKhokGlKLxeBQ+f90AGXho5WOB/ez/C6zBVyD4BQfcRGZRUnQteNYWljVHH79J5z1imOMusDzFXvGeHnFkyQFJuoyk+y6oiU6uCsd0wdlFDpvpOhjaz5AuSkCLBY+bBPaBcKMwes7bRmWwc2stzh5GVJX1E9QoDxKRM5Wubc8kwB+BhkPtipQAXYg9K9rBhHDJ4czNzQ1xcaCfC75itQgzbEp5jN6JjVAb+oE+OEjQpPvBiMhurZy5DOFPGa8WAoZ4ELW473BwKT/K0UCwDMlKQG1bvAeANAsd+m4feWqA/sh8i0QRIyUhTwdGLGprNxeTmoKqfMpZh0Ip5poXFW6ina04mb+j2ckd48p0wQ9mqLnP4dszTtEUyUgzn2Apm0hiaw1Wd149Te8z16XGvIEiunD4YKdgORsTm01jnG4iAk7lNVcUpBxVuWTtyWYnzNp1gWg29HupgY5iHGw3dNpwRe5ubKSEbJdUVKVBFp9GfLZ8touZonxLidiLbS7POokiP84AeWkVGEhZfuDGz7+MVaTIPOKmZnbAtcVNW2457HFtf2kU4sR6lKxvvLayIlD5P4xJiMkgfFtvimunznTJVmJSHSpx1swGbmQvZolB8YVLXXnwbx4KSF97G6oLjJE+75ITHCHQOWE9oXty6Qyd0S6w9LuWmfkHJfSTKeNgIXFByHG5gy5epyGrl4ACQRXHOmkxEfoZHnA0BEe2tkeX8kui1ynITU4aZYhupIjMkocVC8KEEZzi49TLALBq3v36Jld1pWnyJQlERrDq6sOKkCZNIStt9gI8WI/RZIPN+5fvvWwtXFCMamLcaDcGe4iEZ5uuoDLQhA/a2ZjA7YbWIEQZv7cMT5o6kGkRA/A5ZqO7z7ZtD0q2ld3esmvj5WNVIwKaR8GV80zC5l+c+1o/dykqTjWFHwAQUtrhrNPyyVSvk4extApgAvRHndDmL08XCq7ngXJQq53OBE+/lCCxyu6Rem8LpEya3qluowdNxsXItKExVzHRVpHx+6b4ut8d+P55Dam3mWd5KPO6quQwzJNzmIDJ11Kg8aiwW0n1P4dXxoexY8/+X236Y7Su4M3cxH8v4nmb8yS7pDer1ffVJurraWxffxpi69lCbWTSlTdlPLtMQlgGFKPChkSpoWWtsgn7bq/zERoVNBi2eLkOW5lRcytcSRiAuspb7FQCnes/tT5AMiehpD3ZtOTO3XUl1cM9iD+Po5UHbFd2tU39rfgPHvMxmxfWj9jcP/+t2/3+LvI4rDt07j7kr+Z+l6/3/RloNk1rUdTYbJHBGtnJR+/j7t7gmn9TvQDxH02mMRmRl3aO4jWI/9r6RPrqfg2l5HGUnSPkxXdqve9jaZ7SSLTkrcaekXE/udRdzp5MXeg76CPj36QMLybXAjXMMvLw0VwEo5LXwwfAABkpiCdoETE5inv9lU6M/TFIOaQ5KFplWySJQAX79UGM3R6NmcrVIegw0ODahHdS8olJXmJ9KFBumiNDSUn/JW0zR1GBf6xbWTHCeFPwNS8Jt/ojBUmB65Xnj6uJdARegmw+jY3/XD5fGk31D6zVnH4hipmM2i8xIPR2lp5LPI+gNAAQ3kwUJ3dyV4AE7Aqa+A8+BR6bWqyKYpyU646E3nG6+ESti44sqPKAWX8htUUkwJPtPENeYBKCw7ztfJxPrZ2KbmNqX+N5TwtHSkYwAb02/svMzAPwwzdo2PTkPlxNpliMbl7j5ug8fqqBZ8leQ7zIbDCXLb3sttZSoqjjQTB1vq7XF+A5y98Yp5PLGHzWQD+xjyW5zvs5VTYMEWoNgpTS/TiDolHBnLjJ3PsPovIpmG+QENcgoJGJRGkYKYXiKMleAu+TLF5HXd3L3hE58Fdok8G2JWPlYYp/TaV5TSTLNA0YH+xA0ikmck9FWZhJPwxUxBTmNSt/zAGq4I3PuYQageN7PAeVWoM5O9Ex6BBkDz2AzqdV/7PHM7wvRmVtFWVgLCqykTGOxk3DjUji//AyAoJrydkg8HC+y1drIbUdcSr3FDo3fHhNggkbByi4woQz5abJiaa/VI6ySycuzCMxF7VZcLUKTLgXYB0/Z/UGxFt6ukZQQgbA7YG9BTuNnKsWd5JMtRO0OQKsmNleUIMYBDiMto9Uu7gvgJ7gMSTF6/opQR4GfOfMfmZ42/YmN4/GRmc+JJqN0v8dsVNUX5PEWizDruiT//hMnCYK3VhONJIv/WtHR8AlXiJ7Wm8FfsWZKlLQFaL52lB3ZIG+bs0oMDVpfbu0OJKpHu1k/O5KBtDX6vHVEkXDaubVItTKN2/vNEVhHKR0AyPtX0xeC4zBOgtSgeFRM4jBm0wjF8h9KDTpRhpEtSkjSMpExCSUnSMCZIkkRd/5Q+FwqqEBVbs940KOAc0DxuuvhM9iiy68gWO00ffgVR8F962fkiA58wumR5/uAEPEF5+CDubm9+imWFjWl29/BxAzBmlIUUVP5P1c3hJXh9U5BUO63ltrDIzN23AjRsylNO7NOx0s7g5u3ZEk+m4X4BhbQyotLLJTWMMqDRrgTuRqwoCSK65JeZZXJnFu+Sr7NIJzI7PgiwaSrpU1ziY13n9TwcsD+nzwcU7kzK3j6K3JkkVgi0rAzaIqsuiIdXT/NC/J14UjGHHVtgTAPEBqXHLZoztJPgYWKe9DBOeW91xMxjWQxgtThIBxYV9DPAhzlrgv3fWz9YK3jG4rw7n6OPkrbDQL91sjkHMvx3SREVxIi+TqtAtBta2UMkcVBbCqON2G4jSlKI8XpCDK7VTJiyGmRfkJXtEBFYWf+768tkziGS8ZqgncQpH7U8Rv+/NBYqa8DXEchumD9d/quJe93I+L7x+igTDfg7uo1BbTEvHGo4rgyzV3L1zRmhygTQoSvS0GzdbnCo9vjVZmaFRkbfW9if2IsMGw4tmDN2FNGs7fFiDorx7TvHrrM7jnvXM48AtRikCfQ8BrBde2oDgCG0lrPt2mRbZ2WrdDt0JTboMAHJzcI2mpHUmROX/62OMg86KbUjuZYKlUVI+KpwqAMNN7+n0awSb6goZTO0FiSGpFqh+Wfg+ykl4W6PAn1rAjwfyBS6hFKvSTElCAUfT4cGw3JgSqr/RVR4k4G+tgVmjTTB2ca7sWvNqv+lPvqtZPK+dJirQl0vDmxGq0WBVlGA53rWo2k/21wuzdfiCytJcYkeVbjk44AACOQ4BSvS9Uni1SlSfkDGrBwlLbFuBUQX66sx2UUsKmhqjwd35Nt6tH9NFOkCb3qkubPnFJRdy4Dq9wsjegf8JkGNYaj7tm4ujfOAEQ8saUm+7FnOlY2V8v8ASdifqXPjd4nkbCc6Iab0gxV2t1BuFdxzAsHU+5GUW+80aKMYWQnmGAE8byP4jvGn5s7VU1oQjEZWhgPU8qSCiyRFosIVheX+V5HDFKW0z4dbt1R+jNLQ6TYTxHg9pwNghGWVpZJRF+nrmuynAVPCMTxpz10js985x21BhGv7qLPdtTLXjtRakQxRvit7mF25kww01V7iwRQUMFhh+KAIpC+KIY5J6g/w8n9O9YifLIqMwOmn4YJgz9TG+N8RLQGWcAdzVR0cSdK5yBqY/lrsgJ4NyDO2I8KmI8V14BBPIkepQw7Y+2X8mWIZmR8oBA1qq4XSDCAtFPOnUhDoG9b41kAVoOgqUTgXbUaCaNOkfqquDmuEQMHFFLjO6IFQmcH/BKh/uTKux+ZQ8rqztGNCgif0gO6W40Y6wMQCznv8vIpVBaNVSAOEN40zN3OzMeBsPFKtk1CBARWjL08rOkH76fZnAklnL2G1qUnOQyGS+aHd4J82YHnoXg+WwZSVUwKYwSZt8Eh0CjCGRYujPXZo/QTnFxvnMn2qASGBFUQmlnEJ9rwjztS6QClCpsXKy5X/FsKKhUHchFAMpMLFu6f5kVxGK6ByAir7TEfq4XdsaB075mhonKX+JhMQjK+Bmm4FkxASYgBKZv8uYc+wdtLX7lHGq0giJOeu82xAtDcnTyxgGVpzIHcQJIQ1XXoB0CLbDa5fy2Tus8HFuRzpo0hptPtFKGGBHqTYlkjPA7HYWTr3eDDPFtRnx/2q53/GKJ3bvnXQWORGZcXApSjTcAkswRILYQccJylUooRy9PoZ2GHic6J6pwdfHHk0NQnUqgb7oEz8JfSkdw9fUFaeg5il3laCEzOal4Qo3MzZkdcosdkGCE5z8rLRDQ26dMnbgrYF40Ek68vdnW7myGIbc7Yotpq3K2RCe2byu/eW4TUJdAlCH1KsobfsCWLjZgycD+a/jZ114DUpMTcpLhWbGud6IWvUjglkmtAKc+8WjDNBTfdomfsHd5wv4ttwx+TxWLx5lcU54HvPSGwVtwREVWKkGNSqAO8lRPdNv8URtIFOImJgMRvbrIDs+/T4HsxDjjDqJARdR3sXHdK2Zf4RVlBViqL8LAjswaYcL9xtyOD2I+S3RKnQMwGY4F6M9qQfWNvHf7LTTa2bwSyyNP15Mwz0SYcq+y1m9jAcJz2DjcpPA0dIKtySnfMTgcOiF40dIYQWLY/cxKdltBbqRsQVLKyoXjMjFrK7c/3eaMJzF1YIcTiRBObYYrEQifAjiGLRqoIGI2cJiHvhcrJvnLRuVYBvgdMcyevDmDSnha1jqdAK733Fm8ImY8kcpXNjVXtS7G9H0dPGjPY+a2DjcGVfVv2sHZnjvOYGh/BETvWhSxPMQ/NzavC6klMRgJ4SuoEujYadMK2zi9k2wvvQ5Ht9MYbvFMQsrEVYOj7BleJTAj6F1EBiaSvjQYTrhMT/x22oP6FjxgieOFxQBc9GxGY5ifXhHwKN2/tv6a+vKCPpjow3sOx5jMaRx30LjNOVaJZO2zmr+MlXRt9WdCMsCqczzRd4/iXBzNUK6makGvWjzzkSFC+iGGEot8EeKlntuZ9dXpdR96iU7CKqN2Q6NRP/WbLs6kAtZlUkcMoQBK4Xpo2qmp4BQ2maCTb3b1SdCprfJ5LsUJ8ZMzHZR7A7wTE8N2C558+Y4tDTJteUT8z7zlSDiKR6NEf/IM5BFG4b5HmZQQ0upHHLEkg5G2N0t72uKpOOsvkqG2w79dWdgPAzxaKndoowYEnMs1SCwo6eT0VdIWbw3l++LwQLPcUuENIZFl706SLLL6mgbhQSKrrAyhrfAUq1ffpmMDa+IMgq1KQ0DgpXNeFptDUE0c1Z/wxGuYws1CrPtFu8LxATXY6YRatczzbNcvzLoMxZSYZC+8qOlMEo9DH9u8KNFcF4MgiKN8hcETwzIlj3Af4zL7nMS7k8mFEHloNDkf1aG/Ch8E4a06spwdHYeTLAW/mbzFRBwztllowdJBgJiRhIKYWd5oFQc9bYhjnI8voNBJhSQloiABwTOw1pNNcVN0HFfSyMfGR4jNu6TjBg5ag0ORW44ZzapVf4p1UQ4S3K5PiceWt8SDrWCChVxUQhH6VuwawxGiSRrtJ2akoWJ8LLOuUpo6eoo2wUkLbplADDfhN/uPEuEcKErWiJIHjLgP5tvS/++JDL38SEoJRdiJlPxRtEilPjENvxg6ESAPAclVORRvFVnpZ/f5dpp1XLHqYCewuSkiRHUmvsctiepXBUAWvzF9or3ILkCDG5TkEGWm/GghXWWsB9fFRgqv80Hcgs1kej+EY5jXKcoqQZuJOZzJJV7XQ8wEUR4vwu0XgvZF0Y0MqI+0pRZCM46Nyu9wW5wurEQgLjgs38NhaB6Eak8s4bsNNOyUl5VGtBQMBFrDjfv2kELcvr3dheXomVOgnm3uLnZHGYyvA43g4Q6W2lj3xNc1x0AGrj43z2EBP6yj3Al0lIGFbfzjKf3X1i69wntpXfRFalxoUA2h79bgAyMEeQ5WH5iCI/j1L6hzOjz8s5DdP18Z6AFf0J8NXlA6oZRBggvy63jCC6Iyg+a0P592IjUVmdkgqf1EYqP17Xm9rOuILiEyDJ0ws2xoFCVC4ZAGswtGb7JOzGH8bmgqwBHo/i/i5IGlwh5Qzd9SPIfSh8WXwBWar9WG0AYWzJiT8aczwNUFseIZ2KjRLCMa7zfGTDh9GGKeqKSLk/eC3Zi/G/wdvvodH5vc0fJgB6ZmKwyT1Sxk2ItTC48GEJ5ECBDfTN2wtAR3WvPZhSn9HUdKMovvpxTTu3wGRfYCh1GcAAJsvfnEFGOKa429Yg7CJ9MKKUivHej6/94WovOxjA5NEnMEDnOcE7cxLtD/Gy+8rah7+kP5yqaQDhvd1oepqYHzBeO5RGJkOHSiR1qlBGXS0i5MKff+ObDnlq17vZmAeRXIuVo7Jq2RaJEFyCLo1p+xJ5T8rzB4AjVdJ3m0y6aueD8w/BsTVNxXvafA1mJphVJBZiF/MMEGtS12P8mIfXSv/uxGzAL7fdRgLaYuvXK5aSXwCk8YKFNVTmcYOvpPXPHon6dxXqMIeaV7HpVwd2oVVTmzH8za/EoBK46CDTePrIEJ5byz3+aa7zbVgc4vH6ROtX1W+SjwiUBjE2ZX9rfFme9dHyxoWLwZIVMAFDXika8AsNhfQF55bUTxroZPEytr25moEy9Yy1sbXL6q85Bo+12XrudLbvJlpnwrROzWfKRksI5Hv+7roCqN3SBP6C/xgReSryY27rjc+lIJAUatcSpPGG8lxs/vxvmZokkFkOLDi5v6R/a/qHpWCCAN2mNaJOpNk1yfVi2LY7e1pmicZ8u8r+Nsam/k+aSV6XckoxG0Wm45ySWufHxbkNNw1YIodCoxidAmPD6Mq6TQcyZLKvRn4yWyDo+DkYoArwwz1tkyd74+f9Z8OvuLmvlt++9P5n/YFQbvdpnsVUjUHe8kuTNr+lZhBXAgIcsQ50X/fCuHtRAVMnGCm9AV/Yp4b5oMEyMKZc80l0g+YBrzJHMpKg/6gSjuMdEjSjMzNVYoHcYd0KVtLaFOGansJnbVIGFiuWn+ul8hyp94+l5sOZ0eUVfWbhUR45hRfxzyGB5KMygLy7LfUobxxx3HjUFS979n42YZi7vR8S9lt3C4ZUGNt3nwPc6tK+cgE+WlgM2XWNFefbX5czhp9cyZxZbg5NFoBWP+UO9+6bxJHR4HojhSBGXeVqsYXI6LxjPp7/YOs3d1Urk+R77kTI0Y65cONZFNBvPHUUQe5MP8TD87YJEITLINEmpPiCTjH44pIF3Z3OJQu1p81flHsu2mGqZA/HOXo8Gm5yHw6G3bXyndrZsXd3WM7Tjqt2p9iPE19B9vDb7O0DsWKUtj/wCvBesyzpdARBP+F3z0InWMD0TjygQB1K1Wtcoj+0c1c0Kd8+D0NskxEJunyB1d9qUmNsacoKEtQFIwR7CMeySANrnqHEk9mPwxYoF7d2xHq1QVtfh/tRKgo5MYtzdpYipXwW6QWf14iarw+tKJwjlszJSBCTmMyyC+dHRVHG8vD+FKPjc65H1qGh3zm2DfE9zRAt1kBNH+OiRNvz0ZAzJHCOGHTs6pMmmdBAivUXrRo7qrJC0wKmFT/Cub1iHrKtEdduVnvpiITgvZTLsFaBkBoIkqdOnOHjNgt6Z2t01gFfHp91/RkwKAGCYLQSYAvVqQcaWJ4lvf1Jp8+ymxwXsgtrRRdOByucg/3bQynz7Clgb9xKs5Ju+CRDWp+/z04Hfr/Zen9cU1g4GkISS17i7ccYwaF/9kGQ0xhJHJf5Hv9lHlJJHOKOiBHuXeCe7aOJ9uymPGr8sZ3Nt1/O2AFH+lpmUvT+CzDPnMyTky8TMjTvy53T1G2G/65Ym+qwJn/fkpujpt9RBuNjcAjMx5JBK1V2U+IPGH8cLyQawI/42kruJ0qWUfISnzvM6XWnZBoT9nM9ma3h6OciIsROpzzBFfCZf0g6FVlm7pZK1jNCac1zDGSAvVBSAkG5sELypoKbKjaxl/cG96xbvje84V/HhVeZr0vxlpreZoIQ7qZlkqt1zmhXjsG2y8iJ/xB6CWyBuz8f4Xgi3Pjv8cu1PsdZ22GUqURv42YlErWyMYgQlrwWunVGBMtk6Dw71NZDHjY295oXFHTWGFOkw0ppxO/e9DPHhs0Yu4Dnptpzdjiw0jKVupKbu2LUlsBnNw8Sv8lIsaax9Hgj1JpNRdfPOv7L6Z8PiaqmUEiX2srbQuMywnxO9BblWpYQnVmkG6yTGlmxwVdGPXpjsnxsmKknmz+0+0dTN/98ZfcGUPhYYIOVGXdo+BDcskvPGtkqGAnypxi5EU43Rmwjs/cQURupcSSCDeKzeebD1XSIj726H7EumyzMnXV9Ue5uwqoKziwsDbd4Qh8Aq7sVCM5jXmbYNeLCyuaHJ8hnGaFvwHdk6GSkRuZPfj9nWjGUyilPoMGY6ic+KFm85l+iQQgXrArqw4TmFOsQVBt53rWgsO2BF0zoAE6oO7PLO7mRIj0kKtNQg05xcnJc4pJ9FJc+h8rOf7GBd+wj+Bl6qYNJaQBy7VkZNxvg4h6b4Vz/slu7Xy7TjoyK1ghxv6wTUALZvG0KWDP1QW40g+QQnJFOENSVjux4WChrQ5zyKMlUKnRbtLn1tdMHpW0tpZbqzu2Yo4MtJuSe7RFWsL0+tzM9ESkal8lJuOo6Oz3UUG02t3jxZlYTim9eBgTUDJDhvYQqgkCRKwxCHTn+YkylmLL6wbrWtjoUsjmtmZDoh5bK4twbSKlPkwc2Mv/iozSMeTH+VeY/fmv/5ZUPLCyK9wDNYl+Vu+epEIpiLApJOLEsA02aYQg5QpVJwFV8YdlIsdjzF9WUhLyy4rJgr5jdlJzbnVZXSw1qftHaOaOKp0qaGey7RNsEhWZNsfJLWY1FjJDCEKI2S7dVmZCoOcmyaJ3Yq231buOOzZlWFRkiydJREwOMtTe1p22dXXUj6XH6RWMLfztOSV69KW2ziDQr24uvOv1SrTDDqnm0ewhPG9DmLb64V8q+dMsVCTsyEzA4nSGvpfUijMqf69DZYpUHW8E+ENGBWMOasRRLCsPSwuv8IUXlBj00zeowPh3aQeHLx3Ad4Q/dmIULzBaM7Pma7Q1MTgJQZ9RP7c2GeYUyAlGz36jVOr7wKpPM3QkchxbU7n3EqGRs+qXniDfbe1vpwqqXsY8j23Y/FBRiq/SYCerxqtAgDynsrvSdAXD6f+sYprgXYu4M6xaX/9pxxbM4utS9qJKPDDTK7ZSw0p4YkO4M6KvtpLioIbA1dhdqz5w7rEgscLEP0zEteQhh8/cDmro0zP44mHDvdiNhWmVz+eCuD4g/9CZQyPtyhAsQLuWuGyf7P+5yepz69u+gwXpM6sm6jkpgTfzThCMR2TI47i3Dxy1y+N8dWxgobudawx2Fzpr2beuySzubtd26y5O7erK+4y6j/2cvvrgzv0Uihq6eftc0oYzJYGuBfBvqUKZE6JixJUovbwH9npk03Kvitt8VDWvQe/L9KngrliUE7q7ONVASN1c4biee+aZ7rXXZnQdZDm4wj8oDTx7ngEA3rZAxXA90aeW3P2T4J7bFBV09gwaz+tnlg56ckSNdYE2+J28eVG7f7OKWb36b8uuMizwNuCFsRkCF3g5I0LqNWXBQHHAIIFCyETQhcSv8iNGiYap/PpO7f7nWWX4nN1EUgJ68NFROlw1BUZIZ04rhJ07L9dQogHfM5lA6kk7sjfaMZ28ZMEsF1jhB2y9E9BK6YCsr2NDKPmGatk97m0LUk40d9xNjp3avJ/xdQKmQ295SkYKwL2po1vNYrmLvWb4q7vKuaNGHqJCbtUSRZGZvpaxt6bcF45ewWM5QSZPLt0NRYUJbaLQ8nGxH/4oTNCWwnF7TLt4ijSuAWbLwQYIe0xfboLxP84bzMyKeIspSZwDoqg5KrGxYQVQVfXxsbWQiuUmQ2agN+Uyshvghheh7opqhmvVEDmfV1WzqfowRp8zVk3Ue94g4ptnBC9lIvcDAai9oviqSk+SLIpeX+ixG8RipZX+QKL7BkeBYnYzQOHds+XiaRpl6OcbgKVU9Wd+hc2ygTR+HaY60zd20NiuY4BrVkzpCbjFCR2FswHXgd4tRGf9556uAiMgEZj+9RvociTDxi5k31KqdfrqTUDfbSI78+SXXeKTCJ0/u/2GNvzI9Ud2y2z/k+VFG8YUwvzjm72qWbPPg5oasdhlq5lAaU4L/My3zPZmJU+7DnOjzLZi/pibMBy0b0t/lSq+q8y/1wIIhfw/z0xwJ71xhhaINzV1TlYLNkxQgYI6IoT5DMzXx3wk28/H/PFuHjZzcDCjLG7fz+01Wfo6zpDJPm1p5JAOsS1QDLj4vqEwzLg3mHmuAYMZnpAxkbGhhixsPliOiAovEXPJU94JrJDmhGwHMpBmsl0FIK9D4/GWal8EF0+NxAoy0ozAN1rp+wGdhhh+S52BKRymWC4vNQFUT2mT0Mv136WC8fsdFxDXSsOpEanj40iw6e5CNRD5WvnqsIDaM7c8tG/Gsjob/fqVYRA0dtLiCL9ZzsHUlvcQwUAaLvBP+/ES0kFdz27CN0aBI7NX3Dy7qu6a6MgeCvvvVQiCBoYSYK7wDuvSCMUV5tPT5YIFNZqnB+60MfwnGHJK9ssEWQsNOaD6XvwkaZAfNeFE6hgCoR7bcwP94wM9LqUNMj5u29G9hvCwMsAswvEtTvh5zIYALoXpH/yRdQ/OyKE7vUxemo+bHCxFeEfko4sOF0mrL+A9s6ueY23hk7kBsZFGFgqmvrxaHwkjiZfQWhTtcwR2lrMP20hrCOoW5iatdtMoXXJQWgFKmlaAwCs/D0vO/HKG4aNy+M67vlEaSQzeGyulCa6HB73rGHwD90iRTAnpSKGWDeXayzN8HoVeyZHo4eDWZBGLdI5OS0dZL+7D86X+zTzwCioIFmWDiJKdBiklTV5fUeVUlv3cy0xbDyHiNoPp6B2N7Y0ydo1bGiofEMfsWGuy4OgepidAiWlsyaVTZZlW5RLgZFyYCSAaPorDtT+i2FLcdRq0FrrnBRBFRqwO3fohMAt7enT3FYBegzEEMEVRBd02vCP+pRAFzRpCLTemtXS/+nknPHlSGqPFcl5o0eyUkhZgprSlmsGimjKA4/VoNAES2EDhjgPC3lf5zAVHjAnVxSyI1CYze/QyQwFgBbgWQ6t845IT/Q+HdDVMJmTShX1gzRE/rNi+CWqi9NN4AsPfq6+F7/O9V5f5wqr4twuF6SHdhMnvlTKY3vfWXiTt3czwjMKLjEaH6ESYCq0O8csEaPYQZywq1KcIJ6+i82QAkXdePD9e/P11o715k8X9VtWMas+wKhT+1NYNUGjMBlI4VJM5pWv8LJTxJXxmHDnvx1cEaJ8jCfsJGbjDh85vLmLAtIqb5e1aSKe+qUHfzcKtmrGFbi3g321v3jBnbOmT0lyDpJc1e5mH2ffJ26NMI+2eimhC5Az0WBt35pz+kD9aubPxl60+99x5dOnrn5K3BGyMjl367Yt5LeFUNw65l0eqllcJ/EfCvglulLS3Z6/cIa4InN6EuS+aPE/z9ZLlLbOTOsC6ZEsYcxxw+R5ujKaYuhsXkxViKpmCoMqUICRtNyXM3/a+A2kT9B5GDcDQDz1Kf4/XsihI47b9wtH+oFYmsMwdDagd1OoRkzg0ohmP/BwrMn0s0RhlJfBgHfv/VjI79Fw/+82sZBCek8ySHDv6LB/6QbOn/aBl9MzXiE71U8KxzV9aLe4T/i0f3R+GasrFZQppEawUhbXWSOyTzH2y6go7Ljnwwg3iwhlrCDv39w3rolBLWpjVwKUWptu2gLlPl2r98YFyvmqbQCEL8jfpd/KowHST0ytiWCIgwlpp5rJltTf7UBLTOJaM9j7BBzpzSWBeLT/Tstqv3GD/XjVmTO3G8SZYAg2L3ZlTKf4ID8XcF3YVVZOY7Wnf8NmHqO+5Wg+N7kg6anbATuNtoRcugz3XBT8ddkPfq9fKALW/bBZ3X+MyD1hpnJmXDVaXIA07JILHcOw/zFFuNXUO3DZFjARgfp0a+K+ksRmB/WpR70JepmVCXvfgrE/D2sNSY72rJwWjZt7rrJIQXFBt0EqVl4onBEhBb92O9pmWMsZGuzwW2+BeYIfBFtXvu54QjVEgi00t/20hYovblZyoCq4j58SP+5MuGA1PYLNJYZM1w2D1a61Sh1ni0ItQefWHhujcjpfrsNWt/w9qSn2+rJPO7H6kU+Ri1kLxXVjGDKD8GAniBmiAgHvBLjrJJx7pTeX47jExdSp5BOchbbHLh4/aDSIphGYw2FFBG1bMM2bmBH8XwVhc5RP2EDpUVLZgZmgEAz701H4VlCimA6oDH9X5vkQFPyi4cxQ/q7sCyMcz59E1wZvTG8dZB5y34PATPU1U0iOhZ+NoqN/7wE/6aRjadvyvg2N82T4tSN97YOTIN3RlUdutPgQ+GVOtC3SUZd02icexFHmZavPOa6uctQrTdSFK5h0nhtfORzbcIpSINrW+kt/n7mWfZC3cm9GdIqqSkW9pK95St8u97fRnQSjf8uTELuWi4eV8NajlbVeXtbNJtlGCuFs+Aotknj7LFns8xWU2JzISfZKtRovYiXKvqlZEYfbcU75JQGYgZM7yL2SbmsyxHMWBayHfYhr7XKd4h4RHz2QQJgOttJamZwVNxqrW7LiXtsY2DfqArLNy6HfXwS3ovHLd3Yno0IZ1F1MeTQwJD3mUqcz/w/pkUMvHDgpCz1FBHeS6TEtc4LaMC/k5uJucM9LWI6gYK5YiuYDh3UHUkUNSMMCxcgYZILm2Jm/vF8R5WWK3+4ocuPxclvK2kGws+PzJXbmi6dt1SSkboH5M7ap3b5qBeSI9SHrjHFz9lPmB5rXMl/UG7MjCczBq82w37AnWRQOBJqI+Y/q3W5NnvUElU3LeNyLRipluZWIT5cTeqKhr3AzDBTS+FpN0wGTaNiqxXqiPIxdalloIa1V4sxvb1UolRIkcjErfefKZgdaiv5jZAz4wRh14VCE+cZ1DytV1rORZLQ8wEVOklBbkoMeLZ9VtdahcFQ1U2BWRcyXkiN4o1MlSzqlE3FCUUKAr8wmkIv/tHSrtjjW/SGiXDSxhliL8AGZcRyHY6Dz8apjhWh6egmlmYyZPRF4jqiXjVfurmOci3XKyG1QQXtoNdTRSPVzsiWasxuPWhBvf4U2IzJ55IqcC5sxQi2SUlSZKTnGV5MaFvUbZZmmIUqLMARP70Su0Ar3P62eLu0J0veh3c8LfLLI+FABxko+NRxJmiAqRt5msCAqzBYPdgnUMsvIMYKoLwChnH1BZtFEh42i07Q0gOeHe/jemW6MAnfOgctHhNI3lfqYVHhywtFiMhA73JleGcAs4296LRsUaCfxbWYmobrox7cwqDLJxFIsdFNtrUkr2clr1IWy+BuRmhJkUREVou/ccSlbKo9ApReDrkqWWZMElT0NKcIGmuGHYXlzKfIGmWy77wX7wnI2pqtnfjmY3v1vbs8c420gp0Nj2dHOX+tMhXgoEkanBUCVW56q22Hm+fOVlP6tmp+8tV8JbVFccLuFEwCtvxIqM2zzs/RnTviY5p3jK0S3inHxpqdzByXLHK+yhdcZd5Y5yRa2xfTu4Wxcy/98Cb4VbV3sWOgd/6+uBmbNyy9frdIt5nHSMob1Hm9DT+/jHCHow2sVFRprMtWPbXNPSl3H/4eB3DC9dprAtfQxGT3cyPFLhimSWfF3oNEVl70eFG7RjBA6mSuv7R7nA7tgUj/QqQvwWzO/ezQx7YGbEpIjNYz7GK9s3YFSbP9rnJA6xPbusuaOn6QyYhs33kcmYXhhhjTHeRyjK6SjHnZ8rLr33HIyr3bjb7KfAz2VofqZRitXANWqxpT9TVCYy73ZQeboqKr6sjE6QVKmZ8LE8sjI11TaivgFgy5WaUTAalYM8bSg+B9cGgVlUWBZEJ+i7uRM6q2O9Q7yfzXDvEH9yZ49ceanSSQGU8xFd6mYajQlxOZEheuRMXSiqf10GkV3z7JVOhin13DMcdWR56SNm/AWGQKvvdbk8vR0Fyf3dkmeN+SZmcXBXmoWo2X474ce2hTrOlbhBWKsXPbgy9VW3gApuFqrF8w1B0By8ZmhyR8dCR6KUxSikf7If6qjmiwS2aHB/Qm6+FCk+QJUqZgG+U1mkrXW01ytzXBJQKNyPLj4FV834w10aAjUjYpxUeKpxQGOPEZDSUpIGNTYnwsAzOiALP5TS55d/fTd8orxeimDVqtbBVG6LTyIiu1c18YPFhP9UXx4Quf46OIsBZsPsn3oqIfJXj7N7zbbUlcz4xAmHiuitL6cfGjIXSSV5WhOGyM03veIV8njw5Vh8A7491FvMjX8Q9e3OgUf2LjwdE3fepiur9x17HayU2y2qdTepdbjOpvr+d01CeNwDsINu/X8ZKWF7s2ZtlNZRswTjQ98s9lfdBa7QXhopUydqhhc8Dq9X8sBRm3c7PZJd0QARblvYxElKNonFDG0otsq9sBsUY84/mbB95bdOg2rDtJDw+e/1KZn9tQyqpBuY13eGQVXuOO4nqb4tEr9fFuEmQFCbWOAL8VkZlM7ekJiZeeT8M6clENVJH66x2w4sagQGXwqJXMpFcV26oauxTr6G6dIrWHB85YEvDdaX7FOoiMqp+fq8QfXy8il0Hjy+6QqmUAosf9LSLQ1C41E+bUur9COmszAyrm/Uv+nTW5Ql0ry085MHVVjpqjdwlffpJQyz7OchHIQ2rNnuX9CzwNKpSQcNQTpm3bXvvdLNN8qFT6SPzqInpn8d0GI0af8UyrTVWwyPLMq6Or8u4TXh8oSeZRvJR9nCKwCkef5aQn/KfoQy8vzt1Xv129Ja/F428x6y/I2qHPhdFZaIxyD7WfNVkxZQ7rzKvx30Q0U8jY3oXNGJXiHW1bZ2eUk6ws2VJSmEJ7fPT4iQ05i/VcnMaOw0mlZYfN71fxk2hO2/DvpMwGOU+dmHc9MWGEkS3UbKKP6rSaYvo3ApmB9k0KeAw22mi2vi4ERSJjhrlACXaqhOcqmzUGMabB72UbrsLlrL52d26O2/yXCI06j8WTGPXeRXeGZnr9fVrr9BCsz1fgE4ESWvrbuL8PpNl2mTd8jRTmOZldVYcVxvrPBQKEYh7hUEANx6d/fC1Gjo8Ko3YWMxUSEMtbLYbC9A6LtiiygJtcdu9jfVOtC/HjIozSgmUWkUpHwIVZ3yCbRdPbjakTu92cpbYrDv9EoiNzE4H2+71T4dL3yQhvUacxa5RyTVaW4PXkFvnUzH704W6AQreRMoQx7x39ogXDYjfNU5sngteUNgSa4i5j9X+fkQR8LYu0UratGNvkGIs0PO+RlLQRq+IPWX70nR/j77XyML1mbLQylWw4+c7HvUvHuNio2i9bPoiwtKJkVaRPWofju2NshI0jSn7LzJBvMo5fEUKUxVwOjzL1G4SRO4QTFNeI8v2davRPN62Ki6cSbuE5hyfndOqG0ipLjpaEvHARPuO9//MNt1xhjpBw02OL7dUbFOYxL3Tu3L+uyRL55NMSffh4Cbc89BpqouNISEx0ZBJis37ku4scoMyKqkqXQuF2F5Db5K8WBvWbnn/MwIri3VM9pOwNUvleNqjUfZg0wtMtLtwSHHxxpEeI/zRmDnRTRiPoteYmqT+oLDUajHXRlYLsrq1URkKF25orQzbWjSGZ7u4MEjFc4TOegEdqxpGhx2fn+rJDaQY2gYfMHJksb1j6yjaqiZ0raMpp1sXGXfM6BQeg57o4Vs02XryoTCiQ2yzefhvzcdHo3NX2DDa7xcAqubqvY2gSodphwQWSwXeBNzqDmKuqNODXiaJSrOm8gwSyjcqFJ6TnIdSTMMMeVQX5brF8CMgRM+ZgzqWQoIShmZeeMEWYBUVDA9qmVWHfTOFlYBLZKwIX5/RvqOFJLgx/lVJtJyn/7/blJ34UQK4ef5/bLzMQzlJOAqUP6ZIM2MvXMapd/H4a1nozklw2pIb7fYJINYwSodRUgr2M2e3hnY27UjWjce1FYd1tBTizYJRHxL2Ypr9StC/PvDJWa3AbKRUN1yKKw0rrVjw/pihocPcan21ohuSNUzo9APvQTgNuIv3n3RPEDEP/tYsLBX0ewUxFFltztDj1gyxS6FAhZXCC4uWpTgMMiqaDiIiCUB10ldGdmUogpuxoY93NrXKdAx9wgLYAgcsUcCyc+DBkByXF4Qi4O+4MoJg8l5it4QH0jtJCqajiy67yBqc/d6mhdsySYIxSWDE7gayn9MQHh2lUS25Q1SpHov+2hHGccZpFMc5+el0vzYgEtDbie4K6AaFv/BQyQyvzxy/QHBIxROXSxmLPHkAtwtCy/CgQ3WokoCjvqJ8ASsY68AOvhN0721xjRolNyvxPJzTZ8c+ytRyFaIje6YQCSof2AAHJzYXRoGdA7BghTeJMxEKLaQ48tMeDRfi6VG0XY0NKf/INPac6Ivt2T1JO8zGeU7OipgDtGWmkVC4dS84u/fMarBKCpBgmgKZuTZPXBRUmqChy67cvzqVa+jR0a4YvQw4h8usIwIh97+zfOtm/yC93KENBBiDWd/N4WZUQWIHYW9/0iLj6RnTpZuRzTcfT4WG3S27tCSuu+m2plbtemYLSZFlSmLKINovuXnDnHy6RErEZKpNHotRfDC1vGn3537OUWdnWRDms99+noz+7EnhcoGPwbS+NPq7k3VTQH9Ip1DGSY9cCqnc2zao9fKBrj6YWjEIf4foK5N2IJk5cJkxDWB5CDdrLQrPS9cwV2Pkb/pQ/AqmGo2R2ytzbSkdWHv6R3I6acPP/wXr/szg5rZq0K6xAvBJxq3am2OdSBVnlKLvF+i1cDeZs/04mcPAYbtwWkGLP3j8TZJ3GB+tYWP0Vqvrkw2Nj4zB8OLiOJ45vL2BFn7Sz/9MA1Widu9rA2tNj7AEZyasyYaMH0McWB8s8Ukf6OcN7golEZt28UmUgM5Ir0LbDUydh3hL6U4EP7K7CdPRjOjfJ0yzLsXXMBm7OjlVlJgk7jjlNOCTcFpL7ebd0VYxoMlGOdj73WXVft9NhBInifmBU/cmpElkjkonplFULovGZH62zyPQ9Rdxqg3eHtX1H0ZKDwufMmYHJHD/Cp+9BB1JtTy9fjeiVdH8yVA/qRimxF6d3AsKbFI+bGrTNg1rItBsdVujcLqiPEeRnsrxTuwinD0TWG/7pR02K+RfQelNtGOAyB7KKrBXDlxUHelfgAHN9XN5eLbpKh93ItNE7LGxZES/b+D5MHRfiUxz23zV4u9GbmhKByRuIEqacuvKm7jyg6Smvqo5/CX4C9h4+pd2aJGYOcBf8tR6ZHuovYfS4zej+YcNk6sx6iTk38lhmrqnQsFeHvb7xfJ40oX8YTGaPuMTirIPwjg6/WtE/Is5J0+ThqNDdR8up2h0S5LxiThiaj9P2TdwslMuF7slgkxh30otVfH4knrEhNUii3SX13yXX6JnrhyV42jbfddDtKPPNf72DSn+TnTGiKlvz4KCRVfwHq/WIGNjLOdXzbS3sNXl6Hv4VdeiZEUvNXPeTm5Lpl1sdy1VybUtIbzPY34usf59bRNaIb7kSj6OSIzIGbLa9fB1XEsRODVQpZ3EJpRhVWuzE5UsDs2CZBOPlxF/NDv+uBIa+wCPPPlVCxMEqkzPKu/wrOKrGzAdwvhfRzHcuZSs8BwRjczxdElRpyChJEJWByxMdeAOBQH5UKct0iNQMkyaiptUUj3QiOvxwkyPmJfMO6araTLA5/5WtNQKbY1B7d3DAgSRo/QmU/9n0ey5eDFvxH4n8JpbWrImrkvB9haQDNV6AaxAXyFdZKYs5tHlEiuoWPUm4GP9bCotvl/LSb1ncnZDzAupEI08szK6KqgGRrsWXFJkJLQ6KjSYO7knSBYWlhI0M1FF5VFCuYwwSbE26qlgBMaN0ipnPSfAx6kp3Us1vLPhpDhJYH70VNTYkSWv98+isG00ITGT18ExMy8xPyL4SBqREuro1zk7RlfKZ93qe6+r2wcL2Fab7BqbE88pHj6u0cG0ka3pxNcLwRUK1WQcUt3is3icRx0GeWMbh2t8urjo3t2Q5P8Y8/WmEf2vCloIttb+PdNUi9ddqHj7pyl4zLt6+/3+K3zfvwfYlg12bMBGz86vnrZP8eFrGpbAUQk+lsDMg98fr4+DYnc/RJGnObg32lLeXHOz3tfnWFzPtqECpThU2KGMzrCPIINF0mSoU7jyx5uzaO+DoPjFC67NxxQaU8LNskx2iEL2JSY+bK8XJOJH5nJWr9qrF0InwDkmY8Zk0MzyVREgCXiaSkSwxQebJFlahmZJoKciMze0rIxJXb0q72HkUwYm0udidQle2NO/AwJwRN941Y7gU+H/aJ2YD3dAHYj0rW4omH8a2jCWtBMBi6+wlNBn5YydjUs/rIzOVxEMv2PiFVUhclGqEl9b9+ghUb8yKS9mgahXHG+oD1fSIUW33oQxGuXpXpGyJqoqmeWP09rNWXEi6m8ftLjdyoGiPN9ufvJTelRyIUXXum5C7mOZoEokEuypTlHNqbpW9WVAPFVdCUgTliiN0oBP4dF27lpTcP9/es4FIHQ21Yx9XkAU2h09ZsWeJZRe7q0bS3SA4sSYTq4jckJMY+JePpp4abB2QXjdnxwFz9tw+PcOxx9PFNPgzWe8iLaAkM5We4lL5UIngV4WcZxIWIqznm8cuxCMyWHg2AITJEkEqMKyBjRC/Dd0jf3GzIjz73LDOKxUJhPSsPDQXuiK8oWa5fmkRKOpTB+hbFcTkkXQURLCmg0suBkbMdiKNi1KciynGgtJc6iVJKaa1uL+NnsVZXYAsLWVL/TrUtJ1vWh+v3dYO1NUjCauprkZXIQBFHXbULfwE9KzJ4qJnFZSMEB1o+Vzf5/JoocGadpvE2aaI0Lr7kHVnssl1YMaOBBXic9T4RRHhkY5jT5uXLL+Qcctcwo53snoluTGwnrHFs6ehU8jT8tfn2ovu+gBn/YB4yTavBprea/MsS1sL0gi71DCXHbp6d6skCc+uRWoYxdeP4K2gFlAr/oL2OuxPyvLSmn9jfx6cBzQODtsb/RzFIpwAluphrDJ+BZI3wHQo8O3nu4i8tvAjZkb2zaIL/e1WvvDLq+15Mdw80G85DYVs5XoR1NYlAGOY+efMtXmOlHxjcdXinZyE1B0MqNncIqCCdhSk9hifxJQXvyCIrKdhbgSrg0iItNNXqpwupjkqRHOGIU4pSCxFYP9hCSY4Q0NuE0vCJUWY6PNzzYWyAirD5Gd8T8Z8oP/hUOWWgNrem5PZF/+pbm13YEHOGpbve1uH+ds9PVDu8mVkVCzGsXaqO0nbXWulIWsU0eW0XF+dRDtaGNduKSwJa5sI0Z7dojJ7VWTSDekXrSLQFcyrUYwYd3dGO0Yrdht46/AD7Xa6Dd3rYZA2HCKBqSp4IVY+4NfBUUk1CGCRPmPitxdIaPLq41SeGT2yaPYONhY1EWh1bhdMaojtmvqalkIw7AxGTQ01wMIGvbyuKD/x+XWpY9R1kbSZjDxX4Xrl9nwfusX4VSt9FMXn1K/G9U+lbyz6h9F8fEICNlYIU/wQxv2wNuTufva3Y1VJW3C+ZM+c00iWO83AqE3DD5KvViE/GO2yAndEwQKFRZ+ijVeMYkZKlpsLr0itTa6Gx5OKST+avZzkpnJ1zIV9+DmvxrMifz91mpx51Nq2bdu3r4YMNCJIglwUFaWVdrwUFCaCFiaFO7ItsRe86UWLWP4ajNSz7baKO9j650xbodFvGiaXSc1+1QpVRkCggDTpGBquO5JaTO5xYQc24e7qrxfKhwChI+SyezpekJUluh8SgoydY7jgSLx9T5UA183+wGNa3ada3xhq7xbbfSRbf4anHlJsZMK56TF/AzoWTs+HSTbQY5eaPMbfCkHlyjyMItfjKMYHD/TfXqTznSbBK26HGsv7t0R9eSxRabUYDndNFAEMQHukZsF4js2Tz6xwvKEE4xPmr2aaS/3Eb50yr0mM5yQbKdxXNkmwCPJQquWU1CvuUBnIZ5Ci+1Kjv5KECkwSKZQlpPbY003FD6pWnKVRO8CalU6HGG0BpR1eswMATx8VTJPK0gKa8d4ps9yLOCbqsvLhdcuEAnDb5JHCRonv2yzMsYID4AlC8Iwcz8gYC8tzaHnRcI81AmXSMaVXbjJ8oDZqItc4/OvUuUKTVH4HdsvElJKF05OuNqZczn2wTnO+6NS+am2+tKP6djXMpVHzoTjfDCaz+gKeEATe/lfRDuzZanQQPsk1EZhSF2FqTHFVzEr2AHkl6a1eNJkSg572H4abCoh6TgigoZfIiLHQKloaU8QhW5yLqxVIYxeSycBLQPkfp7ASUqFTny/C7AcmpB4TFdbUKeoYmH1HPNqtSKkC/3x9FqGm52pqscRNlQSEp3TcKp9dKOJmgD6PSaaPAIXQKYuoLtc9qFtYHFG7gPSiBBpRrfAsw52Z7H2+G64fMjdXDri5ALj+JS0jUltru3XgI2KLXkJ//XEi7PyLHpRHKOjofYW2RfJQn1frE3AnWC/damUqzFdlJqPMpOUH7AwKHOmVfxAmsZNzwEyi52ZEq/KKSS2sZ9ArTHOp1jAW2HRDBzUTrLVceLlmenz7q/dtaJodlgbrhm04IKmiFS65F4IsUn7yI1tTU6w4EKs2z+a3wppTNrJePkq+m4rtzFgZwo4LHjPckP7YP7iAuw+rDXTw3fHlYadQ+Y8SBqMmDLGDe2qtXnSytoULMJhNRgpEIg00qFz8M6+qgEeTbRWpXWU02pj3s51YshldN9p8gLhIny2gBeGXLf0AKkn7HiHDb1UQVi0uN/iC7khOaFnh70zKSGjgKZFMeRCwJzrqhcf2aadqcIEuV4z639XsFcoOf5FMAaWhPzB5rglHlxm3/awBzx3IL3zgppe/+P8TR3Jf3Sti29c6ewqcc0uF1OYEJJEXYXKzhVr0QxutvH+RoVELFjKQjzFAnJYUEyqez3nLGyEgOkKmLv/e8XYkusPHES4oQR9cFyvPOt3UWGPYiB468T/l13HgitnpPCV6av0dN7OILiln1FqbXLm/YoPnRvnudQUv4ZA3VZiDJdp0D6zFngQ13OaZe1MEQKjSmKUb0RHSYVo8zF6wFZi+8EaotP9xN3KCWl+oQMsqprHhBNAHdVdbobrRGJ8M2l7GxssLHHEH8lahdoRZ98tRiJOEUUEc9wiNQ37l1j4YEI6dF+aQgW3x77lU7uebUZWR2JAZDqOmZHV8caKxNT4BqfHJQfSHyfJ9RiTmKjM0Sr/wgIa2SGp3Mkb5wHDMLDMfKd5ZgCueg8aFyL5h+ZtCNgXT4piAZrI/ixYkoBaWFtJC2VoRY9NTBHR47amloGqT2SQ0wi7G8FT1ETtW8JEkVu3XU9HCP0VqavWiVqeHQqSbvh8la+ZpmLssucTwPjvbt4o50q81anvmMiXSQ49KYXDtmnxJjlNUmHoASHl21p3BasYQKs0KvRKiaPia5bnPy4Zqg2gzayK+N5CoVV01Ujr9Zbf3VfxACoH6gaI7emdtqVSlTSoIC+jLX1liJhhTHPVf/oQfXcPMfQiNrwvi8/ybQvdh8tMUj/vmbRIVTv0UTxIpAaWV8lIfXP9+phAf2qEM0cCLC5aaVufy92B30ffEf59WF6+5RxhNAmT9Nzgz3xl1jjzh7cmfa/EGDC9suzesy6k+PQatRBOvHeMJq3kizMKE308kicKU/Tco0yJ4Db3ZXbbfxrTnzSfPBx3qeoAMRhhuAk0dTt+ajI+3vKGf33XxVQrMogOx98FWNJXU40/SiumOLWWffa5U1E0Xo57zoAYBqvVTAhSMfP95biwKQyBLCACmaZv30sk4T4mRaDR4/eIniI7LJeZUxKhc7ajnKBkBgsGO/lRUN+u1wUFbouVixiLghmpVS6puXE/W4oRvAxU5FDo5xdKur4eEjEmUXo9EAwxlpv09n1jiUQ3we+U0qqWqlPF+fS+NBjBkxAcZYZCXY8NfLqprrCNM0xDK4vEa5GaOJiKYPrkvHskexQRiwX5D4HhDgJGI/rIDrEWGM3lAzZ8QNPpLsf9k6GbLTLIKk0qfgyOKi3f2ZPP94XT+g6Ox0zWd524NT1ywj++uKTY3x9/zPDOoNy+uRsI1WoUCbpIDrSfJHi7Tm/uLnpSD3+eqsO38GVOT7KG8oe+zccf+0dGFGBCwMA7WR6wIwPQajY3/JRitrV8miYXSGvNQR7zoM83rNBsryr1R4ZjYfo51HTasRO77ylYP2N5tymm3bQ939DdEY5VnYQ/e1lMK9HH31PEIAp+kUcSP9RuQPXBajHaREYwK+X99o/3XQ/UaGs+VaIo2aQ+ONYf6wMa7GeQKSDlR1lZgcNc44BdHIFc3RNTNInchEi76pxZ/48vnbZWtl19ApJutStAW7IixVdGOw4COd3WC0K/e9QTL861e0nRmnJCzanbxIfp9hTxrE1xgAM+tJjiLQeDR3L1qFFFFFGwZOLtrnd8lPL5pmINH7LEGCpj/5Cuev4jsE6lNAfGIN6zoydWUebYLyZ8Tvo/u7fKzfB8ZInt9Qa6UrwFRUYe0VQh1JrTA6UGErLHzSIQDrAKRPn87pWmbuWZDRpkZn9UbdkOOI7VD8CUIEKwv2eabk9vlOfotSLaZ1hfRuViojNDk3zBkL37+EtF4ot7VAuBkEOIAK5hOUUJZTpgb3uFX121rE+UJ1WYbV/sVOLu1mTb4ltaF0L3ldhHbg3dOTXKe847KB2QmhjV7t8J4OZXCyOBvi5B+qubEzExuAO4RE5sX82Cd6MSLj3CgfZ4uFu8Vh3q6h7E+cGz/GBZyyha7E0YUl7iDq5cjxDF4mL0rN6YZ+CQSo93NMJ2DImjqideBPLvgVzKrcBWtWCq7A6m6nmoQwfKJqfVEDZSHHuVsagU/FUd15RcdPA2RDO9YNKykFDlnLgT+ED8e4uFPf2f1MLbJK0k+lKCmhFTAcS2Yz5gbTLdPi4NP+wmdWKEWllBnHlIG8rG5tcoNj7RRShMOE/sQmno9CdlyfDSWbZeSQQPRPEQMLt/DPLX+bK9IGZ5bgi5ajrEhumZPnqEmHDVFLVjOLAnUE/cv+Df5mrHSV9ApvNiMkRn54hpmWLEu8kIik8oATkWsCBI3XXFeCjHkIXYpoJRoTK+NaQjmR2BZ6vXdEg6nKWYxTKybM8pIA0DFTlchMb5Wl40d5paVHWlswt58nNBYAOilHgHGDoGxW+Ny393lwdbZugz3hyyzNutI6zw9V1FrCgqwgoOeX1qUUnTCO6AZmLrT7dPqI2WVVWBwdiwEhyNsMIMgnuMITUAs0E0BgZcUyraJOXlx/IyioM5xRTnizmy8AwZsvMWqUyVuh5GDbdR9e2oKmlBGKD4sWlUoMFNFzWV7yRqE34nQpytp8ZlKLVO+R/+EKz4NIhX+F9uRDvtW70OTSoafxERL/07LodE6N7SpB39dIZVDXNs5n8QAoPbkeTs34Wu7U3IJZN/DocfzfSnn4rdOQZH7AQCH/TVV7Y68WL/gOVfdiEI908QvE7eCNmZtp8ZTLU1SwKB4b8L7dTTByDvxVZ8OacP6kJ0j6XXfdPsGAojnvpl3KdRSPLT2yobcemOOa+ifewIWJ/wx8KiEBSxAALGgY9kiX0UGeVcKOYlF8Fizu4xxjGfNeZ39F4vBTKZf2XscNayMY+65uytOYI33gGAQZYzSgb9RVFIhcZVbrswTTGpoNIvJTWq95RZlTTr8SsMZSnss0fJFOgcFksg18g6CiqWuMcUuYoZv9LTL3ZAoxITgvKkQLIZUGKeMHV7Ynkfqu5Pr+lpkpQ+Jg5xEyDzYjv1daYu+bVzg7xNooHXyGitkai33C8BmzyAVZlFPumomWKiiMfJSh/sin+XtMkrDGYFUraCDPIHv2uYw09TVeGG4vFKwpr5uRSdl8XcaF7lHhuN858y+nNpJ7iaW/HoyxyBKe1OKR/+9WUIMoWO9iv9jjp23NnM5WBKfC7woP/ef/mXC2rNb8HQ7VeIIxlNRXzUoqYeUci+T9JvljaZ52Isxi9m8Zt3lXhOERbPsFVGeEmi3S9sMJhMWqMAzCwW6JMzn8Zcw2Oe/pKFoM02aVgkbhS1vlJa+vxeAMmB1GA6E9gtOpx3y9K8q1/eg75IBiyY7XVmUYpZEoum3MtmLH1Ijg/HQQ4veicji0zFxtHaCvHoqQEVJXhbIpihmIzNG86lcVWyV/Md5i/MG305gduGQqJAM6GtUrY+E+fTjnGT2JP+d5Srkvv9kQrPWhpy1e0UkuXrdtTFn3wAY7vmMW4f0M8Y3twT4Cqp3HhzLlJqII+adasBFkcWwN3qV8O7B3GkIo+F5d6gQkeikuO21MtNmfP17ru055MwE9kH9MyQY/sByqooLeZ2mYWMg25mfhvvA9HrQHqytS03DDfGiAlGSiWibo2lqc5W9c6IZV84SNylFG92xbs4f5k3fwjZLcpr7o+/bGmmSoV4vq6oNFhjEjuXAlEaMKUE67XNuolwk5lkwjP8YqLbyQ0yWsLT3J8aU4fEH7ZqtyTOdZsH8JXTkHUWDjdtTlhpIb4JnWvoa6q9f/mG2YVdNN+Zb2zi/Qw2T5mN5rMif5l4rE2VpoKl+2JP4flmBimc+DZHalh9LqZc8e/UyoSS7wv3aYeie3ai/Us8srK/WzZ2tzWazVUx+bcxSFB8uK0cJ86VzMawIPV765qiEa3NkbqtADGVJ/8++/FPmGLin+cbHMfqO6d9YI5f63I7SQqXJk4v3qceP+0LmxptKJ7w96elemvSgjecpRdUFINkwp1Il9UQrFguVn3b+5Vk4Q+kkvid1aY0Etma5e4hFO8ux6q1OIkLguh/cZNzWcG9T2DEg2BaWNxoL3I8ddZB1NTF5xrQvG9ZGvIUV7WgEadkqjK6PbBh6Xfzzkd6OU1NCo5lX1tGTla6e5cuP1mZKP0nCXY++vWfL65IMmIOFOwj27ggjvHGe0Zdh/VIqDyqHYux1LXnYSHvkw/3VgbD3/gjzvS+lhXHMEQb40Mz3+QJ3QjXxRqIP7w4lXFmpV5oYfEhj+0bZhDdxdvnAia6IrJ8aGKGCG/mRzZMXloUj30E7oH/nu+QWc26M7Fx1X3J6GwEw/83gHwDkDQTbD/vvjcSo83lyVC7TmHAvqKA08pqiua23/DFPAXZqE/NJlwnj7hRv8ypSuJ2o0JQqz0klRD7xnemeFgmsyIzTixfIy4dZixvHzCs/nwRkhEjNZu83uPKS2ZCa8b8EWsEVcPkFSsS0zefmb8mmjUON1YKaZtI4hVZsMZQZGJb1fTAl0VhKmp8rPRGmWibRurVM8awjxaBmecmSuF1lAUoOSlr9fcnlpDBfzaaP9+ghX+35/Tf7PcZjt8tp9TS5qzmRlBGYFnCb9EXZ0IMfG4sRd9aowwndneIyMIhs4kAGmtyZQ6vjsRe9yk8oUgu6pH19qwY45WfcMrOWjThBzOP2RTo8eQFG86BlFqyGVZK1qC1W3ujxofZTMUam+cPKGGEMibb8QlmRNAhFvRVioC2qKaZaYRT3qaYg6InTjUvWWCHkZTLCjilMS5BvACjckYRmsCH929OnU8nbKTl0XkNv8m736VYaNLk1iVXFRz9UuwM7wQtlj9zu0MVbt2ri8S7Hm/avMxfLHmovu1zmw33tefvF93mWDrA9BhQu0Omc9kTDb3v6xOL/Pf9mCf3tueHTrRkSjGHDBD2P/JHd8cUlmEuJx2+Zy7c9AX3TyLDasf2OXQea5dFs8BBTjsLojB0GirXvHuHllK54nogGsSFUFYDKQzyBejxed9I76nLWmw9Jn7K4bVxfnzdGZFvq6ZRsF2C7X3/FIv1bkTL8sbQsHoKpaJzpcPqeE4HG7tXYdjHT2nBJgau9fLBotp0skLcamGBhEWYfHvYJSq1RNGE3IzJnharcH4NbE4X+zj78bkCKrHYVvyMkEfj3rMJW9doytvBIjIWNGHUJeq7aUOfWz23l0uHyWP/LkltAuXgS1b7hIdfgIv3VehBJ0zDHG1/7yzlpt49lfTxY1IZhbB0CqpH6F1LlQzChH1SYtmTFoi2IB0FYi2csylXk0qKzyPABoJDOXdDg86JJtoReFKRLjCeWHTmNoeqJL5n1K2/3blveYx/hsvU/r07vU1q+g6OvWs4xb5/NcjAosjYwZDtF++xmBbs3Qyl1pmPVt49MnaPG3rDKM8PzBg/RPZSnukl0R+YIjzxBtPSrnv/XoqKdCeI1WtJRSQBVUNUDvPY5lvHTqpa3aBes2JKOUM7+EdWLnmcuBzyCe6RNNkKtWuGK/Wod29PGjHKDBYWu8Y2MsVzY5r9CXovc6RwnfCbDaS80TmlGJbAItHxoRkzSTxQWSDXflLhmswvXRJbwOoVSSBt0IuI1ATctR4Ab+rDpCWNllWJlt4B7JGWwvoG7uE0hZj5VTEeipAbBfy6vkTiRXTKAdpAfRDiodYWuQ6MAF/XtfhZGnyoE1oec2KK3kl331n+vMsoNlll8v11PhPcAtHWAzTp+Dnd+AuyV0t+mJkKFvjppBjkNja5CKOg1l7OlJ8w3BDZ4CT7KQ39de5Q43i3MfGxyHDsLLS2WiqD5sd6Kr3Iv2zhS8NgAVRNqR0zf+gBp1sxrWO4DnoWLbW+2vfjedg6Y9kdE6ayJXSwfqoIKdB0Ys6rqtLoMiMR9UClWXbShCxoB+eqj5EbHwqEe1K8kUG8co70WE489kQCARJxiZKNiheytnosVkccFSFclK7VfMB/z+ziDCWmYzXkpO7dvWZP3/1D6PEeQIbKN6QzKmW8uvosrXuytZL5yOEYp7nzXQwdx7usaNQ9YysZNfnHsW2tU/vMNV5+KtGy0uie95mFCvxpdfHAlgXrIl7TCf1rKcYNlFhRxSk7vv14wXLk3ubc1/qkD4YNdhtZvMFa50tqcUWVGruhfr2Z20sd+WvCTXdiW7+ltOd1JUPji/doQNHUMLYjFw9dn4/y6R4D5rspb+U71dGIGRyJ5WIuT17/QfU18f6qapDB9OvQuhlEDsVtqArLG8ezlDuqOYSwiAk81pgj1G5lWVvurhdUMBmr93p+8JsPIu0eyYii2Mn5OGUBiXB2VzK8CJTsx/qeEwAPYm7AgbBkA13LL7IbHCNC4MADdfUvkm2WfXEcE+b/oLw+RuoFf9WtcKLug38oyKm2Hsw+3aJwHYIYba774mpjGLJS4G49uiUvDghpcN+7C7KwdW0boB7gXI5FVkVX0lkY85oTN4FTEl2VTfVYDmIpuesbtRZ+74QJqiihDwMnn1a0O1Wj7PhN3PXnVFIlCu3jOlIfvB6LCQ9CxQIQcEjCHl29P9wvN/XuDDhJ+cLwDmjDk2IOyoaP8YVPSEtyTXF9/epXifxr/N4xZV4vXji0s5eSgiQ9r3xvu5ipa/Xs5hNC1GH165us73QW6SiY8LLA0/0/aAu+0Il/jDnlDPZCJKKu+p6pV0XkVJ2okzXAoHcVv6VbP8HxKNlFFU52cvQrEUWHjLulmRWiyHLaTo0S5eyDf1nSSLX1GxNfd7ujaHqa3KMZgS8J/wONL5/8h1mnZ7LLlgYfxcPiLhNlKdRUevoo3BDiuHPR4GEAyseanlbfiPCQQNxbBjmHDcZlRRSYDj0E2+Sh7SmY354Do218itPvs7O93JjGxWgRZjPFAZ8+KbCKF8gnIzOWp7Er/GaX9nLy9/jlHFF/FNCV8om9U+TlII/qBTP5lroUzDfulHjtKop4YMMAa35A5o3jHC8gYxb0wS2Y+KmecZEnnYw50dEl1dkBeY8iiOcwb7VsWBhlVxv9giH0noS2s0kFKXks5zau3EutaCOzpYvJFZb+C+mYsIlH1d9vTaXJpbA+pj8jj2r+SkCiK+fLhg0cln9eNUEg0aI+JSMaiwrts8wHGXd3nyO8Hpub+RYYLVsNCYp/4noPqBqqss+fsNsWWjAD/5Xg9rEku26RiO3UPjlEqFbvQD8sGdoWo//QtzuVs6cqRbjtq53gmvH4UhEP/+lfufLWKh3WqeKL1+0qQzt2SOJyHNzDPj4nOAkt6pjrfUa4cmJfdRGIT0rvjxVtCEyVrXgrEYaY6vCWPE52cA5ouQyZdq8GucIfAmtGQ1i0r6RkG5e5lxyAX5pjX7ZMqSHgw8DWyjv0BctHfw1zfWmpvTrto8RuBS6A6ejHijgEWUbeMVIBT0dG09M84YsfiBk9qfnzYhtm3l3zyUf8g6clludCJk0d4zZPmT/a6R7qFWP/W2uMKuGgcjOWJ9+GGRx27km0z9uWiI5POME84uFdpKN7g4tbv9c+IV4Wno2OaTP4ist/C39lM+r84JqwTduMiR84rG+YyIc6JjyYUrGchOdcfAWxMXP6FI+uMBE58n/Ur9EArvSsLts81uqMMQ8CokAhsurYKXrdrVCE60UpaLNBVYVnmWW6FnRXsGOHToyAne/sqs4G6CxOdEYNI48Um3HZ3h9+tsKi3S8z7i6mnxtVzJODhQf93BQMM+FZW/2MeDnyhXXvEzEvYhZR/mzju9HVQPsU8VHn4jYsWDHpU0lrZB6chzmUZtsYyGBbhpPK6PxHOwnF8XJBZzk+9m+AZs6w+p8CaRj233vqHtph86gu13uvsykthymW03tHcXB5jLAenEHuvqulVZMb9yO4vIjT9QPPES73zu42xa6qnA0vG7PutYy4Q+HIG0BOOwReOKnvLsrYW20acvoAF0V5VQrLVg9vspBMeBzLxrIhpGLOMl+YSR0Nyz4xQmb+cAx9ZYOMihIxvX5sNKsCynOuUn3qeKhk/BFhS5VL/BKjGBJzZ1h07h+ItIlFPrHWU4WXiBrzTCu0IRwmSJ4Rz697oIxKS6uci8lnWNYZTRA8aiSRoGdF/ryjHia2gZ1rIq/7mF5xWfiT2crQa2BDW8RPflCO+b6zj9MkViv7ePLM1D6ZSo1XDVhMdLAxWbSHdhsc7KGLJZXAK5LWKZGqG5DSspe7c08BcadXC6M66nS8Fg2LeAv4XXeyRPo7KmV5qiFHo2qWxVyCYvv0XnqJFXVluJkMU2GvbkEmrO/nhukenZUbvknCbqqW/Xxzf907TsIrItYV3RiYvJgShINDqlyYFwwkM69k4lHID/p0qXK8pGbC7nFqpOcGt5OzGfwpVdsZ3snWqmKB88GiSlj/d1Hl/tvn3J9JKU4LEG+SyY3gGhMYyqtLw3ekp7qZN11PIEVCJffU2K0z2xc+7z296947gwv9rRPByM0OcfbCMRUZZz1+4VV16aDoxjB/EC25q/pLAebFX87SbGkEDw1xn8T9orT/tYyecD8XQMI5ZXXtZxOFeZTmzYyrFVdLmD/SNPr7cVQPph2LS0P0XvNctZEUhsVlNoWKpyJPCyEWgYlGQFTscyDxTHc+bFLiU+xcZS9j9MbmbJn9OYhjw8x5N7qSc18zfhrDJPzi2+VuKzZ+HdvseeKrAb354z4yqnXmBUSXfJHfsBYnU5ZQTR6dMinKz/OOc6+uTc/B4Dz5Rl6OlWtZlmUgumRZloHocsKB0KhlWZZlUsFcuil6y/M8tyw/ckijZRkmepmSBAF2OckZUACqyj32ntRqKkZW9vBSqyl38SrZ7dzbq2lrGEFs8d4pS5ZZQorYZibQKYxUCGit9cDtSkf8et8zr2VB8Z3z5FAheBZYySsxi1qZgyuhIaxRj8MKzCMkPkV41lzZ5KXxMsY89nMLGUx1ozzhIsdcY0RFK/o8R0HWohXjcSDUNMkmIorLUaq3rtsPTcKEciKmmQG9xtqkqxShb9eVsF0m+YwtXwDEXpBth1IInpZo8W8xgEx+wRTOt5l83dhnuTH1lEzV8tJZpuZwckun7LPUeXhoLHT7WNmyne+Gl6MYWArScy05bKd1nWlWqynYdJEQ5o/hljtTvNhI+zUuIiPNhIddgozb/LKIyx/CwgZonF4SqsZ79POkx0sgtYsWM38f8Tze5VieW6LA+o/Ful+hlLfikaLnJfpQiCHK958VyCZXXxGHnA3EJDpr8Th1hIElbIIGQr/b4EKPmx8lSrduWi++ayf9RXGQPvPklg5n18L62w8KH0EdxjAMMZfZtIOfW6w5IAi3wBrb3et2jHzgtw3TLc4Sh83w/uFreJZEp2u+k3kEpEVAHnuNDRhJEszo/SZf4lT6YIc1a6RYRrg7c4p4Dl9ImzC/ZqWdUbOEODgPqDKdvGEe64sJiz/4WBXNtT1kC5beQTC4DgHgkMUgRkqwwv9IKSjqrCJsSvR6+KmvnEX5tSPYF3rHJTkEZ8u2mK1whVBelcGnZEeRwf3tHLyYqn01Egjy+YXlm3HKbLSqHcUG7YzDafrGKsE5iLB8Xdkm270hc5AHYGYCIdE6Mn2HaWGs6gVdyn7gwx/qXldFKwiBgl38AZ3TtppGn/rJtmRJGBbENDoknptNBUJgERaGf8E+h5zl99h4bnBm7sHXojTGwdA0WAhNlGg6ceGzyFPBeCVwboC0bG6MpxKIe2In6YXCoVi4d/2esfczEcwFRtKZmjGaORbFXrXPpOSbVXIWOV/bQeSu/5qxP8e9hD8rdEcNJ0Fk+/0/2OG9FbYgqzr5PSFp9jJ9Stn00c3IwMgwTs6rlEP0rK2F+fwHbKKBNUQ+fwU9ih+DFtnlbfWSgcuuIBJiF+VSOaJcFwztcIW4ilw4IYBkshVcFHVQokt/r7OxbplAD9ZvYiRF9UY1nfB/2nqC/XsJDe4rzRT/UhcVpoy0PxZaXWY6fnlbG64O1cnMuKhIcdvoxhGUdk3RJy8f+yD85u8ySr0VGt04DSNYLF+pKd3YZ8Qkh0yrgCwWWJc2W3O1e1E2hBKI7bYoVi3Vkb9PISMv7iRH3TKViUZvs/1DQPy9b5cEbJeksl5JlxJjJfVmqeimndo7OJVzNtkrysybxGJez5Rzdi5WMfMMvsW32s+jqEoAwV7cGy6RuDLLNRrPcq4xkUiWaWMOlFNvbp/cOBI8NGN8KXzsDWIR7OBJgf/JEVAA9I/C29gjhsXsFhaa4GNLE842VeLEhlCkMhSnkWtrXjVrFCfNJzKtUsIH/KOqI5Ccbbzu7eINXPjmfJqylj6rPmDh6/hYhBeqG9+beWp6WvobF9+JPODteq3KTM0FLm8024lZyl2xWjZv3y/DYP5+3AE/hwOrmqTHeBegB42UGSQq8gnwQYIifuaQ+LxOJ7i6ElfzPf6kP1ZIzpSohovDlCvWy80JcqqueL8tFIqIfD2M1WehrKt9/v6s9UsIWnxKgAoMOTVFmWxUCdqUYF7MRaU2Zc1MF/ZCCZ4zQcdlsyewnLYGPc0oj1kcputFteGrT0tdyhBs3KIPv6PXyKCoX2cLTqgD0RXoUPYGyk/13/a91GKBxFuTrQo/u7gRD45cruLfdx67HooG/pxr9Gqazdt2rF3x7Ss9/9hCkI8oTCHrGDtvSl3Vac61HVOOpQJrQCHK1dJiW/KuHy84TbubGK+zaaRLp4sIHbg/L7cR38MOfmFKV3jXirTkNN+DbA2gtTff6bclk7qd0hLWyN/z85cmNk4sWY3vk6f8a2oxdqdkA5g9q0uVbEp+hKuHgSH7ttSF8E98Fc/QhSAdLYZAonJt0xzj68jjX+jbI3/36iNwBIh89FOBdIzfbDL7NOx0u+nkqbiyTaP9KkLclw7UtcYHxRUiOV4HVwLrUieXX37PfJN09gi/u3XZCQPal24521htPCZNsZfQWJdhamnP0EYiaGr4zFmtoTyDa+1NRnnmP6b4JLG+4bu32FALndnQ5HuSbkOxg+idXGC1e72Uw05aTlr4G6D+7HVpeoh4/gKtvFs+V3rkZPyzd/snot11nILcARxpHcNBjnqoPooMPGe2c1Mx5KsJKYAQsP1rfEhvHMUMVcd1GNcDTB6HHNM8lU2hUOsbKpGFcsNYjpSVge3sDMZCkvX/hoiUld8RfG7IQ0FIYva3mB7uohbC+A1OXC0jR5TKL/WyfRiLjduiNe9dPF45JgnXELkMPFQnROo+ROpB+VSwndhoHRV7q1R9aZbbF50yPU1RU7TXpugvV223d4/m7/rciLELBuz0+uNjl9s7OpwUX/NzWGMOhcnPkUIAzHPhx2bYh1SZper1ViO8zhsN1cvHnBlgIWMartVbrgzfJukcOdlhx8KKjc/8eG6n5DhxM31Xzw6WOtnq7acOLKRS6RFiAuTLSblMWsZeVP4zvRIa1FK7xIvTduGDAMdendXZj7GeM4eSrnc+cJhWuXsRj3mwhsc8SwVRXTKp4NB7VvRk75sN9nKQ8EgK/lssvke6FUdhIpBy0du86Ihj8wCLj5sxtd8yzAYp6P5EzNmpWCg83xTUSbHI9xJIrbb0yuuMUfdrbaCV7x6QJl3XVsVLZZkJWDkObDNBfOdyMsyTEaR334SBJJKIuZ4+/ye6SgQpdXKEe5BNrSjp/bBdMEWUJF2GRUnTAAm+j8jdZEBubsgSjCxnhM4xukcUf5X/rRRQZvgj7bVHYpTnRlKTPm21rzReU2i7r09cwpZhWeKvKiTupQJAf9Be001uVN5jcEYTSno37SY9TDvcB3NftORxqAK7N2VmnIrf3b68zzClm5PhWdyK64kAUdqk6JakAdIwkdNALEUJJeMVm0jx4z0HHXGZJLNftNa3BGu5Yjc6KGJ3ccfwNGXHeu5gIarcHHWYMsEyv0/SJjzGu3kYhQUIb+rbWnClhE4oYBNdhB71qiK6eFlVxcx1S+ZIXSi0kXNMopV65Fae/hiO6/dt6OnjJqa5JnDylnaN27+62z0JOgaYPciKbI15ohcB2b8l/ZFoBZ5MGzqj8OBwO/DSi83apuMz4pKYXvqHiwH65mE5MDLqGpXuvlzTn9GSe0crDzh2Ih5PhwlCSDQREw2nZ4sJ6Y/Qkw8fZP6PdbxGgARc9dtETgLuadOlTBOWem0q+or3v77kpNodTixPu4cUt1B3e8kL/6oGRh2CDC81MwHv3NFpWHsieOz5mO+izbTnnxJpJCDwmVOwLkrhTNl54bcMf4LkZ6cuUuE9kiffU73udRhlmh5d5qiWtIbFl11uguAwRAU1bLQ1Em56oAAkjp7PtySkwdhXLe2YMr1nlO4CC1rStF6nAiutcc326QZyuidEnHbIqI/2TTUwwpAmMvTVzz/Vj43pj1MBwLLDk+wDa8hv6buEnWEKaWIoVSs/mAjXhCENUhQsbcGfhh1dhacGWuD7uAq/tu5n/WCZl9Jk9tgqXheERr4G0ccV3qIFNp4fM10ueLV4Kf1eVksPLsouHJ3XZcXDFA/+l7KLLBeh6S1cFFD7FSDqgmk5LqSQfLUhUzxStzs0d899P8nNiEKZiq7WI1OIGPc0adfxfDQY7cQz6toBE0/sq0P3A6afug7YZcaBjgv3zwh0tU0oZf/yfZBLL5fsF6GpiI3qY0B9axQaL4XVCVDCFV5hIHlKO5Y6wvuo421AFVKFFhm+b5g4Os5aqSOdp8/pNa3sox3qdM/JygaT4sZJP7xXbyqDT2EUjQTFm7eIPJQGmynW0DoWVxRgOyMGBfshSuCDhLkbTfAVhsWvvHPi+0vPgaXgjwX6fExGLp2mNAoW4C2q6bjTKBWUBOhQArqiYDj+ZU8//64pwCuSTln+jZvqiHOChG/tblx+DgYsw1Z/yE255Nto0qqdt6F13PXuOYbnaemZKC7uFQeeE+S/JT44+n25Acvu4emdq61J4U+81TJIn7ex3M1pOxcwNjF/KFID3idiDbgqL9T2c0x/guUbZyxuUnnuXhyz3oniHlQZU7KQ6KIuiRcnlqXyd0OBfRgX+zB7zeiYAYZ5GGmMRskn/F4YTExQt9R/XVS8ceYzKg6ys1HaxSGVbTnY221tMk3FfaiTVDmvyW+Doyw26EpP5SdAeoMjm952fQaG9vuRMIeZXvXdC0NcAza9nW7bn+dQdh62fAvHXIZzQ/rpXBqqJ3IXra+jR41hIXNXA3rrilrpJYDb17FBoZuU9uHx8dhVx79bhvYrE7b1MLUFHwZKX35AIvNhbNq4Jhow52WTWCbztPgg2MwJ68MPerkRLri2LIbyZJIUapF3k3Ao0G0+11Q8wZcD5KvSLvRYFNHBsnPDtP/3trCB2UByll7i9MnwqPmGWy8uTWehYd2qqE258+8r41vtf+fLyHAY0s1FdKXAeTHoiy/9GnUF80b5hFXERIG7ucExXDaVtGDjKufCgcp0oEns0SPVchOJ1/FKW71jgQKF3WVVx7VhS4wsfKV3l9E2vViYXkZXRiFGouIbeNVS94InPulg1PCCpFio/YXCMcDtQDcN6PjM3r+XxUrKQra/TapE3gfFOcn367g0XZLhWGMbp0/WDyJN2TaNeB22/8bPCHIXb4M0ySwGKrUNxMekxDTGqZtiQ9sLRsumfqNgsg68tT7CLcTGvta3FVaF0ECXn09+0snNWPVCKXbsfFd4eb/vpCME6d9q0pfr+1vR1O3OBEVsN2u8KDZGodwSDWi6Th5U2OZP6jyFQ7CErl5NvCnZFjqfyrKxHFA1XkF6rja0ZHBelFC4FeKdXPDSTLg7vC4D2cQGnHdLg4MwKtP03DTsg6PEnmzoSCzdPTLiJ0H9Qi7Vt7YcQqrlRzlbRzeC6ANR5WJJenaSZgi7uX+lrwCCl7cCB3FnezKMfLOboy7f8hA1HpC3ApugRoh1pkipd//y+eLM2qnplXLYgE2+0/dwnwV492lT/y7FFIGvGzJ/cjOYqS0hAQnnIthulGO5isuRT+LvW0SN1l/57l2kPAJTSmMQifRFYWh/pjwd8kojHrTz7rX0za4YMmTfOIInl9zKrZwETOWrHIOQX5dnJHZAczE/GXn1/T9H4i7KUuKbGbLSFanURES4ck/yWsryecX2W0+N8GzozMJn/bvIEszoa1pUEpwOkcjzLHMJBimG7TbAIoiBHJ88C2SoJg0b3a5k3CuL/O4m7yoYpuaIs+IJeqA76Cb4dSIPUiHsIsGE2KTi/z7CtocZ5GLmp3qsqrhUrKBDEGwMkDEK+ygC/XULZh5SqeO1iZeekjn0GlGEMCPFS3e+gPyiY/phNns8znWTvzCiZj3MTrDwyRTcWC9wBSY7tutZuOjyJFls6c9Re4m6b/ntduilG06WQLruI9Vb3wuVpOqVYh/FbBFRbGOrPaoq07tFtHtQJkm8CDg0WR5HexdDGnu+fQJoL2AGijbbMPr61wUSuzWcszBbdEjpvHVDPysrWDK8jIPYw8S5Ct7aTSqBxQPw4E0a8q90ve6x+VqJJmwItRmHsGnGaO8XxEWv0Z84hA0KGl2Kww18v/zbYh7QIMAR8Z0H/GpcsaW8lr7g9yfMrUMGfPZo+o2FRotTBUe1MZJCOlP+tFHSGYNrgFIiKlwgWMJiWRiqQAAzVGbi/FudS5yQtM78C6noVVxHDkHkfqgDmc5psjR1NyoWkOgeGLd7KIdI4tuE+V6TUSL2AVTPR3oHyGP5Gg3KQXdEIZiy+4D+DDsRY/H96uIsLxZMkTlpzlTobxS9YrdA0hLkd33N9usbx33JAZpSTOzSKxArmZ65h52I2zonjwLT02B8OJu+STm/Gxol7wIsMjDJFtsv38vxIGzKKMq0PZ6CQ2SGHcCbFMwGGFhUGIxfqRV3Wm3kGBRGbx3LbdwKrRmEkSwl3m6BcJltc3BDyIZzRA3WD3gyEZOmpKwDhuxa34qe6H4WAV4rLvVhvMeeQPn6iwsJsv+Fjb2G+VgreFJnCevzRZBJ0aTzF3p5zeIGHt6XS3+/LnTj1RzKnLh6+2e0Qjk58v+4L17S8ln1r6OMkbrRZrhmY3ex2D9fw6b78vH75X860i1nCl7esaCV7KxtgXCpCxZsDcpUSxUSrHS5Z8GHa49ggZ2c5pwskYa6b4M6EMxQbQhZWKiqXETBR05kODWHO0ms3zVfDNk4uI0JRwPnTECaXgnN9rM/K32uIgW5h7Tlmf74MjuEuE9O+mGJLc1jD3aCXRyKSk27WLTGQpoBc5X1kTRPnaZRSmSjlMgRnR+SrhKwoLZxRfSUBl/Co0qgkvoEFcZQtLl57OSdQR3tTRBuo9e5RrfuFPMe/52pS9f4077O35wNf2Z23pTUjaSzG7JoTagow0fVUAZeVYiRSgXoxj/qN3xx60+cj6J9Tn+HbzPr3QNpiMQC+TkKLfm/2PaWnGPcnjoaOkP3kHwZFN3K/CsUrdEDIilN3JBWB9WEVLuk4GxkwdpOrIyyOGyp0X9bW/US0+o9tOh3M9hWygB8T2ds8fSSMhrF/R+mATBB1ipu+xaEzug5RLBX56/zYyZMiYeI4t7mqu54fliGGKuzQAEb6vRrVJfnoqk+anXlU+R0eqFslzrcvhvDugowXCgEFTEvMe7vEFGCV15Vfk/v5UJjJtiwgLU6mCDjjedme8ALa7FBxLWbzNsdigBzN8kj6YYvqmAZWbdDwc00AYlmzDSI/IXnfvMsZQntYkdQEXg9LAyEnZg5OpnDkp0CfvY9UOS4HYyyXowywB5A8DKf8H018tTSK2cFsIViDGY/Tn6u/PMpti3PYPp8kG5Jspsw1hwqqurrTY7PKkFeJjJfiKXbBbYYLHEyhAy1tt3w3NeG8yVbYJBUg5hGT9i/pLPxrNZZkPEVdOO8u11syFeB66p8W/G+phDpFBNyU0kxxPjP5fTnEhO/pGL67INBNLcQSpBHur71HerZk8+58g/GJ/rjS/OXH0UFWSEPaOMBqmHBYP7Ldo0gkQSqd4Xvpr+gstYZarLK8zYwuKiUsEuo8mC+b0LxqLFoE83SypKTWwNfXYdWbzd4vevP36aMgjMc0hX/z6P65yFJmFyJGwQqJIh7jQxoDlyl8ZOa0J/2yj7vuwFzUEToN7F8PFib2amiOKzM+y0GAoyaghIrolt1ZIgbYm2X0kCoSMePui3CB3b6TbnymarzTd+r0VYCUwaO/uoCn7Xe3d94zXtdT96PVL8PkN8pseh7SEMJBEYJolPXSCLp0pEswkWLAhKIkSaS7O/mKjazdP/j/KehMIhtLDOiYpnGVwmuRJpWOivRfXqkDE4dyg5jNAK1AltkFD5FA/oIeR4CDRc9S4jYZJQ0GQKrfMboR3xR0wI57CwPz22+JZoqo3xGmfvy1t6BvbECuFyHzNIaPhAc2wb3fy0kqv4G9QU3HgzjzF937VVUf6GTHbwAv66oC8bvAAZPy6aBCSfgWBOwXKRDbdj5g6hccUOSe/XnCPO8Af8BxexmnhBY8nw0NqWnc3RicjcZtIJctxCxNtEbM94uMaizTS/0aV4Y0wui6cqMmuP/qHHAsUU21cAx3X9l/jq8xfWGpxJuTCfsGe8duJ59yllP7lvVfGDSeo9cxpgLFT06hvXrb2DXNVDueNolynKM3NWcnOIoAiLLxLbbt4uG/jUKgXrc7L606CZYe7wQAZss3i5jg603VxLG+tGFUV5LaQcPValb+YJ3grWj7IZgg+2hUSuP20DRB99B1AyLywN+zCBronnPGBradya04ELfM0TTx/pP03dbDdY4gRPWi6i5ieDl5M5yeJE+ixol1LTYzk+HA8CalAc/gedPLDnBEfeI3QHcr+tkHWyofBFvJO4GhMib+AXn3P6O/P2TqQfnXQa0ny/QkQgN0cS2tG66EFRkqarHFh4/TYkpN5TkgmPKT1Adc34BYyl8f6toVFgRCjvo4/hRB2KfMuI8qcZo9v4E27udv3wX6UT/e/9pROyRAnNMT//nPBi1WHuJBOFFPhwyQhMxI0uFhr5dTm0moYxOHk+Kl85hMlkTa+rfxyhP8ombvrbwGxPfkSOa/l/2V/V/yILJAqreKlo5yC/DpsGBmgqr+Pakx4iLwRKVYvOXzBmhpHeHbU8EbT6atw4n12QREFKCBofghpGlge+kYamaO3+MlM32v4HvKf6/Bv0hG46TuPZfNY89Rf//QP7zpH242iffhn+t7VpPlf+TVH/k/+ZP095/g5kG/19uTGLDaYO3p9r/k4Q/LzSofSxqlyv/8Dd4aZVrQVp5iNE2wbF9J8c84iwAaHxD/Tm4/J95AghgP/q/n4eQSVi2PPb8EEXo0L69WFF8ikm5p3ExSz+hE9q4GgyO0lKn0+LUhn9tFVz4ffZrm2ENlH9pfYj3UfNT+D6Y1xHAB4J0TS+OuZUrwE4SE7V4jwTeej7Jc52bZpVb/SJPqY6/SyW9s3kY9SjBfmTnvQOeIto1ZKvPbfBEXDWpMopqAfBBQuwj17P5diDioHfKsxIdgG8D/alRY8iOt9zyr02dUHeJaFcU7w+/qwOuLWPN/8llwYV6AKoJ7pIQDvtQPA0O1plFjftI1aqsci2qGJWEfI5Ds/CwASqSfoZI7JLCfrwWspOYjZ9FN2W8FUVCW+YTcE4ijunA/5LyZIOi5qxVom7KqeYjhf03nOURKI6AdtBwuI2sC/xiN/n7fTjuXVOO9yogVFlis3OZE1/L8w+Vmvhm8HQSPT8mT6oLsHe7/Wsfd5Dr94scjYC5CU5lioscivsY2L0uCWF9DmbvGt5luSR2k7/sHlFXROsv3elpxYP/0C8JdK/ORA2HtbFHzyYSTinH0f4LGpRFdhL666KO85LCr7p6BLF5BDVH+i/RutzReRijqt2urF2PrPP+qkJlgCaCn9fM8fPHpRwN7WibimSTPD+iFm8DXq0Ug3i5E03iXQX1ZcPNpstfLO5H9J8OoG2gfqT9en26TfanPH3iLS6egW/p/dMSgH2oxVi0jpn76rnyONNC/v/1glVW1v5G7qsL50TwNWVetwVu33FQ2Ch8JW/xc8KtmfypCdKYKFriXkb05QG7SAoRitiaqHEfWlmvRWhBolmnCE4iALqnUI17icLRBS/PeNpGJZOjXSUtcOxfGc8GF3a0Sgbz+1qOzADahrYZV4nkdiC82/i6VoL7RSx/dv+lWlfYSgfUe4zL320y0kQRLXGlc1NJuxrwEnBqlJ3vXCtkdDROo7fEbsWqEwRuK9uNh/ZL1Bkv2U4uO2fnwGk3in+op7t6su8yqVOjIY561wzkkojW1O9k8mwRpfr3dWuzOgPou3zm6nNjciZJrBb9WO8R6Es4FyjapH983BzFMdBOCZNIMsPpY3eUz6wVF/Ttclc3QKmUwYolgODfgn1gFcnrNQRd+SoLdc2g7FAWAORm9hcjiNUKN5HuWx+F5Hoxz7eiQZJMznXOjsNck94/RHh2axf64VsIFfLQXLFa4b3Zr0WU3oUuOFaTKDNFH/E7932cwbWupSovR5NN99FX7nr5VPMhb7ffJRjSdVdT/sylhBbejjMJonX0s5MHiPp/K4QAwFUJiLRQVDnItAP2MUNhHch9URhDBrfNgb1EuG4KjBmknxLgHQ9VmIH5MUAWAjAhA8kEGNjCDAd8C7AMLUiTAdL/lIRz2EHV5ZAeDXDXWlDmM5BGFD5pwYC2YWMuVgBQAAtw4scVeShVaRRAeN2baMn/38HQfcgmWsFmteO7W6bD2/pn1xdv27ftzy4UpzzcmE1ZHLqXeNpRvA1hn3fJ668BL7xu8qcY/ii/M4/9O89W+a567Uqt+Sq563n2U+zjS4BXTE4e6TCeIvCOCcyVT8xICX8xU2UkklqqwC+p8qjcSFsWcCcdWEQS6cQycAVQFYOtWCEOu2UVJcd21EFKbORJZYFNeGSFy/FRPM7TBNngAmuVZ9zIBjngpjZRAjPLNsiZmbJTeWPW8ox8MBt4jjQym9gH+kcGrcoPWcUBuZZtOUSayjqOgR5kkReV/6j8fJlsYtExbWnHAu4ifWcxcJ/pwCLx0NKRSrloWrDYcgl2YrklaemDZcdV7jWPkSHwmbnn44drjpaHSH9ZDiSRrpgPfAe+0py/YP4oI4OaL8qRrl7Xxa7qOfmuWNt+e2rWReP77U+zKpq2f6ybtmjGXoz3xZP2pfFtofRL0xyLJvm6PjW+WHf9z1MTioZ+z817sQ79T9P0RdP1W9PURVP1z/nhs1iF3pp1Xmy1P/Naiy39GJcvFFUaWZxJxvSvppb7ffrG4oOHSLNTOeNhl87r4jX/suzqostPnPN6ecuG0wx2+VeL2am4Gk7OYNYBAMy64j7ZLFFdEixyX10uHdJXguQedLeCj8YEmPox8ipj6XN+8zBUHiqijJvOnL3xO42zmehaFwH2QzAcF8obZwdBL0qq455saN+rtisnJ4S69DPpugc0gt2z9KEXi/0GzpKctZlNOofqHjuw+tU0We2YEQIkeqQEMWge3GHe6cyPYy8Lxpws+Acn4sNiFufllAfmf2WYcXUwCUxoumBui4lND+Bc7T7nzNWLPhkg/w4M+RNjDgsUim2+zIvIR92NeB7ESwjGxN1GlOOPTVtIB2Bad1qF8v5wncLroOw1R7B5bziN6RQ2BD7E+SXVGvQjKan8o1xfapPthdvHh850zxynfBF2lnMmfxpobTbBjO8uid7CBeCzyUZcB2qD9jBC01UWbSDAYex+a9Sx7RL+kkg+WkHdh09OLY9UFdhYsidaFPcMUduc/RNDikS/YTvqQkJ2esnVEfKndpRmrAUejCUkZ8fAmlDh2rB7OalOnyn0RctkGE6kjf/atIw0+AMAbttjQK0gD4iS4agFUJ6Ldtm1pDUYjxM7QgUo80nazP3sGlcH/NO8d6VOqk5IbxtkNk5W8EfZMf4YerTtGCm+hKjCCZ1tEDj1ZRyOJCSF+VU1D5eQtMT8Y1RYyvAZcNu/IXF0JJKvHFZl7Z1D9xaYKmI7N9PGQSC9P4s7r85c3xlFsTAyz/4bXwxsT/jp1N6SH2W42u6S1krRy3NWMSJUNjwOsfuWP4eRx7fcQZZoWgmOoixcRUEuNea9YbQjxeQ68Hwe5L3l6eTMVlj5Jjl2GssQ0dEPKcdGFpCcnWd2Oq+yvQPwYnYIG7PqXJxf2MsUAeurnnGSJCyHJFCRjqxD4peFzqN6td2l8DmEbz3qpG0qqkgoKuNby0t2D0Dvzz7PXHa+bA3p2W56WHhzYglWkHkS4euwpOfNAqy8F/F7GqVeN9vv3fh0/xpookbzUpdgDVHeeHj3ucjLTTiloyY2jACL3EWNuehjVbOTO4RsN4sVBN3TyzakR/p8DoeckVVE8lyqHhM12cesmVvpbH7uaCvbTIX9JxaBhTOLKn74MGIzbODousRlaZdGiqTFXgivXha0KuZ9xuMJgF81J9fIcwfQaUnOpQdU3f1o1F4NvdS/mwFNeExXnbclyd4lVKGSlWac0j5ZA4K5P6R0fHTGlcF5iuwswzvAtMEMEcUfeaLKUrTFIj2+LIPmca1nN3grEqaUqFFx4h0/KFevPNG8x7XslC5U3CMkSnQU4h+LbtCAIKitiKqLxsGfVGWiBmCD/b87R7Rn3zVDtf6AyPqTc0Tz5IjhyePfG2N09MCUHnp9XqeDbLWkcDgJacuRO2+trwCO9Nq++XmJpsRoQW+mgxiGYRi3P+c0eZH/2DU/m+6ouk+/BZ2uu8PZs4SBSAUs1yMERyEy/zF7Y8IQ7fKi13fbz/3dSd1zKnWAHdpCpSk1uyVMspwliVbUaTYSSG8ffRmNwIgK+nWKz8dUT8ymkeLahWkoSAmJPXSILEtD971/zR8D684RTjmMJ3HWPNOZOR2QXc0MP8H2Sz7IEMowD73rFQNRYRGjJE0UJxJ678krSeYWBIRjKTBljWZBXZZmsed3TFO4IUfOHgLzLU2CJBfw70RmsOVMaCbN88O5mmH58vHJC/thymTajsAdwoCEPycW1Zm4JJwgHvcepo1n9OLbPGsDwrsvTM9zGXZHRJK48ZgZcvkMcxnc5yBqwe400LoYH2ohK9Xzo/mRBNJtekPZWQs2wMLvNQwZqZeFLTKYoha+X9OWmC/xMIdJs7PnG7p9hrAhTs+Noo8MjtKIrhtmWrluXhB4ZZEcSs0eL1BToqNn1FPTQeb2XZyHswZONwjHZBUf0X0o8NLPquSSDSXFOHdEnb23StJ3xfGdIYzL3mviKE3f+EruVXs/psy/URNK6quc97ECM24lhXvZosjv69Rhp+EUbyTIJ1Sjnr4l3tyP4s2abZDuPCLVpnsiSY+OCXMH9QNZ5K1H3HTbEVrvjt6vp4D55CSMt8yj8zSE5JCshuWAjrXA75HkneXxvQwVnVuFJ9bCJ+BSJWZkuPD2PqOBs6RjzyV0ASDfI21ek40+u9NPDQ+zHCo0Lz4qSvolO9bd+NJ7DrVooCdvC5X4K92nWYdcohIIZH5dsSFg+Ox1E/LO+KJsHXsa4D/bD5pkc5pdzt+Ejg6VxcfN5w5uxGS14MmOiObHlWUielR9GbOIhD1rvT09LJIMkQGdSRLjKexRyoxaoIvOPcRLufA98wMCkbdzp0fi0rpDaf7nIHJZlig2SiYCw4WdOI93NPLDRaHRfqg/IDGieiTp8Tzg8lqOTvY6i4lgI1dO6OeQIIe306hEBkqiSanqOHwBJgkMtPtOlzmtmb/jbD20IAJjxqo2z8sis+jF/WfP+Dd57kHggqdB47v29mwLUvPGGgQ6bIvPo4kVmIILVLJCfhf1AXME0oQQkZ0KinxQk06Gbvsex2czL992RAh20kkIska5GWaCovA788Na/rODgXN2nZ4g0t/t5B25xhnSEYOWczzPVXNuWozhq9nuT+fppYcOXLTDlfYuErK/bzq2ziV6G02fWDAHnBM+uE7cpbFBkgspwtLLH1uwGN/zLrk8N/PBq+Lc/C+8DzN2eSbrm0D6rSHo2OBJ2xOMyCpcF92v+Ypobv1KQLZtmaYlYdTNcpPg54Ze6ELbj4lCPsZJc1BtQvRy4U6YTecjITgj/oRhGIYROwY765fdXWhL0mgBFDOzJqJPFkB47mIOLt0eNlHOBBVNYR6dnVyMoWMCqy19eRXjAUf7q0ickeBfs9p5FtJpTe8ieAH4USQlLFrU+cXsduLQc0V3h2decPaQ37T/8l46q4kpYEARy0vdOPiKoL0DDXhDhmHmILClvBMNmaBcnMm304mqwscQNZoyNZGe7+MnSJJvG7kOOzIGESJXxV31QJWgaiyREDf6+7PA3j8dUEkDsltI1AbI9Qxjz1EeUMkMclO19NtDVfakLme8X2Y/v+ERHp0PkmwTYwmQgTyQCuqhOZFA1giCmg/upboKIRv25JJ0NCUirxYyz7Ts+oMT4Ce3tgypNspKxC2+SA2LuGGYJK747xk22T79E3mvpdW1w9fDzYJ+oYeVaxCHQOrJoLjmTOK+VxipUmJ8sA6G1qoaq6UrbRfsNj1wf/oxl+7E2+yRmBdVcz4LX0jUao2Aa9BrJiY83lp5cOOuXfHFLEAOyjbLfdak9sMpg9JWNyNDnCzff3Pmm3p0/+wziRhXNEl80lDHRYeeC/foJLz94A5zavsMOnZyE4eJbzbCVrF7DG2Fv623ZZBqHl/js/af20vxvvslSoJXqXky72DXMrfnXsHtok24Qlq7me8g37uoDqrPUu46D1HqFxwapZfFG9WoQnvRq5+0GzTwTwdhpYwT+9/P5GqtSDweCvw4Q7wA1nAiXB6iIFmCjRsyY/FQLdMNVUE1DAFHXx7vGfQzWyKHGmIvcitniMpfyDS6TL9z1P4IiR2vappCAlHb+8tC+CY/J9SrOltkxSUv7Bq8NaZFMSf8SMy9XaTSnN6urSyLwr/SSYP2sHKUY+MbvGvMn0Kfy/3MmvazoOV5gWkB4RDsjLoZq9HzBFvNbuTJDehMhx+elOdMeDbjw07sLCAWX9LeCR3a+0VTFoy7aWssq1tsA7jSAT+h71nABGNXO9C9nSROxXJujo91yRUvLqXcMp9T3ddaSA6aFEthgrV1cbtwYmoyO37rL4aB+qPinRT+OAh4ONXYkB7KVbtUF7zwSe5K7TX7QdHrLVDFUVrL+2rNxoxznpvX1mAHcFr+fMeEqsG4+EuZXP7cNGmUFTuinK0nB7955vswL5WPKofpjfNTdBeYBKGFB7yVIot+deLPAE9iF0kUCDxevSNvg3roXHNG+R9nhynQv/RVysNZ0dc0VFBdYUFLYvE1Tq8fQFgyc1ukaNALxEOlpv4Cxtq2uxelsVsSJ6UX+DQbDz0YHTegNeS91wCTog5mtC+d5xrrSdz2o7hGrugHAeUkLnQ+d0GLcVHGCl9/6IdlfZ/K5H4BXmGzavettIZ1rcJEQ8SM80qb8ZMTKrJZNLM4DMMwfHuO+t0gd8BGetleiwQTjY4jMoErEVUz+MB1ZMtruCsCUMKAnf0mgZfPdgw6Kw64//4T99+5yilF3VCDSRJrxgVU+/ukB1p+J9F4sSAvh67WFB0VW4mZVFOLmfm//kf1M+xqfDTiw2TLyV2ahqeGy0fhhoKmotX35QOYf2LorRSXgiXq2g/hahJMMXP+6U2OeYzkH346DhHA3pfpDyW2pYZmrLjmNP1AdPXhUmMdEuiUJ0pmBL5NpxCxD759/YDHthrsVbFh1FsOC57gw2VAMPZjQT0ScDLFsEEel6cKG5QaMYUv16xEbOuuxdd3WilLIK9BBLPUuZINLDMtYVMoCNEUeR1WRh7lFLc7p5NuxXgkhVvC5PjbEsTKWx8hf4VqiJkpOEeSgbIxGB8N5cbF3tSR1ORVY7dohgLbqlFxzzWqU1bLN+mCmyvd0lLPJNmuQO2X7gOmrDe1z8TIIdTMAD/6zpnb9bphSRSD41qMcdypdt9G9Ws3likorZuMvPIB1VuvgwIRRo31Sug7cCQj9nESw8vQIXQCA/RcgRRLWUbpqPOxYM0HJGzvRyGN22vcF8kiTICU+wT27XGyojJKvbp5CqEeN3gbz+ZVWO8PNvNsIDx0qKmxvqyruKQJDmGVxNhLx/vC8ol8+Xz/LkemcrjAN28dkuSWTGOwBdhU6b5PrGMFAtfnwI799+kqxfsQ4dTiosaKS7xY8eEGgOnxG57b+BI2WE/u/z3mr9/hgHdMy/qIkEILGUoEShCpE/EpLMar6y2dQtHW5+xPW51HnF6fx5eyj3QqJH1YaTu6XjqiXvehTVRDiEdTQ12nNm+k71dG5i9o/TjVQnWi2Rt36B9YLSjzCgzUud8QR3pikwiICQi/BYSNMg2HDi/s6FNbbuF2mG6v14KV1Ak0BKnS/h2tksTwrcFYewqMirg5moUGHYTyypaFe/LRlGISYKieqZWgDq7r5AdRkLLw37iboOaym6l6ucxRoFyEQ7OgJ/oEuql6WCNotvBk+asBUoS3DqPoPpnc0Cckpp7Y5OwEWM3eRUFJzja1mzgbPUz6Hco8n4VX7xUghtQDwUtU9y0/jRYF6Jwpvs4nwzdVOv4NASHJTwzHWzv4QC5StgO+6Gm4xH7TOFX2AzQX7I6A4SByUAANOVc2IKOpFT4c9X+QzyQ08fXFfJJxlpv3uwF5ROP5XEJtqefGrnGAxrTQNc4JCuLD2xmqeuGSwdBvfdnYYmXzWX+E5K6GFxjHFYTAZRr6e8uRa2IrsHMle31T48cgxfKKkuK1c5xs190mqL1m56G3Nt5Av1Uj01lxiPSWr1dw7saotHRiKbw+cjAdhg7MR3dnXeBIzFVvclSrAsMwDONQ19RSlWObnhDhq/9/hVJg/7HfjnL+3uyhn6eouC1YednqaRuV1GG0S9DtoZuxXShsFiCsOaYKcmhgulSnoyv+uEfjHMFFKA8Uuu7qGhBF/lvWYF96+Hjw+fj8dQ8P8ruw6Fx2rlR74dyXV6fbotpMFEE+8Z7EYbRpuw/Vy7d8BA440WpnWg3M+GrFECxmZ1memIncmjhi0+v3gpXKyP9xFSIGQE8mVIFxyToRZ3aR9zK4EJUbm5x/FKtUnbyBCv5KbHAPDPlfEE9J7eYpP+E1pxwbiC0bWfWbZSO584CddKZDboLOfsXhCFgpf/QA2zE6raG9og/PrTfJPEhLoRTn1YWZy0/Hm1rwZMH3J+d3ONZV3Qqa6gfsVArL8KaNGalV8mNrCJFN4FUU/7I6cPVZuQQIdDdHSqGEuTBhMyVCu2aSsulPzz43yNy7o4S8FM66HH4voq4AKNco4SaShryLLrZ4t6P8JzYAXQnSXcDTQB4TYyI/zs/Bvz0mjxUC4e+nL08bs4xklcbLVPPE/MkoGulhhYSZcuB6JxrgTEKnsQ/Bhhdiveq4Lp9TaW2D6CTbbp6k3f34ep5KFVxQBJTyjChcFhQv3UPjwWWS/3qzNai0m1OhE/P83acO/tlkHrcPC8d6izuJ6Yr0pKts2UFF4snN+WiuzLjeELJcvd7r285wC63D15NPnyNew0wqvppyRedfLHWxSH++RFYuXhHzoW2d1ytqnEKdlMSTUz9yIJHx2lL31gL8KMbPXxicyAmvI6mNOofFg8sFNRDNcYi2E1DAU4lXg4Z2uN07R/kHpwJPt/Er6DtjtBS+vWAdAdaCYn8/1gZUL5OE9C7cwz2Kwte5dpi5JjNuGvzSaKUCVSUmYiMNWG7Ak3jnnnH29PejSEoHx8QQiUJmQevgAso4bDYkmcA4d/hS2xlMdFMvxrHRjbDZLBcCB4mbXOOi+YNhv1Midex1ziBbX0959JXm+vBZCnLD2lvGPmT2mJK2Kf1QnAukbfbsqw8KQbEf+xwj4ZGYB0D3VkKHHARhMzeqLJeyRiDVOBPSavJieos0MqvNn+TG8gQ7GeGIqvme6sc3MEQna0RuuToHTZv4VU5xOmXH1bQSxYBHD7sQmDNg9on8gZAl3B1+q86VPFgpR3Trxjn4/XJSKqm8omiIAJ/GVqBWOvqTwHsyTmpeWZEV0xhStKU4byhHukzhy3ohEpHNvGxX2B5HxInZ91qZJq7/R4ISHehAMQkqfV/rNVSEP2TTdV5Irtnx1k08QM76fYUYRBWFX8gySx1vmhlyyrO79Tp2m380Lw7J0wY2oabxrdQkBPicS0AqgntMt5Z7rN5lmfQzKC2rtGXuSyJ2oa9RF1t87RpL2zH2NfG9NGgMw0SsSrB21PZ94ceziBRipLsjbVLwle4LaZXCcKSbSTWFMtH9QxpSiBXdB9JNCoKuN2lMYejoskuXg1Du6C6aVAYh3tHtunQ1CH7SfW3SPAjDA100KT8K5YTuZ5PiIMRPurdNuv4oeEv33KTpIAxXdNddWh+E8oLul0ayF2JDt23SZi94pvvUpNVeGL7RTU2qe6F8oPurScNeiKd0D0262Quu6Z6aNF4Iwxu6dZMul0L5Q/eiSWUpxCe6+yZdLQW/0P1o0rwUhr/oNClHoRS6c0hRhfhMtw/pehRs6Y4hTVUYzuk2Ia2rUO7pXobkKMRrutuQNrPgE93nkFazMPygW4VUZ6Fc0v0d0jAL8ZzufUg3s2CiW0Iad8KwpqshXe6E8pXu35DKToj3dK9CutoJ/qL7FtK8E4YndENI+adQzuj+DykWQvymexfS9Z+CB7pTSNNCGG7obkJaL4Tyiu6PkMoowp02O6aqjqWLcsHR7lyrq1FEf6HNNqkaxtJF98jR16zVPIooj9rsZapuxtKFNUeRtcqvIrpTbXabqvFriehPOfqZtYqjCF+02edUXR5LRPnF0dus1fVXEf0vbbZKVTmWiO6ao+es1XQUUa612d+pujqWCC84uj7Xan0U0b3UZu9TNR9LRP+So1/SKgcRZm22pCoPJaJsOdpmrTaTiH6rzWqqYioR3XeOPmWtVpOI8l2b/Zuq60OJcM/RlLWqk4juozZ7lappKhH9R47+yloNkwj/aLNvqVpPJaI84+gha3UzieifabMhVV6WLrq3HD1lrcaXIspbbfZ/qjar0oUfHK2zVpcrEd3/2uxdqlar0kX/P0cvslZlJcIHbXZKVV2VLsotR/dZq6uViP5Wm92kaliVLrr/OPqRtZpXIsp/YvZHUt2sShdw0JgFJUvnYGQ2UdKZgwMzXcmSHFwyWzUl7Tl4zWxoSpYLDgqzsSnpyMEbZiWULDsOrpjNoaSBrqc0boShp8uzdDkK5QvdRUooobETTEpTwsjOxMRZCQd2dJMyKOGSnVUzsVfCa3aGZlKWSijsjM3EUQlv2ClhUnZKuGJnDhMbJdyxE2lSjkqY2ZnSZFyVh7R+aV/0cSx2U2n7VWnTtuQ0SiYeYA3+8a20w8l3fzyN/P4YB+fvjz/P+vhfWVtef/qra3XT56fbp9jWZbir/8VuKvF+fb57tf68f/3pa+/X9xMPg97ge7hcnc/fEZ8PV98f15v/jjrD/99N4K+um+128Sl+CLBa0iycRiYn99yt2u7lVczU7W/0cYNRRXr8g1QVA0p1MaBU2RtIlcYBgQ0DpeoY+PdGUti5pa3hJbDRSnSisQcPOizDH2eGRub7YMfqXZIslwzTBe2ejmgcyBmNs5HXuabtL97x/bdWTx3mN4Zn/hTk3cZnJ+1w9P2H/UjvDmx8EoWT18Te89Ib1qB1B6blPQwmJFq6bHgzo5JXjXNbnK0vJO/ZNtSNgR50wzBKesmgJ8GBSa1md2LNOMcT1pes46z6047T2moVmVvNHLvViczHBLEncquvPmB/4ibzL/NXsx7OorgFfXTTdTsIh9elHdaRsXFeRN/qzS//2WkK/N8Pf+WnseVTz+E2teliz7fPp+2zLhzWmnU7cY+msXcTKzW50sCBbrxveESQTmL8pRvScaHJowN6hfYv31KOZ0fxYnfnbGSnNDNdhEu+GsKNUo1n98rRnJ7E0Sa9MG7szuXJPOrZPdmMLlJoLmdn7PEPvaXtNYD97QgwdnbnjFRhArxVMQQ/6hyVM5sDwkwSXdSNvT9p/+v5G1FtohSrqsdQGEuLseh10KKUVlPLMhr3bpXRxGsQlURUopFIX/a9qblXJiv2ymwV3ioHq/ROSTMPykJTWCWhf2rr34cSwyHdlvsVlkRuEBOjwwlyj+jguaUMg+W/trqkldxj2SNXiEvG8/QS+R7RN5xCqXNtxKahH1CPCB2PA/IWccvoUJGvECVM8eWLMm5PktgG+gL1gW3JBZYZWRFXDb0iF0RtOB0Uc4dYJ/qE+o1deTJiWSFvEDfN2KePyHeILvG8RA6I4YxlRP2LVnLE8g45dq+6k9F4nr4gD43oB5yqUucuic2Afof6AyHx2CFbIz6F0WGLfN2IcsDzToltJLE9oL9AfcJtuR+x/EReNuI60E+Qj42oH3FaKOYSxHqP/sEocVceRyxPkVeNmNLYprfIN43o9ng+Iksjhj2WDepLWskZyyfk3IjLNHn4gvzQiH6J06QM8yaJzRL9D+r/CBd4fIO8a8Rt2jtA7hpRqinuemWYt0lsK/o9ajat5AHLZ2Q24mpAL8geRB1xulPMpRHrGf0SdW7uyuMRy3PkdSNuBmObzpFvg+hmPD8gI4jhiOU16qppJQPLe+QUWidLPU+/kA9B9DucTpQ690FsduhfUX82wg6Pa+Q2iE8Ho8OAvA+iLPB8pcR2dya2C/RXqE+b23I/YfmNXAdxfUA/Qz4FUf/E6YVidibWI/qFsstzuisPI5ZH5CaJaW9s0ylyn0Q34vkb0pkYNlh61OdNKzlhuUaukrjcmzz0yPdJ9EecPijDXM/E5oj+C/V3I3zF4ynyNonbvdFhjXyVRJk0nTJuxyS2E/oz1MdmW3KF5TuyJnG1RN8ilyTqAac/irkLYr1Cv0X93uzK0xHLf8ibJG6Wxj5dI98l0a3w/BdySGJ4ieUt6n9NejnDEsiRXWxHY59ukQdED6eimLtGbKA31EMQ4BGyIT5Vo8MG+RpRGp7PlXH75kxsG/oSdRG25b5iOSAvEdcVfUA+ImrH6V4xF8Q60HfKLi/SXXk4YlkgrxDTbGzTGfINogs8/0AWxNCwVNQXoZVsWCbkjLicTR4ukB8QfeJ0qQzzOolNoh9R/wThjMcReYe4nY0OPXLXiTKY4u6LMm6HM7Ed0B9Q78O25BHLHTI7cbVD75C9ETVx+qqYSxLrA/oV6tewK4sRywvkdSdudsY+XSDfNqI74PkJMhoxfMRygvoqtJI7LB+QUysC43l6RD40ot/jdKbUuU9is0f/hvorCHs8bpDbRnxaGB1eI+8bUZZ4vlFiu09iu0T/C/VZuC33Ryx/kOtGXC/Q3yCfGlEvcNoU/9QF2MfqzeehC52Ksp0pm1y2o1NR3Tzp+hB1FXQq+vXsicAH8F1frKfGHOXny6TDxf7QGalJD9Skx8uennErUTWZqrOoKhWnFY2zMfZw2ZeorRSNc6t9telWnETU9k/Ull32Ik4iSuZF0j9R0lLkz//FJli8IK1D7ZOsLLPoxYp1ouxErXXaCDJZ41HRihleeFWXK62oDTb4AhkcGtaytSgeBEdgI1srNvodMjpWYSXaMlMv8urdVjmIumDxFgkOrbw8WTK8VJK7VHkWtZULG8HiTEarq9fQ7wT+adiLZuKrwoaNIQQXNDfGub1kHedVNNu6re78hG3b0Z2c4181xuam+1y3tY0nJRWOp5FE7E+xZn8O47ZujStpXR6UMteRmCdsnQEfnjQDhYlgj4mfQeT+rwUTbYXNbmnd5TSa9NgW/3A4MUXk43jyqhesvQCcydfYVIcCCxBGb/8C3ZN9RVlILjQR+FZq+QeX3PQOyWt72T98PwfTell+zev/eKJRkclfKwcrCy8PEeQMGJxkmK85v2B8tks85CL+ZkGV2p/qV6/Pzu3Nwjujk3O3CiJ3b43sP2NlEkV5ufp3VJ6+/hq5uXRplY5m+XPpXDp5rBj21O3K1VO7rPX+jYuPZE+Xj8Xv9qU+TVpq+nlt81T8Oj9NdZFOTx9Tu91lq+ubkxCzSZ7X+jGtunlxGmYnZjsUcfKZndeVXD5Cd1n7XkXGZY6ZHhZ1+IC9C/DdzpW8ZTIoanSySDaYsIm+ijzoDh1OU9613+uBwg/5LNgP8h03okpwzdCGp1qicxE/7W8TtV3N2ylR7uGUD8QyHz7W74k20+NAfn53aKqsaXSJQvLDVz8XGT7kPXk+yQILm3M5fsJLdaMA52WGU440vae2OgPMp6o7rjJQXFSHRZK/JboXNgWNGkQt3N8GODCe5J7lMC5lwtwCoJC4snCC3qsjt2KJZ5MtUL8zqHWMZ9IESIPdzJQZPzQFqVFQ+Bx4Pf9yknJTMwXsRlDiwbDS6hsr0y3uk4tmwSH4A/3OfNYhMEXgQlFpLAkbBYwmimN2yTmgGHr6+ve4whpcEshicPj4nNwANteaI1bTuB8mBbWWCHqqA/zDvS+LaAejZkAtxmzUZR5rIoinRrs6D15Z247hsErqCbrCYKNTLDxmwqIABJsVmj+VLjO88dt8VEd4/ZAYDF6PRJoetckUUP/oXh4t2YoSejKUpkIr3/I8gV6ZXfh1zXvJV9tTXAoGz6ioj6f0OL8eM63jalHXSiYDTqJo9c6x+KxFm4x8Fio5CxWSKJcMcmnElxLisvLJaUZRXHbt56ICJ1Tg6HnR6LFddM8P8dWanbrxa+0hYv2J3McG2SbAAH79Kg46G0nyqBpxfvXzO7TtXWuC06PzukUUZJr6YX5XFrKgCxbKNkgvqmi2tBaF/dhVBvuSg3bzduynEXQh5tGlFwd1GgTy8GYqDTH0jUFHCqbsnN8lIo7ughaVSJMlOq0ovGghTOeGHFRovza9PIMY+lGlAL6eSL8B6VEIQYnibfW3x8bkWasG1aEI0OJP9PZwqO43gOfirX1Ok2i433bSgUFmGxHWflJMOEDRtCu9/UfoAIiDphT4EDRwqL5tPqUJvG3w1K6oiKDYiFQyT83gQ6pWR4LQ9SesDolCwKlxsAwt8ESnlIQjnVj1hfVV4HtpZU1GX1r1tLqxwGhizIvPp2y3jrJfg9PEap5Z9SnOIiCbrJAoNJWmB/tKCpK3tyJUmF0oTFJ23omyB+U9nhDOszMeg1ljlGJGYjJ3BMnhipprejhfGlji6SuwbP2mp8Ttld7Tj3vLdRMbm4Z+8mT7FPO5DXpfpUWrFCiWhC1dMFPNJ/N72C+Cr+vQ32Xh81zn3oIz4slj/F0LJpG/zkscL3eEcP7bmXkgMRJH29TL54j3AK3MhNUNidyVHqWOMT4L73+b3M5hVg8Bk1EtKhRfNTGenKUA4PN4NBRVmF8105aExpScmKDF/0j46et7us3bhnMViUMUU/J6mSmP3dgWHgp81dg9e64WCtPjZCrmuxYyVTbj8frmOB5dfC6GJyTnKDetfjWXyEs/i5ORXViJjHQEqWR4DohECXJZu96Uthmj52ZP3TrvA9ST40x6snE2Z3PiHv3c2sCqfyjTNO7OU0uv2zAYv6ifsEkMAX/BVcMwDZt61+CeYdD/O3U4O+fvPVf5R2vTbt+Fduzua9Ouu0E7xh+/fH58Wk4zPYLA1n1dEqY2mSBksiM9bY6dScKZbiJWQ+OsCzcyT2pruY6cLfqMtjb1m/23f5Voyk0J2NnJ5kiyBD4+m2ANybluANncsc6HC2VpAgY4xS1AdYLIwZBVWB9G1mXxI2nFyaCiAiQrPQgaGwweE8S3/FHgDPYiq+VGWlUnk6Q8o39NPZAjoYhFwftOHTLvWjlnBGbwZoNgJtsNaU4JZinZT+YL339o10VRZpm8fY4vWecp4yszGO1oZU46hVXZwmPb0jWHG2gJdmjCde/mV7+j09RARPdI+y5KOMErFF16PU89BvLIo+JgVsGRQpRwu2vRQ6hMEH9+axcCsjCPgPZiesfVGl2lZeikozVjubXwrzr6qD2EP8QB/3e6aeZlnwi77ZpxueW7mYMK5L9F8FDAukmQPu1Any9uV246tvAK1gKbnOxMgjrQH9mwQdPgLGwSejc61tlmXT78eta2OjvUD51Jv0212fCYU0auokhLaYvFbjqLF1rr4pbcJ4KWG3IaNJ1DIDS1qUlM+lPLLupILFIY8iWUj66GtMUUA+jyNf8Gqrd/PugZh41bwcR3RPgaGlQG8z4eK4LLBsMhodfmhUj7aZjd8KMrgn31jcSu3EC77rGeTXFzggB/j3Lb/ZoV700+UilIlXFK2hkTROwFQkVFWn/8jx5bn5nMG6dOt8aAJ89wYTTjl2bg2c99i78ylRYcr2r/A/OasYMjTSSnLatMnxaaIaTnJEw7nvq2ytchw9Ptc28g/96mIpmPzNkPSDzMwmKv0yUiO4wk02repV3jWUqtidxwZ+shlmNL10iD7AxalZonZ4Z1U0PcvxOylCCAReCxTP9yXxk887n/NlIRjVyn80f+sgrM3JDNKSpmnFPhWaSeuj9IqVz2aBSQrtpvp6RBTFLw5Y5GQBMsFIqgHQFFqFLIZFgq1ei2jikIsPpMViBABMGFvgOeILPlUoTFWhQGcoB8WLLiAsHriGRTd7NEBssAJ6+Bts2DGjj5mc7NoXGlQnfEJRaZcEAfcnvifDpsXefi7nrN8iavu0UEapW1zlEDSDyRVE+Obl9SBogZK4yIFlPM5NsZkRq7eFiHP1+2I2Zw74xCAYm/E7ZX/GyWyk7Q3QMvheGX2luE52xCqRW6u+eXYlgo1EgoE1rONbmcfsDumg9nRbwKo+8186OT8plBTNryvXX4wLcuTEqrRNlu+RuEPOT8kvP9HYyAajp42sufYlgAzzf6yTh99aU2NvAAqj8/qCTd4J0I4Nh77NZhqJdRIxYoAa8DMG/YLaiPfmuYuF5RTCXchSjMwYv5YqkKft7+8eSfrJkxuAJ21GH2+F+BfGIs2kHW1uOK2pNzFOTQ4vI4GafWF2T/H2+U068moFTL6ea+yZW12Ze7cTPr2OKNIH/4F8rmxQnSiBGNPQVFbtkxGfOrvZExjgas04Mfj+H1c7kvthQcDmpyO6GztLmkJS47J8KkCgCaDqw/xz5gyge0hAQntOJvI1TtPrnhIUn+VxixtNKwGgGZPlIfxsk2Y672h+bNAg3NeQfATx9J5R9XvBHnR8R/VnXRvA47NFlHtfxzY+CRFOi0o3vIvpNyPUEjUU/cgG6tsvLAtIZt6v85zBGKDvFIPbJvK281U9Qmpwi8z7ryLcitcInP73Gpbv08MfLU0+3Orhhhkfdse9hr0tch7UArDyxqYOih8G9baAlju6d92X4hZCYUDm6z/ZHucVDOzPopDhY7mFjwUR7WoWffLfOuBogHzktl3xUiH72dWIZgWAc4Q+OWmLuBJJghMKKyYZXytkHuo9JWGnXLJ8m7s0Zjyd6Yr7Ks+ne6a/G8V4mMnPGRlvhtWpPNpuS40CWYJCDitzH3WS0FoQXDhPJ0kTIqL7U/sqoGmryl8FSRDYA87baVqGpG+0YaD1uMdiznD4REnIYFqsALQOTB8CFzdLdgWZ2DxyLYRpXOlHFSHHy/d/+lCk23eHEuz//bSFl++WH7ZvZmGE/qqba8lrnOM8IJbHgI6+CCsZEPiMBGNxXUQXlf0GrugTvJwA5E2U6qA+qMtHrn4V0d98+LaR9HTde71M93avIY4Eog5VHI7FjExUstqHHurML4mt0oce6uzeIv6M94RMXCSZ1pcnSRgILmF6766GQ5tkukq04DfzbHuPSfTlzn0venrdBq2w6LiL4OYI29/ivIV//FHeZAzgPvKfRTxUX/oHg6GxCf+p1tt+h4jgaZeeV1eAPCxNjNTgob+0wsav2XHhiU4NZKGfJODmMlXVeIe96J9pMUDoYvfpcC4ZamBOIy6x6Fr75IVImPjQrjLYMULC5A9O5Nthwgp3c2g8g+i9OVkpF+NrvntVkZ5OWcrr7QlnX0VJr7l80S7LT9j4GSAxvbKUsBVvNMZQB6Wmwx+5vsPxfwMK8Hom0LsqqOt1eQDUItm2oZ5zrEQ6peku1vLMku9zbZx0pUz9+FUJ42Uu/1utIwfM+NtIFkaoT8GU7Mw0xi3h6UyjxPZYOCYqlaOhC5UudeE0WA29T3rbAYSVZtLxuJBoB6UpszeTpslT79H2+gbkUNkt1M0jKZStAuOKFF9TP6X6O0kjp9ie8zDETJl1h9+xHG5APCuh5Bnf53PbDaQcr9OnhtWe+Qr6Gldm7Hf5lY9ev0ctOtueJVvw9tMPN1GojmT4xPdeOvoPo8KECwViuzAdxrNXHcZupzhmVLWqYE97URe9g6bmQPShrSIZlpiHErr0+BhO9u8HxNKIDzXqVtUTraRvW4HxrRyA29kZzMd1c1oERv60aQPUXMCFTJndRwqGu0Z2cadEeliPsFjSZ+k5zLZQnU2XtrzHhjNWtUuJNw5ZFtYh+kZsHN/l65MdTkX8cDn4ezbnrh7yFMF1/9KCaBTstbP+IuRBoFqIu+tcT1kdQNb+f+4z8A7dQEg8RO/bb84IepUHMcAn38bZ62eTNdADh+awF/MzPqBm7fJsAJT9stPv3U5cFv1J3u25azQkLg/uWndxt85duIu1rA4tagqeGKWEuUU0eyhJB1LhBj6FqjNxgvD5T31sDJ8cfUsMjqsRW8R+DhqhBaPQgJvn5KzQv+xiGKNBtWgsvpMbmNEZOoQafnISTmg0NjxyJWnybvMhcDchSHmRxT46bJnzqymkbyApgSPD2Kv+C/p1Z0fNQsVAS9Y/z15JGmlwW3mf1D9A/8Dv70RphW1NgeXna9YXWaxBm6k63RwckAZGqcisMLALwI5GD1PI9OyfGGr+sAUwu6d0K29aDNjoMh7m9hTm9YZjhfN2+Hl/Yjxs5BKZrZO+8ECzl/fuf+b1Y1+zBZBPdm+uPJNjHS7nSepqyB4ASlUHf+ySJhdf3hvwAe24mKo7r0zgKlT9zVyo2tO88jmZY9yYXqcD9EkWHA0JuASDXmtAXi4T1lgXr43BALvmfEM5LvY4iBPSdPPfJ7Vkp1L4gbqeixhsBeEqAc2Z+06vBc71UuVIdrDjSiQe01C9RhnCLtfUBEfyJQ3Yixl6cH4IVA2cCn1KF82EPKV2+080wLz56SQDkWb6F79E0DqB4Ndrh3/56nfHXuTAaaDHJteyF56612Iim0l8RTjrV32My5vWKRkf61P3Qte83euntyxJ++UKCHkdCIoW8JwhZ4UwCqR5xS793Im4Cn7nangn8Y/Xua8tU76tM4aIv/BpjkrVfk90fhvHnTARppve8pYLYqzl6kQnWuOXBQ0reXindkhuAa2atUbGggnY7WnnvNIvXwG9V74JsKgZHRGuy1355pdn17UuLvMUUf0GEfbf1HRwo9LIAB9NrRU/tHh0bwjE1/P3ZxmR9sjCaAV5vCE0iiUkNudtYw8XL7C7BAAeRXWRJf6IZ1jmPfG0a9X74XOZ6CxJTWQmVSbeb3mp42tkwYA++JOYnIPGW3XaG6Hn6WuZIGX95Quf7fL8U25lEsmy7xCgzUQUFdVDaBc8thdwMI24tuig10bzl48EUpPw0qKPn7zrbOk3rY/MxsEL9zgEBcxW5gg5xunZrzN/UGdS6U/DWbzHTzp+KabE44yd4SEFX6wtKQRrE/B4Iou5KFtbDiFxJUJAqTxUSRYlQF8wWKN+L2KnAs5fUl6+vCxQuvbFxba8UquBgGp+ugTfZzrDI72uPI1PSUEgYXRZ3+ofUT+i91P+/lyVy1ZzyAv/AVThf2UxSWkFwTY0R+kgiuaxCEBI2LMj3VJctjBrw1ybn9z1h+oEwsHtun3flj3JfexuJgcRLbJvMkB3MjSYNMLAcoWzhbKRgzIDIe9lY1KCqY2Cc+FCO7vkHsYUp434Wqd4wlBqiftgjAcJoDTyHnvOoAfPZFUXZHM5C0qcmD24OUIU9blpg+mhMN9IpR0UbmS9yaw3ktCMYmZCQLczMUHVXhS/n3qv3himhQc7sVMTEbVrIhh52dWN/ZJP0AfXM+aqmGnsqPDmq0EIFmzPQceQeCeX1pePaspyN3bQtvX+LLXy/eVFPFiGWu+dkzxx6UwARrvfCzFu7Iso+63B+0VQLL+CCVRK8kKOUuVvY8KJ+atfsJ3s+XJKqeH05bDB2HMYtbox+OqWxp3q2pmMy+dJfT57m90QKcc2v1MmzWSt92ADyb+WagnLuek1tXvoMQM3AuBartknhO3QZnTvPMBhNb9isS5rREeFupSNh+vWbU3aB0rnOAmi2xF83mNDWPR68tWhYJczogIlpgTczXEOOEyqKywFquNXy1y2Rp1w/l1Hl9UWJ2sYLM7XaTjvlmo6IdDK1qHmRq5rnIuz6KSJte7TNm062U2iw1LOrHE4WEzxkFRWSLWgY6oSygY83EvhV2veGqnLsMjf1Yfw2gOp0r4roIwECqgzqS95y8akJAh4Bp8AI4XDBzM6onhaU4MKio7/SnnLeUjbk5ihkkI7VnQu5zfzdA8Yk7xMjQFjZT3za/FboZ1JCAQ2AaCShYMNCTCfauLml3xMoFuoRJOxXAFnNi5MW2cRIheask5yvOuRlYyMGCwCDrH/63pKlJsMOgeI9uKjWk9J/2mb0bMPXhlTTUiAMBLSb+RmDz4XHpSK5mh3PoSZLCjxbWPByCdIoMRFhWLzIJaIaTOMl0AOhAAJssige8Z27YlhqHbsy3pmLkKiYPlRUulMb7QmX6UxSsJ2kYuJDDrcAdaSggvWGkAsjm/p2Cvl3OXZFt6H/TforFxCh3Ccx1EGmchNz96vDDRJNQ4X+6gOTcKtK1d98QXHc7nehcjSHZkVJHKYHuNcgQcLGBllKsX3rGsx0+QEiyWwGOpITFuIXE4v+Qe9Jp3yAJlM/xc5SiOM9RN9m50LDxPuRI7tQjUOvCoZT7IQiMVD2lPoVGIUMJNMBvvLXquQY2mAPWYhi78sadZIuJd3PafHCN29ztMGeKutYIh6hS6E1Vs7pIceQQLYEWDsGlN3rWdcY8BENNmECMEqGKUojDl8a41YOgqxjfYpYAoiHGEKlHse1zKsP2Et/1sXBiLD+6xv/kQ/9bHHzogy/Hw1/7YvPUTC4+rvhoUYG60s+k6u0DLJKyNhcZ3BBckS02PR4KJ6e/odyG3qc0plN5QKs9o6EPE5YCDeCdSyCh9SyaHhzjuON73sD66Ps83j+h2WnF8B9PbeMaDHoAblB3k53U6wtX5wzCYxpiW6IxJ3/hKtcSfeV+R12hebCecU3NdPLilRvNWXiV+i2LyFWNBYok9WDK2jnMAPQSQqirE/tAK58HkxpmAWM+T6a63n7RSHSOcyHmiiXujCqW2iBKnfza8P2jrcyxOoLziE9QgZaSTAGi09rBAERTGheCN+GhpHittgUaT9EXNRPM71bu/a74cp/qJ7zhoEGMvMMBt8EpFt3rlpZdN7PtlrxayOG2ZzxrTSY4VCn8DEcFGjrgPwQ4HkjAk/WpEp1suN0b46Hulijl+d1NnloUU8nM6KrgCr0H9iQMCxj24sWXg9CAwSK42IaB33GCUOiczGmESOUaXQK522oPvHE85JMqVJzIg5dfGn0PFSZhL9CNBo8qQ6Iq02zpPCJQK7VeoYg4GtQ0HATtUcYZckmow233PWVEY0UDTxa62hYaKsZS8IIuMgD3M0v8N+lJ2/9M/Hs3HnDehiHAmIvug1oO/0Dq55it9Es6YWBG42H5npFXQEaXkaXGCrDE4qALY7zRsfEBXFNqWliFiKbk4o9lcketQGNpSKbCF8fc81kmxBUpBClJqN7NWJ7MksMdILg4pE4VI0iQlvFkrAWjlLVCiSlMFBDWzyYU6bywTg4Vg401j9H5IZEnMpdQAA9cKhwZTRUcWCwrClv4NaEz6RZWh+B6Tv2DYHrW1IfoiEMqVrLSvXc9qgVVbAAi71nQR9yuz3EIBpNJQnPT9gvtURkTUyouzscEwZzd+FNTybT9O+p2dol2QWVoJoDBLGdEu/fd+5wqnDUDr8K9SAhzLUO9N3bfCsY03l3gAnCB5tvQZc2xLX7JW7FlmQiWYQ3QrospTeYPhZEtAaNZS1G7NAe9cGhab9W4mBEf2O2NJQhBWTiUjCSGbSaHmmNQyjWeOZmAqvVztoTuoO4+GKCPc4eEZZG8t7jpKjiqKNd+BPa5tNbBSoh18ALqfuVjy5hAtmyaENNuJORx2ih6R4XFVcWzj0xiW4qtEk7mlRSdsRb3jhNRs2S2ksEPHO68QrQyHnPE4MJh8y62+L9cDSrQpbv8mK6t6kqITn9ISNo4MpqIw7t1BN0uiGAXqTggZBR1AIzW5vgrVP8UjemrRkrvhuOsC42RcgRTDWuIuJxywqESo2dByAn1nxXxwr+ioOxkXtGqIy9HIHK3p1vavfufiYWydCOGLJeWsQ70W1SQGzo3Fykco2wm5UrPFanBkD6KBJmrJ4XcgkaBK5v6EFV71SONWtunx5vYVJQgxUq/5q6NqVorNa69YP34w4CSA9gsa2BkN+m8WIj6/FqUHkjDYy4zKgs5UJcY34cbOyJVQlUcu/xuQuuMe0eekYBr0nekW0n7cymK+lWJQKNJUEoVMAAJYbhaSNdx8FDQujK3LpDYINWanh8JNmJ4kWtidTKq78hHc5DjKIP6v2YsSJMZCv8qH+c6J5cr/adiF5B3SWdWyWnEhTYgaW200npNQaRSbkB5E6ZRnRbC0LTM81vn/aBSD4UWyrUPlkB+NRoTHiZ8UsdJufbx5pxzHNfQJYUDM9nuCJI4pcJSABq+6pZu8ejndURE/tmZ5QvZEQICMGTgNQCph3WFBXmRtDVZ6+RniB862dcHGZJbDg52dwrDNxjHfNaM2RszGzQN6aeR1tvALy2n99PAjwNIA9FCKbTKnM6Hutw5+0NenTwA7ZoC8fpcQzuIU4pyGJ4MTdazxGdBkzOnoOI4KAqDrMKWvTdoboUdAcP4RTiwiXof28MJM8U6R9ENlfPG+R1OXjbQ5WCoBslzL9joxT3N6I6jKsfLUjq08YX1GteEg5lQkkPDTgI5eHnCiiD8lq0hKExgXfNC06u1mHk4KkfqmEu0blnsxLr9w1HdYXzfuIb7j/IjFn/WTd0Q5pu6aKzhyAGswXD7JHCNMXW1al3E7BNejcMtG6BsB7/jA6vwn8NWrwe12vNoDa8JISEE6fsTGCLe4ueajpgipF1FxHpIF6j40Z92kD2DXjb24nFyIfwBWj3TuSEgbwI5ewTqCJ6RaDWiQtip8jfSUc0rb98UUaLzUVXryaNWLxpy5xn+tSF+jRcv7rGx3YFszDt3dLzeUgnUtoEmjAwV1y+dl3/VCyUK8ux7MvdpmHCol8v6dR41AE7Jxm08ulOso6ipTlDKB85oQEjSlwKTHqMZr6S+1EO1BD3FWasdwX9TB5Tyfr5PpQHkI8v7nlrJKKB7d/p0lOmWFZHLqh5PdUeXnN5L0K9UHvNCAog0Ori62sOND5NdXZxeDiuzTqIJdOaFFRB3ncUQOVjX/F7PEGEY2giAubk8Ra56b3UEThDiYpqs7k26lYhEtTduOkqVX/s1mnWyA2ielpfXOgif6OfzIFohBr1QUTMYT6ChgzXAN4jWsWdQzV2l6vb+y7p3eSqqzuLlsHDQtXFlC0iqWOLqEVqhzOhArhR0CPoBAOl8AFNSU2A4cbdCXbVYn57BkLD8quYz1/LnIn8rjyBIx1tduwROlOxrK2Ytsgk3ZNBwGQoHdyIH8aZfJaVJ5LEU5vxIZ0NuItKK4n3mH6ovSx8fG971aGnKVecI08uhNHPAYW1AJ1JHJRHhau4Jg/Xr/fPBbZEA2ls5d7a++4SsKw3VlzvyXFuv+RJbp3/XCc1l0HyZOM1WpwmnXodOvmzcyfU4zTU4DSy75EfNOut0FoYA8WxsJ1W/hZD83KgwwNWMYaB5bdAMZqPqhj87GtNQIzOcDED+kjpysaFzC+rQnNYvhu+HifO3nH9Q9TVeOnr20UURvngeKzPpkDztBaXAVcBcWSyvfJfwU0Bfq3sSWbg6aE+7DMXC4x/IEi/+Thi+yUE9cQmYHCu6vkK+lwN1WrDfgQXKvuAg97k137u89fGWm7fdw7B78nL/8+iIuh0esJUW6ypSdLtpcq79/7bMvdYIfoilQMgKOkqjpfmRhKKVNFJZURz0lI7aVRx2t7BxcIEvULCrEgluOLFRsJWsnftRmHYz9iPl45cZwiNZCwqQeGgQ/xhZf+nLBtQ7FnLx6V6LQAkhW3Dup1btf/zgHnCvYeHLQTSjb/Qt0b2x3Y2gHA0RtVud6ELaxMichZr2blVPs191dqCrAgc9UEOMe72e3Nvbbl7FNQxKpC7He60se191UuHSSy8NVOtsdK+bQ6YqL5DcLsP+qarSYkjaqXc77LsxwUKsk46tXxMHseVrRFfW0Vm/CQaAdd8NJn0Xnxb5W2X84bnNAkGdpimHZEseVJwMBSihWenVQqlEmm4vjJf1T6kqbjLjpJw0Gra6zouV38xvFpnMqdMghO3Jgsx5Zb1XRDoxE9MxzlSPHOENG0DDPgpYARz2PW4mcjwA6d2kce3VyJTHkdgvSzxwv2WPwRuB0JLMGnmMsMpO6kvSeWb8ZLUMSIcJInMUs1WECPvjvTh2BN5mm5pCztDbVoB5I0ccagpvRFTe63nLNJuAdi5p1tNxFR5g1bW2M05raFnjBss12xCpbJqFeujhylBUEfgO6C1hOqoTLta2cMZAM5cvP40vhOlJH62CpBoIQnirsdbnV/Ks19vKWLOpl47sNvG5L8UlwT1hpGSuBXnkXKG3kOgvHYUlo2cgP6KK67xa9uC04CqnT5wOR3x0nhlTcXxQza6jqatXKa6QlmNGQ5SHoSo4Ug3s8klEHIVrVn4dW+L0wDx8pjACdK5W0fiLs6LwjULn7GyiD0zSp9WNTUDqo/woErRL0VwkkE8mFDMy1TIel+vphmaKLElUyFKI5Vw12y4NPpRxyCu7SrfXb/vddn1lDcFiu8ZbeeyA4EyjChc8lFum6w6FfedQ0JHosxZoXXQRoay0ljdn4I7FBIN7uOWo4XRPmOJCdj1OOAnb4H2X4bffXB90+B7MdZkgkL0iPVeRHXnjIO4XDHNNXKNubcwsCqDJXSALMpcJ0tP+cwE701BazbpLC3yyaBBjYlTJG+reAH3bqtxR/BLkHG9z4EJ6ow9zBxnMoT6LCyCMzxKTpwi3N73MSf7S+GFA6bK10sm8lMOIz/VXVutkvbikhe+viR5ZQimTeYCawbytHvx/gbNeLq3PCJXThGCxQp0aJdO0rcdqpQjWkGK4uJebLafLQnHBBTvv6LQLWHQP83+Kws5nA3dVWPYoeCuRr7CE0TMabQpLGQVKIy1myZoUHXkRDpY4AtVNUsO3usa2bv/U0/Hquq8VEB3mnCiRmiazxaF341N/jYm9HVm1CXV9IKRm4aMG8//r+s41eQYarwlXmtQgI3Cbu+WTZivuwJf+l4p941b3M04ZvqrudlwDPjTmLOAqMcwBAx/G76qsgxge5bj0hrpDeXOUgFSX4Fr5jQ57noEIM2oRyaG646309cEDWEsCHavQ9sv5+NoQAwDdPPTzzami81QL+QwC1v3S/ss35asmcl7nSJCZrZX09Vlcts7dhN/tWLJoS9RN+er65xrOct2YfVVZsOVLZK657rmGqxWxpcqZF2qBmu9B4/KiO5T5t4jwXHmuFuJBg2av3C6kmcl3yooBZlm6KIPO7f1n0zRDszJ0BK7434Bask90g8FAHb0bkQPsw/jNVBpsUaq24diEUGSrQ/dD0t7CGbgFIXnk/IKMONcS5J2hKG0rJ5H+o5eaBajzTe6+j8Qs2/f4HVsmTXFvvEf4sQgwhCONKjM0BtRoQOPy14BKOPBSDMbXOa8Pq3DAEB4mInc24y2ejVZmMYrn0M83ZMy0qRakU2KGuT0ENd883vjjNs+/TJqZ44pjB5WevR69GTi5QZrbdm4z8l4oNwqHXj+mN7LZ2zSlc9pOMWj/lD7+vy9CbezDU7WfqQcpeiVptS2/OpDIVG7qSz/mCeeHuBzyqAoaVB1/jYiXA2/F4KIsrxcHc5j1tSrc5YzvFDE/qOVo3ZUHY+10DTyOayx7NpnpbeqYjvJTdvd2t4ByEDDBGCcesxbBFrjJEU88FEDPjkAcOWzEXQ7FUbdkxBGRcOmwfTuNp2HRF5GHXW1XndKfqKFMzmak6y9neowkxSsvtmVUaPuMLbZSW/ULuwkN+foMox2mQNbCG7LqAGqoQDsAgO79VUrAg8MhEUqZ8CSrtSs0h+QAhqVOnCjblpUNdy7aHcyorngEOBgWo2PH9BBZqmYdTuDIXhwQ8rSMChZC5ptdUf/cr97KVRx2UJbYC7e7iNv2wSEzEbnGXFIqTjYO/eQA/HkBnlWr1de9ewrDi0xJ5jBFaUn1XYLYvdSY3sgp4gFc1ZPugSAL4bRM/4BTmEdQfwYvmMuHd3EMzw2CPLjF6zU+PZDA+oQ7wgB9w+wlWeo+4Bfeaf5H+Bo0R5AsvRHzqxY7ui9I8NiY75VAp7wIxWX1Fzt6GCitxskMwy3PCq56c+0+SaQln+reAP4zE7vflILHLQ8opuV26eVaiuZXW0RMwfjdhGDxn7EhCP7n7pAdRUlXP7kia4txOwx0Lb0ZWsjqgHRFpEm/VqWqtr/u5LmSvL0W5qhsPG5ElkopPoQVOAyLSTwpYdSwreJaGsF5ty0uHM9z/3fguCIzpZXZkCM3ebzGqWKTnT9kFAzx1MZseaNSlHpqtH1jwiMI4hUT4B64whKqq7u137kyC0H8xHlIu7VJl9bFWIGeC29Aw3W2/UJwMFHZGlTm5zra/bayWP0U0gPDfq9QCzG4hps9SKDFcMI+UFQl+LnYDjQxxQdDC0FSkQghwpYOoLoL6Ah6KGLrSbjDJ+MOOZcyNd6kexW25mNH2juYDDMl/azpJXxj0XgI84L2KwnzQvAY751o3gjbXl7B1hBqQSV/jfiI0mdLe55BmY8mQqsf/TSD6AxgPLXO9d2YuO+lQdhJYqRXFECjDtfbAvCnZhWllep8K5nIOsW1U5+erlIS9wtCv0uZ30YzH6CFVj9aLoYzEj1Z6Cfjd7xuEuzCNGJQ3Vtf/dLPBxSFxGFeeVGMipQW9ak6Y0gcf6TtSEoM+aib87uQmTv7x5XjnR0f9viox3s4PuDx3ONipYu96t14fyUYb3ro3o5xElQ6abOnNbJ6RwEKIj0UBxjM2uO8C4WKiio439cAekZTABTJK+k70TOXfBYGMHf1b16KrvVHnifa6cQrDugtgg8zQzK3G1Mj7e8ft1j1u0y6SzQvSh7uJvkGxVkyb10/BYZt4m7cwuytFrAAq9dU7cAUZTzogfY0Q6WPlTVdJdNjYnqN1rfpy7f5xbd1h7X9eo1NC5M762lYroMUCws1nvw+rDNpqPRHTggdC+awRtrdW1ncI9Dzp5EP87K7fW/DG1naKmYm7KGmQ5gF1dziYFGDE6MJ/U940zblbu4O5V+YY/4cRXI+HqF54b0av31JQ5vgUCPoinoOY3hZfirhZwTTIL8ZQwMhldzB91K1sYlqayvtDeTqaAkAVxeexZLqX3TPEE/raCCoYF1LYgVbVaXSNb6chcsdjMdLYcff19BrSmUZOqXP7JSDQEce+hXvWk9YJfZLxAteEzM3IynOBXHNUpVHF7XLmL48Ar3sJpnksPj1DRAavZvIvFeM5jEJCZPss89kjI1yCCDtN2vZ9OeFwHuawY6Uicuv9VqJzOZeifwmbZIAe5dr+2r5GZVF2eujZYtuG3DtyGXjO+tIBuMqly17uc0dtvmR6r/vErEmmeSe052qIGwhEMtn+1UUKMGj1gnlmFsu/hHbpMwYvYXirHAw+w1LWwP8ufneOqzZ/wRpFGP6rSsz7llh1N0q6l674pvLXfTMZHo/GwONLlLQ+ur/KpJZtZTaVXqU1/3SowuWmGgt3ppH2ot9PlQxBT91drg3r6Wl/RJt62qAWqeP6IKr0BIrswvtV6Dcwtq6e4Sd8HCPd04b69aEnfhXVw4kgJ3gCbVsYX950n2uFbz4rJjczXa9eR8+8kD1N4x9lx1+174qP9pUhvE7SllUX3+GYf7DYWsa50+mCLS+5xeHwUjbEig/oO9UfVmZoEOS8daY2UfwR1VijW+wPY6BeP54i32+65G2D3O04/wvXMEghRwR+de37n5bzv221w88rUDL/xmxo2D/NYdR/gv/2aoalBruc/r486sqUdYuNVn8NFb9K49YkCNy2FATbmp0/mlBVEZ0WCb5yzpCpkQYIVFSR6zlJQ8ivsn7lZzJfXzo+Rfh6vYYGu1KkSN09280eDrAsCT9823Lx7nMPv5Yq37uLNURun9kr5amFbey20KqYV7wTO8ZKNlYSQkzPcs0JwXpjnTKmcswKA/alqcc7Zkz2hONIiZKg3agPwZbUb31wWPUHkqjazvyDySU/2yfuleTfjrAAVN5zOJa8SOoBQa3VEnihLuy+BkY4KdVFoGMyZt40QNFqQ0qA5T9K4Mrk3weWdYLQhxw9MEwZCL/REon7SphL5P6szrNHCGiC6EFn84umbCQffHncLUwVGFZ+abBA7YWtsty/h6w6lDs6ih/f1ezSH8YX+5yk652r4RGbIXvx8jZT/vsylR/HSSH2degUhM5wyVF4L4SQs3uLggipSptvC1CNWqahPAGKE/DbK3HRBu+o2Y7xCliBXhsiZZatT9/TMgonKbTdBCC8EOLr8t6iXnUcPrTIqVvLzPw3wqsv8hHh+ZgFTZVnfIias7a68vXMxKrDUgyqHQPgFlnnL5mrTIclMoQHHDNrH+8RBfbSaNLWd6ekE7KozFTDiyD6W4eeuNn0I4O7yxLINPzJMTJrNXnSdYxzjFOPWK+BC/07t6BNmKR9wLpL3+7t/ORZ7U6Yo3mkdQuiD0PDKwriMuM3WVQ4JALo/7DyVKcY4E2NuFL62kpgSFAKo5Rwh5kkrAIooflXJG+m2N4IlIiE5YPXVrvdx1hs2YGEnolw7F1r1ZPAR2Wfe6uQ+OyEm3OzHsbQb6sgEek+CnRem9HN2g8LLaXz95x0iWGmO3jPp0fvPVjQbjkk0HZ4yy7eMzYSAOZ6Lx9nA4wqzvnm1J1vhJgpfayGYXZK6eKsLOu9/3QNM0EkGbZPvvIORmMkHoZqLv6Nk9AihXwu4afZ9FZ14v6fiYEkDdYrQFWutpPy2ObgbSrw4TlXQ71z6fIxbsPTak1A5Ov0LTpnX2pEsQZ1nSUBVxb9EQRlQ0RLAE5r4EUQCts19vdSOK9VSJ+Pyur1O1PZCtTrG4htI+0ukxiCyBlOgX8zZoPpJHZa1qpOl15LxtXftbKuvWOHeog1lw+DI9iBPwORgCI7/tLOIqLKaX307sXeXx2D5Ck3AxODXxSqQag9qOpo4/yNk9mhYLZDetXDS56Pvq1zl/cWE7cwI97H0rbMgcYD6s/VrubWMuyh2w6fPHDcwqQmOqNxtb7NKwt+Ccjb71kHKDT+cslTS7GKvZsDlFhOW+RSr2/SENq9B6xWbWM/G6/28mwk6jErx6LitwYdLWWUKw8m5FOGXcH9HzEVlcDhpbHlea5SvTdd4wGbdIa8qhQadG0JRjZpsSoYgu+CSw3qG+dUokaoXf1Y6y8gkxlKXeM9x7xn0+Jz/ehEo3To4UjEOjuIuZ8EDbPCx8sFbP2TmWNjRt7m0eDyYS9uVYnCHR5+mzbP7m5UOVOC5Uai1N9W6BeuYFu+ccG3eDTxwTBtfUErEAdYv+MHuSzYr6ADEqtqL6QNKWn8GCv8DaKddmNZFyOY06pfJJJKWFN1YZDe+OqEowyWOiZSY+u7y7/KTs51P9UMtB51CP8WOwhHqIEHVqUZ6PhoOgQf+fX4ucd0sQMqHqp0Z80Sk4m7Kw0ivafZWD46qLkLKG962D2X2vA5l3hwRLUnWUpyahaQpW+hRTn+nFhIXHnOMg3ZQ8775FbHsBRylUH5A0pHP4ycX285tUtvBV2NfBbuqweXt4TDrmjJ8wuqAyCKgkmaCIJCAZE6BludhIKYnsIAu0sZJxCFukcsBHHUh7tbErppHnHEEqCLtiKouEnzORjnRGAkIg+po0O0X6NK41RoWrJ9G4zr0zicqhBIg/McmNFTZ/BbahVMy5A36zkjGllMm4SAbMacS9gptgBzucJV2s+/WOn51sHLeQPc/9Hz4DwHoFugP/ic4C+/8e/U8lGLCm+A2tAFetCk7WlmSEuhC+bRzamg15GWzRSr3QUxp7NsSlODB8ZculkQrjoN0vk7dHMez0mxlsaHZFOmDhrNWZ8aSgt/0VNW+dPf8s/Nxoe2oOpAgBjz7XsmJHmPOuH1OtOOMZb7mx8ZGLX0XmgOlRgIo3ZNO7cRQML3SMsTcRos320KshAsM43nlC6kCK9u3KNNIKPkBC+cKtgDrEe/Tg/HPWLOZuViVbXXTRIMR7ZwJHUvht5sNR4avIHnrY/+KtHw4W2K3O3WpAkDhjneygpKLer/+BWNKDoiCAnkpxHjbgbdbDYjw2OSsoN2p9pFze+jnJXOx6xYZDu8JIKFsfZ1bKeDvzf30b1uXvqCPRgiNMEiLOrpvMdJOnzit2V9Yriy1tBS5iDfRWm/jJPKH8sWsRVZk27LrrORxsvF28PHDvghMubqQ+xOzp8eTBTGLm/q0N3AfIJdTCFW2p3yrXyaUKDUJ1zvYE+LTTAn4YTujvRcn2RrnV4Pg3HLmQMiwcd2AGzPIZnn9IIDiRbcwz280F67b+LBzgXUqaX+AaA18jbU0b3bQGS3EG/0s6/N85GqOKrHtAjlSMhszzYfsLHePv9ObAa1qEICDV9Hso1tpxI/We3987s1KJSPAx98lqf/W4CThm35q+K3At9bdKFWKY1lC14US2GnrApjfOUEXYLIbLPAifaANmt2rK0PtJH2fItBenhS5oiEDTYDRMkT0BJbrlNAP/Roe+KnF+sTVS9Ob63YpattZqSWMTStH5MqjsPhDZ3Dg0Onzd1lNIHEmY11SWhX2DgihzNhVLwl71TY1C1aMW/dQFmGcOSC4Uzd/JxaYPFlAXlXmLXvJcb/I7XzuHE49Rb/PmcMadH1i527qzg8mhK/TV8EhUPndZII6JfZPVL9t56kwB9BLlzY3xkTTjoSzu3TcrT0qCYt1q1qnpXX//gs2aRoLKuyZnPnasO3OG1ZRX7nLX1jNV0Lk/6CoC3DD+7+wDIwLo26MAq97tSof+KfI/7oQpiuU88/sHeYZou9hsKjFH+liu/zS+V2GgB+jx1fbDs8mq+G7SoEmJYulj9hDnPfBaXszEaiSEGSVC+SlsOkO/qr1KxnFaeLX39ap6wlRQ/DtaV992o4CKcNktioaTL1Ds/rtlJg2+TFgYd6tAx8LRyBj9u7bcUSibF48zdmqENDhPfbb8UawaDkr31nZiEFRayemz409go4SIvdpA5Gciqu6l2JzYKKeGPNehoECQyb/6gt0A/oYD0Dy/+1CzrvB9OwXJ1oa6ElT1H1t/veuWG5qPXpx1g3DqRDXyXvievxLe741gNfTH2mCQjIUZawJDa1QqU9kCcCZgZ/EV7MAZwXpyO7Y3iu/C2X4crzxz/AR+B9RYK38eiJdTyNFExqbOJAPKTb0IHl4RJgBR74OdyvP8mO3gnMDRMspjwn036gkeBu6UX/RLtI7fqOL879o1QmNEEF+q+fBweXJjMpdl8mWxZOnPV/Y5TDQmczf0lGyA0Zc8IkMnkAQGnsuNsj1S8zBH1QW/F4NGxeTRlDpeQ93lek2aYBb1qSAOpkmOn5tMjQaU6XG1TCzLxXtc2qrJ4mFl/HkCIL6l8PUVFmSzkC9vYG/ecUzpA+nDD8XN5QBTGYpaLO7sLYSAKeMtcfrwAtcpVbn96aFeCwx21bYL6ZRT7u4U3bohHFKgkKzmzCjt3kBn6de42ooO5R0TyNChMTuVvbpJED28XjnKpylqeLPSDrY9E2a2nCftHnQzqT1ZsSXf3H6kLj2Dm26fZLxJJqcBMjuFbpEzn6umBRSf9btKItVocGwyEltzxYy9kffKJIMVHDS4wb/qYTEBJTSGC5TvXuagvbUq70T6t3bWHqg1Z5spqQTozlarUBvTRSly4633jx43/c4YkdNvobK6JVa7AIJaiHq6V8CN6GQY00Sk4NTtdYwwFY59Supo7yaefFLj4vs4QmJEQfpY7BW4pVp7kFs34BICvcdgWjo5v9QvsdHNoF2JNfVsvvDQ42DMPjA57sPg038VrMPKNGTsBVb5wmFAC/kdfeK0F28b9u/D5+JPuWGlZMcgDL9AvNp596NHZgmW0sUDgT94HXDx0ZgsfPfFOBDCHrWLz2/UDmcwRVAxHtGWCm834PRPxjrQzsOMMv3u7iETvOfSpmgMMfxSisLlUDvlVWTXxc+k/ctxmzKLqxS71+J80nmGWq/kQXaMhQVgPqyKQZ1F9Tq5Wo/1ccTVa/FZ557ALNouOnaPTPJhpf0TpRxPKypsYa0AjZnwCbStpW86diE3fUFSrq84sjzlqz/WFR/qC+abmJ/nKGjXwBF/sJKwgz9UvEwYzR60ILgUW7fp7Exwv9312lqSRtUamUOJyh37cy7XJeXFQS28HdfYfXcEAaC/HfiRFz/aKhbbnTy3fEvn2b5r94SJnGaC+DaLIf/Fd4xqCjlCI+/bvrQUSTGo4C3D6ojN4YZy0EmMdwu548oWYyPBgqpdzNp83Ihy9iWR2fkJG8kzEeMZvsoJhcuYuSrjyzX6B1ltfSs2phd9OuiAcnt7N26zMvwLa/gcbp3KvOYGkj4Mgs3gdge+H3Vz5Qlv2i/N5qWjiU7Yct6jyMOgtthOnkCYHd/QtggvwGGcBNn8EvFXiiH3h5qOfoxmtpUuYV/jThHjum/NHjsg2qNk25RXBcew/Aw+wWwVYEajLSIZDmNiBDqz3gas7geIZGwlh/+eHDEaLrsn9B0Fyjv1z0IbRkhPablp+6qrgkRTtqFN4EhGLm5HOKE9aLJ0oYsDdFQsHJnz/GamwPnXShdH2RU+I41IzLP69R476pScLp6rRFOXHYd0fMVsOFbJVFFXFLEP5kZ12FIlxhiEzGlN9OGdnm8QThIf9IDzio9ctz/CpGUrFzO7C9oVbaQokBoXOOJB6w0JLkD8fkGCnt/32JSFSQltTZDoB4UcivwvcLBbHpxaT+wLOB9IBxXU3V6I8raD8BPZBRY8lboX3BxW1qzUDrqX/umnm07gVcCnGLTKkl9TGQum3d3Br1W1z7zrhHUla75UR/91SHayTXqK7l3ZGQsMq/PZD0oh5q6IcraJ8UsAUzRi35jvS3asD3XqUVnRjoujyDtdPhR7XQA7k7ZBAwAgmPKYfEpd/9iFWdfODrTKJkoAmD7mVYigivDn/2pur+bbci+I2E78POFv/YqVuelxjXIypYSYCpiQOAJHcJyJKSerr6TG6oK8IknvhJu6HuY08xqzxmble0mgScDMB9gbSP2hQ/6AXulOd8NzUX807LptM4FnJNCEpNztT8Mzg/RgmkwQNhrUa4vKZTKKN0ItgosLqRvYFBWkICQILNp/OSmYvvR89POBOlgJkhPCBgDt9buAnlSFY3n6ZS6QajMEcYBLsAmSuxkbaG1sdgd5B/99KHzjz/5LrRsQwkw8FhorXgGLo5mv+Xys84Lih6qURSar8j4oqrPtBVdGqxTDgYir5wU8H1LkTIvHFiUwHoJZaaDEUzukGrj7ySCebHr2ImH7XOlNcNrXWioVDMGwjjKPlXKbXeeI/G783EJuiwnuKcx698W4WL0NP7lIwz2mMlJauJsgat7oRrisSK61uWxHup00w7UWCLorLZIa5MrPP87qAJRhM4h1cgtJxjZl4Rv1gPiBAglnMKwHfVLLt3Hfna+gJUM2J7wCqgZ5qMluEvw5WL16BlTBbCSb/N01D+2IsQK7NiZkd4riN3DzXam2u1dpcW2cA5NI50wNoPN/1+ul7W5lQgs8br+CXcZX+Vvnr7WGeUjqVimSWIYtg7GKdiGoRtwr5utVxeAEUxztqg8GLS6ZbI+HdGIfLbscT/vhiOEtReIjOA5CbM7i9IWUWYrX/AL1PkefvU+TG+7QTn9z3jscitNdpEBj1Vrm4cDT9ItrZ0HWGkJiTrB6PQwLjgbJo1RqmMAp2bsNCOQOtVikLK6xeqo0ongTeKn65RE8FkJWs9BR3iIK8uiHPL+aPuhwgjoerQKbZQie4mDxUQoJ0tD4sq58Wb0+e7yNSf2N1lJrub+Gj/OzkfpeTXImPftYKs89TPssnLVaMDi9eqlkv8sT7j95vLiuJzzqEt89vQGeXMrqiQ7qzudLukb05j5KA2fwDPvlCHfNwdxmFJ0c+jwA4BS228WmFdGzlEVLE7KSTc0efAdgriI0mlwmYjj4P009ohnS3ueRGlmKyCdfOcIFa6Wh77RsQlZvQT1DNC+OwTDOLxR7ptGieTcUSzb2a3R2liWwfnSvAkUK4EVe8rdJmucMlqRlB6OxNIbg7dQhfKGIiAsmn6vVoFhJ7151YqevpvbyMSTaU+E7FDtzhqP5zT7NUNuHMRnZtIoQX5qRLf++SD9LpgvsSZgGesu0lP3yDymNe0gtL5WwagEaTHOHC/XpfYoxkedttqDPOp10XEULGBETtLH+Ff0cphxJRoZM9fGf/m+urRNMMZme6Qhb2zxf9w5VJkx+CPJLgXCkfkcokh3TqNmoAypGGhQ5aUnYKjh3fSZ+1zjY1WnoXWx4H8s5kHCFqCzW6mftjBZZZqAuq4QC4NBvViW82UjEse8Fx00VqVtLsImxaWo7gGy9Uq2U9brmBN+vFvd3Alae8bHUElJUR+DJU7h4YB9sWVcqoFGleIpasSLc41+WSATa3N/B73T9xrJVDypL7lew2gFOZHrowblJje4kv0INAw1BDfE/ovDox/RyAmAOrwq9hqHcZLtPwK4ZhGmQy2Djo6HoXIXE+8vEkOTxC8kXTHv26R97eEeoIoO1sAtn463wEUg6MvAuCnRmGxZm9djsiaBkJojNfpQ9jyByBL6ytODWnF8pjC33+kRlCPF3TnSSYMVrQJYcklVhn68wr60KX5xIAM2dPyHgzZDmBHe2bJeI5OUP4esfvGB/zkLvHd0vnKbljJDNDLXido8R7HZDSfbkoJiSgw8JJHhgY0kh0gNKNdyQLzNF4JWSEo9lNOSPTzKB4n2tAT1Mt4iwSphY6veVy9S4jEqKsoMNKN7jkDV3h3+/dcxQW+5CYyhhzFsO8YzrvtJI8nS98Bbm/i7nYCzIYhY24+M97wnNwha7VL/N7NnKzxzI+rMAwsxWjyTVEE6KRYrYywLtl1YeJtdxq1OMT1NKDhZO3rzUmE3VMFZ+WcO6svYWHCp9ve6jkb/jJPha1/boNfkTc+pyYvVbb0iknC6tcVrZMj0ugYYHnDUfTCQPWvbUwA5WqY8yTTwZgTIHPpGn+QS1CKBp4UMyHlm+5+ZPd7G1IYLdeeosGihAjgn11mlI73U0Sc0Tc+jAptWsvaQfzvRkpKOa41uNsxkJ/XKu1uxnt1+3kIc8CQ/sjA74JMghif/uAT6xEbHIac07AGEn5OKOTLupbPLeXI3uqogXnAoiRjCjC3oMtXGfy48wXRYM2G7YkQkD0XERCfbiVKbe6cN3MHV35gLw1dwzM3fp/WEhooyggYxL67u5ZMkCcBqiJmvb98++N11xPI5ifMHV6tJ038nivKFOIV4Uodr8GDLRoafS9LNeB/SkKcBcwASqc5hnECrS/uVLKdKqAAOChtzQHFsDS+oHNQBUkug87zVQtCGk6b716DcHZuB5ui9TVBJ13sKNz1x6z5R4wiy9cXh6iXokRE0vjsiv5C/SwuvS2v+/QSP8AgmRI79YwWBaDivqQDwqt3hn7B8dyIu6HklJ4KOLW9La8LIKkZS9ZVcMAF2RSVG7dGIXjuorYiELd4KiDmP6vxJferz7GTglkmYd0D8l0nN4ltrxCB8uaZYVV6FqRu2oP9LakauSLc97OpP6oG9qeX4g2NoRnjIjUX3Bwg5nL+kjeYqEzcGBVZuRqMD4jpYF8JgK5QxAnx29vno2EvfOXkdbP+YuMd7wesX8F+iA5nyxE+dliZ7Gzoxz+ugvJMXiaJr6eJLONV82XIlCKGS64xu+sdRwAXYtaMwdDw8amK69SY5vWn5KZjxhH1D9a0Pf35MxBrcyFluWoWixitA8M9zWy4KCe8InY5FbJe9TaQiko+jEyQ4F1hXjjwceYsBlN1W0JgeKk2nCFriV4YCQjho07y4RzaqZmdGb8/9JbXNTrckxXUP48b6IPs3WC9SRJuVs3oRxi1r0GuXjQFDPMhmT/wLgmoOckjD9kLg+Wsi3ASobWKrBQd5NAweuEZ+EAc0wwobJSvqSB7Rnha8MmKyzEcnIHagMMjVhY5YDT5WVI6Hmil9hnkFCZTmaIBNt5YjXMdInAv4RLllm7coibB6t/o1SICPDVeJ8tzkBviBQOGoqluITVPL/Isw2mK7am5VvFWZkh1N/aiK6sSXNkmtTPqLgxUhDIvBJcrzvDV5pbdL4KnY4Ns/WkgYQC/vJSgM3MeG5ZaQFw7OpRvZxkqirp8NR6bbtfVqKq/LLMedLV1ajKc/n87hDLU/Ozya4ur141ylmqqiWZp84s9ZXWUdfXtXV5MOnyrh7uz9QjylpRuId3bu+uec9BlQnElkfTnJWhrQlA8048+1d9TJzVpj5WqjWzx20z7weWr2wiN4/HMIU9mhjzU380BYy4PUYW3tu/d/OwJlDZginiWLRq4htY4ai91p9ew6wJl19mGpULCkGJLa1mByCO29SdGBFpTjvz7Kn3Z3kwtylsy3dteFsuEh9gkBNW5dLl9+KoDffzcXqec46m81yGtrSyefFL23UX7DhLKXDr/or5GsGQvfOIp0f8/IQ7tYclc2/mYA4qySpgAKKz3DRiKxBH2tK66Zd1EQ+aRj3cFOys6oQag2xdE+hIUCl4bn1h5luv0a3d7XmPG71qRGNo5P0970qa7V3zGiac0kBgXYGmGSjCJS6wcIBC7xEWFl2pdkPDrh7reRR5KJfq73c2VJeQ06USChTAMDgsZfvQrlD/5jCg31Ms7hUXaiJA4AZEG5jNbPV8mdgG6IBUpUQVWrM+QxFY7uwnBEoC089ypi6UHF2MyeeeqjADb+h0XQO6SIldPA2PYK7kce8XYlG9AGzTEuVIH8ehGcLQTacnZJXrtiLli/RutU1N5pMBpHYlEJCFi0n9sg3/IaOEDYmCFH7QGdGPeZr1mse2h/Bjx/pE30endkrHaNrp5XoXfReaFXAQme/bFWuyCSX5GkJpSoL0FNRG0r0lRFdePzXx+34Gl2vWcX8kk7RUOKW7OHbRgZTQ6hAm6p990duTBot7EJLpI82/5mvP9fj7kaxA5P7P7YQ7NyFdZRxq3WhfxIdBlmYHdQ/sGkY8kOhLayNigrUQxGwVFvQXF6xsah0EVAzzKNGbQr5Zyv3zXkrGzuPWQtpOc54nDkIMt0mZLtgytFS/KReIQO4KuiGhB6zsnkyQARCFv4FjdFob9FPZBJAkRv3WFGm1Y7LbB2YQThZdUIjBtwh1IrufJTGF2MlZayw/sSngjPazr0ef3CgXcsKnYuMZ+CXNaPKHzfbZWmZ0RbLI25f+8758qR3UoipyW8SeDodfCJBUSZCQLVg3TozshuFwdvGpR97QIUDGcd0ygnlsjaVkrzYLz48XuYS9Hs9pshbBRH2ZFUnDeovVVnj0GUnjIocNK0wuT1ZmDlWc5LmlDbBUpOFr85VFPVRlHEwkZlR1kumsVEgTpHstMASaBV6UU67ZZLa1f8qfSWhRHKvID+2xypswqIgwYFb8E7I4s+//ZIiBuaHCiURguAZZ1Qy3fuFIl1HMbpBU2dvE52pao58VPQ61eTEJLHtm4fYm4SO+pg4hJx9k94djJKI67UEkKSohy84bDJRaryKH+di8w0AneZDnyvQGlgosTkRWzAGXo1uC0SRC+vcRDm7Ic4XGSKYpe56Awb4sACQk1qysMkWK3HDONHPVcGevt5XeMPE/eM4K3V6XmmSR63bkV9sRl9CAD0scJqjeialkXes4W74ym5j7y0y2cCkZMqso54BXBFspgITS0gCRmukRY57pP8I/Sd9JILYPYS2gFQOdEv8eId1P6TUBZhjaLrjd9UZVip3Wx+H6GF2k08044cooW6WRigZPXIKujqIupnSLqO+7SZKRZusjPyJzR/0g/h3tCNNO5vcoRemf0et0aVIpQPp1BfcS9l5Sj8rP0BLWpHRR53ExmI+QFHFLq6BVBhM1MjlyEfFFBZ8zR+nmNG2Fcfet8X2ZdlRhzCHp0Gr1AISQ5hFzLtFK49OnttEgQWEqj6gIuOfE8Rb44lAnajHs7uKnd1Va2m/J4L3aCByjnuNm5Dfyvee86P0fesVPnR5BXhhq+1t9vW3VwjtvFEomwunHTnk5/vZxOOrihF/z24FUkh0GbP1B3NOb+G2X0v+Y3fGUMcRHFhrCYQ+Q8fx2zzvmsWmGVg6gSrJqoqWTcmhnDMFelQwmKZgfySqBUMzzU5crtwJTXJEm5Ln3Dqq9PH1JB9iGfNbSrTguTnI5V6Aj3ywwjId+PH32TNgxuJISCR/YmhVBaBJTawCKXEbEEz491nP48agQ2tGTBvFRVm6nI/0gEJA4mdycGiR6qIRup7CNt+O6QkNl5IMbppS3y98uo1PsAva4hXTjMoXsfiT64emetsJn9hbl+2V+KFdeiL502eyW5Bdmg/+FfBS4bhpJDfDmQGSG/PE/J8rwD0osKptKHJOemVKmFOcBeE5ounTgGuFvdlfNB0oBVGXZkTse7SBP/f8R4NiwMHFS4u5omj73knOVX5gqAzPF7t0dlJqnYEzZRtneHMZGf5U1C2wywSKjasIbmdBsStZTQKgyxRzvsAR88Q+9EEE+Bf4bUcdMkqJnfp8volXWNuMADZUDFlO8DOX42QrE7JC1kwDw4SSm5drl0RC6yMfMHyfuDBuaKFTf9yg58exQtmy0Pdrc8MgzhHShaDO26nZU1a+ub6WzXpZp56IhJR+C6iEZeDSQ+uWk1z9/OLabRJYdHxXSnJmvHqUO/E0LVi+4pm0lju2s8WLkxTNa5ADRedanL9cwwR1CN9C65qtutmtLz61rog5rk49QI5nd+hoJrGBvQx6mIE22We/wPKkyHqZZJoX5uXtCzfRmOmjALDVO5+gLoN36HdzriW4VCvL+f9ze+5zhAPv77RtUSpNw0cjpBoidN6qw0Om7EDWIED6DN3qSaPSctTM+JkfIZszwXoQrJwu1bPDdkxMHOKw4uC5gdNZu0/7pNSmwciKEQkx6kRnbMGerTY3nc3ji1ddPtJ6g6PCOJKN06ikVm2dD6ZLubAkyebkKvISjHb0iHIAradYFSfzPXz6nC4+6CyLXVt7JfRxUCX2+gUoQ4RBzqmhVOaTSiWnaocepmABOYwQ7X4GNIBNoAQGoFPsTASFz2xQVgXkOcZX+e2pKbm/FQ7z1uJSE88aCsxWyUcFKag7TI0PYmV9sG+LT/VctkilOD3RTwovbJZu8DS1/sMMqLtNtImcr33Lk4opQ9If4CpR9/14/NOcFhL7l18WA38TOfFudpQi2HUxL/r7ZzGvr3bKDRfXPRT3ue3d46DQurRLSeydmz97RtWzzUwLj6T2VAJ4OioJ9/WEd+N4zvaXlftma/GFirTeZVhELcZcrVvYJKEkOgZEm4/eYREQlGqks2YM+By92GR9E6MyNQGSRjuXpRPD5aE9wUmDHT1vvORuaozxkORWJ9LbVgp8xwNzToE4n0NJyd5/mwI3pUnttPuL84aYErMKfaqCwB8hm+pG6YAes5yNo53so3i1GH4YXj+sbV1dUH95NBx+GXHZIPmGBXArxQP6BZZQQAkMPVrKTLBgNNc7Qzt+rX9fY3YGlSMRGtT69d8GCYzfxFMGR6uJbb7ig3cPk2kf7yLeQypyhLjD7u6EIpH8pa6nZLekC9c3NlyS3duIMC++C/ljT5ONmdKQ0lrTTWkjWl/Dn6ld3L88f+2l/v+QL7XjtZvpWAMxjXDuPq9W7R1SEFgJUxMz/Hmyvybuyrzj21fX6VUpQ18MbLmdQznnQyJXp1owXgZoyHB+WTaNeHaL79SbWu0MmBqCciCSWwHJdXWX4BSGv0jyQywxeBZCnBFeRx+6evPBjhmoszXtzy7wDSDs3BjGchyTmYb3Xp12LGiVS99BbR5SeGMfx/Peraf5kwHaPY3tJEIrFfdZznPXrUwPyf1gWn+VnTNSb8RkPG7sPqbGYfORKx0qIFteJwAEYEuu/wQOQ4slPrf3s2+z54BzepPRJ4uCGMtHbfao+Lbm994/I0bgymqT8z58kvGuihO30VRp2FZ9kJE1vqG18Tqw8XpGULtAt11ng8wEyxB39tm/gZMBETGqDGuAKgBMPV9c5GACDGdlno2/cJjLVCVap+EluaRRR/9R4mDrzk2P+ENoR/jdOqPHX6CcTCTwtt8S0PVov0xQhZZJrq4W/+eZ90FAziLT3XnERdurtvuTaaReY3SWeYjyU4ETL3s4NqrwiGqz7JSU/CntpWRTky9K0q5PGmdgL0f4bjMkeTiPqXndoc/fmIWE1i3x1SxEMoF5iLDgv9dRMuBPnLHi7tdsYMlebhWnPXwMbYbLDSGFq7QfqZpQ+JQwYDBxS3+m9GKQCoTtGKXXya2Fk252HEN3qPtEaG+awb7wlMmtkvSBtgg+UWt0h2debNZIFWt0BW3l6wZG0cmSkRy6hXPLJknaDksTLbj1jtY80PChXIcdmtdq2EPZEs8nFse/Bu/+YeiS2Pl/5163kG/4IPBFZ15rQrUMl4PsvGPOt1dC4Obsz956M6z1dnOSoM/nQUD9oJSRDWEvcxy0RRWkIY5giow130f1QEBXsYlPv+YO4sVmWybYDRRO9lOrR5FRR5E9hVxCLu8lutJVFQkATxqDPtrEI7AI0lioZ2mndU448OimRZuqCKhkd9BeAdxeiY+ZoyHuCkHkRmUvXFMN4QWtftq+dpw1OLlKVwhrCeAJj2g1eqUuKg16ep9ezoH2ozR2h7+W4RIwALG1VlGkyX8ockm9LTL2Ghy9ktJVMobOqt6Z2TeS6YLJnRPuAnhCCrG5MOiuKkZuJX+/O3gvReFSt7QkYbklWQepMbPXx5zKxB9U0da3EhFcUFFhoVkFC1ORibmtwpd0boqYK0gUqdu5R1XfHB9BGPAIERqVFMuBEO5lgMBHPINjPc348LWyPi5pfg9QSueLRwxzxgALzxCWNRm6XUvM88BHEeo7ZGfOGagVEFmEoOsYlwy4Jt6otB7sCEuU+RoT41OSgD0qXKSy99YzcLQyVnFZX5orcRDD1zB494Rg7p6knB8JiOEnAAyP7VarroCtPJcpve63Hhznkq4uLwjfx/SRdIpW9ezGcsDG8UcypZM1wORAL5abMsmpwYMPq9ns8Ga6ffDUdaNtl/vhhfC3OaQSPHqilfPhnf4fITGGKQqNX8+tGdZr+8mqk3t8gNsSWq2CwpmqVEdpJV9jmDTz6PmlTs7PtaPBS3clgGJ9U/Ivk+LadwBSwRSiuMfKmw7I3hBkqN8d3HmEzqy8ypqObFSxVuwLn25hCaqiahjdh1G/sr3u2HNXIYqCiRpsLfibuuFLNKdzQwC9bomsn3JhiJdIoOpJCGZDqTmvXenU/gJE0oAw1khS3mswoPb/DzdNuYVv/9LvnWn7g8ExcRdkHEo83Xjn16O2nz6DQ130roNf7aouGSNlFOXQ+dQHXO311CyRAyVvToebPCtTmAnhkAA95MmN7IjUD4eituKIj6ZG1le4DNkaXwLCzi1fcbmI8Kw2DpCOEYXJCUFw9JXzq29WBSuEKvDIdwOeu0zqxS5IelvpDbtslo02cSPhWNUMoltAsUxtNscrnMyEBqGn4QGc1yhFJlOlMEjeLwCd9rhWdx/eY6Djghy+KbWaGSN777ZIUJUcklew1ajgkNzW2paPQTcIpLg5PihFOG6SPzs+o38kdeFpxYKFezVouPye2c2MoGaDtFUtLgmubsrWDXJNS2hmIv6aUMs5lOqLTotSzKpFDSVh04CO4pMN9XKs3s8JyluAkUN4Qj1Gtj0hZJRXBqezTA3DOHOltEU+pQrQX2QLAIkTls/kAYP0sRfTW3PBgyzTMLoJ1o48edpbXyYq6G+r8MEuW262O/fSgUBKsYfZiO4mXYxDWKnlbdWg195YGhuw5v9qEC+usU4hbveU869K7fMa+mrIeGMxXUut9qT6ZIpeDYadPgZbo623x8QKCYutFk6FSGRiO91WgFHAMPUkGYiIYcldEg3Zq5nnHck7XfLQzSrucNdgG/pybtgJwosrwR0QwNv3qHqh2SmJGRIaSb9PTnn993U7TKG0Lx0ipjIP9eWVG1c3xMCLehZWrsDP81EHvAcFdaPWu/8k+hn1rJITxV1WQetdaMXXTPoBXJWNyLsSQlfSgHn4VYvt3Ks3ikYxvrtXylzYAmGpS1Amxz98dnVQWiyvfkE4km72HyiBVic1DyDF2Le49D1kTErOHTVOxoylhjo1K6hBpAeg2uxaQHkFKBEs59a0Pj9z9xQ1dF8czAN0eAExgPGD4DC8doaC5ud5TnUXO1idLqWSGKW2m0rIVUQDBpB6enMxANd7spD+8dr4v47Ft/LJOvdyI7u0Ch8BhFs5tnAu1pHd8IPvBCbIUIw7Wj/DZkX4YwEJKYLI2qOjmXAfIwyPvLZQLVAwX7i/Nzk5GAz3RYYDDc9Qdtc7bUxabGoUrDsRwhjzm3QO34cBsPHoayV4wRlFlw4PPT6ewu0TE1B3Dz9c2mEILfOISVYqthy4bWa+2euS0AGNpl8JUtVBgkgRSU7Mwg1edQfy4HQChx1YBM6fs/JEez5kjYrdm/iga8PFTXdZgTgsSO3o44i9cYl01toVNTjZH3ILhXacpse3jxRtYeQ+cZDBhIGJHPxmHwnZYRx2VCU7d3pDzGt6anOOPUJTZf5FpxoUoto56WlvXvtza9WuhhTa0tw1TJoOn37PFJlQmIneEvPPDIDvQaxZCgPDfCwrX4LYKWZnxVMbjTON7/oHNVEFFpNx9Z2XPd51OXycu89g7S3NZQre02rBu6oZDg2dJXCNncD8aXaQ78NYuwZXKHYjtuL5N3lWxD8CJdZ8bMvR2Ac19ykm4kfvgnxxUvwR44CYvJ4itXJ5964207FDevga3Z/aRe3lAwYf2L/4yYPQfzj8wbPvyGqz5HFBmoa3U2VUq9JxyR+DZHt310Fht1GWooZXNFCkkORI6v9KxGWikTlg+noPrPDWuj9kVSzN8zzORl0J9POnZrajyuE5sOrjVObbdOBy+qY5n2l5XGOFKX4MW2uquQDEKczxDq2jkaJAsvWbfA4WxWkblkb2y2452uKn0B3xFU5o08XEq74kk2P7ZE9A6z5ax+oR5PiOvBMbxr9zLe4omSMkaF/9SB0BLf0ST+fe8+KvYWV5IZH7mR6wYCnbsCe2SGlf+MooIUWDbCn4uwp8L1YMl2xzay1BNSCuvHCXrtyfcm7L0qG3F0WB3KSrKunQAes2cCUGts8KwbX2ZmqZhHPRc183/B3QRSlxsfwymqA3lBWKaXg5YbLsknEgBOACWELH9zun/rwPHJ9NfztcKjBIOcPYaEVqTbevDCLLSxeSYTAZ/l1FII8pjR9IG3BjXPpmfjiWQdpybGX6wzXqYUfqzqEdw2FdIkuvVsZ9sF9LEKE044tYz03Oyhi7RvfrjymNnLs3/qs5dvuZrSstN6fKW3u0d2mnm7SUCuJmrbPOn6PS5BnGxzmrbpMhfPFVGV0cnZzOSY3Tm8WdJv8oh5X1op1k6uTDjB9bhr7MVpr/1voS8eWlH1ogrcIkA7+tfRP9IHCWaOf7BZKDUMnLFYXLfwXWJtLH5ik1ZTl6hvMs6nRfd6SisL1636FhT5P9UDy5qr7vwGc9vEC9e/dn/FpXX6oz0a5KLv1QjhFXY6ex17upVmmmhZLyGHpRi+y6edUaOjaA5iMzSDC+Ec8Kwbiq85iw8G069eTzFOZ+QEWPcp9mUKovWfXCAKmwBzgQy20p+spimc4iHNWOppRlOlQQ2SkH99lLKzl69z4nih68ObcpBE7Eq3WO6jB6PS9RTjiqTjZeRI+UUTB/z4q9lAMm0PATKB4dLN805yB9+kHXGa+Dptu/nZaEQj8vLnBSbX/qoyUaVYJO4kbXO78c0UERQbYMm/reCknaIgBxlMldoyYcXSgDqFMLHd1le4Di7yGCmnDBLNpYzTA3j1cfE115zqqoEHQ6ypLDtKaqPR9iATSNIR1nYvPFHYIChMOmQtjJ4AbE4ZisdDKVnppBczdBOC6R0bKZrXiwriMmTDWLqnMpw4DLb4taDq4Nia5jzCzgfWa3tCx+Nkp1ByAnAdd9eMQSW8BrPMnERD5itP8oOiYI4tYiB+PjeWSy9G4vD9EEB7XgQQFsmff2xXIFiNBHjWvU5WnsL6cfyzQgwwr6eWc3gdrIzJApkzQ6nAU6kzS9A3rXMnaag074CSBSe7xpSMw+jQDJp0JnhNZu8Cdi6HPWRnwPP7IWZtI5/1R2LBvEwqkCKjYwfFJVa+2QhSzBD0bd4GedTGqXKxffP5Rz63z2nMNpc+L0JH/0hiFqVKlJXMhp6ee8XHpCSSZDCqkZ0aJ14SMSbjiO3H4wsfKHUjahyk9MDVLkx6hbBnUlAxUQ1g5/HlZwurFVLzZ9VTH7bKLsZXZJ/625HwNki30ebukuGaf/oQe/yijkyvrPSMjOV/i5QYAjkiAPz1g4I3fMNxmOCx9l7/e0EmLX+yIrCMl5oWfVK6osdSCchiOaaIj7B0RTVmOk3C1RAI2SPzzHr1UacVrE+fCl03L5lxTa1bcHpaOWNVuD21uyPLblNLHebDtYWy0vidgw/ULQr5Dko09I4nKzM7Y+AoW4HYewnsPh06P94StqWZnSiha8kUwIhvNeVWHqtvg0eIPb8hD4zf6Lpw9ejO4DaM85/08mwRF7nbXrMNf+FtE+hMzhkbo1jKZ5x2G4y8tao8ksYY+tLBu/Jb1/Wtdeh1FtNuoChXndAXUFVGOMQNsHjoqUjFC0PjsXPeeD8XK/N7/R5Bk17KqBRXfVRiGL/qqUdyPBW3sNdcR4zTc47xaTY1c2hIM/G6Q/L12u3OHqT2RfE5Nd8Hl64O3nB5qycq6v8c05v+TRjBRu+pCilK8uMs5yMWtH5NrqicLi1QjToZOEKsyZGtMipgCgcrkrP68lgJPajzkPV0vGxuMB5zjjH1Xp1bzAl9WSqzhPcQmO1aiZYw4Rk0MToPcH1W1dVd9ZTbPEY33S0z+JWh6kXfPOw4Qt6ZjA9FvcW2FI9S/zXQE1xn7TJAAPnMdcvY2pryKyx7eQBcYcmbp0xkBfTunR5rlMt6zqW3dNIxpM4UqxPWt+8xT5eOA1tfNV7sdHYNzzqGp7gHo5yiscsaJMqPJxLKcH6eFJdJBWfww52FD4IvsfYDosjMkYvB549ahNmevMcZlqkDT8aHFpDt+CsJy82enoctKT7gaxJPvOGwhU3cPdDZsq6HfKmSw29BC1fEwO+Ff37K/dOL9S7VBlaJ8GbreAUT5G3Fac4vbBev03OfdY854tl6AXWhpYocyjTg8kyLY+YssRC91qEhrVXdEuHMfFgmamjG3iOxEoBci6s/ZNS0xAgUM7glufJD9IadY0XqjZ78t4khhui62rxBhvnD3IG4BLf1pVRrYNBetXqlv+cXoCnLOqKnMO6SISyQN8QD0vSU398ZipV0geq2QsB4p5vVdBqvJFziTCk27ZKqURDR55BKHIJSs+PPB656uKlrwc9BcVFaga0mTYv7lk1jtl42T+1d8U00jeoDOc+gbFXDQ0Bz1do5EFZISc8jJmKMg45w0tifTDzoGle9D23dd85kDGh/yqPegcj6iVhXdv4u6yM1yDERcw6h0dy1dEnQF1eZSjT3UnMAm2aHMmk0AX0QwG04wmO5MAP5mQ+0PLyb3VByoVTbykhYhUf1PtPa0QKVfwQZ5kn3KjvLfp4z2PNpR2BlP33POZBckk+6MiehPOJl8wbx/unjM3KySRCfwu0QnB4aZyBBbrhCM/UHSAOKlx700l5OvmpTUVHtRNGP0Ht0htIPNwUEojgxYWRgiajRwmorZz6LgLbtSCJr928ggt4tupq7GSiA9P+3a3fcMbp3kT4ujJ86VTK/7jINrwQFWfw760WlL0CeVrwk5Vby9KTuRPl1NDjZ68Upa2PaDD6kNBlT9wyHZkkuVHYtzNoulIzLD1bb0SgqcOvW3mE3hgDJXk7SxHzXIGAoF/9/mQxcKC0eTgm1wWxL7t4jwoc9nvATKhM3vSngdMRVluuZ1dVPvsG1JOHxfVPZBxPxVSfBZj519Nxopu/eYFy79wCm/KaeLmaNmGfbzFeFp9hqNgWgH2MZ5aL68Gw6mKQBPIsFBANYPNAOt9luymUBkO4IKdaixlmAx4P/eQIz37UTrawGR/bdSOPUY/T6QCfp8/6nSag2Ok3FogDNMf9XsxvftHSdNxxU8yv3L3vi9E3N8F4MpdiQBzg82W9i7qfMWo7lyzDN3FVnKteun6wdj06b/145w1W5eyfBpRzhXj5tY58+GhB0xWHLlDJgz1nK5FPMSpeZDX89NBtsY3QGATVgolxqnKcZpYCh2hgia+ykvIcLsJSzAN40R4k7iY141P4q1gZh5EneVqBXOGDSpIQtuMDRgjWprPOSmjB/VrDiG7Y+Movng9XpZGVP0Xna4hrdx1XIMN34t16R0XdD9vrNFFYl2eusHwgGqwCEArfd5UnXBw0Tg7sxFDgQCGt/5pswjmWHXaLV9dbBr+sN3rwVHyNwoHoqGZKPs8YS4zfyn5BP10bovQyNGsuruhtOD8DUHh9WJnRxI07iQ+eXs/7PTd0aCkr3YPZRbVkmK4DwHJoLrdLhh9MRdBbf5EuRbEVSCv9mT3IMNmXLrOarsv37NXv1EAw6mXYWr/bBeh1VW3y12SE02HUUKOlSqsnnafWitlDSiCBK6/114qAKmt8XVijNWtZQYrt3oNC6mIkwUCQ3+oASnoWWlXu6R3O3i3DrY7Ki/UPz6DxfpPI4TggJwOyf01T2y8SHP16fzeJpq6u2vkohKVHQT3Dt13g6KTJfz2/gJXKkxG8xLen3OPH0SH/uPC/6zGoF/1OYW2L5t9+GsC70NjWcVgOraTAEfUc47CJX+3vgvgBJsMYdOFFJxrx6MSV+GkO8++c0fMxI+sbhJAHDEW2NS6GBmcRSYiJd4uSjhBDyOcTzoPhp+EDVsFtlsotHsZL/mfhsG/z755h2gaMootNz1Pntgk0zN/TWdd3EjHj/M0g3LD7Zi2AI/nSy5JBgs8J5EKHMMjP3SYeQ555DiUaWLNUEIwIaOY/juFgQjnyoCyDURTmDGQKi8xVaL+NE+wdSfqWdabDy1C24/qz3UZ2hOjfKI0ZMhaULrKkaMAzHCArRDfiMMtCDimEmJHKvCJ3M4Bhx9OABn1CtRg9GzDLTfK3qcJf2rtYeXt4CuzsbkcdcHNpjyB9lwL+2jrKr8fmmOdVwm3/AVtuKMBKQ8WWkfW27Iax30zdGD6GBNz/lzTvrqkL9GxjKcEH9gR/qX8/5wHzxIXSx0Ymauq32UUh/5MuoMNrblxidzuApp0PwMQE8i5E4JEMrGPMNzG0B7j1RpbkpnCJwUl+5Z+DsB3X0gRbuzNQsksKUb0u+7Yh1luyZZh7pJeAgunpXB5eyb60ze7reu1piu3YHhP2/NlsadORGR8VLsu2UzPFrtN/z0PfCdzPm9Ia336AlzfEOP+KG83ya9Tj3ow3crwprmdVxqoqicyOfrFZ8uXFXNTnAS6LScFehFJGIU5iW0zJjxxOd9ikMzEm3sdj8KMfBUqnKschKO3WAjbdeqfvLi2ATY91jSaQoV+GADo4gA3B4AzvxsntBgJ4ILN0SdiSdJbsFrhrGJzyo0xu9ff5mf/83l2Gcn8e","base64")).toString()),qq)});var YIe=_((IJt,jIe)=>{var Xq=Symbol("arg flag"),Oa=class extends Error{constructor(e,r){super(e),this.name="ArgError",this.code=r,Object.setPrototypeOf(this,Oa.prototype)}};function sv(t,{argv:e=process.argv.slice(2),permissive:r=!1,stopAtPositional:o=!1}={}){if(!t)throw new Oa("argument specification object is required","ARG_CONFIG_NO_SPEC");let a={_:[]},n={},u={};for(let A of Object.keys(t)){if(!A)throw new Oa("argument key cannot be an empty string","ARG_CONFIG_EMPTY_KEY");if(A[0]!=="-")throw new Oa(`argument key must start with '-' but found: '${A}'`,"ARG_CONFIG_NONOPT_KEY");if(A.length===1)throw new Oa(`argument key must have a name; singular '-' keys are not allowed: ${A}`,"ARG_CONFIG_NONAME_KEY");if(typeof t[A]=="string"){n[A]=t[A];continue}let p=t[A],h=!1;if(Array.isArray(p)&&p.length===1&&typeof p[0]=="function"){let[E]=p;p=(I,v,x=[])=>(x.push(E(I,v,x[x.length-1])),x),h=E===Boolean||E[Xq]===!0}else if(typeof p=="function")h=p===Boolean||p[Xq]===!0;else throw new Oa(`type missing or not a function or valid array type: ${A}`,"ARG_CONFIG_VAD_TYPE");if(A[1]!=="-"&&A.length>2)throw new Oa(`short argument keys (with a single hyphen) must have only one character: ${A}`,"ARG_CONFIG_SHORTOPT_TOOLONG");u[A]=[p,h]}for(let A=0,p=e.length;A<p;A++){let h=e[A];if(o&&a._.length>0){a._=a._.concat(e.slice(A));break}if(h==="--"){a._=a._.concat(e.slice(A+1));break}if(h.length>1&&h[0]==="-"){let E=h[1]==="-"||h.length===2?[h]:h.slice(1).split("").map(I=>`-${I}`);for(let I=0;I<E.length;I++){let v=E[I],[x,C]=v[1]==="-"?v.split(/=(.*)/,2):[v,void 0],R=x;for(;R in n;)R=n[R];if(!(R in u))if(r){a._.push(v);continue}else throw new Oa(`unknown or unexpected option: ${x}`,"ARG_UNKNOWN_OPTION");let[N,U]=u[R];if(!U&&I+1<E.length)throw new Oa(`option requires argument (but was followed by another short argument): ${x}`,"ARG_MISSING_REQUIRED_SHORTARG");if(U)a[R]=N(!0,R,a[R]);else if(C===void 0){if(e.length<A+2||e[A+1].length>1&&e[A+1][0]==="-"&&!(e[A+1].match(/^-?\d*(\.(?=\d))?\d*$/)&&(N===Number||typeof BigInt<"u"&&N===BigInt))){let V=x===R?"":` (alias for ${R})`;throw new Oa(`option requires argument: ${x}${V}`,"ARG_MISSING_REQUIRED_LONGARG")}a[R]=N(e[A+1],R,a[R]),++A}else a[R]=N(C,R,a[R])}}else a._.push(h)}return a}sv.flag=t=>(t[Xq]=!0,t);sv.COUNT=sv.flag((t,e,r)=>(r||0)+1);sv.ArgError=Oa;jIe.exports=sv});var $Ie=_((ZJt,ZIe)=>{var tG;ZIe.exports=()=>(typeof tG>"u"&&(tG=ve("zlib").brotliDecompressSync(Buffer.from("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","base64")).toString()),tG)});var i1e=_((aG,lG)=>{(function(t){aG&&typeof aG=="object"&&typeof lG<"u"?lG.exports=t():typeof define=="function"&&define.amd?define([],t):typeof window<"u"?window.isWindows=t():typeof global<"u"?global.isWindows=t():typeof self<"u"?self.isWindows=t():this.isWindows=t()})(function(){"use strict";return function(){return process&&(process.platform==="win32"||/^(msys|cygwin)$/.test(process.env.OSTYPE))}})});var l1e=_((JXt,a1e)=>{"use strict";cG.ifExists=$It;var YC=ve("util"),oc=ve("path"),s1e=i1e(),JIt=/^#!\s*(?:\/usr\/bin\/env)?\s*([^ \t]+)(.*)$/,XIt={createPwshFile:!0,createCmdFile:s1e(),fs:ve("fs")},ZIt=new Map([[".js","node"],[".cjs","node"],[".mjs","node"],[".cmd","cmd"],[".bat","cmd"],[".ps1","pwsh"],[".sh","sh"]]);function o1e(t){let e={...XIt,...t},r=e.fs;return e.fs_={chmod:r.chmod?YC.promisify(r.chmod):async()=>{},mkdir:YC.promisify(r.mkdir),readFile:YC.promisify(r.readFile),stat:YC.promisify(r.stat),unlink:YC.promisify(r.unlink),writeFile:YC.promisify(r.writeFile)},e}async function cG(t,e,r){let o=o1e(r);await o.fs_.stat(t),await t1t(t,e,o)}function $It(t,e,r){return cG(t,e,r).catch(()=>{})}function e1t(t,e){return e.fs_.unlink(t).catch(()=>{})}async function t1t(t,e,r){let o=await o1t(t,r);return await r1t(e,r),n1t(t,e,o,r)}function r1t(t,e){return e.fs_.mkdir(oc.dirname(t),{recursive:!0})}function n1t(t,e,r,o){let a=o1e(o),n=[{generator:c1t,extension:""}];return a.createCmdFile&&n.push({generator:l1t,extension:".cmd"}),a.createPwshFile&&n.push({generator:u1t,extension:".ps1"}),Promise.all(n.map(u=>a1t(t,e+u.extension,r,u.generator,a)))}function i1t(t,e){return e1t(t,e)}function s1t(t,e){return A1t(t,e)}async function o1t(t,e){let a=(await e.fs_.readFile(t,"utf8")).trim().split(/\r*\n/)[0].match(JIt);if(!a){let n=oc.extname(t).toLowerCase();return{program:ZIt.get(n)||null,additionalArgs:""}}return{program:a[1],additionalArgs:a[2]}}async function a1t(t,e,r,o,a){let n=a.preserveSymlinks?"--preserve-symlinks":"",u=[r.additionalArgs,n].filter(A=>A).join(" ");return a=Object.assign({},a,{prog:r.program,args:u}),await i1t(e,a),await a.fs_.writeFile(e,o(t,e,a),"utf8"),s1t(e,a)}function l1t(t,e,r){let a=oc.relative(oc.dirname(e),t).split("/").join("\\"),n=oc.isAbsolute(a)?`"${a}"`:`"%~dp0\\${a}"`,u,A=r.prog,p=r.args||"",h=uG(r.nodePath).win32;A?(u=`"%~dp0\\${A}.exe"`,a=n):(A=n,p="",a="");let E=r.progArgs?`${r.progArgs.join(" ")} `:"",I=h?`@SET NODE_PATH=${h}\r
-`:"";return u?I+=`@IF EXIST ${u} (\r
- ${u} ${p} ${a} ${E}%*\r
-) ELSE (\r
- @SETLOCAL\r
- @SET PATHEXT=%PATHEXT:;.JS;=;%\r
- ${A} ${p} ${a} ${E}%*\r
-)\r
-`:I+=`@${A} ${p} ${a} ${E}%*\r
-`,I}function c1t(t,e,r){let o=oc.relative(oc.dirname(e),t),a=r.prog&&r.prog.split("\\").join("/"),n;o=o.split("\\").join("/");let u=oc.isAbsolute(o)?`"${o}"`:`"$basedir/${o}"`,A=r.args||"",p=uG(r.nodePath).posix;a?(n=`"$basedir/${r.prog}"`,o=u):(a=u,A="",o="");let h=r.progArgs?`${r.progArgs.join(" ")} `:"",E=`#!/bin/sh
-basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
-
-case \`uname\` in
- *CYGWIN*) basedir=\`cygpath -w "$basedir"\`;;
-esac
-
-`,I=r.nodePath?`export NODE_PATH="${p}"
-`:"";return n?E+=`${I}if [ -x ${n} ]; then
- exec ${n} ${A} ${o} ${h}"$@"
-else
- exec ${a} ${A} ${o} ${h}"$@"
-fi
-`:E+=`${I}${a} ${A} ${o} ${h}"$@"
-exit $?
-`,E}function u1t(t,e,r){let o=oc.relative(oc.dirname(e),t),a=r.prog&&r.prog.split("\\").join("/"),n=a&&`"${a}$exe"`,u;o=o.split("\\").join("/");let A=oc.isAbsolute(o)?`"${o}"`:`"$basedir/${o}"`,p=r.args||"",h=uG(r.nodePath),E=h.win32,I=h.posix;n?(u=`"$basedir/${r.prog}$exe"`,o=A):(n=A,p="",o="");let v=r.progArgs?`${r.progArgs.join(" ")} `:"",x=`#!/usr/bin/env pwsh
-$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
-
-$exe=""
-${r.nodePath?`$env_node_path=$env:NODE_PATH
-$env:NODE_PATH="${E}"
-`:""}if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
- # Fix case when both the Windows and Linux builds of Node
- # are installed in the same directory
- $exe=".exe"
-}`;return r.nodePath&&(x+=` else {
- $env:NODE_PATH="${I}"
-}`),u?x+=`
-$ret=0
-if (Test-Path ${u}) {
- # Support pipeline input
- if ($MyInvocation.ExpectingInput) {
- $input | & ${u} ${p} ${o} ${v}$args
- } else {
- & ${u} ${p} ${o} ${v}$args
- }
- $ret=$LASTEXITCODE
-} else {
- # Support pipeline input
- if ($MyInvocation.ExpectingInput) {
- $input | & ${n} ${p} ${o} ${v}$args
- } else {
- & ${n} ${p} ${o} ${v}$args
- }
- $ret=$LASTEXITCODE
-}
-${r.nodePath?`$env:NODE_PATH=$env_node_path
-`:""}exit $ret
-`:x+=`
-# Support pipeline input
-if ($MyInvocation.ExpectingInput) {
- $input | & ${n} ${p} ${o} ${v}$args
-} else {
- & ${n} ${p} ${o} ${v}$args
-}
-${r.nodePath?`$env:NODE_PATH=$env_node_path
-`:""}exit $LASTEXITCODE
-`,x}function A1t(t,e){return e.fs_.chmod(t,493)}function uG(t){if(!t)return{win32:"",posix:""};let e=typeof t=="string"?t.split(oc.delimiter):Array.from(t),r={};for(let o=0;o<e.length;o++){let a=e[o].split("/").join("\\"),n=s1e()?e[o].split("\\").join("/").replace(/^([^:\\/]*):/,(u,A)=>`/mnt/${A.toLowerCase()}`):e[o];r.win32=r.win32?`${r.win32};${a}`:a,r.posix=r.posix?`${r.posix}:${n}`:n,r[o]={win32:a,posix:n}}return r}a1e.exports=cG});var vG=_((m$t,x1e)=>{x1e.exports=ve("stream")});var R1e=_((y$t,F1e)=>{"use strict";function k1e(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter(function(a){return Object.getOwnPropertyDescriptor(t,a).enumerable})),r.push.apply(r,o)}return r}function M1t(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?k1e(Object(r),!0).forEach(function(o){U1t(t,o,r[o])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):k1e(Object(r)).forEach(function(o){Object.defineProperty(t,o,Object.getOwnPropertyDescriptor(r,o))})}return t}function U1t(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function _1t(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function Q1e(t,e){for(var r=0;r<e.length;r++){var o=e[r];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function H1t(t,e,r){return e&&Q1e(t.prototype,e),r&&Q1e(t,r),t}var q1t=ve("buffer"),xQ=q1t.Buffer,G1t=ve("util"),DG=G1t.inspect,j1t=DG&&DG.custom||"inspect";function Y1t(t,e,r){xQ.prototype.copy.call(t,e,r)}F1e.exports=function(){function t(){_1t(this,t),this.head=null,this.tail=null,this.length=0}return H1t(t,[{key:"push",value:function(r){var o={data:r,next:null};this.length>0?this.tail.next=o:this.head=o,this.tail=o,++this.length}},{key:"unshift",value:function(r){var o={data:r,next:this.head};this.length===0&&(this.tail=o),this.head=o,++this.length}},{key:"shift",value:function(){if(this.length!==0){var r=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,r}}},{key:"clear",value:function(){this.head=this.tail=null,this.length=0}},{key:"join",value:function(r){if(this.length===0)return"";for(var o=this.head,a=""+o.data;o=o.next;)a+=r+o.data;return a}},{key:"concat",value:function(r){if(this.length===0)return xQ.alloc(0);for(var o=xQ.allocUnsafe(r>>>0),a=this.head,n=0;a;)Y1t(a.data,o,n),n+=a.data.length,a=a.next;return o}},{key:"consume",value:function(r,o){var a;return r<this.head.data.length?(a=this.head.data.slice(0,r),this.head.data=this.head.data.slice(r)):r===this.head.data.length?a=this.shift():a=o?this._getString(r):this._getBuffer(r),a}},{key:"first",value:function(){return this.head.data}},{key:"_getString",value:function(r){var o=this.head,a=1,n=o.data;for(r-=n.length;o=o.next;){var u=o.data,A=r>u.length?u.length:r;if(A===u.length?n+=u:n+=u.slice(0,r),r-=A,r===0){A===u.length?(++a,o.next?this.head=o.next:this.head=this.tail=null):(this.head=o,o.data=u.slice(A));break}++a}return this.length-=a,n}},{key:"_getBuffer",value:function(r){var o=xQ.allocUnsafe(r),a=this.head,n=1;for(a.data.copy(o),r-=a.data.length;a=a.next;){var u=a.data,A=r>u.length?u.length:r;if(u.copy(o,o.length-r,0,A),r-=A,r===0){A===u.length?(++n,a.next?this.head=a.next:this.head=this.tail=null):(this.head=a,a.data=u.slice(A));break}++n}return this.length-=n,o}},{key:j1t,value:function(r,o){return DG(this,M1t({},o,{depth:0,customInspect:!1}))}}]),t}()});var SG=_((E$t,L1e)=>{"use strict";function W1t(t,e){var r=this,o=this._readableState&&this._readableState.destroyed,a=this._writableState&&this._writableState.destroyed;return o||a?(e?e(t):t&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(PG,this,t)):process.nextTick(PG,this,t)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(t||null,function(n){!e&&n?r._writableState?r._writableState.errorEmitted?process.nextTick(kQ,r):(r._writableState.errorEmitted=!0,process.nextTick(T1e,r,n)):process.nextTick(T1e,r,n):e?(process.nextTick(kQ,r),e(n)):process.nextTick(kQ,r)}),this)}function T1e(t,e){PG(t,e),kQ(t)}function kQ(t){t._writableState&&!t._writableState.emitClose||t._readableState&&!t._readableState.emitClose||t.emit("close")}function K1t(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function PG(t,e){t.emit("error",e)}function z1t(t,e){var r=t._readableState,o=t._writableState;r&&r.autoDestroy||o&&o.autoDestroy?t.destroy(e):t.emit("error",e)}L1e.exports={destroy:W1t,undestroy:K1t,errorOrDestroy:z1t}});var F0=_((C$t,M1e)=>{"use strict";var O1e={};function lc(t,e,r){r||(r=Error);function o(n,u,A){return typeof e=="string"?e:e(n,u,A)}class a extends r{constructor(u,A,p){super(o(u,A,p))}}a.prototype.name=r.name,a.prototype.code=t,O1e[t]=a}function N1e(t,e){if(Array.isArray(t)){let r=t.length;return t=t.map(o=>String(o)),r>2?`one of ${e} ${t.slice(0,r-1).join(", ")}, or `+t[r-1]:r===2?`one of ${e} ${t[0]} or ${t[1]}`:`of ${e} ${t[0]}`}else return`of ${e} ${String(t)}`}function V1t(t,e,r){return t.substr(!r||r<0?0:+r,e.length)===e}function J1t(t,e,r){return(r===void 0||r>t.length)&&(r=t.length),t.substring(r-e.length,r)===e}function X1t(t,e,r){return typeof r!="number"&&(r=0),r+e.length>t.length?!1:t.indexOf(e,r)!==-1}lc("ERR_INVALID_OPT_VALUE",function(t,e){return'The value "'+e+'" is invalid for option "'+t+'"'},TypeError);lc("ERR_INVALID_ARG_TYPE",function(t,e,r){let o;typeof e=="string"&&V1t(e,"not ")?(o="must not be",e=e.replace(/^not /,"")):o="must be";let a;if(J1t(t," argument"))a=`The ${t} ${o} ${N1e(e,"type")}`;else{let n=X1t(t,".")?"property":"argument";a=`The "${t}" ${n} ${o} ${N1e(e,"type")}`}return a+=`. Received type ${typeof r}`,a},TypeError);lc("ERR_STREAM_PUSH_AFTER_EOF","stream.push() after EOF");lc("ERR_METHOD_NOT_IMPLEMENTED",function(t){return"The "+t+" method is not implemented"});lc("ERR_STREAM_PREMATURE_CLOSE","Premature close");lc("ERR_STREAM_DESTROYED",function(t){return"Cannot call "+t+" after a stream was destroyed"});lc("ERR_MULTIPLE_CALLBACK","Callback called multiple times");lc("ERR_STREAM_CANNOT_PIPE","Cannot pipe, not readable");lc("ERR_STREAM_WRITE_AFTER_END","write after end");lc("ERR_STREAM_NULL_VALUES","May not write null values to stream",TypeError);lc("ERR_UNKNOWN_ENCODING",function(t){return"Unknown encoding: "+t},TypeError);lc("ERR_STREAM_UNSHIFT_AFTER_END_EVENT","stream.unshift() after end event");M1e.exports.codes=O1e});var bG=_((w$t,U1e)=>{"use strict";var Z1t=F0().codes.ERR_INVALID_OPT_VALUE;function $1t(t,e,r){return t.highWaterMark!=null?t.highWaterMark:e?t[r]:null}function e2t(t,e,r,o){var a=$1t(e,o,r);if(a!=null){if(!(isFinite(a)&&Math.floor(a)===a)||a<0){var n=o?r:"highWaterMark";throw new Z1t(n,a)}return Math.floor(a)}return t.objectMode?16:16*1024}U1e.exports={getHighWaterMark:e2t}});var _1e=_((I$t,xG)=>{typeof Object.create=="function"?xG.exports=function(e,r){r&&(e.super_=r,e.prototype=Object.create(r.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:xG.exports=function(e,r){if(r){e.super_=r;var o=function(){};o.prototype=r.prototype,e.prototype=new o,e.prototype.constructor=e}}});var R0=_((B$t,QG)=>{try{if(kG=ve("util"),typeof kG.inherits!="function")throw"";QG.exports=kG.inherits}catch{QG.exports=_1e()}var kG});var q1e=_((v$t,H1e)=>{H1e.exports=ve("util").deprecate});var TG=_((D$t,z1e)=>{"use strict";z1e.exports=Ri;function j1e(t){var e=this;this.next=null,this.entry=null,this.finish=function(){S2t(e,t)}}var JC;Ri.WritableState=mv;var t2t={deprecate:q1e()},Y1e=vG(),FQ=ve("buffer").Buffer,r2t=global.Uint8Array||function(){};function n2t(t){return FQ.from(t)}function i2t(t){return FQ.isBuffer(t)||t instanceof r2t}var RG=SG(),s2t=bG(),o2t=s2t.getHighWaterMark,T0=F0().codes,a2t=T0.ERR_INVALID_ARG_TYPE,l2t=T0.ERR_METHOD_NOT_IMPLEMENTED,c2t=T0.ERR_MULTIPLE_CALLBACK,u2t=T0.ERR_STREAM_CANNOT_PIPE,A2t=T0.ERR_STREAM_DESTROYED,f2t=T0.ERR_STREAM_NULL_VALUES,p2t=T0.ERR_STREAM_WRITE_AFTER_END,h2t=T0.ERR_UNKNOWN_ENCODING,XC=RG.errorOrDestroy;R0()(Ri,Y1e);function g2t(){}function mv(t,e,r){JC=JC||Cm(),t=t||{},typeof r!="boolean"&&(r=e instanceof JC),this.objectMode=!!t.objectMode,r&&(this.objectMode=this.objectMode||!!t.writableObjectMode),this.highWaterMark=o2t(this,t,"writableHighWaterMark",r),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var o=t.decodeStrings===!1;this.decodeStrings=!o,this.defaultEncoding=t.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(a){I2t(e,a)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=t.emitClose!==!1,this.autoDestroy=!!t.autoDestroy,this.bufferedRequestCount=0,this.corkedRequestsFree=new j1e(this)}mv.prototype.getBuffer=function(){for(var e=this.bufferedRequest,r=[];e;)r.push(e),e=e.next;return r};(function(){try{Object.defineProperty(mv.prototype,"buffer",{get:t2t.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch{}})();var QQ;typeof Symbol=="function"&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]=="function"?(QQ=Function.prototype[Symbol.hasInstance],Object.defineProperty(Ri,Symbol.hasInstance,{value:function(e){return QQ.call(this,e)?!0:this!==Ri?!1:e&&e._writableState instanceof mv}})):QQ=function(e){return e instanceof this};function Ri(t){JC=JC||Cm();var e=this instanceof JC;if(!e&&!QQ.call(Ri,this))return new Ri(t);this._writableState=new mv(t,this,e),this.writable=!0,t&&(typeof t.write=="function"&&(this._write=t.write),typeof t.writev=="function"&&(this._writev=t.writev),typeof t.destroy=="function"&&(this._destroy=t.destroy),typeof t.final=="function"&&(this._final=t.final)),Y1e.call(this)}Ri.prototype.pipe=function(){XC(this,new u2t)};function d2t(t,e){var r=new p2t;XC(t,r),process.nextTick(e,r)}function m2t(t,e,r,o){var a;return r===null?a=new f2t:typeof r!="string"&&!e.objectMode&&(a=new a2t("chunk",["string","Buffer"],r)),a?(XC(t,a),process.nextTick(o,a),!1):!0}Ri.prototype.write=function(t,e,r){var o=this._writableState,a=!1,n=!o.objectMode&&i2t(t);return n&&!FQ.isBuffer(t)&&(t=n2t(t)),typeof e=="function"&&(r=e,e=null),n?e="buffer":e||(e=o.defaultEncoding),typeof r!="function"&&(r=g2t),o.ending?d2t(this,r):(n||m2t(this,o,t,r))&&(o.pendingcb++,a=E2t(this,o,n,t,e,r)),a};Ri.prototype.cork=function(){this._writableState.corked++};Ri.prototype.uncork=function(){var t=this._writableState;t.corked&&(t.corked--,!t.writing&&!t.corked&&!t.bufferProcessing&&t.bufferedRequest&&W1e(this,t))};Ri.prototype.setDefaultEncoding=function(e){if(typeof e=="string"&&(e=e.toLowerCase()),!(["hex","utf8","utf-8","ascii","binary","base64","ucs2","ucs-2","utf16le","utf-16le","raw"].indexOf((e+"").toLowerCase())>-1))throw new h2t(e);return this._writableState.defaultEncoding=e,this};Object.defineProperty(Ri.prototype,"writableBuffer",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});function y2t(t,e,r){return!t.objectMode&&t.decodeStrings!==!1&&typeof e=="string"&&(e=FQ.from(e,r)),e}Object.defineProperty(Ri.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function E2t(t,e,r,o,a,n){if(!r){var u=y2t(e,o,a);o!==u&&(r=!0,a="buffer",o=u)}var A=e.objectMode?1:o.length;e.length+=A;var p=e.length<e.highWaterMark;if(p||(e.needDrain=!0),e.writing||e.corked){var h=e.lastBufferedRequest;e.lastBufferedRequest={chunk:o,encoding:a,isBuf:r,callback:n,next:null},h?h.next=e.lastBufferedRequest:e.bufferedRequest=e.lastBufferedRequest,e.bufferedRequestCount+=1}else FG(t,e,!1,A,o,a,n);return p}function FG(t,e,r,o,a,n,u){e.writelen=o,e.writecb=u,e.writing=!0,e.sync=!0,e.destroyed?e.onwrite(new A2t("write")):r?t._writev(a,e.onwrite):t._write(a,n,e.onwrite),e.sync=!1}function C2t(t,e,r,o,a){--e.pendingcb,r?(process.nextTick(a,o),process.nextTick(dv,t,e),t._writableState.errorEmitted=!0,XC(t,o)):(a(o),t._writableState.errorEmitted=!0,XC(t,o),dv(t,e))}function w2t(t){t.writing=!1,t.writecb=null,t.length-=t.writelen,t.writelen=0}function I2t(t,e){var r=t._writableState,o=r.sync,a=r.writecb;if(typeof a!="function")throw new c2t;if(w2t(r),e)C2t(t,r,o,e,a);else{var n=K1e(r)||t.destroyed;!n&&!r.corked&&!r.bufferProcessing&&r.bufferedRequest&&W1e(t,r),o?process.nextTick(G1e,t,r,n,a):G1e(t,r,n,a)}}function G1e(t,e,r,o){r||B2t(t,e),e.pendingcb--,o(),dv(t,e)}function B2t(t,e){e.length===0&&e.needDrain&&(e.needDrain=!1,t.emit("drain"))}function W1e(t,e){e.bufferProcessing=!0;var r=e.bufferedRequest;if(t._writev&&r&&r.next){var o=e.bufferedRequestCount,a=new Array(o),n=e.corkedRequestsFree;n.entry=r;for(var u=0,A=!0;r;)a[u]=r,r.isBuf||(A=!1),r=r.next,u+=1;a.allBuffers=A,FG(t,e,!0,e.length,a,"",n.finish),e.pendingcb++,e.lastBufferedRequest=null,n.next?(e.corkedRequestsFree=n.next,n.next=null):e.corkedRequestsFree=new j1e(e),e.bufferedRequestCount=0}else{for(;r;){var p=r.chunk,h=r.encoding,E=r.callback,I=e.objectMode?1:p.length;if(FG(t,e,!1,I,p,h,E),r=r.next,e.bufferedRequestCount--,e.writing)break}r===null&&(e.lastBufferedRequest=null)}e.bufferedRequest=r,e.bufferProcessing=!1}Ri.prototype._write=function(t,e,r){r(new l2t("_write()"))};Ri.prototype._writev=null;Ri.prototype.end=function(t,e,r){var o=this._writableState;return typeof t=="function"?(r=t,t=null,e=null):typeof e=="function"&&(r=e,e=null),t!=null&&this.write(t,e),o.corked&&(o.corked=1,this.uncork()),o.ending||P2t(this,o,r),this};Object.defineProperty(Ri.prototype,"writableLength",{enumerable:!1,get:function(){return this._writableState.length}});function K1e(t){return t.ending&&t.length===0&&t.bufferedRequest===null&&!t.finished&&!t.writing}function v2t(t,e){t._final(function(r){e.pendingcb--,r&&XC(t,r),e.prefinished=!0,t.emit("prefinish"),dv(t,e)})}function D2t(t,e){!e.prefinished&&!e.finalCalled&&(typeof t._final=="function"&&!e.destroyed?(e.pendingcb++,e.finalCalled=!0,process.nextTick(v2t,t,e)):(e.prefinished=!0,t.emit("prefinish")))}function dv(t,e){var r=K1e(e);if(r&&(D2t(t,e),e.pendingcb===0&&(e.finished=!0,t.emit("finish"),e.autoDestroy))){var o=t._readableState;(!o||o.autoDestroy&&o.endEmitted)&&t.destroy()}return r}function P2t(t,e,r){e.ending=!0,dv(t,e),r&&(e.finished?process.nextTick(r):t.once("finish",r)),e.ended=!0,t.writable=!1}function S2t(t,e,r){var o=t.entry;for(t.entry=null;o;){var a=o.callback;e.pendingcb--,a(r),o=o.next}e.corkedRequestsFree.next=t}Object.defineProperty(Ri.prototype,"destroyed",{enumerable:!1,get:function(){return this._writableState===void 0?!1:this._writableState.destroyed},set:function(e){!this._writableState||(this._writableState.destroyed=e)}});Ri.prototype.destroy=RG.destroy;Ri.prototype._undestroy=RG.undestroy;Ri.prototype._destroy=function(t,e){e(t)}});var Cm=_((P$t,J1e)=>{"use strict";var b2t=Object.keys||function(t){var e=[];for(var r in t)e.push(r);return e};J1e.exports=EA;var V1e=OG(),NG=TG();R0()(EA,V1e);for(LG=b2t(NG.prototype),RQ=0;RQ<LG.length;RQ++)TQ=LG[RQ],EA.prototype[TQ]||(EA.prototype[TQ]=NG.prototype[TQ]);var LG,TQ,RQ;function EA(t){if(!(this instanceof EA))return new EA(t);V1e.call(this,t),NG.call(this,t),this.allowHalfOpen=!0,t&&(t.readable===!1&&(this.readable=!1),t.writable===!1&&(this.writable=!1),t.allowHalfOpen===!1&&(this.allowHalfOpen=!1,this.once("end",x2t)))}Object.defineProperty(EA.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});Object.defineProperty(EA.prototype,"writableBuffer",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});Object.defineProperty(EA.prototype,"writableLength",{enumerable:!1,get:function(){return this._writableState.length}});function x2t(){this._writableState.ended||process.nextTick(k2t,this)}function k2t(t){t.end()}Object.defineProperty(EA.prototype,"destroyed",{enumerable:!1,get:function(){return this._readableState===void 0||this._writableState===void 0?!1:this._readableState.destroyed&&this._writableState.destroyed},set:function(e){this._readableState===void 0||this._writableState===void 0||(this._readableState.destroyed=e,this._writableState.destroyed=e)}})});var $1e=_((MG,Z1e)=>{var LQ=ve("buffer"),sp=LQ.Buffer;function X1e(t,e){for(var r in t)e[r]=t[r]}sp.from&&sp.alloc&&sp.allocUnsafe&&sp.allocUnsafeSlow?Z1e.exports=LQ:(X1e(LQ,MG),MG.Buffer=ZC);function ZC(t,e,r){return sp(t,e,r)}X1e(sp,ZC);ZC.from=function(t,e,r){if(typeof t=="number")throw new TypeError("Argument must not be a number");return sp(t,e,r)};ZC.alloc=function(t,e,r){if(typeof t!="number")throw new TypeError("Argument must be a number");var o=sp(t);return e!==void 0?typeof r=="string"?o.fill(e,r):o.fill(e):o.fill(0),o};ZC.allocUnsafe=function(t){if(typeof t!="number")throw new TypeError("Argument must be a number");return sp(t)};ZC.allocUnsafeSlow=function(t){if(typeof t!="number")throw new TypeError("Argument must be a number");return LQ.SlowBuffer(t)}});var HG=_(t2e=>{"use strict";var _G=$1e().Buffer,e2e=_G.isEncoding||function(t){switch(t=""+t,t&&t.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function Q2t(t){if(!t)return"utf8";for(var e;;)switch(t){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return t;default:if(e)return;t=(""+t).toLowerCase(),e=!0}}function F2t(t){var e=Q2t(t);if(typeof e!="string"&&(_G.isEncoding===e2e||!e2e(t)))throw new Error("Unknown encoding: "+t);return e||t}t2e.StringDecoder=yv;function yv(t){this.encoding=F2t(t);var e;switch(this.encoding){case"utf16le":this.text=M2t,this.end=U2t,e=4;break;case"utf8":this.fillLast=L2t,e=4;break;case"base64":this.text=_2t,this.end=H2t,e=3;break;default:this.write=q2t,this.end=G2t;return}this.lastNeed=0,this.lastTotal=0,this.lastChar=_G.allocUnsafe(e)}yv.prototype.write=function(t){if(t.length===0)return"";var e,r;if(this.lastNeed){if(e=this.fillLast(t),e===void 0)return"";r=this.lastNeed,this.lastNeed=0}else r=0;return r<t.length?e?e+this.text(t,r):this.text(t,r):e||""};yv.prototype.end=O2t;yv.prototype.text=N2t;yv.prototype.fillLast=function(t){if(this.lastNeed<=t.length)return t.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);t.copy(this.lastChar,this.lastTotal-this.lastNeed,0,t.length),this.lastNeed-=t.length};function UG(t){return t<=127?0:t>>5===6?2:t>>4===14?3:t>>3===30?4:t>>6===2?-1:-2}function R2t(t,e,r){var o=e.length-1;if(o<r)return 0;var a=UG(e[o]);return a>=0?(a>0&&(t.lastNeed=a-1),a):--o<r||a===-2?0:(a=UG(e[o]),a>=0?(a>0&&(t.lastNeed=a-2),a):--o<r||a===-2?0:(a=UG(e[o]),a>=0?(a>0&&(a===2?a=0:t.lastNeed=a-3),a):0))}function T2t(t,e,r){if((e[0]&192)!==128)return t.lastNeed=0,"\uFFFD";if(t.lastNeed>1&&e.length>1){if((e[1]&192)!==128)return t.lastNeed=1,"\uFFFD";if(t.lastNeed>2&&e.length>2&&(e[2]&192)!==128)return t.lastNeed=2,"\uFFFD"}}function L2t(t){var e=this.lastTotal-this.lastNeed,r=T2t(this,t,e);if(r!==void 0)return r;if(this.lastNeed<=t.length)return t.copy(this.lastChar,e,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);t.copy(this.lastChar,e,0,t.length),this.lastNeed-=t.length}function N2t(t,e){var r=R2t(this,t,e);if(!this.lastNeed)return t.toString("utf8",e);this.lastTotal=r;var o=t.length-(r-this.lastNeed);return t.copy(this.lastChar,0,o),t.toString("utf8",e,o)}function O2t(t){var e=t&&t.length?this.write(t):"";return this.lastNeed?e+"\uFFFD":e}function M2t(t,e){if((t.length-e)%2===0){var r=t.toString("utf16le",e);if(r){var o=r.charCodeAt(r.length-1);if(o>=55296&&o<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1],r.slice(0,-1)}return r}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=t[t.length-1],t.toString("utf16le",e,t.length-1)}function U2t(t){var e=t&&t.length?this.write(t):"";if(this.lastNeed){var r=this.lastTotal-this.lastNeed;return e+this.lastChar.toString("utf16le",0,r)}return e}function _2t(t,e){var r=(t.length-e)%3;return r===0?t.toString("base64",e):(this.lastNeed=3-r,this.lastTotal=3,r===1?this.lastChar[0]=t[t.length-1]:(this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1]),t.toString("base64",e,t.length-r))}function H2t(t){var e=t&&t.length?this.write(t):"";return this.lastNeed?e+this.lastChar.toString("base64",0,3-this.lastNeed):e}function q2t(t){return t.toString(this.encoding)}function G2t(t){return t&&t.length?this.write(t):""}});var NQ=_((b$t,i2e)=>{"use strict";var r2e=F0().codes.ERR_STREAM_PREMATURE_CLOSE;function j2t(t){var e=!1;return function(){if(!e){e=!0;for(var r=arguments.length,o=new Array(r),a=0;a<r;a++)o[a]=arguments[a];t.apply(this,o)}}}function Y2t(){}function W2t(t){return t.setHeader&&typeof t.abort=="function"}function n2e(t,e,r){if(typeof e=="function")return n2e(t,null,e);e||(e={}),r=j2t(r||Y2t);var o=e.readable||e.readable!==!1&&t.readable,a=e.writable||e.writable!==!1&&t.writable,n=function(){t.writable||A()},u=t._writableState&&t._writableState.finished,A=function(){a=!1,u=!0,o||r.call(t)},p=t._readableState&&t._readableState.endEmitted,h=function(){o=!1,p=!0,a||r.call(t)},E=function(C){r.call(t,C)},I=function(){var C;if(o&&!p)return(!t._readableState||!t._readableState.ended)&&(C=new r2e),r.call(t,C);if(a&&!u)return(!t._writableState||!t._writableState.ended)&&(C=new r2e),r.call(t,C)},v=function(){t.req.on("finish",A)};return W2t(t)?(t.on("complete",A),t.on("abort",I),t.req?v():t.on("request",v)):a&&!t._writableState&&(t.on("end",n),t.on("close",n)),t.on("end",h),t.on("finish",A),e.error!==!1&&t.on("error",E),t.on("close",I),function(){t.removeListener("complete",A),t.removeListener("abort",I),t.removeListener("request",v),t.req&&t.req.removeListener("finish",A),t.removeListener("end",n),t.removeListener("close",n),t.removeListener("finish",A),t.removeListener("end",h),t.removeListener("error",E),t.removeListener("close",I)}}i2e.exports=n2e});var o2e=_((x$t,s2e)=>{"use strict";var OQ;function L0(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var K2t=NQ(),N0=Symbol("lastResolve"),wm=Symbol("lastReject"),Ev=Symbol("error"),MQ=Symbol("ended"),Im=Symbol("lastPromise"),qG=Symbol("handlePromise"),Bm=Symbol("stream");function O0(t,e){return{value:t,done:e}}function z2t(t){var e=t[N0];if(e!==null){var r=t[Bm].read();r!==null&&(t[Im]=null,t[N0]=null,t[wm]=null,e(O0(r,!1)))}}function V2t(t){process.nextTick(z2t,t)}function J2t(t,e){return function(r,o){t.then(function(){if(e[MQ]){r(O0(void 0,!0));return}e[qG](r,o)},o)}}var X2t=Object.getPrototypeOf(function(){}),Z2t=Object.setPrototypeOf((OQ={get stream(){return this[Bm]},next:function(){var e=this,r=this[Ev];if(r!==null)return Promise.reject(r);if(this[MQ])return Promise.resolve(O0(void 0,!0));if(this[Bm].destroyed)return new Promise(function(u,A){process.nextTick(function(){e[Ev]?A(e[Ev]):u(O0(void 0,!0))})});var o=this[Im],a;if(o)a=new Promise(J2t(o,this));else{var n=this[Bm].read();if(n!==null)return Promise.resolve(O0(n,!1));a=new Promise(this[qG])}return this[Im]=a,a}},L0(OQ,Symbol.asyncIterator,function(){return this}),L0(OQ,"return",function(){var e=this;return new Promise(function(r,o){e[Bm].destroy(null,function(a){if(a){o(a);return}r(O0(void 0,!0))})})}),OQ),X2t),$2t=function(e){var r,o=Object.create(Z2t,(r={},L0(r,Bm,{value:e,writable:!0}),L0(r,N0,{value:null,writable:!0}),L0(r,wm,{value:null,writable:!0}),L0(r,Ev,{value:null,writable:!0}),L0(r,MQ,{value:e._readableState.endEmitted,writable:!0}),L0(r,qG,{value:function(n,u){var A=o[Bm].read();A?(o[Im]=null,o[N0]=null,o[wm]=null,n(O0(A,!1))):(o[N0]=n,o[wm]=u)},writable:!0}),r));return o[Im]=null,K2t(e,function(a){if(a&&a.code!=="ERR_STREAM_PREMATURE_CLOSE"){var n=o[wm];n!==null&&(o[Im]=null,o[N0]=null,o[wm]=null,n(a)),o[Ev]=a;return}var u=o[N0];u!==null&&(o[Im]=null,o[N0]=null,o[wm]=null,u(O0(void 0,!0))),o[MQ]=!0}),e.on("readable",V2t.bind(null,o)),o};s2e.exports=$2t});var u2e=_((k$t,c2e)=>{"use strict";function a2e(t,e,r,o,a,n,u){try{var A=t[n](u),p=A.value}catch(h){r(h);return}A.done?e(p):Promise.resolve(p).then(o,a)}function eBt(t){return function(){var e=this,r=arguments;return new Promise(function(o,a){var n=t.apply(e,r);function u(p){a2e(n,o,a,u,A,"next",p)}function A(p){a2e(n,o,a,u,A,"throw",p)}u(void 0)})}}function l2e(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter(function(a){return Object.getOwnPropertyDescriptor(t,a).enumerable})),r.push.apply(r,o)}return r}function tBt(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?l2e(Object(r),!0).forEach(function(o){rBt(t,o,r[o])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):l2e(Object(r)).forEach(function(o){Object.defineProperty(t,o,Object.getOwnPropertyDescriptor(r,o))})}return t}function rBt(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var nBt=F0().codes.ERR_INVALID_ARG_TYPE;function iBt(t,e,r){var o;if(e&&typeof e.next=="function")o=e;else if(e&&e[Symbol.asyncIterator])o=e[Symbol.asyncIterator]();else if(e&&e[Symbol.iterator])o=e[Symbol.iterator]();else throw new nBt("iterable",["Iterable"],e);var a=new t(tBt({objectMode:!0},r)),n=!1;a._read=function(){n||(n=!0,u())};function u(){return A.apply(this,arguments)}function A(){return A=eBt(function*(){try{var p=yield o.next(),h=p.value,E=p.done;E?a.push(null):a.push(yield h)?u():n=!1}catch(I){a.destroy(I)}}),A.apply(this,arguments)}return a}c2e.exports=iBt});var OG=_((F$t,C2e)=>{"use strict";C2e.exports=mn;var $C;mn.ReadableState=h2e;var Q$t=ve("events").EventEmitter,p2e=function(e,r){return e.listeners(r).length},wv=vG(),UQ=ve("buffer").Buffer,sBt=global.Uint8Array||function(){};function oBt(t){return UQ.from(t)}function aBt(t){return UQ.isBuffer(t)||t instanceof sBt}var GG=ve("util"),en;GG&&GG.debuglog?en=GG.debuglog("stream"):en=function(){};var lBt=R1e(),JG=SG(),cBt=bG(),uBt=cBt.getHighWaterMark,_Q=F0().codes,ABt=_Q.ERR_INVALID_ARG_TYPE,fBt=_Q.ERR_STREAM_PUSH_AFTER_EOF,pBt=_Q.ERR_METHOD_NOT_IMPLEMENTED,hBt=_Q.ERR_STREAM_UNSHIFT_AFTER_END_EVENT,ew,jG,YG;R0()(mn,wv);var Cv=JG.errorOrDestroy,WG=["error","close","destroy","pause","resume"];function gBt(t,e,r){if(typeof t.prependListener=="function")return t.prependListener(e,r);!t._events||!t._events[e]?t.on(e,r):Array.isArray(t._events[e])?t._events[e].unshift(r):t._events[e]=[r,t._events[e]]}function h2e(t,e,r){$C=$C||Cm(),t=t||{},typeof r!="boolean"&&(r=e instanceof $C),this.objectMode=!!t.objectMode,r&&(this.objectMode=this.objectMode||!!t.readableObjectMode),this.highWaterMark=uBt(this,t,"readableHighWaterMark",r),this.buffer=new lBt,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=t.emitClose!==!1,this.autoDestroy=!!t.autoDestroy,this.destroyed=!1,this.defaultEncoding=t.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,t.encoding&&(ew||(ew=HG().StringDecoder),this.decoder=new ew(t.encoding),this.encoding=t.encoding)}function mn(t){if($C=$C||Cm(),!(this instanceof mn))return new mn(t);var e=this instanceof $C;this._readableState=new h2e(t,this,e),this.readable=!0,t&&(typeof t.read=="function"&&(this._read=t.read),typeof t.destroy=="function"&&(this._destroy=t.destroy)),wv.call(this)}Object.defineProperty(mn.prototype,"destroyed",{enumerable:!1,get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(e){!this._readableState||(this._readableState.destroyed=e)}});mn.prototype.destroy=JG.destroy;mn.prototype._undestroy=JG.undestroy;mn.prototype._destroy=function(t,e){e(t)};mn.prototype.push=function(t,e){var r=this._readableState,o;return r.objectMode?o=!0:typeof t=="string"&&(e=e||r.defaultEncoding,e!==r.encoding&&(t=UQ.from(t,e),e=""),o=!0),g2e(this,t,e,!1,o)};mn.prototype.unshift=function(t){return g2e(this,t,null,!0,!1)};function g2e(t,e,r,o,a){en("readableAddChunk",e);var n=t._readableState;if(e===null)n.reading=!1,yBt(t,n);else{var u;if(a||(u=dBt(n,e)),u)Cv(t,u);else if(n.objectMode||e&&e.length>0)if(typeof e!="string"&&!n.objectMode&&Object.getPrototypeOf(e)!==UQ.prototype&&(e=oBt(e)),o)n.endEmitted?Cv(t,new hBt):KG(t,n,e,!0);else if(n.ended)Cv(t,new fBt);else{if(n.destroyed)return!1;n.reading=!1,n.decoder&&!r?(e=n.decoder.write(e),n.objectMode||e.length!==0?KG(t,n,e,!1):VG(t,n)):KG(t,n,e,!1)}else o||(n.reading=!1,VG(t,n))}return!n.ended&&(n.length<n.highWaterMark||n.length===0)}function KG(t,e,r,o){e.flowing&&e.length===0&&!e.sync?(e.awaitDrain=0,t.emit("data",r)):(e.length+=e.objectMode?1:r.length,o?e.buffer.unshift(r):e.buffer.push(r),e.needReadable&&HQ(t)),VG(t,e)}function dBt(t,e){var r;return!aBt(e)&&typeof e!="string"&&e!==void 0&&!t.objectMode&&(r=new ABt("chunk",["string","Buffer","Uint8Array"],e)),r}mn.prototype.isPaused=function(){return this._readableState.flowing===!1};mn.prototype.setEncoding=function(t){ew||(ew=HG().StringDecoder);var e=new ew(t);this._readableState.decoder=e,this._readableState.encoding=this._readableState.decoder.encoding;for(var r=this._readableState.buffer.head,o="";r!==null;)o+=e.write(r.data),r=r.next;return this._readableState.buffer.clear(),o!==""&&this._readableState.buffer.push(o),this._readableState.length=o.length,this};var A2e=1073741824;function mBt(t){return t>=A2e?t=A2e:(t--,t|=t>>>1,t|=t>>>2,t|=t>>>4,t|=t>>>8,t|=t>>>16,t++),t}function f2e(t,e){return t<=0||e.length===0&&e.ended?0:e.objectMode?1:t!==t?e.flowing&&e.length?e.buffer.head.data.length:e.length:(t>e.highWaterMark&&(e.highWaterMark=mBt(t)),t<=e.length?t:e.ended?e.length:(e.needReadable=!0,0))}mn.prototype.read=function(t){en("read",t),t=parseInt(t,10);var e=this._readableState,r=t;if(t!==0&&(e.emittedReadable=!1),t===0&&e.needReadable&&((e.highWaterMark!==0?e.length>=e.highWaterMark:e.length>0)||e.ended))return en("read: emitReadable",e.length,e.ended),e.length===0&&e.ended?zG(this):HQ(this),null;if(t=f2e(t,e),t===0&&e.ended)return e.length===0&&zG(this),null;var o=e.needReadable;en("need readable",o),(e.length===0||e.length-t<e.highWaterMark)&&(o=!0,en("length less than watermark",o)),e.ended||e.reading?(o=!1,en("reading or ended",o)):o&&(en("do read"),e.reading=!0,e.sync=!0,e.length===0&&(e.needReadable=!0),this._read(e.highWaterMark),e.sync=!1,e.reading||(t=f2e(r,e)));var a;return t>0?a=y2e(t,e):a=null,a===null?(e.needReadable=e.length<=e.highWaterMark,t=0):(e.length-=t,e.awaitDrain=0),e.length===0&&(e.ended||(e.needReadable=!0),r!==t&&e.ended&&zG(this)),a!==null&&this.emit("data",a),a};function yBt(t,e){if(en("onEofChunk"),!e.ended){if(e.decoder){var r=e.decoder.end();r&&r.length&&(e.buffer.push(r),e.length+=e.objectMode?1:r.length)}e.ended=!0,e.sync?HQ(t):(e.needReadable=!1,e.emittedReadable||(e.emittedReadable=!0,d2e(t)))}}function HQ(t){var e=t._readableState;en("emitReadable",e.needReadable,e.emittedReadable),e.needReadable=!1,e.emittedReadable||(en("emitReadable",e.flowing),e.emittedReadable=!0,process.nextTick(d2e,t))}function d2e(t){var e=t._readableState;en("emitReadable_",e.destroyed,e.length,e.ended),!e.destroyed&&(e.length||e.ended)&&(t.emit("readable"),e.emittedReadable=!1),e.needReadable=!e.flowing&&!e.ended&&e.length<=e.highWaterMark,XG(t)}function VG(t,e){e.readingMore||(e.readingMore=!0,process.nextTick(EBt,t,e))}function EBt(t,e){for(;!e.reading&&!e.ended&&(e.length<e.highWaterMark||e.flowing&&e.length===0);){var r=e.length;if(en("maybeReadMore read 0"),t.read(0),r===e.length)break}e.readingMore=!1}mn.prototype._read=function(t){Cv(this,new pBt("_read()"))};mn.prototype.pipe=function(t,e){var r=this,o=this._readableState;switch(o.pipesCount){case 0:o.pipes=t;break;case 1:o.pipes=[o.pipes,t];break;default:o.pipes.push(t);break}o.pipesCount+=1,en("pipe count=%d opts=%j",o.pipesCount,e);var a=(!e||e.end!==!1)&&t!==process.stdout&&t!==process.stderr,n=a?A:R;o.endEmitted?process.nextTick(n):r.once("end",n),t.on("unpipe",u);function u(N,U){en("onunpipe"),N===r&&U&&U.hasUnpiped===!1&&(U.hasUnpiped=!0,E())}function A(){en("onend"),t.end()}var p=CBt(r);t.on("drain",p);var h=!1;function E(){en("cleanup"),t.removeListener("close",x),t.removeListener("finish",C),t.removeListener("drain",p),t.removeListener("error",v),t.removeListener("unpipe",u),r.removeListener("end",A),r.removeListener("end",R),r.removeListener("data",I),h=!0,o.awaitDrain&&(!t._writableState||t._writableState.needDrain)&&p()}r.on("data",I);function I(N){en("ondata");var U=t.write(N);en("dest.write",U),U===!1&&((o.pipesCount===1&&o.pipes===t||o.pipesCount>1&&E2e(o.pipes,t)!==-1)&&!h&&(en("false write response, pause",o.awaitDrain),o.awaitDrain++),r.pause())}function v(N){en("onerror",N),R(),t.removeListener("error",v),p2e(t,"error")===0&&Cv(t,N)}gBt(t,"error",v);function x(){t.removeListener("finish",C),R()}t.once("close",x);function C(){en("onfinish"),t.removeListener("close",x),R()}t.once("finish",C);function R(){en("unpipe"),r.unpipe(t)}return t.emit("pipe",r),o.flowing||(en("pipe resume"),r.resume()),t};function CBt(t){return function(){var r=t._readableState;en("pipeOnDrain",r.awaitDrain),r.awaitDrain&&r.awaitDrain--,r.awaitDrain===0&&p2e(t,"data")&&(r.flowing=!0,XG(t))}}mn.prototype.unpipe=function(t){var e=this._readableState,r={hasUnpiped:!1};if(e.pipesCount===0)return this;if(e.pipesCount===1)return t&&t!==e.pipes?this:(t||(t=e.pipes),e.pipes=null,e.pipesCount=0,e.flowing=!1,t&&t.emit("unpipe",this,r),this);if(!t){var o=e.pipes,a=e.pipesCount;e.pipes=null,e.pipesCount=0,e.flowing=!1;for(var n=0;n<a;n++)o[n].emit("unpipe",this,{hasUnpiped:!1});return this}var u=E2e(e.pipes,t);return u===-1?this:(e.pipes.splice(u,1),e.pipesCount-=1,e.pipesCount===1&&(e.pipes=e.pipes[0]),t.emit("unpipe",this,r),this)};mn.prototype.on=function(t,e){var r=wv.prototype.on.call(this,t,e),o=this._readableState;return t==="data"?(o.readableListening=this.listenerCount("readable")>0,o.flowing!==!1&&this.resume()):t==="readable"&&!o.endEmitted&&!o.readableListening&&(o.readableListening=o.needReadable=!0,o.flowing=!1,o.emittedReadable=!1,en("on readable",o.length,o.reading),o.length?HQ(this):o.reading||process.nextTick(wBt,this)),r};mn.prototype.addListener=mn.prototype.on;mn.prototype.removeListener=function(t,e){var r=wv.prototype.removeListener.call(this,t,e);return t==="readable"&&process.nextTick(m2e,this),r};mn.prototype.removeAllListeners=function(t){var e=wv.prototype.removeAllListeners.apply(this,arguments);return(t==="readable"||t===void 0)&&process.nextTick(m2e,this),e};function m2e(t){var e=t._readableState;e.readableListening=t.listenerCount("readable")>0,e.resumeScheduled&&!e.paused?e.flowing=!0:t.listenerCount("data")>0&&t.resume()}function wBt(t){en("readable nexttick read 0"),t.read(0)}mn.prototype.resume=function(){var t=this._readableState;return t.flowing||(en("resume"),t.flowing=!t.readableListening,IBt(this,t)),t.paused=!1,this};function IBt(t,e){e.resumeScheduled||(e.resumeScheduled=!0,process.nextTick(BBt,t,e))}function BBt(t,e){en("resume",e.reading),e.reading||t.read(0),e.resumeScheduled=!1,t.emit("resume"),XG(t),e.flowing&&!e.reading&&t.read(0)}mn.prototype.pause=function(){return en("call pause flowing=%j",this._readableState.flowing),this._readableState.flowing!==!1&&(en("pause"),this._readableState.flowing=!1,this.emit("pause")),this._readableState.paused=!0,this};function XG(t){var e=t._readableState;for(en("flow",e.flowing);e.flowing&&t.read()!==null;);}mn.prototype.wrap=function(t){var e=this,r=this._readableState,o=!1;t.on("end",function(){if(en("wrapped end"),r.decoder&&!r.ended){var u=r.decoder.end();u&&u.length&&e.push(u)}e.push(null)}),t.on("data",function(u){if(en("wrapped data"),r.decoder&&(u=r.decoder.write(u)),!(r.objectMode&&u==null)&&!(!r.objectMode&&(!u||!u.length))){var A=e.push(u);A||(o=!0,t.pause())}});for(var a in t)this[a]===void 0&&typeof t[a]=="function"&&(this[a]=function(A){return function(){return t[A].apply(t,arguments)}}(a));for(var n=0;n<WG.length;n++)t.on(WG[n],this.emit.bind(this,WG[n]));return this._read=function(u){en("wrapped _read",u),o&&(o=!1,t.resume())},this};typeof Symbol=="function"&&(mn.prototype[Symbol.asyncIterator]=function(){return jG===void 0&&(jG=o2e()),jG(this)});Object.defineProperty(mn.prototype,"readableHighWaterMark",{enumerable:!1,get:function(){return this._readableState.highWaterMark}});Object.defineProperty(mn.prototype,"readableBuffer",{enumerable:!1,get:function(){return this._readableState&&this._readableState.buffer}});Object.defineProperty(mn.prototype,"readableFlowing",{enumerable:!1,get:function(){return this._readableState.flowing},set:function(e){this._readableState&&(this._readableState.flowing=e)}});mn._fromList=y2e;Object.defineProperty(mn.prototype,"readableLength",{enumerable:!1,get:function(){return this._readableState.length}});function y2e(t,e){if(e.length===0)return null;var r;return e.objectMode?r=e.buffer.shift():!t||t>=e.length?(e.decoder?r=e.buffer.join(""):e.buffer.length===1?r=e.buffer.first():r=e.buffer.concat(e.length),e.buffer.clear()):r=e.buffer.consume(t,e.decoder),r}function zG(t){var e=t._readableState;en("endReadable",e.endEmitted),e.endEmitted||(e.ended=!0,process.nextTick(vBt,e,t))}function vBt(t,e){if(en("endReadableNT",t.endEmitted,t.length),!t.endEmitted&&t.length===0&&(t.endEmitted=!0,e.readable=!1,e.emit("end"),t.autoDestroy)){var r=e._writableState;(!r||r.autoDestroy&&r.finished)&&e.destroy()}}typeof Symbol=="function"&&(mn.from=function(t,e){return YG===void 0&&(YG=u2e()),YG(mn,t,e)});function E2e(t,e){for(var r=0,o=t.length;r<o;r++)if(t[r]===e)return r;return-1}});var ZG=_((R$t,I2e)=>{"use strict";I2e.exports=op;var qQ=F0().codes,DBt=qQ.ERR_METHOD_NOT_IMPLEMENTED,PBt=qQ.ERR_MULTIPLE_CALLBACK,SBt=qQ.ERR_TRANSFORM_ALREADY_TRANSFORMING,bBt=qQ.ERR_TRANSFORM_WITH_LENGTH_0,GQ=Cm();R0()(op,GQ);function xBt(t,e){var r=this._transformState;r.transforming=!1;var o=r.writecb;if(o===null)return this.emit("error",new PBt);r.writechunk=null,r.writecb=null,e!=null&&this.push(e),o(t);var a=this._readableState;a.reading=!1,(a.needReadable||a.length<a.highWaterMark)&&this._read(a.highWaterMark)}function op(t){if(!(this instanceof op))return new op(t);GQ.call(this,t),this._transformState={afterTransform:xBt.bind(this),needTransform:!1,transforming:!1,writecb:null,writechunk:null,writeencoding:null},this._readableState.needReadable=!0,this._readableState.sync=!1,t&&(typeof t.transform=="function"&&(this._transform=t.transform),typeof t.flush=="function"&&(this._flush=t.flush)),this.on("prefinish",kBt)}function kBt(){var t=this;typeof this._flush=="function"&&!this._readableState.destroyed?this._flush(function(e,r){w2e(t,e,r)}):w2e(this,null,null)}op.prototype.push=function(t,e){return this._transformState.needTransform=!1,GQ.prototype.push.call(this,t,e)};op.prototype._transform=function(t,e,r){r(new DBt("_transform()"))};op.prototype._write=function(t,e,r){var o=this._transformState;if(o.writecb=r,o.writechunk=t,o.writeencoding=e,!o.transforming){var a=this._readableState;(o.needTransform||a.needReadable||a.length<a.highWaterMark)&&this._read(a.highWaterMark)}};op.prototype._read=function(t){var e=this._transformState;e.writechunk!==null&&!e.transforming?(e.transforming=!0,this._transform(e.writechunk,e.writeencoding,e.afterTransform)):e.needTransform=!0};op.prototype._destroy=function(t,e){GQ.prototype._destroy.call(this,t,function(r){e(r)})};function w2e(t,e,r){if(e)return t.emit("error",e);if(r!=null&&t.push(r),t._writableState.length)throw new bBt;if(t._transformState.transforming)throw new SBt;return t.push(null)}});var D2e=_((T$t,v2e)=>{"use strict";v2e.exports=Iv;var B2e=ZG();R0()(Iv,B2e);function Iv(t){if(!(this instanceof Iv))return new Iv(t);B2e.call(this,t)}Iv.prototype._transform=function(t,e,r){r(null,t)}});var k2e=_((L$t,x2e)=>{"use strict";var $G;function QBt(t){var e=!1;return function(){e||(e=!0,t.apply(void 0,arguments))}}var b2e=F0().codes,FBt=b2e.ERR_MISSING_ARGS,RBt=b2e.ERR_STREAM_DESTROYED;function P2e(t){if(t)throw t}function TBt(t){return t.setHeader&&typeof t.abort=="function"}function LBt(t,e,r,o){o=QBt(o);var a=!1;t.on("close",function(){a=!0}),$G===void 0&&($G=NQ()),$G(t,{readable:e,writable:r},function(u){if(u)return o(u);a=!0,o()});var n=!1;return function(u){if(!a&&!n){if(n=!0,TBt(t))return t.abort();if(typeof t.destroy=="function")return t.destroy();o(u||new RBt("pipe"))}}}function S2e(t){t()}function NBt(t,e){return t.pipe(e)}function OBt(t){return!t.length||typeof t[t.length-1]!="function"?P2e:t.pop()}function MBt(){for(var t=arguments.length,e=new Array(t),r=0;r<t;r++)e[r]=arguments[r];var o=OBt(e);if(Array.isArray(e[0])&&(e=e[0]),e.length<2)throw new FBt("streams");var a,n=e.map(function(u,A){var p=A<e.length-1,h=A>0;return LBt(u,p,h,function(E){a||(a=E),E&&n.forEach(S2e),!p&&(n.forEach(S2e),o(a))})});return e.reduce(NBt)}x2e.exports=MBt});var tw=_((cc,vv)=>{var Bv=ve("stream");process.env.READABLE_STREAM==="disable"&&Bv?(vv.exports=Bv.Readable,Object.assign(vv.exports,Bv),vv.exports.Stream=Bv):(cc=vv.exports=OG(),cc.Stream=Bv||cc,cc.Readable=cc,cc.Writable=TG(),cc.Duplex=Cm(),cc.Transform=ZG(),cc.PassThrough=D2e(),cc.finished=NQ(),cc.pipeline=k2e())});var R2e=_((N$t,F2e)=>{"use strict";var{Buffer:cu}=ve("buffer"),Q2e=Symbol.for("BufferList");function ni(t){if(!(this instanceof ni))return new ni(t);ni._init.call(this,t)}ni._init=function(e){Object.defineProperty(this,Q2e,{value:!0}),this._bufs=[],this.length=0,e&&this.append(e)};ni.prototype._new=function(e){return new ni(e)};ni.prototype._offset=function(e){if(e===0)return[0,0];let r=0;for(let o=0;o<this._bufs.length;o++){let a=r+this._bufs[o].length;if(e<a||o===this._bufs.length-1)return[o,e-r];r=a}};ni.prototype._reverseOffset=function(t){let e=t[0],r=t[1];for(let o=0;o<e;o++)r+=this._bufs[o].length;return r};ni.prototype.get=function(e){if(e>this.length||e<0)return;let r=this._offset(e);return this._bufs[r[0]][r[1]]};ni.prototype.slice=function(e,r){return typeof e=="number"&&e<0&&(e+=this.length),typeof r=="number"&&r<0&&(r+=this.length),this.copy(null,0,e,r)};ni.prototype.copy=function(e,r,o,a){if((typeof o!="number"||o<0)&&(o=0),(typeof a!="number"||a>this.length)&&(a=this.length),o>=this.length||a<=0)return e||cu.alloc(0);let n=!!e,u=this._offset(o),A=a-o,p=A,h=n&&r||0,E=u[1];if(o===0&&a===this.length){if(!n)return this._bufs.length===1?this._bufs[0]:cu.concat(this._bufs,this.length);for(let I=0;I<this._bufs.length;I++)this._bufs[I].copy(e,h),h+=this._bufs[I].length;return e}if(p<=this._bufs[u[0]].length-E)return n?this._bufs[u[0]].copy(e,r,E,E+p):this._bufs[u[0]].slice(E,E+p);n||(e=cu.allocUnsafe(A));for(let I=u[0];I<this._bufs.length;I++){let v=this._bufs[I].length-E;if(p>v)this._bufs[I].copy(e,h,E),h+=v;else{this._bufs[I].copy(e,h,E,E+p),h+=v;break}p-=v,E&&(E=0)}return e.length>h?e.slice(0,h):e};ni.prototype.shallowSlice=function(e,r){if(e=e||0,r=typeof r!="number"?this.length:r,e<0&&(e+=this.length),r<0&&(r+=this.length),e===r)return this._new();let o=this._offset(e),a=this._offset(r),n=this._bufs.slice(o[0],a[0]+1);return a[1]===0?n.pop():n[n.length-1]=n[n.length-1].slice(0,a[1]),o[1]!==0&&(n[0]=n[0].slice(o[1])),this._new(n)};ni.prototype.toString=function(e,r,o){return this.slice(r,o).toString(e)};ni.prototype.consume=function(e){if(e=Math.trunc(e),Number.isNaN(e)||e<=0)return this;for(;this._bufs.length;)if(e>=this._bufs[0].length)e-=this._bufs[0].length,this.length-=this._bufs[0].length,this._bufs.shift();else{this._bufs[0]=this._bufs[0].slice(e),this.length-=e;break}return this};ni.prototype.duplicate=function(){let e=this._new();for(let r=0;r<this._bufs.length;r++)e.append(this._bufs[r]);return e};ni.prototype.append=function(e){if(e==null)return this;if(e.buffer)this._appendBuffer(cu.from(e.buffer,e.byteOffset,e.byteLength));else if(Array.isArray(e))for(let r=0;r<e.length;r++)this.append(e[r]);else if(this._isBufferList(e))for(let r=0;r<e._bufs.length;r++)this.append(e._bufs[r]);else typeof e=="number"&&(e=e.toString()),this._appendBuffer(cu.from(e));return this};ni.prototype._appendBuffer=function(e){this._bufs.push(e),this.length+=e.length};ni.prototype.indexOf=function(t,e,r){if(r===void 0&&typeof e=="string"&&(r=e,e=void 0),typeof t=="function"||Array.isArray(t))throw new TypeError('The "value" argument must be one of type string, Buffer, BufferList, or Uint8Array.');if(typeof t=="number"?t=cu.from([t]):typeof t=="string"?t=cu.from(t,r):this._isBufferList(t)?t=t.slice():Array.isArray(t.buffer)?t=cu.from(t.buffer,t.byteOffset,t.byteLength):cu.isBuffer(t)||(t=cu.from(t)),e=Number(e||0),isNaN(e)&&(e=0),e<0&&(e=this.length+e),e<0&&(e=0),t.length===0)return e>this.length?this.length:e;let o=this._offset(e),a=o[0],n=o[1];for(;a<this._bufs.length;a++){let u=this._bufs[a];for(;n<u.length;)if(u.length-n>=t.length){let p=u.indexOf(t,n);if(p!==-1)return this._reverseOffset([a,p]);n=u.length-t.length+1}else{let p=this._reverseOffset([a,n]);if(this._match(p,t))return p;n++}n=0}return-1};ni.prototype._match=function(t,e){if(this.length-t<e.length)return!1;for(let r=0;r<e.length;r++)if(this.get(t+r)!==e[r])return!1;return!0};(function(){let t={readDoubleBE:8,readDoubleLE:8,readFloatBE:4,readFloatLE:4,readInt32BE:4,readInt32LE:4,readUInt32BE:4,readUInt32LE:4,readInt16BE:2,readInt16LE:2,readUInt16BE:2,readUInt16LE:2,readInt8:1,readUInt8:1,readIntBE:null,readIntLE:null,readUIntBE:null,readUIntLE:null};for(let e in t)(function(r){t[r]===null?ni.prototype[r]=function(o,a){return this.slice(o,o+a)[r](0,a)}:ni.prototype[r]=function(o=0){return this.slice(o,o+t[r])[r](0)}})(e)})();ni.prototype._isBufferList=function(e){return e instanceof ni||ni.isBufferList(e)};ni.isBufferList=function(e){return e!=null&&e[Q2e]};F2e.exports=ni});var T2e=_((O$t,jQ)=>{"use strict";var ej=tw().Duplex,UBt=R0(),Dv=R2e();function Uo(t){if(!(this instanceof Uo))return new Uo(t);if(typeof t=="function"){this._callback=t;let e=function(o){this._callback&&(this._callback(o),this._callback=null)}.bind(this);this.on("pipe",function(o){o.on("error",e)}),this.on("unpipe",function(o){o.removeListener("error",e)}),t=null}Dv._init.call(this,t),ej.call(this)}UBt(Uo,ej);Object.assign(Uo.prototype,Dv.prototype);Uo.prototype._new=function(e){return new Uo(e)};Uo.prototype._write=function(e,r,o){this._appendBuffer(e),typeof o=="function"&&o()};Uo.prototype._read=function(e){if(!this.length)return this.push(null);e=Math.min(e,this.length),this.push(this.slice(0,e)),this.consume(e)};Uo.prototype.end=function(e){ej.prototype.end.call(this,e),this._callback&&(this._callback(null,this.slice()),this._callback=null)};Uo.prototype._destroy=function(e,r){this._bufs.length=0,this.length=0,r(e)};Uo.prototype._isBufferList=function(e){return e instanceof Uo||e instanceof Dv||Uo.isBufferList(e)};Uo.isBufferList=Dv.isBufferList;jQ.exports=Uo;jQ.exports.BufferListStream=Uo;jQ.exports.BufferList=Dv});var nj=_(nw=>{var _Bt=Buffer.alloc,HBt="0000000000000000000",qBt="7777777777777777777",L2e="0".charCodeAt(0),N2e=Buffer.from("ustar\0","binary"),GBt=Buffer.from("00","binary"),jBt=Buffer.from("ustar ","binary"),YBt=Buffer.from(" \0","binary"),WBt=parseInt("7777",8),Pv=257,rj=263,KBt=function(t,e,r){return typeof t!="number"?r:(t=~~t,t>=e?e:t>=0||(t+=e,t>=0)?t:0)},zBt=function(t){switch(t){case 0:return"file";case 1:return"link";case 2:return"symlink";case 3:return"character-device";case 4:return"block-device";case 5:return"directory";case 6:return"fifo";case 7:return"contiguous-file";case 72:return"pax-header";case 55:return"pax-global-header";case 27:return"gnu-long-link-path";case 28:case 30:return"gnu-long-path"}return null},VBt=function(t){switch(t){case"file":return 0;case"link":return 1;case"symlink":return 2;case"character-device":return 3;case"block-device":return 4;case"directory":return 5;case"fifo":return 6;case"contiguous-file":return 7;case"pax-header":return 72}return 0},O2e=function(t,e,r,o){for(;r<o;r++)if(t[r]===e)return r;return o},M2e=function(t){for(var e=256,r=0;r<148;r++)e+=t[r];for(var o=156;o<512;o++)e+=t[o];return e},M0=function(t,e){return t=t.toString(8),t.length>e?qBt.slice(0,e)+" ":HBt.slice(0,e-t.length)+t+" "};function JBt(t){var e;if(t[0]===128)e=!0;else if(t[0]===255)e=!1;else return null;for(var r=[],o=t.length-1;o>0;o--){var a=t[o];e?r.push(a):r.push(255-a)}var n=0,u=r.length;for(o=0;o<u;o++)n+=r[o]*Math.pow(256,o);return e?n:-1*n}var U0=function(t,e,r){if(t=t.slice(e,e+r),e=0,t[e]&128)return JBt(t);for(;e<t.length&&t[e]===32;)e++;for(var o=KBt(O2e(t,32,e,t.length),t.length,t.length);e<o&&t[e]===0;)e++;return o===e?0:parseInt(t.slice(e,o).toString(),8)},rw=function(t,e,r,o){return t.slice(e,O2e(t,0,e,e+r)).toString(o)},tj=function(t){var e=Buffer.byteLength(t),r=Math.floor(Math.log(e)/Math.log(10))+1;return e+r>=Math.pow(10,r)&&r++,e+r+t};nw.decodeLongPath=function(t,e){return rw(t,0,t.length,e)};nw.encodePax=function(t){var e="";t.name&&(e+=tj(" path="+t.name+`
-`)),t.linkname&&(e+=tj(" linkpath="+t.linkname+`
-`));var r=t.pax;if(r)for(var o in r)e+=tj(" "+o+"="+r[o]+`
-`);return Buffer.from(e)};nw.decodePax=function(t){for(var e={};t.length;){for(var r=0;r<t.length&&t[r]!==32;)r++;var o=parseInt(t.slice(0,r).toString(),10);if(!o)return e;var a=t.slice(r+1,o-1).toString(),n=a.indexOf("=");if(n===-1)return e;e[a.slice(0,n)]=a.slice(n+1),t=t.slice(o)}return e};nw.encode=function(t){var e=_Bt(512),r=t.name,o="";if(t.typeflag===5&&r[r.length-1]!=="/"&&(r+="/"),Buffer.byteLength(r)!==r.length)return null;for(;Buffer.byteLength(r)>100;){var a=r.indexOf("/");if(a===-1)return null;o+=o?"/"+r.slice(0,a):r.slice(0,a),r=r.slice(a+1)}return Buffer.byteLength(r)>100||Buffer.byteLength(o)>155||t.linkname&&Buffer.byteLength(t.linkname)>100?null:(e.write(r),e.write(M0(t.mode&WBt,6),100),e.write(M0(t.uid,6),108),e.write(M0(t.gid,6),116),e.write(M0(t.size,11),124),e.write(M0(t.mtime.getTime()/1e3|0,11),136),e[156]=L2e+VBt(t.type),t.linkname&&e.write(t.linkname,157),N2e.copy(e,Pv),GBt.copy(e,rj),t.uname&&e.write(t.uname,265),t.gname&&e.write(t.gname,297),e.write(M0(t.devmajor||0,6),329),e.write(M0(t.devminor||0,6),337),o&&e.write(o,345),e.write(M0(M2e(e),6),148),e)};nw.decode=function(t,e,r){var o=t[156]===0?0:t[156]-L2e,a=rw(t,0,100,e),n=U0(t,100,8),u=U0(t,108,8),A=U0(t,116,8),p=U0(t,124,12),h=U0(t,136,12),E=zBt(o),I=t[157]===0?null:rw(t,157,100,e),v=rw(t,265,32),x=rw(t,297,32),C=U0(t,329,8),R=U0(t,337,8),N=M2e(t);if(N===8*32)return null;if(N!==U0(t,148,8))throw new Error("Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?");if(N2e.compare(t,Pv,Pv+6)===0)t[345]&&(a=rw(t,345,155,e)+"/"+a);else if(!(jBt.compare(t,Pv,Pv+6)===0&&YBt.compare(t,rj,rj+2)===0)){if(!r)throw new Error("Invalid tar header: unknown format.")}return o===0&&a&&a[a.length-1]==="/"&&(o=5),{name:a,mode:n,uid:u,gid:A,size:p,mtime:new Date(1e3*h),type:E,linkname:I,uname:v,gname:x,devmajor:C,devminor:R}}});var Y2e=_((U$t,j2e)=>{var _2e=ve("util"),XBt=T2e(),Sv=nj(),H2e=tw().Writable,q2e=tw().PassThrough,G2e=function(){},U2e=function(t){return t&=511,t&&512-t},ZBt=function(t,e){var r=new YQ(t,e);return r.end(),r},$Bt=function(t,e){return e.path&&(t.name=e.path),e.linkpath&&(t.linkname=e.linkpath),e.size&&(t.size=parseInt(e.size,10)),t.pax=e,t},YQ=function(t,e){this._parent=t,this.offset=e,q2e.call(this,{autoDestroy:!1})};_2e.inherits(YQ,q2e);YQ.prototype.destroy=function(t){this._parent.destroy(t)};var ap=function(t){if(!(this instanceof ap))return new ap(t);H2e.call(this,t),t=t||{},this._offset=0,this._buffer=XBt(),this._missing=0,this._partial=!1,this._onparse=G2e,this._header=null,this._stream=null,this._overflow=null,this._cb=null,this._locked=!1,this._destroyed=!1,this._pax=null,this._paxGlobal=null,this._gnuLongPath=null,this._gnuLongLinkPath=null;var e=this,r=e._buffer,o=function(){e._continue()},a=function(v){if(e._locked=!1,v)return e.destroy(v);e._stream||o()},n=function(){e._stream=null;var v=U2e(e._header.size);v?e._parse(v,u):e._parse(512,I),e._locked||o()},u=function(){e._buffer.consume(U2e(e._header.size)),e._parse(512,I),o()},A=function(){var v=e._header.size;e._paxGlobal=Sv.decodePax(r.slice(0,v)),r.consume(v),n()},p=function(){var v=e._header.size;e._pax=Sv.decodePax(r.slice(0,v)),e._paxGlobal&&(e._pax=Object.assign({},e._paxGlobal,e._pax)),r.consume(v),n()},h=function(){var v=e._header.size;this._gnuLongPath=Sv.decodeLongPath(r.slice(0,v),t.filenameEncoding),r.consume(v),n()},E=function(){var v=e._header.size;this._gnuLongLinkPath=Sv.decodeLongPath(r.slice(0,v),t.filenameEncoding),r.consume(v),n()},I=function(){var v=e._offset,x;try{x=e._header=Sv.decode(r.slice(0,512),t.filenameEncoding,t.allowUnknownFormat)}catch(C){e.emit("error",C)}if(r.consume(512),!x){e._parse(512,I),o();return}if(x.type==="gnu-long-path"){e._parse(x.size,h),o();return}if(x.type==="gnu-long-link-path"){e._parse(x.size,E),o();return}if(x.type==="pax-global-header"){e._parse(x.size,A),o();return}if(x.type==="pax-header"){e._parse(x.size,p),o();return}if(e._gnuLongPath&&(x.name=e._gnuLongPath,e._gnuLongPath=null),e._gnuLongLinkPath&&(x.linkname=e._gnuLongLinkPath,e._gnuLongLinkPath=null),e._pax&&(e._header=x=$Bt(x,e._pax),e._pax=null),e._locked=!0,!x.size||x.type==="directory"){e._parse(512,I),e.emit("entry",x,ZBt(e,v),a);return}e._stream=new YQ(e,v),e.emit("entry",x,e._stream,a),e._parse(x.size,n),o()};this._onheader=I,this._parse(512,I)};_2e.inherits(ap,H2e);ap.prototype.destroy=function(t){this._destroyed||(this._destroyed=!0,t&&this.emit("error",t),this.emit("close"),this._stream&&this._stream.emit("close"))};ap.prototype._parse=function(t,e){this._destroyed||(this._offset+=t,this._missing=t,e===this._onheader&&(this._partial=!1),this._onparse=e)};ap.prototype._continue=function(){if(!this._destroyed){var t=this._cb;this._cb=G2e,this._overflow?this._write(this._overflow,void 0,t):t()}};ap.prototype._write=function(t,e,r){if(!this._destroyed){var o=this._stream,a=this._buffer,n=this._missing;if(t.length&&(this._partial=!0),t.length<n)return this._missing-=t.length,this._overflow=null,o?o.write(t,r):(a.append(t),r());this._cb=r,this._missing=0;var u=null;t.length>n&&(u=t.slice(n),t=t.slice(0,n)),o?o.end(t):a.append(t),this._overflow=u,this._onparse()}};ap.prototype._final=function(t){if(this._partial)return this.destroy(new Error("Unexpected end of data"));t()};j2e.exports=ap});var K2e=_((_$t,W2e)=>{W2e.exports=ve("fs").constants||ve("constants")});var Z2e=_((H$t,X2e)=>{var iw=K2e(),z2e=NM(),KQ=R0(),evt=Buffer.alloc,V2e=tw().Readable,sw=tw().Writable,tvt=ve("string_decoder").StringDecoder,WQ=nj(),rvt=parseInt("755",8),nvt=parseInt("644",8),J2e=evt(1024),sj=function(){},ij=function(t,e){e&=511,e&&t.push(J2e.slice(0,512-e))};function ivt(t){switch(t&iw.S_IFMT){case iw.S_IFBLK:return"block-device";case iw.S_IFCHR:return"character-device";case iw.S_IFDIR:return"directory";case iw.S_IFIFO:return"fifo";case iw.S_IFLNK:return"symlink"}return"file"}var zQ=function(t){sw.call(this),this.written=0,this._to=t,this._destroyed=!1};KQ(zQ,sw);zQ.prototype._write=function(t,e,r){if(this.written+=t.length,this._to.push(t))return r();this._to._drain=r};zQ.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit("close"))};var VQ=function(){sw.call(this),this.linkname="",this._decoder=new tvt("utf-8"),this._destroyed=!1};KQ(VQ,sw);VQ.prototype._write=function(t,e,r){this.linkname+=this._decoder.write(t),r()};VQ.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit("close"))};var bv=function(){sw.call(this),this._destroyed=!1};KQ(bv,sw);bv.prototype._write=function(t,e,r){r(new Error("No body allowed for this entry"))};bv.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit("close"))};var CA=function(t){if(!(this instanceof CA))return new CA(t);V2e.call(this,t),this._drain=sj,this._finalized=!1,this._finalizing=!1,this._destroyed=!1,this._stream=null};KQ(CA,V2e);CA.prototype.entry=function(t,e,r){if(this._stream)throw new Error("already piping an entry");if(!(this._finalized||this._destroyed)){typeof e=="function"&&(r=e,e=null),r||(r=sj);var o=this;if((!t.size||t.type==="symlink")&&(t.size=0),t.type||(t.type=ivt(t.mode)),t.mode||(t.mode=t.type==="directory"?rvt:nvt),t.uid||(t.uid=0),t.gid||(t.gid=0),t.mtime||(t.mtime=new Date),typeof e=="string"&&(e=Buffer.from(e)),Buffer.isBuffer(e)){t.size=e.length,this._encode(t);var a=this.push(e);return ij(o,t.size),a?process.nextTick(r):this._drain=r,new bv}if(t.type==="symlink"&&!t.linkname){var n=new VQ;return z2e(n,function(A){if(A)return o.destroy(),r(A);t.linkname=n.linkname,o._encode(t),r()}),n}if(this._encode(t),t.type!=="file"&&t.type!=="contiguous-file")return process.nextTick(r),new bv;var u=new zQ(this);return this._stream=u,z2e(u,function(A){if(o._stream=null,A)return o.destroy(),r(A);if(u.written!==t.size)return o.destroy(),r(new Error("size mismatch"));ij(o,t.size),o._finalizing&&o.finalize(),r()}),u}};CA.prototype.finalize=function(){if(this._stream){this._finalizing=!0;return}this._finalized||(this._finalized=!0,this.push(J2e),this.push(null))};CA.prototype.destroy=function(t){this._destroyed||(this._destroyed=!0,t&&this.emit("error",t),this.emit("close"),this._stream&&this._stream.destroy&&this._stream.destroy())};CA.prototype._encode=function(t){if(!t.pax){var e=WQ.encode(t);if(e){this.push(e);return}}this._encodePax(t)};CA.prototype._encodePax=function(t){var e=WQ.encodePax({name:t.name,linkname:t.linkname,pax:t.pax}),r={name:"PaxHeader",mode:t.mode,uid:t.uid,gid:t.gid,size:e.length,mtime:t.mtime,type:"pax-header",linkname:t.linkname&&"PaxHeader",uname:t.uname,gname:t.gname,devmajor:t.devmajor,devminor:t.devminor};this.push(WQ.encode(r)),this.push(e),ij(this,e.length),r.size=t.size,r.type=t.type,this.push(WQ.encode(r))};CA.prototype._read=function(t){var e=this._drain;this._drain=sj,e()};X2e.exports=CA});var $2e=_(oj=>{oj.extract=Y2e();oj.pack=Z2e()});var ABe=_((aer,uBe)=>{"use strict";var vm=class{constructor(e,r,o){this.__specs=e||{},Object.keys(this.__specs).forEach(a=>{if(typeof this.__specs[a]=="string"){let n=this.__specs[a],u=this.__specs[n];if(u){let A=u.aliases||[];A.push(a,n),u.aliases=[...new Set(A)],this.__specs[a]=u}else throw new Error(`Alias refers to invalid key: ${n} -> ${a}`)}}),this.__opts=r||{},this.__providers=lBe(o.filter(a=>a!=null&&typeof a=="object")),this.__isFiggyPudding=!0}get(e){return fj(this,e,!0)}get[Symbol.toStringTag](){return"FiggyPudding"}forEach(e,r=this){for(let[o,a]of this.entries())e.call(r,a,o,this)}toJSON(){let e={};return this.forEach((r,o)=>{e[o]=r}),e}*entries(e){for(let o of Object.keys(this.__specs))yield[o,this.get(o)];let r=e||this.__opts.other;if(r){let o=new Set;for(let a of this.__providers){let n=a.entries?a.entries(r):Evt(a);for(let[u,A]of n)r(u)&&!o.has(u)&&(o.add(u),yield[u,A])}}}*[Symbol.iterator](){for(let[e,r]of this.entries())yield[e,r]}*keys(){for(let[e]of this.entries())yield e}*values(){for(let[,e]of this.entries())yield e}concat(...e){return new Proxy(new vm(this.__specs,this.__opts,lBe(this.__providers).concat(e)),cBe)}};try{let t=ve("util");vm.prototype[t.inspect.custom]=function(e,r){return this[Symbol.toStringTag]+" "+t.inspect(this.toJSON(),r)}}catch{}function mvt(t){throw Object.assign(new Error(`invalid config key requested: ${t}`),{code:"EBADKEY"})}function fj(t,e,r){let o=t.__specs[e];if(r&&!o&&(!t.__opts.other||!t.__opts.other(e)))mvt(e);else{o||(o={});let a;for(let n of t.__providers){if(a=aBe(e,n),a===void 0&&o.aliases&&o.aliases.length){for(let u of o.aliases)if(u!==e&&(a=aBe(u,n),a!==void 0))break}if(a!==void 0)break}return a===void 0&&o.default!==void 0?typeof o.default=="function"?o.default(t):o.default:a}}function aBe(t,e){let r;return e.__isFiggyPudding?r=fj(e,t,!1):typeof e.get=="function"?r=e.get(t):r=e[t],r}var cBe={has(t,e){return e in t.__specs&&fj(t,e,!1)!==void 0},ownKeys(t){return Object.keys(t.__specs)},get(t,e){return typeof e=="symbol"||e.slice(0,2)==="__"||e in vm.prototype?t[e]:t.get(e)},set(t,e,r){if(typeof e=="symbol"||e.slice(0,2)==="__")return t[e]=r,!0;throw new Error("figgyPudding options cannot be modified. Use .concat() instead.")},deleteProperty(){throw new Error("figgyPudding options cannot be deleted. Use .concat() and shadow them instead.")}};uBe.exports=yvt;function yvt(t,e){function r(...o){return new Proxy(new vm(t,e,o),cBe)}return r}function lBe(t){let e=[];return t.forEach(r=>e.unshift(r)),e}function Evt(t){return Object.keys(t).map(e=>[e,t[e]])}});var hBe=_((ler,BA)=>{"use strict";var kv=ve("crypto"),Cvt=ABe(),wvt=ve("stream").Transform,fBe=["sha256","sha384","sha512"],Ivt=/^[a-z0-9+/]+(?:=?=?)$/i,Bvt=/^([^-]+)-([^?]+)([?\S*]*)$/,vvt=/^([^-]+)-([A-Za-z0-9+/=]{44,88})(\?[\x21-\x7E]*)*$/,Dvt=/^[\x21-\x7E]+$/,ia=Cvt({algorithms:{default:["sha512"]},error:{default:!1},integrity:{},options:{default:[]},pickAlgorithm:{default:()=>Rvt},Promise:{default:()=>Promise},sep:{default:" "},single:{default:!1},size:{},strict:{default:!1}}),H0=class{get isHash(){return!0}constructor(e,r){r=ia(r);let o=!!r.strict;this.source=e.trim();let a=this.source.match(o?vvt:Bvt);if(!a||o&&!fBe.some(u=>u===a[1]))return;this.algorithm=a[1],this.digest=a[2];let n=a[3];this.options=n?n.slice(1).split("?"):[]}hexDigest(){return this.digest&&Buffer.from(this.digest,"base64").toString("hex")}toJSON(){return this.toString()}toString(e){if(e=ia(e),e.strict&&!(fBe.some(o=>o===this.algorithm)&&this.digest.match(Ivt)&&(this.options||[]).every(o=>o.match(Dvt))))return"";let r=this.options&&this.options.length?`?${this.options.join("?")}`:"";return`${this.algorithm}-${this.digest}${r}`}},Dm=class{get isIntegrity(){return!0}toJSON(){return this.toString()}toString(e){e=ia(e);let r=e.sep||" ";return e.strict&&(r=r.replace(/\S+/g," ")),Object.keys(this).map(o=>this[o].map(a=>H0.prototype.toString.call(a,e)).filter(a=>a.length).join(r)).filter(o=>o.length).join(r)}concat(e,r){r=ia(r);let o=typeof e=="string"?e:xv(e,r);return IA(`${this.toString(r)} ${o}`,r)}hexDigest(){return IA(this,{single:!0}).hexDigest()}match(e,r){r=ia(r);let o=IA(e,r),a=o.pickAlgorithm(r);return this[a]&&o[a]&&this[a].find(n=>o[a].find(u=>n.digest===u.digest))||!1}pickAlgorithm(e){e=ia(e);let r=e.pickAlgorithm,o=Object.keys(this);if(!o.length)throw new Error(`No algorithms available for ${JSON.stringify(this.toString())}`);return o.reduce((a,n)=>r(a,n)||a)}};BA.exports.parse=IA;function IA(t,e){if(e=ia(e),typeof t=="string")return pj(t,e);if(t.algorithm&&t.digest){let r=new Dm;return r[t.algorithm]=[t],pj(xv(r,e),e)}else return pj(xv(t,e),e)}function pj(t,e){return e.single?new H0(t,e):t.trim().split(/\s+/).reduce((r,o)=>{let a=new H0(o,e);if(a.algorithm&&a.digest){let n=a.algorithm;r[n]||(r[n]=[]),r[n].push(a)}return r},new Dm)}BA.exports.stringify=xv;function xv(t,e){return e=ia(e),t.algorithm&&t.digest?H0.prototype.toString.call(t,e):typeof t=="string"?xv(IA(t,e),e):Dm.prototype.toString.call(t,e)}BA.exports.fromHex=Pvt;function Pvt(t,e,r){r=ia(r);let o=r.options&&r.options.length?`?${r.options.join("?")}`:"";return IA(`${e}-${Buffer.from(t,"hex").toString("base64")}${o}`,r)}BA.exports.fromData=Svt;function Svt(t,e){e=ia(e);let r=e.algorithms,o=e.options&&e.options.length?`?${e.options.join("?")}`:"";return r.reduce((a,n)=>{let u=kv.createHash(n).update(t).digest("base64"),A=new H0(`${n}-${u}${o}`,e);if(A.algorithm&&A.digest){let p=A.algorithm;a[p]||(a[p]=[]),a[p].push(A)}return a},new Dm)}BA.exports.fromStream=bvt;function bvt(t,e){e=ia(e);let r=e.Promise||Promise,o=hj(e);return new r((a,n)=>{t.pipe(o),t.on("error",n),o.on("error",n);let u;o.on("integrity",A=>{u=A}),o.on("end",()=>a(u)),o.on("data",()=>{})})}BA.exports.checkData=xvt;function xvt(t,e,r){if(r=ia(r),e=IA(e,r),!Object.keys(e).length){if(r.error)throw Object.assign(new Error("No valid integrity hashes to check against"),{code:"EINTEGRITY"});return!1}let o=e.pickAlgorithm(r),a=kv.createHash(o).update(t).digest("base64"),n=IA({algorithm:o,digest:a}),u=n.match(e,r);if(u||!r.error)return u;if(typeof r.size=="number"&&t.length!==r.size){let A=new Error(`data size mismatch when checking ${e}.
- Wanted: ${r.size}
- Found: ${t.length}`);throw A.code="EBADSIZE",A.found=t.length,A.expected=r.size,A.sri=e,A}else{let A=new Error(`Integrity checksum failed when using ${o}: Wanted ${e}, but got ${n}. (${t.length} bytes)`);throw A.code="EINTEGRITY",A.found=n,A.expected=e,A.algorithm=o,A.sri=e,A}}BA.exports.checkStream=kvt;function kvt(t,e,r){r=ia(r);let o=r.Promise||Promise,a=hj(r.concat({integrity:e}));return new o((n,u)=>{t.pipe(a),t.on("error",u),a.on("error",u);let A;a.on("verified",p=>{A=p}),a.on("end",()=>n(A)),a.on("data",()=>{})})}BA.exports.integrityStream=hj;function hj(t){t=ia(t);let e=t.integrity&&IA(t.integrity,t),r=e&&Object.keys(e).length,o=r&&e.pickAlgorithm(t),a=r&&e[o],n=Array.from(new Set(t.algorithms.concat(o?[o]:[]))),u=n.map(kv.createHash),A=0,p=new wvt({transform(h,E,I){A+=h.length,u.forEach(v=>v.update(h,E)),I(null,h,E)}}).on("end",()=>{let h=t.options&&t.options.length?`?${t.options.join("?")}`:"",E=IA(u.map((v,x)=>`${n[x]}-${v.digest("base64")}${h}`).join(" "),t),I=r&&E.match(e,t);if(typeof t.size=="number"&&A!==t.size){let v=new Error(`stream size mismatch when checking ${e}.
- Wanted: ${t.size}
- Found: ${A}`);v.code="EBADSIZE",v.found=A,v.expected=t.size,v.sri=e,p.emit("error",v)}else if(t.integrity&&!I){let v=new Error(`${e} integrity checksum failed when using ${o}: wanted ${a} but got ${E}. (${A} bytes)`);v.code="EINTEGRITY",v.found=E,v.expected=a,v.algorithm=o,v.sri=e,p.emit("error",v)}else p.emit("size",A),p.emit("integrity",E),I&&p.emit("verified",I)});return p}BA.exports.create=Qvt;function Qvt(t){t=ia(t);let e=t.algorithms,r=t.options.length?`?${t.options.join("?")}`:"",o=e.map(kv.createHash);return{update:function(a,n){return o.forEach(u=>u.update(a,n)),this},digest:function(a){return e.reduce((u,A)=>{let p=o.shift().digest("base64"),h=new H0(`${A}-${p}${r}`,t);if(h.algorithm&&h.digest){let E=h.algorithm;u[E]||(u[E]=[]),u[E].push(h)}return u},new Dm)}}}var Fvt=new Set(kv.getHashes()),pBe=["md5","whirlpool","sha1","sha224","sha256","sha384","sha512","sha3","sha3-256","sha3-384","sha3-512","sha3_256","sha3_384","sha3_512"].filter(t=>Fvt.has(t));function Rvt(t,e){return pBe.indexOf(t.toLowerCase())>=pBe.indexOf(e.toLowerCase())?t:e}});var GBe=_((Air,qBe)=>{var RDt=cN();function TDt(t){return RDt(t)?void 0:t}qBe.exports=TDt});var YBe=_((fir,jBe)=>{var LDt=Hb(),NDt=x8(),ODt=R8(),MDt=jd(),UDt=md(),_Dt=GBe(),HDt=v_(),qDt=b8(),GDt=1,jDt=2,YDt=4,WDt=HDt(function(t,e){var r={};if(t==null)return r;var o=!1;e=LDt(e,function(n){return n=MDt(n,t),o||(o=n.length>1),n}),UDt(t,qDt(t),r),o&&(r=NDt(r,GDt|jDt|YDt,_Dt));for(var a=e.length;a--;)ODt(r,e[a]);return r});jBe.exports=WDt});Pt();Ye();Pt();var JBe=ve("child_process"),XBe=$e(rd());qt();var AC=new Map([]);var a2={};zt(a2,{BaseCommand:()=>ut,WorkspaceRequiredError:()=>nr,getCli:()=>ehe,getDynamicLibs:()=>$pe,getPluginConfiguration:()=>pC,openWorkspace:()=>fC,pluginCommands:()=>AC,runExit:()=>nk});qt();var ut=class extends nt{constructor(){super(...arguments);this.cwd=ge.String("--cwd",{hidden:!0})}validateAndExecute(){if(typeof this.cwd<"u")throw new it("The --cwd option is ambiguous when used anywhere else than the very first parameter provided in the command line, before even the command path");return super.validateAndExecute()}};Ye();Pt();qt();var nr=class extends it{constructor(e,r){let o=z.relative(e,r),a=z.join(e,Ot.fileName);super(`This command can only be run from within a workspace of your project (${o} isn't a workspace of ${a}).`)}};Ye();Pt();iA();Nl();k1();qt();var TAt=$e(Jn());$a();var $pe=()=>new Map([["@yarnpkg/cli",a2],["@yarnpkg/core",o2],["@yarnpkg/fslib",zw],["@yarnpkg/libzip",x1],["@yarnpkg/parsers",rI],["@yarnpkg/shell",T1],["clipanion",hI],["semver",TAt],["typanion",zo]]);Ye();async function fC(t,e){let{project:r,workspace:o}=await St.find(t,e);if(!o)throw new nr(r.cwd,e);return o}Ye();Pt();iA();Nl();k1();qt();var tPt=$e(Jn());$a();var $8={};zt($8,{AddCommand:()=>Qh,BinCommand:()=>Fh,CacheCleanCommand:()=>Rh,ClipanionCommand:()=>zd,ConfigCommand:()=>Oh,ConfigGetCommand:()=>Th,ConfigSetCommand:()=>Lh,ConfigUnsetCommand:()=>Nh,DedupeCommand:()=>Mh,EntryCommand:()=>mC,ExecCommand:()=>Uh,ExplainCommand:()=>qh,ExplainPeerRequirementsCommand:()=>_h,HelpCommand:()=>Vd,InfoCommand:()=>Gh,LinkCommand:()=>Yh,NodeCommand:()=>Wh,PluginCheckCommand:()=>Kh,PluginImportCommand:()=>Jh,PluginImportSourcesCommand:()=>Xh,PluginListCommand:()=>zh,PluginRemoveCommand:()=>Zh,PluginRuntimeCommand:()=>$h,RebuildCommand:()=>e0,RemoveCommand:()=>t0,RunCommand:()=>r0,RunIndexCommand:()=>Zd,SetResolutionCommand:()=>n0,SetVersionCommand:()=>Hh,SetVersionSourcesCommand:()=>Vh,UnlinkCommand:()=>i0,UpCommand:()=>Vf,VersionCommand:()=>Jd,WhyCommand:()=>s0,WorkspaceCommand:()=>l0,WorkspacesListCommand:()=>a0,YarnCommand:()=>jh,dedupeUtils:()=>pk,default:()=>Sgt,suggestUtils:()=>Xc});var Qde=$e(rd());Ye();Ye();Ye();qt();var H0e=$e(f2());$a();var Xc={};zt(Xc,{Modifier:()=>B8,Strategy:()=>uk,Target:()=>p2,WorkspaceModifier:()=>N0e,applyModifier:()=>ept,extractDescriptorFromPath:()=>v8,extractRangeModifier:()=>O0e,fetchDescriptorFrom:()=>D8,findProjectDescriptors:()=>_0e,getModifier:()=>h2,getSuggestedDescriptors:()=>g2,makeWorkspaceDescriptor:()=>U0e,toWorkspaceModifier:()=>M0e});Ye();Ye();Pt();var I8=$e(Jn()),Zft="workspace:",p2=(o=>(o.REGULAR="dependencies",o.DEVELOPMENT="devDependencies",o.PEER="peerDependencies",o))(p2||{}),B8=(o=>(o.CARET="^",o.TILDE="~",o.EXACT="",o))(B8||{}),N0e=(o=>(o.CARET="^",o.TILDE="~",o.EXACT="*",o))(N0e||{}),uk=(n=>(n.KEEP="keep",n.REUSE="reuse",n.PROJECT="project",n.LATEST="latest",n.CACHE="cache",n))(uk||{});function h2(t,e){return t.exact?"":t.caret?"^":t.tilde?"~":e.configuration.get("defaultSemverRangePrefix")}var $ft=/^([\^~]?)[0-9]+(?:\.[0-9]+){0,2}(?:-\S+)?$/;function O0e(t,{project:e}){let r=t.match($ft);return r?r[1]:e.configuration.get("defaultSemverRangePrefix")}function ept(t,e){let{protocol:r,source:o,params:a,selector:n}=W.parseRange(t.range);return I8.default.valid(n)&&(n=`${e}${t.range}`),W.makeDescriptor(t,W.makeRange({protocol:r,source:o,params:a,selector:n}))}function M0e(t){switch(t){case"^":return"^";case"~":return"~";case"":return"*";default:throw new Error(`Assertion failed: Unknown modifier: "${t}"`)}}function U0e(t,e){return W.makeDescriptor(t.anchoredDescriptor,`${Zft}${M0e(e)}`)}async function _0e(t,{project:e,target:r}){let o=new Map,a=n=>{let u=o.get(n.descriptorHash);return u||o.set(n.descriptorHash,u={descriptor:n,locators:[]}),u};for(let n of e.workspaces)if(r==="peerDependencies"){let u=n.manifest.peerDependencies.get(t.identHash);u!==void 0&&a(u).locators.push(n.anchoredLocator)}else{let u=n.manifest.dependencies.get(t.identHash),A=n.manifest.devDependencies.get(t.identHash);r==="devDependencies"?A!==void 0?a(A).locators.push(n.anchoredLocator):u!==void 0&&a(u).locators.push(n.anchoredLocator):u!==void 0?a(u).locators.push(n.anchoredLocator):A!==void 0&&a(A).locators.push(n.anchoredLocator)}return o}async function v8(t,{cwd:e,workspace:r}){return await tpt(async o=>{z.isAbsolute(t)||(t=z.relative(r.cwd,z.resolve(e,t)),t.match(/^\.{0,2}\//)||(t=`./${t}`));let{project:a}=r,n=await D8(W.makeIdent(null,"archive"),t,{project:r.project,cache:o,workspace:r});if(!n)throw new Error("Assertion failed: The descriptor should have been found");let u=new Qi,A=a.configuration.makeResolver(),p=a.configuration.makeFetcher(),h={checksums:a.storedChecksums,project:a,cache:o,fetcher:p,report:u,resolver:A},E=A.bindDescriptor(n,r.anchoredLocator,h),I=W.convertDescriptorToLocator(E),v=await p.fetch(I,h),x=await Ot.find(v.prefixPath,{baseFs:v.packageFs});if(!x.name)throw new Error("Target path doesn't have a name");return W.makeDescriptor(x.name,t)})}async function g2(t,{project:e,workspace:r,cache:o,target:a,fixed:n,modifier:u,strategies:A,maxResults:p=1/0}){if(!(p>=0))throw new Error(`Invalid maxResults (${p})`);let[h,E]=t.range!=="unknown"?n||kr.validRange(t.range)||!t.range.match(/^[a-z0-9._-]+$/i)?[t.range,"latest"]:["unknown",t.range]:["unknown","latest"];if(h!=="unknown")return{suggestions:[{descriptor:t,name:`Use ${W.prettyDescriptor(e.configuration,t)}`,reason:"(unambiguous explicit request)"}],rejections:[]};let I=typeof r<"u"&&r!==null&&r.manifest[a].get(t.identHash)||null,v=[],x=[],C=async R=>{try{await R()}catch(N){x.push(N)}};for(let R of A){if(v.length>=p)break;switch(R){case"keep":await C(async()=>{I&&v.push({descriptor:I,name:`Keep ${W.prettyDescriptor(e.configuration,I)}`,reason:"(no changes)"})});break;case"reuse":await C(async()=>{for(let{descriptor:N,locators:U}of(await _0e(t,{project:e,target:a})).values()){if(U.length===1&&U[0].locatorHash===r.anchoredLocator.locatorHash&&A.includes("keep"))continue;let V=`(originally used by ${W.prettyLocator(e.configuration,U[0])}`;V+=U.length>1?` and ${U.length-1} other${U.length>2?"s":""})`:")",v.push({descriptor:N,name:`Reuse ${W.prettyDescriptor(e.configuration,N)}`,reason:V})}});break;case"cache":await C(async()=>{for(let N of e.storedDescriptors.values())N.identHash===t.identHash&&v.push({descriptor:N,name:`Reuse ${W.prettyDescriptor(e.configuration,N)}`,reason:"(already used somewhere in the lockfile)"})});break;case"project":await C(async()=>{if(r.manifest.name!==null&&t.identHash===r.manifest.name.identHash)return;let N=e.tryWorkspaceByIdent(t);if(N===null)return;let U=U0e(N,u);v.push({descriptor:U,name:`Attach ${W.prettyDescriptor(e.configuration,U)}`,reason:`(local workspace at ${de.pretty(e.configuration,N.relativeCwd,de.Type.PATH)})`})});break;case"latest":{let N=e.configuration.get("enableNetwork"),U=e.configuration.get("enableOfflineMode");await C(async()=>{if(a==="peerDependencies")v.push({descriptor:W.makeDescriptor(t,"*"),name:"Use *",reason:"(catch-all peer dependency pattern)"});else if(!N&&!U)v.push({descriptor:null,name:"Resolve from latest",reason:de.pretty(e.configuration,"(unavailable because enableNetwork is toggled off)","grey")});else{let V=await D8(t,E,{project:e,cache:o,workspace:r,modifier:u});V&&v.push({descriptor:V,name:`Use ${W.prettyDescriptor(e.configuration,V)}`,reason:`(resolved from ${U?"the cache":"latest"})`})}})}break}}return{suggestions:v.slice(0,p),rejections:x.slice(0,p)}}async function D8(t,e,{project:r,cache:o,workspace:a,preserveModifier:n=!0,modifier:u}){let A=r.configuration.normalizeDependency(W.makeDescriptor(t,e)),p=new Qi,h=r.configuration.makeFetcher(),E=r.configuration.makeResolver(),I={project:r,fetcher:h,cache:o,checksums:r.storedChecksums,report:p,cacheOptions:{skipIntegrityCheck:!0}},v={...I,resolver:E,fetchOptions:I},x=E.bindDescriptor(A,a.anchoredLocator,v),C=await E.getCandidates(x,{},v);if(C.length===0)return null;let R=C[0],{protocol:N,source:U,params:V,selector:te}=W.parseRange(W.convertToManifestRange(R.reference));if(N===r.configuration.get("defaultProtocol")&&(N=null),I8.default.valid(te)){let ae=te;if(typeof u<"u")te=u+te;else if(n!==!1){let me=typeof n=="string"?n:A.range;te=O0e(me,{project:r})+te}let fe=W.makeDescriptor(R,W.makeRange({protocol:N,source:U,params:V,selector:te}));(await E.getCandidates(r.configuration.normalizeDependency(fe),{},v)).length!==1&&(te=ae)}return W.makeDescriptor(R,W.makeRange({protocol:N,source:U,params:V,selector:te}))}async function tpt(t){return await oe.mktempPromise(async e=>{let r=Ke.create(e);return r.useWithSource(e,{enableMirror:!1,compressionLevel:0},e,{overwrite:!0}),await t(new Nr(e,{configuration:r,check:!1,immutable:!1}))})}var Qh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.fixed=ge.Boolean("-F,--fixed",!1,{description:"Store dependency tags as-is instead of resolving them"});this.exact=ge.Boolean("-E,--exact",!1,{description:"Don't use any semver modifier on the resolved range"});this.tilde=ge.Boolean("-T,--tilde",!1,{description:"Use the `~` semver modifier on the resolved range"});this.caret=ge.Boolean("-C,--caret",!1,{description:"Use the `^` semver modifier on the resolved range"});this.dev=ge.Boolean("-D,--dev",!1,{description:"Add a package as a dev dependency"});this.peer=ge.Boolean("-P,--peer",!1,{description:"Add a package as a peer dependency"});this.optional=ge.Boolean("-O,--optional",!1,{description:"Add / upgrade a package to an optional regular / peer dependency"});this.preferDev=ge.Boolean("--prefer-dev",!1,{description:"Add / upgrade a package to a dev dependency"});this.interactive=ge.Boolean("-i,--interactive",{description:"Reuse the specified package from other workspaces in the project"});this.cached=ge.Boolean("--cached",!1,{description:"Reuse the highest version already used somewhere within the project"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:Ks(hl)});this.silent=ge.Boolean("--silent",{hidden:!0});this.packages=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=this.fixed,A=this.interactive??r.get("preferInteractive"),p=A||r.get("preferReuse"),h=h2(this,o),E=[p?"reuse":void 0,"project",this.cached?"cache":void 0,"latest"].filter(U=>typeof U<"u"),I=A?1/0:1,v=await Promise.all(this.packages.map(async U=>{let V=U.match(/^\.{0,2}\//)?await v8(U,{cwd:this.context.cwd,workspace:a}):W.tryParseDescriptor(U),te=U.match(/^(https?:|git@github)/);if(te)throw new it(`It seems you are trying to add a package using a ${de.pretty(r,`${te[0]}...`,de.Type.RANGE)} url; we now require package names to be explicitly specified.
-Try running the command again with the package name prefixed: ${de.pretty(r,"yarn add",de.Type.CODE)} ${de.pretty(r,W.makeDescriptor(W.makeIdent(null,"my-package"),`${te[0]}...`),de.Type.DESCRIPTOR)}`);if(!V)throw new it(`The ${de.pretty(r,U,de.Type.CODE)} string didn't match the required format (package-name@range). Did you perhaps forget to explicitly reference the package name?`);let ae=rpt(a,V,{dev:this.dev,peer:this.peer,preferDev:this.preferDev,optional:this.optional});return await Promise.all(ae.map(async ue=>{let me=await g2(V,{project:o,workspace:a,cache:n,fixed:u,target:ue,modifier:h,strategies:E,maxResults:I});return{request:V,suggestedDescriptors:me,target:ue}}))})).then(U=>U.flat()),x=await fA.start({configuration:r,stdout:this.context.stdout,suggestInstall:!1},async U=>{for(let{request:V,suggestedDescriptors:{suggestions:te,rejections:ae}}of v)if(te.filter(ue=>ue.descriptor!==null).length===0){let[ue]=ae;if(typeof ue>"u")throw new Error("Assertion failed: Expected an error to have been set");o.configuration.get("enableNetwork")?U.reportError(27,`${W.prettyDescriptor(r,V)} can't be resolved to a satisfying range`):U.reportError(27,`${W.prettyDescriptor(r,V)} can't be resolved to a satisfying range (note: network resolution has been disabled)`),U.reportSeparator(),U.reportExceptionOnce(ue)}});if(x.hasErrors())return x.exitCode();let C=!1,R=[],N=[];for(let{suggestedDescriptors:{suggestions:U},target:V}of v){let te,ae=U.filter(he=>he.descriptor!==null),fe=ae[0].descriptor,ue=ae.every(he=>W.areDescriptorsEqual(he.descriptor,fe));ae.length===1||ue?te=fe:(C=!0,{answer:te}=await(0,H0e.prompt)({type:"select",name:"answer",message:"Which range do you want to use?",choices:U.map(({descriptor:he,name:Be,reason:we})=>he?{name:Be,hint:we,descriptor:he}:{name:Be,hint:we,disabled:!0}),onCancel:()=>process.exit(130),result(he){return this.find(he,"descriptor")},stdin:this.context.stdin,stdout:this.context.stdout}));let me=a.manifest[V].get(te.identHash);(typeof me>"u"||me.descriptorHash!==te.descriptorHash)&&(a.manifest[V].set(te.identHash,te),this.optional&&(V==="dependencies"?a.manifest.ensureDependencyMeta({...te,range:"unknown"}).optional=!0:V==="peerDependencies"&&(a.manifest.ensurePeerDependencyMeta({...te,range:"unknown"}).optional=!0)),typeof me>"u"?R.push([a,V,te,E]):N.push([a,V,me,te]))}return await r.triggerMultipleHooks(U=>U.afterWorkspaceDependencyAddition,R),await r.triggerMultipleHooks(U=>U.afterWorkspaceDependencyReplacement,N),C&&this.context.stdout.write(`
-`),await o.installWithNewReport({json:this.json,stdout:this.context.stdout,quiet:this.context.quiet},{cache:n,mode:this.mode})}};Qh.paths=[["add"]],Qh.usage=nt.Usage({description:"add dependencies to the project",details:"\n This command adds a package to the package.json for the nearest workspace.\n\n - If it didn't exist before, the package will by default be added to the regular `dependencies` field, but this behavior can be overriden thanks to the `-D,--dev` flag (which will cause the dependency to be added to the `devDependencies` field instead) and the `-P,--peer` flag (which will do the same but for `peerDependencies`).\n\n - If the package was already listed in your dependencies, it will by default be upgraded whether it's part of your `dependencies` or `devDependencies` (it won't ever update `peerDependencies`, though).\n\n - If set, the `--prefer-dev` flag will operate as a more flexible `-D,--dev` in that it will add the package to your `devDependencies` if it isn't already listed in either `dependencies` or `devDependencies`, but it will also happily upgrade your `dependencies` if that's what you already use (whereas `-D,--dev` would throw an exception).\n\n - If set, the `-O,--optional` flag will add the package to the `optionalDependencies` field and, in combination with the `-P,--peer` flag, it will add the package as an optional peer dependency. If the package was already listed in your `dependencies`, it will be upgraded to `optionalDependencies`. If the package was already listed in your `peerDependencies`, in combination with the `-P,--peer` flag, it will be upgraded to an optional peer dependency: `\"peerDependenciesMeta\": { \"<package>\": { \"optional\": true } }`\n\n - If the added package doesn't specify a range at all its `latest` tag will be resolved and the returned version will be used to generate a new semver range (using the `^` modifier by default unless otherwise configured via the `defaultSemverRangePrefix` configuration, or the `~` modifier if `-T,--tilde` is specified, or no modifier at all if `-E,--exact` is specified). Two exceptions to this rule: the first one is that if the package is a workspace then its local version will be used, and the second one is that if you use `-P,--peer` the default range will be `*` and won't be resolved at all.\n\n - If the added package specifies a range (such as `^1.0.0`, `latest`, or `rc`), Yarn will add this range as-is in the resulting package.json entry (in particular, tags such as `rc` will be encoded as-is rather than being converted into a semver range).\n\n If the `--cached` option is used, Yarn will preferably reuse the highest version already used somewhere within the project, even if through a transitive dependency.\n\n If the `-i,--interactive` option is used (or if the `preferInteractive` settings is toggled on) the command will first try to check whether other workspaces in the project use the specified package and, if so, will offer to reuse them.\n\n If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n\n For a compilation of all the supported protocols, please consult the dedicated page from our website: https://yarnpkg.com/protocols.\n ",examples:[["Add a regular package to the current workspace","$0 add lodash"],["Add a specific version for a package to the current workspace","$0 add lodash@1.2.3"],["Add a package from a GitHub repository (the master branch) to the current workspace using a URL","$0 add lodash@https://github.com/lodash/lodash"],["Add a package from a GitHub repository (the master branch) to the current workspace using the GitHub protocol","$0 add lodash@github:lodash/lodash"],["Add a package from a GitHub repository (the master branch) to the current workspace using the GitHub protocol (shorthand)","$0 add lodash@lodash/lodash"],["Add a package from a specific branch of a GitHub repository to the current workspace using the GitHub protocol (shorthand)","$0 add lodash-es@lodash/lodash#es"]]});function rpt(t,e,{dev:r,peer:o,preferDev:a,optional:n}){let u=t.manifest["dependencies"].has(e.identHash),A=t.manifest["devDependencies"].has(e.identHash),p=t.manifest["peerDependencies"].has(e.identHash);if((r||o)&&u)throw new it(`Package "${W.prettyIdent(t.project.configuration,e)}" is already listed as a regular dependency - remove the -D,-P flags or remove it from your dependencies first`);if(!r&&!o&&p)throw new it(`Package "${W.prettyIdent(t.project.configuration,e)}" is already listed as a peer dependency - use either of -D or -P, or remove it from your peer dependencies first`);if(n&&A)throw new it(`Package "${W.prettyIdent(t.project.configuration,e)}" is already listed as a dev dependency - remove the -O flag or remove it from your dev dependencies first`);if(n&&!o&&p)throw new it(`Package "${W.prettyIdent(t.project.configuration,e)}" is already listed as a peer dependency - remove the -O flag or add the -P flag or remove it from your peer dependencies first`);if((r||a)&&n)throw new it(`Package "${W.prettyIdent(t.project.configuration,e)}" cannot simultaneously be a dev dependency and an optional dependency`);let h=[];return o&&h.push("peerDependencies"),(r||a)&&h.push("devDependencies"),n&&h.push("dependencies"),h.length>0?h:A?["devDependencies"]:p?["peerDependencies"]:["dependencies"]}Ye();Ye();qt();var Fh=class extends ut{constructor(){super(...arguments);this.verbose=ge.Boolean("-v,--verbose",!1,{description:"Print both the binary name and the locator of the package that provides the binary"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.name=ge.String({required:!1})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,locator:a}=await St.find(r,this.context.cwd);if(await o.restoreInstallState(),this.name){let A=(await un.getPackageAccessibleBinaries(a,{project:o})).get(this.name);if(!A)throw new it(`Couldn't find a binary named "${this.name}" for package "${W.prettyLocator(r,a)}"`);let[,p]=A;return this.context.stdout.write(`${p}
-`),0}return(await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout},async u=>{let A=await un.getPackageAccessibleBinaries(a,{project:o}),h=Array.from(A.keys()).reduce((E,I)=>Math.max(E,I.length),0);for(let[E,[I,v]]of A)u.reportJson({name:E,source:W.stringifyIdent(I),path:v});if(this.verbose)for(let[E,[I]]of A)u.reportInfo(null,`${E.padEnd(h," ")} ${W.prettyLocator(r,I)}`);else for(let E of A.keys())u.reportInfo(null,E)})).exitCode()}};Fh.paths=[["bin"]],Fh.usage=nt.Usage({description:"get the path to a binary script",details:`
- When used without arguments, this command will print the list of all the binaries available in the current workspace. Adding the \`-v,--verbose\` flag will cause the output to contain both the binary name and the locator of the package that provides the binary.
-
- When an argument is specified, this command will just print the path to the binary on the standard output and exit. Note that the reported path may be stored within a zip archive.
- `,examples:[["List all the available binaries","$0 bin"],["Print the path to a specific binary","$0 bin eslint"]]});Ye();Pt();qt();var Rh=class extends ut{constructor(){super(...arguments);this.mirror=ge.Boolean("--mirror",!1,{description:"Remove the global cache files instead of the local cache files"});this.all=ge.Boolean("--all",!1,{description:"Remove both the global cache files and the local cache files of the current project"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=await Nr.find(r);return(await Lt.start({configuration:r,stdout:this.context.stdout},async()=>{let n=(this.all||this.mirror)&&o.mirrorCwd!==null,u=!this.mirror;n&&(await oe.removePromise(o.mirrorCwd),await r.triggerHook(A=>A.cleanGlobalArtifacts,r)),u&&await oe.removePromise(o.cwd)})).exitCode()}};Rh.paths=[["cache","clean"],["cache","clear"]],Rh.usage=nt.Usage({description:"remove the shared cache files",details:`
- This command will remove all the files from the cache.
- `,examples:[["Remove all the local archives","$0 cache clean"],["Remove all the archives stored in the ~/.yarn directory","$0 cache clean --mirror"]]});Ye();qt();var G0e=$e(d2()),P8=ve("util"),Th=class extends ut{constructor(){super(...arguments);this.why=ge.Boolean("--why",!1,{description:"Print the explanation for why a setting has its value"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.unsafe=ge.Boolean("--no-redacted",!1,{description:"Don't redact secrets (such as tokens) from the output"});this.name=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=this.name.replace(/[.[].*$/,""),a=this.name.replace(/^[^.[]*/,"");if(typeof r.settings.get(o)>"u")throw new it(`Couldn't find a configuration settings named "${o}"`);let u=r.getSpecial(o,{hideSecrets:!this.unsafe,getNativePaths:!0}),A=_e.convertMapsToIndexableObjects(u),p=a?(0,G0e.default)(A,a):A,h=await Lt.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async E=>{E.reportJson(p)});if(!this.json){if(typeof p=="string")return this.context.stdout.write(`${p}
-`),h.exitCode();P8.inspect.styles.name="cyan",this.context.stdout.write(`${(0,P8.inspect)(p,{depth:1/0,colors:r.get("enableColors"),compact:!1})}
-`)}return h.exitCode()}};Th.paths=[["config","get"]],Th.usage=nt.Usage({description:"read a configuration settings",details:`
- This command will print a configuration setting.
-
- Secrets (such as tokens) will be redacted from the output by default. If this behavior isn't desired, set the \`--no-redacted\` to get the untransformed value.
- `,examples:[["Print a simple configuration setting","yarn config get yarnPath"],["Print a complex configuration setting","yarn config get packageExtensions"],["Print a nested field from the configuration",`yarn config get 'npmScopes["my-company"].npmRegistryServer'`],["Print a token from the configuration","yarn config get npmAuthToken --no-redacted"],["Print a configuration setting as JSON","yarn config get packageExtensions --json"]]});Ye();qt();var Rge=$e(k8()),Tge=$e(d2()),Lge=$e(Q8()),F8=ve("util"),Lh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Set complex configuration settings to JSON values"});this.home=ge.Boolean("-H,--home",!1,{description:"Update the home configuration instead of the project configuration"});this.name=ge.String();this.value=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=()=>{if(!r.projectCwd)throw new it("This command must be run from within a project folder");return r.projectCwd},a=this.name.replace(/[.[].*$/,""),n=this.name.replace(/^[^.[]*\.?/,"");if(typeof r.settings.get(a)>"u")throw new it(`Couldn't find a configuration settings named "${a}"`);if(a==="enableStrictSettings")throw new it("This setting only affects the file it's in, and thus cannot be set from the CLI");let A=this.json?JSON.parse(this.value):this.value;await(this.home?C=>Ke.updateHomeConfiguration(C):C=>Ke.updateConfiguration(o(),C))(C=>{if(n){let R=(0,Rge.default)(C);return(0,Lge.default)(R,this.name,A),R}else return{...C,[a]:A}});let E=(await Ke.find(this.context.cwd,this.context.plugins)).getSpecial(a,{hideSecrets:!0,getNativePaths:!0}),I=_e.convertMapsToIndexableObjects(E),v=n?(0,Tge.default)(I,n):I;return(await Lt.start({configuration:r,includeFooter:!1,stdout:this.context.stdout},async C=>{F8.inspect.styles.name="cyan",C.reportInfo(0,`Successfully set ${this.name} to ${(0,F8.inspect)(v,{depth:1/0,colors:r.get("enableColors"),compact:!1})}`)})).exitCode()}};Lh.paths=[["config","set"]],Lh.usage=nt.Usage({description:"change a configuration settings",details:`
- This command will set a configuration setting.
-
- When used without the \`--json\` flag, it can only set a simple configuration setting (a string, a number, or a boolean).
-
- When used with the \`--json\` flag, it can set both simple and complex configuration settings, including Arrays and Objects.
- `,examples:[["Set a simple configuration setting (a string, a number, or a boolean)","yarn config set initScope myScope"],["Set a simple configuration setting (a string, a number, or a boolean) using the `--json` flag",'yarn config set initScope --json \\"myScope\\"'],["Set a complex configuration setting (an Array) using the `--json` flag",`yarn config set unsafeHttpWhitelist --json '["*.example.com", "example.com"]'`],["Set a complex configuration setting (an Object) using the `--json` flag",`yarn config set packageExtensions --json '{ "@babel/parser@*": { "dependencies": { "@babel/types": "*" } } }'`],["Set a nested configuration setting",'yarn config set npmScopes.company.npmRegistryServer "https://npm.example.com"'],["Set a nested configuration setting using indexed access for non-simple keys",`yarn config set 'npmRegistries["//npm.example.com"].npmAuthToken' "ffffffff-ffff-ffff-ffff-ffffffffffff"`]]});Ye();qt();var Wge=$e(k8()),Kge=$e(Uge()),zge=$e(T8()),Nh=class extends ut{constructor(){super(...arguments);this.home=ge.Boolean("-H,--home",!1,{description:"Update the home configuration instead of the project configuration"});this.name=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=()=>{if(!r.projectCwd)throw new it("This command must be run from within a project folder");return r.projectCwd},a=this.name.replace(/[.[].*$/,""),n=this.name.replace(/^[^.[]*\.?/,"");if(typeof r.settings.get(a)>"u")throw new it(`Couldn't find a configuration settings named "${a}"`);let A=this.home?h=>Ke.updateHomeConfiguration(h):h=>Ke.updateConfiguration(o(),h);return(await Lt.start({configuration:r,includeFooter:!1,stdout:this.context.stdout},async h=>{let E=!1;await A(I=>{if(!(0,Kge.default)(I,this.name))return h.reportWarning(0,`Configuration doesn't contain setting ${this.name}; there is nothing to unset`),E=!0,I;let v=n?(0,Wge.default)(I):{...I};return(0,zge.default)(v,this.name),v}),E||h.reportInfo(0,`Successfully unset ${this.name}`)})).exitCode()}};Nh.paths=[["config","unset"]],Nh.usage=nt.Usage({description:"unset a configuration setting",details:`
- This command will unset a configuration setting.
- `,examples:[["Unset a simple configuration setting","yarn config unset initScope"],["Unset a complex configuration setting","yarn config unset packageExtensions"],["Unset a nested configuration setting","yarn config unset npmScopes.company.npmRegistryServer"]]});Ye();Pt();qt();var fk=ve("util"),Oh=class extends ut{constructor(){super(...arguments);this.noDefaults=ge.Boolean("--no-defaults",!1,{description:"Omit the default values from the display"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.verbose=ge.Boolean("-v,--verbose",{hidden:!0});this.why=ge.Boolean("--why",{hidden:!0});this.names=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins,{strict:!1}),o=await NE({configuration:r,stdout:this.context.stdout,forceError:this.json},[{option:this.verbose,message:"The --verbose option is deprecated, the settings' descriptions are now always displayed"},{option:this.why,message:"The --why option is deprecated, the settings' sources are now always displayed"}]);if(o!==null)return o;let a=this.names.length>0?[...new Set(this.names)].sort():[...r.settings.keys()].sort(),n,u=await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async A=>{if(r.invalid.size>0&&!this.json){for(let[p,h]of r.invalid)A.reportError(34,`Invalid configuration key "${p}" in ${h}`);A.reportSeparator()}if(this.json)for(let p of a){let h=r.settings.get(p);typeof h>"u"&&A.reportError(34,`No configuration key named "${p}"`);let E=r.getSpecial(p,{hideSecrets:!0,getNativePaths:!0}),I=r.sources.get(p)??"<default>",v=I&&I[0]!=="<"?le.fromPortablePath(I):I;A.reportJson({key:p,effective:E,source:v,...h})}else{let p={breakLength:1/0,colors:r.get("enableColors"),maxArrayLength:2},h={},E={children:h};for(let I of a){if(this.noDefaults&&!r.sources.has(I))continue;let v=r.settings.get(I),x=r.sources.get(I)??"<default>",C=r.getSpecial(I,{hideSecrets:!0,getNativePaths:!0}),R={Description:{label:"Description",value:de.tuple(de.Type.MARKDOWN,{text:v.description,format:this.cli.format(),paragraphs:!1})},Source:{label:"Source",value:de.tuple(x[0]==="<"?de.Type.CODE:de.Type.PATH,x)}};h[I]={value:de.tuple(de.Type.CODE,I),children:R};let N=(U,V)=>{for(let[te,ae]of V)if(ae instanceof Map){let fe={};U[te]={children:fe},N(fe,ae)}else U[te]={label:te,value:de.tuple(de.Type.NO_HINT,(0,fk.inspect)(ae,p))}};C instanceof Map?N(R,C):R.Value={label:"Value",value:de.tuple(de.Type.NO_HINT,(0,fk.inspect)(C,p))}}a.length!==1&&(n=void 0),$s.emitTree(E,{configuration:r,json:this.json,stdout:this.context.stdout,separators:2})}});if(!this.json&&typeof n<"u"){let A=a[0],p=(0,fk.inspect)(r.getSpecial(A,{hideSecrets:!0,getNativePaths:!0}),{colors:r.get("enableColors")});this.context.stdout.write(`
-`),this.context.stdout.write(`${p}
-`)}return u.exitCode()}};Oh.paths=[["config"]],Oh.usage=nt.Usage({description:"display the current configuration",details:`
- This command prints the current active configuration settings.
- `,examples:[["Print the active configuration settings","$0 config"]]});Ye();qt();$a();var pk={};zt(pk,{Strategy:()=>m2,acceptedStrategies:()=>M0t,dedupe:()=>L8});Ye();Ye();var Vge=$e(Zo()),m2=(e=>(e.HIGHEST="highest",e))(m2||{}),M0t=new Set(Object.values(m2)),U0t={highest:async(t,e,{resolver:r,fetcher:o,resolveOptions:a,fetchOptions:n})=>{let u=new Map;for(let[p,h]of t.storedResolutions){let E=t.storedDescriptors.get(p);if(typeof E>"u")throw new Error(`Assertion failed: The descriptor (${p}) should have been registered`);_e.getSetWithDefault(u,E.identHash).add(h)}let A=new Map(_e.mapAndFilter(t.storedDescriptors.values(),p=>W.isVirtualDescriptor(p)?_e.mapAndFilter.skip:[p.descriptorHash,_e.makeDeferred()]));for(let p of t.storedDescriptors.values()){let h=A.get(p.descriptorHash);if(typeof h>"u")throw new Error(`Assertion failed: The descriptor (${p.descriptorHash}) should have been registered`);let E=t.storedResolutions.get(p.descriptorHash);if(typeof E>"u")throw new Error(`Assertion failed: The resolution (${p.descriptorHash}) should have been registered`);let I=t.originalPackages.get(E);if(typeof I>"u")throw new Error(`Assertion failed: The package (${E}) should have been registered`);Promise.resolve().then(async()=>{let v=r.getResolutionDependencies(p,a),x=Object.fromEntries(await _e.allSettledSafe(Object.entries(v).map(async([te,ae])=>{let fe=A.get(ae.descriptorHash);if(typeof fe>"u")throw new Error(`Assertion failed: The descriptor (${ae.descriptorHash}) should have been registered`);let ue=await fe.promise;if(!ue)throw new Error("Assertion failed: Expected the dependency to have been through the dedupe process itself");return[te,ue.updatedPackage]})));if(e.length&&!Vge.default.isMatch(W.stringifyIdent(p),e)||!r.shouldPersistResolution(I,a))return I;let C=u.get(p.identHash);if(typeof C>"u")throw new Error(`Assertion failed: The resolutions (${p.identHash}) should have been registered`);if(C.size===1)return I;let R=[...C].map(te=>{let ae=t.originalPackages.get(te);if(typeof ae>"u")throw new Error(`Assertion failed: The package (${te}) should have been registered`);return ae}),N=await r.getSatisfying(p,x,R,a),U=N.locators?.[0];if(typeof U>"u"||!N.sorted)return I;let V=t.originalPackages.get(U.locatorHash);if(typeof V>"u")throw new Error(`Assertion failed: The package (${U.locatorHash}) should have been registered`);return V}).then(async v=>{let x=await t.preparePackage(v,{resolver:r,resolveOptions:a});h.resolve({descriptor:p,currentPackage:I,updatedPackage:v,resolvedPackage:x})}).catch(v=>{h.reject(v)})}return[...A.values()].map(p=>p.promise)}};async function L8(t,{strategy:e,patterns:r,cache:o,report:a}){let{configuration:n}=t,u=new Qi,A=n.makeResolver(),p=n.makeFetcher(),h={cache:o,checksums:t.storedChecksums,fetcher:p,project:t,report:u,cacheOptions:{skipIntegrityCheck:!0}},E={project:t,resolver:A,report:u,fetchOptions:h};return await a.startTimerPromise("Deduplication step",async()=>{let I=U0t[e],v=await I(t,r,{resolver:A,resolveOptions:E,fetcher:p,fetchOptions:h}),x=Xs.progressViaCounter(v.length);await a.reportProgress(x);let C=0;await Promise.all(v.map(U=>U.then(V=>{if(V===null||V.currentPackage.locatorHash===V.updatedPackage.locatorHash)return;C++;let{descriptor:te,currentPackage:ae,updatedPackage:fe}=V;a.reportInfo(0,`${W.prettyDescriptor(n,te)} can be deduped from ${W.prettyLocator(n,ae)} to ${W.prettyLocator(n,fe)}`),a.reportJson({descriptor:W.stringifyDescriptor(te),currentResolution:W.stringifyLocator(ae),updatedResolution:W.stringifyLocator(fe)}),t.storedResolutions.set(te.descriptorHash,fe.locatorHash)}).finally(()=>x.tick())));let R;switch(C){case 0:R="No packages";break;case 1:R="One package";break;default:R=`${C} packages`}let N=de.pretty(n,e,de.Type.CODE);return a.reportInfo(0,`${R} can be deduped using the ${N} strategy`),C})}var Mh=class extends ut{constructor(){super(...arguments);this.strategy=ge.String("-s,--strategy","highest",{description:"The strategy to use when deduping dependencies",validator:Ks(m2)});this.check=ge.Boolean("-c,--check",!1,{description:"Exit with exit code 1 when duplicates are found, without persisting the dependency tree"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:Ks(hl)});this.patterns=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),a=await Nr.find(r);await o.restoreInstallState({restoreResolutions:!1});let n=0,u=await Lt.start({configuration:r,includeFooter:!1,stdout:this.context.stdout,json:this.json},async A=>{n=await L8(o,{strategy:this.strategy,patterns:this.patterns,cache:a,report:A})});return u.hasErrors()?u.exitCode():this.check?n?1:0:await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:a,mode:this.mode})}};Mh.paths=[["dedupe"]],Mh.usage=nt.Usage({description:"deduplicate dependencies with overlapping ranges",details:"\n Duplicates are defined as descriptors with overlapping ranges being resolved and locked to different locators. They are a natural consequence of Yarn's deterministic installs, but they can sometimes pile up and unnecessarily increase the size of your project.\n\n This command dedupes dependencies in the current project using different strategies (only one is implemented at the moment):\n\n - `highest`: Reuses (where possible) the locators with the highest versions. This means that dependencies can only be upgraded, never downgraded. It's also guaranteed that it never takes more than a single pass to dedupe the entire dependency tree.\n\n **Note:** Even though it never produces a wrong dependency tree, this command should be used with caution, as it modifies the dependency tree, which can sometimes cause problems when packages don't strictly follow semver recommendations. Because of this, it is recommended to also review the changes manually.\n\n If set, the `-c,--check` flag will only report the found duplicates, without persisting the modified dependency tree. If changes are found, the command will exit with a non-zero exit code, making it suitable for CI purposes.\n\n If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n\n This command accepts glob patterns as arguments (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n\n ### In-depth explanation:\n\n Yarn doesn't deduplicate dependencies by default, otherwise installs wouldn't be deterministic and the lockfile would be useless. What it actually does is that it tries to not duplicate dependencies in the first place.\n\n **Example:** If `foo@^2.3.4` (a dependency of a dependency) has already been resolved to `foo@2.3.4`, running `yarn add foo@*`will cause Yarn to reuse `foo@2.3.4`, even if the latest `foo` is actually `foo@2.10.14`, thus preventing unnecessary duplication.\n\n Duplication happens when Yarn can't unlock dependencies that have already been locked inside the lockfile.\n\n **Example:** If `foo@^2.3.4` (a dependency of a dependency) has already been resolved to `foo@2.3.4`, running `yarn add foo@2.10.14` will cause Yarn to install `foo@2.10.14` because the existing resolution doesn't satisfy the range `2.10.14`. This behavior can lead to (sometimes) unwanted duplication, since now the lockfile contains 2 separate resolutions for the 2 `foo` descriptors, even though they have overlapping ranges, which means that the lockfile can be simplified so that both descriptors resolve to `foo@2.10.14`.\n ",examples:[["Dedupe all packages","$0 dedupe"],["Dedupe all packages using a specific strategy","$0 dedupe --strategy highest"],["Dedupe a specific package","$0 dedupe lodash"],["Dedupe all packages with the `@babel/*` scope","$0 dedupe '@babel/*'"],["Check for duplicates (can be used as a CI step)","$0 dedupe --check"]]});Ye();qt();var zd=class extends ut{async execute(){let{plugins:e}=await Ke.find(this.context.cwd,this.context.plugins),r=[];for(let u of e){let{commands:A}=u[1];if(A){let h=as.from(A).definitions();r.push([u[0],h])}}let o=this.cli.definitions(),a=(u,A)=>u.split(" ").slice(1).join()===A.split(" ").slice(1).join(),n=Jge()["@yarnpkg/builder"].bundles.standard;for(let u of r){let A=u[1];for(let p of A)o.find(h=>a(h.path,p.path)).plugin={name:u[0],isDefault:n.includes(u[0])}}this.context.stdout.write(`${JSON.stringify(o,null,2)}
-`)}};zd.paths=[["--clipanion=definitions"]];var Vd=class extends ut{async execute(){this.context.stdout.write(this.cli.usage(null))}};Vd.paths=[["help"],["--help"],["-h"]];Ye();Pt();qt();var mC=class extends ut{constructor(){super(...arguments);this.leadingArgument=ge.String();this.args=ge.Proxy()}async execute(){if(this.leadingArgument.match(/[\\/]/)&&!W.tryParseIdent(this.leadingArgument)){let r=z.resolve(this.context.cwd,le.toPortablePath(this.leadingArgument));return await this.cli.run(this.args,{cwd:r})}else return await this.cli.run(["run",this.leadingArgument,...this.args])}};Ye();var Jd=class extends ut{async execute(){this.context.stdout.write(`${rn||"<unknown>"}
-`)}};Jd.paths=[["-v"],["--version"]];Ye();Ye();qt();var Uh=class extends ut{constructor(){super(...arguments);this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,locator:a}=await St.find(r,this.context.cwd);return await o.restoreInstallState(),await un.executePackageShellcode(a,this.commandName,this.args,{cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,project:o})}};Uh.paths=[["exec"]],Uh.usage=nt.Usage({description:"execute a shell script",details:`
- This command simply executes a shell script within the context of the root directory of the active workspace using the portable shell.
-
- It also makes sure to call it in a way that's compatible with the current project (for example, on PnP projects the environment will be setup in such a way that PnP will be correctly injected into the environment).
- `,examples:[["Execute a single shell command","$0 exec echo Hello World"],["Execute a shell script",'$0 exec "tsc & babel src --out-dir lib"']]});Ye();qt();$a();var _h=class extends ut{constructor(){super(...arguments);this.hash=ge.String({validator:oP(Cy(),[oI(/^p[0-9a-f]{5}$/)])})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);return await o.restoreInstallState({restoreResolutions:!1}),await o.applyLightResolution(),await H0t(this.hash,o,{stdout:this.context.stdout})}};_h.paths=[["explain","peer-requirements"]],_h.usage=nt.Usage({description:"explain a set of peer requirements",details:`
- A set of peer requirements represents all peer requirements that a dependent must satisfy when providing a given peer request to a requester and its descendants.
-
- When the hash argument is specified, this command prints a detailed explanation of all requirements of the set corresponding to the hash and whether they're satisfied or not.
-
- When used without arguments, this command lists all sets of peer requirements and the corresponding hash that can be used to get detailed information about a given set.
-
- **Note:** A hash is a six-letter p-prefixed code that can be obtained from peer dependency warnings or from the list of all peer requirements (\`yarn explain peer-requirements\`).
- `,examples:[["Explain the corresponding set of peer requirements for a hash","$0 explain peer-requirements p1a4ed"],["List all sets of peer requirements","$0 explain peer-requirements"]]});async function H0t(t,e,r){let o=e.peerWarnings.find(n=>n.hash===t);if(typeof o>"u")throw new Error(`No peerDependency requirements found for hash: "${t}"`);return(await Lt.start({configuration:e.configuration,stdout:r.stdout,includeFooter:!1,includePrefix:!1},async n=>{let u=de.mark(e.configuration);switch(o.type){case 2:{n.reportInfo(0,`We have a problem with ${de.pretty(e.configuration,o.requested,de.Type.IDENT)}, which is provided with version ${W.prettyReference(e.configuration,o.version)}.`),n.reportInfo(0,"It is needed by the following direct dependencies of workspaces in your project:"),n.reportSeparator();for(let h of o.requesters.values()){let E=e.storedPackages.get(h.locatorHash);if(!E)throw new Error("Assertion failed: Expected the package to be registered");let I=E?.peerDependencies.get(o.requested.identHash);if(!I)throw new Error("Assertion failed: Expected the package to list the peer dependency");let v=kr.satisfiesWithPrereleases(o.version,I.range)?u.Check:u.Cross;n.reportInfo(null,` ${v} ${W.prettyLocator(e.configuration,h)} (via ${W.prettyRange(e.configuration,I.range)})`)}let A=[...o.links.values()].filter(h=>!o.requesters.has(h.locatorHash));if(A.length>0){n.reportSeparator(),n.reportInfo(0,`However, those packages themselves have more dependencies listing ${W.prettyIdent(e.configuration,o.requested)} as peer dependency:`),n.reportSeparator();for(let h of A){let E=e.storedPackages.get(h.locatorHash);if(!E)throw new Error("Assertion failed: Expected the package to be registered");let I=E?.peerDependencies.get(o.requested.identHash);if(!I)throw new Error("Assertion failed: Expected the package to list the peer dependency");let v=kr.satisfiesWithPrereleases(o.version,I.range)?u.Check:u.Cross;n.reportInfo(null,` ${v} ${W.prettyLocator(e.configuration,h)} (via ${W.prettyRange(e.configuration,I.range)})`)}}let p=Array.from(o.links.values(),h=>{let E=e.storedPackages.get(h.locatorHash);if(typeof E>"u")throw new Error("Assertion failed: Expected the package to be registered");let I=E.peerDependencies.get(o.requested.identHash);if(typeof I>"u")throw new Error("Assertion failed: Expected the ident to be registered");return I.range});if(p.length>1){let h=kr.simplifyRanges(p);n.reportSeparator(),h===null?(n.reportInfo(0,"Unfortunately, put together, we found no single range that can satisfy all those peer requirements."),n.reportInfo(0,`Your best option may be to try to upgrade some dependencies with ${de.pretty(e.configuration,"yarn up",de.Type.CODE)}, or silence the warning via ${de.pretty(e.configuration,"logFilters",de.Type.CODE)}.`)):n.reportInfo(0,`Put together, the final range we computed is ${de.pretty(e.configuration,h,de.Type.RANGE)}`)}}break;default:n.reportInfo(0,`The ${de.pretty(e.configuration,"yarn explain peer-requirements",de.Type.CODE)} command doesn't support this warning type yet.`);break}})).exitCode()}Ye();qt();$a();Ye();Ye();Pt();qt();var Xge=$e(Jn()),Hh=class extends ut{constructor(){super(...arguments);this.useYarnPath=ge.Boolean("--yarn-path",{description:"Set the yarnPath setting even if the version can be accessed by Corepack"});this.onlyIfNeeded=ge.Boolean("--only-if-needed",!1,{description:"Only lock the Yarn version if it isn't already locked"});this.version=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);if(this.onlyIfNeeded&&r.get("yarnPath")){let A=r.sources.get("yarnPath");if(!A)throw new Error("Assertion failed: Expected 'yarnPath' to have a source");let p=r.projectCwd??r.startingCwd;if(z.contains(p,A))return 0}let o=()=>{if(typeof rn>"u")throw new it("The --install flag can only be used without explicit version specifier from the Yarn CLI");return`file://${process.argv[1]}`},a,n=(A,p)=>({version:p,url:A.replace(/\{\}/g,p)});if(this.version==="self")a={url:o(),version:rn??"self"};else if(this.version==="latest"||this.version==="berry"||this.version==="stable")a=n("https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js",await y2(r,"stable"));else if(this.version==="canary")a=n("https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js",await y2(r,"canary"));else if(this.version==="classic")a={url:"https://classic.yarnpkg.com/latest.js",version:"classic"};else if(this.version.match(/^https?:/))a={url:this.version,version:"remote"};else if(this.version.match(/^\.{0,2}[\\/]/)||le.isAbsolute(this.version))a={url:`file://${z.resolve(le.toPortablePath(this.version))}`,version:"file"};else if(kr.satisfiesWithPrereleases(this.version,">=2.0.0"))a=n("https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js",this.version);else if(kr.satisfiesWithPrereleases(this.version,"^0.x || ^1.x"))a=n("https://github.com/yarnpkg/yarn/releases/download/v{}/yarn-{}.js",this.version);else if(kr.validRange(this.version))a=n("https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js",await q0t(r,this.version));else throw new it(`Invalid version descriptor "${this.version}"`);return(await Lt.start({configuration:r,stdout:this.context.stdout,includeLogs:!this.context.quiet},async A=>{let p=async()=>{let h="file://";return a.url.startsWith(h)?(A.reportInfo(0,`Retrieving ${de.pretty(r,a.url,de.Type.PATH)}`),await oe.readFilePromise(a.url.slice(h.length))):(A.reportInfo(0,`Downloading ${de.pretty(r,a.url,de.Type.URL)}`),await nn.get(a.url,{configuration:r}))};await N8(r,a.version,p,{report:A,useYarnPath:this.useYarnPath})})).exitCode()}};Hh.paths=[["set","version"]],Hh.usage=nt.Usage({description:"lock the Yarn version used by the project",details:"\n This command will set a specific release of Yarn to be used by Corepack: https://nodejs.org/api/corepack.html.\n\n By default it only will set the `packageManager` field at the root of your project, but if the referenced release cannot be represented this way, if you already have `yarnPath` configured, or if you set the `--yarn-path` command line flag, then the release will also be downloaded from the Yarn GitHub repository, stored inside your project, and referenced via the `yarnPath` settings from your project `.yarnrc.yml` file.\n\n A very good use case for this command is to enforce the version of Yarn used by any single member of your team inside the same project - by doing this you ensure that you have control over Yarn upgrades and downgrades (including on your deployment servers), and get rid of most of the headaches related to someone using a slightly different version and getting different behavior.\n\n The version specifier can be:\n\n - a tag:\n - `latest` / `berry` / `stable` -> the most recent stable berry (`>=2.0.0`) release\n - `canary` -> the most recent canary (release candidate) berry (`>=2.0.0`) release\n - `classic` -> the most recent classic (`^0.x || ^1.x`) release\n\n - a semver range (e.g. `2.x`) -> the most recent version satisfying the range (limited to berry releases)\n\n - a semver version (e.g. `2.4.1`, `1.22.1`)\n\n - a local file referenced through either a relative or absolute path\n\n - `self` -> the version used to invoke the command\n ",examples:[["Download the latest release from the Yarn repository","$0 set version latest"],["Download the latest canary release from the Yarn repository","$0 set version canary"],["Download the latest classic release from the Yarn repository","$0 set version classic"],["Download the most recent Yarn 3 build","$0 set version 3.x"],["Download a specific Yarn 2 build","$0 set version 2.0.0-rc.30"],["Switch back to a specific Yarn 1 release","$0 set version 1.22.1"],["Use a release from the local filesystem","$0 set version ./yarn.cjs"],["Use a release from a URL","$0 set version https://repo.yarnpkg.com/3.1.0/packages/yarnpkg-cli/bin/yarn.js"],["Download the version used to invoke the command","$0 set version self"]]});async function q0t(t,e){let o=(await nn.get("https://repo.yarnpkg.com/tags",{configuration:t,jsonResponse:!0})).tags.filter(a=>kr.satisfiesWithPrereleases(a,e));if(o.length===0)throw new it(`No matching release found for range ${de.pretty(t,e,de.Type.RANGE)}.`);return o[0]}async function y2(t,e){let r=await nn.get("https://repo.yarnpkg.com/tags",{configuration:t,jsonResponse:!0});if(!r.latest[e])throw new it(`Tag ${de.pretty(t,e,de.Type.RANGE)} not found`);return r.latest[e]}async function N8(t,e,r,{report:o,useYarnPath:a}){let n,u=async()=>(typeof n>"u"&&(n=await r()),n);if(e===null){let te=await u();await oe.mktempPromise(async ae=>{let fe=z.join(ae,"yarn.cjs");await oe.writeFilePromise(fe,te);let{stdout:ue}=await Ur.execvp(process.execPath,[le.fromPortablePath(fe),"--version"],{cwd:ae,env:{...t.env,YARN_IGNORE_PATH:"1"}});if(e=ue.trim(),!Xge.default.valid(e))throw new Error(`Invalid semver version. ${de.pretty(t,"yarn --version",de.Type.CODE)} returned:
-${e}`)})}let A=t.projectCwd??t.startingCwd,p=z.resolve(A,".yarn/releases"),h=z.resolve(p,`yarn-${e}.cjs`),E=z.relative(t.startingCwd,h),I=_e.isTaggedYarnVersion(e),v=t.get("yarnPath"),x=!I,C=x||!!v||!!a;if(a===!1){if(x)throw new Jt(0,"You explicitly opted out of yarnPath usage in your command line, but the version you specified cannot be represented by Corepack");C=!1}else!C&&!process.env.COREPACK_ROOT&&(o.reportWarning(0,`You don't seem to have ${de.applyHyperlink(t,"Corepack","https://nodejs.org/api/corepack.html")} enabled; we'll have to rely on ${de.applyHyperlink(t,"yarnPath","https://yarnpkg.com/configuration/yarnrc#yarnPath")} instead`),C=!0);if(C){let te=await u();o.reportInfo(0,`Saving the new release in ${de.pretty(t,E,"magenta")}`),await oe.removePromise(z.dirname(h)),await oe.mkdirPromise(z.dirname(h),{recursive:!0}),await oe.writeFilePromise(h,te,{mode:493}),await Ke.updateConfiguration(A,{yarnPath:z.relative(A,h)})}else await oe.removePromise(z.dirname(h)),await Ke.updateConfiguration(A,{yarnPath:Ke.deleteProperty});let R=await Ot.tryFind(A)||new Ot;R.packageManager=`yarn@${I?e:await y2(t,"stable")}`;let N={};R.exportTo(N);let U=z.join(A,Ot.fileName),V=`${JSON.stringify(N,null,R.indent)}
-`;return await oe.changeFilePromise(U,V,{automaticNewlines:!0}),{bundleVersion:e}}function Zge(t){return wr[AP(t)]}var G0t=/## (?<code>YN[0-9]{4}) - `(?<name>[A-Z_]+)`\n\n(?<details>(?:.(?!##))+)/gs;async function j0t(t){let r=`https://repo.yarnpkg.com/${_e.isTaggedYarnVersion(rn)?rn:await y2(t,"canary")}/packages/gatsby/content/advanced/error-codes.md`,o=await nn.get(r,{configuration:t});return new Map(Array.from(o.toString().matchAll(G0t),({groups:a})=>{if(!a)throw new Error("Assertion failed: Expected the match to have been successful");let n=Zge(a.code);if(a.name!==n)throw new Error(`Assertion failed: Invalid error code data: Expected "${a.name}" to be named "${n}"`);return[a.code,a.details]}))}var qh=class extends ut{constructor(){super(...arguments);this.code=ge.String({required:!1,validator:aI(Cy(),[oI(/^YN[0-9]{4}$/)])});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);if(typeof this.code<"u"){let o=Zge(this.code),a=de.pretty(r,o,de.Type.CODE),n=this.cli.format().header(`${this.code} - ${a}`),A=(await j0t(r)).get(this.code),p=typeof A<"u"?de.jsonOrPretty(this.json,r,de.tuple(de.Type.MARKDOWN,{text:A,format:this.cli.format(),paragraphs:!0})):`This error code does not have a description.
-
-You can help us by editing this page on GitHub \u{1F642}:
-${de.jsonOrPretty(this.json,r,de.tuple(de.Type.URL,"https://github.com/yarnpkg/berry/blob/master/packages/gatsby/content/advanced/error-codes.md"))}
-`;this.json?this.context.stdout.write(`${JSON.stringify({code:this.code,name:o,details:p})}
-`):this.context.stdout.write(`${n}
-
-${p}
-`)}else{let o={children:_e.mapAndFilter(Object.entries(wr),([a,n])=>Number.isNaN(Number(a))?_e.mapAndFilter.skip:{label:Ku(Number(a)),value:de.tuple(de.Type.CODE,n)})};$s.emitTree(o,{configuration:r,stdout:this.context.stdout,json:this.json})}}};qh.paths=[["explain"]],qh.usage=nt.Usage({description:"explain an error code",details:`
- When the code argument is specified, this command prints its name and its details.
-
- When used without arguments, this command lists all error codes and their names.
- `,examples:[["Explain an error code","$0 explain YN0006"],["List all error codes","$0 explain"]]});Ye();Pt();qt();var $ge=$e(Zo()),Gh=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Print versions of a package from the whole project"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Print information for all packages, including transitive dependencies"});this.extra=ge.Array("-X,--extra",[],{description:"An array of requests of extra data provided by plugins"});this.cache=ge.Boolean("--cache",!1,{description:"Print information about the cache entry of a package (path, size, checksum)"});this.dependents=ge.Boolean("--dependents",!1,{description:"Print all dependents for each matching package"});this.manifest=ge.Boolean("--manifest",!1,{description:"Print data obtained by looking at the package archive (license, homepage, ...)"});this.nameOnly=ge.Boolean("--name-only",!1,{description:"Only print the name for the matching packages"});this.virtuals=ge.Boolean("--virtuals",!1,{description:"Print each instance of the virtual packages"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.patterns=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a&&!this.all)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState();let u=new Set(this.extra);this.cache&&u.add("cache"),this.dependents&&u.add("dependents"),this.manifest&&u.add("manifest");let A=(ae,{recursive:fe})=>{let ue=ae.anchoredLocator.locatorHash,me=new Map,he=[ue];for(;he.length>0;){let Be=he.shift();if(me.has(Be))continue;let we=o.storedPackages.get(Be);if(typeof we>"u")throw new Error("Assertion failed: Expected the package to be registered");if(me.set(Be,we),W.isVirtualLocator(we)&&he.push(W.devirtualizeLocator(we).locatorHash),!(!fe&&Be!==ue))for(let g of we.dependencies.values()){let Ee=o.storedResolutions.get(g.descriptorHash);if(typeof Ee>"u")throw new Error("Assertion failed: Expected the resolution to be registered");he.push(Ee)}}return me.values()},p=({recursive:ae})=>{let fe=new Map;for(let ue of o.workspaces)for(let me of A(ue,{recursive:ae}))fe.set(me.locatorHash,me);return fe.values()},h=({all:ae,recursive:fe})=>ae&&fe?o.storedPackages.values():ae?p({recursive:fe}):A(a,{recursive:fe}),E=({all:ae,recursive:fe})=>{let ue=h({all:ae,recursive:fe}),me=this.patterns.map(we=>{let g=W.parseLocator(we),Ee=$ge.default.makeRe(W.stringifyIdent(g)),Pe=W.isVirtualLocator(g),ce=Pe?W.devirtualizeLocator(g):g;return ne=>{let ee=W.stringifyIdent(ne);if(!Ee.test(ee))return!1;if(g.reference==="unknown")return!0;let Ie=W.isVirtualLocator(ne),Fe=Ie?W.devirtualizeLocator(ne):ne;return!(Pe&&Ie&&g.reference!==ne.reference||ce.reference!==Fe.reference)}}),he=_e.sortMap([...ue],we=>W.stringifyLocator(we));return{selection:he.filter(we=>me.length===0||me.some(g=>g(we))),sortedLookup:he}},{selection:I,sortedLookup:v}=E({all:this.all,recursive:this.recursive});if(I.length===0)throw new it("No package matched your request");let x=new Map;if(this.dependents)for(let ae of v)for(let fe of ae.dependencies.values()){let ue=o.storedResolutions.get(fe.descriptorHash);if(typeof ue>"u")throw new Error("Assertion failed: Expected the resolution to be registered");_e.getArrayWithDefault(x,ue).push(ae)}let C=new Map;for(let ae of v){if(!W.isVirtualLocator(ae))continue;let fe=W.devirtualizeLocator(ae);_e.getArrayWithDefault(C,fe.locatorHash).push(ae)}let R={},N={children:R},U=r.makeFetcher(),V={project:o,fetcher:U,cache:n,checksums:o.storedChecksums,report:new Qi,cacheOptions:{skipIntegrityCheck:!0}},te=[async(ae,fe,ue)=>{if(!fe.has("manifest"))return;let me=await U.fetch(ae,V),he;try{he=await Ot.find(me.prefixPath,{baseFs:me.packageFs})}finally{me.releaseFs?.()}ue("Manifest",{License:de.tuple(de.Type.NO_HINT,he.license),Homepage:de.tuple(de.Type.URL,he.raw.homepage??null)})},async(ae,fe,ue)=>{if(!fe.has("cache"))return;let me=o.storedChecksums.get(ae.locatorHash)??null,he=n.getLocatorPath(ae,me),Be;if(he!==null)try{Be=await oe.statPromise(he)}catch{}let we=typeof Be<"u"?[Be.size,de.Type.SIZE]:void 0;ue("Cache",{Checksum:de.tuple(de.Type.NO_HINT,me),Path:de.tuple(de.Type.PATH,he),Size:we})}];for(let ae of I){let fe=W.isVirtualLocator(ae);if(!this.virtuals&&fe)continue;let ue={},me={value:[ae,de.Type.LOCATOR],children:ue};if(R[W.stringifyLocator(ae)]=me,this.nameOnly){delete me.children;continue}let he=C.get(ae.locatorHash);typeof he<"u"&&(ue.Instances={label:"Instances",value:de.tuple(de.Type.NUMBER,he.length)}),ue.Version={label:"Version",value:de.tuple(de.Type.NO_HINT,ae.version)};let Be=(g,Ee)=>{let Pe={};if(ue[g]=Pe,Array.isArray(Ee))Pe.children=Ee.map(ce=>({value:ce}));else{let ce={};Pe.children=ce;for(let[ne,ee]of Object.entries(Ee))typeof ee>"u"||(ce[ne]={label:ne,value:ee})}};if(!fe){for(let g of te)await g(ae,u,Be);await r.triggerHook(g=>g.fetchPackageInfo,ae,u,Be)}ae.bin.size>0&&!fe&&Be("Exported Binaries",[...ae.bin.keys()].map(g=>de.tuple(de.Type.PATH,g)));let we=x.get(ae.locatorHash);typeof we<"u"&&we.length>0&&Be("Dependents",we.map(g=>de.tuple(de.Type.LOCATOR,g))),ae.dependencies.size>0&&!fe&&Be("Dependencies",[...ae.dependencies.values()].map(g=>{let Ee=o.storedResolutions.get(g.descriptorHash),Pe=typeof Ee<"u"?o.storedPackages.get(Ee)??null:null;return de.tuple(de.Type.RESOLUTION,{descriptor:g,locator:Pe})})),ae.peerDependencies.size>0&&fe&&Be("Peer dependencies",[...ae.peerDependencies.values()].map(g=>{let Ee=ae.dependencies.get(g.identHash),Pe=typeof Ee<"u"?o.storedResolutions.get(Ee.descriptorHash)??null:null,ce=Pe!==null?o.storedPackages.get(Pe)??null:null;return de.tuple(de.Type.RESOLUTION,{descriptor:g,locator:ce})}))}$s.emitTree(N,{configuration:r,json:this.json,stdout:this.context.stdout,separators:this.nameOnly?0:2})}};Gh.paths=[["info"]],Gh.usage=nt.Usage({description:"see information related to packages",details:"\n This command prints various information related to the specified packages, accepting glob patterns.\n\n By default, if the locator reference is missing, Yarn will default to print the information about all the matching direct dependencies of the package for the active workspace. To instead print all versions of the package that are direct dependencies of any of your workspaces, use the `-A,--all` flag. Adding the `-R,--recursive` flag will also report transitive dependencies.\n\n Some fields will be hidden by default in order to keep the output readable, but can be selectively displayed by using additional options (`--dependents`, `--manifest`, `--virtuals`, ...) described in the option descriptions.\n\n Note that this command will only print the information directly related to the selected packages - if you wish to know why the package is there in the first place, use `yarn why` which will do just that (it also provides a `-R,--recursive` flag that may be of some help).\n ",examples:[["Show information about Lodash","$0 info lodash"]]});Ye();Pt();Nl();var hk=$e(rd());qt();var O8=$e(Jn());$a();var Y0t=[{selector:t=>t===-1,name:"nodeLinker",value:"node-modules"},{selector:t=>t!==-1&&t<8,name:"enableGlobalCache",value:!1},{selector:t=>t!==-1&&t<8,name:"compressionLevel",value:"mixed"}],jh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.immutable=ge.Boolean("--immutable",{description:"Abort with an error exit code if the lockfile was to be modified"});this.immutableCache=ge.Boolean("--immutable-cache",{description:"Abort with an error exit code if the cache folder was to be modified"});this.refreshLockfile=ge.Boolean("--refresh-lockfile",{description:"Refresh the package metadata stored in the lockfile"});this.checkCache=ge.Boolean("--check-cache",{description:"Always refetch the packages and ensure that their checksums are consistent"});this.checkResolutions=ge.Boolean("--check-resolutions",{description:"Validates that the package resolutions are coherent"});this.inlineBuilds=ge.Boolean("--inline-builds",{description:"Verbosely print the output of the build steps of dependencies"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:Ks(hl)});this.cacheFolder=ge.String("--cache-folder",{hidden:!0});this.frozenLockfile=ge.Boolean("--frozen-lockfile",{hidden:!0});this.ignoreEngines=ge.Boolean("--ignore-engines",{hidden:!0});this.nonInteractive=ge.Boolean("--non-interactive",{hidden:!0});this.preferOffline=ge.Boolean("--prefer-offline",{hidden:!0});this.production=ge.Boolean("--production",{hidden:!0});this.registry=ge.String("--registry",{hidden:!0});this.silent=ge.Boolean("--silent",{hidden:!0});this.networkTimeout=ge.String("--network-timeout",{hidden:!0})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);typeof this.inlineBuilds<"u"&&r.useWithSource("<cli>",{enableInlineBuilds:this.inlineBuilds},r.startingCwd,{overwrite:!0});let o=!!process.env.FUNCTION_TARGET||!!process.env.GOOGLE_RUNTIME,a=await NE({configuration:r,stdout:this.context.stdout},[{option:this.ignoreEngines,message:"The --ignore-engines option is deprecated; engine checking isn't a core feature anymore",error:!hk.default.VERCEL},{option:this.registry,message:"The --registry option is deprecated; prefer setting npmRegistryServer in your .yarnrc.yml file"},{option:this.preferOffline,message:"The --prefer-offline flag is deprecated; use the --cached flag with 'yarn add' instead",error:!hk.default.VERCEL},{option:this.production,message:"The --production option is deprecated on 'install'; use 'yarn workspaces focus' instead",error:!0},{option:this.nonInteractive,message:"The --non-interactive option is deprecated",error:!o},{option:this.frozenLockfile,message:"The --frozen-lockfile option is deprecated; use --immutable and/or --immutable-cache instead",callback:()=>this.immutable=this.frozenLockfile},{option:this.cacheFolder,message:"The cache-folder option has been deprecated; use rc settings instead",error:!hk.default.NETLIFY}]);if(a!==null)return a;let n=this.mode==="update-lockfile";if(n&&(this.immutable||this.immutableCache))throw new it(`${de.pretty(r,"--immutable",de.Type.CODE)} and ${de.pretty(r,"--immutable-cache",de.Type.CODE)} cannot be used with ${de.pretty(r,"--mode=update-lockfile",de.Type.CODE)}`);let u=(this.immutable??r.get("enableImmutableInstalls"))&&!n,A=this.immutableCache&&!n;if(r.projectCwd!==null){let R=await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async N=>{let U=!1;await z0t(r,u)&&(N.reportInfo(48,"Automatically removed core plugins that are now builtins \u{1F44D}"),U=!0),await K0t(r,u)&&(N.reportInfo(48,"Automatically fixed merge conflicts \u{1F44D}"),U=!0),U&&N.reportSeparator()});if(R.hasErrors())return R.exitCode()}if(r.projectCwd!==null){let R=await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async N=>{if(Ke.telemetry?.isNew)Ke.telemetry.commitTips(),N.reportInfo(65,"Yarn will periodically gather anonymous telemetry: https://yarnpkg.com/advanced/telemetry"),N.reportInfo(65,`Run ${de.pretty(r,"yarn config set --home enableTelemetry 0",de.Type.CODE)} to disable`),N.reportSeparator();else if(Ke.telemetry?.shouldShowTips){let U=await nn.get("https://repo.yarnpkg.com/tags",{configuration:r,jsonResponse:!0}).catch(()=>null);if(U!==null){let V=null;if(rn!==null){let ae=O8.default.prerelease(rn)?"canary":"stable",fe=U.latest[ae];O8.default.gt(fe,rn)&&(V=[ae,fe])}if(V)Ke.telemetry.commitTips(),N.reportInfo(88,`${de.applyStyle(r,`A new ${V[0]} version of Yarn is available:`,de.Style.BOLD)} ${W.prettyReference(r,V[1])}!`),N.reportInfo(88,`Upgrade now by running ${de.pretty(r,`yarn set version ${V[1]}`,de.Type.CODE)}`),N.reportSeparator();else{let te=Ke.telemetry.selectTip(U.tips);te&&(N.reportInfo(89,de.pretty(r,te.message,de.Type.MARKDOWN_INLINE)),te.url&&N.reportInfo(89,`Learn more at ${te.url}`),N.reportSeparator())}}}});if(R.hasErrors())return R.exitCode()}let{project:p,workspace:h}=await St.find(r,this.context.cwd),E=p.lockfileLastVersion;if(E!==null){let R=await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async N=>{let U={};for(let V of Y0t)V.selector(E)&&typeof r.sources.get(V.name)>"u"&&(r.use("<compat>",{[V.name]:V.value},p.cwd,{overwrite:!0}),U[V.name]=V.value);Object.keys(U).length>0&&(await Ke.updateConfiguration(p.cwd,U),N.reportInfo(87,"Migrated your project to the latest Yarn version \u{1F680}"),N.reportSeparator())});if(R.hasErrors())return R.exitCode()}let I=await Nr.find(r,{immutable:A,check:this.checkCache});if(!h)throw new nr(p.cwd,this.context.cwd);await p.restoreInstallState({restoreResolutions:!1});let v=r.get("enableHardenedMode");v&&typeof r.sources.get("enableHardenedMode")>"u"&&await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async R=>{R.reportWarning(0,"Yarn detected that the current workflow is executed from a public pull request. For safety the hardened mode has been enabled."),R.reportWarning(0,`It will prevent malicious lockfile manipulations, in exchange for a slower install time. You can opt-out if necessary; check our ${de.applyHyperlink(r,"documentation","https://yarnpkg.com/features/security#hardened-mode")} for more details.`),R.reportSeparator()}),(this.refreshLockfile??v)&&(p.lockfileNeedsRefresh=!0);let x=this.checkResolutions??v;return(await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout,forceSectionAlignment:!0,includeLogs:!0,includeVersion:!0},async R=>{await p.install({cache:I,report:R,immutable:u,checkResolutions:x,mode:this.mode})})).exitCode()}};jh.paths=[["install"],nt.Default],jh.usage=nt.Usage({description:"install the project dependencies",details:"\n This command sets up your project if needed. The installation is split into four different steps that each have their own characteristics:\n\n - **Resolution:** First the package manager will resolve your dependencies. The exact way a dependency version is privileged over another isn't standardized outside of the regular semver guarantees. If a package doesn't resolve to what you would expect, check that all dependencies are correctly declared (also check our website for more information: ).\n\n - **Fetch:** Then we download all the dependencies if needed, and make sure that they're all stored within our cache (check the value of `cacheFolder` in `yarn config` to see where the cache files are stored).\n\n - **Link:** Then we send the dependency tree information to internal plugins tasked with writing them on the disk in some form (for example by generating the `.pnp.cjs` file you might know).\n\n - **Build:** Once the dependency tree has been written on the disk, the package manager will now be free to run the build scripts for all packages that might need it, in a topological order compatible with the way they depend on one another. See https://yarnpkg.com/advanced/lifecycle-scripts for detail.\n\n Note that running this command is not part of the recommended workflow. Yarn supports zero-installs, which means that as long as you store your cache and your `.pnp.cjs` file inside your repository, everything will work without requiring any install right after cloning your repository or switching branches.\n\n If the `--immutable` option is set (defaults to true on CI), Yarn will abort with an error exit code if the lockfile was to be modified (other paths can be added using the `immutablePatterns` configuration setting). For backward compatibility we offer an alias under the name of `--frozen-lockfile`, but it will be removed in a later release.\n\n If the `--immutable-cache` option is set, Yarn will abort with an error exit code if the cache folder was to be modified (either because files would be added, or because they'd be removed).\n\n If the `--refresh-lockfile` option is set, Yarn will keep the same resolution for the packages currently in the lockfile but will refresh their metadata. If used together with `--immutable`, it can validate that the lockfile information are consistent. This flag is enabled by default when Yarn detects it runs within a pull request context.\n\n If the `--check-cache` option is set, Yarn will always refetch the packages and will ensure that their checksum matches what's 1/ described in the lockfile 2/ inside the existing cache files (if present). This is recommended as part of your CI workflow if you're both following the Zero-Installs model and accepting PRs from third-parties, as they'd otherwise have the ability to alter the checked-in packages before submitting them.\n\n If the `--inline-builds` option is set, Yarn will verbosely print the output of the build steps of your dependencies (instead of writing them into individual files). This is likely useful mostly for debug purposes only when using Docker-like environments.\n\n If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n ",examples:[["Install the project","$0 install"],["Validate a project when using Zero-Installs","$0 install --immutable --immutable-cache"],["Validate a project when using Zero-Installs (slightly safer if you accept external PRs)","$0 install --immutable --immutable-cache --check-cache"]]});var W0t="<<<<<<<";async function K0t(t,e){if(!t.projectCwd)return!1;let r=z.join(t.projectCwd,dr.lockfile);if(!await oe.existsPromise(r)||!(await oe.readFilePromise(r,"utf8")).includes(W0t))return!1;if(e)throw new Jt(47,"Cannot autofix a lockfile when running an immutable install");let a=await Ur.execvp("git",["rev-parse","MERGE_HEAD","HEAD"],{cwd:t.projectCwd});if(a.code!==0&&(a=await Ur.execvp("git",["rev-parse","REBASE_HEAD","HEAD"],{cwd:t.projectCwd})),a.code!==0&&(a=await Ur.execvp("git",["rev-parse","CHERRY_PICK_HEAD","HEAD"],{cwd:t.projectCwd})),a.code!==0)throw new Jt(83,"Git returned an error when trying to find the commits pertaining to the conflict");let n=await Promise.all(a.stdout.trim().split(/\n/).map(async A=>{let p=await Ur.execvp("git",["show",`${A}:./${dr.lockfile}`],{cwd:t.projectCwd});if(p.code!==0)throw new Jt(83,`Git returned an error when trying to access the lockfile content in ${A}`);try{return Ki(p.stdout)}catch{throw new Jt(46,"A variant of the conflicting lockfile failed to parse")}}));n=n.filter(A=>!!A.__metadata);for(let A of n){if(A.__metadata.version<7)for(let p of Object.keys(A)){if(p==="__metadata")continue;let h=W.parseDescriptor(p,!0),E=t.normalizeDependency(h),I=W.stringifyDescriptor(E);I!==p&&(A[I]=A[p],delete A[p])}for(let p of Object.keys(A)){if(p==="__metadata")continue;let h=A[p].checksum;typeof h=="string"&&h.includes("/")||(A[p].checksum=`${A.__metadata.cacheKey}/${h}`)}}let u=Object.assign({},...n);u.__metadata.version=`${Math.min(...n.map(A=>parseInt(A.__metadata.version??0)))}`,u.__metadata.cacheKey="merged";for(let[A,p]of Object.entries(u))typeof p=="string"&&delete u[A];return await oe.changeFilePromise(r,Ba(u),{automaticNewlines:!0}),!0}async function z0t(t,e){if(!t.projectCwd)return!1;let r=[],o=z.join(t.projectCwd,".yarn/plugins/@yarnpkg");return await Ke.updateConfiguration(t.projectCwd,{plugins:n=>{if(!Array.isArray(n))return n;let u=n.filter(A=>{if(!A.path)return!0;let p=z.resolve(t.projectCwd,A.path),h=v1.has(A.spec)&&z.contains(o,p);return h&&r.push(p),!h});return u.length===0?Ke.deleteProperty:u.length===n.length?n:u}},{immutable:e})?(await Promise.all(r.map(async n=>{await oe.removePromise(n)})),!0):!1}Ye();Pt();qt();var Yh=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Link all workspaces belonging to the target projects to the current one"});this.private=ge.Boolean("-p,--private",!1,{description:"Also link private workspaces belonging to the target projects to the current one"});this.relative=ge.Boolean("-r,--relative",!1,{description:"Link workspaces using relative paths instead of absolute paths"});this.destinations=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=o.topLevelWorkspace,A=[];for(let p of this.destinations){let h=z.resolve(this.context.cwd,le.toPortablePath(p)),E=await Ke.find(h,this.context.plugins,{useRc:!1,strict:!1}),{project:I,workspace:v}=await St.find(E,h);if(o.cwd===I.cwd)throw new it(`Invalid destination '${p}'; Can't link the project to itself`);if(!v)throw new nr(I.cwd,h);if(this.all){let x=!1;for(let C of I.workspaces)C.manifest.name&&(!C.manifest.private||this.private)&&(A.push(C),x=!0);if(!x)throw new it(`No workspace found to be linked in the target project: ${p}`)}else{if(!v.manifest.name)throw new it(`The target workspace at '${p}' doesn't have a name and thus cannot be linked`);if(v.manifest.private&&!this.private)throw new it(`The target workspace at '${p}' is marked private - use the --private flag to link it anyway`);A.push(v)}}for(let p of A){let h=W.stringifyIdent(p.anchoredLocator),E=this.relative?z.relative(o.cwd,p.cwd):p.cwd;u.manifest.resolutions.push({pattern:{descriptor:{fullName:h}},reference:`portal:${E}`})}return await o.installWithNewReport({stdout:this.context.stdout},{cache:n})}};Yh.paths=[["link"]],Yh.usage=nt.Usage({description:"connect the local project to another one",details:"\n This command will set a new `resolutions` field in the project-level manifest and point it to the workspace at the specified location (even if part of another project).\n ",examples:[["Register one or more remote workspaces for use in the current project","$0 link ~/ts-loader ~/jest"],["Register all workspaces from a remote project for use in the current project","$0 link ~/jest --all"]]});qt();var Wh=class extends ut{constructor(){super(...arguments);this.args=ge.Proxy()}async execute(){return this.cli.run(["exec","node",...this.args])}};Wh.paths=[["node"]],Wh.usage=nt.Usage({description:"run node with the hook already setup",details:`
- This command simply runs Node. It also makes sure to call it in a way that's compatible with the current project (for example, on PnP projects the environment will be setup in such a way that PnP will be correctly injected into the environment).
-
- The Node process will use the exact same version of Node as the one used to run Yarn itself, which might be a good way to ensure that your commands always use a consistent Node version.
- `,examples:[["Run a Node script","$0 node ./my-script.js"]]});Ye();qt();var Kh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=await Ke.findRcFiles(this.context.cwd);return(await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout},async n=>{for(let u of o)if(!!u.data?.plugins)for(let A of u.data.plugins){if(!A.checksum||!A.spec.match(/^https?:/))continue;let p=await nn.get(A.spec,{configuration:r}),h=wn.makeHash(p);if(A.checksum===h)continue;let E=de.pretty(r,A.path,de.Type.PATH),I=de.pretty(r,A.spec,de.Type.URL),v=`${E} is different from the file provided by ${I}`;n.reportJson({...A,newChecksum:h}),n.reportError(0,v)}})).exitCode()}};Kh.paths=[["plugin","check"]],Kh.usage=nt.Usage({category:"Plugin-related commands",description:"find all third-party plugins that differ from their own spec",details:`
- Check only the plugins from https.
-
- If this command detects any plugin differences in the CI environment, it will throw an error.
- `,examples:[["find all third-party plugins that differ from their own spec","$0 plugin check"]]});Ye();Ye();Pt();qt();var ide=ve("os");Ye();Pt();qt();var ede=ve("os");Ye();Nl();qt();var V0t="https://raw.githubusercontent.com/yarnpkg/berry/master/plugins.yml";async function Xd(t,e){let r=await nn.get(V0t,{configuration:t}),o=Ki(r.toString());return Object.fromEntries(Object.entries(o).filter(([a,n])=>!e||kr.satisfiesWithPrereleases(e,n.range??"<4.0.0-rc.1")))}var zh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);return(await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout},async a=>{let n=await Xd(r,rn);for(let[u,{experimental:A,...p}]of Object.entries(n)){let h=u;A&&(h+=" [experimental]"),a.reportJson({name:u,experimental:A,...p}),a.reportInfo(null,h)}})).exitCode()}};zh.paths=[["plugin","list"]],zh.usage=nt.Usage({category:"Plugin-related commands",description:"list the available official plugins",details:"\n This command prints the plugins available directly from the Yarn repository. Only those plugins can be referenced by name in `yarn plugin import`.\n ",examples:[["List the official plugins","$0 plugin list"]]});var J0t=/^[0-9]+$/,X0t=process.platform==="win32";function tde(t){return J0t.test(t)?`pull/${t}/head`:t}var Z0t=({repository:t,branch:e},r)=>[["git","init",le.fromPortablePath(r)],["git","remote","add","origin",t],["git","fetch","origin","--depth=1",tde(e)],["git","reset","--hard","FETCH_HEAD"]],$0t=({branch:t})=>[["git","fetch","origin","--depth=1",tde(t),"--force"],["git","reset","--hard","FETCH_HEAD"],["git","clean","-dfx","-e","packages/yarnpkg-cli/bundles"]],egt=({plugins:t,noMinify:e},r,o)=>[["yarn","build:cli",...new Array().concat(...t.map(a=>["--plugin",z.resolve(o,a)])),...e?["--no-minify"]:[],"|"],[X0t?"move":"mv","packages/yarnpkg-cli/bundles/yarn.js",le.fromPortablePath(r),"|"]],Vh=class extends ut{constructor(){super(...arguments);this.installPath=ge.String("--path",{description:"The path where the repository should be cloned to"});this.repository=ge.String("--repository","https://github.com/yarnpkg/berry.git",{description:"The repository that should be cloned"});this.branch=ge.String("--branch","master",{description:"The branch of the repository that should be cloned"});this.plugins=ge.Array("--plugin",[],{description:"An array of additional plugins that should be included in the bundle"});this.dryRun=ge.Boolean("-n,--dry-run",!1,{description:"If set, the bundle will be built but not added to the project"});this.noMinify=ge.Boolean("--no-minify",!1,{description:"Build a bundle for development (debugging) - non-minified and non-mangled"});this.force=ge.Boolean("-f,--force",!1,{description:"Always clone the repository instead of trying to fetch the latest commits"});this.skipPlugins=ge.Boolean("--skip-plugins",!1,{description:"Skip updating the contrib plugins"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),a=typeof this.installPath<"u"?z.resolve(this.context.cwd,le.toPortablePath(this.installPath)):z.resolve(le.toPortablePath((0,ede.tmpdir)()),"yarnpkg-sources",wn.makeHash(this.repository).slice(0,6));return(await Lt.start({configuration:r,stdout:this.context.stdout},async u=>{await M8(this,{configuration:r,report:u,target:a}),u.reportSeparator(),u.reportInfo(0,"Building a fresh bundle"),u.reportSeparator();let A=await Ur.execvp("git",["rev-parse","--short","HEAD"],{cwd:a,strict:!0}),p=z.join(a,`packages/yarnpkg-cli/bundles/yarn-${A.stdout.trim()}.js`);oe.existsSync(p)||(await E2(egt(this,p,a),{configuration:r,context:this.context,target:a}),u.reportSeparator());let h=await oe.readFilePromise(p);if(!this.dryRun){let{bundleVersion:E}=await N8(r,null,async()=>h,{report:u});this.skipPlugins||await tgt(this,E,{project:o,report:u,target:a})}})).exitCode()}};Vh.paths=[["set","version","from","sources"]],Vh.usage=nt.Usage({description:"build Yarn from master",details:`
- This command will clone the Yarn repository into a temporary folder, then build it. The resulting bundle will then be copied into the local project.
-
- By default, it also updates all contrib plugins to the same commit the bundle is built from. This behavior can be disabled by using the \`--skip-plugins\` flag.
- `,examples:[["Build Yarn from master","$0 set version from sources"]]});async function E2(t,{configuration:e,context:r,target:o}){for(let[a,...n]of t){let u=n[n.length-1]==="|";if(u&&n.pop(),u)await Ur.pipevp(a,n,{cwd:o,stdin:r.stdin,stdout:r.stdout,stderr:r.stderr,strict:!0});else{r.stdout.write(`${de.pretty(e,` $ ${[a,...n].join(" ")}`,"grey")}
-`);try{await Ur.execvp(a,n,{cwd:o,strict:!0})}catch(A){throw r.stdout.write(A.stdout||A.stack),A}}}}async function M8(t,{configuration:e,report:r,target:o}){let a=!1;if(!t.force&&oe.existsSync(z.join(o,".git"))){r.reportInfo(0,"Fetching the latest commits"),r.reportSeparator();try{await E2($0t(t),{configuration:e,context:t.context,target:o}),a=!0}catch{r.reportSeparator(),r.reportWarning(0,"Repository update failed; we'll try to regenerate it")}}a||(r.reportInfo(0,"Cloning the remote repository"),r.reportSeparator(),await oe.removePromise(o),await oe.mkdirPromise(o,{recursive:!0}),await E2(Z0t(t,o),{configuration:e,context:t.context,target:o}))}async function tgt(t,e,{project:r,report:o,target:a}){let n=await Xd(r.configuration,e),u=new Set(Object.keys(n));for(let A of r.configuration.plugins.keys())!u.has(A)||await U8(A,t,{project:r,report:o,target:a})}Ye();Ye();Pt();qt();var rde=$e(Jn()),nde=ve("vm");var Jh=class extends ut{constructor(){super(...arguments);this.name=ge.String();this.checksum=ge.Boolean("--checksum",!0,{description:"Whether to care if this plugin is modified"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);return(await Lt.start({configuration:r,stdout:this.context.stdout},async a=>{let{project:n}=await St.find(r,this.context.cwd),u,A;if(this.name.match(/^\.{0,2}[\\/]/)||le.isAbsolute(this.name)){let p=z.resolve(this.context.cwd,le.toPortablePath(this.name));a.reportInfo(0,`Reading ${de.pretty(r,p,de.Type.PATH)}`),u=z.relative(n.cwd,p),A=await oe.readFilePromise(p)}else{let p;if(this.name.match(/^https?:/)){try{new URL(this.name)}catch{throw new Jt(52,`Plugin specifier "${this.name}" is neither a plugin name nor a valid url`)}u=this.name,p=this.name}else{let h=W.parseLocator(this.name.replace(/^((@yarnpkg\/)?plugin-)?/,"@yarnpkg/plugin-"));if(h.reference!=="unknown"&&!rde.default.valid(h.reference))throw new Jt(0,"Official plugins only accept strict version references. Use an explicit URL if you wish to download them from another location.");let E=W.stringifyIdent(h),I=await Xd(r,rn);if(!Object.hasOwn(I,E)){let v=`Couldn't find a plugin named ${W.prettyIdent(r,h)} on the remote registry.
-`;throw r.plugins.has(E)?v+=`A plugin named ${W.prettyIdent(r,h)} is already installed; possibly attempting to import a built-in plugin.`:v+=`Note that only the plugins referenced on our website (${de.pretty(r,"https://github.com/yarnpkg/berry/blob/master/plugins.yml",de.Type.URL)}) can be referenced by their name; any other plugin will have to be referenced through its public url (for example ${de.pretty(r,"https://github.com/yarnpkg/berry/raw/master/packages/plugin-typescript/bin/%40yarnpkg/plugin-typescript.js",de.Type.URL)}).`,new Jt(51,v)}u=E,p=I[E].url,h.reference!=="unknown"?p=p.replace(/\/master\//,`/${E}/${h.reference}/`):rn!==null&&(p=p.replace(/\/master\//,`/@yarnpkg/cli/${rn}/`))}a.reportInfo(0,`Downloading ${de.pretty(r,p,"green")}`),A=await nn.get(p,{configuration:r})}await _8(u,A,{checksum:this.checksum,project:n,report:a})})).exitCode()}};Jh.paths=[["plugin","import"]],Jh.usage=nt.Usage({category:"Plugin-related commands",description:"download a plugin",details:`
- This command downloads the specified plugin from its remote location and updates the configuration to reference it in further CLI invocations.
-
- Three types of plugin references are accepted:
-
- - If the plugin is stored within the Yarn repository, it can be referenced by name.
- - Third-party plugins can be referenced directly through their public urls.
- - Local plugins can be referenced by their path on the disk.
-
- If the \`--no-checksum\` option is set, Yarn will no longer care if the plugin is modified.
-
- Plugins cannot be downloaded from the npm registry, and aren't allowed to have dependencies (they need to be bundled into a single file, possibly thanks to the \`@yarnpkg/builder\` package).
- `,examples:[['Download and activate the "@yarnpkg/plugin-exec" plugin',"$0 plugin import @yarnpkg/plugin-exec"],['Download and activate the "@yarnpkg/plugin-exec" plugin (shorthand)',"$0 plugin import exec"],["Download and activate a community plugin","$0 plugin import https://example.org/path/to/plugin.js"],["Activate a local plugin","$0 plugin import ./path/to/plugin.js"]]});async function _8(t,e,{checksum:r=!0,project:o,report:a}){let{configuration:n}=o,u={},A={exports:u};(0,nde.runInNewContext)(e.toString(),{module:A,exports:u});let h=`.yarn/plugins/${A.exports.name}.cjs`,E=z.resolve(o.cwd,h);a.reportInfo(0,`Saving the new plugin in ${de.pretty(n,h,"magenta")}`),await oe.mkdirPromise(z.dirname(E),{recursive:!0}),await oe.writeFilePromise(E,e);let I={path:h,spec:t};r&&(I.checksum=wn.makeHash(e)),await Ke.addPlugin(o.cwd,[I])}var rgt=({pluginName:t,noMinify:e},r)=>[["yarn",`build:${t}`,...e?["--no-minify"]:[],"|"]],Xh=class extends ut{constructor(){super(...arguments);this.installPath=ge.String("--path",{description:"The path where the repository should be cloned to"});this.repository=ge.String("--repository","https://github.com/yarnpkg/berry.git",{description:"The repository that should be cloned"});this.branch=ge.String("--branch","master",{description:"The branch of the repository that should be cloned"});this.noMinify=ge.Boolean("--no-minify",!1,{description:"Build a plugin for development (debugging) - non-minified and non-mangled"});this.force=ge.Boolean("-f,--force",!1,{description:"Always clone the repository instead of trying to fetch the latest commits"});this.name=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=typeof this.installPath<"u"?z.resolve(this.context.cwd,le.toPortablePath(this.installPath)):z.resolve(le.toPortablePath((0,ide.tmpdir)()),"yarnpkg-sources",wn.makeHash(this.repository).slice(0,6));return(await Lt.start({configuration:r,stdout:this.context.stdout},async n=>{let{project:u}=await St.find(r,this.context.cwd),A=W.parseIdent(this.name.replace(/^((@yarnpkg\/)?plugin-)?/,"@yarnpkg/plugin-")),p=W.stringifyIdent(A),h=await Xd(r,rn);if(!Object.hasOwn(h,p))throw new Jt(51,`Couldn't find a plugin named "${p}" on the remote registry. Note that only the plugins referenced on our website (https://github.com/yarnpkg/berry/blob/master/plugins.yml) can be built and imported from sources.`);let E=p;await M8(this,{configuration:r,report:n,target:o}),await U8(E,this,{project:u,report:n,target:o})})).exitCode()}};Xh.paths=[["plugin","import","from","sources"]],Xh.usage=nt.Usage({category:"Plugin-related commands",description:"build a plugin from sources",details:`
- This command clones the Yarn repository into a temporary folder, builds the specified contrib plugin and updates the configuration to reference it in further CLI invocations.
-
- The plugins can be referenced by their short name if sourced from the official Yarn repository.
- `,examples:[['Build and activate the "@yarnpkg/plugin-exec" plugin',"$0 plugin import from sources @yarnpkg/plugin-exec"],['Build and activate the "@yarnpkg/plugin-exec" plugin (shorthand)',"$0 plugin import from sources exec"]]});async function U8(t,{context:e,noMinify:r},{project:o,report:a,target:n}){let u=t.replace(/@yarnpkg\//,""),{configuration:A}=o;a.reportSeparator(),a.reportInfo(0,`Building a fresh ${u}`),a.reportSeparator(),await E2(rgt({pluginName:u,noMinify:r},n),{configuration:A,context:e,target:n}),a.reportSeparator();let p=z.resolve(n,`packages/${u}/bundles/${t}.js`),h=await oe.readFilePromise(p);await _8(t,h,{project:o,report:a})}Ye();Pt();qt();var Zh=class extends ut{constructor(){super(...arguments);this.name=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);return(await Lt.start({configuration:r,stdout:this.context.stdout},async n=>{let u=this.name,A=W.parseIdent(u);if(!r.plugins.has(u))throw new it(`${W.prettyIdent(r,A)} isn't referenced by the current configuration`);let p=`.yarn/plugins/${u}.cjs`,h=z.resolve(o.cwd,p);oe.existsSync(h)&&(n.reportInfo(0,`Removing ${de.pretty(r,p,de.Type.PATH)}...`),await oe.removePromise(h)),n.reportInfo(0,"Updating the configuration..."),await Ke.updateConfiguration(o.cwd,{plugins:E=>{if(!Array.isArray(E))return E;let I=E.filter(v=>v.path!==p);return I.length===0?Ke.deleteProperty:I.length===E.length?E:I}})})).exitCode()}};Zh.paths=[["plugin","remove"]],Zh.usage=nt.Usage({category:"Plugin-related commands",description:"remove a plugin",details:`
- This command deletes the specified plugin from the .yarn/plugins folder and removes it from the configuration.
-
- **Note:** The plugins have to be referenced by their name property, which can be obtained using the \`yarn plugin runtime\` command. Shorthands are not allowed.
- `,examples:[["Remove a plugin imported from the Yarn repository","$0 plugin remove @yarnpkg/plugin-typescript"],["Remove a plugin imported from a local file","$0 plugin remove my-local-plugin"]]});Ye();qt();var $h=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);return(await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout},async a=>{for(let n of r.plugins.keys()){let u=this.context.plugins.plugins.has(n),A=n;u&&(A+=" [builtin]"),a.reportJson({name:n,builtin:u}),a.reportInfo(null,`${A}`)}})).exitCode()}};$h.paths=[["plugin","runtime"]],$h.usage=nt.Usage({category:"Plugin-related commands",description:"list the active plugins",details:`
- This command prints the currently active plugins. Will be displayed both builtin plugins and external plugins.
- `,examples:[["List the currently active plugins","$0 plugin runtime"]]});Ye();Ye();qt();var e0=class extends ut{constructor(){super(...arguments);this.idents=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);let u=new Set;for(let A of this.idents)u.add(W.parseIdent(A).identHash);if(await o.restoreInstallState({restoreResolutions:!1}),await o.resolveEverything({cache:n,report:new Qi}),u.size>0)for(let A of o.storedPackages.values())u.has(A.identHash)&&(o.storedBuildState.delete(A.locatorHash),o.skippedBuilds.delete(A.locatorHash));else o.storedBuildState.clear(),o.skippedBuilds.clear();return await o.installWithNewReport({stdout:this.context.stdout,quiet:this.context.quiet},{cache:n})}};e0.paths=[["rebuild"]],e0.usage=nt.Usage({description:"rebuild the project's native packages",details:`
- This command will automatically cause Yarn to forget about previous compilations of the given packages and to run them again.
-
- Note that while Yarn forgets the compilation, the previous artifacts aren't erased from the filesystem and may affect the next builds (in good or bad). To avoid this, you may remove the .yarn/unplugged folder, or any other relevant location where packages might have been stored (Yarn may offer a way to do that automatically in the future).
-
- By default all packages will be rebuilt, but you can filter the list by specifying the names of the packages you want to clear from memory.
- `,examples:[["Rebuild all packages","$0 rebuild"],["Rebuild fsevents only","$0 rebuild fsevents"]]});Ye();Ye();Ye();qt();var H8=$e(Zo());$a();var t0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Apply the operation to all workspaces from the current project"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:Ks(hl)});this.patterns=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=this.all?o.workspaces:[a],A=["dependencies","devDependencies","peerDependencies"],p=[],h=!1,E=[];for(let C of this.patterns){let R=!1,N=W.parseIdent(C);for(let U of u){let V=[...U.manifest.peerDependenciesMeta.keys()];for(let te of(0,H8.default)(V,C))U.manifest.peerDependenciesMeta.delete(te),h=!0,R=!0;for(let te of A){let ae=U.manifest.getForScope(te),fe=[...ae.values()].map(ue=>W.stringifyIdent(ue));for(let ue of(0,H8.default)(fe,W.stringifyIdent(N))){let{identHash:me}=W.parseIdent(ue),he=ae.get(me);if(typeof he>"u")throw new Error("Assertion failed: Expected the descriptor to be registered");U.manifest[te].delete(me),E.push([U,te,he]),h=!0,R=!0}}}R||p.push(C)}let I=p.length>1?"Patterns":"Pattern",v=p.length>1?"don't":"doesn't",x=this.all?"any":"this";if(p.length>0)throw new it(`${I} ${de.prettyList(r,p,de.Type.CODE)} ${v} match any packages referenced by ${x} workspace`);return h?(await r.triggerMultipleHooks(C=>C.afterWorkspaceDependencyRemoval,E),await o.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})):0}};t0.paths=[["remove"]],t0.usage=nt.Usage({description:"remove dependencies from the project",details:`
- This command will remove the packages matching the specified patterns from the current workspace.
-
- If the \`--mode=<mode>\` option is set, Yarn will change which artifacts are generated. The modes currently supported are:
-
- - \`skip-build\` will not run the build scripts at all. Note that this is different from setting \`enableScripts\` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.
-
- - \`update-lockfile\` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.
-
- This command accepts glob patterns as arguments (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.
- `,examples:[["Remove a dependency from the current project","$0 remove lodash"],["Remove a dependency from all workspaces at once","$0 remove lodash --all"],["Remove all dependencies starting with `eslint-`","$0 remove 'eslint-*'"],["Remove all dependencies with the `@babel` scope","$0 remove '@babel/*'"],["Remove all dependencies matching `react-dom` or `react-helmet`","$0 remove 'react-{dom,helmet}'"]]});Ye();Ye();qt();var sde=ve("util"),Zd=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);return(await Lt.start({configuration:r,stdout:this.context.stdout,json:this.json},async u=>{let A=a.manifest.scripts,p=_e.sortMap(A.keys(),I=>I),h={breakLength:1/0,colors:r.get("enableColors"),maxArrayLength:2},E=p.reduce((I,v)=>Math.max(I,v.length),0);for(let[I,v]of A.entries())u.reportInfo(null,`${I.padEnd(E," ")} ${(0,sde.inspect)(v,h)}`),u.reportJson({name:I,script:v})})).exitCode()}};Zd.paths=[["run"]];Ye();Ye();qt();var r0=class extends ut{constructor(){super(...arguments);this.inspect=ge.String("--inspect",!1,{tolerateBoolean:!0,description:"Forwarded to the underlying Node process when executing a binary"});this.inspectBrk=ge.String("--inspect-brk",!1,{tolerateBoolean:!0,description:"Forwarded to the underlying Node process when executing a binary"});this.topLevel=ge.Boolean("-T,--top-level",!1,{description:"Check the root workspace for scripts and/or binaries instead of the current one"});this.binariesOnly=ge.Boolean("-B,--binaries-only",!1,{description:"Ignore any user defined scripts and only check for binaries"});this.require=ge.String("--require",{description:"Forwarded to the underlying Node process when executing a binary"});this.silent=ge.Boolean("--silent",{hidden:!0});this.scriptName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a,locator:n}=await St.find(r,this.context.cwd);await o.restoreInstallState();let u=this.topLevel?o.topLevelWorkspace.anchoredLocator:n;if(!this.binariesOnly&&await un.hasPackageScript(u,this.scriptName,{project:o}))return await un.executePackageScript(u,this.scriptName,this.args,{project:o,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});let A=await un.getPackageAccessibleBinaries(u,{project:o});if(A.get(this.scriptName)){let h=[];return this.inspect&&(typeof this.inspect=="string"?h.push(`--inspect=${this.inspect}`):h.push("--inspect")),this.inspectBrk&&(typeof this.inspectBrk=="string"?h.push(`--inspect-brk=${this.inspectBrk}`):h.push("--inspect-brk")),this.require&&h.push(`--require=${this.require}`),await un.executePackageAccessibleBinary(u,this.scriptName,this.args,{cwd:this.context.cwd,project:o,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,nodeArgs:h,packageAccessibleBinaries:A})}if(!this.topLevel&&!this.binariesOnly&&a&&this.scriptName.includes(":")){let E=(await Promise.all(o.workspaces.map(async I=>I.manifest.scripts.has(this.scriptName)?I:null))).filter(I=>I!==null);if(E.length===1)return await un.executeWorkspaceScript(E[0],this.scriptName,this.args,{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})}if(this.topLevel)throw this.scriptName==="node-gyp"?new it(`Couldn't find a script name "${this.scriptName}" in the top-level (used by ${W.prettyLocator(r,n)}). This typically happens because some package depends on "node-gyp" to build itself, but didn't list it in their dependencies. To fix that, please run "yarn add node-gyp" into your top-level workspace. You also can open an issue on the repository of the specified package to suggest them to use an optional peer dependency.`):new it(`Couldn't find a script name "${this.scriptName}" in the top-level (used by ${W.prettyLocator(r,n)}).`);{if(this.scriptName==="global")throw new it("The 'yarn global' commands have been removed in 2.x - consider using 'yarn dlx' or a third-party plugin instead");let h=[this.scriptName].concat(this.args);for(let[E,I]of AC)for(let v of I)if(h.length>=v.length&&JSON.stringify(h.slice(0,v.length))===JSON.stringify(v))throw new it(`Couldn't find a script named "${this.scriptName}", but a matching command can be found in the ${E} plugin. You can install it with "yarn plugin import ${E}".`);throw new it(`Couldn't find a script named "${this.scriptName}".`)}}};r0.paths=[["run"]],r0.usage=nt.Usage({description:"run a script defined in the package.json",details:`
- This command will run a tool. The exact tool that will be executed will depend on the current state of your workspace:
-
- - If the \`scripts\` field from your local package.json contains a matching script name, its definition will get executed.
-
- - Otherwise, if one of the local workspace's dependencies exposes a binary with a matching name, this binary will get executed.
-
- - Otherwise, if the specified name contains a colon character and if one of the workspaces in the project contains exactly one script with a matching name, then this script will get executed.
-
- Whatever happens, the cwd of the spawned process will be the workspace that declares the script (which makes it possible to call commands cross-workspaces using the third syntax).
- `,examples:[["Run the tests from the local workspace","$0 run test"],['Same thing, but without the "run" keyword',"$0 test"],["Inspect Webpack while running","$0 run --inspect-brk webpack"]]});Ye();Ye();qt();var n0=class extends ut{constructor(){super(...arguments);this.descriptor=ge.String();this.resolution=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(await o.restoreInstallState({restoreResolutions:!1}),!a)throw new nr(o.cwd,this.context.cwd);let u=W.parseDescriptor(this.descriptor,!0),A=W.makeDescriptor(u,this.resolution);return o.storedDescriptors.set(u.descriptorHash,u),o.storedDescriptors.set(A.descriptorHash,A),o.resolutionAliases.set(u.descriptorHash,A.descriptorHash),await o.installWithNewReport({stdout:this.context.stdout},{cache:n})}};n0.paths=[["set","resolution"]],n0.usage=nt.Usage({description:"enforce a package resolution",details:'\n This command updates the resolution table so that `descriptor` is resolved by `resolution`.\n\n Note that by default this command only affect the current resolution table - meaning that this "manual override" will disappear if you remove the lockfile, or if the package disappear from the table. If you wish to make the enforced resolution persist whatever happens, edit the `resolutions` field in your top-level manifest.\n\n Note that no attempt is made at validating that `resolution` is a valid resolution entry for `descriptor`.\n ',examples:[["Force all instances of lodash@npm:^1.2.3 to resolve to 1.5.0","$0 set resolution lodash@npm:^1.2.3 1.5.0"]]});Ye();Pt();qt();var ode=$e(Zo()),i0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Unlink all workspaces belonging to the target project from the current one"});this.leadingArguments=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);let u=o.topLevelWorkspace,A=new Set;if(this.leadingArguments.length===0&&this.all)for(let{pattern:p,reference:h}of u.manifest.resolutions)h.startsWith("portal:")&&A.add(p.descriptor.fullName);if(this.leadingArguments.length>0)for(let p of this.leadingArguments){let h=z.resolve(this.context.cwd,le.toPortablePath(p));if(_e.isPathLike(p)){let E=await Ke.find(h,this.context.plugins,{useRc:!1,strict:!1}),{project:I,workspace:v}=await St.find(E,h);if(!v)throw new nr(I.cwd,h);if(this.all){for(let x of I.workspaces)x.manifest.name&&A.add(W.stringifyIdent(x.anchoredLocator));if(A.size===0)throw new it("No workspace found to be unlinked in the target project")}else{if(!v.manifest.name)throw new it("The target workspace doesn't have a name and thus cannot be unlinked");A.add(W.stringifyIdent(v.anchoredLocator))}}else{let E=[...u.manifest.resolutions.map(({pattern:I})=>I.descriptor.fullName)];for(let I of(0,ode.default)(E,p))A.add(I)}}return u.manifest.resolutions=u.manifest.resolutions.filter(({pattern:p})=>!A.has(p.descriptor.fullName)),await o.installWithNewReport({stdout:this.context.stdout,quiet:this.context.quiet},{cache:n})}};i0.paths=[["unlink"]],i0.usage=nt.Usage({description:"disconnect the local project from another one",details:`
- This command will remove any resolutions in the project-level manifest that would have been added via a yarn link with similar arguments.
- `,examples:[["Unregister a remote workspace in the current project","$0 unlink ~/ts-loader"],["Unregister all workspaces from a remote project in the current project","$0 unlink ~/jest --all"],["Unregister all previously linked workspaces","$0 unlink --all"],["Unregister all workspaces matching a glob","$0 unlink '@babel/*' 'pkg-{a,b}'"]]});Ye();Ye();Ye();qt();var ade=$e(f2()),q8=$e(Zo());$a();var Vf=class extends ut{constructor(){super(...arguments);this.interactive=ge.Boolean("-i,--interactive",{description:"Offer various choices, depending on the detected upgrade paths"});this.fixed=ge.Boolean("-F,--fixed",!1,{description:"Store dependency tags as-is instead of resolving them"});this.exact=ge.Boolean("-E,--exact",!1,{description:"Don't use any semver modifier on the resolved range"});this.tilde=ge.Boolean("-T,--tilde",!1,{description:"Use the `~` semver modifier on the resolved range"});this.caret=ge.Boolean("-C,--caret",!1,{description:"Use the `^` semver modifier on the resolved range"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Resolve again ALL resolutions for those packages"});this.mode=ge.String("--mode",{description:"Change what artifacts installs generate",validator:Ks(hl)});this.patterns=ge.Rest()}async execute(){return this.recursive?await this.executeUpRecursive():await this.executeUpClassic()}async executeUpRecursive(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=[...o.storedDescriptors.values()],A=u.map(E=>W.stringifyIdent(E)),p=new Set;for(let E of this.patterns){if(W.parseDescriptor(E).range!=="unknown")throw new it("Ranges aren't allowed when using --recursive");for(let I of(0,q8.default)(A,E)){let v=W.parseIdent(I);p.add(v.identHash)}}let h=u.filter(E=>p.has(E.identHash));for(let E of h)o.storedDescriptors.delete(E.descriptorHash),o.storedResolutions.delete(E.descriptorHash);return await o.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})}async executeUpClassic(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=this.fixed,A=this.interactive??r.get("preferInteractive"),p=h2(this,o),h=A?["keep","reuse","project","latest"]:["project","latest"],E=[],I=[];for(let N of this.patterns){let U=!1,V=W.parseDescriptor(N),te=W.stringifyIdent(V);for(let ae of o.workspaces)for(let fe of["dependencies","devDependencies"]){let me=[...ae.manifest.getForScope(fe).values()].map(Be=>W.stringifyIdent(Be)),he=te==="*"?me:(0,q8.default)(me,te);for(let Be of he){let we=W.parseIdent(Be),g=ae.manifest[fe].get(we.identHash);if(typeof g>"u")throw new Error("Assertion failed: Expected the descriptor to be registered");let Ee=W.makeDescriptor(we,V.range);E.push(Promise.resolve().then(async()=>[ae,fe,g,await g2(Ee,{project:o,workspace:ae,cache:n,target:fe,fixed:u,modifier:p,strategies:h})])),U=!0}}U||I.push(N)}if(I.length>1)throw new it(`Patterns ${de.prettyList(r,I,de.Type.CODE)} don't match any packages referenced by any workspace`);if(I.length>0)throw new it(`Pattern ${de.prettyList(r,I,de.Type.CODE)} doesn't match any packages referenced by any workspace`);let v=await Promise.all(E),x=await fA.start({configuration:r,stdout:this.context.stdout,suggestInstall:!1},async N=>{for(let[,,U,{suggestions:V,rejections:te}]of v){let ae=V.filter(fe=>fe.descriptor!==null);if(ae.length===0){let[fe]=te;if(typeof fe>"u")throw new Error("Assertion failed: Expected an error to have been set");let ue=this.cli.error(fe);o.configuration.get("enableNetwork")?N.reportError(27,`${W.prettyDescriptor(r,U)} can't be resolved to a satisfying range
-
-${ue}`):N.reportError(27,`${W.prettyDescriptor(r,U)} can't be resolved to a satisfying range (note: network resolution has been disabled)
-
-${ue}`)}else ae.length>1&&!A&&N.reportError(27,`${W.prettyDescriptor(r,U)} has multiple possible upgrade strategies; use -i to disambiguate manually`)}});if(x.hasErrors())return x.exitCode();let C=!1,R=[];for(let[N,U,,{suggestions:V}]of v){let te,ae=V.filter(he=>he.descriptor!==null),fe=ae[0].descriptor,ue=ae.every(he=>W.areDescriptorsEqual(he.descriptor,fe));ae.length===1||ue?te=fe:(C=!0,{answer:te}=await(0,ade.prompt)({type:"select",name:"answer",message:`Which range do you want to use in ${W.prettyWorkspace(r,N)} \u276F ${U}?`,choices:V.map(({descriptor:he,name:Be,reason:we})=>he?{name:Be,hint:we,descriptor:he}:{name:Be,hint:we,disabled:!0}),onCancel:()=>process.exit(130),result(he){return this.find(he,"descriptor")},stdin:this.context.stdin,stdout:this.context.stdout}));let me=N.manifest[U].get(te.identHash);if(typeof me>"u")throw new Error("Assertion failed: This descriptor should have a matching entry");if(me.descriptorHash!==te.descriptorHash)N.manifest[U].set(te.identHash,te),R.push([N,U,me,te]);else{let he=r.makeResolver(),Be={project:o,resolver:he},we=r.normalizeDependency(me),g=he.bindDescriptor(we,N.anchoredLocator,Be);o.forgetResolution(g)}}return await r.triggerMultipleHooks(N=>N.afterWorkspaceDependencyReplacement,R),C&&this.context.stdout.write(`
-`),await o.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})}};Vf.paths=[["up"]],Vf.usage=nt.Usage({description:"upgrade dependencies across the project",details:"\n This command upgrades the packages matching the list of specified patterns to their latest available version across the whole project (regardless of whether they're part of `dependencies` or `devDependencies` - `peerDependencies` won't be affected). This is a project-wide command: all workspaces will be upgraded in the process.\n\n If `-R,--recursive` is set the command will change behavior and no other switch will be allowed. When operating under this mode `yarn up` will force all ranges matching the selected packages to be resolved again (often to the highest available versions) before being stored in the lockfile. It however won't touch your manifests anymore, so depending on your needs you might want to run both `yarn up` and `yarn up -R` to cover all bases.\n\n If `-i,--interactive` is set (or if the `preferInteractive` settings is toggled on) the command will offer various choices, depending on the detected upgrade paths. Some upgrades require this flag in order to resolve ambiguities.\n\n The, `-C,--caret`, `-E,--exact` and `-T,--tilde` options have the same meaning as in the `add` command (they change the modifier used when the range is missing or a tag, and are ignored when the range is explicitly set).\n\n If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n\n Generally you can see `yarn up` as a counterpart to what was `yarn upgrade --latest` in Yarn 1 (ie it ignores the ranges previously listed in your manifests), but unlike `yarn upgrade` which only upgraded dependencies in the current workspace, `yarn up` will upgrade all workspaces at the same time.\n\n This command accepts glob patterns as arguments (if valid Descriptors and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n\n **Note:** The ranges have to be static, only the package scopes and names can contain glob patterns.\n ",examples:[["Upgrade all instances of lodash to the latest release","$0 up lodash"],["Upgrade all instances of lodash to the latest release, but ask confirmation for each","$0 up lodash -i"],["Upgrade all instances of lodash to 1.2.3","$0 up lodash@1.2.3"],["Upgrade all instances of packages with the `@babel` scope to the latest release","$0 up '@babel/*'"],["Upgrade all instances of packages containing the word `jest` to the latest release","$0 up '*jest*'"],["Upgrade all instances of packages with the `@babel` scope to 7.0.0","$0 up '@babel/*@7.0.0'"]]}),Vf.schema=[cI("recursive",Yu.Forbids,["interactive","exact","tilde","caret"],{ignore:[void 0,!1]})];Ye();Ye();Ye();qt();var s0=class extends ut{constructor(){super(...arguments);this.recursive=ge.Boolean("-R,--recursive",!1,{description:"List, for each workspace, what are all the paths that lead to the dependency"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.peers=ge.Boolean("--peers",!1,{description:"Also print the peer dependencies that match the specified name"});this.package=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=W.parseIdent(this.package).identHash,u=this.recursive?igt(o,n,{configuration:r,peers:this.peers}):ngt(o,n,{configuration:r,peers:this.peers});$s.emitTree(u,{configuration:r,stdout:this.context.stdout,json:this.json,separators:1})}};s0.paths=[["why"]],s0.usage=nt.Usage({description:"display the reason why a package is needed",details:`
- This command prints the exact reasons why a package appears in the dependency tree.
-
- If \`-R,--recursive\` is set, the listing will go in depth and will list, for each workspaces, what are all the paths that lead to the dependency. Note that the display is somewhat optimized in that it will not print the package listing twice for a single package, so if you see a leaf named "Foo" when looking for "Bar", it means that "Foo" already got printed higher in the tree.
- `,examples:[["Explain why lodash is used in your project","$0 why lodash"]]});function ngt(t,e,{configuration:r,peers:o}){let a=_e.sortMap(t.storedPackages.values(),A=>W.stringifyLocator(A)),n={},u={children:n};for(let A of a){let p={};for(let E of A.dependencies.values()){if(!o&&A.peerDependencies.has(E.identHash))continue;let I=t.storedResolutions.get(E.descriptorHash);if(!I)throw new Error("Assertion failed: The resolution should have been registered");let v=t.storedPackages.get(I);if(!v)throw new Error("Assertion failed: The package should have been registered");if(v.identHash!==e)continue;{let C=W.stringifyLocator(A);n[C]={value:[A,de.Type.LOCATOR],children:p}}let x=W.stringifyLocator(v);p[x]={value:[{descriptor:E,locator:v},de.Type.DEPENDENT]}}}return u}function igt(t,e,{configuration:r,peers:o}){let a=_e.sortMap(t.workspaces,v=>W.stringifyLocator(v.anchoredLocator)),n=new Set,u=new Set,A=v=>{if(n.has(v.locatorHash))return u.has(v.locatorHash);if(n.add(v.locatorHash),v.identHash===e)return u.add(v.locatorHash),!0;let x=!1;v.identHash===e&&(x=!0);for(let C of v.dependencies.values()){if(!o&&v.peerDependencies.has(C.identHash))continue;let R=t.storedResolutions.get(C.descriptorHash);if(!R)throw new Error("Assertion failed: The resolution should have been registered");let N=t.storedPackages.get(R);if(!N)throw new Error("Assertion failed: The package should have been registered");A(N)&&(x=!0)}return x&&u.add(v.locatorHash),x};for(let v of a)A(v.anchoredPackage);let p=new Set,h={},E={children:h},I=(v,x,C)=>{if(!u.has(v.locatorHash))return;let R=C!==null?de.tuple(de.Type.DEPENDENT,{locator:v,descriptor:C}):de.tuple(de.Type.LOCATOR,v),N={},U={value:R,children:N},V=W.stringifyLocator(v);if(x[V]=U,!(C!==null&&t.tryWorkspaceByLocator(v))&&!p.has(v.locatorHash)){p.add(v.locatorHash);for(let te of v.dependencies.values()){if(!o&&v.peerDependencies.has(te.identHash))continue;let ae=t.storedResolutions.get(te.descriptorHash);if(!ae)throw new Error("Assertion failed: The resolution should have been registered");let fe=t.storedPackages.get(ae);if(!fe)throw new Error("Assertion failed: The package should have been registered");I(fe,N,te)}}};for(let v of a)I(v.anchoredPackage,h,null);return E}Ye();var Z8={};zt(Z8,{GitFetcher:()=>w2,GitResolver:()=>I2,default:()=>Dgt,gitUtils:()=>ra});Ye();Pt();var ra={};zt(ra,{TreeishProtocols:()=>C2,clone:()=>X8,fetchBase:()=>xde,fetchChangedFiles:()=>kde,fetchChangedWorkspaces:()=>Bgt,fetchRoot:()=>bde,isGitUrl:()=>CC,lsRemote:()=>Sde,normalizeLocator:()=>Igt,normalizeRepoUrl:()=>yC,resolveUrl:()=>J8,splitRepoUrl:()=>o0,validateRepoUrl:()=>V8});Ye();Pt();qt();var vde=$e(wde()),Dde=$e(mU()),EC=$e(ve("querystring")),K8=$e(Jn());function W8(t,e,r){let o=t.indexOf(r);return t.lastIndexOf(e,o>-1?o:1/0)}function Ide(t){try{return new URL(t)}catch{return}}function Cgt(t){let e=W8(t,"@","#"),r=W8(t,":","#");return r>e&&(t=`${t.slice(0,r)}/${t.slice(r+1)}`),W8(t,":","#")===-1&&t.indexOf("//")===-1&&(t=`ssh://${t}`),t}function Bde(t){return Ide(t)||Ide(Cgt(t))}function yC(t,{git:e=!1}={}){if(t=t.replace(/^git\+https:/,"https:"),t=t.replace(/^(?:github:|https:\/\/github\.com\/|git:\/\/github\.com\/)?(?!\.{1,2}\/)([a-zA-Z0-9._-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)(?:\.git)?(#.*)?$/,"https://github.com/$1/$2.git$3"),t=t.replace(/^https:\/\/github\.com\/(?!\.{1,2}\/)([a-zA-Z0-9._-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)\/tarball\/(.+)?$/,"https://github.com/$1/$2.git#$3"),e){let r=Bde(t);r&&(t=r.href),t=t.replace(/^git\+([^:]+):/,"$1:")}return t}function Pde(){return{...process.env,GIT_SSH_COMMAND:process.env.GIT_SSH_COMMAND||`${process.env.GIT_SSH||"ssh"} -o BatchMode=yes`}}var wgt=[/^ssh:/,/^git(?:\+[^:]+)?:/,/^(?:git\+)?https?:[^#]+\/[^#]+(?:\.git)(?:#.*)?$/,/^git@[^#]+\/[^#]+\.git(?:#.*)?$/,/^(?:github:|https:\/\/github\.com\/)?(?!\.{1,2}\/)([a-zA-Z._0-9-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z._0-9-]+?)(?:\.git)?(?:#.*)?$/,/^https:\/\/github\.com\/(?!\.{1,2}\/)([a-zA-Z0-9._-]+)\/(?!\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)\/tarball\/(.+)?$/],C2=(a=>(a.Commit="commit",a.Head="head",a.Tag="tag",a.Semver="semver",a))(C2||{});function CC(t){return t?wgt.some(e=>!!t.match(e)):!1}function o0(t){t=yC(t);let e=t.indexOf("#");if(e===-1)return{repo:t,treeish:{protocol:"head",request:"HEAD"},extra:{}};let r=t.slice(0,e),o=t.slice(e+1);if(o.match(/^[a-z]+=/)){let a=EC.default.parse(o);for(let[p,h]of Object.entries(a))if(typeof h!="string")throw new Error(`Assertion failed: The ${p} parameter must be a literal string`);let n=Object.values(C2).find(p=>Object.hasOwn(a,p)),[u,A]=typeof n<"u"?[n,a[n]]:["head","HEAD"];for(let p of Object.values(C2))delete a[p];return{repo:r,treeish:{protocol:u,request:A},extra:a}}else{let a=o.indexOf(":"),[n,u]=a===-1?[null,o]:[o.slice(0,a),o.slice(a+1)];return{repo:r,treeish:{protocol:n,request:u},extra:{}}}}function Igt(t){return W.makeLocator(t,yC(t.reference))}function V8(t,{configuration:e}){let r=yC(t,{git:!0});if(!nn.getNetworkSettings(`https://${(0,vde.default)(r).resource}`,{configuration:e}).enableNetwork)throw new Jt(80,`Request to '${r}' has been blocked because of your configuration settings`);return r}async function Sde(t,e){let r=V8(t,{configuration:e}),o=await z8("listing refs",["ls-remote",r],{cwd:e.startingCwd,env:Pde()},{configuration:e,normalizedRepoUrl:r}),a=new Map,n=/^([a-f0-9]{40})\t([^\n]+)/gm,u;for(;(u=n.exec(o.stdout))!==null;)a.set(u[2],u[1]);return a}async function J8(t,e){let{repo:r,treeish:{protocol:o,request:a},extra:n}=o0(t),u=await Sde(r,e),A=(h,E)=>{switch(h){case"commit":{if(!E.match(/^[a-f0-9]{40}$/))throw new Error("Invalid commit hash");return EC.default.stringify({...n,commit:E})}case"head":{let I=u.get(E==="HEAD"?E:`refs/heads/${E}`);if(typeof I>"u")throw new Error(`Unknown head ("${E}")`);return EC.default.stringify({...n,commit:I})}case"tag":{let I=u.get(`refs/tags/${E}`);if(typeof I>"u")throw new Error(`Unknown tag ("${E}")`);return EC.default.stringify({...n,commit:I})}case"semver":{let I=kr.validRange(E);if(!I)throw new Error(`Invalid range ("${E}")`);let v=new Map([...u.entries()].filter(([C])=>C.startsWith("refs/tags/")).map(([C,R])=>[K8.default.parse(C.slice(10)),R]).filter(C=>C[0]!==null)),x=K8.default.maxSatisfying([...v.keys()],I);if(x===null)throw new Error(`No matching range ("${E}")`);return EC.default.stringify({...n,commit:v.get(x)})}case null:{let I;if((I=p("commit",E))!==null||(I=p("tag",E))!==null||(I=p("head",E))!==null)return I;throw E.match(/^[a-f0-9]+$/)?new Error(`Couldn't resolve "${E}" as either a commit, a tag, or a head - if a commit, use the 40-characters commit hash`):new Error(`Couldn't resolve "${E}" as either a commit, a tag, or a head`)}default:throw new Error(`Invalid Git resolution protocol ("${h}")`)}},p=(h,E)=>{try{return A(h,E)}catch{return null}};return yC(`${r}#${A(o,a)}`)}async function X8(t,e){return await e.getLimit("cloneConcurrency")(async()=>{let{repo:r,treeish:{protocol:o,request:a}}=o0(t);if(o!=="commit")throw new Error("Invalid treeish protocol when cloning");let n=V8(r,{configuration:e}),u=await oe.mktempPromise(),A={cwd:u,env:Pde()};return await z8("cloning the repository",["clone","-c core.autocrlf=false",n,le.fromPortablePath(u)],A,{configuration:e,normalizedRepoUrl:n}),await z8("switching branch",["checkout",`${a}`],A,{configuration:e,normalizedRepoUrl:n}),u})}async function bde(t){let e,r=t;do{if(e=r,await oe.existsPromise(z.join(e,".git")))return e;r=z.dirname(e)}while(r!==e);return null}async function xde(t,{baseRefs:e}){if(e.length===0)throw new it("Can't run this command with zero base refs specified.");let r=[];for(let A of e){let{code:p}=await Ur.execvp("git",["merge-base",A,"HEAD"],{cwd:t});p===0&&r.push(A)}if(r.length===0)throw new it(`No ancestor could be found between any of HEAD and ${e.join(", ")}`);let{stdout:o}=await Ur.execvp("git",["merge-base","HEAD",...r],{cwd:t,strict:!0}),a=o.trim(),{stdout:n}=await Ur.execvp("git",["show","--quiet","--pretty=format:%s",a],{cwd:t,strict:!0}),u=n.trim();return{hash:a,title:u}}async function kde(t,{base:e,project:r}){let o=_e.buildIgnorePattern(r.configuration.get("changesetIgnorePatterns")),{stdout:a}=await Ur.execvp("git",["diff","--name-only",`${e}`],{cwd:t,strict:!0}),n=a.split(/\r\n|\r|\n/).filter(h=>h.length>0).map(h=>z.resolve(t,le.toPortablePath(h))),{stdout:u}=await Ur.execvp("git",["ls-files","--others","--exclude-standard"],{cwd:t,strict:!0}),A=u.split(/\r\n|\r|\n/).filter(h=>h.length>0).map(h=>z.resolve(t,le.toPortablePath(h))),p=[...new Set([...n,...A].sort())];return o?p.filter(h=>!z.relative(r.cwd,h).match(o)):p}async function Bgt({ref:t,project:e}){if(e.configuration.projectCwd===null)throw new it("This command can only be run from within a Yarn project");let r=[z.resolve(e.cwd,dr.lockfile),z.resolve(e.cwd,e.configuration.get("cacheFolder")),z.resolve(e.cwd,e.configuration.get("installStatePath")),z.resolve(e.cwd,e.configuration.get("virtualFolder"))];await e.configuration.triggerHook(u=>u.populateYarnPaths,e,u=>{u!=null&&r.push(u)});let o=await bde(e.configuration.projectCwd);if(o==null)throw new it("This command can only be run on Git repositories");let a=await xde(o,{baseRefs:typeof t=="string"?[t]:e.configuration.get("changesetBaseRefs")}),n=await kde(o,{base:a.hash,project:e});return new Set(_e.mapAndFilter(n,u=>{let A=e.tryWorkspaceByFilePath(u);return A===null?_e.mapAndFilter.skip:r.some(p=>u.startsWith(p))?_e.mapAndFilter.skip:A}))}async function z8(t,e,r,{configuration:o,normalizedRepoUrl:a}){try{return await Ur.execvp("git",e,{...r,strict:!0})}catch(n){if(!(n instanceof Ur.ExecError))throw n;let u=n.reportExtra,A=n.stderr.toString();throw new Jt(1,`Failed ${t}`,p=>{p.reportError(1,` ${de.prettyField(o,{label:"Repository URL",value:de.tuple(de.Type.URL,a)})}`);for(let h of A.matchAll(/^(.+?): (.*)$/gm)){let[,E,I]=h;E=E.toLowerCase();let v=E==="error"?"Error":`${(0,Dde.default)(E)} Error`;p.reportError(1,` ${de.prettyField(o,{label:v,value:de.tuple(de.Type.NO_HINT,I)})}`)}u?.(p)})}}var w2=class{supports(e,r){return CC(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,a=new Map(r.checksums);a.set(e.locatorHash,o);let n={...r,checksums:a},u=await this.downloadHosted(e,n);if(u!==null)return u;let[A,p,h]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote repository`),loader:()=>this.cloneFromRemote(e,n),...r.cacheOptions});return{packageFs:A,releaseFs:p,prefixPath:W.getIdentVendorPath(e),checksum:h}}async downloadHosted(e,r){return r.project.configuration.reduceHook(o=>o.fetchHostedRepository,null,e,r)}async cloneFromRemote(e,r){let o=await X8(e.reference,r.project.configuration),a=o0(e.reference),n=z.join(o,"package.tgz");await un.prepareExternalProject(o,n,{configuration:r.project.configuration,report:r.report,workspace:a.extra.workspace,locator:e});let u=await oe.readFilePromise(n);return await _e.releaseAfterUseAsync(async()=>await Xi.convertToZip(u,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1}))}};Ye();Ye();var I2=class{supportsDescriptor(e,r){return CC(e.range)}supportsLocator(e,r){return CC(e.reference)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=await J8(e.range,o.project.configuration);return[W.makeLocator(e,a)]}async getSatisfying(e,r,o,a){let n=o0(e.range);return{locators:o.filter(A=>{if(A.identHash!==e.identHash)return!1;let p=o0(A.reference);return!(n.repo!==p.repo||n.treeish.protocol==="commit"&&n.treeish.request!==p.treeish.request)}),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await _e.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var vgt={configuration:{changesetBaseRefs:{description:"The base git refs that the current HEAD is compared against when detecting changes. Supports git branches, tags, and commits.",type:"STRING",isArray:!0,isNullable:!1,default:["master","origin/master","upstream/master","main","origin/main","upstream/main"]},changesetIgnorePatterns:{description:"Array of glob patterns; files matching them will be ignored when fetching the changed files",type:"STRING",default:[],isArray:!0},cloneConcurrency:{description:"Maximal number of concurrent clones",type:"NUMBER",default:2}},fetchers:[w2],resolvers:[I2]};var Dgt=vgt;qt();var a0=class extends ut{constructor(){super(...arguments);this.since=ge.String("--since",{description:"Only include workspaces that have been changed since the specified ref.",tolerateBoolean:!0});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Find packages via dependencies/devDependencies instead of using the workspaces field"});this.noPrivate=ge.Boolean("--no-private",{description:"Exclude workspaces that have the private field set to true"});this.verbose=ge.Boolean("-v,--verbose",!1,{description:"Also return the cross-dependencies between workspaces"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);return(await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout},async n=>{let u=this.since?await ra.fetchChangedWorkspaces({ref:this.since,project:o}):o.workspaces,A=new Set(u);if(this.recursive)for(let p of[...u].map(h=>h.getRecursiveWorkspaceDependents()))for(let h of p)A.add(h);for(let p of A){let{manifest:h}=p;if(h.private&&this.noPrivate)continue;let E;if(this.verbose){let I=new Set,v=new Set;for(let x of Ot.hardDependencies)for(let[C,R]of h.getForScope(x)){let N=o.tryWorkspaceByDescriptor(R);N===null?o.workspacesByIdent.has(C)&&v.add(R):I.add(N)}E={workspaceDependencies:Array.from(I).map(x=>x.relativeCwd),mismatchedWorkspaceDependencies:Array.from(v).map(x=>W.stringifyDescriptor(x))}}n.reportInfo(null,`${p.relativeCwd}`),n.reportJson({location:p.relativeCwd,name:h.name?W.stringifyIdent(h.name):null,...E})}})).exitCode()}};a0.paths=[["workspaces","list"]],a0.usage=nt.Usage({category:"Workspace-related commands",description:"list all available workspaces",details:"\n This command will print the list of all workspaces in the project.\n\n - If `--since` is set, Yarn will only list workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\n\n - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\n\n - If `--no-private` is set, Yarn will not list any workspaces that have the `private` field set to `true`.\n\n - If both the `-v,--verbose` and `--json` options are set, Yarn will also return the cross-dependencies between each workspaces (useful when you wish to automatically generate Buck / Bazel rules).\n "});Ye();Ye();qt();var l0=class extends ut{constructor(){super(...arguments);this.workspaceName=ge.String();this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);let n=o.workspaces,u=new Map(n.map(p=>[W.stringifyIdent(p.anchoredLocator),p])),A=u.get(this.workspaceName);if(A===void 0){let p=Array.from(u.keys()).sort();throw new it(`Workspace '${this.workspaceName}' not found. Did you mean any of the following:
- - ${p.join(`
- - `)}?`)}return this.cli.run([this.commandName,...this.args],{cwd:A.cwd})}};l0.paths=[["workspace"]],l0.usage=nt.Usage({category:"Workspace-related commands",description:"run a command within the specified workspace",details:`
- This command will run a given sub-command on a single workspace.
- `,examples:[["Add a package to a single workspace","yarn workspace components add -D react"],["Run build script on a single workspace","yarn workspace components run build"]]});var Pgt={configuration:{enableImmutableInstalls:{description:"If true (the default on CI), prevents the install command from modifying the lockfile",type:"BOOLEAN",default:Qde.isCI},defaultSemverRangePrefix:{description:"The default save prefix: '^', '~' or ''",type:"STRING",values:["^","~",""],default:"^"},preferReuse:{description:"If true, `yarn add` will attempt to reuse the most common dependency range in other workspaces.",type:"BOOLEAN",default:!1}},commands:[Rh,Th,Lh,Nh,n0,Vh,Hh,a0,zd,Vd,mC,Jd,Qh,Fh,Oh,Mh,Uh,_h,qh,Gh,jh,Yh,i0,Wh,Kh,Xh,Jh,Zh,zh,$h,e0,t0,Zd,r0,Vf,s0,l0]},Sgt=Pgt;var iH={};zt(iH,{default:()=>xgt});Ye();var kt={optional:!0},eH=[["@tailwindcss/aspect-ratio@<0.2.1",{peerDependencies:{tailwindcss:"^2.0.2"}}],["@tailwindcss/line-clamp@<0.2.1",{peerDependencies:{tailwindcss:"^2.0.2"}}],["@fullhuman/postcss-purgecss@3.1.3 || 3.1.3-alpha.0",{peerDependencies:{postcss:"^8.0.0"}}],["@samverschueren/stream-to-observable@<0.3.1",{peerDependenciesMeta:{rxjs:kt,zenObservable:kt}}],["any-observable@<0.5.1",{peerDependenciesMeta:{rxjs:kt,zenObservable:kt}}],["@pm2/agent@<1.0.4",{dependencies:{debug:"*"}}],["debug@<4.2.0",{peerDependenciesMeta:{["supports-color"]:kt}}],["got@<11",{dependencies:{["@types/responselike"]:"^1.0.0",["@types/keyv"]:"^3.1.1"}}],["cacheable-lookup@<4.1.2",{dependencies:{["@types/keyv"]:"^3.1.1"}}],["http-link-dataloader@*",{peerDependencies:{graphql:"^0.13.1 || ^14.0.0"}}],["typescript-language-server@*",{dependencies:{["vscode-jsonrpc"]:"^5.0.1",["vscode-languageserver-protocol"]:"^3.15.0"}}],["postcss-syntax@*",{peerDependenciesMeta:{["postcss-html"]:kt,["postcss-jsx"]:kt,["postcss-less"]:kt,["postcss-markdown"]:kt,["postcss-scss"]:kt}}],["jss-plugin-rule-value-function@<=10.1.1",{dependencies:{["tiny-warning"]:"^1.0.2"}}],["ink-select-input@<4.1.0",{peerDependencies:{react:"^16.8.2"}}],["license-webpack-plugin@<2.3.18",{peerDependenciesMeta:{webpack:kt}}],["snowpack@>=3.3.0",{dependencies:{["node-gyp"]:"^7.1.0"}}],["promise-inflight@*",{peerDependenciesMeta:{bluebird:kt}}],["reactcss@*",{peerDependencies:{react:"*"}}],["react-color@<=2.19.0",{peerDependencies:{react:"*"}}],["gatsby-plugin-i18n@*",{dependencies:{ramda:"^0.24.1"}}],["useragent@^2.0.0",{dependencies:{request:"^2.88.0",yamlparser:"0.0.x",semver:"5.5.x"}}],["@apollographql/apollo-tools@<=0.5.2",{peerDependencies:{graphql:"^14.2.1 || ^15.0.0"}}],["material-table@^2.0.0",{dependencies:{"@babel/runtime":"^7.11.2"}}],["@babel/parser@*",{dependencies:{"@babel/types":"^7.8.3"}}],["fork-ts-checker-webpack-plugin@<=6.3.4",{peerDependencies:{eslint:">= 6",typescript:">= 2.7",webpack:">= 4","vue-template-compiler":"*"},peerDependenciesMeta:{eslint:kt,"vue-template-compiler":kt}}],["rc-animate@<=3.1.1",{peerDependencies:{react:">=16.9.0","react-dom":">=16.9.0"}}],["react-bootstrap-table2-paginator@*",{dependencies:{classnames:"^2.2.6"}}],["react-draggable@<=4.4.3",{peerDependencies:{react:">= 16.3.0","react-dom":">= 16.3.0"}}],["apollo-upload-client@<14",{peerDependencies:{graphql:"14 - 15"}}],["react-instantsearch-core@<=6.7.0",{peerDependencies:{algoliasearch:">= 3.1 < 5"}}],["react-instantsearch-dom@<=6.7.0",{dependencies:{"react-fast-compare":"^3.0.0"}}],["ws@<7.2.1",{peerDependencies:{bufferutil:"^4.0.1","utf-8-validate":"^5.0.2"},peerDependenciesMeta:{bufferutil:kt,"utf-8-validate":kt}}],["react-portal@<4.2.2",{peerDependencies:{"react-dom":"^15.0.0-0 || ^16.0.0-0 || ^17.0.0-0"}}],["react-scripts@<=4.0.1",{peerDependencies:{react:"*"}}],["testcafe@<=1.10.1",{dependencies:{"@babel/plugin-transform-for-of":"^7.12.1","@babel/runtime":"^7.12.5"}}],["testcafe-legacy-api@<=4.2.0",{dependencies:{"testcafe-hammerhead":"^17.0.1","read-file-relative":"^1.2.0"}}],["@google-cloud/firestore@<=4.9.3",{dependencies:{protobufjs:"^6.8.6"}}],["gatsby-source-apiserver@*",{dependencies:{["babel-polyfill"]:"^6.26.0"}}],["@webpack-cli/package-utils@<=1.0.1-alpha.4",{dependencies:{["cross-spawn"]:"^7.0.3"}}],["gatsby-remark-prismjs@<3.3.28",{dependencies:{lodash:"^4"}}],["gatsby-plugin-favicon@*",{peerDependencies:{webpack:"*"}}],["gatsby-plugin-sharp@<=4.6.0-next.3",{dependencies:{debug:"^4.3.1"}}],["gatsby-react-router-scroll@<=5.6.0-next.0",{dependencies:{["prop-types"]:"^15.7.2"}}],["@rebass/forms@*",{dependencies:{["@styled-system/should-forward-prop"]:"^5.0.0"},peerDependencies:{react:"^16.8.6"}}],["rebass@*",{peerDependencies:{react:"^16.8.6"}}],["@ant-design/react-slick@<=0.28.3",{peerDependencies:{react:">=16.0.0"}}],["mqtt@<4.2.7",{dependencies:{duplexify:"^4.1.1"}}],["vue-cli-plugin-vuetify@<=2.0.3",{dependencies:{semver:"^6.3.0"},peerDependenciesMeta:{"sass-loader":kt,"vuetify-loader":kt}}],["vue-cli-plugin-vuetify@<=2.0.4",{dependencies:{"null-loader":"^3.0.0"}}],["vue-cli-plugin-vuetify@>=2.4.3",{peerDependencies:{vue:"*"}}],["@vuetify/cli-plugin-utils@<=0.0.4",{dependencies:{semver:"^6.3.0"},peerDependenciesMeta:{"sass-loader":kt}}],["@vue/cli-plugin-typescript@<=5.0.0-alpha.0",{dependencies:{"babel-loader":"^8.1.0"}}],["@vue/cli-plugin-typescript@<=5.0.0-beta.0",{dependencies:{"@babel/core":"^7.12.16"},peerDependencies:{"vue-template-compiler":"^2.0.0"},peerDependenciesMeta:{"vue-template-compiler":kt}}],["cordova-ios@<=6.3.0",{dependencies:{underscore:"^1.9.2"}}],["cordova-lib@<=10.0.1",{dependencies:{underscore:"^1.9.2"}}],["git-node-fs@*",{peerDependencies:{"js-git":"^0.7.8"},peerDependenciesMeta:{"js-git":kt}}],["consolidate@<0.16.0",{peerDependencies:{mustache:"^3.0.0"},peerDependenciesMeta:{mustache:kt}}],["consolidate@<=0.16.0",{peerDependencies:{velocityjs:"^2.0.1",tinyliquid:"^0.2.34","liquid-node":"^3.0.1",jade:"^1.11.0","then-jade":"*",dust:"^0.3.0","dustjs-helpers":"^1.7.4","dustjs-linkedin":"^2.7.5",swig:"^1.4.2","swig-templates":"^2.0.3","razor-tmpl":"^1.3.1",atpl:">=0.7.6",liquor:"^0.0.5",twig:"^1.15.2",ejs:"^3.1.5",eco:"^1.1.0-rc-3",jazz:"^0.0.18",jqtpl:"~1.1.0",hamljs:"^0.6.2",hamlet:"^0.3.3",whiskers:"^0.4.0","haml-coffee":"^1.14.1","hogan.js":"^3.0.2",templayed:">=0.2.3",handlebars:"^4.7.6",underscore:"^1.11.0",lodash:"^4.17.20",pug:"^3.0.0","then-pug":"*",qejs:"^3.0.5",walrus:"^0.10.1",mustache:"^4.0.1",just:"^0.1.8",ect:"^0.5.9",mote:"^0.2.0",toffee:"^0.3.6",dot:"^1.1.3","bracket-template":"^1.1.5",ractive:"^1.3.12",nunjucks:"^3.2.2",htmling:"^0.0.8","babel-core":"^6.26.3",plates:"~0.4.11","react-dom":"^16.13.1",react:"^16.13.1","arc-templates":"^0.5.3",vash:"^0.13.0",slm:"^2.0.0",marko:"^3.14.4",teacup:"^2.0.0","coffee-script":"^1.12.7",squirrelly:"^5.1.0",twing:"^5.0.2"},peerDependenciesMeta:{velocityjs:kt,tinyliquid:kt,"liquid-node":kt,jade:kt,"then-jade":kt,dust:kt,"dustjs-helpers":kt,"dustjs-linkedin":kt,swig:kt,"swig-templates":kt,"razor-tmpl":kt,atpl:kt,liquor:kt,twig:kt,ejs:kt,eco:kt,jazz:kt,jqtpl:kt,hamljs:kt,hamlet:kt,whiskers:kt,"haml-coffee":kt,"hogan.js":kt,templayed:kt,handlebars:kt,underscore:kt,lodash:kt,pug:kt,"then-pug":kt,qejs:kt,walrus:kt,mustache:kt,just:kt,ect:kt,mote:kt,toffee:kt,dot:kt,"bracket-template":kt,ractive:kt,nunjucks:kt,htmling:kt,"babel-core":kt,plates:kt,"react-dom":kt,react:kt,"arc-templates":kt,vash:kt,slm:kt,marko:kt,teacup:kt,"coffee-script":kt,squirrelly:kt,twing:kt}}],["vue-loader@<=16.3.3",{peerDependencies:{"@vue/compiler-sfc":"^3.0.8",webpack:"^4.1.0 || ^5.0.0-0"},peerDependenciesMeta:{"@vue/compiler-sfc":kt}}],["vue-loader@^16.7.0",{peerDependencies:{"@vue/compiler-sfc":"^3.0.8",vue:"^3.2.13"},peerDependenciesMeta:{"@vue/compiler-sfc":kt,vue:kt}}],["scss-parser@<=1.0.5",{dependencies:{lodash:"^4.17.21"}}],["query-ast@<1.0.5",{dependencies:{lodash:"^4.17.21"}}],["redux-thunk@<=2.3.0",{peerDependencies:{redux:"^4.0.0"}}],["skypack@<=0.3.2",{dependencies:{tar:"^6.1.0"}}],["@npmcli/metavuln-calculator@<2.0.0",{dependencies:{"json-parse-even-better-errors":"^2.3.1"}}],["bin-links@<2.3.0",{dependencies:{"mkdirp-infer-owner":"^1.0.2"}}],["rollup-plugin-polyfill-node@<=0.8.0",{peerDependencies:{rollup:"^1.20.0 || ^2.0.0"}}],["snowpack@<3.8.6",{dependencies:{"magic-string":"^0.25.7"}}],["elm-webpack-loader@*",{dependencies:{temp:"^0.9.4"}}],["winston-transport@<=4.4.0",{dependencies:{logform:"^2.2.0"}}],["jest-vue-preprocessor@*",{dependencies:{"@babel/core":"7.8.7","@babel/template":"7.8.6"},peerDependencies:{pug:"^2.0.4"},peerDependenciesMeta:{pug:kt}}],["redux-persist@*",{peerDependencies:{react:">=16"},peerDependenciesMeta:{react:kt}}],["sodium@>=3",{dependencies:{"node-gyp":"^3.8.0"}}],["babel-plugin-graphql-tag@<=3.1.0",{peerDependencies:{graphql:"^14.0.0 || ^15.0.0"}}],["@playwright/test@<=1.14.1",{dependencies:{"jest-matcher-utils":"^26.4.2"}}],...["babel-plugin-remove-graphql-queries@<3.14.0-next.1","babel-preset-gatsby-package@<1.14.0-next.1","create-gatsby@<1.14.0-next.1","gatsby-admin@<0.24.0-next.1","gatsby-cli@<3.14.0-next.1","gatsby-core-utils@<2.14.0-next.1","gatsby-design-tokens@<3.14.0-next.1","gatsby-legacy-polyfills@<1.14.0-next.1","gatsby-plugin-benchmark-reporting@<1.14.0-next.1","gatsby-plugin-graphql-config@<0.23.0-next.1","gatsby-plugin-image@<1.14.0-next.1","gatsby-plugin-mdx@<2.14.0-next.1","gatsby-plugin-netlify-cms@<5.14.0-next.1","gatsby-plugin-no-sourcemaps@<3.14.0-next.1","gatsby-plugin-page-creator@<3.14.0-next.1","gatsby-plugin-preact@<5.14.0-next.1","gatsby-plugin-preload-fonts@<2.14.0-next.1","gatsby-plugin-schema-snapshot@<2.14.0-next.1","gatsby-plugin-styletron@<6.14.0-next.1","gatsby-plugin-subfont@<3.14.0-next.1","gatsby-plugin-utils@<1.14.0-next.1","gatsby-recipes@<0.25.0-next.1","gatsby-source-shopify@<5.6.0-next.1","gatsby-source-wikipedia@<3.14.0-next.1","gatsby-transformer-screenshot@<3.14.0-next.1","gatsby-worker@<0.5.0-next.1"].map(t=>[t,{dependencies:{"@babel/runtime":"^7.14.8"}}]),["gatsby-core-utils@<2.14.0-next.1",{dependencies:{got:"8.3.2"}}],["gatsby-plugin-gatsby-cloud@<=3.1.0-next.0",{dependencies:{"gatsby-core-utils":"^2.13.0-next.0"}}],["gatsby-plugin-gatsby-cloud@<=3.2.0-next.1",{peerDependencies:{webpack:"*"}}],["babel-plugin-remove-graphql-queries@<=3.14.0-next.1",{dependencies:{"gatsby-core-utils":"^2.8.0-next.1"}}],["gatsby-plugin-netlify@3.13.0-next.1",{dependencies:{"gatsby-core-utils":"^2.13.0-next.0"}}],["clipanion-v3-codemod@<=0.2.0",{peerDependencies:{jscodeshift:"^0.11.0"}}],["react-live@*",{peerDependencies:{"react-dom":"*",react:"*"}}],["webpack@<4.44.1",{peerDependenciesMeta:{"webpack-cli":kt,"webpack-command":kt}}],["webpack@<5.0.0-beta.23",{peerDependenciesMeta:{"webpack-cli":kt}}],["webpack-dev-server@<3.10.2",{peerDependenciesMeta:{"webpack-cli":kt}}],["@docusaurus/responsive-loader@<1.5.0",{peerDependenciesMeta:{sharp:kt,jimp:kt}}],["eslint-module-utils@*",{peerDependenciesMeta:{"eslint-import-resolver-node":kt,"eslint-import-resolver-typescript":kt,"eslint-import-resolver-webpack":kt,"@typescript-eslint/parser":kt}}],["eslint-plugin-import@*",{peerDependenciesMeta:{"@typescript-eslint/parser":kt}}],["critters-webpack-plugin@<3.0.2",{peerDependenciesMeta:{"html-webpack-plugin":kt}}],["terser@<=5.10.0",{dependencies:{acorn:"^8.5.0"}}],["babel-preset-react-app@10.0.x <10.0.2",{dependencies:{"@babel/plugin-proposal-private-property-in-object":"^7.16.7"}}],["eslint-config-react-app@*",{peerDependenciesMeta:{typescript:kt}}],["@vue/eslint-config-typescript@<11.0.0",{peerDependenciesMeta:{typescript:kt}}],["unplugin-vue2-script-setup@<0.9.1",{peerDependencies:{"@vue/composition-api":"^1.4.3","@vue/runtime-dom":"^3.2.26"}}],["@cypress/snapshot@*",{dependencies:{debug:"^3.2.7"}}],["auto-relay@<=0.14.0",{peerDependencies:{"reflect-metadata":"^0.1.13"}}],["vue-template-babel-compiler@<1.2.0",{peerDependencies:{["vue-template-compiler"]:"^2.6.0"}}],["@parcel/transformer-image@<2.5.0",{peerDependencies:{["@parcel/core"]:"*"}}],["@parcel/transformer-js@<2.5.0",{peerDependencies:{["@parcel/core"]:"*"}}],["parcel@*",{peerDependenciesMeta:{["@parcel/core"]:kt}}],["react-scripts@*",{peerDependencies:{eslint:"*"}}],["focus-trap-react@^8.0.0",{dependencies:{tabbable:"^5.3.2"}}],["react-rnd@<10.3.7",{peerDependencies:{react:">=16.3.0","react-dom":">=16.3.0"}}],["connect-mongo@<5.0.0",{peerDependencies:{"express-session":"^1.17.1"}}],["vue-i18n@<9",{peerDependencies:{vue:"^2"}}],["vue-router@<4",{peerDependencies:{vue:"^2"}}],["unified@<10",{dependencies:{"@types/unist":"^2.0.0"}}],["react-github-btn@<=1.3.0",{peerDependencies:{react:">=16.3.0"}}],["react-dev-utils@*",{peerDependencies:{typescript:">=2.7",webpack:">=4"},peerDependenciesMeta:{typescript:kt}}],["@asyncapi/react-component@<=1.0.0-next.39",{peerDependencies:{react:">=16.8.0","react-dom":">=16.8.0"}}],["xo@*",{peerDependencies:{webpack:">=1.11.0"},peerDependenciesMeta:{webpack:kt}}],["babel-plugin-remove-graphql-queries@<=4.20.0-next.0",{dependencies:{"@babel/types":"^7.15.4"}}],["gatsby-plugin-page-creator@<=4.20.0-next.1",{dependencies:{"fs-extra":"^10.1.0"}}],["gatsby-plugin-utils@<=3.14.0-next.1",{dependencies:{fastq:"^1.13.0"},peerDependencies:{graphql:"^15.0.0"}}],["gatsby-plugin-mdx@<3.1.0-next.1",{dependencies:{mkdirp:"^1.0.4"}}],["gatsby-plugin-mdx@^2",{peerDependencies:{gatsby:"^3.0.0-next"}}],["fdir@<=5.2.0",{peerDependencies:{picomatch:"2.x"},peerDependenciesMeta:{picomatch:kt}}],["babel-plugin-transform-typescript-metadata@<=0.3.2",{peerDependencies:{"@babel/core":"^7","@babel/traverse":"^7"},peerDependenciesMeta:{"@babel/traverse":kt}}],["graphql-compose@>=9.0.10",{peerDependencies:{graphql:"^14.2.0 || ^15.0.0 || ^16.0.0"}}],["vite-plugin-vuetify@<=1.0.2",{peerDependencies:{vue:"^3.0.0"}}],["webpack-plugin-vuetify@<=2.0.1",{peerDependencies:{vue:"^3.2.6"}}],["eslint-import-resolver-vite@<2.0.1",{dependencies:{debug:"^4.3.4",resolve:"^1.22.8"}}]];var tH;function Fde(){return typeof tH>"u"&&(tH=ve("zlib").brotliDecompressSync(Buffer.from("G7weAByFTVk3Vs7UfHhq4yykgEM7pbW7TI43SG2S5tvGrwHBAzdz+s/npQ6tgEvobvxisrPIadkXeUAJotBn5bDZ5kAhcRqsIHe3F75Walet5hNalwgFDtxb0BiDUjiUQkjG0yW2hto9HPgiCkm316d6bC0kST72YN7D7rfkhCE9x4J0XwB0yavalxpUu2t9xszHrmtwalOxT7VslsxWcB1qpqZwERUra4psWhTV8BgwWeizurec82Caf1ABL11YMfbf8FJ9JBceZOkgmvrQPbC9DUldX/yMbmX06UQluCEjSwUoyO+EZPIjofr+/oAZUck2enraRD+oWLlnlYnj8xB+gwSo9lmmks4fXv574qSqcWA6z21uYkzMu3EWj+K23RxeQlLqiE35/rC8GcS4CGkKHKKq+zAIQwD9iRDNfiAqueLLpicFFrNsAI4zeTD/eO9MHcnRa5m8UT+M2+V+AkFST4BlKneiAQRSdST8KEAIyFlULt6wa9EBd0Ds28VmpaxquJdVt+nwdEs5xUskI13OVtFyY0UrQIRAlCuvvWivvlSKQfTO+2Q8OyUR1W5RvetaPz4jD27hdtwHFFA1Ptx6Ee/t2cY2rg2G46M1pNDRf2pWhvpy8pqMnuI3++4OF3+7OFIWXGjh+o7Nr2jNvbiYcQdQS1h903/jVFgOpA0yJ78z+x759bFA0rq+6aY5qPB4FzS3oYoLupDUhD9nDz6F6H7hpnlMf18KNKDu4IKjTWwrAnY6MFQw1W6ymOALHlFyCZmQhldg1MQHaMVVQTVgDC60TfaBqG++Y8PEoFhN/PBTZT175KNP/BlHDYGOOBmnBdzqJKplZ/ljiVG0ZBzfqeBRrrUkn6rA54462SgiliKoYVnbeptMdXNfAuaupIEi0bApF10TlgHfmEJAPUVidRVFyDupSem5po5vErPqWKhKbUIp0LozpYsIKK57dM/HKr+nguF+7924IIWMICkQ8JUigs9D+W+c4LnNoRtPPKNRUiCYmP+Jfo2lfKCKw8qpraEeWU3uiNRO6zcyKQoXPR5htmzzLznke7b4YbXW3I1lIRzmgG02Udb58U+7TpwyN7XymCgH+wuPDthZVQvRZuEP+SnLtMicz9m5zASWOBiAcLmkuFlTKuHspSIhCBD0yUPKcxu81A+4YD78rA2vtwsUEday9WNyrShyrl60rWmA+SmbYZkQOwFJWArxRYYc5jGhA5ikxYw1rx3ei4NmeX/lKiwpZ9Ln1tV2Ae7sArvxuVLbJjqJRjW1vFXAyHpvLG+8MJ6T2Ubx5M2KDa2SN6vuIGxJ9WQM9Mk3Q7aCNiZONXllhqq24DmoLbQfW2rYWsOgHWjtOmIQMyMKdiHZDjoyIq5+U700nZ6odJAoYXPQBvFNiQ78d5jaXliBqLTJEqUCwi+LiH2mx92EmNKDsJL74Z613+3lf20pxkV1+erOrjj8pW00vsPaahKUM+05ssd5uwM7K482KWEf3TCwlg/o3e5ngto7qSMz7YteIgCsF1UOcsLk7F7MxWbvrPMY473ew0G+noVL8EPbkmEMftMSeL6HFub/zy+2JQ==","base64")).toString()),tH}var rH;function Rde(){return typeof rH>"u"&&(rH=ve("zlib").brotliDecompressSync(Buffer.from("G8MSIIzURnVBnObTcvb3XE6v2S9Qgc2K801Oa5otNKEtK8BINZNcaQHy+9/vf/WXBimwutXC33P2DPc64pps5rz7NGGWaOKNSPL4Y2KRE8twut2lFOIN+OXPtRmPMRhMTILib2bEQx43az2I5d3YS8Roa5UZpF/ujHb3Djd3GDvYUfvFYSUQ39vb2cmifp/rgB4J/65JK3wRBTvMBoNBmn3mbXC63/gbBkW/2IRPri0O8bcsRBsmarF328pAln04nyJFkwUAvNu934supAqLtyerZZpJ8I8suJHhf/ocMV+scKwa8NOiDKIPXw6Ex/EEZD6TEGaW8N5zvNHYF10l6Lfooj7D5W2k3dgvQSbp2Wv8TGOayS978gxlOLVjTGXs66ozewbrjwElLtyrYNnWTfzzdEutgROUFPVMhnMoy8EjJLLlWwIEoySxliim9kYW30JUHiPVyjt0iAw/ZpPmCbUCltYPnq6ZNblIKhTNhqS/oqC9iya5sGKZTOVsTEg34n92uZTf2iPpcZih8rPW8CzA+adIGmyCPcKdLMsBLShd+zuEbTrqpwuh+DLmracZcjPC5Sdf5odDAhKpFuOsQS67RT+1VgWWygSv3YwxDnylc04/PYuaMeIzhBkLrvs7e/OUzRTF56MmfY6rI63QtEjEQzq637zQqJ39nNhu3NmoRRhW/086bHGBUtx0PE0j3aEGvkdh9WJC8y8j8mqqke9/dQ5la+Q3ba4RlhvTbnfQhPDDab3tUifkjKuOsp13mXEmO00Mu88F/M67R7LXfoFDFLNtgCSWjWX+3Jn1371pJTK9xPBiMJafvDjtFyAzu8rxeQ0TKMQXNPs5xxiBOd+BRJP8KP88XPtJIbZKh/cdW8KvBUkpqKpGoiIaA32c3/JnQr4efXt85mXvidOvn/eU3Pase1typLYBalJ14mCso9h79nuMOuCa/kZAOkJHmTjP5RM2WNoPasZUAnT1TAE/NH25hUxcQv6hQWR/m1PKk4ooXMcM4SR1iYU3fUohvqk4RY2hbmTVVIXv6TvqO+0doOjgeVFAcom+RlwJQmOVH7pr1Q9LoJT6n1DeQEB+NHygsATbIwTcOKZlJsY8G4+suX1uQLjUWwLjjs0mvSvZcLTpIGAekeR7GCgl8eo3ndAqEe2XCav4huliHjdbIPBsGJuPX7lrO9HX1UbXRH5opOe1x6JsOSgHZR+EaxuXVhpLLxm6jk1LJtZfHSc6BKPun3CpYYVMJGwEUyk8MTGG0XL5MfEwaXpnc9TKnBmlGn6nHiGREc3ysn47XIBDzA+YvFdjZzVIEDcKGpS6PbUJehFRjEne8D0lVU1XuRtlgszq6pTNlQ/3MzNOEgCWPyTct22V2mEi2krizn5VDo9B19/X2DB3hCGRMM7ONbtnAcIx/OWB1u5uPbW1gsH8irXxT/IzG0PoXWYjhbMsH3KTuoOl5o17PulcgvsfTSnKFM354GWI8luqZnrswWjiXy3G+Vbyo1KMopFmmvBwNELgaS8z8dNZchx/Cl/xjddxhMcyqtzFyONb2Zdu90NkI8pAeufe7YlXrp53v8Dj/l8vWeVspRKBGXScBBPI/HinSTGmLDOGGOCIyH0JFdOZx0gWsacNlQLJMIrBhqRxXxHF/5pseWwejlAAvZ3klZSDSYY8mkToaWejXhgNomeGtx1DTLEUFMRkgF5yFB22WYdJnaWN14r1YJj81hGi45+jrADS5nYRhCiSlCJJ1nL8pYX+HDSMhdTEWyRcgHVp/IsUIZYMfT+YYncUQPgcxNGCHfZ88vDdrcUuaGIl6zhAsiaq7R5dfqrqXH/JcBhfjT8D0azayIyEz75Nxp6YkcyDxlJq3EXnJUpqDohJJOysL1t1uNiHESlvsxPb5cpbW0+ICZqJmUZus1BMW0F5IVBODLIo2zHHjA0=","base64")).toString()),rH}var nH;function Tde(){return typeof nH>"u"&&(nH=ve("zlib").brotliDecompressSync(Buffer.from("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","base64")).toString()),nH}var Lde=new Map([[W.makeIdent(null,"fsevents").identHash,Fde],[W.makeIdent(null,"resolve").identHash,Rde],[W.makeIdent(null,"typescript").identHash,Tde]]),bgt={hooks:{registerPackageExtensions:async(t,e)=>{for(let[r,o]of eH)e(W.parseDescriptor(r,!0),o)},getBuiltinPatch:async(t,e)=>{let r="compat/";if(!e.startsWith(r))return;let o=W.parseIdent(e.slice(r.length)),a=Lde.get(o.identHash)?.();return typeof a<"u"?a:null},reduceDependency:async(t,e,r,o)=>typeof Lde.get(t.identHash)>"u"?t:W.makeDescriptor(t,W.makeRange({protocol:"patch:",source:W.stringifyDescriptor(t),selector:`optional!builtin<compat/${W.stringifyIdent(t)}>`,params:null}))}},xgt=bgt;var wH={};zt(wH,{ConstraintsCheckCommand:()=>g0,ConstraintsQueryCommand:()=>p0,ConstraintsSourceCommand:()=>h0,default:()=>rdt});Ye();Ye();v2();var IC=class{constructor(e){this.project=e}createEnvironment(){let e=new wC(["cwd","ident"]),r=new wC(["workspace","type","ident"]),o=new wC(["ident"]),a={manifestUpdates:new Map,reportedErrors:new Map},n=new Map,u=new Map;for(let A of this.project.storedPackages.values()){let p=Array.from(A.peerDependencies.values(),h=>[W.stringifyIdent(h),h.range]);n.set(A.locatorHash,{workspace:null,ident:W.stringifyIdent(A),version:A.version,dependencies:new Map,peerDependencies:new Map(p.filter(([h])=>A.peerDependenciesMeta.get(h)?.optional!==!0)),optionalPeerDependencies:new Map(p.filter(([h])=>A.peerDependenciesMeta.get(h)?.optional===!0))})}for(let A of this.project.storedPackages.values()){let p=n.get(A.locatorHash);p.dependencies=new Map(Array.from(A.dependencies.values(),h=>{let E=this.project.storedResolutions.get(h.descriptorHash);if(typeof E>"u")throw new Error("Assertion failed: The resolution should have been registered");let I=n.get(E);if(typeof I>"u")throw new Error("Assertion failed: The package should have been registered");return[W.stringifyIdent(h),I]})),p.dependencies.delete(p.ident)}for(let A of this.project.workspaces){let p=W.stringifyIdent(A.anchoredLocator),h=A.manifest.exportTo({}),E=n.get(A.anchoredLocator.locatorHash);if(typeof E>"u")throw new Error("Assertion failed: The package should have been registered");let I=(R,N,{caller:U=Vi.getCaller()}={})=>{let V=B2(R),te=_e.getMapWithDefault(a.manifestUpdates,A.cwd),ae=_e.getMapWithDefault(te,V),fe=_e.getSetWithDefault(ae,N);U!==null&&fe.add(U)},v=R=>I(R,void 0,{caller:Vi.getCaller()}),x=R=>{_e.getArrayWithDefault(a.reportedErrors,A.cwd).push(R)},C=e.insert({cwd:A.relativeCwd,ident:p,manifest:h,pkg:E,set:I,unset:v,error:x});u.set(A,C);for(let R of Ot.allDependencies)for(let N of A.manifest[R].values()){let U=W.stringifyIdent(N),V=()=>{I([R,U],void 0,{caller:Vi.getCaller()})},te=fe=>{I([R,U],fe,{caller:Vi.getCaller()})},ae=null;if(R!=="peerDependencies"&&(R!=="dependencies"||!A.manifest.devDependencies.has(N.identHash))){let fe=A.anchoredPackage.dependencies.get(N.identHash);if(fe){if(typeof fe>"u")throw new Error("Assertion failed: The dependency should have been registered");let ue=this.project.storedResolutions.get(fe.descriptorHash);if(typeof ue>"u")throw new Error("Assertion failed: The resolution should have been registered");let me=n.get(ue);if(typeof me>"u")throw new Error("Assertion failed: The package should have been registered");ae=me}}r.insert({workspace:C,ident:U,range:N.range,type:R,resolution:ae,update:te,delete:V,error:x})}}for(let A of this.project.storedPackages.values()){let p=this.project.tryWorkspaceByLocator(A);if(!p)continue;let h=u.get(p);if(typeof h>"u")throw new Error("Assertion failed: The workspace should have been registered");let E=n.get(A.locatorHash);if(typeof E>"u")throw new Error("Assertion failed: The package should have been registered");E.workspace=h}return{workspaces:e,dependencies:r,packages:o,result:a}}async process(){let e=this.createEnvironment(),r={Yarn:{workspace:a=>e.workspaces.find(a)[0]??null,workspaces:a=>e.workspaces.find(a),dependency:a=>e.dependencies.find(a)[0]??null,dependencies:a=>e.dependencies.find(a),package:a=>e.packages.find(a)[0]??null,packages:a=>e.packages.find(a)}},o=await this.project.loadUserConfig();return o?.constraints?(await o.constraints(r),e.result):null}};Ye();Ye();qt();var p0=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.query=ge.String()}async execute(){let{Constraints:r}=await Promise.resolve().then(()=>(x2(),b2)),o=await Ke.find(this.context.cwd,this.context.plugins),{project:a}=await St.find(o,this.context.cwd),n=await r.find(a),u=this.query;return u.endsWith(".")||(u=`${u}.`),(await Lt.start({configuration:o,json:this.json,stdout:this.context.stdout},async p=>{for await(let h of n.query(u)){let E=Array.from(Object.entries(h)),I=E.length,v=E.reduce((x,[C])=>Math.max(x,C.length),0);for(let x=0;x<I;x++){let[C,R]=E[x];p.reportInfo(null,`${edt(x,I)}${C.padEnd(v," ")} = ${$gt(R)}`)}p.reportJson(h)}})).exitCode()}};p0.paths=[["constraints","query"]],p0.usage=nt.Usage({category:"Constraints-related commands",description:"query the constraints fact database",details:`
- This command will output all matches to the given prolog query.
- `,examples:[["List all dependencies throughout the workspace","yarn constraints query 'workspace_has_dependency(_, DependencyName, _, _).'"]]});function $gt(t){return typeof t!="string"?`${t}`:t.match(/^[a-zA-Z][a-zA-Z0-9_]+$/)?t:`'${t}'`}function edt(t,e){let r=t===0,o=t===e-1;return r&&o?"":r?"\u250C ":o?"\u2514 ":"\u2502 "}Ye();qt();var h0=class extends ut{constructor(){super(...arguments);this.verbose=ge.Boolean("-v,--verbose",!1,{description:"Also print the fact database automatically compiled from the workspace manifests"})}async execute(){let{Constraints:r}=await Promise.resolve().then(()=>(x2(),b2)),o=await Ke.find(this.context.cwd,this.context.plugins),{project:a}=await St.find(o,this.context.cwd),n=await r.find(a);this.context.stdout.write(this.verbose?n.fullSource:n.source)}};h0.paths=[["constraints","source"]],h0.usage=nt.Usage({category:"Constraints-related commands",description:"print the source code for the constraints",details:"\n This command will print the Prolog source code used by the constraints engine. Adding the `-v,--verbose` flag will print the *full* source code, including the fact database automatically compiled from the workspace manifests.\n ",examples:[["Prints the source code","yarn constraints source"],["Print the source code and the fact database","yarn constraints source -v"]]});Ye();Ye();qt();v2();var g0=class extends ut{constructor(){super(...arguments);this.fix=ge.Boolean("--fix",!1,{description:"Attempt to automatically fix unambiguous issues, following a multi-pass process"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);await o.restoreInstallState();let a=await o.loadUserConfig(),n;if(a?.constraints)n=new IC(o);else{let{Constraints:h}=await Promise.resolve().then(()=>(x2(),b2));n=await h.find(o)}let u,A=!1,p=!1;for(let h=this.fix?10:1;h>0;--h){let E=await n.process();if(!E)break;let{changedWorkspaces:I,remainingErrors:v}=gk(o,E,{fix:this.fix}),x=[];for(let[C,R]of I){let N=C.manifest.indent;C.manifest=new Ot,C.manifest.indent=N,C.manifest.load(R),x.push(C.persistManifest())}if(await Promise.all(x),!(I.size>0&&h>1)){u=qde(v,{configuration:r}),A=!1,p=!0;for(let[,C]of v)for(let R of C)R.fixable?A=!0:p=!1}}if(u.children.length===0)return 0;if(A){let h=p?`Those errors can all be fixed by running ${de.pretty(r,"yarn constraints --fix",de.Type.CODE)}`:`Errors prefixed by '\u2699' can be fixed by running ${de.pretty(r,"yarn constraints --fix",de.Type.CODE)}`;await Lt.start({configuration:r,stdout:this.context.stdout,includeNames:!1,includeFooter:!1},async E=>{E.reportInfo(0,h),E.reportSeparator()})}return u.children=_e.sortMap(u.children,h=>h.value[1]),$s.emitTree(u,{configuration:r,stdout:this.context.stdout,json:this.json,separators:1}),1}};g0.paths=[["constraints"]],g0.usage=nt.Usage({category:"Constraints-related commands",description:"check that the project constraints are met",details:`
- This command will run constraints on your project and emit errors for each one that is found but isn't met. If any error is emitted the process will exit with a non-zero exit code.
-
- If the \`--fix\` flag is used, Yarn will attempt to automatically fix the issues the best it can, following a multi-pass process (with a maximum of 10 iterations). Some ambiguous patterns cannot be autofixed, in which case you'll have to manually specify the right resolution.
-
- For more information as to how to write constraints, please consult our dedicated page on our website: https://yarnpkg.com/features/constraints.
- `,examples:[["Check that all constraints are satisfied","yarn constraints"],["Autofix all unmet constraints","yarn constraints --fix"]]});v2();var tdt={configuration:{enableConstraintsChecks:{description:"If true, constraints will run during installs",type:"BOOLEAN",default:!1},constraintsPath:{description:"The path of the constraints file.",type:"ABSOLUTE_PATH",default:"./constraints.pro"}},commands:[p0,h0,g0],hooks:{async validateProjectAfterInstall(t,{reportError:e}){if(!t.configuration.get("enableConstraintsChecks"))return;let r=await t.loadUserConfig(),o;if(r?.constraints)o=new IC(t);else{let{Constraints:u}=await Promise.resolve().then(()=>(x2(),b2));o=await u.find(t)}let a=await o.process();if(!a)return;let{remainingErrors:n}=gk(t,a);if(n.size!==0)if(t.configuration.isCI)for(let[u,A]of n)for(let p of A)e(84,`${de.pretty(t.configuration,u.anchoredLocator,de.Type.IDENT)}: ${p.text}`);else e(84,`Constraint check failed; run ${de.pretty(t.configuration,"yarn constraints",de.Type.CODE)} for more details`)}}},rdt=tdt;var IH={};zt(IH,{CreateCommand:()=>rm,DlxCommand:()=>d0,default:()=>idt});Ye();qt();var rm=class extends ut{constructor(){super(...arguments);this.pkg=ge.String("-p,--package",{description:"The package to run the provided command from"});this.quiet=ge.Boolean("-q,--quiet",!1,{description:"Only report critical errors instead of printing the full install logs"});this.command=ge.String();this.args=ge.Proxy()}async execute(){let r=[];this.pkg&&r.push("--package",this.pkg),this.quiet&&r.push("--quiet");let o=this.command.replace(/^(@[^@/]+)(@|$)/,"$1/create$2"),a=W.parseDescriptor(o),n=a.name.match(/^create(-|$)/)?a:a.scope?W.makeIdent(a.scope,`create-${a.name}`):W.makeIdent(null,`create-${a.name}`),u=W.stringifyIdent(n);return a.range!=="unknown"&&(u+=`@${a.range}`),this.cli.run(["dlx",...r,u,...this.args])}};rm.paths=[["create"]];Ye();Ye();Pt();qt();var d0=class extends ut{constructor(){super(...arguments);this.packages=ge.Array("-p,--package",{description:"The package(s) to install before running the command"});this.quiet=ge.Boolean("-q,--quiet",!1,{description:"Only report critical errors instead of printing the full install logs"});this.command=ge.String();this.args=ge.Proxy()}async execute(){return Ke.telemetry=null,await oe.mktempPromise(async r=>{let o=z.join(r,`dlx-${process.pid}`);await oe.mkdirPromise(o),await oe.writeFilePromise(z.join(o,"package.json"),`{}
-`),await oe.writeFilePromise(z.join(o,"yarn.lock"),"");let a=z.join(o,".yarnrc.yml"),n=await Ke.findProjectCwd(this.context.cwd),A={enableGlobalCache:!(await Ke.find(this.context.cwd,null,{strict:!1})).get("enableGlobalCache"),enableTelemetry:!1,logFilters:[{code:Ku(68),level:de.LogLevel.Discard}]},p=n!==null?z.join(n,".yarnrc.yml"):null;p!==null&&oe.existsSync(p)?(await oe.copyFilePromise(p,a),await Ke.updateConfiguration(o,N=>{let U=_e.toMerged(N,A);return Array.isArray(N.plugins)&&(U.plugins=N.plugins.map(V=>{let te=typeof V=="string"?V:V.path,ae=le.isAbsolute(te)?te:le.resolve(le.fromPortablePath(n),te);return typeof V=="string"?ae:{path:ae,spec:V.spec}})),U})):await oe.writeJsonPromise(a,A);let h=this.packages??[this.command],E=W.parseDescriptor(this.command).name,I=await this.cli.run(["add","--fixed","--",...h],{cwd:o,quiet:this.quiet});if(I!==0)return I;this.quiet||this.context.stdout.write(`
-`);let v=await Ke.find(o,this.context.plugins),{project:x,workspace:C}=await St.find(v,o);if(C===null)throw new nr(x.cwd,o);await x.restoreInstallState();let R=await un.getWorkspaceAccessibleBinaries(C);return R.has(E)===!1&&R.size===1&&typeof this.packages>"u"&&(E=Array.from(R)[0][0]),await un.executeWorkspaceAccessibleBinary(C,E,this.args,{packageAccessibleBinaries:R,cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})})}};d0.paths=[["dlx"]],d0.usage=nt.Usage({description:"run a package in a temporary environment",details:"\n This command will install a package within a temporary environment, and run its binary script if it contains any. The binary will run within the current cwd.\n\n By default Yarn will download the package named `command`, but this can be changed through the use of the `-p,--package` flag which will instruct Yarn to still run the same command but from a different package.\n\n Using `yarn dlx` as a replacement of `yarn add` isn't recommended, as it makes your project non-deterministic (Yarn doesn't keep track of the packages installed through `dlx` - neither their name, nor their version).\n ",examples:[["Use create-react-app to create a new React app","yarn dlx create-react-app ./my-app"],["Install multiple packages for a single command",`yarn dlx -p typescript -p ts-node ts-node --transpile-only -e "console.log('hello!')"`]]});var ndt={commands:[rm,d0]},idt=ndt;var DH={};zt(DH,{ExecFetcher:()=>Q2,ExecResolver:()=>F2,default:()=>adt,execUtils:()=>Ek});Ye();Ye();Pt();var pA="exec:";var Ek={};zt(Ek,{loadGeneratorFile:()=>k2,makeLocator:()=>vH,makeSpec:()=>hme,parseSpec:()=>BH});Ye();Pt();function BH(t){let{params:e,selector:r}=W.parseRange(t),o=le.toPortablePath(r);return{parentLocator:e&&typeof e.locator=="string"?W.parseLocator(e.locator):null,path:o}}function hme({parentLocator:t,path:e,generatorHash:r,protocol:o}){let a=t!==null?{locator:W.stringifyLocator(t)}:{},n=typeof r<"u"?{hash:r}:{};return W.makeRange({protocol:o,source:e,selector:e,params:{...n,...a}})}function vH(t,{parentLocator:e,path:r,generatorHash:o,protocol:a}){return W.makeLocator(t,hme({parentLocator:e,path:r,generatorHash:o,protocol:a}))}async function k2(t,e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(t,{protocol:e}),n=z.isAbsolute(a)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(o,r),u=n.localPath?{packageFs:new gn(Bt.root),prefixPath:z.relative(Bt.root,n.localPath)}:n;n!==u&&n.releaseFs&&n.releaseFs();let A=u.packageFs,p=z.join(u.prefixPath,a);return await A.readFilePromise(p,"utf8")}var Q2=class{supports(e,r){return!!e.reference.startsWith(pA)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:pA});if(z.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:z.resolve(n,a)}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:u}}async fetchFromDisk(e,r){let o=await k2(e.reference,pA,r);return oe.mktempPromise(async a=>{let n=z.join(a,"generator.js");return await oe.writeFilePromise(n,o),oe.mktempPromise(async u=>{if(await this.generatePackage(u,e,n,r),!oe.existsSync(z.join(u,"build")))throw new Error("The script should have generated a build directory");return await Xi.makeArchiveFromDirectory(z.join(u,"build"),{prefixPath:W.getIdentVendorPath(e),compressionLevel:r.project.configuration.get("compressionLevel")})})})}async generatePackage(e,r,o,a){return await oe.mktempPromise(async n=>{let u=await un.makeScriptEnv({project:a.project,binFolder:n}),A=z.join(e,"runtime.js");return await oe.mktempPromise(async p=>{let h=z.join(p,"buildfile.log"),E=z.join(e,"generator"),I=z.join(e,"build");await oe.mkdirPromise(E),await oe.mkdirPromise(I);let v={tempDir:le.fromPortablePath(E),buildDir:le.fromPortablePath(I),locator:W.stringifyLocator(r)};await oe.writeFilePromise(A,`
- // Expose 'Module' as a global variable
- Object.defineProperty(global, 'Module', {
- get: () => require('module'),
- configurable: true,
- enumerable: false,
- });
-
- // Expose non-hidden built-in modules as global variables
- for (const name of Module.builtinModules.filter((name) => name !== 'module' && !name.startsWith('_'))) {
- Object.defineProperty(global, name, {
- get: () => require(name),
- configurable: true,
- enumerable: false,
- });
- }
-
- // Expose the 'execEnv' global variable
- Object.defineProperty(global, 'execEnv', {
- value: {
- ...${JSON.stringify(v)},
- },
- enumerable: true,
- });
- `);let x=u.NODE_OPTIONS||"",C=/\s*--require\s+\S*\.pnp\.c?js\s*/g;x=x.replace(C," ").trim(),u.NODE_OPTIONS=x;let{stdout:R,stderr:N}=a.project.configuration.getSubprocessStreams(h,{header:`# This file contains the result of Yarn generating a package (${W.stringifyLocator(r)})
-`,prefix:W.prettyLocator(a.project.configuration,r),report:a.report}),{code:U}=await Ur.pipevp(process.execPath,["--require",le.fromPortablePath(A),le.fromPortablePath(o),W.stringifyIdent(r)],{cwd:e,env:u,stdin:null,stdout:R,stderr:N});if(U!==0)throw oe.detachTemp(p),new Error(`Package generation failed (exit code ${U}, logs can be found here: ${de.pretty(a.project.configuration,h,de.Type.PATH)})`)})})}};Ye();Ye();var sdt=2,F2=class{supportsDescriptor(e,r){return!!e.range.startsWith(pA)}supportsLocator(e,r){return!!e.reference.startsWith(pA)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let{path:a,parentLocator:n}=BH(e.range);if(n===null)throw new Error("Assertion failed: The descriptor should have been bound");let u=await k2(W.makeRange({protocol:pA,source:a,selector:a,params:{locator:W.stringifyLocator(n)}}),pA,o.fetchOptions),A=wn.makeHash(`${sdt}`,u).slice(0,6);return[vH(e,{parentLocator:n,path:a,generatorHash:A,protocol:pA})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await _e.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var odt={fetchers:[Q2],resolvers:[F2]},adt=odt;var SH={};zt(SH,{FileFetcher:()=>N2,FileResolver:()=>O2,TarballFileFetcher:()=>M2,TarballFileResolver:()=>U2,default:()=>udt,fileUtils:()=>nm});Ye();Pt();var PC=/^(?:[a-zA-Z]:[\\/]|\.{0,2}\/)/,R2=/^[^?]*\.(?:tar\.gz|tgz)(?:::.*)?$/,Ui="file:";var nm={};zt(nm,{fetchArchiveFromLocator:()=>L2,makeArchiveFromLocator:()=>Ck,makeBufferFromLocator:()=>PH,makeLocator:()=>SC,makeSpec:()=>gme,parseSpec:()=>T2});Ye();Pt();function T2(t){let{params:e,selector:r}=W.parseRange(t),o=le.toPortablePath(r);return{parentLocator:e&&typeof e.locator=="string"?W.parseLocator(e.locator):null,path:o}}function gme({parentLocator:t,path:e,hash:r,protocol:o}){let a=t!==null?{locator:W.stringifyLocator(t)}:{},n=typeof r<"u"?{hash:r}:{};return W.makeRange({protocol:o,source:e,selector:e,params:{...n,...a}})}function SC(t,{parentLocator:e,path:r,hash:o,protocol:a}){return W.makeLocator(t,gme({parentLocator:e,path:r,hash:o,protocol:a}))}async function L2(t,e){let{parentLocator:r,path:o}=W.parseFileStyleRange(t.reference,{protocol:Ui}),a=z.isAbsolute(o)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await e.fetcher.fetch(r,e),n=a.localPath?{packageFs:new gn(Bt.root),prefixPath:z.relative(Bt.root,a.localPath)}:a;a!==n&&a.releaseFs&&a.releaseFs();let u=n.packageFs,A=z.join(n.prefixPath,o);return await _e.releaseAfterUseAsync(async()=>await u.readFilePromise(A),n.releaseFs)}async function Ck(t,{protocol:e,fetchOptions:r,inMemory:o=!1}){let{parentLocator:a,path:n}=W.parseFileStyleRange(t.reference,{protocol:e}),u=z.isAbsolute(n)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(a,r),A=u.localPath?{packageFs:new gn(Bt.root),prefixPath:z.relative(Bt.root,u.localPath)}:u;u!==A&&u.releaseFs&&u.releaseFs();let p=A.packageFs,h=z.join(A.prefixPath,n);return await _e.releaseAfterUseAsync(async()=>await Xi.makeArchiveFromDirectory(h,{baseFs:p,prefixPath:W.getIdentVendorPath(t),compressionLevel:r.project.configuration.get("compressionLevel"),inMemory:o}),A.releaseFs)}async function PH(t,{protocol:e,fetchOptions:r}){return(await Ck(t,{protocol:e,fetchOptions:r,inMemory:!0})).getBufferAndClose()}var N2=class{supports(e,r){return!!e.reference.startsWith(Ui)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:Ui});if(z.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:z.resolve(n,a)}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:u}}async fetchFromDisk(e,r){return Ck(e,{protocol:Ui,fetchOptions:r})}};Ye();Ye();var ldt=2,O2=class{supportsDescriptor(e,r){return e.range.match(PC)?!0:!!e.range.startsWith(Ui)}supportsLocator(e,r){return!!e.reference.startsWith(Ui)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return PC.test(e.range)&&(e=W.makeDescriptor(e,`${Ui}${e.range}`)),W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let{path:a,parentLocator:n}=T2(e.range);if(n===null)throw new Error("Assertion failed: The descriptor should have been bound");let u=await PH(W.makeLocator(e,W.makeRange({protocol:Ui,source:a,selector:a,params:{locator:W.stringifyLocator(n)}})),{protocol:Ui,fetchOptions:o.fetchOptions}),A=wn.makeHash(`${ldt}`,u).slice(0,6);return[SC(e,{parentLocator:n,path:a,hash:A,protocol:Ui})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await _e.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};Ye();var M2=class{supports(e,r){return R2.test(e.reference)?!!e.reference.startsWith(Ui):!1}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromDisk(e,r){let o=await L2(e,r);return await Xi.convertToZip(o,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}};Ye();Ye();Ye();var U2=class{supportsDescriptor(e,r){return R2.test(e.range)?!!(e.range.startsWith(Ui)||PC.test(e.range)):!1}supportsLocator(e,r){return R2.test(e.reference)?!!e.reference.startsWith(Ui):!1}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return PC.test(e.range)&&(e=W.makeDescriptor(e,`${Ui}${e.range}`)),W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let{path:a,parentLocator:n}=T2(e.range);if(n===null)throw new Error("Assertion failed: The descriptor should have been bound");let u=SC(e,{parentLocator:n,path:a,hash:"",protocol:Ui}),A=await L2(u,o.fetchOptions),p=wn.makeHash(A).slice(0,6);return[SC(e,{parentLocator:n,path:a,hash:p,protocol:Ui})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await _e.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var cdt={fetchers:[M2,N2],resolvers:[U2,O2]},udt=cdt;var kH={};zt(kH,{GithubFetcher:()=>_2,default:()=>fdt,githubUtils:()=>wk});Ye();Pt();var wk={};zt(wk,{invalidGithubUrlMessage:()=>yme,isGithubUrl:()=>bH,parseGithubUrl:()=>xH});var dme=$e(ve("querystring")),mme=[/^https?:\/\/(?:([^/]+?)@)?github.com\/([^/#]+)\/([^/#]+)\/tarball\/([^/#]+)(?:#(.*))?$/,/^https?:\/\/(?:([^/]+?)@)?github.com\/([^/#]+)\/([^/#]+?)(?:\.git)?(?:#(.*))?$/];function bH(t){return t?mme.some(e=>!!t.match(e)):!1}function xH(t){let e;for(let A of mme)if(e=t.match(A),e)break;if(!e)throw new Error(yme(t));let[,r,o,a,n="master"]=e,{commit:u}=dme.default.parse(n);return n=u||n.replace(/[^:]*:/,""),{auth:r,username:o,reponame:a,treeish:n}}function yme(t){return`Input cannot be parsed as a valid GitHub URL ('${t}').`}var _2=class{supports(e,r){return!!bH(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from GitHub`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let o=await nn.get(this.getLocatorUrl(e,r),{configuration:r.project.configuration});return await oe.mktempPromise(async a=>{let n=new gn(a);await Xi.extractArchiveTo(o,n,{stripComponents:1});let u=ra.splitRepoUrl(e.reference),A=z.join(a,"package.tgz");await un.prepareExternalProject(a,A,{configuration:r.project.configuration,report:r.report,workspace:u.extra.workspace,locator:e});let p=await oe.readFilePromise(A);return await Xi.convertToZip(p,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})})}getLocatorUrl(e,r){let{auth:o,username:a,reponame:n,treeish:u}=xH(e.reference);return`https://${o?`${o}@`:""}github.com/${a}/${n}/archive/${u}.tar.gz`}};var Adt={hooks:{async fetchHostedRepository(t,e,r){if(t!==null)return t;let o=new _2;if(!o.supports(e,r))return null;try{return await o.fetch(e,r)}catch{return null}}}},fdt=Adt;var QH={};zt(QH,{TarballHttpFetcher:()=>q2,TarballHttpResolver:()=>G2,default:()=>hdt});Ye();function H2(t){let e;try{e=new URL(t)}catch{return!1}return!(e.protocol!=="http:"&&e.protocol!=="https:"||!e.pathname.match(/(\.tar\.gz|\.tgz|\/[^.]+)$/))}var q2=class{supports(e,r){return H2(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote server`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let o=await nn.get(e.reference,{configuration:r.project.configuration});return await Xi.convertToZip(o,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}};Ye();Ye();var G2=class{supportsDescriptor(e,r){return H2(e.range)}supportsLocator(e,r){return H2(e.reference)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){return[W.convertDescriptorToLocator(e)]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await _e.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"HARD",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var pdt={fetchers:[q2],resolvers:[G2]},hdt=pdt;var FH={};zt(FH,{InitCommand:()=>m0,default:()=>ddt});Ye();Ye();Pt();qt();var m0=class extends ut{constructor(){super(...arguments);this.private=ge.Boolean("-p,--private",!1,{description:"Initialize a private package"});this.workspace=ge.Boolean("-w,--workspace",!1,{description:"Initialize a workspace root with a `packages/` directory"});this.install=ge.String("-i,--install",!1,{tolerateBoolean:!0,description:"Initialize a package with a specific bundle that will be locked in the project"});this.name=ge.String("-n,--name",{description:"Initialize a package with the given name"});this.usev2=ge.Boolean("-2",!1,{hidden:!0});this.yes=ge.Boolean("-y,--yes",{hidden:!0})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=typeof this.install=="string"?this.install:this.usev2||this.install===!0?"latest":null;return o!==null?await this.executeProxy(r,o):await this.executeRegular(r)}async executeProxy(r,o){if(r.projectCwd!==null&&r.projectCwd!==this.context.cwd)throw new it("Cannot use the --install flag from within a project subdirectory");oe.existsSync(this.context.cwd)||await oe.mkdirPromise(this.context.cwd,{recursive:!0});let a=z.join(this.context.cwd,dr.lockfile);oe.existsSync(a)||await oe.writeFilePromise(a,"");let n=await this.cli.run(["set","version",o],{quiet:!0});if(n!==0)return n;let u=[];return this.private&&u.push("-p"),this.workspace&&u.push("-w"),this.name&&u.push(`-n=${this.name}`),this.yes&&u.push("-y"),await oe.mktempPromise(async A=>{let{code:p}=await Ur.pipevp("yarn",["init",...u],{cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,env:await un.makeScriptEnv({binFolder:A})});return p})}async executeRegular(r){let o=null;try{o=(await St.find(r,this.context.cwd)).project}catch{o=null}oe.existsSync(this.context.cwd)||await oe.mkdirPromise(this.context.cwd,{recursive:!0});let a=await Ot.tryFind(this.context.cwd),n=a??new Ot,u=Object.fromEntries(r.get("initFields").entries());n.load(u),n.name=n.name??W.makeIdent(r.get("initScope"),this.name??z.basename(this.context.cwd)),n.packageManager=rn&&_e.isTaggedYarnVersion(rn)?`yarn@${rn}`:null,(!a&&this.workspace||this.private)&&(n.private=!0),this.workspace&&n.workspaceDefinitions.length===0&&(await oe.mkdirPromise(z.join(this.context.cwd,"packages"),{recursive:!0}),n.workspaceDefinitions=[{pattern:"packages/*"}]);let A={};n.exportTo(A);let p=z.join(this.context.cwd,Ot.fileName);await oe.changeFilePromise(p,`${JSON.stringify(A,null,2)}
-`,{automaticNewlines:!0});let h=[p],E=z.join(this.context.cwd,"README.md");if(oe.existsSync(E)||(await oe.writeFilePromise(E,`# ${W.stringifyIdent(n.name)}
-`),h.push(E)),!o||o.cwd===this.context.cwd){let I=z.join(this.context.cwd,dr.lockfile);oe.existsSync(I)||(await oe.writeFilePromise(I,""),h.push(I));let x=[".yarn/*","!.yarn/patches","!.yarn/plugins","!.yarn/releases","!.yarn/sdks","!.yarn/versions","","# Swap the comments on the following lines if you wish to use zero-installs","# In that case, don't forget to run `yarn config set enableGlobalCache false`!","# Documentation here: https://yarnpkg.com/features/caching#zero-installs","","#!.yarn/cache",".pnp.*"].map(fe=>`${fe}
-`).join(""),C=z.join(this.context.cwd,".gitignore");oe.existsSync(C)||(await oe.writeFilePromise(C,x),h.push(C));let N=["/.yarn/** linguist-vendored","/.yarn/releases/* binary","/.yarn/plugins/**/* binary","/.pnp.* binary linguist-generated"].map(fe=>`${fe}
-`).join(""),U=z.join(this.context.cwd,".gitattributes");oe.existsSync(U)||(await oe.writeFilePromise(U,N),h.push(U));let V={["*"]:{endOfLine:"lf",insertFinalNewline:!0},["*.{js,json,yml}"]:{charset:"utf-8",indentStyle:"space",indentSize:2}};_e.mergeIntoTarget(V,r.get("initEditorConfig"));let te=`root = true
-`;for(let[fe,ue]of Object.entries(V)){te+=`
-[${fe}]
-`;for(let[me,he]of Object.entries(ue)){let Be=me.replace(/[A-Z]/g,we=>`_${we.toLowerCase()}`);te+=`${Be} = ${he}
-`}}let ae=z.join(this.context.cwd,".editorconfig");oe.existsSync(ae)||(await oe.writeFilePromise(ae,te),h.push(ae)),await this.cli.run(["install"],{quiet:!0}),oe.existsSync(z.join(this.context.cwd,".git"))||(await Ur.execvp("git",["init"],{cwd:this.context.cwd}),await Ur.execvp("git",["add","--",...h],{cwd:this.context.cwd}),await Ur.execvp("git",["commit","--allow-empty","-m","First commit"],{cwd:this.context.cwd}))}}};m0.paths=[["init"]],m0.usage=nt.Usage({description:"create a new package",details:"\n This command will setup a new package in your local directory.\n\n If the `-p,--private` or `-w,--workspace` options are set, the package will be private by default.\n\n If the `-w,--workspace` option is set, the package will be configured to accept a set of workspaces in the `packages/` directory.\n\n If the `-i,--install` option is given a value, Yarn will first download it using `yarn set version` and only then forward the init call to the newly downloaded bundle. Without arguments, the downloaded bundle will be `latest`.\n\n The initial settings of the manifest can be changed by using the `initScope` and `initFields` configuration values. Additionally, Yarn will generate an EditorConfig file whose rules can be altered via `initEditorConfig`, and will initialize a Git repository in the current directory.\n ",examples:[["Create a new package in the local directory","yarn init"],["Create a new private package in the local directory","yarn init -p"],["Create a new package and store the Yarn release inside","yarn init -i=latest"],["Create a new private package and defines it as a workspace root","yarn init -w"]]});var gdt={configuration:{initScope:{description:"Scope used when creating packages via the init command",type:"STRING",default:null},initFields:{description:"Additional fields to set when creating packages via the init command",type:"MAP",valueDefinition:{description:"",type:"ANY"}},initEditorConfig:{description:"Extra rules to define in the generator editorconfig",type:"MAP",valueDefinition:{description:"",type:"ANY"}}},commands:[m0]},ddt=gdt;var Tq={};zt(Tq,{SearchCommand:()=>I0,UpgradeInteractiveCommand:()=>v0,default:()=>iIt});Ye();var Cme=$e(ve("os"));function bC({stdout:t}){if(Cme.default.endianness()==="BE")throw new Error("Interactive commands cannot be used on big-endian systems because ink depends on yoga-layout-prebuilt which only supports little-endian architectures");if(!t.isTTY)throw new Error("Interactive commands can only be used inside a TTY environment")}qt();var Fye=$e(JH()),XH={appId:"OFCNCOG2CU",apiKey:"6fe4476ee5a1832882e326b506d14126",indexName:"npm-search"},pyt=(0,Fye.default)(XH.appId,XH.apiKey).initIndex(XH.indexName),ZH=async(t,e=0)=>await pyt.search(t,{analyticsTags:["yarn-plugin-interactive-tools"],attributesToRetrieve:["name","version","owner","repository","humanDownloadsLast30Days"],page:e,hitsPerPage:10});var qB=["regular","dev","peer"],I0=class extends ut{async execute(){bC(this.context);let{Gem:e}=await Promise.resolve().then(()=>(cQ(),Bq)),{ScrollableItems:r}=await Promise.resolve().then(()=>(pQ(),fQ)),{useKeypress:o}=await Promise.resolve().then(()=>(UB(),Kwe)),{useMinistore:a}=await Promise.resolve().then(()=>(xq(),bq)),{renderForm:n}=await Promise.resolve().then(()=>(mQ(),dQ)),{default:u}=await Promise.resolve().then(()=>$e(nIe())),{Box:A,Text:p}=await Promise.resolve().then(()=>$e(sc())),{default:h,useEffect:E,useState:I}=await Promise.resolve().then(()=>$e(on())),v=await Ke.find(this.context.cwd,this.context.plugins),x=()=>h.createElement(A,{flexDirection:"row"},h.createElement(A,{flexDirection:"column",width:48},h.createElement(A,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<up>"),"/",h.createElement(p,{bold:!0,color:"cyanBright"},"<down>")," to move between packages.")),h.createElement(A,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<space>")," to select a package.")),h.createElement(A,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<space>")," again to change the target."))),h.createElement(A,{flexDirection:"column"},h.createElement(A,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<enter>")," to install the selected packages.")),h.createElement(A,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<ctrl+c>")," to abort.")))),C=()=>h.createElement(h.Fragment,null,h.createElement(A,{width:15},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Owner")),h.createElement(A,{width:11},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Version")),h.createElement(A,{width:10},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Downloads"))),R=()=>h.createElement(A,{width:17},h.createElement(p,{bold:!0,underline:!0,color:"gray"},"Target")),N=({hit:he,active:Be})=>{let[we,g]=a(he.name,null);o({active:Be},(ce,ne)=>{if(ne.name!=="space")return;if(!we){g(qB[0]);return}let ee=qB.indexOf(we)+1;ee===qB.length?g(null):g(qB[ee])},[we,g]);let Ee=W.parseIdent(he.name),Pe=W.prettyIdent(v,Ee);return h.createElement(A,null,h.createElement(A,{width:45},h.createElement(p,{bold:!0,wrap:"wrap"},Pe)),h.createElement(A,{width:14,marginLeft:1},h.createElement(p,{bold:!0,wrap:"truncate"},he.owner.name)),h.createElement(A,{width:10,marginLeft:1},h.createElement(p,{italic:!0,wrap:"truncate"},he.version)),h.createElement(A,{width:16,marginLeft:1},h.createElement(p,null,he.humanDownloadsLast30Days)))},U=({name:he,active:Be})=>{let[we]=a(he,null),g=W.parseIdent(he);return h.createElement(A,null,h.createElement(A,{width:47},h.createElement(p,{bold:!0}," - ",W.prettyIdent(v,g))),qB.map(Ee=>h.createElement(A,{key:Ee,width:14,marginLeft:1},h.createElement(p,null," ",h.createElement(e,{active:we===Ee})," ",h.createElement(p,{bold:!0},Ee)))))},V=()=>h.createElement(A,{marginTop:1},h.createElement(p,null,"Powered by Algolia.")),ae=await n(({useSubmit:he})=>{let Be=a();he(Be);let we=Array.from(Be.keys()).filter(H=>Be.get(H)!==null),[g,Ee]=I(""),[Pe,ce]=I(0),[ne,ee]=I([]),Ie=H=>{H.match(/\t| /)||Ee(H)},Fe=async()=>{ce(0);let H=await ZH(g);H.query===g&&ee(H.hits)},At=async()=>{let H=await ZH(g,Pe+1);H.query===g&&H.page-1===Pe&&(ce(H.page),ee([...ne,...H.hits]))};return E(()=>{g?Fe():ee([])},[g]),h.createElement(A,{flexDirection:"column"},h.createElement(x,null),h.createElement(A,{flexDirection:"row",marginTop:1},h.createElement(p,{bold:!0},"Search: "),h.createElement(A,{width:41},h.createElement(u,{value:g,onChange:Ie,placeholder:"i.e. babel, webpack, react...",showCursor:!1})),h.createElement(C,null)),ne.length?h.createElement(r,{radius:2,loop:!1,children:ne.map(H=>h.createElement(N,{key:H.name,hit:H,active:!1})),willReachEnd:At}):h.createElement(p,{color:"gray"},"Start typing..."),h.createElement(A,{flexDirection:"row",marginTop:1},h.createElement(A,{width:49},h.createElement(p,{bold:!0},"Selected:")),h.createElement(R,null)),we.length?we.map(H=>h.createElement(U,{key:H,name:H,active:!1})):h.createElement(p,{color:"gray"},"No selected packages..."),h.createElement(V,null))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof ae>"u")return 1;let fe=Array.from(ae.keys()).filter(he=>ae.get(he)==="regular"),ue=Array.from(ae.keys()).filter(he=>ae.get(he)==="dev"),me=Array.from(ae.keys()).filter(he=>ae.get(he)==="peer");return fe.length&&await this.cli.run(["add",...fe]),ue.length&&await this.cli.run(["add","--dev",...ue]),me&&await this.cli.run(["add","--peer",...me]),0}};I0.paths=[["search"]],I0.usage=nt.Usage({category:"Interactive commands",description:"open the search interface",details:`
- This command opens a fullscreen terminal interface where you can search for and install packages from the npm registry.
- `,examples:[["Open the search window","yarn search"]]});Ye();qt();E_();var uIe=$e(Jn()),cIe=/^((?:[\^~]|>=?)?)([0-9]+)(\.[0-9]+)(\.[0-9]+)((?:-\S+)?)$/,AIe=(t,e)=>t.length>0?[t.slice(0,e)].concat(AIe(t.slice(e),e)):[],v0=class extends ut{async execute(){bC(this.context);let{ItemOptions:e}=await Promise.resolve().then(()=>(lIe(),aIe)),{Pad:r}=await Promise.resolve().then(()=>(Rq(),oIe)),{ScrollableItems:o}=await Promise.resolve().then(()=>(pQ(),fQ)),{useMinistore:a}=await Promise.resolve().then(()=>(xq(),bq)),{renderForm:n}=await Promise.resolve().then(()=>(mQ(),dQ)),{Box:u,Text:A}=await Promise.resolve().then(()=>$e(sc())),{default:p,useEffect:h,useRef:E,useState:I}=await Promise.resolve().then(()=>$e(on())),v=await Ke.find(this.context.cwd,this.context.plugins),{project:x,workspace:C}=await St.find(v,this.context.cwd),R=await Nr.find(v);if(!C)throw new nr(x.cwd,this.context.cwd);await x.restoreInstallState({restoreResolutions:!1});let N=this.context.stdout.rows-7,U=(Ee,Pe)=>{let ce=Ape(Ee,Pe),ne="";for(let ee of ce)ee.added?ne+=de.pretty(v,ee.value,"green"):ee.removed||(ne+=ee.value);return ne},V=(Ee,Pe)=>{if(Ee===Pe)return Pe;let ce=W.parseRange(Ee),ne=W.parseRange(Pe),ee=ce.selector.match(cIe),Ie=ne.selector.match(cIe);if(!ee||!Ie)return U(Ee,Pe);let Fe=["gray","red","yellow","green","magenta"],At=null,H="";for(let at=1;at<Fe.length;++at)At!==null||ee[at]!==Ie[at]?(At===null&&(At=Fe[at-1]),H+=de.pretty(v,Ie[at],At)):H+=Ie[at];return H},te=async(Ee,Pe,ce)=>{let ne=await Xc.fetchDescriptorFrom(Ee,ce,{project:x,cache:R,preserveModifier:Pe,workspace:C});return ne!==null?ne.range:Ee.range},ae=async Ee=>{let Pe=uIe.default.valid(Ee.range)?`^${Ee.range}`:Ee.range,[ce,ne]=await Promise.all([te(Ee,Ee.range,Pe).catch(()=>null),te(Ee,Ee.range,"latest").catch(()=>null)]),ee=[{value:null,label:Ee.range}];return ce&&ce!==Ee.range?ee.push({value:ce,label:V(Ee.range,ce)}):ee.push({value:null,label:""}),ne&&ne!==ce&&ne!==Ee.range?ee.push({value:ne,label:V(Ee.range,ne)}):ee.push({value:null,label:""}),ee},fe=()=>p.createElement(u,{flexDirection:"row"},p.createElement(u,{flexDirection:"column",width:49},p.createElement(u,{marginLeft:1},p.createElement(A,null,"Press ",p.createElement(A,{bold:!0,color:"cyanBright"},"<up>"),"/",p.createElement(A,{bold:!0,color:"cyanBright"},"<down>")," to select packages.")),p.createElement(u,{marginLeft:1},p.createElement(A,null,"Press ",p.createElement(A,{bold:!0,color:"cyanBright"},"<left>"),"/",p.createElement(A,{bold:!0,color:"cyanBright"},"<right>")," to select versions."))),p.createElement(u,{flexDirection:"column"},p.createElement(u,{marginLeft:1},p.createElement(A,null,"Press ",p.createElement(A,{bold:!0,color:"cyanBright"},"<enter>")," to install.")),p.createElement(u,{marginLeft:1},p.createElement(A,null,"Press ",p.createElement(A,{bold:!0,color:"cyanBright"},"<ctrl+c>")," to abort.")))),ue=()=>p.createElement(u,{flexDirection:"row",paddingTop:1,paddingBottom:1},p.createElement(u,{width:50},p.createElement(A,{bold:!0},p.createElement(A,{color:"greenBright"},"?")," Pick the packages you want to upgrade.")),p.createElement(u,{width:17},p.createElement(A,{bold:!0,underline:!0,color:"gray"},"Current")),p.createElement(u,{width:17},p.createElement(A,{bold:!0,underline:!0,color:"gray"},"Range")),p.createElement(u,{width:17},p.createElement(A,{bold:!0,underline:!0,color:"gray"},"Latest"))),me=({active:Ee,descriptor:Pe,suggestions:ce})=>{let[ne,ee]=a(Pe.descriptorHash,null),Ie=W.stringifyIdent(Pe),Fe=Math.max(0,45-Ie.length);return p.createElement(p.Fragment,null,p.createElement(u,null,p.createElement(u,{width:45},p.createElement(A,{bold:!0},W.prettyIdent(v,Pe)),p.createElement(r,{active:Ee,length:Fe})),p.createElement(e,{active:Ee,options:ce,value:ne,skewer:!0,onChange:ee,sizes:[17,17,17]})))},he=({dependencies:Ee})=>{let[Pe,ce]=I(Ee.map(()=>null)),ne=E(!0),ee=async Ie=>{let Fe=await ae(Ie);return Fe.filter(At=>At.label!=="").length<=1?null:{descriptor:Ie,suggestions:Fe}};return h(()=>()=>{ne.current=!1},[]),h(()=>{let Ie=Math.trunc(N*1.75),Fe=Ee.slice(0,Ie),At=Ee.slice(Ie),H=AIe(At,N),at=Fe.map(ee).reduce(async(Re,ke)=>{await Re;let xe=await ke;xe!==null&&(!ne.current||ce(He=>{let Te=He.findIndex(qe=>qe===null),Ve=[...He];return Ve[Te]=xe,Ve}))},Promise.resolve());H.reduce((Re,ke)=>Promise.all(ke.map(xe=>Promise.resolve().then(()=>ee(xe)))).then(async xe=>{xe=xe.filter(He=>He!==null),await Re,ne.current&&ce(He=>{let Te=He.findIndex(Ve=>Ve===null);return He.slice(0,Te).concat(xe).concat(He.slice(Te+xe.length))})}),at).then(()=>{ne.current&&ce(Re=>Re.filter(ke=>ke!==null))})},[]),Pe.length?p.createElement(o,{radius:N>>1,children:Pe.map((Ie,Fe)=>Ie!==null?p.createElement(me,{key:Fe,active:!1,descriptor:Ie.descriptor,suggestions:Ie.suggestions}):p.createElement(A,{key:Fe},"Loading..."))}):p.createElement(A,null,"No upgrades found")},we=await n(({useSubmit:Ee})=>{Ee(a());let Pe=new Map;for(let ne of x.workspaces)for(let ee of["dependencies","devDependencies"])for(let Ie of ne.manifest[ee].values())x.tryWorkspaceByDescriptor(Ie)===null&&(Ie.range.startsWith("link:")||Pe.set(Ie.descriptorHash,Ie));let ce=_e.sortMap(Pe.values(),ne=>W.stringifyDescriptor(ne));return p.createElement(u,{flexDirection:"column"},p.createElement(fe,null),p.createElement(ue,null),p.createElement(he,{dependencies:ce}))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof we>"u")return 1;let g=!1;for(let Ee of x.workspaces)for(let Pe of["dependencies","devDependencies"]){let ce=Ee.manifest[Pe];for(let ne of ce.values()){let ee=we.get(ne.descriptorHash);typeof ee<"u"&&ee!==null&&(ce.set(ne.identHash,W.makeDescriptor(ne,ee)),g=!0)}}return g?await x.installWithNewReport({quiet:this.context.quiet,stdout:this.context.stdout},{cache:R}):0}};v0.paths=[["upgrade-interactive"]],v0.usage=nt.Usage({category:"Interactive commands",description:"open the upgrade interface",details:`
- This command opens a fullscreen terminal interface where you can see any out of date packages used by your application, their status compared to the latest versions available on the remote registry, and select packages to upgrade.
- `,examples:[["Open the upgrade window","yarn upgrade-interactive"]]});var nIt={commands:[I0,v0]},iIt=nIt;var Lq={};zt(Lq,{LinkFetcher:()=>jB,LinkResolver:()=>YB,PortalFetcher:()=>WB,PortalResolver:()=>KB,default:()=>oIt});Ye();Pt();var tp="portal:",rp="link:";var jB=class{supports(e,r){return!!e.reference.startsWith(rp)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:rp});if(z.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:z.resolve(n,a)}async fetch(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:rp}),n=z.isAbsolute(a)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(o,r),u=n.localPath?{packageFs:new gn(Bt.root),prefixPath:z.relative(Bt.root,n.localPath),localPath:Bt.root}:n;n!==u&&n.releaseFs&&n.releaseFs();let A=u.packageFs,p=z.resolve(u.localPath??u.packageFs.getRealPath(),u.prefixPath,a);return n.localPath?{packageFs:new gn(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot,discardFromLookup:!0,localPath:p}:{packageFs:new Hu(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot,discardFromLookup:!0}}};Ye();Pt();var YB=class{supportsDescriptor(e,r){return!!e.range.startsWith(rp)}supportsLocator(e,r){return!!e.reference.startsWith(rp)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=e.range.slice(rp.length);return[W.makeLocator(e,`${rp}${le.toPortablePath(a)}`)]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){return{...e,version:"0.0.0",languageName:r.project.configuration.get("defaultLanguageName"),linkType:"SOFT",conditions:null,dependencies:new Map,peerDependencies:new Map,dependenciesMeta:new Map,peerDependenciesMeta:new Map,bin:new Map}}};Ye();Pt();var WB=class{supports(e,r){return!!e.reference.startsWith(tp)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:tp});if(z.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:z.resolve(n,a)}async fetch(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:tp}),n=z.isAbsolute(a)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(o,r),u=n.localPath?{packageFs:new gn(Bt.root),prefixPath:z.relative(Bt.root,n.localPath),localPath:Bt.root}:n;n!==u&&n.releaseFs&&n.releaseFs();let A=u.packageFs,p=z.resolve(u.localPath??u.packageFs.getRealPath(),u.prefixPath,a);return n.localPath?{packageFs:new gn(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot,localPath:p}:{packageFs:new Hu(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot}}};Ye();Ye();Pt();var KB=class{supportsDescriptor(e,r){return!!e.range.startsWith(tp)}supportsLocator(e,r){return!!e.reference.startsWith(tp)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=e.range.slice(tp.length);return[W.makeLocator(e,`${tp}${le.toPortablePath(a)}`)]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await _e.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||"0.0.0",languageName:a.languageName||r.project.configuration.get("defaultLanguageName"),linkType:"SOFT",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var sIt={fetchers:[jB,WB],resolvers:[YB,KB]},oIt=sIt;var yG={};zt(yG,{NodeModulesLinker:()=>lv,NodeModulesMode:()=>hG,PnpLooseLinker:()=>cv,default:()=>I1t});Pt();Ye();Pt();Pt();var Oq=(t,e)=>`${t}@${e}`,fIe=(t,e)=>{let r=e.indexOf("#"),o=r>=0?e.substring(r+1):e;return Oq(t,o)};var gIe=(t,e={})=>{let r=e.debugLevel||Number(process.env.NM_DEBUG_LEVEL||-1),o=e.check||r>=9,a=e.hoistingLimits||new Map,n={check:o,debugLevel:r,hoistingLimits:a,fastLookupPossible:!0},u;n.debugLevel>=0&&(u=Date.now());let A=pIt(t,n),p=!1,h=0;do p=Mq(A,[A],new Set([A.locator]),new Map,n).anotherRoundNeeded,n.fastLookupPossible=!1,h++;while(p);if(n.debugLevel>=0&&console.log(`hoist time: ${Date.now()-u}ms, rounds: ${h}`),n.debugLevel>=1){let E=zB(A);if(Mq(A,[A],new Set([A.locator]),new Map,n).isGraphChanged)throw new Error(`The hoisting result is not terminal, prev tree:
-${E}, next tree:
-${zB(A)}`);let v=dIe(A);if(v)throw new Error(`${v}, after hoisting finished:
-${zB(A)}`)}return n.debugLevel>=2&&console.log(zB(A)),hIt(A)},aIt=t=>{let e=t[t.length-1],r=new Map,o=new Set,a=n=>{if(!o.has(n)){o.add(n);for(let u of n.hoistedDependencies.values())r.set(u.name,u);for(let u of n.dependencies.values())n.peerNames.has(u.name)||a(u)}};return a(e),r},lIt=t=>{let e=t[t.length-1],r=new Map,o=new Set,a=new Set,n=(u,A)=>{if(o.has(u))return;o.add(u);for(let h of u.hoistedDependencies.values())if(!A.has(h.name)){let E;for(let I of t)E=I.dependencies.get(h.name),E&&r.set(E.name,E)}let p=new Set;for(let h of u.dependencies.values())p.add(h.name);for(let h of u.dependencies.values())u.peerNames.has(h.name)||n(h,p)};return n(e,a),r},pIe=(t,e)=>{if(e.decoupled)return e;let{name:r,references:o,ident:a,locator:n,dependencies:u,originalDependencies:A,hoistedDependencies:p,peerNames:h,reasons:E,isHoistBorder:I,hoistPriority:v,dependencyKind:x,hoistedFrom:C,hoistedTo:R}=e,N={name:r,references:new Set(o),ident:a,locator:n,dependencies:new Map(u),originalDependencies:new Map(A),hoistedDependencies:new Map(p),peerNames:new Set(h),reasons:new Map(E),decoupled:!0,isHoistBorder:I,hoistPriority:v,dependencyKind:x,hoistedFrom:new Map(C),hoistedTo:new Map(R)},U=N.dependencies.get(r);return U&&U.ident==N.ident&&N.dependencies.set(r,N),t.dependencies.set(N.name,N),N},cIt=(t,e)=>{let r=new Map([[t.name,[t.ident]]]);for(let a of t.dependencies.values())t.peerNames.has(a.name)||r.set(a.name,[a.ident]);let o=Array.from(e.keys());o.sort((a,n)=>{let u=e.get(a),A=e.get(n);return A.hoistPriority!==u.hoistPriority?A.hoistPriority-u.hoistPriority:A.peerDependents.size!==u.peerDependents.size?A.peerDependents.size-u.peerDependents.size:A.dependents.size-u.dependents.size});for(let a of o){let n=a.substring(0,a.indexOf("@",1)),u=a.substring(n.length+1);if(!t.peerNames.has(n)){let A=r.get(n);A||(A=[],r.set(n,A)),A.indexOf(u)<0&&A.push(u)}}return r},Nq=t=>{let e=new Set,r=(o,a=new Set)=>{if(!a.has(o)){a.add(o);for(let n of o.peerNames)if(!t.peerNames.has(n)){let u=t.dependencies.get(n);u&&!e.has(u)&&r(u,a)}e.add(o)}};for(let o of t.dependencies.values())t.peerNames.has(o.name)||r(o);return e},Mq=(t,e,r,o,a,n=new Set)=>{let u=e[e.length-1];if(n.has(u))return{anotherRoundNeeded:!1,isGraphChanged:!1};n.add(u);let A=gIt(u),p=cIt(u,A),h=t==u?new Map:a.fastLookupPossible?aIt(e):lIt(e),E,I=!1,v=!1,x=new Map(Array.from(p.entries()).map(([R,N])=>[R,N[0]])),C=new Map;do{let R=fIt(t,e,r,h,x,p,o,C,a);R.isGraphChanged&&(v=!0),R.anotherRoundNeeded&&(I=!0),E=!1;for(let[N,U]of p)U.length>1&&!u.dependencies.has(N)&&(x.delete(N),U.shift(),x.set(N,U[0]),E=!0)}while(E);for(let R of u.dependencies.values())if(!u.peerNames.has(R.name)&&!r.has(R.locator)){r.add(R.locator);let N=Mq(t,[...e,R],r,C,a);N.isGraphChanged&&(v=!0),N.anotherRoundNeeded&&(I=!0),r.delete(R.locator)}return{anotherRoundNeeded:I,isGraphChanged:v}},uIt=t=>{for(let[e,r]of t.dependencies)if(!t.peerNames.has(e)&&r.ident!==t.ident)return!0;return!1},AIt=(t,e,r,o,a,n,u,A,{outputReason:p,fastLookupPossible:h})=>{let E,I=null,v=new Set;p&&(E=`${Array.from(e).map(N=>no(N)).join("\u2192")}`);let x=r[r.length-1],R=!(o.ident===x.ident);if(p&&!R&&(I="- self-reference"),R&&(R=o.dependencyKind!==1,p&&!R&&(I="- workspace")),R&&o.dependencyKind===2&&(R=!uIt(o),p&&!R&&(I="- external soft link with unhoisted dependencies")),R&&(R=x.dependencyKind!==1||x.hoistedFrom.has(o.name)||e.size===1,p&&!R&&(I=x.reasons.get(o.name))),R&&(R=!t.peerNames.has(o.name),p&&!R&&(I=`- cannot shadow peer: ${no(t.originalDependencies.get(o.name).locator)} at ${E}`)),R){let N=!1,U=a.get(o.name);if(N=!U||U.ident===o.ident,p&&!N&&(I=`- filled by: ${no(U.locator)} at ${E}`),N)for(let V=r.length-1;V>=1;V--){let ae=r[V].dependencies.get(o.name);if(ae&&ae.ident!==o.ident){N=!1;let fe=A.get(x);fe||(fe=new Set,A.set(x,fe)),fe.add(o.name),p&&(I=`- filled by ${no(ae.locator)} at ${r.slice(0,V).map(ue=>no(ue.locator)).join("\u2192")}`);break}}R=N}if(R&&(R=n.get(o.name)===o.ident,p&&!R&&(I=`- filled by: ${no(u.get(o.name)[0])} at ${E}`)),R){let N=!0,U=new Set(o.peerNames);for(let V=r.length-1;V>=1;V--){let te=r[V];for(let ae of U){if(te.peerNames.has(ae)&&te.originalDependencies.has(ae))continue;let fe=te.dependencies.get(ae);fe&&t.dependencies.get(ae)!==fe&&(V===r.length-1?v.add(fe):(v=null,N=!1,p&&(I=`- peer dependency ${no(fe.locator)} from parent ${no(te.locator)} was not hoisted to ${E}`))),U.delete(ae)}if(!N)break}R=N}if(R&&!h)for(let N of o.hoistedDependencies.values()){let U=a.get(N.name)||t.dependencies.get(N.name);if(!U||N.ident!==U.ident){R=!1,p&&(I=`- previously hoisted dependency mismatch, needed: ${no(N.locator)}, available: ${no(U?.locator)}`);break}}return v!==null&&v.size>0?{isHoistable:2,dependsOn:v,reason:I}:{isHoistable:R?0:1,reason:I}},yQ=t=>`${t.name}@${t.locator}`,fIt=(t,e,r,o,a,n,u,A,p)=>{let h=e[e.length-1],E=new Set,I=!1,v=!1,x=(U,V,te,ae,fe)=>{if(E.has(ae))return;let ue=[...V,yQ(ae)],me=[...te,yQ(ae)],he=new Map,Be=new Map;for(let ce of Nq(ae)){let ne=AIt(h,r,[h,...U,ae],ce,o,a,n,A,{outputReason:p.debugLevel>=2,fastLookupPossible:p.fastLookupPossible});if(Be.set(ce,ne),ne.isHoistable===2)for(let ee of ne.dependsOn){let Ie=he.get(ee.name)||new Set;Ie.add(ce.name),he.set(ee.name,Ie)}}let we=new Set,g=(ce,ne,ee)=>{if(!we.has(ce)){we.add(ce),Be.set(ce,{isHoistable:1,reason:ee});for(let Ie of he.get(ce.name)||[])g(ae.dependencies.get(Ie),ne,p.debugLevel>=2?`- peer dependency ${no(ce.locator)} from parent ${no(ae.locator)} was not hoisted`:"")}};for(let[ce,ne]of Be)ne.isHoistable===1&&g(ce,ne,ne.reason);let Ee=!1;for(let ce of Be.keys())if(!we.has(ce)){v=!0;let ne=u.get(ae);ne&&ne.has(ce.name)&&(I=!0),Ee=!0,ae.dependencies.delete(ce.name),ae.hoistedDependencies.set(ce.name,ce),ae.reasons.delete(ce.name);let ee=h.dependencies.get(ce.name);if(p.debugLevel>=2){let Ie=Array.from(V).concat([ae.locator]).map(At=>no(At)).join("\u2192"),Fe=h.hoistedFrom.get(ce.name);Fe||(Fe=[],h.hoistedFrom.set(ce.name,Fe)),Fe.push(Ie),ae.hoistedTo.set(ce.name,Array.from(e).map(At=>no(At.locator)).join("\u2192"))}if(!ee)h.ident!==ce.ident&&(h.dependencies.set(ce.name,ce),fe.add(ce));else for(let Ie of ce.references)ee.references.add(Ie)}if(ae.dependencyKind===2&&Ee&&(I=!0),p.check){let ce=dIe(t);if(ce)throw new Error(`${ce}, after hoisting dependencies of ${[h,...U,ae].map(ne=>no(ne.locator)).join("\u2192")}:
-${zB(t)}`)}let Pe=Nq(ae);for(let ce of Pe)if(we.has(ce)){let ne=Be.get(ce);if((a.get(ce.name)===ce.ident||!ae.reasons.has(ce.name))&&ne.isHoistable!==0&&ae.reasons.set(ce.name,ne.reason),!ce.isHoistBorder&&me.indexOf(yQ(ce))<0){E.add(ae);let Ie=pIe(ae,ce);x([...U,ae],ue,me,Ie,R),E.delete(ae)}}},C,R=new Set(Nq(h)),N=Array.from(e).map(U=>yQ(U));do{C=R,R=new Set;for(let U of C){if(U.locator===h.locator||U.isHoistBorder)continue;let V=pIe(h,U);x([],Array.from(r),N,V,R)}}while(R.size>0);return{anotherRoundNeeded:I,isGraphChanged:v}},dIe=t=>{let e=[],r=new Set,o=new Set,a=(n,u,A)=>{if(r.has(n)||(r.add(n),o.has(n)))return;let p=new Map(u);for(let h of n.dependencies.values())n.peerNames.has(h.name)||p.set(h.name,h);for(let h of n.originalDependencies.values()){let E=p.get(h.name),I=()=>`${Array.from(o).concat([n]).map(v=>no(v.locator)).join("\u2192")}`;if(n.peerNames.has(h.name)){let v=u.get(h.name);(v!==E||!v||v.ident!==h.ident)&&e.push(`${I()} - broken peer promise: expected ${h.ident} but found ${v&&v.ident}`)}else{let v=A.hoistedFrom.get(n.name),x=n.hoistedTo.get(h.name),C=`${v?` hoisted from ${v.join(", ")}`:""}`,R=`${x?` hoisted to ${x}`:""}`,N=`${I()}${C}`;E?E.ident!==h.ident&&e.push(`${N} - broken require promise for ${h.name}${R}: expected ${h.ident}, but found: ${E.ident}`):e.push(`${N} - broken require promise: no required dependency ${h.name}${R} found`)}}o.add(n);for(let h of n.dependencies.values())n.peerNames.has(h.name)||a(h,p,n);o.delete(n)};return a(t,t.dependencies,t),e.join(`
-`)},pIt=(t,e)=>{let{identName:r,name:o,reference:a,peerNames:n}=t,u={name:o,references:new Set([a]),locator:Oq(r,a),ident:fIe(r,a),dependencies:new Map,originalDependencies:new Map,hoistedDependencies:new Map,peerNames:new Set(n),reasons:new Map,decoupled:!0,isHoistBorder:!0,hoistPriority:0,dependencyKind:1,hoistedFrom:new Map,hoistedTo:new Map},A=new Map([[t,u]]),p=(h,E)=>{let I=A.get(h),v=!!I;if(!I){let{name:x,identName:C,reference:R,peerNames:N,hoistPriority:U,dependencyKind:V}=h,te=e.hoistingLimits.get(E.locator);I={name:x,references:new Set([R]),locator:Oq(C,R),ident:fIe(C,R),dependencies:new Map,originalDependencies:new Map,hoistedDependencies:new Map,peerNames:new Set(N),reasons:new Map,decoupled:!0,isHoistBorder:te?te.has(x):!1,hoistPriority:U||0,dependencyKind:V||0,hoistedFrom:new Map,hoistedTo:new Map},A.set(h,I)}if(E.dependencies.set(h.name,I),E.originalDependencies.set(h.name,I),v){let x=new Set,C=R=>{if(!x.has(R)){x.add(R),R.decoupled=!1;for(let N of R.dependencies.values())R.peerNames.has(N.name)||C(N)}};C(I)}else for(let x of h.dependencies)p(x,I)};for(let h of t.dependencies)p(h,u);return u},Uq=t=>t.substring(0,t.indexOf("@",1)),hIt=t=>{let e={name:t.name,identName:Uq(t.locator),references:new Set(t.references),dependencies:new Set},r=new Set([t]),o=(a,n,u)=>{let A=r.has(a),p;if(n===a)p=u;else{let{name:h,references:E,locator:I}=a;p={name:h,identName:Uq(I),references:E,dependencies:new Set}}if(u.dependencies.add(p),!A){r.add(a);for(let h of a.dependencies.values())a.peerNames.has(h.name)||o(h,a,p);r.delete(a)}};for(let a of t.dependencies.values())o(a,t,e);return e},gIt=t=>{let e=new Map,r=new Set([t]),o=u=>`${u.name}@${u.ident}`,a=u=>{let A=o(u),p=e.get(A);return p||(p={dependents:new Set,peerDependents:new Set,hoistPriority:0},e.set(A,p)),p},n=(u,A)=>{let p=!!r.has(A);if(a(A).dependents.add(u.ident),!p){r.add(A);for(let E of A.dependencies.values()){let I=a(E);I.hoistPriority=Math.max(I.hoistPriority,E.hoistPriority),A.peerNames.has(E.name)?I.peerDependents.add(A.ident):n(A,E)}}};for(let u of t.dependencies.values())t.peerNames.has(u.name)||n(t,u);return e},no=t=>{if(!t)return"none";let e=t.indexOf("@",1),r=t.substring(0,e);r.endsWith("$wsroot$")&&(r=`wh:${r.replace("$wsroot$","")}`);let o=t.substring(e+1);if(o==="workspace:.")return".";if(o){let a=(o.indexOf("#")>0?o.split("#")[1]:o).replace("npm:","");return o.startsWith("virtual")&&(r=`v:${r}`),a.startsWith("workspace")&&(r=`w:${r}`,a=""),`${r}${a?`@${a}`:""}`}else return`${r}`},hIe=5e4,zB=t=>{let e=0,r=(a,n,u="")=>{if(e>hIe||n.has(a))return"";e++;let A=Array.from(a.dependencies.values()).sort((h,E)=>h.name===E.name?0:h.name>E.name?1:-1),p="";n.add(a);for(let h=0;h<A.length;h++){let E=A[h];if(!a.peerNames.has(E.name)&&E!==a){let I=a.reasons.get(E.name),v=Uq(E.locator);p+=`${u}${h<A.length-1?"\u251C\u2500":"\u2514\u2500"}${(n.has(E)?">":"")+(v!==E.name?`a:${E.name}:`:"")+no(E.locator)+(I?` ${I}`:"")}
-`,p+=r(E,n,`${u}${h<A.length-1?"\u2502 ":" "}`)}}return n.delete(a),p};return r(t,new Set)+(e>hIe?`
-Tree is too large, part of the tree has been dunped
-`:"")};var VB=(o=>(o.WORKSPACES="workspaces",o.DEPENDENCIES="dependencies",o.NONE="none",o))(VB||{}),mIe="node_modules",D0="$wsroot$";var JB=(t,e)=>{let{packageTree:r,hoistingLimits:o,errors:a,preserveSymlinksRequired:n}=mIt(t,e),u=null;if(a.length===0){let A=gIe(r,{hoistingLimits:o});u=EIt(t,A,e)}return{tree:u,errors:a,preserveSymlinksRequired:n}},dA=t=>`${t.name}@${t.reference}`,Hq=t=>{let e=new Map;for(let[r,o]of t.entries())if(!o.dirList){let a=e.get(o.locator);a||(a={target:o.target,linkType:o.linkType,locations:[],aliases:o.aliases},e.set(o.locator,a)),a.locations.push(r)}for(let r of e.values())r.locations=r.locations.sort((o,a)=>{let n=o.split(z.delimiter).length,u=a.split(z.delimiter).length;return a===o?0:n!==u?u-n:a>o?1:-1});return e},yIe=(t,e)=>{let r=W.isVirtualLocator(t)?W.devirtualizeLocator(t):t,o=W.isVirtualLocator(e)?W.devirtualizeLocator(e):e;return W.areLocatorsEqual(r,o)},_q=(t,e,r,o)=>{if(t.linkType!=="SOFT")return!1;let a=le.toPortablePath(r.resolveVirtual&&e.reference&&e.reference.startsWith("virtual:")?r.resolveVirtual(t.packageLocation):t.packageLocation);return z.contains(o,a)===null},dIt=t=>{let e=t.getPackageInformation(t.topLevel);if(e===null)throw new Error("Assertion failed: Expected the top-level package to have been registered");if(t.findPackageLocator(e.packageLocation)===null)throw new Error("Assertion failed: Expected the top-level package to have a physical locator");let o=le.toPortablePath(e.packageLocation.slice(0,-1)),a=new Map,n={children:new Map},u=t.getDependencyTreeRoots(),A=new Map,p=new Set,h=(v,x)=>{let C=dA(v);if(p.has(C))return;p.add(C);let R=t.getPackageInformation(v);if(R){let N=x?dA(x):"";if(dA(v)!==N&&R.linkType==="SOFT"&&!v.reference.startsWith("link:")&&!_q(R,v,t,o)){let U=EIe(R,v,t);(!A.get(U)||v.reference.startsWith("workspace:"))&&A.set(U,v)}for(let[U,V]of R.packageDependencies)V!==null&&(R.packagePeers.has(U)||h(t.getLocator(U,V),v))}};for(let v of u)h(v,null);let E=o.split(z.sep);for(let v of A.values()){let x=t.getPackageInformation(v),R=le.toPortablePath(x.packageLocation.slice(0,-1)).split(z.sep).slice(E.length),N=n;for(let U of R){let V=N.children.get(U);V||(V={children:new Map},N.children.set(U,V)),N=V}N.workspaceLocator=v}let I=(v,x)=>{if(v.workspaceLocator){let C=dA(x),R=a.get(C);R||(R=new Set,a.set(C,R)),R.add(v.workspaceLocator)}for(let C of v.children.values())I(C,v.workspaceLocator||x)};for(let v of n.children.values())I(v,n.workspaceLocator);return a},mIt=(t,e)=>{let r=[],o=!1,a=new Map,n=dIt(t),u=t.getPackageInformation(t.topLevel);if(u===null)throw new Error("Assertion failed: Expected the top-level package to have been registered");let A=t.findPackageLocator(u.packageLocation);if(A===null)throw new Error("Assertion failed: Expected the top-level package to have a physical locator");let p=le.toPortablePath(u.packageLocation.slice(0,-1)),h={name:A.name,identName:A.name,reference:A.reference,peerNames:u.packagePeers,dependencies:new Set,dependencyKind:1},E=new Map,I=(x,C)=>`${dA(C)}:${x}`,v=(x,C,R,N,U,V,te,ae)=>{let fe=I(x,R),ue=E.get(fe),me=!!ue;!me&&R.name===A.name&&R.reference===A.reference&&(ue=h,E.set(fe,h));let he=_q(C,R,t,p);if(!ue){let ce=0;he?ce=2:C.linkType==="SOFT"&&R.name.endsWith(D0)&&(ce=1),ue={name:x,identName:R.name,reference:R.reference,dependencies:new Set,peerNames:ce===1?new Set:C.packagePeers,dependencyKind:ce},E.set(fe,ue)}let Be;if(he?Be=2:U.linkType==="SOFT"?Be=1:Be=0,ue.hoistPriority=Math.max(ue.hoistPriority||0,Be),ae&&!he){let ce=dA({name:N.identName,reference:N.reference}),ne=a.get(ce)||new Set;a.set(ce,ne),ne.add(ue.name)}let we=new Map(C.packageDependencies);if(e.project){let ce=e.project.workspacesByCwd.get(le.toPortablePath(C.packageLocation.slice(0,-1)));if(ce){let ne=new Set([...Array.from(ce.manifest.peerDependencies.values(),ee=>W.stringifyIdent(ee)),...Array.from(ce.manifest.peerDependenciesMeta.keys())]);for(let ee of ne)we.has(ee)||(we.set(ee,V.get(ee)||null),ue.peerNames.add(ee))}}let g=dA({name:R.name.replace(D0,""),reference:R.reference}),Ee=n.get(g);if(Ee)for(let ce of Ee)we.set(`${ce.name}${D0}`,ce.reference);(C!==U||C.linkType!=="SOFT"||!he&&(!e.selfReferencesByCwd||e.selfReferencesByCwd.get(te)))&&N.dependencies.add(ue);let Pe=R!==A&&C.linkType==="SOFT"&&!R.name.endsWith(D0)&&!he;if(!me&&!Pe){let ce=new Map;for(let[ne,ee]of we)if(ee!==null){let Ie=t.getLocator(ne,ee),Fe=t.getLocator(ne.replace(D0,""),ee),At=t.getPackageInformation(Fe);if(At===null)throw new Error("Assertion failed: Expected the package to have been registered");let H=_q(At,Ie,t,p);if(e.validateExternalSoftLinks&&e.project&&H){At.packageDependencies.size>0&&(o=!0);for(let[He,Te]of At.packageDependencies)if(Te!==null){let Ve=W.parseLocator(Array.isArray(Te)?`${Te[0]}@${Te[1]}`:`${He}@${Te}`);if(dA(Ve)!==dA(Ie)){let qe=we.get(He);if(qe){let b=W.parseLocator(Array.isArray(qe)?`${qe[0]}@${qe[1]}`:`${He}@${qe}`);yIe(b,Ve)||r.push({messageName:71,text:`Cannot link ${W.prettyIdent(e.project.configuration,W.parseIdent(Ie.name))} into ${W.prettyLocator(e.project.configuration,W.parseLocator(`${R.name}@${R.reference}`))} dependency ${W.prettyLocator(e.project.configuration,Ve)} conflicts with parent dependency ${W.prettyLocator(e.project.configuration,b)}`})}else{let b=ce.get(He);if(b){let w=b.target,S=W.parseLocator(Array.isArray(w)?`${w[0]}@${w[1]}`:`${He}@${w}`);yIe(S,Ve)||r.push({messageName:71,text:`Cannot link ${W.prettyIdent(e.project.configuration,W.parseIdent(Ie.name))} into ${W.prettyLocator(e.project.configuration,W.parseLocator(`${R.name}@${R.reference}`))} dependency ${W.prettyLocator(e.project.configuration,Ve)} conflicts with dependency ${W.prettyLocator(e.project.configuration,S)} from sibling portal ${W.prettyIdent(e.project.configuration,W.parseIdent(b.portal.name))}`})}else ce.set(He,{target:Ve.reference,portal:Ie})}}}}let at=e.hoistingLimitsByCwd?.get(te),Re=H?te:z.relative(p,le.toPortablePath(At.packageLocation))||Bt.dot,ke=e.hoistingLimitsByCwd?.get(Re);v(ne,At,Ie,ue,C,we,Re,at==="dependencies"||ke==="dependencies"||ke==="workspaces")}}};return v(A.name,u,A,h,u,u.packageDependencies,Bt.dot,!1),{packageTree:h,hoistingLimits:a,errors:r,preserveSymlinksRequired:o}};function EIe(t,e,r){let o=r.resolveVirtual&&e.reference&&e.reference.startsWith("virtual:")?r.resolveVirtual(t.packageLocation):t.packageLocation;return le.toPortablePath(o||t.packageLocation)}function yIt(t,e,r){let o=e.getLocator(t.name.replace(D0,""),t.reference),a=e.getPackageInformation(o);if(a===null)throw new Error("Assertion failed: Expected the package to be registered");return r.pnpifyFs?{linkType:"SOFT",target:le.toPortablePath(a.packageLocation)}:{linkType:a.linkType,target:EIe(a,t,e)}}var EIt=(t,e,r)=>{let o=new Map,a=(E,I,v)=>{let{linkType:x,target:C}=yIt(E,t,r);return{locator:dA(E),nodePath:I,target:C,linkType:x,aliases:v}},n=E=>{let[I,v]=E.split("/");return v?{scope:I,name:v}:{scope:null,name:I}},u=new Set,A=(E,I,v)=>{if(u.has(E))return;u.add(E);let x=Array.from(E.references).sort().join("#");for(let C of E.dependencies){let R=Array.from(C.references).sort().join("#");if(C.identName===E.identName.replace(D0,"")&&R===x)continue;let N=Array.from(C.references).sort(),U={name:C.identName,reference:N[0]},{name:V,scope:te}=n(C.name),ae=te?[te,V]:[V],fe=z.join(I,mIe),ue=z.join(fe,...ae),me=`${v}/${U.name}`,he=a(U,v,N.slice(1)),Be=!1;if(he.linkType==="SOFT"&&r.project){let we=r.project.workspacesByCwd.get(he.target.slice(0,-1));Be=!!(we&&!we.manifest.name)}if(!C.name.endsWith(D0)&&!Be){let we=o.get(ue);if(we){if(we.dirList)throw new Error(`Assertion failed: ${ue} cannot merge dir node with leaf node`);{let Pe=W.parseLocator(we.locator),ce=W.parseLocator(he.locator);if(we.linkType!==he.linkType)throw new Error(`Assertion failed: ${ue} cannot merge nodes with different link types ${we.nodePath}/${W.stringifyLocator(Pe)} and ${v}/${W.stringifyLocator(ce)}`);if(Pe.identHash!==ce.identHash)throw new Error(`Assertion failed: ${ue} cannot merge nodes with different idents ${we.nodePath}/${W.stringifyLocator(Pe)} and ${v}/s${W.stringifyLocator(ce)}`);he.aliases=[...he.aliases,...we.aliases,W.parseLocator(we.locator).reference]}}o.set(ue,he);let g=ue.split("/"),Ee=g.indexOf(mIe);for(let Pe=g.length-1;Ee>=0&&Pe>Ee;Pe--){let ce=le.toPortablePath(g.slice(0,Pe).join(z.sep)),ne=g[Pe],ee=o.get(ce);if(!ee)o.set(ce,{dirList:new Set([ne])});else if(ee.dirList){if(ee.dirList.has(ne))break;ee.dirList.add(ne)}}}A(C,he.linkType==="SOFT"?he.target:ue,me)}},p=a({name:e.name,reference:Array.from(e.references)[0]},"",[]),h=p.target;return o.set(h,p),A(e,h,""),o};Ye();Ye();Pt();Pt();iA();Nl();var oG={};zt(oG,{PnpInstaller:()=>mm,PnpLinker:()=>b0,UnplugCommand:()=>k0,default:()=>VIt,getPnpPath:()=>x0,jsInstallUtils:()=>yA,pnpUtils:()=>av,quotePathIfNeeded:()=>n1e});Pt();var r1e=ve("url");Ye();Ye();Pt();Pt();var CIe={["DEFAULT"]:{collapsed:!1,next:{["*"]:"DEFAULT"}},["TOP_LEVEL"]:{collapsed:!1,next:{fallbackExclusionList:"FALLBACK_EXCLUSION_LIST",packageRegistryData:"PACKAGE_REGISTRY_DATA",["*"]:"DEFAULT"}},["FALLBACK_EXCLUSION_LIST"]:{collapsed:!1,next:{["*"]:"FALLBACK_EXCLUSION_ENTRIES"}},["FALLBACK_EXCLUSION_ENTRIES"]:{collapsed:!0,next:{["*"]:"FALLBACK_EXCLUSION_DATA"}},["FALLBACK_EXCLUSION_DATA"]:{collapsed:!0,next:{["*"]:"DEFAULT"}},["PACKAGE_REGISTRY_DATA"]:{collapsed:!1,next:{["*"]:"PACKAGE_REGISTRY_ENTRIES"}},["PACKAGE_REGISTRY_ENTRIES"]:{collapsed:!0,next:{["*"]:"PACKAGE_STORE_DATA"}},["PACKAGE_STORE_DATA"]:{collapsed:!1,next:{["*"]:"PACKAGE_STORE_ENTRIES"}},["PACKAGE_STORE_ENTRIES"]:{collapsed:!0,next:{["*"]:"PACKAGE_INFORMATION_DATA"}},["PACKAGE_INFORMATION_DATA"]:{collapsed:!1,next:{packageDependencies:"PACKAGE_DEPENDENCIES",["*"]:"DEFAULT"}},["PACKAGE_DEPENDENCIES"]:{collapsed:!1,next:{["*"]:"PACKAGE_DEPENDENCY"}},["PACKAGE_DEPENDENCY"]:{collapsed:!0,next:{["*"]:"DEFAULT"}}};function CIt(t,e,r){let o="";o+="[";for(let a=0,n=t.length;a<n;++a)o+=EQ(String(a),t[a],e,r).replace(/^ +/g,""),a+1<n&&(o+=", ");return o+="]",o}function wIt(t,e,r){let o=`${r} `,a="";a+=r,a+=`[
-`;for(let n=0,u=t.length;n<u;++n)a+=o+EQ(String(n),t[n],e,o).replace(/^ +/,""),n+1<u&&(a+=","),a+=`
-`;return a+=r,a+="]",a}function IIt(t,e,r){let o=Object.keys(t),a="";a+="{";for(let n=0,u=o.length,A=0;n<u;++n){let p=o[n],h=t[p];typeof h>"u"||(A!==0&&(a+=", "),a+=JSON.stringify(p),a+=": ",a+=EQ(p,h,e,r).replace(/^ +/g,""),A+=1)}return a+="}",a}function BIt(t,e,r){let o=Object.keys(t),a=`${r} `,n="";n+=r,n+=`{
-`;let u=0;for(let A=0,p=o.length;A<p;++A){let h=o[A],E=t[h];typeof E>"u"||(u!==0&&(n+=",",n+=`
-`),n+=a,n+=JSON.stringify(h),n+=": ",n+=EQ(h,E,e,a).replace(/^ +/g,""),u+=1)}return u!==0&&(n+=`
-`),n+=r,n+="}",n}function EQ(t,e,r,o){let{next:a}=CIe[r],n=a[t]||a["*"];return wIe(e,n,o)}function wIe(t,e,r){let{collapsed:o}=CIe[e];return Array.isArray(t)?o?CIt(t,e,r):wIt(t,e,r):typeof t=="object"&&t!==null?o?IIt(t,e,r):BIt(t,e,r):JSON.stringify(t)}function IIe(t){return wIe(t,"TOP_LEVEL","")}function XB(t,e){let r=Array.from(t);Array.isArray(e)||(e=[e]);let o=[];for(let n of e)o.push(r.map(u=>n(u)));let a=r.map((n,u)=>u);return a.sort((n,u)=>{for(let A of o){let p=A[n]<A[u]?-1:A[n]>A[u]?1:0;if(p!==0)return p}return 0}),a.map(n=>r[n])}function vIt(t){let e=new Map,r=XB(t.fallbackExclusionList||[],[({name:o,reference:a})=>o,({name:o,reference:a})=>a]);for(let{name:o,reference:a}of r){let n=e.get(o);typeof n>"u"&&e.set(o,n=new Set),n.add(a)}return Array.from(e).map(([o,a])=>[o,Array.from(a)])}function DIt(t){return XB(t.fallbackPool||[],([e])=>e)}function PIt(t){let e=[];for(let[r,o]of XB(t.packageRegistry,([a])=>a===null?"0":`1${a}`)){let a=[];e.push([r,a]);for(let[n,{packageLocation:u,packageDependencies:A,packagePeers:p,linkType:h,discardFromLookup:E}]of XB(o,([I])=>I===null?"0":`1${I}`)){let I=[];r!==null&&n!==null&&!A.has(r)&&I.push([r,n]);for(let[C,R]of XB(A.entries(),([N])=>N))I.push([C,R]);let v=p&&p.size>0?Array.from(p):void 0,x=E||void 0;a.push([n,{packageLocation:u,packageDependencies:I,packagePeers:v,linkType:h,discardFromLookup:x}])}}return e}function ZB(t){return{__info:["This file is automatically generated. Do not touch it, or risk","your modifications being lost."],dependencyTreeRoots:t.dependencyTreeRoots,enableTopLevelFallback:t.enableTopLevelFallback||!1,ignorePatternData:t.ignorePattern||null,fallbackExclusionList:vIt(t),fallbackPool:DIt(t),packageRegistryData:PIt(t)}}var DIe=$e(vIe());function PIe(t,e){return[t?`${t}
-`:"",`/* eslint-disable */
-`,`// @ts-nocheck
-`,`"use strict";
-`,`
-`,e,`
-`,(0,DIe.default)()].join("")}function SIt(t){return JSON.stringify(t,null,2)}function bIt(t){return`'${t.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/\n/g,`\\
-`)}'`}function xIt(t){return[`const RAW_RUNTIME_STATE =
-`,`${bIt(IIe(t))};
-
-`,`function $$SETUP_STATE(hydrateRuntimeState, basePath) {
-`,` return hydrateRuntimeState(JSON.parse(RAW_RUNTIME_STATE), {basePath: basePath || __dirname});
-`,`}
-`].join("")}function kIt(){return[`function $$SETUP_STATE(hydrateRuntimeState, basePath) {
-`,` const fs = require('fs');
-`,` const path = require('path');
-`,` const pnpDataFilepath = path.resolve(__dirname, ${JSON.stringify(dr.pnpData)});
-`,` return hydrateRuntimeState(JSON.parse(fs.readFileSync(pnpDataFilepath, 'utf8')), {basePath: basePath || __dirname});
-`,`}
-`].join("")}function SIe(t){let e=ZB(t),r=xIt(e);return PIe(t.shebang,r)}function bIe(t){let e=ZB(t),r=kIt(),o=PIe(t.shebang,r);return{dataFile:SIt(e),loaderFile:o}}Pt();function Gq(t,{basePath:e}){let r=le.toPortablePath(e),o=z.resolve(r),a=t.ignorePatternData!==null?new RegExp(t.ignorePatternData):null,n=new Map,u=new Map(t.packageRegistryData.map(([I,v])=>[I,new Map(v.map(([x,C])=>{if(I===null!=(x===null))throw new Error("Assertion failed: The name and reference should be null, or neither should");let R=C.discardFromLookup??!1,N={name:I,reference:x},U=n.get(C.packageLocation);U?(U.discardFromLookup=U.discardFromLookup&&R,R||(U.locator=N)):n.set(C.packageLocation,{locator:N,discardFromLookup:R});let V=null;return[x,{packageDependencies:new Map(C.packageDependencies),packagePeers:new Set(C.packagePeers),linkType:C.linkType,discardFromLookup:R,get packageLocation(){return V||(V=z.join(o,C.packageLocation))}}]}))])),A=new Map(t.fallbackExclusionList.map(([I,v])=>[I,new Set(v)])),p=new Map(t.fallbackPool),h=t.dependencyTreeRoots,E=t.enableTopLevelFallback;return{basePath:r,dependencyTreeRoots:h,enableTopLevelFallback:E,fallbackExclusionList:A,fallbackPool:p,ignorePattern:a,packageLocatorsByLocations:n,packageRegistry:u}}Pt();Pt();var ip=ve("module"),dm=ve("url"),$q=ve("util");var Mo=ve("url");var FIe=$e(ve("assert"));var jq=Array.isArray,$B=JSON.stringify,ev=Object.getOwnPropertyNames,gm=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),Yq=(t,e)=>RegExp.prototype.exec.call(t,e),Wq=(t,...e)=>RegExp.prototype[Symbol.replace].apply(t,e),P0=(t,...e)=>String.prototype.endsWith.apply(t,e),Kq=(t,...e)=>String.prototype.includes.apply(t,e),zq=(t,...e)=>String.prototype.lastIndexOf.apply(t,e),tv=(t,...e)=>String.prototype.indexOf.apply(t,e),xIe=(t,...e)=>String.prototype.replace.apply(t,e),S0=(t,...e)=>String.prototype.slice.apply(t,e),mA=(t,...e)=>String.prototype.startsWith.apply(t,e),kIe=Map,QIe=JSON.parse;function rv(t,e,r){return class extends r{constructor(...o){super(e(...o)),this.code=t,this.name=`${r.name} [${t}]`}}}var RIe=rv("ERR_PACKAGE_IMPORT_NOT_DEFINED",(t,e,r)=>`Package import specifier "${t}" is not defined${e?` in package ${e}package.json`:""} imported from ${r}`,TypeError),Vq=rv("ERR_INVALID_MODULE_SPECIFIER",(t,e,r=void 0)=>`Invalid module "${t}" ${e}${r?` imported from ${r}`:""}`,TypeError),TIe=rv("ERR_INVALID_PACKAGE_TARGET",(t,e,r,o=!1,a=void 0)=>{let n=typeof r=="string"&&!o&&r.length&&!mA(r,"./");return e==="."?((0,FIe.default)(o===!1),`Invalid "exports" main target ${$B(r)} defined in the package config ${t}package.json${a?` imported from ${a}`:""}${n?'; targets must start with "./"':""}`):`Invalid "${o?"imports":"exports"}" target ${$B(r)} defined for '${e}' in the package config ${t}package.json${a?` imported from ${a}`:""}${n?'; targets must start with "./"':""}`},Error),nv=rv("ERR_INVALID_PACKAGE_CONFIG",(t,e,r)=>`Invalid package config ${t}${e?` while importing ${e}`:""}${r?`. ${r}`:""}`,Error),LIe=rv("ERR_PACKAGE_PATH_NOT_EXPORTED",(t,e,r=void 0)=>e==="."?`No "exports" main defined in ${t}package.json${r?` imported from ${r}`:""}`:`Package subpath '${e}' is not defined by "exports" in ${t}package.json${r?` imported from ${r}`:""}`,Error);var wQ=ve("url");function NIe(t,e){let r=Object.create(null);for(let o=0;o<e.length;o++){let a=e[o];gm(t,a)&&(r[a]=t[a])}return r}var CQ=new kIe;function QIt(t,e,r,o){let a=CQ.get(t);if(a!==void 0)return a;let n=o(t);if(n===void 0){let x={pjsonPath:t,exists:!1,main:void 0,name:void 0,type:"none",exports:void 0,imports:void 0};return CQ.set(t,x),x}let u;try{u=QIe(n)}catch(x){throw new nv(t,(r?`"${e}" from `:"")+(0,wQ.fileURLToPath)(r||e),x.message)}let{imports:A,main:p,name:h,type:E}=NIe(u,["imports","main","name","type"]),I=gm(u,"exports")?u.exports:void 0;(typeof A!="object"||A===null)&&(A=void 0),typeof p!="string"&&(p=void 0),typeof h!="string"&&(h=void 0),E!=="module"&&E!=="commonjs"&&(E="none");let v={pjsonPath:t,exists:!0,main:p,name:h,type:E,exports:I,imports:A};return CQ.set(t,v),v}function OIe(t,e){let r=new URL("./package.json",t);for(;;){let n=r.pathname;if(P0(n,"node_modules/package.json"))break;let u=QIt((0,wQ.fileURLToPath)(r),t,void 0,e);if(u.exists)return u;let A=r;if(r=new URL("../package.json",r),r.pathname===A.pathname)break}let o=(0,wQ.fileURLToPath)(r),a={pjsonPath:o,exists:!1,main:void 0,name:void 0,type:"none",exports:void 0,imports:void 0};return CQ.set(o,a),a}function FIt(t,e,r){throw new RIe(t,e&&(0,Mo.fileURLToPath)(new URL(".",e)),(0,Mo.fileURLToPath)(r))}function RIt(t,e,r,o){let a=`request is not a valid subpath for the "${r?"imports":"exports"}" resolution of ${(0,Mo.fileURLToPath)(e)}`;throw new Vq(t,a,o&&(0,Mo.fileURLToPath)(o))}function iv(t,e,r,o,a){throw typeof e=="object"&&e!==null?e=$B(e,null,""):e=`${e}`,new TIe((0,Mo.fileURLToPath)(new URL(".",r)),t,e,o,a&&(0,Mo.fileURLToPath)(a))}var MIe=/(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/i,UIe=/\*/g;function TIt(t,e,r,o,a,n,u,A){if(e!==""&&!n&&t[t.length-1]!=="/"&&iv(r,t,o,u,a),!mA(t,"./")){if(u&&!mA(t,"../")&&!mA(t,"/")){let I=!1;try{new URL(t),I=!0}catch{}if(!I)return n?Wq(UIe,t,()=>e):t+e}iv(r,t,o,u,a)}Yq(MIe,S0(t,2))!==null&&iv(r,t,o,u,a);let p=new URL(t,o),h=p.pathname,E=new URL(".",o).pathname;if(mA(h,E)||iv(r,t,o,u,a),e==="")return p;if(Yq(MIe,e)!==null){let I=n?xIe(r,"*",()=>e):r+e;RIt(I,o,u,a)}return n?new URL(Wq(UIe,p.href,()=>e)):new URL(e,p)}function LIt(t){let e=+t;return`${e}`!==t?!1:e>=0&&e<4294967295}function jC(t,e,r,o,a,n,u,A){if(typeof e=="string")return TIt(e,r,o,t,a,n,u,A);if(jq(e)){if(e.length===0)return null;let p;for(let h=0;h<e.length;h++){let E=e[h],I;try{I=jC(t,E,r,o,a,n,u,A)}catch(v){if(p=v,v.code==="ERR_INVALID_PACKAGE_TARGET")continue;throw v}if(I!==void 0){if(I===null){p=null;continue}return I}}if(p==null)return p;throw p}else if(typeof e=="object"&&e!==null){let p=ev(e);for(let h=0;h<p.length;h++){let E=p[h];if(LIt(E))throw new nv((0,Mo.fileURLToPath)(t),a,'"exports" cannot contain numeric property keys.')}for(let h=0;h<p.length;h++){let E=p[h];if(E==="default"||A.has(E)){let I=e[E],v=jC(t,I,r,o,a,n,u,A);if(v===void 0)continue;return v}}return}else if(e===null)return null;iv(o,e,t,u,a)}function HIe(t,e){let r=tv(t,"*"),o=tv(e,"*"),a=r===-1?t.length:r+1,n=o===-1?e.length:o+1;return a>n?-1:n>a||r===-1?1:o===-1||t.length>e.length?-1:e.length>t.length?1:0}function NIt(t,e,r){if(typeof t=="string"||jq(t))return!0;if(typeof t!="object"||t===null)return!1;let o=ev(t),a=!1,n=0;for(let u=0;u<o.length;u++){let A=o[u],p=A===""||A[0]!==".";if(n++===0)a=p;else if(a!==p)throw new nv((0,Mo.fileURLToPath)(e),r,`"exports" cannot contain some keys starting with '.' and some not. The exports object must either be an object of package subpath keys or an object of main entry condition name keys only.`)}return a}function Jq(t,e,r){throw new LIe((0,Mo.fileURLToPath)(new URL(".",e)),t,r&&(0,Mo.fileURLToPath)(r))}var _Ie=new Set;function OIt(t,e,r){let o=(0,Mo.fileURLToPath)(e);_Ie.has(o+"|"+t)||(_Ie.add(o+"|"+t),process.emitWarning(`Use of deprecated trailing slash pattern mapping "${t}" in the "exports" field module resolution of the package at ${o}${r?` imported from ${(0,Mo.fileURLToPath)(r)}`:""}. Mapping specifiers ending in "/" is no longer supported.`,"DeprecationWarning","DEP0155"))}function qIe({packageJSONUrl:t,packageSubpath:e,exports:r,base:o,conditions:a}){if(NIt(r,t,o)&&(r={".":r}),gm(r,e)&&!Kq(e,"*")&&!P0(e,"/")){let p=r[e],h=jC(t,p,"",e,o,!1,!1,a);return h==null&&Jq(e,t,o),h}let n="",u,A=ev(r);for(let p=0;p<A.length;p++){let h=A[p],E=tv(h,"*");if(E!==-1&&mA(e,S0(h,0,E))){P0(e,"/")&&OIt(e,t,o);let I=S0(h,E+1);e.length>=h.length&&P0(e,I)&&HIe(n,h)===1&&zq(h,"*")===E&&(n=h,u=S0(e,E,e.length-I.length))}}if(n){let p=r[n],h=jC(t,p,u,n,o,!0,!1,a);return h==null&&Jq(e,t,o),h}Jq(e,t,o)}function GIe({name:t,base:e,conditions:r,readFileSyncFn:o}){if(t==="#"||mA(t,"#/")||P0(t,"/")){let u="is not a valid internal imports specifier name";throw new Vq(t,u,(0,Mo.fileURLToPath)(e))}let a,n=OIe(e,o);if(n.exists){a=(0,Mo.pathToFileURL)(n.pjsonPath);let u=n.imports;if(u)if(gm(u,t)&&!Kq(t,"*")){let A=jC(a,u[t],"",t,e,!1,!0,r);if(A!=null)return A}else{let A="",p,h=ev(u);for(let E=0;E<h.length;E++){let I=h[E],v=tv(I,"*");if(v!==-1&&mA(t,S0(I,0,v))){let x=S0(I,v+1);t.length>=I.length&&P0(t,x)&&HIe(A,I)===1&&zq(I,"*")===v&&(A=I,p=S0(t,v,t.length-x.length))}}if(A){let E=u[A],I=jC(a,E,p,A,e,!0,!0,r);if(I!=null)return I}}}FIt(t,a,e)}Pt();var MIt=new Set(["BUILTIN_NODE_RESOLUTION_FAILED","MISSING_DEPENDENCY","MISSING_PEER_DEPENDENCY","QUALIFIED_PATH_RESOLUTION_FAILED","UNDECLARED_DEPENDENCY"]);function $i(t,e,r={},o){o??=MIt.has(t)?"MODULE_NOT_FOUND":t;let a={configurable:!0,writable:!0,enumerable:!1};return Object.defineProperties(new Error(e),{code:{...a,value:o},pnpCode:{...a,value:t},data:{...a,value:r}})}function lu(t){return le.normalize(le.fromPortablePath(t))}var KIe=$e(YIe());function zIe(t){return UIt(),Zq[t]}var Zq;function UIt(){Zq||(Zq={"--conditions":[],...WIe(_It()),...WIe(process.execArgv)})}function WIe(t){return(0,KIe.default)({"--conditions":[String],"-C":"--conditions"},{argv:t,permissive:!0})}function _It(){let t=[],e=HIt(process.env.NODE_OPTIONS||"",t);return t.length,e}function HIt(t,e){let r=[],o=!1,a=!0;for(let n=0;n<t.length;++n){let u=t[n];if(u==="\\"&&o){if(n+1===t.length)return e.push(`invalid value for NODE_OPTIONS (invalid escape)
-`),r;u=t[++n]}else if(u===" "&&!o){a=!0;continue}else if(u==='"'){o=!o;continue}a?(r.push(u),a=!1):r[r.length-1]+=u}return o&&e.push(`invalid value for NODE_OPTIONS (unterminated string)
-`),r}Pt();var[Ma,np]=process.versions.node.split(".").map(t=>parseInt(t,10)),VIe=Ma>19||Ma===19&&np>=2||Ma===18&&np>=13,vJt=Ma===20&&np<6||Ma===19&&np>=3,DJt=Ma>19||Ma===19&&np>=6,PJt=Ma>=21||Ma===20&&np>=10||Ma===18&&np>=19,SJt=Ma>=21||Ma===20&&np>=10||Ma===18&&np>=20,bJt=Ma>=22;function JIe(t){if(process.env.WATCH_REPORT_DEPENDENCIES&&process.send)if(t=t.map(e=>le.fromPortablePath(mi.resolveVirtual(le.toPortablePath(e)))),VIe)process.send({"watch:require":t});else for(let e of t)process.send({"watch:require":e})}function eG(t,e){let r=Number(process.env.PNP_ALWAYS_WARN_ON_FALLBACK)>0,o=Number(process.env.PNP_DEBUG_LEVEL),a=/^(?![a-zA-Z]:[\\/]|\\\\|\.{0,2}(?:\/|$))((?:node:)?(?:@[^/]+\/)?[^/]+)\/*(.*|)$/,n=/^(\/|\.{1,2}(\/|$))/,u=/\/$/,A=/^\.{0,2}\//,p={name:null,reference:null},h=[],E=new Set;if(t.enableTopLevelFallback===!0&&h.push(p),e.compatibilityMode!==!1)for(let Re of["react-scripts","gatsby"]){let ke=t.packageRegistry.get(Re);if(ke)for(let xe of ke.keys()){if(xe===null)throw new Error("Assertion failed: This reference shouldn't be null");h.push({name:Re,reference:xe})}}let{ignorePattern:I,packageRegistry:v,packageLocatorsByLocations:x}=t;function C(Re,ke){return{fn:Re,args:ke,error:null,result:null}}function R(Re){let ke=process.stderr?.hasColors?.()??process.stdout.isTTY,xe=(Ve,qe)=>`\x1B[${Ve}m${qe}\x1B[0m`,He=Re.error;console.error(He?xe("31;1",`\u2716 ${Re.error?.message.replace(/\n.*/s,"")}`):xe("33;1","\u203C Resolution")),Re.args.length>0&&console.error();for(let Ve of Re.args)console.error(` ${xe("37;1","In \u2190")} ${(0,$q.inspect)(Ve,{colors:ke,compact:!0})}`);Re.result&&(console.error(),console.error(` ${xe("37;1","Out \u2192")} ${(0,$q.inspect)(Re.result,{colors:ke,compact:!0})}`));let Te=new Error().stack.match(/(?<=^ +)at.*/gm)?.slice(2)??[];if(Te.length>0){console.error();for(let Ve of Te)console.error(` ${xe("38;5;244",Ve)}`)}console.error()}function N(Re,ke){if(e.allowDebug===!1)return ke;if(Number.isFinite(o)){if(o>=2)return(...xe)=>{let He=C(Re,xe);try{return He.result=ke(...xe)}catch(Te){throw He.error=Te}finally{R(He)}};if(o>=1)return(...xe)=>{try{return ke(...xe)}catch(He){let Te=C(Re,xe);throw Te.error=He,R(Te),He}}}return ke}function U(Re){let ke=g(Re);if(!ke)throw $i("INTERNAL","Couldn't find a matching entry in the dependency tree for the specified parent (this is probably an internal error)");return ke}function V(Re){if(Re.name===null)return!0;for(let ke of t.dependencyTreeRoots)if(ke.name===Re.name&&ke.reference===Re.reference)return!0;return!1}let te=new Set(["node","require",...zIe("--conditions")]);function ae(Re,ke=te,xe){let He=ce(z.join(Re,"internal.js"),{resolveIgnored:!0,includeDiscardFromLookup:!0});if(He===null)throw $i("INTERNAL",`The locator that owns the "${Re}" path can't be found inside the dependency tree (this is probably an internal error)`);let{packageLocation:Te}=U(He),Ve=z.join(Te,dr.manifest);if(!e.fakeFs.existsSync(Ve))return null;let qe=JSON.parse(e.fakeFs.readFileSync(Ve,"utf8"));if(qe.exports==null)return null;let b=z.contains(Te,Re);if(b===null)throw $i("INTERNAL","unqualifiedPath doesn't contain the packageLocation (this is probably an internal error)");b!=="."&&!A.test(b)&&(b=`./${b}`);try{let w=qIe({packageJSONUrl:(0,dm.pathToFileURL)(le.fromPortablePath(Ve)),packageSubpath:b,exports:qe.exports,base:xe?(0,dm.pathToFileURL)(le.fromPortablePath(xe)):null,conditions:ke});return le.toPortablePath((0,dm.fileURLToPath)(w))}catch(w){throw $i("EXPORTS_RESOLUTION_FAILED",w.message,{unqualifiedPath:lu(Re),locator:He,pkgJson:qe,subpath:lu(b),conditions:ke},w.code)}}function fe(Re,ke,{extensions:xe}){let He;try{ke.push(Re),He=e.fakeFs.statSync(Re)}catch{}if(He&&!He.isDirectory())return e.fakeFs.realpathSync(Re);if(He&&He.isDirectory()){let Te;try{Te=JSON.parse(e.fakeFs.readFileSync(z.join(Re,dr.manifest),"utf8"))}catch{}let Ve;if(Te&&Te.main&&(Ve=z.resolve(Re,Te.main)),Ve&&Ve!==Re){let qe=fe(Ve,ke,{extensions:xe});if(qe!==null)return qe}}for(let Te=0,Ve=xe.length;Te<Ve;Te++){let qe=`${Re}${xe[Te]}`;if(ke.push(qe),e.fakeFs.existsSync(qe))return qe}if(He&&He.isDirectory())for(let Te=0,Ve=xe.length;Te<Ve;Te++){let qe=z.format({dir:Re,name:"index",ext:xe[Te]});if(ke.push(qe),e.fakeFs.existsSync(qe))return qe}return null}function ue(Re){let ke=new ip.Module(Re,null);return ke.filename=Re,ke.paths=ip.Module._nodeModulePaths(Re),ke}function me(Re,ke){return ke.endsWith("/")&&(ke=z.join(ke,"internal.js")),ip.Module._resolveFilename(le.fromPortablePath(Re),ue(le.fromPortablePath(ke)),!1,{plugnplay:!1})}function he(Re){if(I===null)return!1;let ke=z.contains(t.basePath,Re);return ke===null?!1:!!I.test(ke.replace(/\/$/,""))}let Be={std:3,resolveVirtual:1,getAllLocators:1},we=p;function g({name:Re,reference:ke}){let xe=v.get(Re);if(!xe)return null;let He=xe.get(ke);return He||null}function Ee({name:Re,reference:ke}){let xe=[];for(let[He,Te]of v)if(He!==null)for(let[Ve,qe]of Te)Ve===null||qe.packageDependencies.get(Re)!==ke||He===Re&&Ve===ke||xe.push({name:He,reference:Ve});return xe}function Pe(Re,ke){let xe=new Map,He=new Set,Te=qe=>{let b=JSON.stringify(qe.name);if(He.has(b))return;He.add(b);let w=Ee(qe);for(let S of w)if(U(S).packagePeers.has(Re))Te(S);else{let F=xe.get(S.name);typeof F>"u"&&xe.set(S.name,F=new Set),F.add(S.reference)}};Te(ke);let Ve=[];for(let qe of[...xe.keys()].sort())for(let b of[...xe.get(qe)].sort())Ve.push({name:qe,reference:b});return Ve}function ce(Re,{resolveIgnored:ke=!1,includeDiscardFromLookup:xe=!1}={}){if(he(Re)&&!ke)return null;let He=z.relative(t.basePath,Re);He.match(n)||(He=`./${He}`),He.endsWith("/")||(He=`${He}/`);do{let Te=x.get(He);if(typeof Te>"u"||Te.discardFromLookup&&!xe){He=He.substring(0,He.lastIndexOf("/",He.length-2)+1);continue}return Te.locator}while(He!=="");return null}function ne(Re){try{return e.fakeFs.readFileSync(le.toPortablePath(Re),"utf8")}catch(ke){if(ke.code==="ENOENT")return;throw ke}}function ee(Re,ke,{considerBuiltins:xe=!0}={}){if(Re.startsWith("#"))throw new Error("resolveToUnqualified can not handle private import mappings");if(Re==="pnpapi")return le.toPortablePath(e.pnpapiResolution);if(xe&&(0,ip.isBuiltin)(Re))return null;let He=lu(Re),Te=ke&&lu(ke);if(ke&&he(ke)&&(!z.isAbsolute(Re)||ce(Re)===null)){let b=me(Re,ke);if(b===!1)throw $i("BUILTIN_NODE_RESOLUTION_FAILED",`The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer was explicitely ignored by the regexp)
-
-Require request: "${He}"
-Required by: ${Te}
-`,{request:He,issuer:Te});return le.toPortablePath(b)}let Ve,qe=Re.match(a);if(qe){if(!ke)throw $i("API_ERROR","The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute",{request:He,issuer:Te});let[,b,w]=qe,S=ce(ke);if(!S){let Le=me(Re,ke);if(Le===!1)throw $i("BUILTIN_NODE_RESOLUTION_FAILED",`The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer doesn't seem to be part of the Yarn-managed dependency tree).
-
-Require path: "${He}"
-Required by: ${Te}
-`,{request:He,issuer:Te});return le.toPortablePath(Le)}let F=U(S).packageDependencies.get(b),J=null;if(F==null&&S.name!==null){let Le=t.fallbackExclusionList.get(S.name);if(!Le||!Le.has(S.reference)){for(let dt=0,Gt=h.length;dt<Gt;++dt){let bt=U(h[dt]).packageDependencies.get(b);if(bt!=null){r?J=bt:F=bt;break}}if(t.enableTopLevelFallback&&F==null&&J===null){let dt=t.fallbackPool.get(b);dt!=null&&(J=dt)}}}let X=null;if(F===null)if(V(S))X=$i("MISSING_PEER_DEPENDENCY",`Your application tried to access ${b} (a peer dependency); this isn't allowed as there is no ancestor to satisfy the requirement. Use a devDependency if needed.
-
-Required package: ${b}${b!==He?` (via "${He}")`:""}
-Required by: ${Te}
-`,{request:He,issuer:Te,dependencyName:b});else{let Le=Pe(b,S);Le.every(ot=>V(ot))?X=$i("MISSING_PEER_DEPENDENCY",`${S.name} tried to access ${b} (a peer dependency) but it isn't provided by your application; this makes the require call ambiguous and unsound.
-
-Required package: ${b}${b!==He?` (via "${He}")`:""}
-Required by: ${S.name}@${S.reference} (via ${Te})
-${Le.map(ot=>`Ancestor breaking the chain: ${ot.name}@${ot.reference}
-`).join("")}
-`,{request:He,issuer:Te,issuerLocator:Object.assign({},S),dependencyName:b,brokenAncestors:Le}):X=$i("MISSING_PEER_DEPENDENCY",`${S.name} tried to access ${b} (a peer dependency) but it isn't provided by its ancestors; this makes the require call ambiguous and unsound.
-
-Required package: ${b}${b!==He?` (via "${He}")`:""}
-Required by: ${S.name}@${S.reference} (via ${Te})
-
-${Le.map(ot=>`Ancestor breaking the chain: ${ot.name}@${ot.reference}
-`).join("")}
-`,{request:He,issuer:Te,issuerLocator:Object.assign({},S),dependencyName:b,brokenAncestors:Le})}else F===void 0&&(!xe&&(0,ip.isBuiltin)(Re)?V(S)?X=$i("UNDECLARED_DEPENDENCY",`Your application tried to access ${b}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${b} isn't otherwise declared in your dependencies, this makes the require call ambiguous and unsound.
-
-Required package: ${b}${b!==He?` (via "${He}")`:""}
-Required by: ${Te}
-`,{request:He,issuer:Te,dependencyName:b}):X=$i("UNDECLARED_DEPENDENCY",`${S.name} tried to access ${b}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${b} isn't otherwise declared in ${S.name}'s dependencies, this makes the require call ambiguous and unsound.
-
-Required package: ${b}${b!==He?` (via "${He}")`:""}
-Required by: ${Te}
-`,{request:He,issuer:Te,issuerLocator:Object.assign({},S),dependencyName:b}):V(S)?X=$i("UNDECLARED_DEPENDENCY",`Your application tried to access ${b}, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound.
-
-Required package: ${b}${b!==He?` (via "${He}")`:""}
-Required by: ${Te}
-`,{request:He,issuer:Te,dependencyName:b}):X=$i("UNDECLARED_DEPENDENCY",`${S.name} tried to access ${b}, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound.
-
-Required package: ${b}${b!==He?` (via "${He}")`:""}
-Required by: ${S.name}@${S.reference} (via ${Te})
-`,{request:He,issuer:Te,issuerLocator:Object.assign({},S),dependencyName:b}));if(F==null){if(J===null||X===null)throw X||new Error("Assertion failed: Expected an error to have been set");F=J;let Le=X.message.replace(/\n.*/g,"");X.message=Le,!E.has(Le)&&o!==0&&(E.add(Le),process.emitWarning(X))}let Z=Array.isArray(F)?{name:F[0],reference:F[1]}:{name:b,reference:F},ie=U(Z);if(!ie.packageLocation)throw $i("MISSING_DEPENDENCY",`A dependency seems valid but didn't get installed for some reason. This might be caused by a partial install, such as dev vs prod.
-
-Required package: ${Z.name}@${Z.reference}${Z.name!==He?` (via "${He}")`:""}
-Required by: ${S.name}@${S.reference} (via ${Te})
-`,{request:He,issuer:Te,dependencyLocator:Object.assign({},Z)});let be=ie.packageLocation;w?Ve=z.join(be,w):Ve=be}else if(z.isAbsolute(Re))Ve=z.normalize(Re);else{if(!ke)throw $i("API_ERROR","The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute",{request:He,issuer:Te});let b=z.resolve(ke);ke.match(u)?Ve=z.normalize(z.join(b,Re)):Ve=z.normalize(z.join(z.dirname(b),Re))}return z.normalize(Ve)}function Ie(Re,ke,xe=te,He){if(n.test(Re))return ke;let Te=ae(ke,xe,He);return Te?z.normalize(Te):ke}function Fe(Re,{extensions:ke=Object.keys(ip.Module._extensions)}={}){let xe=[],He=fe(Re,xe,{extensions:ke});if(He)return z.normalize(He);{JIe(xe.map(qe=>le.fromPortablePath(qe)));let Te=lu(Re),Ve=ce(Re);if(Ve){let{packageLocation:qe}=U(Ve),b=!0;try{e.fakeFs.accessSync(qe)}catch(w){if(w?.code==="ENOENT")b=!1;else{let S=(w?.message??w??"empty exception thrown").replace(/^[A-Z]/,y=>y.toLowerCase());throw $i("QUALIFIED_PATH_RESOLUTION_FAILED",`Required package exists but could not be accessed (${S}).
-
-Missing package: ${Ve.name}@${Ve.reference}
-Expected package location: ${lu(qe)}
-`,{unqualifiedPath:Te,extensions:ke})}}if(!b){let w=qe.includes("/unplugged/")?"Required unplugged package missing from disk. This may happen when switching branches without running installs (unplugged packages must be fully materialized on disk to work).":"Required package missing from disk. If you keep your packages inside your repository then restarting the Node process may be enough. Otherwise, try to run an install first.";throw $i("QUALIFIED_PATH_RESOLUTION_FAILED",`${w}
-
-Missing package: ${Ve.name}@${Ve.reference}
-Expected package location: ${lu(qe)}
-`,{unqualifiedPath:Te,extensions:ke})}}throw $i("QUALIFIED_PATH_RESOLUTION_FAILED",`Qualified path resolution failed: we looked for the following paths, but none could be accessed.
-
-Source path: ${Te}
-${xe.map(qe=>`Not found: ${lu(qe)}
-`).join("")}`,{unqualifiedPath:Te,extensions:ke})}}function At(Re,ke,xe){if(!ke)throw new Error("Assertion failed: An issuer is required to resolve private import mappings");let He=GIe({name:Re,base:(0,dm.pathToFileURL)(le.fromPortablePath(ke)),conditions:xe.conditions??te,readFileSyncFn:ne});if(He instanceof URL)return Fe(le.toPortablePath((0,dm.fileURLToPath)(He)),{extensions:xe.extensions});if(He.startsWith("#"))throw new Error("Mapping from one private import to another isn't allowed");return H(He,ke,xe)}function H(Re,ke,xe={}){try{if(Re.startsWith("#"))return At(Re,ke,xe);let{considerBuiltins:He,extensions:Te,conditions:Ve}=xe,qe=ee(Re,ke,{considerBuiltins:He});if(Re==="pnpapi")return qe;if(qe===null)return null;let b=()=>ke!==null?he(ke):!1,w=(!He||!(0,ip.isBuiltin)(Re))&&!b()?Ie(Re,qe,Ve,ke):qe;return Fe(w,{extensions:Te})}catch(He){throw Object.hasOwn(He,"pnpCode")&&Object.assign(He.data,{request:lu(Re),issuer:ke&&lu(ke)}),He}}function at(Re){let ke=z.normalize(Re),xe=mi.resolveVirtual(ke);return xe!==ke?xe:null}return{VERSIONS:Be,topLevel:we,getLocator:(Re,ke)=>Array.isArray(ke)?{name:ke[0],reference:ke[1]}:{name:Re,reference:ke},getDependencyTreeRoots:()=>[...t.dependencyTreeRoots],getAllLocators(){let Re=[];for(let[ke,xe]of v)for(let He of xe.keys())ke!==null&&He!==null&&Re.push({name:ke,reference:He});return Re},getPackageInformation:Re=>{let ke=g(Re);if(ke===null)return null;let xe=le.fromPortablePath(ke.packageLocation);return{...ke,packageLocation:xe}},findPackageLocator:Re=>ce(le.toPortablePath(Re)),resolveToUnqualified:N("resolveToUnqualified",(Re,ke,xe)=>{let He=ke!==null?le.toPortablePath(ke):null,Te=ee(le.toPortablePath(Re),He,xe);return Te===null?null:le.fromPortablePath(Te)}),resolveUnqualified:N("resolveUnqualified",(Re,ke)=>le.fromPortablePath(Fe(le.toPortablePath(Re),ke))),resolveRequest:N("resolveRequest",(Re,ke,xe)=>{let He=ke!==null?le.toPortablePath(ke):null,Te=H(le.toPortablePath(Re),He,xe);return Te===null?null:le.fromPortablePath(Te)}),resolveVirtual:N("resolveVirtual",Re=>{let ke=at(le.toPortablePath(Re));return ke!==null?le.fromPortablePath(ke):null})}}Pt();var XIe=(t,e,r)=>{let o=ZB(t),a=Gq(o,{basePath:e}),n=le.join(e,dr.pnpCjs);return eG(a,{fakeFs:r,pnpapiResolution:n})};var rG=$e($Ie());qt();var yA={};zt(yA,{checkManifestCompatibility:()=>e1e,extractBuildRequest:()=>IQ,getExtractHint:()=>nG,hasBindingGyp:()=>iG});Ye();Pt();function e1e(t){return W.isPackageCompatible(t,Vi.getArchitectureSet())}function IQ(t,e,r,{configuration:o}){let a=[];for(let n of["preinstall","install","postinstall"])e.manifest.scripts.has(n)&&a.push({type:0,script:n});return!e.manifest.scripts.has("install")&&e.misc.hasBindingGyp&&a.push({type:1,script:"node-gyp rebuild"}),a.length===0?null:t.linkType!=="HARD"?{skipped:!0,explain:n=>n.reportWarningOnce(6,`${W.prettyLocator(o,t)} lists build scripts, but is referenced through a soft link. Soft links don't support build scripts, so they'll be ignored.`)}:r&&r.built===!1?{skipped:!0,explain:n=>n.reportInfoOnce(5,`${W.prettyLocator(o,t)} lists build scripts, but its build has been explicitly disabled through configuration.`)}:!o.get("enableScripts")&&!r.built?{skipped:!0,explain:n=>n.reportWarningOnce(4,`${W.prettyLocator(o,t)} lists build scripts, but all build scripts have been disabled.`)}:e1e(t)?{skipped:!1,directives:a}:{skipped:!0,explain:n=>n.reportWarningOnce(76,`${W.prettyLocator(o,t)} The ${Vi.getArchitectureName()} architecture is incompatible with this package, build skipped.`)}}var GIt=new Set([".exe",".bin",".h",".hh",".hpp",".c",".cc",".cpp",".java",".jar",".node"]);function nG(t){return t.packageFs.getExtractHint({relevantExtensions:GIt})}function iG(t){let e=z.join(t.prefixPath,"binding.gyp");return t.packageFs.existsSync(e)}var av={};zt(av,{getUnpluggedPath:()=>ov});Ye();Pt();function ov(t,{configuration:e}){return z.resolve(e.get("pnpUnpluggedFolder"),W.slugifyLocator(t))}var jIt=new Set([W.makeIdent(null,"open").identHash,W.makeIdent(null,"opn").identHash]),b0=class{constructor(){this.mode="strict";this.pnpCache=new Map}getCustomDataKey(){return JSON.stringify({name:"PnpLinker",version:2})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error("Assertion failed: Expected the PnP linker to be enabled");let o=x0(r.project).cjs;if(!oe.existsSync(o))throw new it(`The project in ${de.pretty(r.project.configuration,`${r.project.cwd}/package.json`,de.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let a=_e.getFactoryWithDefault(this.pnpCache,o,()=>_e.dynamicRequire(o,{cachingStrategy:_e.CachingStrategy.FsTime})),n={name:W.stringifyIdent(e),reference:e.reference},u=a.getPackageInformation(n);if(!u)throw new it(`Couldn't find ${W.prettyLocator(r.project.configuration,e)} in the currently installed PnP map - running an install might help`);return le.toPortablePath(u.packageLocation)}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let o=x0(r.project).cjs;if(!oe.existsSync(o))return null;let n=_e.getFactoryWithDefault(this.pnpCache,o,()=>_e.dynamicRequire(o,{cachingStrategy:_e.CachingStrategy.FsTime})).findPackageLocator(le.fromPortablePath(e));return n?W.makeLocator(W.parseIdent(n.name),n.reference):null}makeInstaller(e){return new mm(e)}isEnabled(e){return!(e.project.configuration.get("nodeLinker")!=="pnp"||e.project.configuration.get("pnpMode")!==this.mode)}},mm=class{constructor(e){this.opts=e;this.mode="strict";this.asyncActions=new _e.AsyncActions(10);this.packageRegistry=new Map;this.virtualTemplates=new Map;this.isESMLoaderRequired=!1;this.customData={store:new Map};this.unpluggedPaths=new Set;this.opts=e}attachCustomData(e){this.customData=e}async installPackage(e,r,o){let a=W.stringifyIdent(e),n=e.reference,u=!!this.opts.project.tryWorkspaceByLocator(e),A=W.isVirtualLocator(e),p=e.peerDependencies.size>0&&!A,h=!p&&!u,E=!p&&e.linkType!=="SOFT",I,v;if(h||E){let te=A?W.devirtualizeLocator(e):e;I=this.customData.store.get(te.locatorHash),typeof I>"u"&&(I=await YIt(r),e.linkType==="HARD"&&this.customData.store.set(te.locatorHash,I)),I.manifest.type==="module"&&(this.isESMLoaderRequired=!0),v=this.opts.project.getDependencyMeta(te,e.version)}let x=h?IQ(e,I,v,{configuration:this.opts.project.configuration}):null,C=E?await this.unplugPackageIfNeeded(e,I,r,v,o):r.packageFs;if(z.isAbsolute(r.prefixPath))throw new Error(`Assertion failed: Expected the prefix path (${r.prefixPath}) to be relative to the parent`);let R=z.resolve(C.getRealPath(),r.prefixPath),N=sG(this.opts.project.cwd,R),U=new Map,V=new Set;if(A){for(let te of e.peerDependencies.values())U.set(W.stringifyIdent(te),null),V.add(W.stringifyIdent(te));if(!u){let te=W.devirtualizeLocator(e);this.virtualTemplates.set(te.locatorHash,{location:sG(this.opts.project.cwd,mi.resolveVirtual(R)),locator:te})}}return _e.getMapWithDefault(this.packageRegistry,a).set(n,{packageLocation:N,packageDependencies:U,packagePeers:V,linkType:e.linkType,discardFromLookup:r.discardFromLookup||!1}),{packageLocation:R,buildRequest:x}}async attachInternalDependencies(e,r){let o=this.getPackageInformation(e);for(let[a,n]of r){let u=W.areIdentsEqual(a,n)?n.reference:[W.stringifyIdent(n),n.reference];o.packageDependencies.set(W.stringifyIdent(a),u)}}async attachExternalDependents(e,r){for(let o of r)this.getDiskInformation(o).packageDependencies.set(W.stringifyIdent(e),e.reference)}async finalizeInstall(){if(this.opts.project.configuration.get("pnpMode")!==this.mode)return;let e=x0(this.opts.project);if(this.isEsmEnabled()||await oe.removePromise(e.esmLoader),this.opts.project.configuration.get("nodeLinker")!=="pnp"){await oe.removePromise(e.cjs),await oe.removePromise(e.data),await oe.removePromise(e.esmLoader),await oe.removePromise(this.opts.project.configuration.get("pnpUnpluggedFolder"));return}for(let{locator:E,location:I}of this.virtualTemplates.values())_e.getMapWithDefault(this.packageRegistry,W.stringifyIdent(E)).set(E.reference,{packageLocation:I,packageDependencies:new Map,packagePeers:new Set,linkType:"SOFT",discardFromLookup:!1});this.packageRegistry.set(null,new Map([[null,this.getPackageInformation(this.opts.project.topLevelWorkspace.anchoredLocator)]]));let r=this.opts.project.configuration.get("pnpFallbackMode"),o=this.opts.project.workspaces.map(({anchoredLocator:E})=>({name:W.stringifyIdent(E),reference:E.reference})),a=r!=="none",n=[],u=new Map,A=_e.buildIgnorePattern([".yarn/sdks/**",...this.opts.project.configuration.get("pnpIgnorePatterns")]),p=this.packageRegistry,h=this.opts.project.configuration.get("pnpShebang");if(r==="dependencies-only")for(let E of this.opts.project.storedPackages.values())this.opts.project.tryWorkspaceByLocator(E)&&n.push({name:W.stringifyIdent(E),reference:E.reference});return await this.asyncActions.wait(),await this.finalizeInstallWithPnp({dependencyTreeRoots:o,enableTopLevelFallback:a,fallbackExclusionList:n,fallbackPool:u,ignorePattern:A,packageRegistry:p,shebang:h}),{customData:this.customData}}async transformPnpSettings(e){}isEsmEnabled(){if(this.opts.project.configuration.sources.has("pnpEnableEsmLoader"))return this.opts.project.configuration.get("pnpEnableEsmLoader");if(this.isESMLoaderRequired)return!0;for(let e of this.opts.project.workspaces)if(e.manifest.type==="module")return!0;return!1}async finalizeInstallWithPnp(e){let r=x0(this.opts.project),o=await this.locateNodeModules(e.ignorePattern);if(o.length>0){this.opts.report.reportWarning(31,"One or more node_modules have been detected and will be removed. This operation may take some time.");for(let n of o)await oe.removePromise(n)}if(await this.transformPnpSettings(e),this.opts.project.configuration.get("pnpEnableInlining")){let n=SIe(e);await oe.changeFilePromise(r.cjs,n,{automaticNewlines:!0,mode:493}),await oe.removePromise(r.data)}else{let{dataFile:n,loaderFile:u}=bIe(e);await oe.changeFilePromise(r.cjs,u,{automaticNewlines:!0,mode:493}),await oe.changeFilePromise(r.data,n,{automaticNewlines:!0,mode:420})}this.isEsmEnabled()&&(this.opts.report.reportWarning(0,"ESM support for PnP uses the experimental loader API and is therefore experimental"),await oe.changeFilePromise(r.esmLoader,(0,rG.default)(),{automaticNewlines:!0,mode:420}));let a=this.opts.project.configuration.get("pnpUnpluggedFolder");if(this.unpluggedPaths.size===0)await oe.removePromise(a);else for(let n of await oe.readdirPromise(a)){let u=z.resolve(a,n);this.unpluggedPaths.has(u)||await oe.removePromise(u)}}async locateNodeModules(e){let r=[],o=e?new RegExp(e):null;for(let a of this.opts.project.workspaces){let n=z.join(a.cwd,"node_modules");if(o&&o.test(z.relative(this.opts.project.cwd,a.cwd))||!oe.existsSync(n))continue;let u=await oe.readdirPromise(n,{withFileTypes:!0}),A=u.filter(p=>!p.isDirectory()||p.name===".bin"||!p.name.startsWith("."));if(A.length===u.length)r.push(n);else for(let p of A)r.push(z.join(n,p.name))}return r}async unplugPackageIfNeeded(e,r,o,a,n){return this.shouldBeUnplugged(e,r,a)?this.unplugPackage(e,o,n):o.packageFs}shouldBeUnplugged(e,r,o){return typeof o.unplugged<"u"?o.unplugged:jIt.has(e.identHash)||e.conditions!=null?!0:r.manifest.preferUnplugged!==null?r.manifest.preferUnplugged:!!(IQ(e,r,o,{configuration:this.opts.project.configuration})?.skipped===!1||r.misc.extractHint)}async unplugPackage(e,r,o){let a=ov(e,{configuration:this.opts.project.configuration});return this.opts.project.disabledLocators.has(e.locatorHash)?new _u(a,{baseFs:r.packageFs,pathUtils:z}):(this.unpluggedPaths.add(a),o.holdFetchResult(this.asyncActions.set(e.locatorHash,async()=>{let n=z.join(a,r.prefixPath,".ready");await oe.existsPromise(n)||(this.opts.project.storedBuildState.delete(e.locatorHash),await oe.mkdirPromise(a,{recursive:!0}),await oe.copyPromise(a,Bt.dot,{baseFs:r.packageFs,overwrite:!1}),await oe.writeFilePromise(n,""))})),new gn(a))}getPackageInformation(e){let r=W.stringifyIdent(e),o=e.reference,a=this.packageRegistry.get(r);if(!a)throw new Error(`Assertion failed: The package information store should have been available (for ${W.prettyIdent(this.opts.project.configuration,e)})`);let n=a.get(o);if(!n)throw new Error(`Assertion failed: The package information should have been available (for ${W.prettyLocator(this.opts.project.configuration,e)})`);return n}getDiskInformation(e){let r=_e.getMapWithDefault(this.packageRegistry,"@@disk"),o=sG(this.opts.project.cwd,e);return _e.getFactoryWithDefault(r,o,()=>({packageLocation:o,packageDependencies:new Map,packagePeers:new Set,linkType:"SOFT",discardFromLookup:!1}))}};function sG(t,e){let r=z.relative(t,e);return r.match(/^\.{0,2}\//)||(r=`./${r}`),r.replace(/\/?$/,"/")}async function YIt(t){let e=await Ot.tryFind(t.prefixPath,{baseFs:t.packageFs})??new Ot,r=new Set(["preinstall","install","postinstall"]);for(let o of e.scripts.keys())r.has(o)||e.scripts.delete(o);return{manifest:{scripts:e.scripts,preferUnplugged:e.preferUnplugged,type:e.type},misc:{extractHint:nG(t),hasBindingGyp:iG(t)}}}Ye();Ye();qt();var t1e=$e(Zo());var k0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Unplug direct dependencies from the entire project"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Unplug both direct and transitive dependencies"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.patterns=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);if(r.get("nodeLinker")!=="pnp")throw new it("This command can only be used if the `nodeLinker` option is set to `pnp`");await o.restoreInstallState();let u=new Set(this.patterns),A=this.patterns.map(x=>{let C=W.parseDescriptor(x),R=C.range!=="unknown"?C:W.makeDescriptor(C,"*");if(!kr.validRange(R.range))throw new it(`The range of the descriptor patterns must be a valid semver range (${W.prettyDescriptor(r,R)})`);return N=>{let U=W.stringifyIdent(N);return!t1e.default.isMatch(U,W.stringifyIdent(R))||N.version&&!kr.satisfiesWithPrereleases(N.version,R.range)?!1:(u.delete(x),!0)}}),p=()=>{let x=[];for(let C of o.storedPackages.values())!o.tryWorkspaceByLocator(C)&&!W.isVirtualLocator(C)&&A.some(R=>R(C))&&x.push(C);return x},h=x=>{let C=new Set,R=[],N=(U,V)=>{if(C.has(U.locatorHash))return;let te=!!o.tryWorkspaceByLocator(U);if(!(V>0&&!this.recursive&&te)&&(C.add(U.locatorHash),!o.tryWorkspaceByLocator(U)&&A.some(ae=>ae(U))&&R.push(U),!(V>0&&!this.recursive)))for(let ae of U.dependencies.values()){let fe=o.storedResolutions.get(ae.descriptorHash);if(!fe)throw new Error("Assertion failed: The resolution should have been registered");let ue=o.storedPackages.get(fe);if(!ue)throw new Error("Assertion failed: The package should have been registered");N(ue,V+1)}};for(let U of x)N(U.anchoredPackage,0);return R},E,I;if(this.all&&this.recursive?(E=p(),I="the project"):this.all?(E=h(o.workspaces),I="any workspace"):(E=h([a]),I="this workspace"),u.size>1)throw new it(`Patterns ${de.prettyList(r,u,de.Type.CODE)} don't match any packages referenced by ${I}`);if(u.size>0)throw new it(`Pattern ${de.prettyList(r,u,de.Type.CODE)} doesn't match any packages referenced by ${I}`);E=_e.sortMap(E,x=>W.stringifyLocator(x));let v=await Lt.start({configuration:r,stdout:this.context.stdout,json:this.json},async x=>{for(let C of E){let R=C.version??"unknown",N=o.topLevelWorkspace.manifest.ensureDependencyMeta(W.makeDescriptor(C,R));N.unplugged=!0,x.reportInfo(0,`Will unpack ${W.prettyLocator(r,C)} to ${de.pretty(r,ov(C,{configuration:r}),de.Type.PATH)}`),x.reportJson({locator:W.stringifyLocator(C),version:R})}await o.topLevelWorkspace.persistManifest(),this.json||x.reportSeparator()});return v.hasErrors()?v.exitCode():await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n})}};k0.paths=[["unplug"]],k0.usage=nt.Usage({description:"force the unpacking of a list of packages",details:"\n This command will add the selectors matching the specified patterns to the list of packages that must be unplugged when installed.\n\n A package being unplugged means that instead of being referenced directly through its archive, it will be unpacked at install time in the directory configured via `pnpUnpluggedFolder`. Note that unpacking packages this way is generally not recommended because it'll make it harder to store your packages within the repository. However, it's a good approach to quickly and safely debug some packages, and can even sometimes be required depending on the context (for example when the package contains shellscripts).\n\n Running the command will set a persistent flag inside your top-level `package.json`, in the `dependenciesMeta` field. As such, to undo its effects, you'll need to revert the changes made to the manifest and run `yarn install` to apply the modification.\n\n By default, only direct dependencies from the current workspace are affected. If `-A,--all` is set, direct dependencies from the entire project are affected. Using the `-R,--recursive` flag will affect transitive dependencies as well as direct ones.\n\n This command accepts glob patterns inside the scope and name components (not the range). Make sure to escape the patterns to prevent your own shell from trying to expand them.\n ",examples:[["Unplug the lodash dependency from the active workspace","yarn unplug lodash"],["Unplug all instances of lodash referenced by any workspace","yarn unplug lodash -A"],["Unplug all instances of lodash referenced by the active workspace and its dependencies","yarn unplug lodash -R"],["Unplug all instances of lodash, anywhere","yarn unplug lodash -AR"],["Unplug one specific version of lodash","yarn unplug lodash@1.2.3"],["Unplug all packages with the `@babel` scope","yarn unplug '@babel/*'"],["Unplug all packages (only for testing, not recommended)","yarn unplug -R '*'"]]});var x0=t=>({cjs:z.join(t.cwd,dr.pnpCjs),data:z.join(t.cwd,dr.pnpData),esmLoader:z.join(t.cwd,dr.pnpEsmLoader)}),n1e=t=>/\s/.test(t)?JSON.stringify(t):t;async function WIt(t,e,r){let o=/\s*--require\s+\S*\.pnp\.c?js\s*/g,a=/\s*--experimental-loader\s+\S*\.pnp\.loader\.mjs\s*/,n=(e.NODE_OPTIONS??"").replace(o," ").replace(a," ").trim();if(t.configuration.get("nodeLinker")!=="pnp"){e.NODE_OPTIONS=n||void 0;return}let u=x0(t),A=`--require ${n1e(le.fromPortablePath(u.cjs))}`;oe.existsSync(u.esmLoader)&&(A=`${A} --experimental-loader ${(0,r1e.pathToFileURL)(le.fromPortablePath(u.esmLoader)).href}`),oe.existsSync(u.cjs)&&(e.NODE_OPTIONS=n?`${A} ${n}`:A)}async function KIt(t,e){let r=x0(t);e(r.cjs),e(r.data),e(r.esmLoader),e(t.configuration.get("pnpUnpluggedFolder"))}var zIt={hooks:{populateYarnPaths:KIt,setupScriptEnvironment:WIt},configuration:{nodeLinker:{description:'The linker used for installing Node packages, one of: "pnp", "pnpm", or "node-modules"',type:"STRING",default:"pnp"},winLinkType:{description:"Whether Yarn should use Windows Junctions or symlinks when creating links on Windows.",type:"STRING",values:["junctions","symlinks"],default:"junctions"},pnpMode:{description:"If 'strict', generates standard PnP maps. If 'loose', merges them with the n_m resolution.",type:"STRING",default:"strict"},pnpShebang:{description:"String to prepend to the generated PnP script",type:"STRING",default:"#!/usr/bin/env node"},pnpIgnorePatterns:{description:"Array of glob patterns; files matching them will use the classic resolution",type:"STRING",default:[],isArray:!0},pnpEnableEsmLoader:{description:"If true, Yarn will generate an ESM loader (`.pnp.loader.mjs`). If this is not explicitly set Yarn tries to automatically detect whether ESM support is required.",type:"BOOLEAN",default:!1},pnpEnableInlining:{description:"If true, the PnP data will be inlined along with the generated loader",type:"BOOLEAN",default:!0},pnpFallbackMode:{description:"If true, the generated PnP loader will follow the top-level fallback rule",type:"STRING",default:"dependencies-only"},pnpUnpluggedFolder:{description:"Folder where the unplugged packages must be stored",type:"ABSOLUTE_PATH",default:"./.yarn/unplugged"}},linkers:[b0],commands:[k0]},VIt=zIt;var A1e=$e(l1e());qt();var pG=$e(ve("crypto")),f1e=$e(ve("fs")),p1e=1,Pi="node_modules",BQ=".bin",h1e=".yarn-state.yml",f1t=1e3,hG=(o=>(o.CLASSIC="classic",o.HARDLINKS_LOCAL="hardlinks-local",o.HARDLINKS_GLOBAL="hardlinks-global",o))(hG||{}),lv=class{constructor(){this.installStateCache=new Map}getCustomDataKey(){return JSON.stringify({name:"NodeModulesLinker",version:3})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error("Assertion failed: Expected the node-modules linker to be enabled");let o=r.project.tryWorkspaceByLocator(e);if(o)return o.cwd;let a=await _e.getFactoryWithDefault(this.installStateCache,r.project.cwd,async()=>await fG(r.project,{unrollAliases:!0}));if(a===null)throw new it("Couldn't find the node_modules state file - running an install might help (findPackageLocation)");let n=a.locatorMap.get(W.stringifyLocator(e));if(!n){let p=new it(`Couldn't find ${W.prettyLocator(r.project.configuration,e)} in the currently installed node_modules map - running an install might help`);throw p.code="LOCATOR_NOT_INSTALLED",p}let u=n.locations.sort((p,h)=>p.split(z.sep).length-h.split(z.sep).length),A=z.join(r.project.configuration.startingCwd,Pi);return u.find(p=>z.contains(A,p))||n.locations[0]}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let o=await _e.getFactoryWithDefault(this.installStateCache,r.project.cwd,async()=>await fG(r.project,{unrollAliases:!0}));if(o===null)return null;let{locationRoot:a,segments:n}=vQ(z.resolve(e),{skipPrefix:r.project.cwd}),u=o.locationTree.get(a);if(!u)return null;let A=u.locator;for(let p of n){if(u=u.children.get(p),!u)break;A=u.locator||A}return W.parseLocator(A)}makeInstaller(e){return new AG(e)}isEnabled(e){return e.project.configuration.get("nodeLinker")==="node-modules"}},AG=class{constructor(e){this.opts=e;this.localStore=new Map;this.realLocatorChecksums=new Map;this.customData={store:new Map}}attachCustomData(e){this.customData=e}async installPackage(e,r){let o=z.resolve(r.packageFs.getRealPath(),r.prefixPath),a=this.customData.store.get(e.locatorHash);if(typeof a>"u"&&(a=await p1t(e,r),e.linkType==="HARD"&&this.customData.store.set(e.locatorHash,a)),!W.isPackageCompatible(e,this.opts.project.configuration.getSupportedArchitectures()))return{packageLocation:null,buildRequest:null};let n=new Map,u=new Set;n.has(W.stringifyIdent(e))||n.set(W.stringifyIdent(e),e.reference);let A=e;if(W.isVirtualLocator(e)){A=W.devirtualizeLocator(e);for(let E of e.peerDependencies.values())n.set(W.stringifyIdent(E),null),u.add(W.stringifyIdent(E))}let p={packageLocation:`${le.fromPortablePath(o)}/`,packageDependencies:n,packagePeers:u,linkType:e.linkType,discardFromLookup:r.discardFromLookup??!1};this.localStore.set(e.locatorHash,{pkg:e,customPackageData:a,dependencyMeta:this.opts.project.getDependencyMeta(e,e.version),pnpNode:p});let h=r.checksum?r.checksum.substring(r.checksum.indexOf("/")+1):null;return this.realLocatorChecksums.set(A.locatorHash,h),{packageLocation:o,buildRequest:null}}async attachInternalDependencies(e,r){let o=this.localStore.get(e.locatorHash);if(typeof o>"u")throw new Error("Assertion failed: Expected information object to have been registered");for(let[a,n]of r){let u=W.areIdentsEqual(a,n)?n.reference:[W.stringifyIdent(n),n.reference];o.pnpNode.packageDependencies.set(W.stringifyIdent(a),u)}}async attachExternalDependents(e,r){throw new Error("External dependencies haven't been implemented for the node-modules linker")}async finalizeInstall(){if(this.opts.project.configuration.get("nodeLinker")!=="node-modules")return;let e=new mi({baseFs:new Jl({maxOpenFiles:80,readOnlyArchives:!0})}),r=await fG(this.opts.project),o=this.opts.project.configuration.get("nmMode");(r===null||o!==r.nmMode)&&(this.opts.project.storedBuildState.clear(),r={locatorMap:new Map,binSymlinks:new Map,locationTree:new Map,nmMode:o,mtimeMs:0});let a=new Map(this.opts.project.workspaces.map(v=>{let x=this.opts.project.configuration.get("nmHoistingLimits");try{x=_e.validateEnum(VB,v.manifest.installConfig?.hoistingLimits??x)}catch{let R=W.prettyWorkspace(this.opts.project.configuration,v);this.opts.report.reportWarning(57,`${R}: Invalid 'installConfig.hoistingLimits' value. Expected one of ${Object.values(VB).join(", ")}, using default: "${x}"`)}return[v.relativeCwd,x]})),n=new Map(this.opts.project.workspaces.map(v=>{let x=this.opts.project.configuration.get("nmSelfReferences");return x=v.manifest.installConfig?.selfReferences??x,[v.relativeCwd,x]})),u={VERSIONS:{std:1},topLevel:{name:null,reference:null},getLocator:(v,x)=>Array.isArray(x)?{name:x[0],reference:x[1]}:{name:v,reference:x},getDependencyTreeRoots:()=>this.opts.project.workspaces.map(v=>{let x=v.anchoredLocator;return{name:W.stringifyIdent(x),reference:x.reference}}),getPackageInformation:v=>{let x=v.reference===null?this.opts.project.topLevelWorkspace.anchoredLocator:W.makeLocator(W.parseIdent(v.name),v.reference),C=this.localStore.get(x.locatorHash);if(typeof C>"u")throw new Error("Assertion failed: Expected the package reference to have been registered");return C.pnpNode},findPackageLocator:v=>{let x=this.opts.project.tryWorkspaceByCwd(le.toPortablePath(v));if(x!==null){let C=x.anchoredLocator;return{name:W.stringifyIdent(C),reference:C.reference}}throw new Error("Assertion failed: Unimplemented")},resolveToUnqualified:()=>{throw new Error("Assertion failed: Unimplemented")},resolveUnqualified:()=>{throw new Error("Assertion failed: Unimplemented")},resolveRequest:()=>{throw new Error("Assertion failed: Unimplemented")},resolveVirtual:v=>le.fromPortablePath(mi.resolveVirtual(le.toPortablePath(v)))},{tree:A,errors:p,preserveSymlinksRequired:h}=JB(u,{pnpifyFs:!1,validateExternalSoftLinks:!0,hoistingLimitsByCwd:a,project:this.opts.project,selfReferencesByCwd:n});if(!A){for(let{messageName:v,text:x}of p)this.opts.report.reportError(v,x);return}let E=Hq(A);await E1t(r,E,{baseFs:e,project:this.opts.project,report:this.opts.report,realLocatorChecksums:this.realLocatorChecksums,loadManifest:async v=>{let x=W.parseLocator(v),C=this.localStore.get(x.locatorHash);if(typeof C>"u")throw new Error("Assertion failed: Expected the slot to exist");return C.customPackageData.manifest}});let I=[];for(let[v,x]of E.entries()){if(y1e(v))continue;let C=W.parseLocator(v),R=this.localStore.get(C.locatorHash);if(typeof R>"u")throw new Error("Assertion failed: Expected the slot to exist");if(this.opts.project.tryWorkspaceByLocator(R.pkg))continue;let N=yA.extractBuildRequest(R.pkg,R.customPackageData,R.dependencyMeta,{configuration:this.opts.project.configuration});!N||I.push({buildLocations:x.locations,locator:C,buildRequest:N})}return h&&this.opts.report.reportWarning(72,`The application uses portals and that's why ${de.pretty(this.opts.project.configuration,"--preserve-symlinks",de.Type.CODE)} Node option is required for launching it`),{customData:this.customData,records:I}}};async function p1t(t,e){let r=await Ot.tryFind(e.prefixPath,{baseFs:e.packageFs})??new Ot,o=new Set(["preinstall","install","postinstall"]);for(let a of r.scripts.keys())o.has(a)||r.scripts.delete(a);return{manifest:{bin:r.bin,scripts:r.scripts},misc:{hasBindingGyp:yA.hasBindingGyp(e)}}}async function h1t(t,e,r,o,{installChangedByUser:a}){let n="";n+=`# Warning: This file is automatically generated. Removing it is fine, but will
-`,n+=`# cause your node_modules installation to become invalidated.
-`,n+=`
-`,n+=`__metadata:
-`,n+=` version: ${p1e}
-`,n+=` nmMode: ${o.value}
-`;let u=Array.from(e.keys()).sort(),A=W.stringifyLocator(t.topLevelWorkspace.anchoredLocator);for(let E of u){let I=e.get(E);n+=`
-`,n+=`${JSON.stringify(E)}:
-`,n+=` locations:
-`;for(let v of I.locations){let x=z.contains(t.cwd,v);if(x===null)throw new Error(`Assertion failed: Expected the path to be within the project (${v})`);n+=` - ${JSON.stringify(x)}
-`}if(I.aliases.length>0){n+=` aliases:
-`;for(let v of I.aliases)n+=` - ${JSON.stringify(v)}
-`}if(E===A&&r.size>0){n+=` bin:
-`;for(let[v,x]of r){let C=z.contains(t.cwd,v);if(C===null)throw new Error(`Assertion failed: Expected the path to be within the project (${v})`);n+=` ${JSON.stringify(C)}:
-`;for(let[R,N]of x){let U=z.relative(z.join(v,Pi),N);n+=` ${JSON.stringify(R)}: ${JSON.stringify(U)}
-`}}}}let p=t.cwd,h=z.join(p,Pi,h1e);a&&await oe.removePromise(h),await oe.changeFilePromise(h,n,{automaticNewlines:!0})}async function fG(t,{unrollAliases:e=!1}={}){let r=t.cwd,o=z.join(r,Pi,h1e),a;try{a=await oe.statPromise(o)}catch{}if(!a)return null;let n=Ki(await oe.readFilePromise(o,"utf8"));if(n.__metadata.version>p1e)return null;let u=n.__metadata.nmMode||"classic",A=new Map,p=new Map;delete n.__metadata;for(let[h,E]of Object.entries(n)){let I=E.locations.map(x=>z.join(r,x)),v=E.bin;if(v)for(let[x,C]of Object.entries(v)){let R=z.join(r,le.toPortablePath(x)),N=_e.getMapWithDefault(p,R);for(let[U,V]of Object.entries(C))N.set(U,le.toPortablePath([R,Pi,V].join(z.sep)))}if(A.set(h,{target:Bt.dot,linkType:"HARD",locations:I,aliases:E.aliases||[]}),e&&E.aliases)for(let x of E.aliases){let{scope:C,name:R}=W.parseLocator(h),N=W.makeLocator(W.makeIdent(C,R),x),U=W.stringifyLocator(N);A.set(U,{target:Bt.dot,linkType:"HARD",locations:I,aliases:[]})}}return{locatorMap:A,binSymlinks:p,locationTree:g1e(A,{skipPrefix:t.cwd}),nmMode:u,mtimeMs:a.mtimeMs}}var WC=async(t,e)=>{if(t.split(z.sep).indexOf(Pi)<0)throw new Error(`Assertion failed: trying to remove dir that doesn't contain node_modules: ${t}`);try{if(!e.innerLoop){let o=e.allowSymlink?await oe.statPromise(t):await oe.lstatPromise(t);if(e.allowSymlink&&!o.isDirectory()||!e.allowSymlink&&o.isSymbolicLink()){await oe.unlinkPromise(t);return}}let r=await oe.readdirPromise(t,{withFileTypes:!0});for(let o of r){let a=z.join(t,o.name);o.isDirectory()?(o.name!==Pi||e&&e.innerLoop)&&await WC(a,{innerLoop:!0,contentsOnly:!1}):await oe.unlinkPromise(a)}e.contentsOnly||await oe.rmdirPromise(t)}catch(r){if(r.code!=="ENOENT"&&r.code!=="ENOTEMPTY")throw r}},c1e=4,vQ=(t,{skipPrefix:e})=>{let r=z.contains(e,t);if(r===null)throw new Error(`Assertion failed: Writing attempt prevented to ${t} which is outside project root: ${e}`);let o=r.split(z.sep).filter(p=>p!==""),a=o.indexOf(Pi),n=o.slice(0,a).join(z.sep),u=z.join(e,n),A=o.slice(a);return{locationRoot:u,segments:A}},g1e=(t,{skipPrefix:e})=>{let r=new Map;if(t===null)return r;let o=()=>({children:new Map,linkType:"HARD"});for(let[a,n]of t.entries()){if(n.linkType==="SOFT"&&z.contains(e,n.target)!==null){let A=_e.getFactoryWithDefault(r,n.target,o);A.locator=a,A.linkType=n.linkType}for(let u of n.locations){let{locationRoot:A,segments:p}=vQ(u,{skipPrefix:e}),h=_e.getFactoryWithDefault(r,A,o);for(let E=0;E<p.length;++E){let I=p[E];if(I!=="."){let v=_e.getFactoryWithDefault(h.children,I,o);h.children.set(I,v),h=v}E===p.length-1&&(h.locator=a,h.linkType=n.linkType)}}}return r},gG=async(t,e,r)=>{if(process.platform==="win32"&&r==="junctions"){let o;try{o=await oe.lstatPromise(t)}catch{}if(!o||o.isDirectory()){await oe.symlinkPromise(t,e,"junction");return}}await oe.symlinkPromise(z.relative(z.dirname(e),t),e)};async function d1e(t,e,r){let o=z.join(t,`${pG.default.randomBytes(16).toString("hex")}.tmp`);try{await oe.writeFilePromise(o,r);try{await oe.linkPromise(o,e)}catch{}}finally{await oe.unlinkPromise(o)}}async function g1t({srcPath:t,dstPath:e,entry:r,globalHardlinksStore:o,baseFs:a,nmMode:n}){if(r.kind===m1e.FILE){if(n.value==="hardlinks-global"&&o&&r.digest){let A=z.join(o,r.digest.substring(0,2),`${r.digest.substring(2)}.dat`),p;try{let h=await oe.statPromise(A);if(h&&(!r.mtimeMs||h.mtimeMs>r.mtimeMs||h.mtimeMs<r.mtimeMs-f1t))if(await wn.checksumFile(A,{baseFs:oe,algorithm:"sha1"})!==r.digest){let I=z.join(o,`${pG.default.randomBytes(16).toString("hex")}.tmp`);await oe.renamePromise(A,I);let v=await a.readFilePromise(t);await oe.writeFilePromise(I,v);try{await oe.linkPromise(I,A),r.mtimeMs=new Date().getTime(),await oe.unlinkPromise(I)}catch{}}else r.mtimeMs||(r.mtimeMs=Math.ceil(h.mtimeMs));await oe.linkPromise(A,e),p=!0}catch{p=!1}if(!p){let h=await a.readFilePromise(t);await d1e(o,A,h),r.mtimeMs=new Date().getTime();try{await oe.linkPromise(A,e)}catch(E){E&&E.code&&E.code=="EXDEV"&&(n.value="hardlinks-local",await a.copyFilePromise(t,e))}}}else await a.copyFilePromise(t,e);let u=r.mode&511;u!==420&&await oe.chmodPromise(e,u)}}var m1e=(o=>(o.FILE="file",o.DIRECTORY="directory",o.SYMLINK="symlink",o))(m1e||{}),d1t=async(t,e,{baseFs:r,globalHardlinksStore:o,nmMode:a,windowsLinkType:n,packageChecksum:u})=>{await oe.mkdirPromise(t,{recursive:!0});let A=async(E=Bt.dot)=>{let I=z.join(e,E),v=await r.readdirPromise(I,{withFileTypes:!0}),x=new Map;for(let C of v){let R=z.join(E,C.name),N,U=z.join(I,C.name);if(C.isFile()){if(N={kind:"file",mode:(await r.lstatPromise(U)).mode},a.value==="hardlinks-global"){let V=await wn.checksumFile(U,{baseFs:r,algorithm:"sha1"});N.digest=V}}else if(C.isDirectory())N={kind:"directory"};else if(C.isSymbolicLink())N={kind:"symlink",symlinkTo:await r.readlinkPromise(U)};else throw new Error(`Unsupported file type (file: ${U}, mode: 0o${await r.statSync(U).mode.toString(8).padStart(6,"0")})`);if(x.set(R,N),C.isDirectory()&&R!==Pi){let V=await A(R);for(let[te,ae]of V)x.set(te,ae)}}return x},p;if(a.value==="hardlinks-global"&&o&&u){let E=z.join(o,u.substring(0,2),`${u.substring(2)}.json`);try{p=new Map(Object.entries(JSON.parse(await oe.readFilePromise(E,"utf8"))))}catch{p=await A()}}else p=await A();let h=!1;for(let[E,I]of p){let v=z.join(e,E),x=z.join(t,E);if(I.kind==="directory")await oe.mkdirPromise(x,{recursive:!0});else if(I.kind==="file"){let C=I.mtimeMs;await g1t({srcPath:v,dstPath:x,entry:I,nmMode:a,baseFs:r,globalHardlinksStore:o}),I.mtimeMs!==C&&(h=!0)}else I.kind==="symlink"&&await gG(z.resolve(z.dirname(x),I.symlinkTo),x,n)}if(a.value==="hardlinks-global"&&o&&h&&u){let E=z.join(o,u.substring(0,2),`${u.substring(2)}.json`);await oe.removePromise(E),await d1e(o,E,Buffer.from(JSON.stringify(Object.fromEntries(p))))}};function m1t(t,e,r,o){let a=new Map,n=new Map,u=new Map,A=!1,p=(h,E,I,v,x)=>{let C=!0,R=z.join(h,E),N=new Set;if(E===Pi||E.startsWith("@")){let V;try{V=oe.statSync(R)}catch{}C=!!V,V?V.mtimeMs>r?(A=!0,N=new Set(oe.readdirSync(R))):N=new Set(I.children.get(E).children.keys()):A=!0;let te=e.get(h);if(te){let ae=z.join(h,Pi,BQ),fe;try{fe=oe.statSync(ae)}catch{}if(!fe)A=!0;else if(fe.mtimeMs>r){A=!0;let ue=new Set(oe.readdirSync(ae)),me=new Map;n.set(h,me);for(let[he,Be]of te)ue.has(he)&&me.set(he,Be)}else n.set(h,te)}}else C=x.has(E);let U=I.children.get(E);if(C){let{linkType:V,locator:te}=U,ae={children:new Map,linkType:V,locator:te};if(v.children.set(E,ae),te){let fe=_e.getSetWithDefault(u,te);fe.add(R),u.set(te,fe)}for(let fe of U.children.keys())p(R,fe,U,ae,N)}else U.locator&&o.storedBuildState.delete(W.parseLocator(U.locator).locatorHash)};for(let[h,E]of t){let{linkType:I,locator:v}=E,x={children:new Map,linkType:I,locator:v};if(a.set(h,x),v){let C=_e.getSetWithDefault(u,E.locator);C.add(h),u.set(E.locator,C)}E.children.has(Pi)&&p(h,Pi,E,x,new Set)}return{locationTree:a,binSymlinks:n,locatorLocations:u,installChangedByUser:A}}function y1e(t){let e=W.parseDescriptor(t);return W.isVirtualDescriptor(e)&&(e=W.devirtualizeDescriptor(e)),e.range.startsWith("link:")}async function y1t(t,e,r,{loadManifest:o}){let a=new Map;for(let[A,{locations:p}]of t){let h=y1e(A)?null:await o(A,p[0]),E=new Map;if(h)for(let[I,v]of h.bin){let x=z.join(p[0],v);v!==""&&oe.existsSync(x)&&E.set(I,v)}a.set(A,E)}let n=new Map,u=(A,p,h)=>{let E=new Map,I=z.contains(r,A);if(h.locator&&I!==null){let v=a.get(h.locator);for(let[x,C]of v){let R=z.join(A,le.toPortablePath(C));E.set(x,R)}for(let[x,C]of h.children){let R=z.join(A,x),N=u(R,R,C);N.size>0&&n.set(A,new Map([...n.get(A)||new Map,...N]))}}else for(let[v,x]of h.children){let C=u(z.join(A,v),p,x);for(let[R,N]of C)E.set(R,N)}return E};for(let[A,p]of e){let h=u(A,A,p);h.size>0&&n.set(A,new Map([...n.get(A)||new Map,...h]))}return n}var u1e=(t,e)=>{if(!t||!e)return t===e;let r=W.parseLocator(t);W.isVirtualLocator(r)&&(r=W.devirtualizeLocator(r));let o=W.parseLocator(e);return W.isVirtualLocator(o)&&(o=W.devirtualizeLocator(o)),W.areLocatorsEqual(r,o)};function dG(t){return z.join(t.get("globalFolder"),"store")}async function E1t(t,e,{baseFs:r,project:o,report:a,loadManifest:n,realLocatorChecksums:u}){let A=z.join(o.cwd,Pi),{locationTree:p,binSymlinks:h,locatorLocations:E,installChangedByUser:I}=m1t(t.locationTree,t.binSymlinks,t.mtimeMs,o),v=g1e(e,{skipPrefix:o.cwd}),x=[],C=async({srcDir:Be,dstDir:we,linkType:g,globalHardlinksStore:Ee,nmMode:Pe,windowsLinkType:ce,packageChecksum:ne})=>{let ee=(async()=>{try{g==="SOFT"?(await oe.mkdirPromise(z.dirname(we),{recursive:!0}),await gG(z.resolve(Be),we,ce)):await d1t(we,Be,{baseFs:r,globalHardlinksStore:Ee,nmMode:Pe,windowsLinkType:ce,packageChecksum:ne})}catch(Ie){throw Ie.message=`While persisting ${Be} -> ${we} ${Ie.message}`,Ie}finally{ae.tick()}})().then(()=>x.splice(x.indexOf(ee),1));x.push(ee),x.length>c1e&&await Promise.race(x)},R=async(Be,we,g)=>{let Ee=(async()=>{let Pe=async(ce,ne,ee)=>{try{ee.innerLoop||await oe.mkdirPromise(ne,{recursive:!0});let Ie=await oe.readdirPromise(ce,{withFileTypes:!0});for(let Fe of Ie){if(!ee.innerLoop&&Fe.name===BQ)continue;let At=z.join(ce,Fe.name),H=z.join(ne,Fe.name);Fe.isDirectory()?(Fe.name!==Pi||ee&&ee.innerLoop)&&(await oe.mkdirPromise(H,{recursive:!0}),await Pe(At,H,{...ee,innerLoop:!0})):me.value==="hardlinks-local"||me.value==="hardlinks-global"?await oe.linkPromise(At,H):await oe.copyFilePromise(At,H,f1e.default.constants.COPYFILE_FICLONE)}}catch(Ie){throw ee.innerLoop||(Ie.message=`While cloning ${ce} -> ${ne} ${Ie.message}`),Ie}finally{ee.innerLoop||ae.tick()}};await Pe(Be,we,g)})().then(()=>x.splice(x.indexOf(Ee),1));x.push(Ee),x.length>c1e&&await Promise.race(x)},N=async(Be,we,g)=>{if(g)for(let[Ee,Pe]of we.children){let ce=g.children.get(Ee);await N(z.join(Be,Ee),Pe,ce)}else{we.children.has(Pi)&&await WC(z.join(Be,Pi),{contentsOnly:!1});let Ee=z.basename(Be)===Pi&&v.has(z.join(z.dirname(Be),z.sep));await WC(Be,{contentsOnly:Be===A,allowSymlink:Ee})}};for(let[Be,we]of p){let g=v.get(Be);for(let[Ee,Pe]of we.children){if(Ee===".")continue;let ce=g&&g.children.get(Ee),ne=z.join(Be,Ee);await N(ne,Pe,ce)}}let U=async(Be,we,g)=>{if(g){u1e(we.locator,g.locator)||await WC(Be,{contentsOnly:we.linkType==="HARD"});for(let[Ee,Pe]of we.children){let ce=g.children.get(Ee);await U(z.join(Be,Ee),Pe,ce)}}else{we.children.has(Pi)&&await WC(z.join(Be,Pi),{contentsOnly:!0});let Ee=z.basename(Be)===Pi&&v.has(z.join(z.dirname(Be),z.sep));await WC(Be,{contentsOnly:we.linkType==="HARD",allowSymlink:Ee})}};for(let[Be,we]of v){let g=p.get(Be);for(let[Ee,Pe]of we.children){if(Ee===".")continue;let ce=g&&g.children.get(Ee);await U(z.join(Be,Ee),Pe,ce)}}let V=new Map,te=[];for(let[Be,we]of E)for(let g of we){let{locationRoot:Ee,segments:Pe}=vQ(g,{skipPrefix:o.cwd}),ce=v.get(Ee),ne=Ee;if(ce){for(let ee of Pe)if(ne=z.join(ne,ee),ce=ce.children.get(ee),!ce)break;if(ce){let ee=u1e(ce.locator,Be),Ie=e.get(ce.locator),Fe=Ie.target,At=ne,H=Ie.linkType;if(ee)V.has(Fe)||V.set(Fe,At);else if(Fe!==At){let at=W.parseLocator(ce.locator);W.isVirtualLocator(at)&&(at=W.devirtualizeLocator(at)),te.push({srcDir:Fe,dstDir:At,linkType:H,realLocatorHash:at.locatorHash})}}}}for(let[Be,{locations:we}]of e.entries())for(let g of we){let{locationRoot:Ee,segments:Pe}=vQ(g,{skipPrefix:o.cwd}),ce=p.get(Ee),ne=v.get(Ee),ee=Ee,Ie=e.get(Be),Fe=W.parseLocator(Be);W.isVirtualLocator(Fe)&&(Fe=W.devirtualizeLocator(Fe));let At=Fe.locatorHash,H=Ie.target,at=g;if(H===at)continue;let Re=Ie.linkType;for(let ke of Pe)ne=ne.children.get(ke);if(!ce)te.push({srcDir:H,dstDir:at,linkType:Re,realLocatorHash:At});else for(let ke of Pe)if(ee=z.join(ee,ke),ce=ce.children.get(ke),!ce){te.push({srcDir:H,dstDir:at,linkType:Re,realLocatorHash:At});break}}let ae=Xs.progressViaCounter(te.length),fe=a.reportProgress(ae),ue=o.configuration.get("nmMode"),me={value:ue},he=o.configuration.get("winLinkType");try{let Be=me.value==="hardlinks-global"?`${dG(o.configuration)}/v1`:null;if(Be&&!await oe.existsPromise(Be)){await oe.mkdirpPromise(Be);for(let g=0;g<256;g++)await oe.mkdirPromise(z.join(Be,g.toString(16).padStart(2,"0")))}for(let g of te)(g.linkType==="SOFT"||!V.has(g.srcDir))&&(V.set(g.srcDir,g.dstDir),await C({...g,globalHardlinksStore:Be,nmMode:me,windowsLinkType:he,packageChecksum:u.get(g.realLocatorHash)||null}));await Promise.all(x),x.length=0;for(let g of te){let Ee=V.get(g.srcDir);g.linkType!=="SOFT"&&g.dstDir!==Ee&&await R(Ee,g.dstDir,{nmMode:me})}await Promise.all(x),await oe.mkdirPromise(A,{recursive:!0});let we=await y1t(e,v,o.cwd,{loadManifest:n});await C1t(h,we,o.cwd,he),await h1t(o,e,we,me,{installChangedByUser:I}),ue=="hardlinks-global"&&me.value=="hardlinks-local"&&a.reportWarningOnce(74,"'nmMode' has been downgraded to 'hardlinks-local' due to global cache and install folder being on different devices")}finally{fe.stop()}}async function C1t(t,e,r,o){for(let a of t.keys()){if(z.contains(r,a)===null)throw new Error(`Assertion failed. Excepted bin symlink location to be inside project dir, instead it was at ${a}`);if(!e.has(a)){let n=z.join(a,Pi,BQ);await oe.removePromise(n)}}for(let[a,n]of e){if(z.contains(r,a)===null)throw new Error(`Assertion failed. Excepted bin symlink location to be inside project dir, instead it was at ${a}`);let u=z.join(a,Pi,BQ),A=t.get(a)||new Map;await oe.mkdirPromise(u,{recursive:!0});for(let p of A.keys())n.has(p)||(await oe.removePromise(z.join(u,p)),process.platform==="win32"&&await oe.removePromise(z.join(u,`${p}.cmd`)));for(let[p,h]of n){let E=A.get(p),I=z.join(u,p);E!==h&&(process.platform==="win32"?await(0,A1e.default)(le.fromPortablePath(h),le.fromPortablePath(I),{createPwshFile:!1}):(await oe.removePromise(I),await gG(h,I,o),z.contains(r,await oe.realpathPromise(h))!==null&&await oe.chmodPromise(h,493)))}}}Ye();Pt();iA();var cv=class extends b0{constructor(){super(...arguments);this.mode="loose"}makeInstaller(r){return new mG(r)}},mG=class extends mm{constructor(){super(...arguments);this.mode="loose"}async transformPnpSettings(r){let o=new mi({baseFs:new Jl({maxOpenFiles:80,readOnlyArchives:!0})}),a=XIe(r,this.opts.project.cwd,o),{tree:n,errors:u}=JB(a,{pnpifyFs:!1,project:this.opts.project});if(!n){for(let{messageName:I,text:v}of u)this.opts.report.reportError(I,v);return}let A=new Map;r.fallbackPool=A;let p=(I,v)=>{let x=W.parseLocator(v.locator),C=W.stringifyIdent(x);C===I?A.set(I,x.reference):A.set(I,[C,x.reference])},h=z.join(this.opts.project.cwd,dr.nodeModules),E=n.get(h);if(!(typeof E>"u")){if("target"in E)throw new Error("Assertion failed: Expected the root junction point to be a directory");for(let I of E.dirList){let v=z.join(h,I),x=n.get(v);if(typeof x>"u")throw new Error("Assertion failed: Expected the child to have been registered");if("target"in x)p(I,x);else for(let C of x.dirList){let R=z.join(v,C),N=n.get(R);if(typeof N>"u")throw new Error("Assertion failed: Expected the subchild to have been registered");if("target"in N)p(`${I}/${C}`,N);else throw new Error("Assertion failed: Expected the leaf junction to be a package")}}}}};var w1t={hooks:{cleanGlobalArtifacts:async t=>{let e=dG(t);await oe.removePromise(e)}},configuration:{nmHoistingLimits:{description:"Prevents packages to be hoisted past specific levels",type:"STRING",values:["workspaces","dependencies","none"],default:"none"},nmMode:{description:"Defines in which measure Yarn must use hardlinks and symlinks when generated `node_modules` directories.",type:"STRING",values:["classic","hardlinks-local","hardlinks-global"],default:"classic"},nmSelfReferences:{description:"Defines whether the linker should generate self-referencing symlinks for workspaces.",type:"BOOLEAN",default:!0}},linkers:[lv,cv]},I1t=w1t;var dj={};zt(dj,{NpmHttpFetcher:()=>fv,NpmRemapResolver:()=>pv,NpmSemverFetcher:()=>ml,NpmSemverResolver:()=>hv,NpmTagResolver:()=>gv,default:()=>Ovt,npmConfigUtils:()=>$n,npmHttpUtils:()=>Zr,npmPublishUtils:()=>ow});Ye();var P1e=$e(Jn());var Wn="npm:";var Zr={};zt(Zr,{AuthType:()=>B1e,customPackageError:()=>ym,del:()=>T1t,get:()=>Em,getIdentUrl:()=>DQ,getPackageMetadata:()=>VC,handleInvalidAuthenticationError:()=>Q0,post:()=>F1t,put:()=>R1t});Ye();Ye();Pt();var wG=$e(f2()),w1e=$e(D_()),I1e=$e(Jn());var $n={};zt($n,{RegistryType:()=>E1e,getAuditRegistry:()=>B1t,getAuthConfiguration:()=>CG,getDefaultRegistry:()=>uv,getPublishRegistry:()=>v1t,getRegistryConfiguration:()=>C1e,getScopeConfiguration:()=>EG,getScopeRegistry:()=>KC,normalizeRegistry:()=>ac});var E1e=(o=>(o.AUDIT_REGISTRY="npmAuditRegistry",o.FETCH_REGISTRY="npmRegistryServer",o.PUBLISH_REGISTRY="npmPublishRegistry",o))(E1e||{});function ac(t){return t.replace(/\/$/,"")}function B1t({configuration:t}){return uv({configuration:t,type:"npmAuditRegistry"})}function v1t(t,{configuration:e}){return t.publishConfig?.registry?ac(t.publishConfig.registry):t.name?KC(t.name.scope,{configuration:e,type:"npmPublishRegistry"}):uv({configuration:e,type:"npmPublishRegistry"})}function KC(t,{configuration:e,type:r="npmRegistryServer"}){let o=EG(t,{configuration:e});if(o===null)return uv({configuration:e,type:r});let a=o.get(r);return a===null?uv({configuration:e,type:r}):ac(a)}function uv({configuration:t,type:e="npmRegistryServer"}){let r=t.get(e);return ac(r!==null?r:t.get("npmRegistryServer"))}function C1e(t,{configuration:e}){let r=e.get("npmRegistries"),o=ac(t),a=r.get(o);if(typeof a<"u")return a;let n=r.get(o.replace(/^[a-z]+:/,""));return typeof n<"u"?n:null}function EG(t,{configuration:e}){if(t===null)return null;let o=e.get("npmScopes").get(t);return o||null}function CG(t,{configuration:e,ident:r}){let o=r&&EG(r.scope,{configuration:e});return o?.get("npmAuthIdent")||o?.get("npmAuthToken")?o:C1e(t,{configuration:e})||e}var B1e=(a=>(a[a.NO_AUTH=0]="NO_AUTH",a[a.BEST_EFFORT=1]="BEST_EFFORT",a[a.CONFIGURATION=2]="CONFIGURATION",a[a.ALWAYS_AUTH=3]="ALWAYS_AUTH",a))(B1e||{});async function Q0(t,{attemptedAs:e,registry:r,headers:o,configuration:a}){if(SQ(t))throw new Jt(41,"Invalid OTP token");if(t.originalError?.name==="HTTPError"&&t.originalError?.response.statusCode===401)throw new Jt(41,`Invalid authentication (${typeof e!="string"?`as ${await N1t(r,o,{configuration:a})}`:`attempted as ${e}`})`)}function ym(t,e){let r=t.response?.statusCode;return r?r===404?"Package not found":r>=500&&r<600?`The registry appears to be down (using a ${de.applyHyperlink(e,"local cache","https://yarnpkg.com/advanced/lexicon#local-cache")} might have protected you against such outages)`:null:null}function DQ(t){return t.scope?`/@${t.scope}%2f${t.name}`:`/${t.name}`}var v1e=new Map,D1t=new Map;async function P1t(t){return await _e.getFactoryWithDefault(v1e,t,async()=>{let e=null;try{e=await oe.readJsonPromise(t)}catch{}return e})}async function S1t(t,e,{configuration:r,cached:o,registry:a,headers:n,version:u,...A}){return await _e.getFactoryWithDefault(D1t,t,async()=>await Em(DQ(e),{...A,customErrorMessage:ym,configuration:r,registry:a,ident:e,headers:{...n,["If-None-Match"]:o?.etag,["If-Modified-Since"]:o?.lastModified},wrapNetworkRequest:async p=>async()=>{let h=await p();if(h.statusCode===304){if(o===null)throw new Error("Assertion failed: cachedMetadata should not be null");return{...h,body:o.metadata}}let E=b1t(JSON.parse(h.body.toString())),I={metadata:E,etag:h.headers.etag,lastModified:h.headers["last-modified"]};return v1e.set(t,Promise.resolve(I)),Promise.resolve().then(async()=>{let v=`${t}-${process.pid}.tmp`;await oe.mkdirPromise(z.dirname(v),{recursive:!0}),await oe.writeJsonPromise(v,I,{compact:!0}),await oe.renamePromise(v,t)}).catch(()=>{}),{...h,body:E}}}))}async function VC(t,{cache:e,project:r,registry:o,headers:a,version:n,...u}){let{configuration:A}=r;o=Av(A,{ident:t,registry:o});let p=k1t(A,o),h=z.join(p,`${W.slugifyIdent(t)}.json`),E=null;if(!r.lockfileNeedsRefresh&&(E=await P1t(h),E)){if(typeof n<"u"&&typeof E.metadata.versions[n]<"u")return E.metadata;if(A.get("enableOfflineMode")){let I=structuredClone(E.metadata),v=new Set;if(e){for(let C of Object.keys(I.versions)){let R=W.makeLocator(t,`npm:${C}`),N=e.getLocatorMirrorPath(R);(!N||!oe.existsSync(N))&&(delete I.versions[C],v.add(C))}let x=I["dist-tags"].latest;if(v.has(x)){let C=Object.keys(E.metadata.versions).sort(I1e.default.compare),R=C.indexOf(x);for(;v.has(C[R])&&R>=0;)R-=1;R>=0?I["dist-tags"].latest=C[R]:delete I["dist-tags"].latest}}return I}}return await S1t(h,t,{...u,configuration:A,cached:E,registry:o,headers:a,version:n})}var D1e=["name","dist.tarball","bin","scripts","os","cpu","libc","dependencies","dependenciesMeta","optionalDependencies","peerDependencies","peerDependenciesMeta","deprecated"];function b1t(t){return{"dist-tags":t["dist-tags"],versions:Object.fromEntries(Object.entries(t.versions).map(([e,r])=>[e,(0,w1e.default)(r,D1e)]))}}var x1t=wn.makeHash(...D1e).slice(0,6);function k1t(t,e){let r=Q1t(t),o=new URL(e);return z.join(r,x1t,o.hostname)}function Q1t(t){return z.join(t.get("globalFolder"),"metadata/npm")}async function Em(t,{configuration:e,headers:r,ident:o,authType:a,registry:n,...u}){n=Av(e,{ident:o,registry:n}),o&&o.scope&&typeof a>"u"&&(a=1);let A=await PQ(n,{authType:a,configuration:e,ident:o});A&&(r={...r,authorization:A});try{return await nn.get(t.charAt(0)==="/"?`${n}${t}`:t,{configuration:e,headers:r,...u})}catch(p){throw await Q0(p,{registry:n,configuration:e,headers:r}),p}}async function F1t(t,e,{attemptedAs:r,configuration:o,headers:a,ident:n,authType:u=3,registry:A,otp:p,...h}){A=Av(o,{ident:n,registry:A});let E=await PQ(A,{authType:u,configuration:o,ident:n});E&&(a={...a,authorization:E}),p&&(a={...a,...zC(p)});try{return await nn.post(A+t,e,{configuration:o,headers:a,...h})}catch(I){if(!SQ(I)||p)throw await Q0(I,{attemptedAs:r,registry:A,configuration:o,headers:a}),I;p=await IG(I,{configuration:o});let v={...a,...zC(p)};try{return await nn.post(`${A}${t}`,e,{configuration:o,headers:v,...h})}catch(x){throw await Q0(x,{attemptedAs:r,registry:A,configuration:o,headers:a}),x}}}async function R1t(t,e,{attemptedAs:r,configuration:o,headers:a,ident:n,authType:u=3,registry:A,otp:p,...h}){A=Av(o,{ident:n,registry:A});let E=await PQ(A,{authType:u,configuration:o,ident:n});E&&(a={...a,authorization:E}),p&&(a={...a,...zC(p)});try{return await nn.put(A+t,e,{configuration:o,headers:a,...h})}catch(I){if(!SQ(I))throw await Q0(I,{attemptedAs:r,registry:A,configuration:o,headers:a}),I;p=await IG(I,{configuration:o});let v={...a,...zC(p)};try{return await nn.put(`${A}${t}`,e,{configuration:o,headers:v,...h})}catch(x){throw await Q0(x,{attemptedAs:r,registry:A,configuration:o,headers:a}),x}}}async function T1t(t,{attemptedAs:e,configuration:r,headers:o,ident:a,authType:n=3,registry:u,otp:A,...p}){u=Av(r,{ident:a,registry:u});let h=await PQ(u,{authType:n,configuration:r,ident:a});h&&(o={...o,authorization:h}),A&&(o={...o,...zC(A)});try{return await nn.del(u+t,{configuration:r,headers:o,...p})}catch(E){if(!SQ(E)||A)throw await Q0(E,{attemptedAs:e,registry:u,configuration:r,headers:o}),E;A=await IG(E,{configuration:r});let I={...o,...zC(A)};try{return await nn.del(`${u}${t}`,{configuration:r,headers:I,...p})}catch(v){throw await Q0(v,{attemptedAs:e,registry:u,configuration:r,headers:o}),v}}}function Av(t,{ident:e,registry:r}){if(typeof r>"u"&&e)return KC(e.scope,{configuration:t});if(typeof r!="string")throw new Error("Assertion failed: The registry should be a string");return ac(r)}async function PQ(t,{authType:e=2,configuration:r,ident:o}){let a=CG(t,{configuration:r,ident:o}),n=L1t(a,e);if(!n)return null;let u=await r.reduceHook(A=>A.getNpmAuthenticationHeader,void 0,t,{configuration:r,ident:o});if(u)return u;if(a.get("npmAuthToken"))return`Bearer ${a.get("npmAuthToken")}`;if(a.get("npmAuthIdent")){let A=a.get("npmAuthIdent");return A.includes(":")?`Basic ${Buffer.from(A).toString("base64")}`:`Basic ${A}`}if(n&&e!==1)throw new Jt(33,"No authentication configured for request");return null}function L1t(t,e){switch(e){case 2:return t.get("npmAlwaysAuth");case 1:case 3:return!0;case 0:return!1;default:throw new Error("Unreachable")}}async function N1t(t,e,{configuration:r}){if(typeof e>"u"||typeof e.authorization>"u")return"an anonymous user";try{return(await nn.get(new URL(`${t}/-/whoami`).href,{configuration:r,headers:e,jsonResponse:!0})).username??"an unknown user"}catch{return"an unknown user"}}async function IG(t,{configuration:e}){let r=t.originalError?.response.headers["npm-notice"];if(r&&(await Lt.start({configuration:e,stdout:process.stdout,includeFooter:!1},async a=>{if(a.reportInfo(0,r.replace(/(https?:\/\/\S+)/g,de.pretty(e,"$1",de.Type.URL))),!process.env.YARN_IS_TEST_ENV){let n=r.match(/open (https?:\/\/\S+)/i);if(n&&Vi.openUrl){let{openNow:u}=await(0,wG.prompt)({type:"confirm",name:"openNow",message:"Do you want to try to open this url now?",required:!0,initial:!0,onCancel:()=>process.exit(130)});u&&(await Vi.openUrl(n[1])||(a.reportSeparator(),a.reportWarning(0,"We failed to automatically open the url; you'll have to open it yourself in your browser of choice.")))}}}),process.stdout.write(`
-`)),process.env.YARN_IS_TEST_ENV)return process.env.YARN_INJECT_NPM_2FA_TOKEN||"";let{otp:o}=await(0,wG.prompt)({type:"password",name:"otp",message:"One-time password:",required:!0,onCancel:()=>process.exit(130)});return process.stdout.write(`
-`),o}function SQ(t){if(t.originalError?.name!=="HTTPError")return!1;try{return(t.originalError?.response.headers["www-authenticate"].split(/,\s*/).map(r=>r.toLowerCase())).includes("otp")}catch{return!1}}function zC(t){return{["npm-otp"]:t}}var fv=class{supports(e,r){if(!e.reference.startsWith(Wn))return!1;let{selector:o,params:a}=W.parseRange(e.reference);return!(!P1e.default.valid(o)||a===null||typeof a.__archiveUrl!="string")}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote server`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let{params:o}=W.parseRange(e.reference);if(o===null||typeof o.__archiveUrl!="string")throw new Error("Assertion failed: The archiveUrl querystring parameter should have been available");let a=await Em(o.__archiveUrl,{customErrorMessage:ym,configuration:r.project.configuration,ident:e});return await Xi.convertToZip(a,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}};Ye();var pv=class{supportsDescriptor(e,r){return!(!e.range.startsWith(Wn)||!W.tryParseDescriptor(e.range.slice(Wn.length),!0))}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error("Unreachable")}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){let o=r.project.configuration.normalizeDependency(W.parseDescriptor(e.range.slice(Wn.length),!0));return r.resolver.getResolutionDependencies(o,r)}async getCandidates(e,r,o){let a=o.project.configuration.normalizeDependency(W.parseDescriptor(e.range.slice(Wn.length),!0));return await o.resolver.getCandidates(a,r,o)}async getSatisfying(e,r,o,a){let n=a.project.configuration.normalizeDependency(W.parseDescriptor(e.range.slice(Wn.length),!0));return a.resolver.getSatisfying(n,r,o,a)}resolve(e,r){throw new Error("Unreachable")}};Ye();Ye();var S1e=$e(Jn());var ml=class{supports(e,r){if(!e.reference.startsWith(Wn))return!1;let o=new URL(e.reference);return!(!S1e.default.valid(o.pathname)||o.searchParams.has("__archiveUrl"))}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote registry`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let o;try{o=await Em(ml.getLocatorUrl(e),{customErrorMessage:ym,configuration:r.project.configuration,ident:e})}catch{o=await Em(ml.getLocatorUrl(e).replace(/%2f/g,"/"),{customErrorMessage:ym,configuration:r.project.configuration,ident:e})}return await Xi.convertToZip(o,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}static isConventionalTarballUrl(e,r,{configuration:o}){let a=KC(e.scope,{configuration:o}),n=ml.getLocatorUrl(e);return r=r.replace(/^https?:(\/\/(?:[^/]+\.)?npmjs.org(?:$|\/))/,"https:$1"),a=a.replace(/^https:\/\/registry\.npmjs\.org($|\/)/,"https://registry.yarnpkg.com$1"),r=r.replace(/^https:\/\/registry\.npmjs\.org($|\/)/,"https://registry.yarnpkg.com$1"),r===a+n||r===a+n.replace(/%2f/g,"/")}static getLocatorUrl(e){let r=kr.clean(e.reference.slice(Wn.length));if(r===null)throw new Jt(10,"The npm semver resolver got selected, but the version isn't semver");return`${DQ(e)}/-/${e.name}-${r}.tgz`}};Ye();Ye();Ye();var BG=$e(Jn());var bQ=W.makeIdent(null,"node-gyp"),O1t=/\b(node-gyp|prebuild-install)\b/,hv=class{supportsDescriptor(e,r){return e.range.startsWith(Wn)?!!kr.validRange(e.range.slice(Wn.length)):!1}supportsLocator(e,r){if(!e.reference.startsWith(Wn))return!1;let{selector:o}=W.parseRange(e.reference);return!!BG.default.valid(o)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=kr.validRange(e.range.slice(Wn.length));if(a===null)throw new Error(`Expected a valid range, got ${e.range.slice(Wn.length)}`);let n=await VC(e,{cache:o.fetchOptions?.cache,project:o.project,version:BG.default.valid(a.raw)?a.raw:void 0}),u=_e.mapAndFilter(Object.keys(n.versions),h=>{try{let E=new kr.SemVer(h);if(a.test(E))return E}catch{}return _e.mapAndFilter.skip}),A=u.filter(h=>!n.versions[h.raw].deprecated),p=A.length>0?A:u;return p.sort((h,E)=>-h.compare(E)),p.map(h=>{let E=W.makeLocator(e,`${Wn}${h.raw}`),I=n.versions[h.raw].dist.tarball;return ml.isConventionalTarballUrl(E,I,{configuration:o.project.configuration})?E:W.bindLocator(E,{__archiveUrl:I})})}async getSatisfying(e,r,o,a){let n=kr.validRange(e.range.slice(Wn.length));if(n===null)throw new Error(`Expected a valid range, got ${e.range.slice(Wn.length)}`);return{locators:_e.mapAndFilter(o,p=>{if(p.identHash!==e.identHash)return _e.mapAndFilter.skip;let h=W.tryParseRange(p.reference,{requireProtocol:Wn});if(!h)return _e.mapAndFilter.skip;let E=new kr.SemVer(h.selector);return n.test(E)?{locator:p,version:E}:_e.mapAndFilter.skip}).sort((p,h)=>-p.version.compare(h.version)).map(({locator:p})=>p),sorted:!0}}async resolve(e,r){let{selector:o}=W.parseRange(e.reference),a=kr.clean(o);if(a===null)throw new Jt(10,"The npm semver resolver got selected, but the version isn't semver");let n=await VC(e,{cache:r.fetchOptions?.cache,project:r.project,version:a});if(!Object.hasOwn(n,"versions"))throw new Jt(15,'Registry returned invalid data for - missing "versions" field');if(!Object.hasOwn(n.versions,a))throw new Jt(16,`Registry failed to return reference "${a}"`);let u=new Ot;if(u.load(n.versions[a]),!u.dependencies.has(bQ.identHash)&&!u.peerDependencies.has(bQ.identHash)){for(let A of u.scripts.values())if(A.match(O1t)){u.dependencies.set(bQ.identHash,W.makeDescriptor(bQ,"latest"));break}}return{...e,version:a,languageName:"node",linkType:"HARD",conditions:u.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(u.dependencies),peerDependencies:u.peerDependencies,dependenciesMeta:u.dependenciesMeta,peerDependenciesMeta:u.peerDependenciesMeta,bin:u.bin}}};Ye();Ye();var b1e=$e(Jn());var gv=class{supportsDescriptor(e,r){return!(!e.range.startsWith(Wn)||!FE.test(e.range.slice(Wn.length)))}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error("Unreachable")}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=e.range.slice(Wn.length),n=await VC(e,{cache:o.fetchOptions?.cache,project:o.project});if(!Object.hasOwn(n,"dist-tags"))throw new Jt(15,'Registry returned invalid data - missing "dist-tags" field');let u=n["dist-tags"];if(!Object.hasOwn(u,a))throw new Jt(16,`Registry failed to return tag "${a}"`);let A=u[a],p=W.makeLocator(e,`${Wn}${A}`),h=n.versions[A].dist.tarball;return ml.isConventionalTarballUrl(p,h,{configuration:o.project.configuration})?[p]:[W.bindLocator(p,{__archiveUrl:h})]}async getSatisfying(e,r,o,a){let n=[];for(let u of o){if(u.identHash!==e.identHash)continue;let A=W.tryParseRange(u.reference,{requireProtocol:Wn});if(!(!A||!b1e.default.valid(A.selector))){if(A.params?.__archiveUrl){let p=W.makeRange({protocol:Wn,selector:A.selector,source:null,params:null}),[h]=await a.resolver.getCandidates(W.makeDescriptor(e,p),r,a);if(u.reference!==h.reference)continue}n.push(u)}}return{locators:n,sorted:!1}}async resolve(e,r){throw new Error("Unreachable")}};var ow={};zt(ow,{getGitHead:()=>Lvt,getPublishAccess:()=>mBe,getReadmeContent:()=>yBe,makePublishBody:()=>Tvt});Ye();Ye();Pt();var Aj={};zt(Aj,{PackCommand:()=>_0,default:()=>dvt,packUtils:()=>wA});Ye();Ye();Ye();Pt();qt();var wA={};zt(wA,{genPackList:()=>XQ,genPackStream:()=>uj,genPackageManifest:()=>sBe,hasPackScripts:()=>lj,prepareForPack:()=>cj});Ye();Pt();var aj=$e(Zo()),nBe=$e($2e()),iBe=ve("zlib"),svt=["/package.json","/readme","/readme.*","/license","/license.*","/licence","/licence.*","/changelog","/changelog.*"],ovt=["/package.tgz",".github",".git",".hg","node_modules",".npmignore",".gitignore",".#*",".DS_Store"];async function lj(t){return!!(un.hasWorkspaceScript(t,"prepack")||un.hasWorkspaceScript(t,"postpack"))}async function cj(t,{report:e},r){await un.maybeExecuteWorkspaceLifecycleScript(t,"prepack",{report:e});try{let o=z.join(t.cwd,Ot.fileName);await oe.existsPromise(o)&&await t.manifest.loadFile(o,{baseFs:oe}),await r()}finally{await un.maybeExecuteWorkspaceLifecycleScript(t,"postpack",{report:e})}}async function uj(t,e){typeof e>"u"&&(e=await XQ(t));let r=new Set;for(let n of t.manifest.publishConfig?.executableFiles??new Set)r.add(z.normalize(n));for(let n of t.manifest.bin.values())r.add(z.normalize(n));let o=nBe.default.pack();process.nextTick(async()=>{for(let n of e){let u=z.normalize(n),A=z.resolve(t.cwd,u),p=z.join("package",u),h=await oe.lstatPromise(A),E={name:p,mtime:new Date(vi.SAFE_TIME*1e3)},I=r.has(u)?493:420,v,x,C=new Promise((N,U)=>{v=N,x=U}),R=N=>{N?x(N):v()};if(h.isFile()){let N;u==="package.json"?N=Buffer.from(JSON.stringify(await sBe(t),null,2)):N=await oe.readFilePromise(A),o.entry({...E,mode:I,type:"file"},N,R)}else h.isSymbolicLink()?o.entry({...E,mode:I,type:"symlink",linkname:await oe.readlinkPromise(A)},R):R(new Error(`Unsupported file type ${h.mode} for ${le.fromPortablePath(u)}`));await C}o.finalize()});let a=(0,iBe.createGzip)();return o.pipe(a),a}async function sBe(t){let e=JSON.parse(JSON.stringify(t.manifest.raw));return await t.project.configuration.triggerHook(r=>r.beforeWorkspacePacking,t,e),e}async function XQ(t){let e=t.project,r=e.configuration,o={accept:[],reject:[]};for(let I of ovt)o.reject.push(I);for(let I of svt)o.accept.push(I);o.reject.push(r.get("rcFilename"));let a=I=>{if(I===null||!I.startsWith(`${t.cwd}/`))return;let v=z.relative(t.cwd,I),x=z.resolve(Bt.root,v);o.reject.push(x)};a(z.resolve(e.cwd,dr.lockfile)),a(r.get("cacheFolder")),a(r.get("globalFolder")),a(r.get("installStatePath")),a(r.get("virtualFolder")),a(r.get("yarnPath")),await r.triggerHook(I=>I.populateYarnPaths,e,I=>{a(I)});for(let I of e.workspaces){let v=z.relative(t.cwd,I.cwd);v!==""&&!v.match(/^(\.\.)?\//)&&o.reject.push(`/${v}`)}let n={accept:[],reject:[]},u=t.manifest.publishConfig?.main??t.manifest.main,A=t.manifest.publishConfig?.module??t.manifest.module,p=t.manifest.publishConfig?.browser??t.manifest.browser,h=t.manifest.publishConfig?.bin??t.manifest.bin;u!=null&&n.accept.push(z.resolve(Bt.root,u)),A!=null&&n.accept.push(z.resolve(Bt.root,A)),typeof p=="string"&&n.accept.push(z.resolve(Bt.root,p));for(let I of h.values())n.accept.push(z.resolve(Bt.root,I));if(p instanceof Map)for(let[I,v]of p.entries())n.accept.push(z.resolve(Bt.root,I)),typeof v=="string"&&n.accept.push(z.resolve(Bt.root,v));let E=t.manifest.files!==null;if(E){n.reject.push("/*");for(let I of t.manifest.files)oBe(n.accept,I,{cwd:Bt.root})}return await avt(t.cwd,{hasExplicitFileList:E,globalList:o,ignoreList:n})}async function avt(t,{hasExplicitFileList:e,globalList:r,ignoreList:o}){let a=[],n=new Hu(t),u=[[Bt.root,[o]]];for(;u.length>0;){let[A,p]=u.pop(),h=await n.lstatPromise(A);if(!tBe(A,{globalList:r,ignoreLists:h.isDirectory()?null:p}))if(h.isDirectory()){let E=await n.readdirPromise(A),I=!1,v=!1;if(!e||A!==Bt.root)for(let R of E)I=I||R===".gitignore",v=v||R===".npmignore";let x=v?await eBe(n,A,".npmignore"):I?await eBe(n,A,".gitignore"):null,C=x!==null?[x].concat(p):p;tBe(A,{globalList:r,ignoreLists:p})&&(C=[...p,{accept:[],reject:["**/*"]}]);for(let R of E)u.push([z.resolve(A,R),C])}else(h.isFile()||h.isSymbolicLink())&&a.push(z.relative(Bt.root,A))}return a.sort()}async function eBe(t,e,r){let o={accept:[],reject:[]},a=await t.readFilePromise(z.join(e,r),"utf8");for(let n of a.split(/\n/g))oBe(o.reject,n,{cwd:e});return o}function lvt(t,{cwd:e}){let r=t[0]==="!";return r&&(t=t.slice(1)),t.match(/\.{0,1}\//)&&(t=z.resolve(e,t)),r&&(t=`!${t}`),t}function oBe(t,e,{cwd:r}){let o=e.trim();o===""||o[0]==="#"||t.push(lvt(o,{cwd:r}))}function tBe(t,{globalList:e,ignoreLists:r}){let o=JQ(t,e.accept);if(o!==0)return o===2;let a=JQ(t,e.reject);if(a!==0)return a===1;if(r!==null)for(let n of r){let u=JQ(t,n.accept);if(u!==0)return u===2;let A=JQ(t,n.reject);if(A!==0)return A===1}return!1}function JQ(t,e){let r=e,o=[];for(let a=0;a<e.length;++a)e[a][0]!=="!"?r!==e&&r.push(e[a]):(r===e&&(r=e.slice(0,a)),o.push(e[a].slice(1)));return rBe(t,o)?2:rBe(t,r)?1:0}function rBe(t,e){let r=e,o=[];for(let a=0;a<e.length;++a)e[a].includes("/")?r!==e&&r.push(e[a]):(r===e&&(r=e.slice(0,a)),o.push(e[a]));return!!(aj.default.isMatch(t,r,{dot:!0,nocase:!0})||aj.default.isMatch(t,o,{dot:!0,basename:!0,nocase:!0}))}var _0=class extends ut{constructor(){super(...arguments);this.installIfNeeded=ge.Boolean("--install-if-needed",!1,{description:"Run a preliminary `yarn install` if the package contains build scripts"});this.dryRun=ge.Boolean("-n,--dry-run",!1,{description:"Print the file paths without actually generating the package archive"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.out=ge.String("-o,--out",{description:"Create the archive at the specified path"});this.filename=ge.String("--filename",{hidden:!0})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);await lj(a)&&(this.installIfNeeded?await o.install({cache:await Nr.find(r),report:new Qi}):await o.restoreInstallState());let n=this.out??this.filename,u=typeof n<"u"?z.resolve(this.context.cwd,cvt(n,{workspace:a})):z.resolve(a.cwd,"package.tgz");return(await Lt.start({configuration:r,stdout:this.context.stdout,json:this.json},async p=>{await cj(a,{report:p},async()=>{p.reportJson({base:le.fromPortablePath(a.cwd)});let h=await XQ(a);for(let E of h)p.reportInfo(null,le.fromPortablePath(E)),p.reportJson({location:le.fromPortablePath(E)});if(!this.dryRun){let E=await uj(a,h),I=oe.createWriteStream(u);E.pipe(I),await new Promise(v=>{I.on("finish",v)})}}),this.dryRun||(p.reportInfo(0,`Package archive generated in ${de.pretty(r,u,de.Type.PATH)}`),p.reportJson({output:le.fromPortablePath(u)}))})).exitCode()}};_0.paths=[["pack"]],_0.usage=nt.Usage({description:"generate a tarball from the active workspace",details:"\n This command will turn the active workspace into a compressed archive suitable for publishing. The archive will by default be stored at the root of the workspace (`package.tgz`).\n\n If the `-o,---out` is set the archive will be created at the specified path. The `%s` and `%v` variables can be used within the path and will be respectively replaced by the package name and version.\n ",examples:[["Create an archive from the active workspace","yarn pack"],["List the files that would be made part of the workspace's archive","yarn pack --dry-run"],["Name and output the archive in a dedicated folder","yarn pack --out /artifacts/%s-%v.tgz"]]});function cvt(t,{workspace:e}){let r=t.replace("%s",uvt(e)).replace("%v",Avt(e));return le.toPortablePath(r)}function uvt(t){return t.manifest.name!==null?W.slugifyIdent(t.manifest.name):"package"}function Avt(t){return t.manifest.version!==null?t.manifest.version:"unknown"}var fvt=["dependencies","devDependencies","peerDependencies"],pvt="workspace:",hvt=(t,e)=>{e.publishConfig&&(e.publishConfig.type&&(e.type=e.publishConfig.type),e.publishConfig.main&&(e.main=e.publishConfig.main),e.publishConfig.browser&&(e.browser=e.publishConfig.browser),e.publishConfig.module&&(e.module=e.publishConfig.module),e.publishConfig.exports&&(e.exports=e.publishConfig.exports),e.publishConfig.imports&&(e.imports=e.publishConfig.imports),e.publishConfig.bin&&(e.bin=e.publishConfig.bin));let r=t.project;for(let o of fvt)for(let a of t.manifest.getForScope(o).values()){let n=r.tryWorkspaceByDescriptor(a),u=W.parseRange(a.range);if(u.protocol===pvt)if(n===null){if(r.tryWorkspaceByIdent(a)===null)throw new Jt(21,`${W.prettyDescriptor(r.configuration,a)}: No local workspace found for this range`)}else{let A;W.areDescriptorsEqual(a,n.anchoredDescriptor)||u.selector==="*"?A=n.manifest.version??"0.0.0":u.selector==="~"||u.selector==="^"?A=`${u.selector}${n.manifest.version??"0.0.0"}`:A=u.selector;let p=o==="dependencies"?W.makeDescriptor(a,"unknown"):null,h=p!==null&&t.manifest.ensureDependencyMeta(p).optional?"optionalDependencies":o;e[h][W.stringifyIdent(a)]=A}}},gvt={hooks:{beforeWorkspacePacking:hvt},commands:[_0]},dvt=gvt;var gBe=ve("crypto"),dBe=$e(hBe());async function Tvt(t,e,{access:r,tag:o,registry:a,gitHead:n}){let u=t.manifest.name,A=t.manifest.version,p=W.stringifyIdent(u),h=(0,gBe.createHash)("sha1").update(e).digest("hex"),E=dBe.default.fromData(e).toString(),I=r??mBe(t,u),v=await yBe(t),x=await wA.genPackageManifest(t),C=`${p}-${A}.tgz`,R=new URL(`${ac(a)}/${p}/-/${C}`);return{_id:p,_attachments:{[C]:{content_type:"application/octet-stream",data:e.toString("base64"),length:e.length}},name:p,access:I,["dist-tags"]:{[o]:A},versions:{[A]:{...x,_id:`${p}@${A}`,name:p,version:A,gitHead:n,dist:{shasum:h,integrity:E,tarball:R.toString()}}},readme:v}}async function Lvt(t){try{let{stdout:e}=await Ur.execvp("git",["rev-parse","--revs-only","HEAD"],{cwd:t});return e.trim()===""?void 0:e.trim()}catch{return}}function mBe(t,e){let r=t.project.configuration;return t.manifest.publishConfig&&typeof t.manifest.publishConfig.access=="string"?t.manifest.publishConfig.access:r.get("npmPublishAccess")!==null?r.get("npmPublishAccess"):e.scope?"restricted":"public"}async function yBe(t){let e=le.toPortablePath(`${t.cwd}/README.md`),r=t.manifest.name,a=`# ${W.stringifyIdent(r)}
-`;try{a=await oe.readFilePromise(e,"utf8")}catch(n){if(n.code==="ENOENT")return a;throw n}return a}var gj={npmAlwaysAuth:{description:"URL of the selected npm registry (note: npm enterprise isn't supported)",type:"BOOLEAN",default:!1},npmAuthIdent:{description:"Authentication identity for the npm registry (_auth in npm and yarn v1)",type:"SECRET",default:null},npmAuthToken:{description:"Authentication token for the npm registry (_authToken in npm and yarn v1)",type:"SECRET",default:null}},EBe={npmAuditRegistry:{description:"Registry to query for audit reports",type:"STRING",default:null},npmPublishRegistry:{description:"Registry to push packages to",type:"STRING",default:null},npmRegistryServer:{description:"URL of the selected npm registry (note: npm enterprise isn't supported)",type:"STRING",default:"https://registry.yarnpkg.com"}},Nvt={configuration:{...gj,...EBe,npmScopes:{description:"Settings per package scope",type:"MAP",valueDefinition:{description:"",type:"SHAPE",properties:{...gj,...EBe}}},npmRegistries:{description:"Settings per registry",type:"MAP",normalizeKeys:ac,valueDefinition:{description:"",type:"SHAPE",properties:{...gj}}}},fetchers:[fv,ml],resolvers:[pv,hv,gv]},Ovt=Nvt;var Dj={};zt(Dj,{NpmAuditCommand:()=>q0,NpmInfoCommand:()=>G0,NpmLoginCommand:()=>j0,NpmLogoutCommand:()=>Y0,NpmPublishCommand:()=>W0,NpmTagAddCommand:()=>z0,NpmTagListCommand:()=>K0,NpmTagRemoveCommand:()=>V0,NpmWhoamiCommand:()=>J0,default:()=>jvt,npmAuditTypes:()=>Rv,npmAuditUtils:()=>ZQ});Ye();Ye();qt();var wj=$e(Zo());$a();var Rv={};zt(Rv,{Environment:()=>Qv,Severity:()=>Fv});var Qv=(o=>(o.All="all",o.Production="production",o.Development="development",o))(Qv||{}),Fv=(n=>(n.Info="info",n.Low="low",n.Moderate="moderate",n.High="high",n.Critical="critical",n))(Fv||{});var ZQ={};zt(ZQ,{allSeverities:()=>aw,getPackages:()=>Cj,getReportTree:()=>yj,getSeverityInclusions:()=>mj,getTopLevelDependencies:()=>Ej});Ye();var CBe=$e(Jn());var aw=["info","low","moderate","high","critical"];function mj(t){if(typeof t>"u")return new Set(aw);let e=aw.indexOf(t),r=aw.slice(e);return new Set(r)}function yj(t){let e={},r={children:e};for(let[o,a]of _e.sortMap(Object.entries(t),n=>n[0]))for(let n of _e.sortMap(a,u=>`${u.id}`))e[`${o}/${n.id}`]={value:de.tuple(de.Type.IDENT,W.parseIdent(o)),children:{ID:typeof n.id<"u"&&{label:"ID",value:de.tuple(de.Type.ID,n.id)},Issue:{label:"Issue",value:de.tuple(de.Type.NO_HINT,n.title)},URL:typeof n.url<"u"&&{label:"URL",value:de.tuple(de.Type.URL,n.url)},Severity:{label:"Severity",value:de.tuple(de.Type.NO_HINT,n.severity)},["Vulnerable Versions"]:{label:"Vulnerable Versions",value:de.tuple(de.Type.RANGE,n.vulnerable_versions)},["Tree Versions"]:{label:"Tree Versions",children:[...n.versions].sort(CBe.default.compare).map(u=>({value:de.tuple(de.Type.REFERENCE,u)}))},Dependents:{label:"Dependents",children:_e.sortMap(n.dependents,u=>W.stringifyLocator(u)).map(u=>({value:de.tuple(de.Type.LOCATOR,u)}))}}};return r}function Ej(t,e,{all:r,environment:o}){let a=[],n=r?t.workspaces:[e],u=["all","production"].includes(o),A=["all","development"].includes(o);for(let p of n)for(let h of p.anchoredPackage.dependencies.values())(p.manifest.devDependencies.has(h.identHash)?!A:!u)||a.push({workspace:p,dependency:h});return a}function Cj(t,e,{recursive:r}){let o=new Map,a=new Set,n=[],u=(A,p)=>{let h=t.storedResolutions.get(p.descriptorHash);if(typeof h>"u")throw new Error("Assertion failed: The resolution should have been registered");if(!a.has(h))a.add(h);else return;let E=t.storedPackages.get(h);if(typeof E>"u")throw new Error("Assertion failed: The package should have been registered");if(W.ensureDevirtualizedLocator(E).reference.startsWith("npm:")&&E.version!==null){let v=W.stringifyIdent(E),x=_e.getMapWithDefault(o,v);_e.getArrayWithDefault(x,E.version).push(A)}if(r)for(let v of E.dependencies.values())n.push([E,v])};for(let{workspace:A,dependency:p}of e)n.push([A.anchoredLocator,p]);for(;n.length>0;){let[A,p]=n.shift();u(A,p)}return o}var q0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean("-A,--all",!1,{description:"Audit dependencies from all workspaces"});this.recursive=ge.Boolean("-R,--recursive",!1,{description:"Audit transitive dependencies as well"});this.environment=ge.String("--environment","all",{description:"Which environments to cover",validator:Ks(Qv)});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.noDeprecations=ge.Boolean("--no-deprecations",!1,{description:"Don't warn about deprecated packages"});this.severity=ge.String("--severity","info",{description:"Minimal severity requested for packages to be displayed",validator:Ks(Fv)});this.excludes=ge.Array("--exclude",[],{description:"Array of glob patterns of packages to exclude from audit"});this.ignores=ge.Array("--ignore",[],{description:"Array of glob patterns of advisory ID's to ignore in the audit report"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=Ej(o,a,{all:this.all,environment:this.environment}),u=Cj(o,n,{recursive:this.recursive}),A=Array.from(new Set([...r.get("npmAuditExcludePackages"),...this.excludes])),p=Object.create(null);for(let[N,U]of u)A.some(V=>wj.default.isMatch(N,V))||(p[N]=[...U.keys()]);let h=$n.getAuditRegistry({configuration:r}),E,I=await fA.start({configuration:r,stdout:this.context.stdout},async()=>{let N=Zr.post("/-/npm/v1/security/advisories/bulk",p,{authType:Zr.AuthType.BEST_EFFORT,configuration:r,jsonResponse:!0,registry:h}),U=this.noDeprecations?[]:await Promise.all(Array.from(Object.entries(p),async([te,ae])=>{let fe=await Zr.getPackageMetadata(W.parseIdent(te),{project:o});return _e.mapAndFilter(ae,ue=>{let{deprecated:me}=fe.versions[ue];return me?[te,ue,me]:_e.mapAndFilter.skip})})),V=await N;for(let[te,ae,fe]of U.flat(1))Object.hasOwn(V,te)&&V[te].some(ue=>kr.satisfiesWithPrereleases(ae,ue.vulnerable_versions))||(V[te]??=[],V[te].push({id:`${te} (deprecation)`,title:fe.trim()||"This package has been deprecated.",severity:"moderate",vulnerable_versions:ae}));E=V});if(I.hasErrors())return I.exitCode();let v=mj(this.severity),x=Array.from(new Set([...r.get("npmAuditIgnoreAdvisories"),...this.ignores])),C=Object.create(null);for(let[N,U]of Object.entries(E)){let V=U.filter(te=>!wj.default.isMatch(`${te.id}`,x)&&v.has(te.severity));V.length>0&&(C[N]=V.map(te=>{let ae=u.get(N);if(typeof ae>"u")throw new Error("Assertion failed: Expected the registry to only return packages that were requested");let fe=[...ae.keys()].filter(me=>kr.satisfiesWithPrereleases(me,te.vulnerable_versions)),ue=new Map;for(let me of fe)for(let he of ae.get(me))ue.set(he.locatorHash,he);return{...te,versions:fe,dependents:[...ue.values()]}}))}let R=Object.keys(C).length>0;return R?($s.emitTree(yj(C),{configuration:r,json:this.json,stdout:this.context.stdout,separators:2}),1):(await Lt.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async N=>{N.reportInfo(1,"No audit suggestions")}),R?1:0)}};q0.paths=[["npm","audit"]],q0.usage=nt.Usage({description:"perform a vulnerability audit against the installed packages",details:`
- This command checks for known security reports on the packages you use. The reports are by default extracted from the npm registry, and may or may not be relevant to your actual program (not all vulnerabilities affect all code paths).
-
- For consistency with our other commands the default is to only check the direct dependencies for the active workspace. To extend this search to all workspaces, use \`-A,--all\`. To extend this search to both direct and transitive dependencies, use \`-R,--recursive\`.
-
- Applying the \`--severity\` flag will limit the audit table to vulnerabilities of the corresponding severity and above. Valid values are ${aw.map(r=>`\`${r}\``).join(", ")}.
-
- If the \`--json\` flag is set, Yarn will print the output exactly as received from the registry. Regardless of this flag, the process will exit with a non-zero exit code if a report is found for the selected packages.
-
- If certain packages produce false positives for a particular environment, the \`--exclude\` flag can be used to exclude any number of packages from the audit. This can also be set in the configuration file with the \`npmAuditExcludePackages\` option.
-
- If particular advisories are needed to be ignored, the \`--ignore\` flag can be used with Advisory ID's to ignore any number of advisories in the audit report. This can also be set in the configuration file with the \`npmAuditIgnoreAdvisories\` option.
-
- To understand the dependency tree requiring vulnerable packages, check the raw report with the \`--json\` flag or use \`yarn why package\` to get more information as to who depends on them.
- `,examples:[["Checks for known security issues with the installed packages. The output is a list of known issues.","yarn npm audit"],["Audit dependencies in all workspaces","yarn npm audit --all"],["Limit auditing to `dependencies` (excludes `devDependencies`)","yarn npm audit --environment production"],["Show audit report as valid JSON","yarn npm audit --json"],["Audit all direct and transitive dependencies","yarn npm audit --recursive"],["Output moderate (or more severe) vulnerabilities","yarn npm audit --severity moderate"],["Exclude certain packages","yarn npm audit --exclude package1 --exclude package2"],["Ignore specific advisories","yarn npm audit --ignore 1234567 --ignore 7654321"]]});Ye();Ye();Pt();qt();var Ij=$e(Jn()),Bj=ve("util"),G0=class extends ut{constructor(){super(...arguments);this.fields=ge.String("-f,--fields",{description:"A comma-separated list of manifest fields that should be displayed"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.packages=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),a=typeof this.fields<"u"?new Set(["name",...this.fields.split(/\s*,\s*/)]):null,n=[],u=!1,A=await Lt.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async p=>{for(let h of this.packages){let E;if(h==="."){let ae=o.topLevelWorkspace;if(!ae.manifest.name)throw new it(`Missing ${de.pretty(r,"name",de.Type.CODE)} field in ${le.fromPortablePath(z.join(ae.cwd,dr.manifest))}`);E=W.makeDescriptor(ae.manifest.name,"unknown")}else E=W.parseDescriptor(h);let I=Zr.getIdentUrl(E),v=vj(await Zr.get(I,{configuration:r,ident:E,jsonResponse:!0,customErrorMessage:Zr.customPackageError})),x=Object.keys(v.versions).sort(Ij.default.compareLoose),R=v["dist-tags"].latest||x[x.length-1],N=kr.validRange(E.range);if(N){let ae=Ij.default.maxSatisfying(x,N);ae!==null?R=ae:(p.reportWarning(0,`Unmet range ${W.prettyRange(r,E.range)}; falling back to the latest version`),u=!0)}else Object.hasOwn(v["dist-tags"],E.range)?R=v["dist-tags"][E.range]:E.range!=="unknown"&&(p.reportWarning(0,`Unknown tag ${W.prettyRange(r,E.range)}; falling back to the latest version`),u=!0);let U=v.versions[R],V={...v,...U,version:R,versions:x},te;if(a!==null){te={};for(let ae of a){let fe=V[ae];if(typeof fe<"u")te[ae]=fe;else{p.reportWarning(1,`The ${de.pretty(r,ae,de.Type.CODE)} field doesn't exist inside ${W.prettyIdent(r,E)}'s information`),u=!0;continue}}}else this.json||(delete V.dist,delete V.readme,delete V.users),te=V;p.reportJson(te),this.json||n.push(te)}});Bj.inspect.styles.name="cyan";for(let p of n)(p!==n[0]||u)&&this.context.stdout.write(`
-`),this.context.stdout.write(`${(0,Bj.inspect)(p,{depth:1/0,colors:!0,compact:!1})}
-`);return A.exitCode()}};G0.paths=[["npm","info"]],G0.usage=nt.Usage({category:"Npm-related commands",description:"show information about a package",details:"\n This command fetches information about a package from the npm registry and prints it in a tree format.\n\n The package does not have to be installed locally, but needs to have been published (in particular, local changes will be ignored even for workspaces).\n\n Append `@<range>` to the package argument to provide information specific to the latest version that satisfies the range or to the corresponding tagged version. If the range is invalid or if there is no version satisfying the range, the command will print a warning and fall back to the latest version.\n\n If the `-f,--fields` option is set, it's a comma-separated list of fields which will be used to only display part of the package information.\n\n By default, this command won't return the `dist`, `readme`, and `users` fields, since they are often very long. To explicitly request those fields, explicitly list them with the `--fields` flag or request the output in JSON mode.\n ",examples:[["Show all available information about react (except the `dist`, `readme`, and `users` fields)","yarn npm info react"],["Show all available information about react as valid JSON (including the `dist`, `readme`, and `users` fields)","yarn npm info react --json"],["Show all available information about react@16.12.0","yarn npm info react@16.12.0"],["Show all available information about react@next","yarn npm info react@next"],["Show the description of react","yarn npm info react --fields description"],["Show all available versions of react","yarn npm info react --fields versions"],["Show the readme of react","yarn npm info react --fields readme"],["Show a few fields of react","yarn npm info react --fields homepage,repository"]]});function vj(t){if(Array.isArray(t)){let e=[];for(let r of t)r=vj(r),r&&e.push(r);return e}else if(typeof t=="object"&&t!==null){let e={};for(let r of Object.keys(t)){if(r.startsWith("_"))continue;let o=vj(t[r]);o&&(e[r]=o)}return e}else return t||null}Ye();Ye();qt();var wBe=$e(f2()),j0=class extends ut{constructor(){super(...arguments);this.scope=ge.String("-s,--scope",{description:"Login to the registry configured for a given scope"});this.publish=ge.Boolean("--publish",!1,{description:"Login to the publish registry"});this.alwaysAuth=ge.Boolean("--always-auth",{description:"Set the npmAlwaysAuth configuration"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=await $Q({configuration:r,cwd:this.context.cwd,publish:this.publish,scope:this.scope});return(await Lt.start({configuration:r,stdout:this.context.stdout,includeFooter:!1},async n=>{let u=await _vt({configuration:r,registry:o,report:n,stdin:this.context.stdin,stdout:this.context.stdout}),A=await Mvt(o,u,r);return await Uvt(o,A,{alwaysAuth:this.alwaysAuth,scope:this.scope}),n.reportInfo(0,"Successfully logged in")})).exitCode()}};j0.paths=[["npm","login"]],j0.usage=nt.Usage({category:"Npm-related commands",description:"store new login info to access the npm registry",details:"\n This command will ask you for your username, password, and 2FA One-Time-Password (when it applies). It will then modify your local configuration (in your home folder, never in the project itself) to reference the new tokens thus generated.\n\n Adding the `-s,--scope` flag will cause the authentication to be done against whatever registry is configured for the associated scope (see also `npmScopes`).\n\n Adding the `--publish` flag will cause the authentication to be done against the registry used when publishing the package (see also `publishConfig.registry` and `npmPublishRegistry`).\n ",examples:[["Login to the default registry","yarn npm login"],["Login to the registry linked to the @my-scope registry","yarn npm login --scope my-scope"],["Login to the publish registry for the current package","yarn npm login --publish"]]});async function $Q({scope:t,publish:e,configuration:r,cwd:o}){return t&&e?$n.getScopeRegistry(t,{configuration:r,type:$n.RegistryType.PUBLISH_REGISTRY}):t?$n.getScopeRegistry(t,{configuration:r}):e?$n.getPublishRegistry((await fC(r,o)).manifest,{configuration:r}):$n.getDefaultRegistry({configuration:r})}async function Mvt(t,e,r){let o=`/-/user/org.couchdb.user:${encodeURIComponent(e.name)}`,a={_id:`org.couchdb.user:${e.name}`,name:e.name,password:e.password,type:"user",roles:[],date:new Date().toISOString()},n={attemptedAs:e.name,configuration:r,registry:t,jsonResponse:!0,authType:Zr.AuthType.NO_AUTH};try{return(await Zr.put(o,a,n)).token}catch(E){if(!(E.originalError?.name==="HTTPError"&&E.originalError?.response.statusCode===409))throw E}let u={...n,authType:Zr.AuthType.NO_AUTH,headers:{authorization:`Basic ${Buffer.from(`${e.name}:${e.password}`).toString("base64")}`}},A=await Zr.get(o,u);for(let[E,I]of Object.entries(A))(!a[E]||E==="roles")&&(a[E]=I);let p=`${o}/-rev/${a._rev}`;return(await Zr.put(p,a,u)).token}async function Uvt(t,e,{alwaysAuth:r,scope:o}){let a=u=>A=>{let p=_e.isIndexableObject(A)?A:{},h=p[u],E=_e.isIndexableObject(h)?h:{};return{...p,[u]:{...E,...r!==void 0?{npmAlwaysAuth:r}:{},npmAuthToken:e}}},n=o?{npmScopes:a(o)}:{npmRegistries:a(t)};return await Ke.updateHomeConfiguration(n)}async function _vt({configuration:t,registry:e,report:r,stdin:o,stdout:a}){r.reportInfo(0,`Logging in to ${de.pretty(t,e,de.Type.URL)}`);let n=!1;if(e.match(/^https:\/\/npm\.pkg\.github\.com(\/|$)/)&&(r.reportInfo(0,"You seem to be using the GitHub Package Registry. Tokens must be generated with the 'repo', 'write:packages', and 'read:packages' permissions."),n=!0),r.reportSeparator(),t.env.YARN_IS_TEST_ENV)return{name:t.env.YARN_INJECT_NPM_USER||"",password:t.env.YARN_INJECT_NPM_PASSWORD||""};let u=await(0,wBe.prompt)([{type:"input",name:"name",message:"Username:",required:!0,onCancel:()=>process.exit(130),stdin:o,stdout:a},{type:"password",name:"password",message:n?"Token:":"Password:",required:!0,onCancel:()=>process.exit(130),stdin:o,stdout:a}]);return r.reportSeparator(),u}Ye();Ye();qt();var lw=new Set(["npmAuthIdent","npmAuthToken"]),Y0=class extends ut{constructor(){super(...arguments);this.scope=ge.String("-s,--scope",{description:"Logout of the registry configured for a given scope"});this.publish=ge.Boolean("--publish",!1,{description:"Logout of the publish registry"});this.all=ge.Boolean("-A,--all",!1,{description:"Logout of all registries"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=async()=>{let n=await $Q({configuration:r,cwd:this.context.cwd,publish:this.publish,scope:this.scope}),u=await Ke.find(this.context.cwd,this.context.plugins),A=W.makeIdent(this.scope??null,"pkg");return!$n.getAuthConfiguration(n,{configuration:u,ident:A}).get("npmAuthToken")};return(await Lt.start({configuration:r,stdout:this.context.stdout},async n=>{if(this.all&&(await qvt(),n.reportInfo(0,"Successfully logged out from everything")),this.scope){await IBe("npmScopes",this.scope),await o()?n.reportInfo(0,`Successfully logged out from ${this.scope}`):n.reportWarning(0,"Scope authentication settings removed, but some other ones settings still apply to it");return}let u=await $Q({configuration:r,cwd:this.context.cwd,publish:this.publish});await IBe("npmRegistries",u),await o()?n.reportInfo(0,`Successfully logged out from ${u}`):n.reportWarning(0,"Registry authentication settings removed, but some other ones settings still apply to it")})).exitCode()}};Y0.paths=[["npm","logout"]],Y0.usage=nt.Usage({category:"Npm-related commands",description:"logout of the npm registry",details:"\n This command will log you out by modifying your local configuration (in your home folder, never in the project itself) to delete all credentials linked to a registry.\n\n Adding the `-s,--scope` flag will cause the deletion to be done against whatever registry is configured for the associated scope (see also `npmScopes`).\n\n Adding the `--publish` flag will cause the deletion to be done against the registry used when publishing the package (see also `publishConfig.registry` and `npmPublishRegistry`).\n\n Adding the `-A,--all` flag will cause the deletion to be done against all registries and scopes.\n ",examples:[["Logout of the default registry","yarn npm logout"],["Logout of the @my-scope scope","yarn npm logout --scope my-scope"],["Logout of the publish registry for the current package","yarn npm logout --publish"],["Logout of all registries","yarn npm logout --all"]]});function Hvt(t,e){let r=t[e];if(!_e.isIndexableObject(r))return!1;let o=new Set(Object.keys(r));if([...lw].every(n=>!o.has(n)))return!1;for(let n of lw)o.delete(n);if(o.size===0)return t[e]=void 0,!0;let a={...r};for(let n of lw)delete a[n];return t[e]=a,!0}async function qvt(){let t=e=>{let r=!1,o=_e.isIndexableObject(e)?{...e}:{};o.npmAuthToken&&(delete o.npmAuthToken,r=!0);for(let a of Object.keys(o))Hvt(o,a)&&(r=!0);if(Object.keys(o).length!==0)return r?o:e};return await Ke.updateHomeConfiguration({npmRegistries:t,npmScopes:t})}async function IBe(t,e){return await Ke.updateHomeConfiguration({[t]:r=>{let o=_e.isIndexableObject(r)?r:{};if(!Object.hasOwn(o,e))return r;let a=o[e],n=_e.isIndexableObject(a)?a:{},u=new Set(Object.keys(n));if([...lw].every(p=>!u.has(p)))return r;for(let p of lw)u.delete(p);if(u.size===0)return Object.keys(o).length===1?void 0:{...o,[e]:void 0};let A={};for(let p of lw)A[p]=void 0;return{...o,[e]:{...n,...A}}}})}Ye();qt();var W0=class extends ut{constructor(){super(...arguments);this.access=ge.String("--access",{description:"The access for the published package (public or restricted)"});this.tag=ge.String("--tag","latest",{description:"The tag on the registry that the package should be attached to"});this.tolerateRepublish=ge.Boolean("--tolerate-republish",!1,{description:"Warn and exit when republishing an already existing version of a package"});this.otp=ge.String("--otp",{description:"The OTP token to use with the command"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);if(a.manifest.private)throw new it("Private workspaces cannot be published");if(a.manifest.name===null||a.manifest.version===null)throw new it("Workspaces must have valid names and versions to be published on an external registry");await o.restoreInstallState();let n=a.manifest.name,u=a.manifest.version,A=$n.getPublishRegistry(a.manifest,{configuration:r});return(await Lt.start({configuration:r,stdout:this.context.stdout},async h=>{if(this.tolerateRepublish)try{let E=await Zr.get(Zr.getIdentUrl(n),{configuration:r,registry:A,ident:n,jsonResponse:!0});if(!Object.hasOwn(E,"versions"))throw new Jt(15,'Registry returned invalid data for - missing "versions" field');if(Object.hasOwn(E.versions,u)){h.reportWarning(0,`Registry already knows about version ${u}; skipping.`);return}}catch(E){if(E.originalError?.response?.statusCode!==404)throw E}await un.maybeExecuteWorkspaceLifecycleScript(a,"prepublish",{report:h}),await wA.prepareForPack(a,{report:h},async()=>{let E=await wA.genPackList(a);for(let R of E)h.reportInfo(null,R);let I=await wA.genPackStream(a,E),v=await _e.bufferStream(I),x=await ow.getGitHead(a.cwd),C=await ow.makePublishBody(a,v,{access:this.access,tag:this.tag,registry:A,gitHead:x});await Zr.put(Zr.getIdentUrl(n),C,{configuration:r,registry:A,ident:n,otp:this.otp,jsonResponse:!0})}),h.reportInfo(0,"Package archive published")})).exitCode()}};W0.paths=[["npm","publish"]],W0.usage=nt.Usage({category:"Npm-related commands",description:"publish the active workspace to the npm registry",details:'\n This command will pack the active workspace into a fresh archive and upload it to the npm registry.\n\n The package will by default be attached to the `latest` tag on the registry, but this behavior can be overridden by using the `--tag` option.\n\n Note that for legacy reasons scoped packages are by default published with an access set to `restricted` (aka "private packages"). This requires you to register for a paid npm plan. In case you simply wish to publish a public scoped package to the registry (for free), just add the `--access public` flag. This behavior can be enabled by default through the `npmPublishAccess` settings.\n ',examples:[["Publish the active workspace","yarn npm publish"]]});Ye();qt();var BBe=$e(Jn());Ye();Pt();qt();var K0=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.package=ge.String({required:!1})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n;if(typeof this.package<"u")n=W.parseIdent(this.package);else{if(!a)throw new nr(o.cwd,this.context.cwd);if(!a.manifest.name)throw new it(`Missing 'name' field in ${le.fromPortablePath(z.join(a.cwd,dr.manifest))}`);n=a.manifest.name}let u=await Tv(n,r),p={children:_e.sortMap(Object.entries(u),([h])=>h).map(([h,E])=>({value:de.tuple(de.Type.RESOLUTION,{descriptor:W.makeDescriptor(n,h),locator:W.makeLocator(n,E)})}))};return $s.emitTree(p,{configuration:r,json:this.json,stdout:this.context.stdout})}};K0.paths=[["npm","tag","list"]],K0.usage=nt.Usage({category:"Npm-related commands",description:"list all dist-tags of a package",details:`
- This command will list all tags of a package from the npm registry.
-
- If the package is not specified, Yarn will default to the current workspace.
- `,examples:[["List all tags of package `my-pkg`","yarn npm tag list my-pkg"]]});async function Tv(t,e){let r=`/-/package${Zr.getIdentUrl(t)}/dist-tags`;return Zr.get(r,{configuration:e,ident:t,jsonResponse:!0,customErrorMessage:Zr.customPackageError})}var z0=class extends ut{constructor(){super(...arguments);this.package=ge.String();this.tag=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);let n=W.parseDescriptor(this.package,!0),u=n.range;if(!BBe.default.valid(u))throw new it(`The range ${de.pretty(r,n.range,de.Type.RANGE)} must be a valid semver version`);let A=$n.getPublishRegistry(a.manifest,{configuration:r}),p=de.pretty(r,n,de.Type.IDENT),h=de.pretty(r,u,de.Type.RANGE),E=de.pretty(r,this.tag,de.Type.CODE);return(await Lt.start({configuration:r,stdout:this.context.stdout},async v=>{let x=await Tv(n,r);Object.hasOwn(x,this.tag)&&x[this.tag]===u&&v.reportWarning(0,`Tag ${E} is already set to version ${h}`);let C=`/-/package${Zr.getIdentUrl(n)}/dist-tags/${encodeURIComponent(this.tag)}`;await Zr.put(C,u,{configuration:r,registry:A,ident:n,jsonRequest:!0,jsonResponse:!0}),v.reportInfo(0,`Tag ${E} added to version ${h} of package ${p}`)})).exitCode()}};z0.paths=[["npm","tag","add"]],z0.usage=nt.Usage({category:"Npm-related commands",description:"add a tag for a specific version of a package",details:`
- This command will add a tag to the npm registry for a specific version of a package. If the tag already exists, it will be overwritten.
- `,examples:[["Add a `beta` tag for version `2.3.4-beta.4` of package `my-pkg`","yarn npm tag add my-pkg@2.3.4-beta.4 beta"]]});Ye();qt();var V0=class extends ut{constructor(){super(...arguments);this.package=ge.String();this.tag=ge.String()}async execute(){if(this.tag==="latest")throw new it("The 'latest' tag cannot be removed.");let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);let n=W.parseIdent(this.package),u=$n.getPublishRegistry(a.manifest,{configuration:r}),A=de.pretty(r,this.tag,de.Type.CODE),p=de.pretty(r,n,de.Type.IDENT),h=await Tv(n,r);if(!Object.hasOwn(h,this.tag))throw new it(`${A} is not a tag of package ${p}`);return(await Lt.start({configuration:r,stdout:this.context.stdout},async I=>{let v=`/-/package${Zr.getIdentUrl(n)}/dist-tags/${encodeURIComponent(this.tag)}`;await Zr.del(v,{configuration:r,registry:u,ident:n,jsonResponse:!0}),I.reportInfo(0,`Tag ${A} removed from package ${p}`)})).exitCode()}};V0.paths=[["npm","tag","remove"]],V0.usage=nt.Usage({category:"Npm-related commands",description:"remove a tag from a package",details:`
- This command will remove a tag from a package from the npm registry.
- `,examples:[["Remove the `beta` tag from package `my-pkg`","yarn npm tag remove my-pkg beta"]]});Ye();Ye();qt();var J0=class extends ut{constructor(){super(...arguments);this.scope=ge.String("-s,--scope",{description:"Print username for the registry configured for a given scope"});this.publish=ge.Boolean("--publish",!1,{description:"Print username for the publish registry"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o;return this.scope&&this.publish?o=$n.getScopeRegistry(this.scope,{configuration:r,type:$n.RegistryType.PUBLISH_REGISTRY}):this.scope?o=$n.getScopeRegistry(this.scope,{configuration:r}):this.publish?o=$n.getPublishRegistry((await fC(r,this.context.cwd)).manifest,{configuration:r}):o=$n.getDefaultRegistry({configuration:r}),(await Lt.start({configuration:r,stdout:this.context.stdout},async n=>{let u;try{u=await Zr.get("/-/whoami",{configuration:r,registry:o,authType:Zr.AuthType.ALWAYS_AUTH,jsonResponse:!0,ident:this.scope?W.makeIdent(this.scope,""):void 0})}catch(A){if(A.response?.statusCode===401||A.response?.statusCode===403){n.reportError(41,"Authentication failed - your credentials may have expired");return}else throw A}n.reportInfo(0,u.username)})).exitCode()}};J0.paths=[["npm","whoami"]],J0.usage=nt.Usage({category:"Npm-related commands",description:"display the name of the authenticated user",details:"\n Print the username associated with the current authentication settings to the standard output.\n\n When using `-s,--scope`, the username printed will be the one that matches the authentication settings of the registry associated with the given scope (those settings can be overriden using the `npmRegistries` map, and the registry associated with the scope is configured via the `npmScopes` map).\n\n When using `--publish`, the registry we'll select will by default be the one used when publishing packages (`publishConfig.registry` or `npmPublishRegistry` if available, otherwise we'll fallback to the regular `npmRegistryServer`).\n ",examples:[["Print username for the default registry","yarn npm whoami"],["Print username for the registry on a given scope","yarn npm whoami --scope company"]]});var Gvt={configuration:{npmPublishAccess:{description:"Default access of the published packages",type:"STRING",default:null},npmAuditExcludePackages:{description:"Array of glob patterns of packages to exclude from npm audit",type:"STRING",default:[],isArray:!0},npmAuditIgnoreAdvisories:{description:"Array of glob patterns of advisory IDs to exclude from npm audit",type:"STRING",default:[],isArray:!0}},commands:[q0,G0,j0,Y0,W0,z0,K0,V0,J0]},jvt=Gvt;var Fj={};zt(Fj,{PatchCommand:()=>$0,PatchCommitCommand:()=>Z0,PatchFetcher:()=>Uv,PatchResolver:()=>_v,default:()=>lDt,patchUtils:()=>Pm});Ye();Ye();Pt();iA();var Pm={};zt(Pm,{applyPatchFile:()=>tF,diffFolders:()=>kj,ensureUnpatchedDescriptor:()=>Pj,ensureUnpatchedLocator:()=>nF,extractPackageToDisk:()=>xj,extractPatchFlags:()=>kBe,isParentRequired:()=>bj,isPatchDescriptor:()=>rF,isPatchLocator:()=>X0,loadPatchFiles:()=>Mv,makeDescriptor:()=>iF,makeLocator:()=>Sj,makePatchHash:()=>Qj,parseDescriptor:()=>Nv,parseLocator:()=>Ov,parsePatchFile:()=>Lv,unpatchDescriptor:()=>sDt,unpatchLocator:()=>oDt});Ye();Pt();Ye();Pt();var Yvt=/^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@.*/;function cw(t){return z.relative(Bt.root,z.resolve(Bt.root,le.toPortablePath(t)))}function Wvt(t){let e=t.trim().match(Yvt);if(!e)throw new Error(`Bad header line: '${t}'`);return{original:{start:Math.max(Number(e[1]),1),length:Number(e[3]||1)},patched:{start:Math.max(Number(e[4]),1),length:Number(e[6]||1)}}}var Kvt=420,zvt=493;var vBe=()=>({semverExclusivity:null,diffLineFromPath:null,diffLineToPath:null,oldMode:null,newMode:null,deletedFileMode:null,newFileMode:null,renameFrom:null,renameTo:null,beforeHash:null,afterHash:null,fromPath:null,toPath:null,hunks:null}),Vvt=t=>({header:Wvt(t),parts:[]}),Jvt={["@"]:"header",["-"]:"deletion",["+"]:"insertion",[" "]:"context",["\\"]:"pragma",undefined:"context"};function Xvt(t){let e=[],r=vBe(),o="parsing header",a=null,n=null;function u(){a&&(n&&(a.parts.push(n),n=null),r.hunks.push(a),a=null)}function A(){u(),e.push(r),r=vBe()}for(let p=0;p<t.length;p++){let h=t[p];if(o==="parsing header")if(h.startsWith("@@"))o="parsing hunks",r.hunks=[],p-=1;else if(h.startsWith("diff --git ")){r&&r.diffLineFromPath&&A();let E=h.match(/^diff --git a\/(.*?) b\/(.*?)\s*$/);if(!E)throw new Error(`Bad diff line: ${h}`);r.diffLineFromPath=E[1],r.diffLineToPath=E[2]}else if(h.startsWith("old mode "))r.oldMode=h.slice(9).trim();else if(h.startsWith("new mode "))r.newMode=h.slice(9).trim();else if(h.startsWith("deleted file mode "))r.deletedFileMode=h.slice(18).trim();else if(h.startsWith("new file mode "))r.newFileMode=h.slice(14).trim();else if(h.startsWith("rename from "))r.renameFrom=h.slice(12).trim();else if(h.startsWith("rename to "))r.renameTo=h.slice(10).trim();else if(h.startsWith("index ")){let E=h.match(/(\w+)\.\.(\w+)/);if(!E)continue;r.beforeHash=E[1],r.afterHash=E[2]}else h.startsWith("semver exclusivity ")?r.semverExclusivity=h.slice(19).trim():h.startsWith("--- ")?r.fromPath=h.slice(6).trim():h.startsWith("+++ ")&&(r.toPath=h.slice(6).trim());else{let E=Jvt[h[0]]||null;switch(E){case"header":u(),a=Vvt(h);break;case null:o="parsing header",A(),p-=1;break;case"pragma":{if(!h.startsWith("\\ No newline at end of file"))throw new Error(`Unrecognized pragma in patch file: ${h}`);if(!n)throw new Error("Bad parser state: No newline at EOF pragma encountered without context");n.noNewlineAtEndOfFile=!0}break;case"context":case"deletion":case"insertion":{if(!a)throw new Error("Bad parser state: Hunk lines encountered before hunk header");n&&n.type!==E&&(a.parts.push(n),n=null),n||(n={type:E,lines:[],noNewlineAtEndOfFile:!1}),n.lines.push(h.slice(1))}break;default:_e.assertNever(E);break}}}A();for(let{hunks:p}of e)if(p)for(let h of p)$vt(h);return e}function Zvt(t){let e=[];for(let r of t){let{semverExclusivity:o,diffLineFromPath:a,diffLineToPath:n,oldMode:u,newMode:A,deletedFileMode:p,newFileMode:h,renameFrom:E,renameTo:I,beforeHash:v,afterHash:x,fromPath:C,toPath:R,hunks:N}=r,U=E?"rename":p?"file deletion":h?"file creation":N&&N.length>0?"patch":"mode change",V=null;switch(U){case"rename":{if(!E||!I)throw new Error("Bad parser state: rename from & to not given");e.push({type:"rename",semverExclusivity:o,fromPath:cw(E),toPath:cw(I)}),V=I}break;case"file deletion":{let te=a||C;if(!te)throw new Error("Bad parse state: no path given for file deletion");e.push({type:"file deletion",semverExclusivity:o,hunk:N&&N[0]||null,path:cw(te),mode:eF(p),hash:v})}break;case"file creation":{let te=n||R;if(!te)throw new Error("Bad parse state: no path given for file creation");e.push({type:"file creation",semverExclusivity:o,hunk:N&&N[0]||null,path:cw(te),mode:eF(h),hash:x})}break;case"patch":case"mode change":V=R||n;break;default:_e.assertNever(U);break}V&&u&&A&&u!==A&&e.push({type:"mode change",semverExclusivity:o,path:cw(V),oldMode:eF(u),newMode:eF(A)}),V&&N&&N.length&&e.push({type:"patch",semverExclusivity:o,path:cw(V),hunks:N,beforeHash:v,afterHash:x})}if(e.length===0)throw new Error("Unable to parse patch file: No changes found. Make sure the patch is a valid UTF8 encoded string");return e}function eF(t){let e=parseInt(t,8)&511;if(e!==Kvt&&e!==zvt)throw new Error(`Unexpected file mode string: ${t}`);return e}function Lv(t){let e=t.split(/\n/g);return e[e.length-1]===""&&e.pop(),Zvt(Xvt(e))}function $vt(t){let e=0,r=0;for(let{type:o,lines:a}of t.parts)switch(o){case"context":r+=a.length,e+=a.length;break;case"deletion":e+=a.length;break;case"insertion":r+=a.length;break;default:_e.assertNever(o);break}if(e!==t.header.original.length||r!==t.header.patched.length){let o=a=>a<0?a:`+${a}`;throw new Error(`hunk header integrity check failed (expected @@ ${o(t.header.original.length)} ${o(t.header.patched.length)} @@, got @@ ${o(e)} ${o(r)} @@)`)}}Ye();Pt();var uw=class extends Error{constructor(r,o){super(`Cannot apply hunk #${r+1}`);this.hunk=o}};async function Aw(t,e,r){let o=await t.lstatPromise(e),a=await r();typeof a<"u"&&(e=a),await t.lutimesPromise(e,o.atime,o.mtime)}async function tF(t,{baseFs:e=new Tn,dryRun:r=!1,version:o=null}={}){for(let a of t)if(!(a.semverExclusivity!==null&&o!==null&&!kr.satisfiesWithPrereleases(o,a.semverExclusivity)))switch(a.type){case"file deletion":if(r){if(!e.existsSync(a.path))throw new Error(`Trying to delete a file that doesn't exist: ${a.path}`)}else await Aw(e,z.dirname(a.path),async()=>{await e.unlinkPromise(a.path)});break;case"rename":if(r){if(!e.existsSync(a.fromPath))throw new Error(`Trying to move a file that doesn't exist: ${a.fromPath}`)}else await Aw(e,z.dirname(a.fromPath),async()=>{await Aw(e,z.dirname(a.toPath),async()=>{await Aw(e,a.fromPath,async()=>(await e.movePromise(a.fromPath,a.toPath),a.toPath))})});break;case"file creation":if(r){if(e.existsSync(a.path))throw new Error(`Trying to create a file that already exists: ${a.path}`)}else{let n=a.hunk?a.hunk.parts[0].lines.join(`
-`)+(a.hunk.parts[0].noNewlineAtEndOfFile?"":`
-`):"";await e.mkdirpPromise(z.dirname(a.path),{chmod:493,utimes:[vi.SAFE_TIME,vi.SAFE_TIME]}),await e.writeFilePromise(a.path,n,{mode:a.mode}),await e.utimesPromise(a.path,vi.SAFE_TIME,vi.SAFE_TIME)}break;case"patch":await Aw(e,a.path,async()=>{await rDt(a,{baseFs:e,dryRun:r})});break;case"mode change":{let u=(await e.statPromise(a.path)).mode;if(DBe(a.newMode)!==DBe(u))continue;await Aw(e,a.path,async()=>{await e.chmodPromise(a.path,a.newMode)})}break;default:_e.assertNever(a);break}}function DBe(t){return(t&64)>0}function PBe(t){return t.replace(/\s+$/,"")}function tDt(t,e){return PBe(t)===PBe(e)}async function rDt({hunks:t,path:e},{baseFs:r,dryRun:o=!1}){let a=await r.statSync(e).mode,u=(await r.readFileSync(e,"utf8")).split(/\n/),A=[],p=0,h=0;for(let I of t){let v=Math.max(h,I.header.patched.start+p),x=Math.max(0,v-h),C=Math.max(0,u.length-v-I.header.original.length),R=Math.max(x,C),N=0,U=0,V=null;for(;N<=R;){if(N<=x&&(U=v-N,V=SBe(I,u,U),V!==null)){N=-N;break}if(N<=C&&(U=v+N,V=SBe(I,u,U),V!==null))break;N+=1}if(V===null)throw new uw(t.indexOf(I),I);A.push(V),p+=N,h=U+I.header.original.length}if(o)return;let E=0;for(let I of A)for(let v of I)switch(v.type){case"splice":{let x=v.index+E;u.splice(x,v.numToDelete,...v.linesToInsert),E+=v.linesToInsert.length-v.numToDelete}break;case"pop":u.pop();break;case"push":u.push(v.line);break;default:_e.assertNever(v);break}await r.writeFilePromise(e,u.join(`
-`),{mode:a})}function SBe(t,e,r){let o=[];for(let a of t.parts)switch(a.type){case"context":case"deletion":{for(let n of a.lines){let u=e[r];if(u==null||!tDt(u,n))return null;r+=1}a.type==="deletion"&&(o.push({type:"splice",index:r-a.lines.length,numToDelete:a.lines.length,linesToInsert:[]}),a.noNewlineAtEndOfFile&&o.push({type:"push",line:""}))}break;case"insertion":o.push({type:"splice",index:r,numToDelete:0,linesToInsert:a.lines}),a.noNewlineAtEndOfFile&&o.push({type:"pop"});break;default:_e.assertNever(a.type);break}return o}var iDt=/^builtin<([^>]+)>$/;function fw(t,e){let{protocol:r,source:o,selector:a,params:n}=W.parseRange(t);if(r!=="patch:")throw new Error("Invalid patch range");if(o===null)throw new Error("Patch locators must explicitly define their source");let u=a?a.split(/&/).map(E=>le.toPortablePath(E)):[],A=n&&typeof n.locator=="string"?W.parseLocator(n.locator):null,p=n&&typeof n.version=="string"?n.version:null,h=e(o);return{parentLocator:A,sourceItem:h,patchPaths:u,sourceVersion:p}}function rF(t){return t.range.startsWith("patch:")}function X0(t){return t.reference.startsWith("patch:")}function Nv(t){let{sourceItem:e,...r}=fw(t.range,W.parseDescriptor);return{...r,sourceDescriptor:e}}function Ov(t){let{sourceItem:e,...r}=fw(t.reference,W.parseLocator);return{...r,sourceLocator:e}}function sDt(t){let{sourceItem:e}=fw(t.range,W.parseDescriptor);return e}function oDt(t){let{sourceItem:e}=fw(t.reference,W.parseLocator);return e}function Pj(t){if(!rF(t))return t;let{sourceItem:e}=fw(t.range,W.parseDescriptor);return e}function nF(t){if(!X0(t))return t;let{sourceItem:e}=fw(t.reference,W.parseLocator);return e}function bBe({parentLocator:t,sourceItem:e,patchPaths:r,sourceVersion:o,patchHash:a},n){let u=t!==null?{locator:W.stringifyLocator(t)}:{},A=typeof o<"u"?{version:o}:{},p=typeof a<"u"?{hash:a}:{};return W.makeRange({protocol:"patch:",source:n(e),selector:r.join("&"),params:{...A,...p,...u}})}function iF(t,{parentLocator:e,sourceDescriptor:r,patchPaths:o}){return W.makeDescriptor(t,bBe({parentLocator:e,sourceItem:r,patchPaths:o},W.stringifyDescriptor))}function Sj(t,{parentLocator:e,sourcePackage:r,patchPaths:o,patchHash:a}){return W.makeLocator(t,bBe({parentLocator:e,sourceItem:r,sourceVersion:r.version,patchPaths:o,patchHash:a},W.stringifyLocator))}function xBe({onAbsolute:t,onRelative:e,onProject:r,onBuiltin:o},a){let n=a.lastIndexOf("!");n!==-1&&(a=a.slice(n+1));let u=a.match(iDt);return u!==null?o(u[1]):a.startsWith("~/")?r(a.slice(2)):z.isAbsolute(a)?t(a):e(a)}function kBe(t){let e=t.lastIndexOf("!");return{optional:(e!==-1?new Set(t.slice(0,e).split(/!/)):new Set).has("optional")}}function bj(t){return xBe({onAbsolute:()=>!1,onRelative:()=>!0,onProject:()=>!1,onBuiltin:()=>!1},t)}async function Mv(t,e,r){let o=t!==null?await r.fetcher.fetch(t,r):null,a=o&&o.localPath?{packageFs:new gn(Bt.root),prefixPath:z.relative(Bt.root,o.localPath)}:o;o&&o!==a&&o.releaseFs&&o.releaseFs();let n=await _e.releaseAfterUseAsync(async()=>await Promise.all(e.map(async u=>{let A=kBe(u),p=await xBe({onAbsolute:async h=>await oe.readFilePromise(h,"utf8"),onRelative:async h=>{if(a===null)throw new Error("Assertion failed: The parent locator should have been fetched");return await a.packageFs.readFilePromise(z.join(a.prefixPath,h),"utf8")},onProject:async h=>await oe.readFilePromise(z.join(r.project.cwd,h),"utf8"),onBuiltin:async h=>await r.project.configuration.firstHook(E=>E.getBuiltinPatch,r.project,h)},u);return{...A,source:p}})));for(let u of n)typeof u.source=="string"&&(u.source=u.source.replace(/\r\n?/g,`
-`));return n}async function xj(t,{cache:e,project:r}){let o=r.storedPackages.get(t.locatorHash);if(typeof o>"u")throw new Error("Assertion failed: Expected the package to be registered");let a=nF(t),n=r.storedChecksums,u=new Qi,A=await oe.mktempPromise(),p=z.join(A,"source"),h=z.join(A,"user"),E=z.join(A,".yarn-patch.json"),I=r.configuration.makeFetcher(),v=[];try{let x,C;if(t.locatorHash===a.locatorHash){let R=await I.fetch(t,{cache:e,project:r,fetcher:I,checksums:n,report:u});v.push(()=>R.releaseFs?.()),x=R,C=R}else x=await I.fetch(t,{cache:e,project:r,fetcher:I,checksums:n,report:u}),v.push(()=>x.releaseFs?.()),C=await I.fetch(t,{cache:e,project:r,fetcher:I,checksums:n,report:u}),v.push(()=>C.releaseFs?.());await Promise.all([oe.copyPromise(p,x.prefixPath,{baseFs:x.packageFs}),oe.copyPromise(h,C.prefixPath,{baseFs:C.packageFs}),oe.writeJsonPromise(E,{locator:W.stringifyLocator(t),version:o.version})])}finally{for(let x of v)x()}return oe.detachTemp(A),h}async function kj(t,e){let r=le.fromPortablePath(t).replace(/\\/g,"/"),o=le.fromPortablePath(e).replace(/\\/g,"/"),{stdout:a,stderr:n}=await Ur.execvp("git",["-c","core.safecrlf=false","diff","--src-prefix=a/","--dst-prefix=b/","--ignore-cr-at-eol","--full-index","--no-index","--no-renames","--text",r,o],{cwd:le.toPortablePath(process.cwd()),env:{...process.env,GIT_CONFIG_NOSYSTEM:"1",HOME:"",XDG_CONFIG_HOME:"",USERPROFILE:""}});if(n.length>0)throw new Error(`Unable to diff directories. Make sure you have a recent version of 'git' available in PATH.
-The following error was reported by 'git':
-${n}`);let u=r.startsWith("/")?A=>A.slice(1):A=>A;return a.replace(new RegExp(`(a|b)(${_e.escapeRegExp(`/${u(r)}/`)})`,"g"),"$1/").replace(new RegExp(`(a|b)${_e.escapeRegExp(`/${u(o)}/`)}`,"g"),"$1/").replace(new RegExp(_e.escapeRegExp(`${r}/`),"g"),"").replace(new RegExp(_e.escapeRegExp(`${o}/`),"g"),"")}function Qj(t,e){let r=[];for(let{source:o}of t){if(o===null)continue;let a=Lv(o);for(let n of a){let{semverExclusivity:u,...A}=n;u!==null&&e!==null&&!kr.satisfiesWithPrereleases(e,u)||r.push(JSON.stringify(A))}}return wn.makeHash(`${3}`,...r).slice(0,6)}Ye();function QBe(t,{configuration:e,report:r}){for(let o of t.parts)for(let a of o.lines)switch(o.type){case"context":r.reportInfo(null,` ${de.pretty(e,a,"grey")}`);break;case"deletion":r.reportError(28,`- ${de.pretty(e,a,de.Type.REMOVED)}`);break;case"insertion":r.reportError(28,`+ ${de.pretty(e,a,de.Type.ADDED)}`);break;default:_e.assertNever(o.type)}}var Uv=class{supports(e,r){return!!X0(e)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.patchPackage(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:u}}async patchPackage(e,r){let{parentLocator:o,sourceLocator:a,sourceVersion:n,patchPaths:u}=Ov(e),A=await Mv(o,u,r),p=await oe.mktempPromise(),h=z.join(p,"current.zip"),E=await r.fetcher.fetch(a,r),I=W.getIdentVendorPath(e),v=new Ji(h,{create:!0,level:r.project.configuration.get("compressionLevel")});await _e.releaseAfterUseAsync(async()=>{await v.copyPromise(I,E.prefixPath,{baseFs:E.packageFs,stableSort:!0})},E.releaseFs),v.saveAndClose();for(let{source:x,optional:C}of A){if(x===null)continue;let R=new Ji(h,{level:r.project.configuration.get("compressionLevel")}),N=new gn(z.resolve(Bt.root,I),{baseFs:R});try{await tF(Lv(x),{baseFs:N,version:n})}catch(U){if(!(U instanceof uw))throw U;let V=r.project.configuration.get("enableInlineHunks"),te=!V&&!C?" (set enableInlineHunks for details)":"",ae=`${W.prettyLocator(r.project.configuration,e)}: ${U.message}${te}`,fe=ue=>{!V||QBe(U.hunk,{configuration:r.project.configuration,report:ue})};if(R.discardAndClose(),C){r.report.reportWarningOnce(66,ae,{reportExtra:fe});continue}else throw new Jt(66,ae,fe)}R.saveAndClose()}return new Ji(h,{level:r.project.configuration.get("compressionLevel")})}};Ye();var _v=class{supportsDescriptor(e,r){return!!rF(e)}supportsLocator(e,r){return!!X0(e)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){let{patchPaths:a}=Nv(e);return a.every(n=>!bj(n))?e:W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){let{sourceDescriptor:o}=Nv(e);return{sourceDescriptor:r.project.configuration.normalizeDependency(o)}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error("Assertion failed: This resolver cannot be used unless a fetcher is configured");let{parentLocator:a,patchPaths:n}=Nv(e),u=await Mv(a,n,o.fetchOptions),A=r.sourceDescriptor;if(typeof A>"u")throw new Error("Assertion failed: The dependency should have been resolved");let p=Qj(u,A.version);return[Sj(e,{parentLocator:a,sourcePackage:A,patchPaths:n,patchHash:p})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let{sourceLocator:o}=Ov(e);return{...await r.resolver.resolve(o,r),...e}}};Ye();Pt();qt();var Z0=class extends ut{constructor(){super(...arguments);this.save=ge.Boolean("-s,--save",!1,{description:"Add the patch to your resolution entries"});this.patchFolder=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=z.resolve(this.context.cwd,le.toPortablePath(this.patchFolder)),u=z.join(n,"../source"),A=z.join(n,"../.yarn-patch.json");if(!oe.existsSync(u))throw new it("The argument folder didn't get created by 'yarn patch'");let p=await kj(u,n),h=await oe.readJsonPromise(A),E=W.parseLocator(h.locator,!0);if(!o.storedPackages.has(E.locatorHash))throw new it("No package found in the project for the given locator");if(!this.save){this.context.stdout.write(p);return}let I=r.get("patchFolder"),v=z.join(I,`${W.slugifyLocator(E)}.patch`);await oe.mkdirPromise(I,{recursive:!0}),await oe.writeFilePromise(v,p);let x=[],C=new Map;for(let R of o.storedPackages.values()){if(W.isVirtualLocator(R))continue;let N=R.dependencies.get(E.identHash);if(!N)continue;let U=W.ensureDevirtualizedDescriptor(N),V=Pj(U),te=o.storedResolutions.get(V.descriptorHash);if(!te)throw new Error("Assertion failed: Expected the resolution to have been registered");if(!o.storedPackages.get(te))throw new Error("Assertion failed: Expected the package to have been registered");let fe=o.tryWorkspaceByLocator(R);if(fe)x.push(fe);else{let ue=o.originalPackages.get(R.locatorHash);if(!ue)throw new Error("Assertion failed: Expected the original package to have been registered");let me=ue.dependencies.get(N.identHash);if(!me)throw new Error("Assertion failed: Expected the original dependency to have been registered");C.set(me.descriptorHash,me)}}for(let R of x)for(let N of Ot.hardDependencies){let U=R.manifest[N].get(E.identHash);if(!U)continue;let V=iF(U,{parentLocator:null,sourceDescriptor:W.convertLocatorToDescriptor(E),patchPaths:[z.join(dr.home,z.relative(o.cwd,v))]});R.manifest[N].set(U.identHash,V)}for(let R of C.values()){let N=iF(R,{parentLocator:null,sourceDescriptor:W.convertLocatorToDescriptor(E),patchPaths:[z.join(dr.home,z.relative(o.cwd,v))]});o.topLevelWorkspace.manifest.resolutions.push({pattern:{descriptor:{fullName:W.stringifyIdent(N),description:R.range}},reference:N.range})}await o.persist()}};Z0.paths=[["patch-commit"]],Z0.usage=nt.Usage({description:"generate a patch out of a directory",details:"\n By default, this will print a patchfile on stdout based on the diff between the folder passed in and the original version of the package. Such file is suitable for consumption with the `patch:` protocol.\n\n With the `-s,--save` option set, the patchfile won't be printed on stdout anymore and will instead be stored within a local file (by default kept within `.yarn/patches`, but configurable via the `patchFolder` setting). A `resolutions` entry will also be added to your top-level manifest, referencing the patched package via the `patch:` protocol.\n\n Note that only folders generated by `yarn patch` are accepted as valid input for `yarn patch-commit`.\n "});Ye();Pt();qt();var $0=class extends ut{constructor(){super(...arguments);this.update=ge.Boolean("-u,--update",!1,{description:"Reapply local patches that already apply to this packages"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.package=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState();let u=W.parseLocator(this.package);if(u.reference==="unknown"){let A=_e.mapAndFilter([...o.storedPackages.values()],p=>p.identHash!==u.identHash?_e.mapAndFilter.skip:W.isVirtualLocator(p)?_e.mapAndFilter.skip:X0(p)!==this.update?_e.mapAndFilter.skip:p);if(A.length===0)throw new it("No package found in the project for the given locator");if(A.length>1)throw new it(`Multiple candidate packages found; explicitly choose one of them (use \`yarn why <package>\` to get more information as to who depends on them):
-${A.map(p=>`
-- ${W.prettyLocator(r,p)}`).join("")}`);u=A[0]}if(!o.storedPackages.has(u.locatorHash))throw new it("No package found in the project for the given locator");await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout},async A=>{let p=nF(u),h=await xj(u,{cache:n,project:o});A.reportJson({locator:W.stringifyLocator(p),path:le.fromPortablePath(h)});let E=this.update?" along with its current modifications":"";A.reportInfo(0,`Package ${W.prettyLocator(r,p)} got extracted with success${E}!`),A.reportInfo(0,`You can now edit the following folder: ${de.pretty(r,le.fromPortablePath(h),"magenta")}`),A.reportInfo(0,`Once you are done run ${de.pretty(r,`yarn patch-commit -s ${process.platform==="win32"?'"':""}${le.fromPortablePath(h)}${process.platform==="win32"?'"':""}`,"cyan")} and Yarn will store a patchfile based on your changes.`)})}};$0.paths=[["patch"]],$0.usage=nt.Usage({description:"prepare a package for patching",details:"\n This command will cause a package to be extracted in a temporary directory intended to be editable at will.\n\n Once you're done with your changes, run `yarn patch-commit -s path` (with `path` being the temporary directory you received) to generate a patchfile and register it into your top-level manifest via the `patch:` protocol. Run `yarn patch-commit -h` for more details.\n\n Calling the command when you already have a patch won't import it by default (in other words, the default behavior is to reset existing patches). However, adding the `-u,--update` flag will import any current patch.\n "});var aDt={configuration:{enableInlineHunks:{description:"If true, the installs will print unmatched patch hunks",type:"BOOLEAN",default:!1},patchFolder:{description:"Folder where the patch files must be written",type:"ABSOLUTE_PATH",default:"./.yarn/patches"}},commands:[Z0,$0],fetchers:[Uv],resolvers:[_v]},lDt=aDt;var Lj={};zt(Lj,{PnpmLinker:()=>Hv,default:()=>pDt});Ye();Pt();qt();var Hv=class{getCustomDataKey(){return JSON.stringify({name:"PnpmLinker",version:3})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error("Assertion failed: Expected the pnpm linker to be enabled");let o=this.getCustomDataKey(),a=r.project.linkersCustomData.get(o);if(!a)throw new it(`The project in ${de.pretty(r.project.configuration,`${r.project.cwd}/package.json`,de.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let n=a.pathsByLocator.get(e.locatorHash);if(typeof n>"u")throw new it(`Couldn't find ${W.prettyLocator(r.project.configuration,e)} in the currently installed pnpm map - running an install might help`);return n.packageLocation}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let o=this.getCustomDataKey(),a=r.project.linkersCustomData.get(o);if(!a)throw new it(`The project in ${de.pretty(r.project.configuration,`${r.project.cwd}/package.json`,de.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let n=e.match(/(^.*\/node_modules\/(@[^/]*\/)?[^/]+)(\/.*$)/);if(n){let p=a.locatorByPath.get(n[1]);if(p)return p}let u=e,A=e;do{A=u,u=z.dirname(A);let p=a.locatorByPath.get(A);if(p)return p}while(u!==A);return null}makeInstaller(e){return new Rj(e)}isEnabled(e){return e.project.configuration.get("nodeLinker")==="pnpm"}},Rj=class{constructor(e){this.opts=e;this.asyncActions=new _e.AsyncActions(10);this.customData={pathsByLocator:new Map,locatorByPath:new Map};this.indexFolderPromise=PD(oe,{indexPath:z.join(e.project.configuration.get("globalFolder"),"index")})}attachCustomData(e){}async installPackage(e,r,o){switch(e.linkType){case"SOFT":return this.installPackageSoft(e,r,o);case"HARD":return this.installPackageHard(e,r,o)}throw new Error("Assertion failed: Unsupported package link type")}async installPackageSoft(e,r,o){let a=z.resolve(r.packageFs.getRealPath(),r.prefixPath),n=this.opts.project.tryWorkspaceByLocator(e)?z.join(a,dr.nodeModules):null;return this.customData.pathsByLocator.set(e.locatorHash,{packageLocation:a,dependenciesLocation:n}),{packageLocation:a,buildRequest:null}}async installPackageHard(e,r,o){let a=cDt(e,{project:this.opts.project}),n=a.packageLocation;this.customData.locatorByPath.set(n,W.stringifyLocator(e)),this.customData.pathsByLocator.set(e.locatorHash,a),o.holdFetchResult(this.asyncActions.set(e.locatorHash,async()=>{await oe.mkdirPromise(n,{recursive:!0}),await oe.copyPromise(n,r.prefixPath,{baseFs:r.packageFs,overwrite:!1,linkStrategy:{type:"HardlinkFromIndex",indexPath:await this.indexFolderPromise,autoRepair:!0}})}));let A=W.isVirtualLocator(e)?W.devirtualizeLocator(e):e,p={manifest:await Ot.tryFind(r.prefixPath,{baseFs:r.packageFs})??new Ot,misc:{hasBindingGyp:yA.hasBindingGyp(r)}},h=this.opts.project.getDependencyMeta(A,e.version),E=yA.extractBuildRequest(e,p,h,{configuration:this.opts.project.configuration});return{packageLocation:n,buildRequest:E}}async attachInternalDependencies(e,r){if(this.opts.project.configuration.get("nodeLinker")!=="pnpm"||!FBe(e,{project:this.opts.project}))return;let o=this.customData.pathsByLocator.get(e.locatorHash);if(typeof o>"u")throw new Error(`Assertion failed: Expected the package to have been registered (${W.stringifyLocator(e)})`);let{dependenciesLocation:a}=o;!a||this.asyncActions.reduce(e.locatorHash,async n=>{await oe.mkdirPromise(a,{recursive:!0});let u=await uDt(a),A=new Map(u),p=[n],h=(I,v)=>{let x=v;FBe(v,{project:this.opts.project})||(this.opts.report.reportWarningOnce(0,"The pnpm linker doesn't support providing different versions to workspaces' peer dependencies"),x=W.devirtualizeLocator(v));let C=this.customData.pathsByLocator.get(x.locatorHash);if(typeof C>"u")throw new Error(`Assertion failed: Expected the package to have been registered (${W.stringifyLocator(v)})`);let R=W.stringifyIdent(I),N=z.join(a,R),U=z.relative(z.dirname(N),C.packageLocation),V=A.get(R);A.delete(R),p.push(Promise.resolve().then(async()=>{if(V){if(V.isSymbolicLink()&&await oe.readlinkPromise(N)===U)return;await oe.removePromise(N)}await oe.mkdirpPromise(z.dirname(N)),process.platform=="win32"&&this.opts.project.configuration.get("winLinkType")==="junctions"?await oe.symlinkPromise(C.packageLocation,N,"junction"):await oe.symlinkPromise(U,N)}))},E=!1;for(let[I,v]of r)I.identHash===e.identHash&&(E=!0),h(I,v);!E&&!this.opts.project.tryWorkspaceByLocator(e)&&h(W.convertLocatorToDescriptor(e),e),p.push(ADt(a,A)),await Promise.all(p)})}async attachExternalDependents(e,r){throw new Error("External dependencies haven't been implemented for the pnpm linker")}async finalizeInstall(){let e=TBe(this.opts.project);if(this.opts.project.configuration.get("nodeLinker")!=="pnpm")await oe.removePromise(e);else{let r;try{r=new Set(await oe.readdirPromise(e))}catch{r=new Set}for(let{dependenciesLocation:o}of this.customData.pathsByLocator.values()){if(!o)continue;let a=z.contains(e,o);if(a===null)continue;let[n]=a.split(z.sep);r.delete(n)}await Promise.all([...r].map(async o=>{await oe.removePromise(z.join(e,o))}))}return await this.asyncActions.wait(),await Tj(e),this.opts.project.configuration.get("nodeLinker")!=="node-modules"&&await Tj(RBe(this.opts.project)),{customData:this.customData}}};function RBe(t){return z.join(t.cwd,dr.nodeModules)}function TBe(t){return z.join(RBe(t),".store")}function cDt(t,{project:e}){let r=W.slugifyLocator(t),o=TBe(e),a=z.join(o,r,"package"),n=z.join(o,r,dr.nodeModules);return{packageLocation:a,dependenciesLocation:n}}function FBe(t,{project:e}){return!W.isVirtualLocator(t)||!e.tryWorkspaceByLocator(t)}async function uDt(t){let e=new Map,r=[];try{r=await oe.readdirPromise(t,{withFileTypes:!0})}catch(o){if(o.code!=="ENOENT")throw o}try{for(let o of r)if(!o.name.startsWith("."))if(o.name.startsWith("@")){let a=await oe.readdirPromise(z.join(t,o.name),{withFileTypes:!0});if(a.length===0)e.set(o.name,o);else for(let n of a)e.set(`${o.name}/${n.name}`,n)}else e.set(o.name,o)}catch(o){if(o.code!=="ENOENT")throw o}return e}async function ADt(t,e){let r=[],o=new Set;for(let a of e.keys()){r.push(oe.removePromise(z.join(t,a)));let n=W.tryParseIdent(a)?.scope;n&&o.add(`@${n}`)}return Promise.all(r).then(()=>Promise.all([...o].map(a=>Tj(z.join(t,a)))))}async function Tj(t){try{await oe.rmdirPromise(t)}catch(e){if(e.code!=="ENOENT"&&e.code!=="ENOTEMPTY")throw e}}var fDt={linkers:[Hv]},pDt=fDt;var qj={};zt(qj,{StageCommand:()=>eg,default:()=>vDt,stageUtils:()=>oF});Ye();Pt();qt();Ye();Pt();var oF={};zt(oF,{ActionType:()=>Nj,checkConsensus:()=>sF,expandDirectory:()=>Uj,findConsensus:()=>_j,findVcsRoot:()=>Oj,genCommitMessage:()=>Hj,getCommitPrefix:()=>LBe,isYarnFile:()=>Mj});Pt();var Nj=(n=>(n[n.CREATE=0]="CREATE",n[n.DELETE=1]="DELETE",n[n.ADD=2]="ADD",n[n.REMOVE=3]="REMOVE",n[n.MODIFY=4]="MODIFY",n))(Nj||{});async function Oj(t,{marker:e}){do if(!oe.existsSync(z.join(t,e)))t=z.dirname(t);else return t;while(t!=="/");return null}function Mj(t,{roots:e,names:r}){if(r.has(z.basename(t)))return!0;do if(!e.has(t))t=z.dirname(t);else return!0;while(t!=="/");return!1}function Uj(t){let e=[],r=[t];for(;r.length>0;){let o=r.pop(),a=oe.readdirSync(o);for(let n of a){let u=z.resolve(o,n);oe.lstatSync(u).isDirectory()?r.push(u):e.push(u)}}return e}function sF(t,e){let r=0,o=0;for(let a of t)a!=="wip"&&(e.test(a)?r+=1:o+=1);return r>=o}function _j(t){let e=sF(t,/^(\w\(\w+\):\s*)?\w+s/),r=sF(t,/^(\w\(\w+\):\s*)?[A-Z]/),o=sF(t,/^\w\(\w+\):/);return{useThirdPerson:e,useUpperCase:r,useComponent:o}}function LBe(t){return t.useComponent?"chore(yarn): ":""}var hDt=new Map([[0,"create"],[1,"delete"],[2,"add"],[3,"remove"],[4,"update"]]);function Hj(t,e){let r=LBe(t),o=[],a=e.slice().sort((n,u)=>n[0]-u[0]);for(;a.length>0;){let[n,u]=a.shift(),A=hDt.get(n);t.useUpperCase&&o.length===0&&(A=`${A[0].toUpperCase()}${A.slice(1)}`),t.useThirdPerson&&(A+="s");let p=[u];for(;a.length>0&&a[0][0]===n;){let[,E]=a.shift();p.push(E)}p.sort();let h=p.shift();p.length===1?h+=" (and one other)":p.length>1&&(h+=` (and ${p.length} others)`),o.push(`${A} ${h}`)}return`${r}${o.join(", ")}`}var gDt="Commit generated via `yarn stage`",dDt=11;async function NBe(t){let{code:e,stdout:r}=await Ur.execvp("git",["log","-1","--pretty=format:%H"],{cwd:t});return e===0?r.trim():null}async function mDt(t,e){let r=[],o=e.filter(h=>z.basename(h.path)==="package.json");for(let{action:h,path:E}of o){let I=z.relative(t,E);if(h===4){let v=await NBe(t),{stdout:x}=await Ur.execvp("git",["show",`${v}:${I}`],{cwd:t,strict:!0}),C=await Ot.fromText(x),R=await Ot.fromFile(E),N=new Map([...R.dependencies,...R.devDependencies]),U=new Map([...C.dependencies,...C.devDependencies]);for(let[V,te]of U){let ae=W.stringifyIdent(te),fe=N.get(V);fe?fe.range!==te.range&&r.push([4,`${ae} to ${fe.range}`]):r.push([3,ae])}for(let[V,te]of N)U.has(V)||r.push([2,W.stringifyIdent(te)])}else if(h===0){let v=await Ot.fromFile(E);v.name?r.push([0,W.stringifyIdent(v.name)]):r.push([0,"a package"])}else if(h===1){let v=await NBe(t),{stdout:x}=await Ur.execvp("git",["show",`${v}:${I}`],{cwd:t,strict:!0}),C=await Ot.fromText(x);C.name?r.push([1,W.stringifyIdent(C.name)]):r.push([1,"a package"])}else throw new Error("Assertion failed: Unsupported action type")}let{code:a,stdout:n}=await Ur.execvp("git",["log",`-${dDt}`,"--pretty=format:%s"],{cwd:t}),u=a===0?n.split(/\n/g).filter(h=>h!==""):[],A=_j(u);return Hj(A,r)}var yDt={[0]:[" A ","?? "],[4]:[" M "],[1]:[" D "]},EDt={[0]:["A "],[4]:["M "],[1]:["D "]},OBe={async findRoot(t){return await Oj(t,{marker:".git"})},async filterChanges(t,e,r,o){let{stdout:a}=await Ur.execvp("git",["status","-s"],{cwd:t,strict:!0}),n=a.toString().split(/\n/g),u=o?.staged?EDt:yDt;return[].concat(...n.map(p=>{if(p==="")return[];let h=p.slice(0,3),E=z.resolve(t,p.slice(3));if(!o?.staged&&h==="?? "&&p.endsWith("/"))return Uj(E).map(I=>({action:0,path:I}));{let v=[0,4,1].find(x=>u[x].includes(h));return v!==void 0?[{action:v,path:E}]:[]}})).filter(p=>Mj(p.path,{roots:e,names:r}))},async genCommitMessage(t,e){return await mDt(t,e)},async makeStage(t,e){let r=e.map(o=>le.fromPortablePath(o.path));await Ur.execvp("git",["add","--",...r],{cwd:t,strict:!0})},async makeCommit(t,e,r){let o=e.map(a=>le.fromPortablePath(a.path));await Ur.execvp("git",["add","-N","--",...o],{cwd:t,strict:!0}),await Ur.execvp("git",["commit","-m",`${r}
-
-${gDt}
-`,"--",...o],{cwd:t,strict:!0})},async makeReset(t,e){let r=e.map(o=>le.fromPortablePath(o.path));await Ur.execvp("git",["reset","HEAD","--",...r],{cwd:t,strict:!0})}};var CDt=[OBe],eg=class extends ut{constructor(){super(...arguments);this.commit=ge.Boolean("-c,--commit",!1,{description:"Commit the staged files"});this.reset=ge.Boolean("-r,--reset",!1,{description:"Remove all files from the staging area"});this.dryRun=ge.Boolean("-n,--dry-run",!1,{description:"Print the commit message and the list of modified files without staging / committing"});this.update=ge.Boolean("-u,--update",!1,{hidden:!0})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),{driver:a,root:n}=await wDt(o.cwd),u=[r.get("cacheFolder"),r.get("globalFolder"),r.get("virtualFolder"),r.get("yarnPath")];await r.triggerHook(I=>I.populateYarnPaths,o,I=>{u.push(I)});let A=new Set;for(let I of u)for(let v of IDt(n,I))A.add(v);let p=new Set([r.get("rcFilename"),dr.lockfile,dr.manifest]),h=await a.filterChanges(n,A,p),E=await a.genCommitMessage(n,h);if(this.dryRun)if(this.commit)this.context.stdout.write(`${E}
-`);else for(let I of h)this.context.stdout.write(`${le.fromPortablePath(I.path)}
-`);else if(this.reset){let I=await a.filterChanges(n,A,p,{staged:!0});I.length===0?this.context.stdout.write("No staged changes found!"):await a.makeReset(n,I)}else h.length===0?this.context.stdout.write("No changes found!"):this.commit?await a.makeCommit(n,h,E):(await a.makeStage(n,h),this.context.stdout.write(E))}};eg.paths=[["stage"]],eg.usage=nt.Usage({description:"add all yarn files to your vcs",details:"\n This command will add to your staging area the files belonging to Yarn (typically any modified `package.json` and `.yarnrc.yml` files, but also linker-generated files, cache data, etc). It will take your ignore list into account, so the cache files won't be added if the cache is ignored in a `.gitignore` file (assuming you use Git).\n\n Running `--reset` will instead remove them from the staging area (the changes will still be there, but won't be committed until you stage them back).\n\n Since the staging area is a non-existent concept in Mercurial, Yarn will always create a new commit when running this command on Mercurial repositories. You can get this behavior when using Git by using the `--commit` flag which will directly create a commit.\n ",examples:[["Adds all modified project files to the staging area","yarn stage"],["Creates a new commit containing all modified project files","yarn stage --commit"]]});async function wDt(t){let e=null,r=null;for(let o of CDt)if((r=await o.findRoot(t))!==null){e=o;break}if(e===null||r===null)throw new it("No stage driver has been found for your current project");return{driver:e,root:r}}function IDt(t,e){let r=[];if(e===null)return r;for(;;){(e===t||e.startsWith(`${t}/`))&&r.push(e);let o;try{o=oe.statSync(e)}catch{break}if(o.isSymbolicLink())e=z.resolve(z.dirname(e),oe.readlinkSync(e));else break}return r}var BDt={commands:[eg]},vDt=BDt;var Gj={};zt(Gj,{default:()=>FDt});Ye();Ye();Pt();var _Be=$e(Jn());Ye();var MBe=$e(JH()),DDt="e8e1bd300d860104bb8c58453ffa1eb4",PDt="OFCNCOG2CU",UBe=async(t,e)=>{let r=W.stringifyIdent(t),a=SDt(e).initIndex("npm-search");try{return(await a.getObject(r,{attributesToRetrieve:["types"]})).types?.ts==="definitely-typed"}catch{return!1}},SDt=t=>(0,MBe.default)(PDt,DDt,{requester:{async send(r){try{let o=await nn.request(r.url,r.data||null,{configuration:t,headers:r.headers});return{content:o.body,isTimedOut:!1,status:o.statusCode}}catch(o){return{content:o.response.body,isTimedOut:!1,status:o.response.statusCode}}}}});var HBe=t=>t.scope?`${t.scope}__${t.name}`:`${t.name}`,bDt=async(t,e,r,o)=>{if(r.scope==="types")return;let{project:a}=t,{configuration:n}=a;if(!(n.get("tsEnableAutoTypes")??(oe.existsSync(z.join(t.cwd,"tsconfig.json"))||oe.existsSync(z.join(a.cwd,"tsconfig.json")))))return;let A=n.makeResolver(),p={project:a,resolver:A,report:new Qi};if(!await UBe(r,n))return;let E=HBe(r),I=W.parseRange(r.range).selector;if(!kr.validRange(I)){let N=n.normalizeDependency(r),U=await A.getCandidates(N,{},p);I=W.parseRange(U[0].reference).selector}let v=_Be.default.coerce(I);if(v===null)return;let x=`${Xc.Modifier.CARET}${v.major}`,C=W.makeDescriptor(W.makeIdent("types",E),x),R=_e.mapAndFind(a.workspaces,N=>{let U=N.manifest.dependencies.get(r.identHash)?.descriptorHash,V=N.manifest.devDependencies.get(r.identHash)?.descriptorHash;if(U!==r.descriptorHash&&V!==r.descriptorHash)return _e.mapAndFind.skip;let te=[];for(let ae of Ot.allDependencies){let fe=N.manifest[ae].get(C.identHash);typeof fe>"u"||te.push([ae,fe])}return te.length===0?_e.mapAndFind.skip:te});if(typeof R<"u")for(let[N,U]of R)t.manifest[N].set(U.identHash,U);else{try{let N=n.normalizeDependency(C);if((await A.getCandidates(N,{},p)).length===0)return}catch{return}t.manifest[Xc.Target.DEVELOPMENT].set(C.identHash,C)}},xDt=async(t,e,r)=>{if(r.scope==="types")return;let{project:o}=t,{configuration:a}=o;if(!(a.get("tsEnableAutoTypes")??(oe.existsSync(z.join(t.cwd,"tsconfig.json"))||oe.existsSync(z.join(o.cwd,"tsconfig.json")))))return;let u=HBe(r),A=W.makeIdent("types",u);for(let p of Ot.allDependencies)typeof t.manifest[p].get(A.identHash)>"u"||t.manifest[p].delete(A.identHash)},kDt=(t,e)=>{e.publishConfig&&e.publishConfig.typings&&(e.typings=e.publishConfig.typings),e.publishConfig&&e.publishConfig.types&&(e.types=e.publishConfig.types)},QDt={configuration:{tsEnableAutoTypes:{description:"Whether Yarn should auto-install @types/ dependencies on 'yarn add'",type:"BOOLEAN",isNullable:!0,default:null}},hooks:{afterWorkspaceDependencyAddition:bDt,afterWorkspaceDependencyRemoval:xDt,beforeWorkspacePacking:kDt}},FDt=QDt;var zj={};zt(zj,{VersionApplyCommand:()=>tg,VersionCheckCommand:()=>rg,VersionCommand:()=>ng,default:()=>XDt,versionUtils:()=>dw});Ye();Ye();qt();var dw={};zt(dw,{Decision:()=>hw,applyPrerelease:()=>KBe,applyReleases:()=>Kj,applyStrategy:()=>lF,clearVersionFiles:()=>jj,getUndecidedDependentWorkspaces:()=>Gv,getUndecidedWorkspaces:()=>aF,openVersionFile:()=>gw,requireMoreDecisions:()=>zDt,resolveVersionFiles:()=>qv,suggestStrategy:()=>Wj,updateVersionFiles:()=>Yj,validateReleaseDecision:()=>pw});Ye();Pt();Nl();qt();var WBe=$e(YBe()),vA=$e(Jn()),KDt=/^(>=|[~^]|)(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$/,hw=(u=>(u.UNDECIDED="undecided",u.DECLINE="decline",u.MAJOR="major",u.MINOR="minor",u.PATCH="patch",u.PRERELEASE="prerelease",u))(hw||{});function pw(t){let e=vA.default.valid(t);return e||_e.validateEnum((0,WBe.default)(hw,"UNDECIDED"),t)}async function qv(t,{prerelease:e=null}={}){let r=new Map,o=t.configuration.get("deferredVersionFolder");if(!oe.existsSync(o))return r;let a=await oe.readdirPromise(o);for(let n of a){if(!n.endsWith(".yml"))continue;let u=z.join(o,n),A=await oe.readFilePromise(u,"utf8"),p=Ki(A);for(let[h,E]of Object.entries(p.releases||{})){if(E==="decline")continue;let I=W.parseIdent(h),v=t.tryWorkspaceByIdent(I);if(v===null)throw new Error(`Assertion failed: Expected a release definition file to only reference existing workspaces (${z.basename(u)} references ${h})`);if(v.manifest.version===null)throw new Error(`Assertion failed: Expected the workspace to have a version (${W.prettyLocator(t.configuration,v.anchoredLocator)})`);let x=v.manifest.raw.stableVersion??v.manifest.version,C=r.get(v),R=lF(x,pw(E));if(R===null)throw new Error(`Assertion failed: Expected ${x} to support being bumped via strategy ${E}`);let N=typeof C<"u"?vA.default.gt(R,C)?R:C:R;r.set(v,N)}}return e&&(r=new Map([...r].map(([n,u])=>[n,KBe(u,{current:n.manifest.version,prerelease:e})]))),r}async function jj(t){let e=t.configuration.get("deferredVersionFolder");!oe.existsSync(e)||await oe.removePromise(e)}async function Yj(t,e){let r=new Set(e),o=t.configuration.get("deferredVersionFolder");if(!oe.existsSync(o))return;let a=await oe.readdirPromise(o);for(let n of a){if(!n.endsWith(".yml"))continue;let u=z.join(o,n),A=await oe.readFilePromise(u,"utf8"),p=Ki(A),h=p?.releases;if(!!h){for(let E of Object.keys(h)){let I=W.parseIdent(E),v=t.tryWorkspaceByIdent(I);(v===null||r.has(v))&&delete p.releases[E]}Object.keys(p.releases).length>0?await oe.changeFilePromise(u,Ba(new Ba.PreserveOrdering(p))):await oe.unlinkPromise(u)}}}async function gw(t,{allowEmpty:e=!1}={}){let r=t.configuration;if(r.projectCwd===null)throw new it("This command can only be run from within a Yarn project");let o=await ra.fetchRoot(r.projectCwd),a=o!==null?await ra.fetchBase(o,{baseRefs:r.get("changesetBaseRefs")}):null,n=o!==null?await ra.fetchChangedFiles(o,{base:a.hash,project:t}):[],u=r.get("deferredVersionFolder"),A=n.filter(x=>z.contains(u,x)!==null);if(A.length>1)throw new it(`Your current branch contains multiple versioning files; this isn't supported:
-- ${A.map(x=>le.fromPortablePath(x)).join(`
-- `)}`);let p=new Set(_e.mapAndFilter(n,x=>{let C=t.tryWorkspaceByFilePath(x);return C===null?_e.mapAndFilter.skip:C}));if(A.length===0&&p.size===0&&!e)return null;let h=A.length===1?A[0]:z.join(u,`${wn.makeHash(Math.random().toString()).slice(0,8)}.yml`),E=oe.existsSync(h)?await oe.readFilePromise(h,"utf8"):"{}",I=Ki(E),v=new Map;for(let x of I.declined||[]){let C=W.parseIdent(x),R=t.getWorkspaceByIdent(C);v.set(R,"decline")}for(let[x,C]of Object.entries(I.releases||{})){let R=W.parseIdent(x),N=t.getWorkspaceByIdent(R);v.set(N,pw(C))}return{project:t,root:o,baseHash:a!==null?a.hash:null,baseTitle:a!==null?a.title:null,changedFiles:new Set(n),changedWorkspaces:p,releaseRoots:new Set([...p].filter(x=>x.manifest.version!==null)),releases:v,async saveAll(){let x={},C=[],R=[];for(let N of t.workspaces){if(N.manifest.version===null)continue;let U=W.stringifyIdent(N.anchoredLocator),V=v.get(N);V==="decline"?C.push(U):typeof V<"u"?x[U]=pw(V):p.has(N)&&R.push(U)}await oe.mkdirPromise(z.dirname(h),{recursive:!0}),await oe.changeFilePromise(h,Ba(new Ba.PreserveOrdering({releases:Object.keys(x).length>0?x:void 0,declined:C.length>0?C:void 0,undecided:R.length>0?R:void 0})))}}}function zDt(t){return aF(t).size>0||Gv(t).length>0}function aF(t){let e=new Set;for(let r of t.changedWorkspaces)r.manifest.version!==null&&(t.releases.has(r)||e.add(r));return e}function Gv(t,{include:e=new Set}={}){let r=[],o=new Map(_e.mapAndFilter([...t.releases],([n,u])=>u==="decline"?_e.mapAndFilter.skip:[n.anchoredLocator.locatorHash,n])),a=new Map(_e.mapAndFilter([...t.releases],([n,u])=>u!=="decline"?_e.mapAndFilter.skip:[n.anchoredLocator.locatorHash,n]));for(let n of t.project.workspaces)if(!(!e.has(n)&&(a.has(n.anchoredLocator.locatorHash)||o.has(n.anchoredLocator.locatorHash)))&&n.manifest.version!==null)for(let u of Ot.hardDependencies)for(let A of n.manifest.getForScope(u).values()){let p=t.project.tryWorkspaceByDescriptor(A);p!==null&&o.has(p.anchoredLocator.locatorHash)&&r.push([n,p])}return r}function Wj(t,e){let r=vA.default.clean(e);for(let o of Object.values(hw))if(o!=="undecided"&&o!=="decline"&&vA.default.inc(t,o)===r)return o;return null}function lF(t,e){if(vA.default.valid(e))return e;if(t===null)throw new it(`Cannot apply the release strategy "${e}" unless the workspace already has a valid version`);if(!vA.default.valid(t))throw new it(`Cannot apply the release strategy "${e}" on a non-semver version (${t})`);let r=vA.default.inc(t,e);if(r===null)throw new it(`Cannot apply the release strategy "${e}" on the specified version (${t})`);return r}function Kj(t,e,{report:r}){let o=new Map;for(let a of t.workspaces)for(let n of Ot.allDependencies)for(let u of a.manifest[n].values()){let A=t.tryWorkspaceByDescriptor(u);if(A===null||!e.has(A))continue;_e.getArrayWithDefault(o,A).push([a,n,u.identHash])}for(let[a,n]of e){let u=a.manifest.version;a.manifest.version=n,vA.default.prerelease(n)===null?delete a.manifest.raw.stableVersion:a.manifest.raw.stableVersion||(a.manifest.raw.stableVersion=u);let A=a.manifest.name!==null?W.stringifyIdent(a.manifest.name):null;r.reportInfo(0,`${W.prettyLocator(t.configuration,a.anchoredLocator)}: Bumped to ${n}`),r.reportJson({cwd:le.fromPortablePath(a.cwd),ident:A,oldVersion:u,newVersion:n});let p=o.get(a);if(!(typeof p>"u"))for(let[h,E,I]of p){let v=h.manifest[E].get(I);if(typeof v>"u")throw new Error("Assertion failed: The dependency should have existed");let x=v.range,C=!1;if(x.startsWith(Xn.protocol)&&(x=x.slice(Xn.protocol.length),C=!0,x===a.relativeCwd))continue;let R=x.match(KDt);if(!R){r.reportWarning(0,`Couldn't auto-upgrade range ${x} (in ${W.prettyLocator(t.configuration,h.anchoredLocator)})`);continue}let N=`${R[1]}${n}`;C&&(N=`${Xn.protocol}${N}`);let U=W.makeDescriptor(v,N);h.manifest[E].set(I,U)}}}var VDt=new Map([["%n",{extract:t=>t.length>=1?[t[0],t.slice(1)]:null,generate:(t=0)=>`${t+1}`}]]);function KBe(t,{current:e,prerelease:r}){let o=new vA.default.SemVer(e),a=o.prerelease.slice(),n=[];o.prerelease=[],o.format()!==t&&(a.length=0);let u=!0,A=r.split(/\./g);for(let p of A){let h=VDt.get(p);if(typeof h>"u")n.push(p),a[0]===p?a.shift():u=!1;else{let E=u?h.extract(a):null;E!==null&&typeof E[0]=="number"?(n.push(h.generate(E[0])),a=E[1]):(n.push(h.generate()),u=!1)}}return o.prerelease&&(o.prerelease=[]),`${t}-${n.join(".")}`}var tg=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean("--all",!1,{description:"Apply the deferred version changes on all workspaces"});this.dryRun=ge.Boolean("--dry-run",!1,{description:"Print the versions without actually generating the package archive"});this.prerelease=ge.String("--prerelease",{description:"Add a prerelease identifier to new versions",tolerateBoolean:!0});this.recursive=ge.Boolean("-R,--recursive",{description:"Release the transitive workspaces as well"});this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout},async A=>{let p=this.prerelease?typeof this.prerelease!="boolean"?this.prerelease:"rc.%n":null,h=await qv(o,{prerelease:p}),E=new Map;if(this.all)E=h;else{let I=this.recursive?a.getRecursiveWorkspaceDependencies():[a];for(let v of I){let x=h.get(v);typeof x<"u"&&E.set(v,x)}}if(E.size===0){let I=h.size>0?" Did you want to add --all?":"";A.reportWarning(0,`The current workspace doesn't seem to require a version bump.${I}`);return}Kj(o,E,{report:A}),this.dryRun||(p||(this.all?await jj(o):await Yj(o,[...E.keys()])),A.reportSeparator())});return this.dryRun||u.hasErrors()?u.exitCode():await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n})}};tg.paths=[["version","apply"]],tg.usage=nt.Usage({category:"Release-related commands",description:"apply all the deferred version bumps at once",details:`
- This command will apply the deferred version changes and remove their definitions from the repository.
-
- Note that if \`--prerelease\` is set, the given prerelease identifier (by default \`rc.%n\`) will be used on all new versions and the version definitions will be kept as-is.
-
- By default only the current workspace will be bumped, but you can configure this behavior by using one of:
-
- - \`--recursive\` to also apply the version bump on its dependencies
- - \`--all\` to apply the version bump on all packages in the repository
-
- Note that this command will also update the \`workspace:\` references across all your local workspaces, thus ensuring that they keep referring to the same workspaces even after the version bump.
- `,examples:[["Apply the version change to the local workspace","yarn version apply"],["Apply the version change to all the workspaces in the local workspace","yarn version apply --all"]]});Ye();Pt();qt();var cF=$e(Jn());var rg=class extends ut{constructor(){super(...arguments);this.interactive=ge.Boolean("-i,--interactive",{description:"Open an interactive interface used to set version bumps"})}async execute(){return this.interactive?await this.executeInteractive():await this.executeStandard()}async executeInteractive(){bC(this.context);let{Gem:r}=await Promise.resolve().then(()=>(cQ(),Bq)),{ScrollableItems:o}=await Promise.resolve().then(()=>(pQ(),fQ)),{FocusRequest:a}=await Promise.resolve().then(()=>(Dq(),Vwe)),{useListInput:n}=await Promise.resolve().then(()=>(AQ(),Jwe)),{renderForm:u}=await Promise.resolve().then(()=>(mQ(),dQ)),{Box:A,Text:p}=await Promise.resolve().then(()=>$e(sc())),{default:h,useCallback:E,useState:I}=await Promise.resolve().then(()=>$e(on())),v=await Ke.find(this.context.cwd,this.context.plugins),{project:x,workspace:C}=await St.find(v,this.context.cwd);if(!C)throw new nr(x.cwd,this.context.cwd);await x.restoreInstallState();let R=await gw(x);if(R===null||R.releaseRoots.size===0)return 0;if(R.root===null)throw new it("This command can only be run on Git repositories");let N=()=>h.createElement(A,{flexDirection:"row",paddingBottom:1},h.createElement(A,{flexDirection:"column",width:60},h.createElement(A,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<up>"),"/",h.createElement(p,{bold:!0,color:"cyanBright"},"<down>")," to select workspaces.")),h.createElement(A,null,h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<left>"),"/",h.createElement(p,{bold:!0,color:"cyanBright"},"<right>")," to select release strategies."))),h.createElement(A,{flexDirection:"column"},h.createElement(A,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<enter>")," to save.")),h.createElement(A,{marginLeft:1},h.createElement(p,null,"Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<ctrl+c>")," to abort.")))),U=({workspace:me,active:he,decision:Be,setDecision:we})=>{let g=me.manifest.raw.stableVersion??me.manifest.version;if(g===null)throw new Error(`Assertion failed: The version should have been set (${W.prettyLocator(v,me.anchoredLocator)})`);if(cF.default.prerelease(g)!==null)throw new Error(`Assertion failed: Prerelease identifiers shouldn't be found (${g})`);let Ee=["undecided","decline","patch","minor","major"];n(Be,Ee,{active:he,minus:"left",plus:"right",set:we});let Pe=Be==="undecided"?h.createElement(p,{color:"yellow"},g):Be==="decline"?h.createElement(p,{color:"green"},g):h.createElement(p,null,h.createElement(p,{color:"magenta"},g)," \u2192 ",h.createElement(p,{color:"green"},cF.default.valid(Be)?Be:cF.default.inc(g,Be)));return h.createElement(A,{flexDirection:"column"},h.createElement(A,null,h.createElement(p,null,W.prettyLocator(v,me.anchoredLocator)," - ",Pe)),h.createElement(A,null,Ee.map(ce=>h.createElement(A,{key:ce,paddingLeft:2},h.createElement(p,null,h.createElement(r,{active:ce===Be})," ",ce)))))},V=me=>{let he=new Set(R.releaseRoots),Be=new Map([...me].filter(([we])=>he.has(we)));for(;;){let we=Gv({project:R.project,releases:Be}),g=!1;if(we.length>0){for(let[Ee]of we)if(!he.has(Ee)){he.add(Ee),g=!0;let Pe=me.get(Ee);typeof Pe<"u"&&Be.set(Ee,Pe)}}if(!g)break}return{relevantWorkspaces:he,relevantReleases:Be}},te=()=>{let[me,he]=I(()=>new Map(R.releases)),Be=E((we,g)=>{let Ee=new Map(me);g!=="undecided"?Ee.set(we,g):Ee.delete(we);let{relevantReleases:Pe}=V(Ee);he(Pe)},[me,he]);return[me,Be]},ae=({workspaces:me,releases:he})=>{let Be=[];Be.push(`${me.size} total`);let we=0,g=0;for(let Ee of me){let Pe=he.get(Ee);typeof Pe>"u"?g+=1:Pe!=="decline"&&(we+=1)}return Be.push(`${we} release${we===1?"":"s"}`),Be.push(`${g} remaining`),h.createElement(p,{color:"yellow"},Be.join(", "))},ue=await u(({useSubmit:me})=>{let[he,Be]=te();me(he);let{relevantWorkspaces:we}=V(he),g=new Set([...we].filter(ne=>!R.releaseRoots.has(ne))),[Ee,Pe]=I(0),ce=E(ne=>{switch(ne){case a.BEFORE:Pe(Ee-1);break;case a.AFTER:Pe(Ee+1);break}},[Ee,Pe]);return h.createElement(A,{flexDirection:"column"},h.createElement(N,null),h.createElement(A,null,h.createElement(p,{wrap:"wrap"},"The following files have been modified in your local checkout.")),h.createElement(A,{flexDirection:"column",marginTop:1,paddingLeft:2},[...R.changedFiles].map(ne=>h.createElement(A,{key:ne},h.createElement(p,null,h.createElement(p,{color:"grey"},le.fromPortablePath(R.root)),le.sep,le.relative(le.fromPortablePath(R.root),le.fromPortablePath(ne)))))),R.releaseRoots.size>0&&h.createElement(h.Fragment,null,h.createElement(A,{marginTop:1},h.createElement(p,{wrap:"wrap"},"Because of those files having been modified, the following workspaces may need to be released again (note that private workspaces are also shown here, because even though they won't be published, releasing them will allow us to flag their dependents for potential re-release):")),g.size>3?h.createElement(A,{marginTop:1},h.createElement(ae,{workspaces:R.releaseRoots,releases:he})):null,h.createElement(A,{marginTop:1,flexDirection:"column"},h.createElement(o,{active:Ee%2===0,radius:1,size:2,onFocusRequest:ce},[...R.releaseRoots].map(ne=>h.createElement(U,{key:ne.cwd,workspace:ne,decision:he.get(ne)||"undecided",setDecision:ee=>Be(ne,ee)}))))),g.size>0?h.createElement(h.Fragment,null,h.createElement(A,{marginTop:1},h.createElement(p,{wrap:"wrap"},"The following workspaces depend on other workspaces that have been marked for release, and thus may need to be released as well:")),h.createElement(A,null,h.createElement(p,null,"(Press ",h.createElement(p,{bold:!0,color:"cyanBright"},"<tab>")," to move the focus between the workspace groups.)")),g.size>5?h.createElement(A,{marginTop:1},h.createElement(ae,{workspaces:g,releases:he})):null,h.createElement(A,{marginTop:1,flexDirection:"column"},h.createElement(o,{active:Ee%2===1,radius:2,size:2,onFocusRequest:ce},[...g].map(ne=>h.createElement(U,{key:ne.cwd,workspace:ne,decision:he.get(ne)||"undecided",setDecision:ee=>Be(ne,ee)}))))):null)},{versionFile:R},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof ue>"u")return 1;R.releases.clear();for(let[me,he]of ue)R.releases.set(me,he);await R.saveAll()}async executeStandard(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);return await o.restoreInstallState(),(await Lt.start({configuration:r,stdout:this.context.stdout},async u=>{let A=await gw(o);if(A===null||A.releaseRoots.size===0)return;if(A.root===null)throw new it("This command can only be run on Git repositories");if(u.reportInfo(0,`Your PR was started right after ${de.pretty(r,A.baseHash.slice(0,7),"yellow")} ${de.pretty(r,A.baseTitle,"magenta")}`),A.changedFiles.size>0){u.reportInfo(0,"You have changed the following files since then:"),u.reportSeparator();for(let v of A.changedFiles)u.reportInfo(null,`${de.pretty(r,le.fromPortablePath(A.root),"gray")}${le.sep}${le.relative(le.fromPortablePath(A.root),le.fromPortablePath(v))}`)}let p=!1,h=!1,E=aF(A);if(E.size>0){p||u.reportSeparator();for(let v of E)u.reportError(0,`${W.prettyLocator(r,v.anchoredLocator)} has been modified but doesn't have a release strategy attached`);p=!0}let I=Gv(A);for(let[v,x]of I)h||u.reportSeparator(),u.reportError(0,`${W.prettyLocator(r,v.anchoredLocator)} doesn't have a release strategy attached, but depends on ${W.prettyWorkspace(r,x)} which is planned for release.`),h=!0;(p||h)&&(u.reportSeparator(),u.reportInfo(0,"This command detected that at least some workspaces have received modifications without explicit instructions as to how they had to be released (if needed)."),u.reportInfo(0,"To correct these errors, run `yarn version check --interactive` then follow the instructions."))})).exitCode()}};rg.paths=[["version","check"]],rg.usage=nt.Usage({category:"Release-related commands",description:"check that all the relevant packages have been bumped",details:"\n **Warning:** This command currently requires Git.\n\n This command will check that all the packages covered by the files listed in argument have been properly bumped or declined to bump.\n\n In the case of a bump, the check will also cover transitive packages - meaning that should `Foo` be bumped, a package `Bar` depending on `Foo` will require a decision as to whether `Bar` will need to be bumped. This check doesn't cross packages that have declined to bump.\n\n In case no arguments are passed to the function, the list of modified files will be generated by comparing the HEAD against `master`.\n ",examples:[["Check whether the modified packages need a bump","yarn version check"]]});Ye();qt();var uF=$e(Jn());var ng=class extends ut{constructor(){super(...arguments);this.deferred=ge.Boolean("-d,--deferred",{description:"Prepare the version to be bumped during the next release cycle"});this.immediate=ge.Boolean("-i,--immediate",{description:"Bump the version immediately"});this.strategy=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);let n=r.get("preferDeferredVersions");this.deferred&&(n=!0),this.immediate&&(n=!1);let u=uF.default.valid(this.strategy),A=this.strategy==="decline",p;if(u)if(a.manifest.version!==null){let E=Wj(a.manifest.version,this.strategy);E!==null?p=E:p=this.strategy}else p=this.strategy;else{let E=a.manifest.version;if(!A){if(E===null)throw new it("Can't bump the version if there wasn't a version to begin with - use 0.0.0 as initial version then run the command again.");if(typeof E!="string"||!uF.default.valid(E))throw new it(`Can't bump the version (${E}) if it's not valid semver`)}p=pw(this.strategy)}if(!n){let I=(await qv(o)).get(a);if(typeof I<"u"&&p!=="decline"){let v=lF(a.manifest.version,p);if(uF.default.lt(v,I))throw new it(`Can't bump the version to one that would be lower than the current deferred one (${I})`)}}let h=await gw(o,{allowEmpty:!0});return h.releases.set(a,p),await h.saveAll(),n?0:await this.cli.run(["version","apply"])}};ng.paths=[["version"]],ng.usage=nt.Usage({category:"Release-related commands",description:"apply a new version to the current package",details:"\n This command will bump the version number for the given package, following the specified strategy:\n\n - If `major`, the first number from the semver range will be increased (`X.0.0`).\n - If `minor`, the second number from the semver range will be increased (`0.X.0`).\n - If `patch`, the third number from the semver range will be increased (`0.0.X`).\n - If prefixed by `pre` (`premajor`, ...), a `-0` suffix will be set (`0.0.0-0`).\n - If `prerelease`, the suffix will be increased (`0.0.0-X`); the third number from the semver range will also be increased if there was no suffix in the previous version.\n - If `decline`, the nonce will be increased for `yarn version check` to pass without version bump.\n - If a valid semver range, it will be used as new version.\n - If unspecified, Yarn will ask you for guidance.\n\n For more information about the `--deferred` flag, consult our documentation (https://yarnpkg.com/features/release-workflow#deferred-versioning).\n ",examples:[["Immediately bump the version to the next major","yarn version major"],["Prepare the version to be bumped to the next major","yarn version major --deferred"]]});var JDt={configuration:{deferredVersionFolder:{description:"Folder where are stored the versioning files",type:"ABSOLUTE_PATH",default:"./.yarn/versions"},preferDeferredVersions:{description:"If true, running `yarn version` will assume the `--deferred` flag unless `--immediate` is set",type:"BOOLEAN",default:!1}},commands:[tg,rg,ng]},XDt=JDt;var Vj={};zt(Vj,{WorkspacesFocusCommand:()=>ig,WorkspacesForeachCommand:()=>lp,default:()=>ePt});Ye();Ye();qt();var ig=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean("--json",!1,{description:"Format the output as an NDJSON stream"});this.production=ge.Boolean("--production",!1,{description:"Only install regular dependencies by omitting dev dependencies"});this.all=ge.Boolean("-A,--all",!1,{description:"Install the entire project"});this.workspaces=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);await o.restoreInstallState({restoreResolutions:!1});let u;if(this.all)u=new Set(o.workspaces);else if(this.workspaces.length===0){if(!a)throw new nr(o.cwd,this.context.cwd);u=new Set([a])}else u=new Set(this.workspaces.map(A=>o.getWorkspaceByIdent(W.parseIdent(A))));for(let A of u)for(let p of this.production?["dependencies"]:Ot.hardDependencies)for(let h of A.manifest.getForScope(p).values()){let E=o.tryWorkspaceByDescriptor(h);E!==null&&u.add(E)}for(let A of o.workspaces)u.has(A)?this.production&&A.manifest.devDependencies.clear():(A.manifest.installConfig=A.manifest.installConfig||{},A.manifest.installConfig.selfReferences=!1,A.manifest.dependencies.clear(),A.manifest.devDependencies.clear(),A.manifest.peerDependencies.clear(),A.manifest.scripts.clear());return await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n,persistProject:!1})}};ig.paths=[["workspaces","focus"]],ig.usage=nt.Usage({category:"Workspace-related commands",description:"install a single workspace and its dependencies",details:"\n This command will run an install as if the specified workspaces (and all other workspaces they depend on) were the only ones in the project. If no workspaces are explicitly listed, the active one will be assumed.\n\n Note that this command is only very moderately useful when using zero-installs, since the cache will contain all the packages anyway - meaning that the only difference between a full install and a focused install would just be a few extra lines in the `.pnp.cjs` file, at the cost of introducing an extra complexity.\n\n If the `-A,--all` flag is set, the entire project will be installed. Combine with `--production` to replicate the old `yarn install --production`.\n "});Ye();Ye();Ye();qt();var mw=$e(Zo()),VBe=$e(sd());$a();var lp=class extends ut{constructor(){super(...arguments);this.from=ge.Array("--from",{description:"An array of glob pattern idents or paths from which to base any recursion"});this.all=ge.Boolean("-A,--all",{description:"Run the command on all workspaces of a project"});this.recursive=ge.Boolean("-R,--recursive",{description:"Run the command on the current workspace and all of its recursive dependencies"});this.worktree=ge.Boolean("-W,--worktree",{description:"Run the command on all workspaces of the current worktree"});this.verbose=ge.Counter("-v,--verbose",{description:"Increase level of logging verbosity up to 2 times"});this.parallel=ge.Boolean("-p,--parallel",!1,{description:"Run the commands in parallel"});this.interlaced=ge.Boolean("-i,--interlaced",!1,{description:"Print the output of commands in real-time instead of buffering it"});this.jobs=ge.String("-j,--jobs",{description:"The maximum number of parallel tasks that the execution will be limited to; or `unlimited`",validator:TT([Ks(["unlimited"]),aI(RT(),[NT(),LT(1)])])});this.topological=ge.Boolean("-t,--topological",!1,{description:"Run the command after all workspaces it depends on (regular) have finished"});this.topologicalDev=ge.Boolean("--topological-dev",!1,{description:"Run the command after all workspaces it depends on (regular + dev) have finished"});this.include=ge.Array("--include",[],{description:"An array of glob pattern idents or paths; only matching workspaces will be traversed"});this.exclude=ge.Array("--exclude",[],{description:"An array of glob pattern idents or paths; matching workspaces won't be traversed"});this.publicOnly=ge.Boolean("--no-private",{description:"Avoid running the command on private workspaces"});this.since=ge.String("--since",{description:"Only include workspaces that have been changed since the specified ref.",tolerateBoolean:!0});this.dryRun=ge.Boolean("-n,--dry-run",{description:"Print the commands that would be run, without actually running them"});this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!this.all&&!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=this.cli.process([this.commandName,...this.args]),u=n.path.length===1&&n.path[0]==="run"&&typeof n.scriptName<"u"?n.scriptName:null;if(n.path.length===0)throw new it("Invalid subcommand name for iteration - use the 'run' keyword if you wish to execute a script");let A=we=>{!this.dryRun||this.context.stdout.write(`${we}
-`)},p=()=>{let we=this.from.map(g=>mw.default.matcher(g));return o.workspaces.filter(g=>{let Ee=W.stringifyIdent(g.anchoredLocator),Pe=g.relativeCwd;return we.some(ce=>ce(Ee)||ce(Pe))})},h=[];if(this.since?(A("Option --since is set; selecting the changed workspaces as root for workspace selection"),h=Array.from(await ra.fetchChangedWorkspaces({ref:this.since,project:o}))):this.from?(A("Option --from is set; selecting the specified workspaces"),h=[...p()]):this.worktree?(A("Option --worktree is set; selecting the current workspace"),h=[a]):this.recursive?(A("Option --recursive is set; selecting the current workspace"),h=[a]):this.all&&(A("Option --all is set; selecting all workspaces"),h=[...o.workspaces]),this.dryRun&&!this.all){for(let we of h)A(`
-- ${we.relativeCwd}
- ${W.prettyLocator(r,we.anchoredLocator)}`);h.length>0&&A("")}let E;if(this.recursive?this.since?(A("Option --recursive --since is set; recursively selecting all dependent workspaces"),E=new Set(h.map(we=>[...we.getRecursiveWorkspaceDependents()]).flat())):(A("Option --recursive is set; recursively selecting all transitive dependencies"),E=new Set(h.map(we=>[...we.getRecursiveWorkspaceDependencies()]).flat())):this.worktree?(A("Option --worktree is set; recursively selecting all nested workspaces"),E=new Set(h.map(we=>[...we.getRecursiveWorkspaceChildren()]).flat())):E=null,E!==null&&(h=[...new Set([...h,...E])],this.dryRun))for(let we of E)A(`
-- ${we.relativeCwd}
- ${W.prettyLocator(r,we.anchoredLocator)}`);let I=[],v=!1;if(u?.includes(":")){for(let we of o.workspaces)if(we.manifest.scripts.has(u)&&(v=!v,v===!1))break}for(let we of h){if(u&&!we.manifest.scripts.has(u)&&!v&&!(await un.getWorkspaceAccessibleBinaries(we)).has(u)){A(`Excluding ${we.relativeCwd} because it doesn't have a "${u}" script`);continue}if(!(u===r.env.npm_lifecycle_event&&we.cwd===a.cwd)){if(this.include.length>0&&!mw.default.isMatch(W.stringifyIdent(we.anchoredLocator),this.include)&&!mw.default.isMatch(we.relativeCwd,this.include)){A(`Excluding ${we.relativeCwd} because it doesn't match the --include filter`);continue}if(this.exclude.length>0&&(mw.default.isMatch(W.stringifyIdent(we.anchoredLocator),this.exclude)||mw.default.isMatch(we.relativeCwd,this.exclude))){A(`Excluding ${we.relativeCwd} because it matches the --include filter`);continue}if(this.publicOnly&&we.manifest.private===!0){A(`Excluding ${we.relativeCwd} because it's a private workspace and --no-private was set`);continue}I.push(we)}}if(this.dryRun)return 0;let x=this.verbose??(this.context.stdout.isTTY?1/0:0),C=x>0,R=x>1,N=this.parallel?this.jobs==="unlimited"?1/0:Number(this.jobs)||Math.ceil(Vi.availableParallelism()/2):1,U=N===1?!1:this.parallel,V=U?this.interlaced:!0,te=(0,VBe.default)(N),ae=new Map,fe=new Set,ue=0,me=null,he=!1,Be=await Lt.start({configuration:r,stdout:this.context.stdout,includePrefix:!1},async we=>{let g=async(Ee,{commandIndex:Pe})=>{if(he)return-1;!U&&R&&Pe>1&&we.reportSeparator();let ce=ZDt(Ee,{configuration:r,label:C,commandIndex:Pe}),[ne,ee]=zBe(we,{prefix:ce,interlaced:V}),[Ie,Fe]=zBe(we,{prefix:ce,interlaced:V});try{R&&we.reportInfo(null,`${ce?`${ce} `:""}Process started`);let At=Date.now(),H=await this.cli.run([this.commandName,...this.args],{cwd:Ee.cwd,stdout:ne,stderr:Ie})||0;ne.end(),Ie.end(),await ee,await Fe;let at=Date.now();if(R){let Re=r.get("enableTimers")?`, completed in ${de.pretty(r,at-At,de.Type.DURATION)}`:"";we.reportInfo(null,`${ce?`${ce} `:""}Process exited (exit code ${H})${Re}`)}return H===130&&(he=!0,me=H),H}catch(At){throw ne.end(),Ie.end(),await ee,await Fe,At}};for(let Ee of I)ae.set(Ee.anchoredLocator.locatorHash,Ee);for(;ae.size>0&&!we.hasErrors();){let Ee=[];for(let[ne,ee]of ae){if(fe.has(ee.anchoredDescriptor.descriptorHash))continue;let Ie=!0;if(this.topological||this.topologicalDev){let Fe=this.topologicalDev?new Map([...ee.manifest.dependencies,...ee.manifest.devDependencies]):ee.manifest.dependencies;for(let At of Fe.values()){let H=o.tryWorkspaceByDescriptor(At);if(Ie=H===null||!ae.has(H.anchoredLocator.locatorHash),!Ie)break}}if(!!Ie&&(fe.add(ee.anchoredDescriptor.descriptorHash),Ee.push(te(async()=>{let Fe=await g(ee,{commandIndex:++ue});return ae.delete(ne),fe.delete(ee.anchoredDescriptor.descriptorHash),Fe})),!U))break}if(Ee.length===0){let ne=Array.from(ae.values()).map(ee=>W.prettyLocator(r,ee.anchoredLocator)).join(", ");we.reportError(3,`Dependency cycle detected (${ne})`);return}let ce=(await Promise.all(Ee)).find(ne=>ne!==0);me===null&&(me=typeof ce<"u"?1:me),(this.topological||this.topologicalDev)&&typeof ce<"u"&&we.reportError(0,"The command failed for workspaces that are depended upon by other workspaces; can't satisfy the dependency graph")}});return me!==null?me:Be.exitCode()}};lp.paths=[["workspaces","foreach"]],lp.usage=nt.Usage({category:"Workspace-related commands",description:"run a command on all workspaces",details:"\n This command will run a given sub-command on current and all its descendant workspaces. Various flags can alter the exact behavior of the command:\n\n - If `-p,--parallel` is set, the commands will be ran in parallel; they'll by default be limited to a number of parallel tasks roughly equal to half your core number, but that can be overridden via `-j,--jobs`, or disabled by setting `-j unlimited`.\n\n - If `-p,--parallel` and `-i,--interlaced` are both set, Yarn will print the lines from the output as it receives them. If `-i,--interlaced` wasn't set, it would instead buffer the output from each process and print the resulting buffers only after their source processes have exited.\n\n - If `-t,--topological` is set, Yarn will only run the command after all workspaces that it depends on through the `dependencies` field have successfully finished executing. If `--topological-dev` is set, both the `dependencies` and `devDependencies` fields will be considered when figuring out the wait points.\n\n - If `-A,--all` is set, Yarn will run the command on all the workspaces of a project.\n\n - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\n\n - If `-W,--worktree` is set, Yarn will find workspaces to run the command on by looking at the current worktree.\n\n - If `--from` is set, Yarn will use the packages matching the 'from' glob as the starting point for any recursive search.\n\n - If `--since` is set, Yarn will only run the command on workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\n\n - If `--dry-run` is set, Yarn will explain what it would do without actually doing anything.\n\n - The command may apply to only some workspaces through the use of `--include` which acts as a whitelist. The `--exclude` flag will do the opposite and will be a list of packages that mustn't execute the script. Both flags accept glob patterns (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n\n The `-v,--verbose` flag can be passed up to twice: once to prefix output lines with the originating workspace's name, and again to include start/finish/timing log lines. Maximum verbosity is enabled by default in terminal environments.\n\n If the command is `run` and the script being run does not exist the child workspace will be skipped without error.\n ",examples:[["Publish all packages","yarn workspaces foreach -A npm publish --tolerate-republish"],["Run the build script on all descendant packages","yarn workspaces foreach -A run build"],["Run the build script on current and all descendant packages in parallel, building package dependencies first","yarn workspaces foreach -Apt run build"],["Run the build script on several packages and all their dependencies, building dependencies first","yarn workspaces foreach -Rpt --from '{workspace-a,workspace-b}' run build"]]}),lp.schema=[cI("all",Yu.Forbids,["from","recursive","since","worktree"],{missingIf:"undefined"}),OT(["all","recursive","since","worktree"],{missingIf:"undefined"})];function zBe(t,{prefix:e,interlaced:r}){let o=t.createStreamReporter(e),a=new _e.DefaultStream;a.pipe(o,{end:!1}),a.on("finish",()=>{o.end()});let n=new Promise(A=>{o.on("finish",()=>{A(a.active)})});if(r)return[a,n];let u=new _e.BufferStream;return u.pipe(a,{end:!1}),u.on("finish",()=>{a.end()}),[u,n]}function ZDt(t,{configuration:e,commandIndex:r,label:o}){if(!o)return null;let n=`[${W.stringifyIdent(t.anchoredLocator)}]:`,u=["#2E86AB","#A23B72","#F18F01","#C73E1D","#CCE2A3"],A=u[r%u.length];return de.pretty(e,n,A)}var $Dt={commands:[ig,lp]},ePt=$Dt;var pC=()=>({modules:new Map([["@yarnpkg/cli",a2],["@yarnpkg/core",o2],["@yarnpkg/fslib",zw],["@yarnpkg/libzip",x1],["@yarnpkg/parsers",rI],["@yarnpkg/shell",T1],["clipanion",hI],["semver",tPt],["typanion",zo],["@yarnpkg/plugin-essentials",$8],["@yarnpkg/plugin-compat",iH],["@yarnpkg/plugin-constraints",wH],["@yarnpkg/plugin-dlx",IH],["@yarnpkg/plugin-exec",DH],["@yarnpkg/plugin-file",SH],["@yarnpkg/plugin-git",Z8],["@yarnpkg/plugin-github",kH],["@yarnpkg/plugin-http",QH],["@yarnpkg/plugin-init",FH],["@yarnpkg/plugin-interactive-tools",Tq],["@yarnpkg/plugin-link",Lq],["@yarnpkg/plugin-nm",yG],["@yarnpkg/plugin-npm",dj],["@yarnpkg/plugin-npm-cli",Dj],["@yarnpkg/plugin-pack",Aj],["@yarnpkg/plugin-patch",Fj],["@yarnpkg/plugin-pnp",oG],["@yarnpkg/plugin-pnpm",Lj],["@yarnpkg/plugin-stage",qj],["@yarnpkg/plugin-typescript",Gj],["@yarnpkg/plugin-version",zj],["@yarnpkg/plugin-workspace-tools",Vj]]),plugins:new Set(["@yarnpkg/plugin-essentials","@yarnpkg/plugin-compat","@yarnpkg/plugin-constraints","@yarnpkg/plugin-dlx","@yarnpkg/plugin-exec","@yarnpkg/plugin-file","@yarnpkg/plugin-git","@yarnpkg/plugin-github","@yarnpkg/plugin-http","@yarnpkg/plugin-init","@yarnpkg/plugin-interactive-tools","@yarnpkg/plugin-link","@yarnpkg/plugin-nm","@yarnpkg/plugin-npm","@yarnpkg/plugin-npm-cli","@yarnpkg/plugin-pack","@yarnpkg/plugin-patch","@yarnpkg/plugin-pnp","@yarnpkg/plugin-pnpm","@yarnpkg/plugin-stage","@yarnpkg/plugin-typescript","@yarnpkg/plugin-version","@yarnpkg/plugin-workspace-tools"])});function ZBe({cwd:t,pluginConfiguration:e}){let r=new as({binaryLabel:"Yarn Package Manager",binaryName:"yarn",binaryVersion:rn??"<unknown>"});return Object.assign(r,{defaultContext:{...as.defaultContext,cwd:t,plugins:e,quiet:!1,stdin:process.stdin,stdout:process.stdout,stderr:process.stderr}})}function rPt(t){if(_e.parseOptionalBoolean(process.env.YARN_IGNORE_NODE))return!0;let r=process.versions.node,o=">=18.12.0";if(kr.satisfiesWithPrereleases(r,o))return!0;let a=new it(`This tool requires a Node version compatible with ${o} (got ${r}). Upgrade Node, or set \`YARN_IGNORE_NODE=1\` in your environment.`);return as.defaultContext.stdout.write(t.error(a)),!1}async function $Be({selfPath:t,pluginConfiguration:e}){return await Ke.find(le.toPortablePath(process.cwd()),e,{strict:!1,usePathCheck:t})}function nPt(t,e,{yarnPath:r}){if(!oe.existsSync(r))return t.error(new Error(`The "yarn-path" option has been set, but the specified location doesn't exist (${r}).`)),1;process.on("SIGINT",()=>{});let o={stdio:"inherit",env:{...process.env,YARN_IGNORE_PATH:"1"}};try{(0,JBe.execFileSync)(process.execPath,[le.fromPortablePath(r),...e],o)}catch(a){return a.status??1}return 0}function iPt(t,e){let r=null,o=e;return e.length>=2&&e[0]==="--cwd"?(r=le.toPortablePath(e[1]),o=e.slice(2)):e.length>=1&&e[0].startsWith("--cwd=")?(r=le.toPortablePath(e[0].slice(6)),o=e.slice(1)):e[0]==="add"&&e[e.length-2]==="--cwd"&&(r=le.toPortablePath(e[e.length-1]),o=e.slice(0,e.length-2)),t.defaultContext.cwd=r!==null?z.resolve(r):z.cwd(),o}function sPt(t,{configuration:e}){if(!e.get("enableTelemetry")||XBe.isCI||!process.stdout.isTTY)return;Ke.telemetry=new uC(e,"puba9cdc10ec5790a2cf4969dd413a47270");let o=/^@yarnpkg\/plugin-(.*)$/;for(let a of e.plugins.keys())AC.has(a.match(o)?.[1]??"")&&Ke.telemetry?.reportPluginName(a);t.binaryVersion&&Ke.telemetry.reportVersion(t.binaryVersion)}function eve(t,{configuration:e}){for(let r of e.plugins.values())for(let o of r.commands||[])t.register(o)}async function oPt(t,e,{selfPath:r,pluginConfiguration:o}){if(!rPt(t))return 1;let a=await $Be({selfPath:r,pluginConfiguration:o}),n=a.get("yarnPath"),u=a.get("ignorePath");if(n&&!u)return nPt(t,e,{yarnPath:n});delete process.env.YARN_IGNORE_PATH;let A=iPt(t,e);sPt(t,{configuration:a}),eve(t,{configuration:a});let p=t.process(A,t.defaultContext);return p.help||Ke.telemetry?.reportCommandName(p.path.join(" ")),await t.run(p,t.defaultContext)}async function ehe({cwd:t=z.cwd(),pluginConfiguration:e=pC()}={}){let r=ZBe({cwd:t,pluginConfiguration:e}),o=await $Be({pluginConfiguration:e,selfPath:null});return eve(r,{configuration:o}),r}async function nk(t,{cwd:e=z.cwd(),selfPath:r,pluginConfiguration:o}){let a=ZBe({cwd:e,pluginConfiguration:o});try{process.exitCode=await oPt(a,t,{selfPath:r,pluginConfiguration:o})}catch(n){as.defaultContext.stdout.write(a.error(n)),process.exitCode=1}finally{await oe.rmtempPromise()}}nk(process.argv.slice(2),{cwd:z.cwd(),selfPath:le.toPortablePath(le.resolve(process.argv[1])),pluginConfiguration:pC()});})();
-/*
-object-assign
-(c) Sindre Sorhus
-@license MIT
-*/
-/*!
- * buildToken
- * Builds OAuth token prefix (helper function)
- *
- * @name buildToken
- * @function
- * @param {GitUrl} obj The parsed Git url object.
- * @return {String} token prefix
- */
-/*!
- * fill-range <https://github.com/jonschlinkert/fill-range>
- *
- * Copyright (c) 2014-present, Jon Schlinkert.
- * Licensed under the MIT License.
- */
-/*!
- * is-extglob <https://github.com/jonschlinkert/is-extglob>
- *
- * Copyright (c) 2014-2016, Jon Schlinkert.
- * Licensed under the MIT License.
- */
-/*!
- * is-glob <https://github.com/jonschlinkert/is-glob>
- *
- * Copyright (c) 2014-2017, Jon Schlinkert.
- * Released under the MIT License.
- */
-/*!
- * is-number <https://github.com/jonschlinkert/is-number>
- *
- * Copyright (c) 2014-present, Jon Schlinkert.
- * Released under the MIT License.
- */
-/*!
- * is-windows <https://github.com/jonschlinkert/is-windows>
- *
- * Copyright © 2015-2018, Jon Schlinkert.
- * Released under the MIT License.
- */
-/*!
- * to-regex-range <https://github.com/micromatch/to-regex-range>
- *
- * Copyright (c) 2015-present, Jon Schlinkert.
- * Released under the MIT License.
- */
-/**
- @license
- Copyright (c) 2015, Rebecca Turner
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
- */
-/**
- @license
- Copyright Joyent, Inc. and other Node contributors.
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to permit
- persons to whom the Software is furnished to do so, subject to the
- following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
- NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-/**
- @license
- Copyright Node.js contributors. All rights reserved.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to
- deal in the Software without restriction, including without limitation the
- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- sell copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- IN THE SOFTWARE.
-*/
-/**
- @license
- The MIT License (MIT)
-
- Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com)
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-*/
-/** @license React v0.18.0
- * scheduler.production.min.js
- *
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-/** @license React v0.24.0
- * react-reconciler.production.min.js
- *
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-/** @license React v16.13.1
- * react.production.min.js
- *
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
diff --git a/server/sonar-web/.yarnrc.yml b/server/sonar-web/.yarnrc.yml
deleted file mode 100644
index 6d779f51314..00000000000
--- a/server/sonar-web/.yarnrc.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-compressionLevel: mixed
-
-defaultSemverRangePrefix: ''
-
-enableGlobalCache: true
-
-nodeLinker: node-modules
-
-yarnPath: .yarn/releases/yarn-4.2.2.cjs
-
-plugins:
- - path: .yarn/plugins/@yarnpkg/plugin-echo-execute.cjs
- spec: "https://yarnplugins.com/plugin-echo-execute"
diff --git a/server/sonar-web/__mocks__/@emotion/react.ts b/server/sonar-web/__mocks__/@emotion/react.ts
deleted file mode 100644
index 1cae4bec7cf..00000000000
--- a/server/sonar-web/__mocks__/@emotion/react.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/**
- * Mock Global from emotion which doesn't like jsdom
- * (Throws `TypeError: node.setAttribute is not a function`)
- */
-function Global() {
- return null;
-}
-
-module.exports = {
- ...jest.requireActual('@emotion/react'),
- Global,
-};
diff --git a/server/sonar-web/__mocks__/lodash.ts b/server/sonar-web/__mocks__/lodash.ts
deleted file mode 100644
index 9d07099fe51..00000000000
--- a/server/sonar-web/__mocks__/lodash.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-module.exports = {
- ...jest.requireActual('lodash'),
- debounce: (fn: Function) => {
- const result = (...args: any[]) => fn(...args);
- result.cancel = () => {}; // required to satisfy the Cancelable interface
- return result;
- }
-};
diff --git a/server/sonar-web/__mocks__/react-intl.tsx b/server/sonar-web/__mocks__/react-intl.tsx
deleted file mode 100644
index d3c6366be5d..00000000000
--- a/server/sonar-web/__mocks__/react-intl.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { isObject, some } from 'lodash';
-import * as React from 'react';
-
-module.exports = {
- ...jest.requireActual('react-intl'),
- useIntl: () => ({
- formatMessage: ({ id }, values = {}) => {
- if (some(values, isObject)) {
- return (
- <>
- {id}
- {Object.entries(values).map(([key, value]) => (
- <React.Fragment key={key}>
- {typeof value === 'function' ? value(`${id}_${key}`) : value}
- </React.Fragment>
- ))}
- </>
- );
- }
- return [id, ...Object.values(values)].join('.');
- },
- formatDate: jest.fn().mockReturnValue(''),
- }),
- FormattedMessage: ({
- id,
- values,
- }: {
- id: string;
- values?: { [x: string]: React.ReactNode | ((text: string) => React.ReactNode) };
- }) => {
- return (
- <>
- {id}
- {values !== undefined &&
- Object.entries(values).map(([key, value]) => (
- <React.Fragment key={key}>
- {typeof value === 'function' ? value(`${id}_${key}`) : value}
- </React.Fragment>
- ))}
- </>
- );
- },
-};
diff --git a/server/sonar-web/__mocks__/react-virtualized.tsx b/server/sonar-web/__mocks__/react-virtualized.tsx
deleted file mode 100644
index 6028f474ae8..00000000000
--- a/server/sonar-web/__mocks__/react-virtualized.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-type AutoSizerProps = {
- children: (props: AutoSizerChildProps) => React.ReactNode;
- disableHeight?: boolean;
- disableWidth?: boolean;
-};
-type AutoSizerChildProps = { height?: number; width?: number };
-
-module.exports = {
- ...jest.requireActual('react-virtualized'),
- AutoSizer: ({ children, disableHeight, disableWidth }: AutoSizerProps) => {
- const props: AutoSizerChildProps = {};
- if (!disableHeight) {
- props.height = 200;
- }
- if (!disableWidth) {
- props.width = 200;
- }
- return children(props);
- }
-};
diff --git a/server/sonar-web/__mocks__/react-virtualized/dist/commonjs/AutoSizer.ts b/server/sonar-web/__mocks__/react-virtualized/dist/commonjs/AutoSizer.ts
deleted file mode 100644
index 0b9b2caf4e1..00000000000
--- a/server/sonar-web/__mocks__/react-virtualized/dist/commonjs/AutoSizer.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-type AutoSizerProps = {
- children: (props: AutoSizerChildProps) => React.ReactNode;
- disableHeight?: boolean;
- disableWidth?: boolean;
-};
-type AutoSizerChildProps = { height?: number; width?: number };
-
-function AutoSizer({ children, disableHeight, disableWidth }: AutoSizerProps) {
- const props: AutoSizerChildProps = {};
- if (!disableHeight) {
- props.height = 200;
- }
- if (!disableWidth) {
- props.width = 200;
- }
- return children(props);
-}
-
-module.exports = { AutoSizer };
diff --git a/server/sonar-web/__mocks__/react-virtualized/dist/commonjs/WindowScroller.ts b/server/sonar-web/__mocks__/react-virtualized/dist/commonjs/WindowScroller.ts
deleted file mode 100644
index b7efcbf10e0..00000000000
--- a/server/sonar-web/__mocks__/react-virtualized/dist/commonjs/WindowScroller.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-type WindowScrollerProps = {
- children: (params: WindowScrollerChildProps) => React.ReactNode;
-};
-type WindowScrollerChildProps = {
- height: number;
- isScrolling: boolean;
- scrollTop: number;
- onChildScroll: (params: { scrollTop: number }) => void;
-};
-
-function WindowScroller({ children }: WindowScrollerProps) {
- const props: WindowScrollerChildProps = {
- height: 200,
- isScrolling: false,
- scrollTop: 0,
- onChildScroll: () => {}
- };
- return children(props);
-}
-
-module.exports = { WindowScroller };
diff --git a/server/sonar-web/babel.config.js b/server/sonar-web/babel.config.js
deleted file mode 100644
index 353be5de9f4..00000000000
--- a/server/sonar-web/babel.config.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2009-2024 SonarSource SA
- * All rights reserved
- * mailto:info AT sonarsource DOT com
- */
-
-const envPlugins = [];
-
-module.exports = {
- plugins: ['@emotion'],
- presets: [
- ['@babel/preset-react', { runtime: 'automatic' }],
- ['@babel/preset-typescript', { allowNamespaces: true }],
- ],
- env: {
- production: {
- plugins: envPlugins,
- },
- development: {
- plugins: envPlugins,
- },
- },
-};
diff --git a/server/sonar-web/config/jest/CSSStub.js b/server/sonar-web/config/jest/CSSStub.js
deleted file mode 100644
index 0ee64fb1837..00000000000
--- a/server/sonar-web/config/jest/CSSStub.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-module.exports = {};
diff --git a/server/sonar-web/config/jest/DataDogReporter.js b/server/sonar-web/config/jest/DataDogReporter.js
deleted file mode 100644
index 194a92ed009..00000000000
--- a/server/sonar-web/config/jest/DataDogReporter.js
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable no-console */
-const fs = require('fs');
-
-const ES_ITEM_CATEGORY = 'Validate-UT-Frontend';
-
-module.exports = class ElasticSearchReporter {
- constructor(globalConfig, options) {
- this.rootDir = globalConfig.rootDir;
- this.outputFilepath = options.outputFilepath;
- }
-
- stripFilePath(path) {
- return path.replace(this.rootDir, '');
- }
-
- writeToFile(data) {
- try {
- fs.writeFileSync(this.outputFilepath, JSON.stringify(data));
- } catch (e) {
- console.error(e);
- }
- }
-
- collectTestData(testClassResults) {
- const commit = process.env.GIT_SHA1;
- const branchName = process.env.GITHUB_BRANCH;
- const build = process.env.BUILD_NUMBER;
-
- const data = testClassResults.reduce((flattenedTestResults, testClassResult) => {
- const formattedTestResults = this.formatTestResults(
- testClassResult,
- commit,
- build,
- branchName,
- );
-
- return flattenedTestResults.concat(formattedTestResults);
- }, []);
-
- this.writeToFile(data);
- }
-
- formatTestResults(testClassResult, commit, build, branchName) {
- const timestamp = new Date(testClassResult.perfStats.start).toISOString();
- const testClass = this.stripFilePath(testClassResult.testFilePath);
-
- return testClassResult.testResults
- .filter((test) => test.status === 'failed')
- .map((testResult) => ({
- commit,
- branchName,
- build,
- category: ES_ITEM_CATEGORY,
- timestamp,
- testClass,
- testMethod: testResult.fullName,
- exceptionClass: '',
- exceptionMessage: testResult.failureMessages[0],
- exceptionLogs: testResult.failureMessages[0],
- }));
- }
-
- onRunComplete(contexts, { testResults }) {
- if (!this.outputFilepath) {
- throw new Error('option `outputFilepath` is undefined');
- }
-
- this.collectTestData(testResults);
- }
-};
diff --git a/server/sonar-web/config/jest/FileStub.js b/server/sonar-web/config/jest/FileStub.js
deleted file mode 100644
index 41bbfb86b1c..00000000000
--- a/server/sonar-web/config/jest/FileStub.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-module.exports = 'test-file-stub';
diff --git a/server/sonar-web/config/jest/GlobalSetup.js b/server/sonar-web/config/jest/GlobalSetup.js
deleted file mode 100644
index 4d6044b7464..00000000000
--- a/server/sonar-web/config/jest/GlobalSetup.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-module.exports = () => {
- process.env.TZ = 'utc';
-};
diff --git a/server/sonar-web/config/jest/JestPreprocess.js b/server/sonar-web/config/jest/JestPreprocess.js
deleted file mode 100644
index 11ec326b4d1..00000000000
--- a/server/sonar-web/config/jest/JestPreprocess.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-// These are merged with the default babel.config.js file, no need to repeat what's already in there
-const babelOptions = {
- presets: ['@babel/preset-env'],
- plugins: ['babel-plugin-twin', 'babel-plugin-macros'],
-};
-
-module.exports = require('babel-jest').default.createTransformer(babelOptions);
diff --git a/server/sonar-web/config/jest/SetupFailOnConsole.ts b/server/sonar-web/config/jest/SetupFailOnConsole.ts
deleted file mode 100644
index 251becf1978..00000000000
--- a/server/sonar-web/config/jest/SetupFailOnConsole.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import failOnConsole from 'jest-fail-on-console';
-const IGNORED_ERROR_MESSAGES: string[] = [
- // react-virtualized & react-draggable use `findDOMNode` which is deprecated
- 'findDOMNode is deprecated and will be removed in the next major release',
-
- // react-intl warning
- '[@formatjs/intl] "defaultRichTextElements" was specified but "message" was not pre-compiled.',
-];
-
-failOnConsole({
- silenceMessage: (message) => {
- return IGNORED_ERROR_MESSAGES.some((ignore_message) => message.includes(ignore_message));
- },
-});
diff --git a/server/sonar-web/config/jest/SetupJestAxe.ts b/server/sonar-web/config/jest/SetupJestAxe.ts
deleted file mode 100644
index 1c9eea5244f..00000000000
--- a/server/sonar-web/config/jest/SetupJestAxe.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { axe, toHaveNoViolations } from 'jest-axe';
-
-expect.extend({
- async toHaveNoA11yViolations(received: HTMLElement) {
- const result = await axe(received);
- return toHaveNoViolations.toHaveNoViolations(result);
- },
-});
diff --git a/server/sonar-web/config/jest/SetupReactTestingLibrary.ts b/server/sonar-web/config/jest/SetupReactTestingLibrary.ts
deleted file mode 100644
index 6101edc2143..00000000000
--- a/server/sonar-web/config/jest/SetupReactTestingLibrary.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import '@testing-library/jest-dom';
-import { configure, screen, waitFor } from '@testing-library/react';
-import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event';
-
-configure({
- asyncUtilTimeout: 6000,
-});
-
-expect.extend({
- async toHaveATooltipWithContent(received: any, content: string) {
- const user = userEvent.setup({ pointerEventsCheck: PointerEventsCheckLevel.Never });
-
- if (!(received instanceof Element)) {
- return {
- pass: false,
- message: () => `Received object is not an HTMLElement, and cannot have a tooltip`,
- };
- }
-
- await user.hover(received);
-
- const tooltip = await screen.findByRole('tooltip');
-
- const result = tooltip.textContent?.includes(content)
- ? {
- pass: true,
- message: () => `Tooltip content "${tooltip.textContent}" contains expected "${content}"`,
- }
- : {
- pass: false,
- message: () =>
- `Tooltip content "${tooltip.textContent}" does not contain expected "${content}"`,
- };
-
- await user.keyboard('{Escape}');
- await user.unhover(received);
-
- await waitFor(() => {
- expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
- });
-
- return result;
- },
- async toHaveAPopoverWithContent(received: any, content: string) {
- const user = userEvent.setup({ pointerEventsCheck: PointerEventsCheckLevel.Never });
-
- if (!(received instanceof Element)) {
- return {
- pass: false,
- message: () => `Received object is not an HTMLElement, and cannot have a tooltip`,
- };
- }
-
- await user.click(received);
-
- const popover = await screen.findByRole('dialog');
-
- const result = popover.textContent?.includes(content)
- ? {
- pass: true,
- message: () => `Tooltip content "${popover.textContent}" contains expected "${content}"`,
- }
- : {
- pass: false,
- message: () =>
- `Tooltip content "${popover.textContent}" does not contain expected "${content}"`,
- };
-
- await user.keyboard('{Escape}');
-
- await waitFor(() => {
- expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
- });
-
- return result;
- },
-});
diff --git a/server/sonar-web/config/jest/SetupTestEnvironment.ts b/server/sonar-web/config/jest/SetupTestEnvironment.ts
deleted file mode 100644
index 7038eb22109..00000000000
--- a/server/sonar-web/config/jest/SetupTestEnvironment.ts
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React from 'react';
-
-(window as any).React = React;
-
-const baseUrl = '';
-(window as any).baseUrl = baseUrl;
-
-jest.mock('../../src/main/js/helpers/l10n', () => ({
- ...jest.requireActual('../../src/main/js/helpers/l10n'),
- hasMessage: () => true,
- translate: (...keys: string[]) => keys.join('.'),
- translateWithParameters: (messageKey: string, ...parameters: Array<string | number>) =>
- [messageKey, ...parameters].join('.'),
-}));
-
-global.___loader = {
- enqueue: jest.fn(),
-};
-
-const MockObserver = {
- observe: jest.fn(),
- unobserve: jest.fn(),
- disconnect: jest.fn(),
-};
-
-const MockIntersectionObserverEntries = [{ isIntersecting: true }];
-
-(window as any).IntersectionObserver = jest.fn().mockImplementation((callback) => {
- callback(MockIntersectionObserverEntries, MockObserver);
- return MockObserver;
-});
-
-Element.prototype.scrollIntoView = () => {};
-
-const content = document.createElement('div');
-content.id = 'content';
-document.documentElement.appendChild(content);
-
-// ResizeObserver
-
-const MockResizeObserverEntries = [
- {
- contentRect: {
- width: 100,
- height: 200,
- },
- },
-];
-
-const MockResizeObserver = {
- observe: jest.fn(),
- unobserve: jest.fn(),
- disconnect: jest.fn(),
-};
-
-global.ResizeObserver = jest.fn().mockImplementation((callback) => {
- callback(MockResizeObserverEntries, MockResizeObserver);
- return MockResizeObserver;
-});
-
-// Copied from pollyfill.io
-// To be remove when upgrading jsdom https://github.com/jsdom/jsdom/releases/tag/22.1.0
-// jest-environment-jsdom to v30
-function number(v) {
- return v === undefined ? 0 : Number(v);
-}
-
-function different(u, v) {
- return u !== v && !(isNaN(u) && isNaN(v));
-}
-
-global.DOMRect = function DOMRect(xArg, yArg, wArg, hArg) {
- let x;
- let y;
- let width;
- let height;
- let left;
- let right;
- let top;
- let bottom;
-
- x = number(xArg);
- y = number(yArg);
- width = number(wArg);
- height = number(hArg);
-
- Object.defineProperties(this, {
- x: {
- get() {
- return x;
- },
- set(newX) {
- if (different(x, newX)) {
- x = newX;
- left = undefined;
- right = undefined;
- }
- },
- enumerable: true,
- },
- y: {
- get() {
- return y;
- },
- set(newY) {
- if (different(y, newY)) {
- y = newY;
- top = undefined;
- bottom = undefined;
- }
- },
- enumerable: true,
- },
- width: {
- get() {
- return width;
- },
- set(newWidth) {
- if (different(width, newWidth)) {
- width = newWidth;
- left = undefined;
- right = undefined;
- }
- },
- enumerable: true,
- },
- height: {
- get() {
- return height;
- },
- set(newHeight) {
- if (different(height, newHeight)) {
- height = newHeight;
- top = undefined;
- bottom = undefined;
- }
- },
- enumerable: true,
- },
- left: {
- get() {
- if (left === undefined) {
- left = x + Math.min(0, width);
- }
- return left;
- },
- enumerable: true,
- },
- right: {
- get() {
- if (right === undefined) {
- right = x + Math.max(0, width);
- }
- return right;
- },
- enumerable: true,
- },
- top: {
- get() {
- if (top === undefined) {
- top = y + Math.min(0, height);
- }
- return top;
- },
- enumerable: true,
- },
- bottom: {
- get() {
- if (bottom === undefined) {
- bottom = y + Math.max(0, height);
- }
- return bottom;
- },
- enumerable: true,
- },
- });
-};
diff --git a/server/sonar-web/config/jest/SetupTheme.js b/server/sonar-web/config/jest/SetupTheme.js
deleted file mode 100644
index 601040da4bf..00000000000
--- a/server/sonar-web/config/jest/SetupTheme.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ThemeContext } from '@emotion/react';
-// WARNING! Using '~design-system' below would break tests in the src/main/js/design-system folder!
-import { lightTheme } from '../../src/main/js/design-system/theme/light';
-
-// Hack : override the default value of the context used for theme by emotion
-// This allows tests to get the theme value without specifiying a theme provider
-ThemeContext['_currentValue'] = lightTheme;
-ThemeContext['_currentValue2'] = lightTheme;
diff --git a/server/sonar-web/config/jest/jest.polyfills.js b/server/sonar-web/config/jest/jest.polyfills.js
deleted file mode 100644
index 6d9764ff447..00000000000
--- a/server/sonar-web/config/jest/jest.polyfills.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import 'whatwg-fetch';
-
-// Polyfills for Jest, because we need these for msw but jsdom doesn't provide them
-import { ReadableStream, TextDecoder, TextEncoder } from 'node:util';
-
-Object.defineProperties(globalThis, {
- TextDecoder: { value: TextDecoder },
- TextEncoder: { value: TextEncoder },
- ReadableStream: { value: ReadableStream },
-});
diff --git a/server/sonar-web/config/license.ts b/server/sonar-web/config/license.ts
deleted file mode 100644
index 066d4e4cad0..00000000000
--- a/server/sonar-web/config/license.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Dependency } from 'rollup-plugin-license';
-
-// To be always synced with https://saas-eu.whitesourcesoftware.com/Wss/WSS.html#!policyDetails;policy=3131;org=318388
-// Below is the list of approved front-end licenses extracted from Mend
-export const ALLOWED_LICENSES = [
- '(MPL-2.0 OR Apache-2.0)', // Multiple licenses. Added specifically for dompurify as we have ignored this in Mend
- '0BSD',
- 'Apache-2.0',
- 'BSD-2-Clause',
- 'BSD-3-Clause',
- 'ISC',
- 'LGPL-3.0',
- 'MIT',
-];
-
-// Just for Sprig currently, it has an Apache-2 license that isn't correctly parsed by the plugin
-export const ALLOWED_LICENSE_TEXT = ['http://www.apache.org/licenses/LICENSE-2.0'];
-
-// Generates license information with necessary details.
-// A package which has a valid license that the plugin is unable read will default to MIT
-export const generateLicenseText = (dependency: Dependency) => {
- const { author, homepage, license, licenseText, name, repository, version } = dependency;
- const lines: string[] = [];
-
- lines.push(`Name: ${name}`);
- lines.push(`Version: ${version}`);
-
- if (license) {
- lines.push(`License: ${license}`);
- }
-
- if (typeof repository === 'string') {
- lines.push(`Repository: ${repository}`);
- } else if (repository?.url) {
- lines.push(`Repository: ${repository.url}`);
- } else if (homepage) {
- lines.push(`Homepage: ${homepage}`);
- }
-
- if (author) {
- lines.push(`Author: ${author.text()}`);
- }
-
- if (licenseText) {
- lines.push(`License Copyright:`);
- lines.push(`${licenseText}`);
- }
-
- return lines.join('\n');
-};
diff --git a/server/sonar-web/config/vite-dev-server-html-plugin.mjs b/server/sonar-web/config/vite-dev-server-html-plugin.mjs
deleted file mode 100644
index e5c690583e3..00000000000
--- a/server/sonar-web/config/vite-dev-server-html-plugin.mjs
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export const viteDevServerHtmlPlugin = () => {
- return {
- name: 'html-transform',
- apply: 'serve',
- transformIndexHtml(html) {
- return html
- .replace(/WEB_CONTEXT/g, '')
- .replace(/%SERVER_STATUS%/g, 'UP')
- .replace(/%INSTANCE%/g, 'SonarQube')
- .replace(/%OFFICIAL%/g, 'true');
- },
- };
-};
diff --git a/server/sonar-web/config/vite-dev-server-l10n-plugin.mjs b/server/sonar-web/config/vite-dev-server-l10n-plugin.mjs
deleted file mode 100644
index 4e53c09ded8..00000000000
--- a/server/sonar-web/config/vite-dev-server-l10n-plugin.mjs
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import fs from 'node:fs';
-import path from 'node:path';
-import { promisify } from 'node:util';
-
-const readFileAsync = promisify(fs.readFile);
-
-const l10nFilePath = '../../../sonar-core/src/main/resources/org/sonar/l10n/core.properties';
-
-const extensionsL10nFilepaths = [
- '../../../private/core-extension-enterprise-server/src/main/resources/org/sonar/l10n/governance.properties',
- '../../../private/core-extension-license/src/main/resources/org/sonar/l10n/license.properties',
- '../../../private/core-extension-developer-server/src/main/resources/org/sonar/l10n/developer-server.properties',
- '../../../private/core-extension-securityreport/src/main/resources/org/sonar/l10n/securityreport.properties',
-];
-
-const STATUS_OK = 200;
-const STATUS_ERROR = 500;
-
-function getFileMessage(filename) {
- return readFileAsync(path.resolve(__dirname, filename), 'utf-8').then(
- (content) => {
- const messages = {};
- const lines = content.split('\n');
- lines.forEach((line) => {
- const parts = line.split('=');
- if (parts.length > 1) {
- messages[parts[0]] = parts.slice(1).join('=');
- }
- });
- return messages;
- },
- () => ({}),
- );
-}
-
-function getMessages() {
- return Promise.all(
- [l10nFilePath, ...extensionsL10nFilepaths].map((filename) => getFileMessage(filename)),
- ).then((filesMessages) => filesMessages.reduce((acc, messages) => ({ ...acc, ...messages }), {}));
-}
-
-// this is a custom l10n-dev-server when proxying locally against another environment so that
-// we don't need to rebuild the server when changing the l10n files
-export const viteDevServerL10nPlugin = () => {
- return {
- name: 'l10n-dev-server',
- apply: 'serve',
- configureServer(server) {
- const app = server.middlewares;
- app.use('/api/l10n', (_req, res) => {
- getMessages()
- .then((messages) => {
- res.writeHead(STATUS_OK, { 'Content-Type': 'application/json' });
- res.end(JSON.stringify({ effectiveLocale: 'en', messages }));
- })
- .catch((e) => {
- console.error(e);
- res.writeHead(STATUS_ERROR);
- res.end(e);
- });
- });
- },
- };
-};
diff --git a/server/sonar-web/eslint-local-rules/__tests__/convert-class-to-function-component-test.js b/server/sonar-web/eslint-local-rules/__tests__/convert-class-to-function-component-test.js
deleted file mode 100644
index 8d5207dacc9..00000000000
--- a/server/sonar-web/eslint-local-rules/__tests__/convert-class-to-function-component-test.js
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-const { RuleTester } = require('eslint');
-const convertClassToFunctionComponent = require('../convert-class-to-function-component');
-
-const ruleTester = new RuleTester({
- parser: require.resolve('@typescript-eslint/parser'),
- parserOptions: {
- ecmaVersion: 2021,
- sourceType: 'module',
- },
-});
-
-ruleTester.run('convert-class-to-function-component', convertClassToFunctionComponent, {
- valid: [
- {
- code: `class ConditionsTable extends React.PureComponent {
- componentDidMount() {}
- render() {}
-}`,
- },
- {
- code: `class ConditionsTable extends React.PureComponent {
- handleClick = () => {}
- render() {}
-}`,
- },
- ],
- invalid: [
- {
- code: `class ConditionsTable extends React.PureComponent {
- render() {}
-}`,
- errors: [{ messageId: 'convertClassToFunctionComponent' }],
- },
- {
- code: `class ConditionsTable extends React.PureComponent {
- ref = null;
- render() {}
-}`,
- errors: [{ messageId: 'convertClassToFunctionComponent' }],
- },
- ],
-});
diff --git a/server/sonar-web/eslint-local-rules/__tests__/no-api-imports-test.js b/server/sonar-web/eslint-local-rules/__tests__/no-api-imports-test.js
deleted file mode 100644
index fc52557fc88..00000000000
--- a/server/sonar-web/eslint-local-rules/__tests__/no-api-imports-test.js
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-const { RuleTester } = require('eslint');
-const noApiImports = require('../no-api-imports');
-
-const ruleTester = new RuleTester({
- parserOptions: {
- ecmaFeatures: {
- jsx: true,
- },
- },
- parser: require.resolve('@typescript-eslint/parser'),
-});
-
-ruleTester.run('no-api-imports', noApiImports, {
- valid: [
- {
- code: `
- import test from 'apitest/';
- test();
- `,
- },
- {
- code: `
- import { test } from '../../helpers';
- test();
- `,
- },
- {
- code: `
- import { api } from '../../helpers';
- api();
- `,
- },
- {
- code: `
- const test = () => {};
- test();
- `,
- },
- ],
- invalid: [
- {
- code: `
- import {test as testRenamed} from './src/api/test';
- testRenamed();
- `,
- errors: [{ messageId: 'noApiImports' }],
- },
- {
- code: `
- import { test } from '../../api/test';
- test();
- `,
- errors: [{ messageId: 'noApiImports' }],
- },
- {
- code: `
- import test from '../../api/test';
- test();
- `,
- errors: [{ messageId: 'noApiImports' }],
- },
- ],
-});
diff --git a/server/sonar-web/eslint-local-rules/__tests__/no-conditional-rendering-of-spinner-test.js b/server/sonar-web/eslint-local-rules/__tests__/no-conditional-rendering-of-spinner-test.js
deleted file mode 100644
index bcd456e9f98..00000000000
--- a/server/sonar-web/eslint-local-rules/__tests__/no-conditional-rendering-of-spinner-test.js
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-const { RuleTester } = require('eslint');
-const noConditionalRenderingOfSpinner = require('../no-conditional-rendering-of-spinner');
-
-const ruleTester = new RuleTester({
- parser: require.resolve('@typescript-eslint/parser'),
- parserOptions: {
- ecmaFeatures: {
- jsx: true,
- },
- },
-});
-
-ruleTester.run('no-conditional-rendering-of-spinner', noConditionalRenderingOfSpinner, {
- valid: [
- {
- code: `function MyCompontent({ loading }) {
- return <>
- <Spinner loading={loading} />
- </>
-}`,
- },
- ],
- invalid: [
- {
- code: `function MyCompontent({ loading }) {
- return <>
- {loading && <Spinner />}
- </>
-}`,
- errors: [{ messageId: 'noConditionalRenderingOfSpinner' }],
- },
- {
- code: `function MyComponent({ loading }) {
- return <>
- {loading ? <Spinner /> : <div />}
- </>
-}`,
- errors: [{ messageId: 'noConditionalRenderingOfSpinner' }],
- },
- {
- code: `function MyCompontent({ loaded }) {
- return <>
- {loaded ? <div /> : <Spinner />}
- </>
-}`,
- errors: [{ messageId: 'noConditionalRenderingOfSpinner' }],
- },
- ],
-});
diff --git a/server/sonar-web/eslint-local-rules/__tests__/no-implicit-coercion-test.js b/server/sonar-web/eslint-local-rules/__tests__/no-implicit-coercion-test.js
deleted file mode 100644
index da9990d7aad..00000000000
--- a/server/sonar-web/eslint-local-rules/__tests__/no-implicit-coercion-test.js
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { RuleTester } from '@typescript-eslint/rule-tester';
-import noImplicitCoercion from '../no-implicit-coercion';
-
-const ruleTester = new RuleTester({
- parserOptions: {
- project: './tsconfig.json',
- tsconfigRootDir: __dirname + '/../test-config',
- ecmaFeatures: {
- jsx: true,
- },
- },
- parser: require.resolve('@typescript-eslint/parser'),
-});
-
-ruleTester.run('no-implicit-coercion', noImplicitCoercion, {
- valid: [
- {
- code: `
- function test(value?: number) {
- if (value === undefined) {
- return true;
- }
- }`,
- },
- {
- code: `
- function test(value?: number) {
- if (Boolean(value)) {
- return true;
- }
- }`,
- },
- {
- code: `
- function test(value?: {}) {
- if (!value) {
- return true;
- }
- }`,
- },
- {
- code: `
- function test(value: string) {
- if (value !== '') {
- return true;
- }
- }`,
- },
- {
- code: `
- function test(value?: number | {}) {
- return value !== undefined && value.toString();
- }`,
- },
- {
- code: `
- function test(value?: number) {
- return value ?? 100;
- }`,
- },
- {
- code: `
- interface Props {
- test?: number;
- }
- function Test(props: Props) {
- if (props.test !== undefined) {
- return props.test * 10;
- }
- return 100;
- }`,
- },
- {
- code: `
- interface Props {
- test?: number;
- check: boolean
- }
- function Test(props: Props) {
- if (props.check && props.test !== undefined) {
- return props.test * 10;
- }
- return 100;
- }`,
- },
- {
- code: `
- interface Props {
- test?: React.ReactNode;
- }
- function Test(props: Props) {
- if (props.test) {
- return props.test;
- }
- return null;
- }`,
- },
- {
- code: `
- interface Props {
- test?: number;
- }
- function Test(props: Props) {
- return (
- <div>
- {props.test !== undefined && <span>{props.test}</span>}
- {props.test === undefined && <span>100</span>}
- </div>
- );
- }`,
- },
- ],
- invalid: [
- {
- code: `
- function test(value?: number) {
- if (!value) {
- return true;
- }
- }`,
- errors: [{ messageId: 'noImplicitCoercion' }],
- },
- {
- code: `
- function test(value?: number) {
- if (value) {
- return true;
- }
- }`,
- errors: [{ messageId: 'noImplicitCoercion' }],
- },
- {
- code: `
- function test(value: string) {
- if (value) {
- return true;
- }
- }`,
- errors: [{ messageId: 'noImplicitCoercion' }],
- },
- {
- code: `
- function test(value?: number) {
- return value && value > -1;
- }`,
- errors: [{ messageId: 'noImplicitCoercion' }],
- },
- {
- code: `
- function test(value?: string | {}) {
- if (value) {
- return 1;
- }
- }`,
- errors: [{ messageId: 'noImplicitCoercion' }],
- },
- {
- code: `
- function test(value?: number) {
- return value || 100;
- }`,
- errors: [{ messageId: 'noImplicitCoercion' }],
- },
- {
- code: `
- interface Props {
- test?: number | {};
- }
- function Test(props: Props) {
- return props.test && props.test.toString();
- }`,
- errors: [{ messageId: 'noImplicitCoercion' }],
- },
- {
- code: `
- interface Props {
- test?: number;
- }
- function Test(props: Props) {
- if (props.test) {
- return props.test * 10;
- }
- return 100;
- }`,
- errors: [{ messageId: 'noImplicitCoercion' }],
- },
- {
- code: `
- interface Props {
- test?: number;
- check: boolean
- }
- function Test(props: Props) {
- if (props.check && props.test) {
- return props.test * 10;
- }
- return 100;
- }`,
- errors: [{ messageId: 'noImplicitCoercion' }],
- },
- {
- code: `
- interface Props {
- test?: number;
- }
- function Test(props: Props) {
- return (
- <div>
- {props.test && <span>{props.test}</span>}
- {!props.test && <span>100</span>}
- </div>
- );
- }`,
- errors: [{ messageId: 'noImplicitCoercion' }, { messageId: 'noImplicitCoercion' }],
- },
- ],
-});
diff --git a/server/sonar-web/eslint-local-rules/__tests__/no-within-test.js b/server/sonar-web/eslint-local-rules/__tests__/no-within-test.js
deleted file mode 100644
index 34f446b077a..00000000000
--- a/server/sonar-web/eslint-local-rules/__tests__/no-within-test.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-const { RuleTester } = require('eslint');
-const noWithin = require('../no-within');
-
-const ruleTester = new RuleTester({
- parserOptions: {
- ecmaFeatures: {
- jsx: true,
- },
- },
- parser: require.resolve('@typescript-eslint/parser'),
-});
-
-ruleTester.run('no-within', noWithin, {
- valid: [
- {
- code: `
- import {within} from '@testing-library/react';
- test();
- `,
- },
- {
- code: `
- within();
- `,
- },
- ],
- invalid: [
- {
- code: `
- import {within} from '@testing-library/react';
-
- within();
- `,
- errors: [{ messageId: 'noWithin' }],
- },
- ],
-});
diff --git a/server/sonar-web/eslint-local-rules/__tests__/use-await-expect-async-matcher-test.js b/server/sonar-web/eslint-local-rules/__tests__/use-await-expect-async-matcher-test.js
deleted file mode 100644
index 103f3e86be3..00000000000
--- a/server/sonar-web/eslint-local-rules/__tests__/use-await-expect-async-matcher-test.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-const { RuleTester } = require('eslint');
-const useJestMocked = require('../use-await-expect-async-matcher');
-
-const ruleTester = new RuleTester({
- parser: require.resolve('@typescript-eslint/parser'),
-});
-
-ruleTester.run('use-await-expect-tohaveatooltipwithcontent', useJestMocked, {
- valid: [
- {
- code: `await expect(node).toHaveATooltipWithContent("Help text");`,
- },
- ],
- invalid: [
- {
- code: `expect(node).toHaveATooltipWithContent("Help text");`,
- errors: [
- {
- message:
- 'expect.toHaveATooltipWithContent() is asynchronous; you must prefix expect() with await',
- },
- ],
- output: `await expect(node).toHaveATooltipWithContent("Help text");`,
- },
- ],
-});
diff --git a/server/sonar-web/eslint-local-rules/__tests__/use-jest-mocked-test.js b/server/sonar-web/eslint-local-rules/__tests__/use-jest-mocked-test.js
deleted file mode 100644
index cef109d1bc2..00000000000
--- a/server/sonar-web/eslint-local-rules/__tests__/use-jest-mocked-test.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-const { RuleTester } = require('eslint');
-const useJestMocked = require('../use-jest-mocked');
-
-const ruleTester = new RuleTester({
- parser: require.resolve('@typescript-eslint/parser'),
-});
-
-ruleTester.run('use-jest-mocked', useJestMocked, {
- valid: [
- {
- code: 'jest.mocked(doSomething)',
- },
- ],
- invalid: [
- {
- code: '(doSomething as jest.Mock).mockImplementation()',
- errors: [{ messageId: 'useJestMocked' }],
- },
- ],
-});
diff --git a/server/sonar-web/eslint-local-rules/convert-class-to-function-component.js b/server/sonar-web/eslint-local-rules/convert-class-to-function-component.js
deleted file mode 100644
index a32c16c236f..00000000000
--- a/server/sonar-web/eslint-local-rules/convert-class-to-function-component.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-module.exports = {
- meta: {
- messages: {
- convertClassToFunctionComponent:
- 'A class component only containing a render() method should be converted to a function component',
- },
- },
- create(context) {
- return {
- ClassDeclaration(node) {
- const methods = node.body.body.filter(
- (n) =>
- n.type === 'MethodDefinition' ||
- (n.type === 'PropertyDefinition' &&
- n.value &&
- n.value.type === 'ArrowFunctionExpression'),
- );
- if (methods.length === 1 && methods[0].key.name === 'render') {
- context.report({ node, messageId: 'convertClassToFunctionComponent' });
- }
- },
- };
- },
-};
diff --git a/server/sonar-web/eslint-local-rules/index.js b/server/sonar-web/eslint-local-rules/index.js
deleted file mode 100644
index 625bc309eec..00000000000
--- a/server/sonar-web/eslint-local-rules/index.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-module.exports = {
- 'use-jest-mocked': require('./use-jest-mocked'),
- 'convert-class-to-function-component': require('./convert-class-to-function-component'),
- 'no-conditional-rendering-of-spinner': require('./no-conditional-rendering-of-spinner'),
- 'use-visibility-enum': require('./use-visibility-enum'),
- 'use-componentqualifier-enum': require('./use-componentqualifier-enum'),
- 'use-metrickey-enum': require('./use-metrickey-enum'),
- 'use-metrictype-enum': require('./use-metrictype-enum'),
- 'use-await-expect-async-matcher': require('./use-await-expect-async-matcher'),
- 'no-implicit-coercion': require('./no-implicit-coercion'),
- 'no-api-imports': require('./no-api-imports'),
- 'no-within': require('./no-within'),
-};
diff --git a/server/sonar-web/eslint-local-rules/lib/__tests__/use-enum-test.js b/server/sonar-web/eslint-local-rules/lib/__tests__/use-enum-test.js
deleted file mode 100644
index 3d01319babb..00000000000
--- a/server/sonar-web/eslint-local-rules/lib/__tests__/use-enum-test.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-const { RuleTester } = require('eslint');
-const { useEnum } = require('../use-enum');
-const useSomeEnum = useEnum(['Val1', 'Val2', 'Val3'], 'SomeEnum');
-
-const ruleTester = new RuleTester({
- parser: require.resolve('@typescript-eslint/parser'),
-});
-
-ruleTester.run('use-some-enum', useSomeEnum, {
- valid: [
- {
- code: '{ qualifier: SomeEnum.FirstValue };',
- },
- {
- code: 'varName === SomeEnum.SecondValue',
- },
- {
- code: `enum SomeEnum {
- FirstValue = 'Val1',
- SecondValue = 'Val2',
- ThirdValue = 'Val3',
-}`,
- },
- ],
- invalid: [
- {
- code: '{ value: "Val1" };',
- errors: [{ messageId: 'useSomeEnumEnum' }],
- },
- {
- code: "varName === 'Val2'",
- errors: [{ messageId: 'useSomeEnumEnum' }],
- },
- ],
-});
diff --git a/server/sonar-web/eslint-local-rules/lib/use-enum.js b/server/sonar-web/eslint-local-rules/lib/use-enum.js
deleted file mode 100644
index 33e75a7c34a..00000000000
--- a/server/sonar-web/eslint-local-rules/lib/use-enum.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-module.exports = {
- useEnum(values, name, help) {
- return {
- meta: {
- messages: {
- [`use${name}Enum`]: `Hard-coded strings ${
- help ? help + ' ' : ''
- }are not allowed; use the ${name} enum instead`,
- },
- },
- create(context) {
- return {
- Literal(node) {
- if (node.parent.type !== 'TSEnumMember' && values.includes(node.value)) {
- context.report({ node, messageId: `use${name}Enum` });
- }
- },
- };
- },
- };
- },
-};
diff --git a/server/sonar-web/eslint-local-rules/no-api-imports.js b/server/sonar-web/eslint-local-rules/no-api-imports.js
deleted file mode 100644
index 007276ed867..00000000000
--- a/server/sonar-web/eslint-local-rules/no-api-imports.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-// no-import-from-specific-folder.js
-
-module.exports = {
- meta: {
- type: 'problem',
- docs: {
- description: 'Warn against importing functions from a "api" folder',
- category: 'Best Practices',
- },
- messages: {
- noApiImports:
- 'Check if an existing react-query retrieves this data. Use it instead of importing the API function directly.',
- },
- },
- create: function (context) {
- const fnNames = [];
- const currentFilePath = context.getFilename();
-
- if (
- ['queries', 'mocks', '__tests__'].some((path) => currentFilePath.split('/').includes(path))
- ) {
- return {};
- }
-
- return {
- ImportDeclaration: function (node) {
- const importPath = node.source.value;
-
- if (importPath.split('/').includes('api')) {
- fnNames.push(...node.specifiers.map((specifier) => specifier.local.name));
- }
- },
- CallExpression: function (node) {
- if (fnNames.includes(node.callee.name)) {
- context.report({
- node: node.callee,
- messageId: 'noApiImports',
- });
- }
- },
- };
- },
-};
diff --git a/server/sonar-web/eslint-local-rules/no-conditional-rendering-of-spinner.js b/server/sonar-web/eslint-local-rules/no-conditional-rendering-of-spinner.js
deleted file mode 100644
index 859100d8742..00000000000
--- a/server/sonar-web/eslint-local-rules/no-conditional-rendering-of-spinner.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-module.exports = {
- meta: {
- messages: {
- noConditionalRenderingOfSpinner:
- 'For accessibility reasons, you should not conditionally render a <Spinner />. Always render it, and pass a loading prop instead.',
- },
- },
- create(context) {
- return {
- JSXExpressionContainer(node) {
- switch (node.expression.type) {
- case 'LogicalExpression':
- const { right } = node.expression;
- if (isSpinnerComponent(right)) {
- context.report({ node, messageId: 'noConditionalRenderingOfSpinner' });
- }
- break;
-
- case 'ConditionalExpression':
- const { consequent, alternate } = node.expression;
- if (isSpinnerComponent(consequent)) {
- context.report({ node, messageId: 'noConditionalRenderingOfSpinner' });
- }
- if (isSpinnerComponent(alternate)) {
- context.report({ node, messageId: 'noConditionalRenderingOfSpinner' });
- }
- break;
- }
- },
- };
- },
-};
-
-function isSpinnerComponent(element) {
- return (
- element.type === 'JSXElement' &&
- element.openingElement &&
- element.openingElement.name.name === 'Spinner'
- );
-}
diff --git a/server/sonar-web/eslint-local-rules/no-implicit-coercion.js b/server/sonar-web/eslint-local-rules/no-implicit-coercion.js
deleted file mode 100644
index 68875f00c45..00000000000
--- a/server/sonar-web/eslint-local-rules/no-implicit-coercion.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-module.exports = {
- meta: {
- type: 'suggestion',
- docs: {
- description:
- 'Enforce using explicit comparison instead of implicit coercion for certain variable types',
- category: 'Best Practices',
- recommended: true,
- },
- messages: {
- noImplicitCoercion:
- 'Use explicit comparison instead of implicit coercion for strings and numbers.',
- },
- },
- create(context) {
- return {
- UnaryExpression: (node) => {
- const { argument, operator } = node;
-
- if (operator === '!') {
- checkImplicitCoercion(context, argument);
- }
- },
- LogicalExpression: (node) => {
- const { left, operator } = node;
- if (operator === '??') {
- return;
- }
- if (isVariableOrObjectField(left)) {
- checkImplicitCoercion(context, left);
- }
- },
- IfStatement: (node) => {
- const { test } = node;
- checkImplicitCoercion(context, test);
- },
- };
- },
-};
-
-const isForbiddenType = (type) =>
- type.intrinsicName === 'number' || type.intrinsicName === 'string';
-
-const isVariableOrObjectField = (node) =>
- node.type === 'Identifier' || node.type === 'MemberExpression';
-
-function checkImplicitCoercion(context, argument) {
- const tsNodeMap = context.parserServices.esTreeNodeToTSNodeMap;
- const typeChecker = context.parserServices?.program?.getTypeChecker();
- const type = typeChecker.getTypeAtLocation(tsNodeMap.get(argument));
- if (type.aliasSymbol && type.aliasSymbol.name === 'ReactNode') {
- return;
- }
- if (type.isUnion() ? type.types.some(isForbiddenType) : isForbiddenType(type)) {
- context.report({
- node: argument,
- messageId: 'noImplicitCoercion',
- });
- }
-}
diff --git a/server/sonar-web/eslint-local-rules/no-within.js b/server/sonar-web/eslint-local-rules/no-within.js
deleted file mode 100644
index efff8b0d7c8..00000000000
--- a/server/sonar-web/eslint-local-rules/no-within.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-// For now lets enable it on this extension
-// once we have made the refactoring we can add it to sonar-web and all other extension.
-module.exports = {
- meta: {
- type: 'problem',
- docs: {
- description: 'Prevent unsing within from testing library',
- category: 'Best Practices',
- },
- messages: {
- noWithin: "Don't use within as it may hide DOM update. Prefer using chain selector.",
- },
- },
- // eslint-disable-next-line object-shorthand
- create: function (context) {
- const fnNames = [];
- const currentFilePath = context.getFilename();
- const sourceCode = context.sourceCode;
- return {
- // eslint-disable-next-line object-shorthand
- CallExpression: function (node) {
- if (node.callee.name === 'within') {
- let scope = sourceCode.getScope(node);
- while (node.callee.name && scope && scope.set.get(node.callee.name) === undefined) {
- scope = scope.upper;
- }
-
- if (node.callee.name && scope) {
- let variable = scope.set.get(node.callee.name);
- if (variable.defs[0] && variable.defs[0].parent.source) {
- const importPath = variable.defs[0].parent.source.value;
- if (importPath.startsWith('@testing-library')) {
- context.report({
- node: node.callee,
- messageId: 'noWithin',
- });
- }
- }
- }
- }
- },
- };
- },
-};
diff --git a/server/sonar-web/eslint-local-rules/test-config/react.tsx b/server/sonar-web/eslint-local-rules/test-config/react.tsx
deleted file mode 100644
index 5e9942f478f..00000000000
--- a/server/sonar-web/eslint-local-rules/test-config/react.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
diff --git a/server/sonar-web/eslint-local-rules/test-config/tsconfig.json b/server/sonar-web/eslint-local-rules/test-config/tsconfig.json
deleted file mode 100644
index 988ec11e634..00000000000
--- a/server/sonar-web/eslint-local-rules/test-config/tsconfig.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "extends": "../../tsconfig",
- "include": [
- "./react.tsx"
- ]
-} \ No newline at end of file
diff --git a/server/sonar-web/eslint-local-rules/use-await-expect-async-matcher.js b/server/sonar-web/eslint-local-rules/use-await-expect-async-matcher.js
deleted file mode 100644
index 48977d9c3e9..00000000000
--- a/server/sonar-web/eslint-local-rules/use-await-expect-async-matcher.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-module.exports = {
- meta: {
- fixable: 'code',
- },
- create(context) {
- return {
- Identifier(node) {
- if (
- ['toHaveATooltipWithContent', 'toHaveNoA11yViolations'].includes(node.name) &&
- node.parent?.parent?.parent?.type !== 'AwaitExpression'
- ) {
- context.report({
- node: node.parent?.parent?.parent,
- message: `expect.${node.name}() is asynchronous; you must prefix expect() with await`,
- fix(fixer) {
- return fixer.insertTextBefore(node.parent?.parent?.parent, 'await ');
- },
- });
- }
- },
- };
- },
-};
diff --git a/server/sonar-web/eslint-local-rules/use-componentqualifier-enum.js b/server/sonar-web/eslint-local-rules/use-componentqualifier-enum.js
deleted file mode 100644
index 1c45ae9916a..00000000000
--- a/server/sonar-web/eslint-local-rules/use-componentqualifier-enum.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-const { useEnum } = require('./lib/use-enum');
-module.exports = useEnum(['APP', 'DIR', 'FIL', 'VW', 'TRK', 'SVW', 'UTS'], 'ComponentQualifier');
diff --git a/server/sonar-web/eslint-local-rules/use-jest-mocked.js b/server/sonar-web/eslint-local-rules/use-jest-mocked.js
deleted file mode 100644
index f57fc3f05d2..00000000000
--- a/server/sonar-web/eslint-local-rules/use-jest-mocked.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-module.exports = {
- meta: {
- messages: {
- useJestMocked: 'Prefer using jest.mocked(func) instead of (func as jest.Mock)',
- },
- },
- create(context) {
- return {
- TSAsExpression(node) {
- if (node.typeAnnotation.typeName) {
- const { left, right } = node.typeAnnotation.typeName;
- if (left && left.name === 'jest' && right && right.name === 'Mock') {
- context.report({ node, messageId: 'useJestMocked' });
- }
- }
- },
- };
- },
-};
diff --git a/server/sonar-web/eslint-local-rules/use-metrickey-enum.js b/server/sonar-web/eslint-local-rules/use-metrickey-enum.js
deleted file mode 100644
index 94cd374b33f..00000000000
--- a/server/sonar-web/eslint-local-rules/use-metrickey-enum.js
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-const { useEnum } = require('./lib/use-enum');
-module.exports = useEnum(
- [
- 'alert_status',
- 'blocker_violations',
- 'branch_coverage',
- 'bugs',
- 'burned_budget',
- 'business_value',
- 'classes',
- 'code_smells',
- 'cognitive_complexity',
- 'comment_lines',
- 'comment_lines_data',
- 'comment_lines_density',
- 'complexity',
- 'conditions_to_cover',
- 'confirmed_issues',
- 'coverage',
- 'critical_violations',
- 'development_cost',
- 'directories',
- 'duplicated_blocks',
- 'duplicated_files',
- 'duplicated_lines',
- 'duplicated_lines_density',
- 'duplications_data',
- 'effort_to_reach_maintainability_rating_a',
- 'executable_lines_data',
- 'false_positive_issues',
- 'filename_size',
- 'filename_size_rating',
- 'files',
- 'functions',
- 'generated_lines',
- 'generated_ncloc',
- 'info_violations',
- 'last_change_on_maintainability_rating',
- 'last_change_on_releasability_rating',
- 'last_change_on_reliability_rating',
- 'last_change_on_security_rating',
- 'last_change_on_security_review_rating',
- 'last_commit_date',
- 'leak_projects',
- 'line_coverage',
- 'lines',
- 'lines_to_cover',
- 'maintainability_rating_effort',
- 'major_violations',
- 'minor_violations',
- 'ncloc',
- 'ncloc_data',
- 'ncloc_language_distribution',
- 'new_blocker_violations',
- 'new_branch_coverage',
- 'new_bugs',
- 'new_code_smells',
- 'new_conditions_to_cover',
- 'new_coverage',
- 'new_critical_violations',
- 'new_development_cost',
- 'new_duplicated_blocks',
- 'new_duplicated_lines',
- 'new_duplicated_lines_density',
- 'new_info_violations',
- 'new_line_coverage',
- 'new_lines',
- 'new_lines_to_cover',
- 'new_maintainability_rating',
- 'new_major_violations',
- 'new_minor_violations',
- 'new_reliability_rating',
- 'new_reliability_remediation_effort',
- 'new_security_hotspots',
- 'new_security_hotspots_reviewed',
- 'new_security_rating',
- 'new_security_remediation_effort',
- 'new_security_review_rating',
- 'new_sqale_debt_ratio',
- 'new_technical_debt',
- 'new_uncovered_conditions',
- 'new_uncovered_lines',
- 'new_violations',
- 'new_vulnerabilities',
- 'open_issues',
- 'projects',
- 'public_api',
- 'public_documented_api_density',
- 'public_undocumented_api',
- 'quality_gate_details',
- 'quality_profiles',
- 'releasability_effort',
- 'releasability_rating',
- 'reliability_rating',
- 'reliability_rating_effort',
- 'reliability_remediation_effort',
- 'reopened_issues',
- 'security_hotspots',
- 'security_hotspots_reviewed',
- 'security_rating',
- 'security_rating_effort',
- 'security_remediation_effort',
- 'security_review_rating',
- 'security_review_rating_effort',
- 'skipped_tests',
- 'sonarjava_feedback',
- 'sqale_debt_ratio',
- 'sqale_index',
- 'sqale_rating',
- 'statements',
- 'team_at_sonarsource',
- 'team_size',
- 'test_errors',
- 'test_execution_time',
- 'test_failures',
- 'test_success_density',
- 'tests',
- 'uncovered_conditions',
- 'uncovered_lines',
- 'violations',
- 'vulnerabilities',
- 'wont_fix_issues',
- ],
- 'MetricKey',
- 'representing metric keys',
-);
diff --git a/server/sonar-web/eslint-local-rules/use-metrictype-enum.js b/server/sonar-web/eslint-local-rules/use-metrictype-enum.js
deleted file mode 100644
index be8d18e1fd4..00000000000
--- a/server/sonar-web/eslint-local-rules/use-metrictype-enum.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-const { useEnum } = require('./lib/use-enum');
-module.exports = useEnum(
- ['RATING', 'PERCENT', 'INT', 'LEVEL', 'SHORT_INT', 'SHORT_WORK_DUR', 'DATA'],
- 'MetricType',
- 'representing metric types',
-);
diff --git a/server/sonar-web/eslint-local-rules/use-visibility-enum.js b/server/sonar-web/eslint-local-rules/use-visibility-enum.js
deleted file mode 100644
index 797b6a24e2b..00000000000
--- a/server/sonar-web/eslint-local-rules/use-visibility-enum.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-const { useEnum } = require('./lib/use-enum');
-module.exports = useEnum(['public', 'private'], 'Visibility');
diff --git a/server/sonar-web/jest.config.js b/server/sonar-web/jest.config.js
deleted file mode 100644
index 3099d29334e..00000000000
--- a/server/sonar-web/jest.config.js
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-const esModules = [
- 'd3',
- 'd3-array',
- 'd3-scale',
- 'highlightjs-',
- '@sonarsource/echoes-react',
- // Jupyterlab
- '@jupyterlab/nbformat',
- // React markdown
- 'react-markdown',
- 'devlop',
- 'hast-util-',
- 'property-information',
- 'space-separated-tokens',
- 'comma-separated-tokens',
- 'unist-util-',
- 'vfile',
- 'estree-util-is-identifier-name',
- 'html-url-attributes',
- 'remark-',
- 'mdast-util-',
- 'micromark',
- 'decode-named-character-reference',
- 'character-entities',
- 'trim-lines',
- 'unified',
- 'bail',
- 'is-plain-obj',
- 'trough',
-].join('|');
-
-module.exports = {
- coverageDirectory: '<rootDir>/coverage',
- collectCoverageFrom: ['src/main/js/**/*.{ts,tsx,js}', '!helpers/{keycodes,testUtils}.{ts,tsx}'],
- coverageReporters: ['lcovonly', 'text'],
- moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
- moduleNameMapper: {
- '^.+\\.(md|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
- '<rootDir>/config/jest/FileStub.js',
- '^~sonar-aligned/(.*)': '<rootDir>/src/main/js/sonar-aligned/$1',
- '^~design-system': '<rootDir>/src/main/js/design-system/index.ts',
- '^.+\\.css$': '<rootDir>/config/jest/CSSStub.js',
- // Jest is using the wrong d3 built package: https://github.com/facebook/jest/issues/12036
- '^d3-(.*)$': `<rootDir>/node_modules/d3-$1/dist/d3-$1.min.js`,
- },
- globalSetup: '<rootDir>/config/jest/GlobalSetup.js',
- setupFiles: [
- '<rootDir>/config/jest/jest.polyfills.js',
- '<rootDir>/config/jest/SetupTestEnvironment.ts',
- '<rootDir>/config/jest/SetupTheme.js',
- ],
- setupFilesAfterEnv: [
- '<rootDir>/config/jest/SetupReactTestingLibrary.ts',
- '<rootDir>/config/jest/SetupJestAxe.ts',
- '<rootDir>/config/jest/SetupFailOnConsole.ts',
- ],
- snapshotSerializers: ['@emotion/jest/serializer'],
- testEnvironment: 'jsdom',
- testPathIgnorePatterns: ['<rootDir>/config', '<rootDir>/node_modules', '<rootDir>/scripts'],
- testRegex: '(/__tests__/.*|\\-test)\\.(ts|tsx|js)$',
- // Our ts,tsx and js files need some babel transformation to be understood by nodejs
- transform: {
- '^.+\\.[jt]sx?$': `<rootDir>/config/jest/JestPreprocess.js`,
- },
- transformIgnorePatterns: [`/node_modules/(?!${esModules})`],
- reporters: [
- 'default',
- [
- 'jest-junit',
- {
- outputDirectory: 'build/test-results/test-jest',
- outputName: 'junit.xml',
- ancestorSeparator: ' > ',
- suiteNameTemplate: '{filename}',
- classNameTemplate: '{classname}',
- titleTemplate: '{title}',
- },
- ],
- ['jest-slow-test-reporter', { numTests: 5, warnOnSlowerThan: 10000, color: true }],
- ],
- testTimeout: 60000,
-};
diff --git a/server/sonar-web/public/.htaccess b/server/sonar-web/public/.htaccess
deleted file mode 100644
index d3c9983451f..00000000000
--- a/server/sonar-web/public/.htaccess
+++ /dev/null
@@ -1,40 +0,0 @@
-# General Apache options
-AddHandler fastcgi-script .fcgi
-AddHandler cgi-script .cgi
-Options +FollowSymLinks +ExecCGI
-
-# If you don't want Rails to look in certain directories,
-# use the following rewrite rules so that Apache won't rewrite certain requests
-#
-# Example:
-# RewriteCond %{REQUEST_URI} ^/notrails.*
-# RewriteRule .* - [L]
-
-# Redirect all requests not available on the filesystem to Rails
-# By default the cgi dispatcher is used which is very slow
-#
-# For better performance replace the dispatcher with the fastcgi one
-#
-# Example:
-# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
-RewriteEngine On
-
-# If your Rails application is accessed via an Alias directive,
-# then you MUST also set the RewriteBase in this htaccess file.
-#
-# Example:
-# Alias /myrailsapp /path/to/myrailsapp/public
-# RewriteBase /myrailsapp
-
-RewriteRule ^$ index.html [QSA]
-RewriteRule ^([^.]+)$ $1.html [QSA]
-RewriteCond %{REQUEST_FILENAME} !-f
-RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
-
-# In case Rails experiences terminal errors
-# Instead of displaying this message you can supply a file here which will be rendered instead
-#
-# Example:
-# ErrorDocument 500 /500.html
-
-ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly" \ No newline at end of file
diff --git a/server/sonar-web/public/WEB-INF/web.xml b/server/sonar-web/public/WEB-INF/web.xml
deleted file mode 100644
index b5d4912371d..00000000000
--- a/server/sonar-web/public/WEB-INF/web.xml
+++ /dev/null
@@ -1,201 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
- id="SonarQube"
- version="3.0"
- metadata-complete="true">
- <display-name>SonarQube</display-name>
-
- <filter>
- <filter-name>ServletFilters</filter-name>
- <filter-class>org.sonar.server.platform.web.MasterServletFilter</filter-class>
- <async-supported>true</async-supported>
- </filter>
- <filter>
- <filter-name>UserSessionFilter</filter-name>
- <filter-class>org.sonar.server.platform.web.UserSessionFilter</filter-class>
- <async-supported>true</async-supported>
- </filter>
- <filter>
- <filter-name>SetCharacterEncodingFilter</filter-name>
- <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
- <async-supported>true</async-supported>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>UTF-8</param-value>
- </init-param>
- </filter>
- <filter>
- <filter-name>SecurityFilter</filter-name>
- <filter-class>org.sonar.server.platform.web.SecurityServletFilter</filter-class>
- <async-supported>true</async-supported>
- </filter>
- <filter>
- <filter-name>RootFilter</filter-name>
- <filter-class>org.sonar.server.platform.web.RootFilter</filter-class>
- <async-supported>true</async-supported>
- </filter>
- <filter>
- <filter-name>RedirectFilter</filter-name>
- <filter-class>org.sonar.server.platform.web.RedirectFilter</filter-class>
- <async-supported>true</async-supported>
- </filter>
- <filter>
- <filter-name>RequestUidFilter</filter-name>
- <filter-class>org.sonar.server.platform.web.RequestIdFilter</filter-class>
- <async-supported>true</async-supported>
- </filter>
- <filter>
- <filter-name>WebPagesFilter</filter-name>
- <filter-class>org.sonar.server.platform.web.WebPagesFilter</filter-class>
- <async-supported>true</async-supported>
- </filter>
- <filter>
- <filter-name>CacheControlFilter</filter-name>
- <filter-class>org.sonar.server.platform.web.CacheControlFilter</filter-class>
- <async-supported>true</async-supported>
- </filter>
- <filter>
- <filter-name>CspFilter</filter-name>
- <filter-class>org.sonar.server.platform.web.CspFilter</filter-class>
- <async-supported>true</async-supported>
- </filter>
- <filter>
- <filter-name>EndpointPathFilter</filter-name>
- <filter-class>org.sonar.server.platform.web.EndpointPathFilter</filter-class>
- <async-supported>true</async-supported>
- </filter>
-
- <!-- order of execution is important -->
- <filter-mapping>
- <filter-name>SetCharacterEncodingFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>RootFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>RequestUidFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>EndpointPathFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>RedirectFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>SecurityFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>CacheControlFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>CspFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>UserSessionFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>ServletFilters</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>WebPagesFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
-
- <servlet>
- <servlet-name>default-servlet</servlet-name>
- <servlet-class>
- org.apache.catalina.servlets.DefaultServlet
- </servlet-class>
- <load-on-startup>1</load-on-startup>
- <async-supported>true</async-supported>
- </servlet>
-
- <servlet-mapping>
- <servlet-name>default</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
-
- <servlet>
- <servlet-name>static</servlet-name>
- <servlet-class>org.sonar.server.platform.web.StaticResourcesServlet</servlet-class>
- </servlet>
-
- <servlet-mapping>
- <servlet-name>static</servlet-name>
- <url-pattern>/static/*</url-pattern>
- </servlet-mapping>
-
- <listener>
- <listener-class>org.sonar.server.platform.web.PlatformServletContextListener</listener-class>
- </listener>
-
- <mime-mapping>
- <extension>css</extension>
- <mime-type>text/css</mime-type>
- </mime-mapping>
- <mime-mapping>
- <extension>xml</extension>
- <mime-type>text/xml</mime-type>
- </mime-mapping>
- <mime-mapping>
- <extension>gif</extension>
- <mime-type>image/gif</mime-type>
- </mime-mapping>
- <mime-mapping>
- <extension>jpeg</extension>
- <mime-type>image/jpeg</mime-type>
- </mime-mapping>
- <mime-mapping>
- <extension>jpg</extension>
- <mime-type>image/jpeg</mime-type>
- </mime-mapping>
- <mime-mapping>
- <extension>htm</extension>
- <mime-type>text/html</mime-type>
- </mime-mapping>
- <mime-mapping>
- <extension>html</extension>
- <mime-type>text/html</mime-type>
- </mime-mapping>
- <mime-mapping>
- <extension>jar</extension>
- <mime-type>application/java-archive</mime-type>
- </mime-mapping>
- <mime-mapping>
- <extension>pdf</extension>
- <mime-type>application/pdf</mime-type>
- </mime-mapping>
- <mime-mapping>
- <extension>png</extension>
- <mime-type>image/png</mime-type>
- </mime-mapping>
- <mime-mapping>
- <extension>ico</extension>
- <mime-type>image/x-icon</mime-type>
- </mime-mapping>
- <mime-mapping>
- <extension>txt</extension>
- <mime-type>text/plain</mime-type>
- </mime-mapping>
- <mime-mapping>
- <extension>csv</extension>
- <mime-type>text/plain</mime-type>
- </mime-mapping>
- <mime-mapping>
- <extension>woff</extension>
- <mime-type>application/font-woff</mime-type>
- </mime-mapping>
-</web-app>
diff --git a/server/sonar-web/public/apple-touch-icon.png b/server/sonar-web/public/apple-touch-icon.png
deleted file mode 100644
index 7a2e9c4e28d..00000000000
--- a/server/sonar-web/public/apple-touch-icon.png
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/favicon.ico b/server/sonar-web/public/favicon.ico
deleted file mode 100644
index 438a3cc7d24..00000000000
--- a/server/sonar-web/public/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-Black.woff2 b/server/sonar-web/public/fonts/Inter/Inter-Black.woff2
deleted file mode 100644
index 68f64c9ed98..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-Black.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-BlackItalic.woff2 b/server/sonar-web/public/fonts/Inter/Inter-BlackItalic.woff2
deleted file mode 100644
index 1c9c7ca8b04..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-BlackItalic.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-Bold.woff2 b/server/sonar-web/public/fonts/Inter/Inter-Bold.woff2
deleted file mode 100644
index 2846f29cc8a..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-Bold.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-BoldItalic.woff2 b/server/sonar-web/public/fonts/Inter/Inter-BoldItalic.woff2
deleted file mode 100644
index 0b1fe8e1255..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-BoldItalic.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-ExtraBold.woff2 b/server/sonar-web/public/fonts/Inter/Inter-ExtraBold.woff2
deleted file mode 100644
index c24c2bdc2f0..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-ExtraBold.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-ExtraBoldItalic.woff2 b/server/sonar-web/public/fonts/Inter/Inter-ExtraBoldItalic.woff2
deleted file mode 100644
index 4a81dc79826..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-ExtraBoldItalic.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-ExtraLight.woff2 b/server/sonar-web/public/fonts/Inter/Inter-ExtraLight.woff2
deleted file mode 100644
index f2ea706fafa..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-ExtraLight.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-ExtraLightItalic.woff2 b/server/sonar-web/public/fonts/Inter/Inter-ExtraLightItalic.woff2
deleted file mode 100644
index 9af717ba91b..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-ExtraLightItalic.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-Italic.woff2 b/server/sonar-web/public/fonts/Inter/Inter-Italic.woff2
deleted file mode 100644
index a619fc54861..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-Italic.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-Light.woff2 b/server/sonar-web/public/fonts/Inter/Inter-Light.woff2
deleted file mode 100644
index bc4be6658b0..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-Light.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-LightItalic.woff2 b/server/sonar-web/public/fonts/Inter/Inter-LightItalic.woff2
deleted file mode 100644
index 842b2dfcb77..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-LightItalic.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-Medium.woff2 b/server/sonar-web/public/fonts/Inter/Inter-Medium.woff2
deleted file mode 100644
index f92498a2ecf..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-Medium.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-MediumItalic.woff2 b/server/sonar-web/public/fonts/Inter/Inter-MediumItalic.woff2
deleted file mode 100644
index 0e3019f4ae7..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-MediumItalic.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-Regular.woff2 b/server/sonar-web/public/fonts/Inter/Inter-Regular.woff2
deleted file mode 100644
index 6c2b6893d59..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-Regular.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-SemiBold.woff2 b/server/sonar-web/public/fonts/Inter/Inter-SemiBold.woff2
deleted file mode 100644
index 611e90c958f..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-SemiBold.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-SemiBoldItalic.woff2 b/server/sonar-web/public/fonts/Inter/Inter-SemiBoldItalic.woff2
deleted file mode 100644
index 545685bd2c6..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-SemiBoldItalic.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-Thin.woff2 b/server/sonar-web/public/fonts/Inter/Inter-Thin.woff2
deleted file mode 100644
index abbc3a5c962..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-Thin.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/Inter-ThinItalic.woff2 b/server/sonar-web/public/fonts/Inter/Inter-ThinItalic.woff2
deleted file mode 100644
index ab0b2002a3a..00000000000
--- a/server/sonar-web/public/fonts/Inter/Inter-ThinItalic.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Inter/inter.css b/server/sonar-web/public/fonts/Inter/inter.css
deleted file mode 100644
index 64008b715ea..00000000000
--- a/server/sonar-web/public/fonts/Inter/inter.css
+++ /dev/null
@@ -1,134 +0,0 @@
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 100;
- font-display: swap;
- src: url('../fonts/Inter/Inter-Thin.woff2') format('woff2');
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 100;
- font-display: swap;
- src: url('../fonts/Inter/Inter-ThinItalic.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 200;
- font-display: swap;
- src: url('../fonts/Inter/Inter-ExtraLight.woff2') format('woff2');
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 200;
- font-display: swap;
- src: url('../fonts/Inter/Inter-ExtraLightItalic.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 300;
- font-display: swap;
- src: url('../fonts/Inter/Inter-Light.woff2') format('woff2');
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 300;
- font-display: swap;
- src: url('../fonts/Inter/Inter-LightItalic.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 400;
- font-display: swap;
- src: url('../fonts/Inter/Inter-Regular.woff2') format('woff2');
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 400;
- font-display: swap;
- src: url('../fonts/Inter/Inter-Italic.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 500;
- font-display: swap;
- src: url('../fonts/Inter/Inter-Medium.woff2') format('woff2');
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 500;
- font-display: swap;
- src: url('../fonts/Inter/Inter-MediumItalic.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 600;
- font-display: swap;
- src: url('../fonts/Inter/Inter-SemiBold.woff2') format('woff2');
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 600;
- font-display: swap;
- src: url('../fonts/Inter/Inter-SemiBoldItalic.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 700;
- font-display: swap;
- src: url('../fonts/Inter/Inter-Bold.woff2') format('woff2');
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 700;
- font-display: swap;
- src: url('../fonts/Inter/Inter-BoldItalic.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 800;
- font-display: swap;
- src: url('../fonts/Inter/Inter-ExtraBold.woff2') format('woff2');
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 800;
- font-display: swap;
- src: url('../fonts/Inter/Inter-ExtraBoldItalic.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Inter';
- font-style: normal;
- font-weight: 900;
- font-display: swap;
- src: url('../fonts/Inter/Inter-Black.woff2') format('woff2');
-}
-@font-face {
- font-family: 'Inter';
- font-style: italic;
- font-weight: 900;
- font-display: swap;
- src: url('../fonts/Inter/Inter-BlackItalic.woff2') format('woff2');
-}
diff --git a/server/sonar-web/public/fonts/Ubuntu/UFL.txt b/server/sonar-web/public/fonts/Ubuntu/UFL.txt
deleted file mode 100644
index 6e722c88daa..00000000000
--- a/server/sonar-web/public/fonts/Ubuntu/UFL.txt
+++ /dev/null
@@ -1,96 +0,0 @@
--------------------------------
-UBUNTU FONT LICENCE Version 1.0
--------------------------------
-
-PREAMBLE
-This licence allows the licensed fonts to be used, studied, modified and
-redistributed freely. The fonts, including any derivative works, can be
-bundled, embedded, and redistributed provided the terms of this licence
-are met. The fonts and derivatives, however, cannot be released under
-any other licence. The requirement for fonts to remain under this
-licence does not require any document created using the fonts or their
-derivatives to be published under this licence, as long as the primary
-purpose of the document is not to be a vehicle for the distribution of
-the fonts.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this licence and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Original Version" refers to the collection of Font Software components
-as received under this licence.
-
-"Modified Version" refers to any derivative made by adding to, deleting,
-or substituting -- in part or in whole -- any of the components of the
-Original Version, by changing formats or by porting the Font Software to
-a new environment.
-
-"Copyright Holder(s)" refers to all individuals and companies who have a
-copyright ownership of the Font Software.
-
-"Substantially Changed" refers to Modified Versions which can be easily
-identified as dissimilar to the Font Software by users of the Font
-Software comparing the Original Version with the Modified Version.
-
-To "Propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification and with or without charging
-a redistribution fee), making available to the public, and in some
-countries other activities as well.
-
-PERMISSION & CONDITIONS
-This licence does not grant any rights under trademark law and all such
-rights are reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of the Font Software, to propagate the Font Software, subject to
-the below conditions:
-
-1) Each copy of the Font Software must contain the above copyright
-notice and this licence. These can be included either as stand-alone
-text files, human-readable headers or in the appropriate machine-
-readable metadata fields within text or binary files as long as those
-fields can be easily viewed by the user.
-
-2) The font name complies with the following:
-(a) The Original Version must retain its name, unmodified.
-(b) Modified Versions which are Substantially Changed must be renamed to
-avoid use of the name of the Original Version or similar names entirely.
-(c) Modified Versions which are not Substantially Changed must be
-renamed to both (i) retain the name of the Original Version and (ii) add
-additional naming elements to distinguish the Modified Version from the
-Original Version. The name of such Modified Versions must be the name of
-the Original Version, with "derivative X" where X represents the name of
-the new work, appended to that name.
-
-3) The name(s) of the Copyright Holder(s) and any contributor to the
-Font Software shall not be used to promote, endorse or advertise any
-Modified Version, except (i) as required by this licence, (ii) to
-acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with
-their explicit written permission.
-
-4) The Font Software, modified or unmodified, in part or in whole, must
-be distributed entirely under this licence, and must not be distributed
-under any other licence. The requirement for fonts to remain under this
-licence does not affect any document created using the Font Software,
-except any version of the Font Software extracted from a document
-created using the Font Software may only be distributed under this
-licence.
-
-TERMINATION
-This licence becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
-COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
-DEALINGS IN THE FONT SOFTWARE.
diff --git a/server/sonar-web/public/fonts/Ubuntu/Ubuntu.css b/server/sonar-web/public/fonts/Ubuntu/Ubuntu.css
deleted file mode 100644
index 244fa66a495..00000000000
--- a/server/sonar-web/public/fonts/Ubuntu/Ubuntu.css
+++ /dev/null
@@ -1,29 +0,0 @@
-@font-face {
- font-family: 'Ubuntu Mono';
- font-style: normal;
- font-weight: 400;
- font-display: swap;
- src: url('../fonts/Ubuntu/UbuntuMono-Regular.woff2') format('woff2');
-}
-@font-face {
- font-family: 'Ubuntu Mono';
- font-style: italic;
- font-weight: 400;
- font-display: swap;
- src: url('../fonts/Ubuntu/UbuntuMono-Italic.woff2') format('woff2');
-}
-
-@font-face {
- font-family: 'Ubuntu Mono';
- font-style: normal;
- font-weight: 700;
- font-display: swap;
- src: url('../fonts/Ubuntu/UbuntuMono-Bold.woff2') format('woff2');
-}
-@font-face {
- font-family: 'Ubuntu Mono';
- font-style: italic;
- font-weight: 700;
- font-display: swap;
- src: url('../fonts/Ubuntu/UbuntuMono-BoldItalic.woff2') format('woff2');
-}
diff --git a/server/sonar-web/public/fonts/Ubuntu/UbuntuMono-Bold.woff2 b/server/sonar-web/public/fonts/Ubuntu/UbuntuMono-Bold.woff2
deleted file mode 100644
index ccf87705256..00000000000
--- a/server/sonar-web/public/fonts/Ubuntu/UbuntuMono-Bold.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Ubuntu/UbuntuMono-BoldItalic.woff2 b/server/sonar-web/public/fonts/Ubuntu/UbuntuMono-BoldItalic.woff2
deleted file mode 100644
index 617d67e1b0f..00000000000
--- a/server/sonar-web/public/fonts/Ubuntu/UbuntuMono-BoldItalic.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Ubuntu/UbuntuMono-Italic.woff2 b/server/sonar-web/public/fonts/Ubuntu/UbuntuMono-Italic.woff2
deleted file mode 100644
index 10da15321c8..00000000000
--- a/server/sonar-web/public/fonts/Ubuntu/UbuntuMono-Italic.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/fonts/Ubuntu/UbuntuMono-Regular.woff2 b/server/sonar-web/public/fonts/Ubuntu/UbuntuMono-Regular.woff2
deleted file mode 100644
index 64b7f901ece..00000000000
--- a/server/sonar-web/public/fonts/Ubuntu/UbuntuMono-Regular.woff2
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/images/activity-chart.svg b/server/sonar-web/public/images/activity-chart.svg
deleted file mode 100644
index 0f38b445036..00000000000
--- a/server/sonar-web/public/images/activity-chart.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="53" height="57" xmlns="http://www.w3.org/2000/svg"><g transform="translate(2 2)" fill="none" fill-rule="evenodd"><rect x="5" y="34" width="10" height="18" rx="2"/><path d="M14.054 34.935v16.13H5.946v-16.13h8.108m0-1.935H5.946A1.94 1.94 0 004 34.935v16.13A1.94 1.94 0 005.946 53h8.108A1.94 1.94 0 0016 51.065v-16.13A1.94 1.94 0 0014.054 33z" fill="#236A97" fill-rule="nonzero"/><rect x="20" y="26" width="10" height="26" rx="2"/><path d="M29.054 26.931v24.138h-8.108V26.931h8.108m0-1.931h-8.108A1.939 1.939 0 0019 26.931v24.138c0 1.066.871 1.931 1.946 1.931h8.108A1.939 1.939 0 0031 51.069V26.931A1.939 1.939 0 0029.054 25z" fill="#236A97" fill-rule="nonzero"/><rect x="34" y="10" width="10" height="43" rx="2"/><path d="M43.054 10.927v40.146h-8.108V10.927h8.108m0-1.927h-8.108A1.936 1.936 0 0033 10.927v40.146c0 1.064.871 1.927 1.946 1.927h8.108A1.936 1.936 0 0045 51.073V10.927A1.936 1.936 0 0043.054 9z" fill="#236A97" fill-rule="nonzero"/><path stroke="#236A97" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M5 24L19.986 9.998l4.93 4.532L40 0"/><path stroke="#236A97" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M40 6V0h-6M0 21v32h49"/></g></svg> \ No newline at end of file
diff --git a/server/sonar-web/public/images/alm/azure.svg b/server/sonar-web/public/images/alm/azure.svg
deleted file mode 100644
index a4350954295..00000000000
--- a/server/sonar-web/public/images/alm/azure.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22.009 22">
- <path fill="#0078d7" d="M2.916 15.015v-7.25l19.093-3.758v13.446L16.62 21.92l-8.226-2.757V22l-5.478-6.985 13.216 1.728V5.052L9.812 0l.044 2.3-7.516 3L0 8.1v6.3z"/>
-</svg> \ No newline at end of file
diff --git a/server/sonar-web/public/images/alm/azure_grey.svg b/server/sonar-web/public/images/alm/azure_grey.svg
deleted file mode 100644
index 44453e2f8cc..00000000000
--- a/server/sonar-web/public/images/alm/azure_grey.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
-<g clip-path="url(#clip0_1483_60265)">
-<g clip-path="url(#clip1_1483_60265)">
-<path d="M0 5.93225L1.4975 3.95575L7.1015 1.67725V0.03125L12.0155 3.62525L1.9765 5.57325V11.0577L0 10.4872L0 5.93225ZM16 2.96575V12.7337L12.164 15.9992L5.9635 13.9627V15.9992L1.9765 11.0567L12.0155 12.2547V3.62475L16 2.96575Z" fill="#9F9F9F"/>
-</g>
-</g>
-<defs>
-<clipPath id="clip0_1483_60265">
-<rect width="16" height="16" fill="white"/>
-</clipPath>
-<clipPath id="clip1_1483_60265">
-<rect width="16" height="16" fill="white"/>
-</clipPath>
-</defs>
-</svg>
diff --git a/server/sonar-web/public/images/alm/bitbucket-white.svg b/server/sonar-web/public/images/alm/bitbucket-white.svg
deleted file mode 100644
index 3255ad0a796..00000000000
--- a/server/sonar-web/public/images/alm/bitbucket-white.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" focusable="false" role="presentation">
- <defs>
- <linearGradient id="a" x1="97.526%" x2="46.927%" y1="25.488%" y2="78.776%">
- <stop offset="0%" stop-color="#FFF" stop-opacity=".4"/>
- <stop offset="100%" stop-color="#FFF"/>
- </linearGradient>
- </defs>
- <path fill="url(#a)" d="M20.063 9.297h-5.279l-.886 5.16h-3.656l-4.317 5.116a.763.763 0 0 0 .492.186h11.458a.562.562 0 0 0 .563-.472l1.625-9.99z" transform="matrix(1.33 0 0 1.33 -4 -3.8)"/>
- <path fill="#FFF" d="M1.11252 1.52a.74879.74879 0 0 0-.74879.86583L3.5411 21.6296a1.01479 1.01479 0 0 0 .99484.84721l5.89589-7.049h-.82726l-1.29808-6.8628h14.37863l1.0108-6.1712a.7448.7448 0 0 0-.73815-.87381H1.11252z"/>
-</svg> \ No newline at end of file
diff --git a/server/sonar-web/public/images/alm/bitbucket.svg b/server/sonar-web/public/images/alm/bitbucket.svg
deleted file mode 100644
index 984afdaa426..00000000000
--- a/server/sonar-web/public/images/alm/bitbucket.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="-361.924 -3545.014 58.441 52.551">
- <defs>
- <linearGradient id="a" x1="1.086" x2=".469" y1=".138" y2=".788" gradientUnits="objectBoundingBox">
- <stop offset=".18" stop-color="#0052cc"/>
- <stop offset="1" stop-color="#2684ff"/>
- </linearGradient>
- </defs>
- <path fill="#2684ff" d="M-360.027-3545.013a1.872 1.872 0 0 0-1.871 2.172l7.947 48.253a2.547 2.547 0 0 0 2.49 2.125h38.133a1.872 1.872 0 0 0 1.872-1.573l7.949-48.8a1.872 1.872 0 0 0-1.872-2.172zm33.47 34.875h-12.171l-3.3-17.217h18.42z"/>
- <path fill="url(#a)" d="M56.464 25.12H38.891l-2.949 17.217H23.771L9.4 59.4a2.537 2.537 0 0 0 1.638.618H49.18a1.872 1.872 0 0 0 1.872-1.573z" transform="translate(-362.499 -3552.476)"/>
-</svg> \ No newline at end of file
diff --git a/server/sonar-web/public/images/alm/bitbucket_grey.svg b/server/sonar-web/public/images/alm/bitbucket_grey.svg
deleted file mode 100644
index 4ad14c1396c..00000000000
--- a/server/sonar-web/public/images/alm/bitbucket_grey.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path fill-rule="evenodd" clip-rule="evenodd" d="M0.124366 1.17313C0.223258 1.0615 0.367814 0.998141 0.519258 1.00004L15.4807 1.00254C15.6322 1.00064 15.7767 1.064 15.8756 1.17562C15.9745 1.28725 16.0176 1.43571 15.9934 1.58119L13.8172 14.5809C13.7766 14.8248 13.5585 15.0031 13.3046 14.9999H2.8646C2.52625 14.9972 2.23875 14.7584 2.18278 14.4337L0.00661524 1.57869C-0.0176304 1.43321 0.0254741 1.28475 0.124366 1.17313ZM6.35057 10.2909H9.68275L10.4902 5.70407H5.44832L6.35057 10.2909Z" fill="#C1C1C1"/>
-<path d="M15.2998 5.90039H10.4458L9.63122 10.3412H6.26937L2.2998 14.741C2.42562 14.8426 2.58603 14.8991 2.75236 14.9003H13.2879C13.5441 14.9034 13.7641 14.7309 13.8051 14.4947L15.2998 5.90039Z" fill="url(#paint0_linear_1483_60281)"/>
-<defs>
-<linearGradient id="paint0_linear_1483_60281" x1="12.1999" y1="4.36721" x2="7.0939" y2="12.1311" gradientUnits="userSpaceOnUse">
-<stop offset="0.18" stop-color="#C8C8C8"/>
-<stop offset="1" stop-color="white"/>
-</linearGradient>
-</defs>
-</svg>
diff --git a/server/sonar-web/public/images/alm/github-white.svg b/server/sonar-web/public/images/alm/github-white.svg
deleted file mode 100644
index 89a559abe96..00000000000
--- a/server/sonar-web/public/images/alm/github-white.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" version="1.1" x="0" y="0" viewBox="0 0 438.5 438.5" xml:space="preserve">
- <path fill="#fff"
- d="M409.1 114.6c-19.6-33.6-46.2-60.2-79.8-79.8C295.7 15.2 259.1 5.4 219.3 5.4c-39.8 0-76.5 9.8-110.1 29.4 -33.6 19.6-60.2 46.2-79.8 79.8C9.8 148.2 0 184.9 0 224.6c0 47.8 13.9 90.7 41.8 128.9 27.9 38.2 63.9 64.6 108.1 79.2 5.1 1 8.9 0.3 11.4-2 2.5-2.3 3.7-5.1 3.7-8.6 0-0.6 0-5.7-0.1-15.4 -0.1-9.7-0.1-18.2-0.1-25.4l-6.6 1.1c-4.2 0.8-9.5 1.1-15.8 1 -6.4-0.1-13-0.8-19.8-2 -6.9-1.2-13.2-4.1-19.1-8.6 -5.9-4.5-10.1-10.3-12.6-17.6l-2.9-6.6c-1.9-4.4-4.9-9.2-9-14.6 -4.1-5.3-8.2-8.9-12.4-10.8l-2-1.4c-1.3-1-2.6-2.1-3.7-3.4 -1.1-1.3-2-2.7-2.6-4 -0.6-1.3-0.1-2.4 1.4-3.3 1.5-0.9 4.3-1.3 8.3-1.3l5.7 0.9c3.8 0.8 8.5 3 14.1 6.9 5.6 3.8 10.2 8.8 13.8 14.8 4.4 7.8 9.7 13.8 15.8 17.8 6.2 4.1 12.4 6.1 18.7 6.1 6.3 0 11.7-0.5 16.3-1.4 4.6-1 8.8-2.4 12.8-4.3 1.7-12.8 6.4-22.6 14-29.4 -10.8-1.1-20.6-2.9-29.3-5.1 -8.7-2.3-17.6-6-26.8-11.1 -9.2-5.1-16.9-11.5-23-19.1 -6.1-7.6-11.1-17.6-15-30 -3.9-12.4-5.9-26.6-5.9-42.8 0-23 7.5-42.6 22.6-58.8 -7-17.3-6.4-36.7 2-58.2 5.5-1.7 13.7-0.4 24.6 3.9 10.9 4.3 18.8 8 23.8 11 5 3 9.1 5.6 12.1 7.7 17.7-4.9 36-7.4 54.8-7.4s37.1 2.5 54.8 7.4l10.8-6.8c7.4-4.6 16.2-8.8 26.3-12.6 10.1-3.8 17.8-4.9 23.1-3.1 8.6 21.5 9.3 40.9 2.3 58.2 15 16.2 22.6 35.8 22.6 58.8 0 16.2-2 30.5-5.9 43 -3.9 12.5-8.9 22.5-15.1 30 -6.2 7.5-13.9 13.9-23.1 19 -9.2 5.1-18.2 8.9-26.8 11.1 -8.7 2.3-18.4 4-29.3 5.1 9.9 8.6 14.8 22.1 14.8 40.5v60.2c0 3.4 1.2 6.3 3.6 8.6 2.4 2.3 6.1 3 11.3 2 44.2-14.7 80.2-41.1 108.1-79.2 27.9-38.2 41.8-81.1 41.8-128.9C438.5 184.9 428.7 148.2 409.1 114.6z"/>
-</svg>
diff --git a/server/sonar-web/public/images/alm/github.svg b/server/sonar-web/public/images/alm/github.svg
deleted file mode 100644
index 97c8f324e50..00000000000
--- a/server/sonar-web/public/images/alm/github.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="-738.601 -3545.014 54.017 52.551">
- <path fill="#191717" fill-rule="evenodd" d="M-711.675-3545.014a26.975 26.975 0 0 0-8.59 52.53c1.322.165 1.817-.661 1.817-1.322v-4.625c-7.433 1.652-9.085-3.634-9.085-3.634-1.156-3.139-2.973-3.965-2.973-3.965-2.478-1.652.165-1.652.165-1.652 2.643.165 4.13 2.808 4.13 2.808 2.478 4.13 6.277 2.973 7.764 2.313a5.752 5.752 0 0 1 1.646-3.634c-5.947-.661-12.224-2.973-12.224-13.38a10.24 10.24 0 0 1 2.808-7.268 9.781 9.781 0 0 1 .33-6.938s2.313-.661 7.433 2.808a23.083 23.083 0 0 1 6.773-.826 30.4 30.4 0 0 1 6.773.826c5.121-3.469 7.433-2.808 7.433-2.808a10.343 10.343 0 0 1 .33 7.1 10.684 10.684 0 0 1 2.815 7.267c0 10.407-6.277 12.554-12.224 13.215.991.826 1.817 2.478 1.817 4.956v7.433c0 .661.5 1.487 1.817 1.322a26.976 26.976 0 0 0-8.755-52.526z"/>
-</svg> \ No newline at end of file
diff --git a/server/sonar-web/public/images/alm/github_grey.svg b/server/sonar-web/public/images/alm/github_grey.svg
deleted file mode 100644
index b7571df85c3..00000000000
--- a/server/sonar-web/public/images/alm/github_grey.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
-<g clip-path="url(#clip0_1483_60262)">
-<path fill-rule="evenodd" clip-rule="evenodd" d="M8 0C3.58 0 0 3.67055 0 8.20235C0 11.8319 2.29 14.8975 5.47 15.9843C5.87 16.0561 6.02 15.81 6.02 15.5947C6.02 15.3999 6.01 14.754 6.01 14.067C4 14.4464 3.48 13.5646 3.32 13.1033C3.23 12.8674 2.84 12.1395 2.5 11.9447C2.22 11.7909 1.82 11.4115 2.49 11.4013C3.12 11.391 3.57 11.9959 3.72 12.242C4.44 13.4826 5.59 13.134 6.05 12.9187C6.12 12.3855 6.33 12.0267 6.56 11.8216C4.78 11.6166 2.92 10.9091 2.92 7.77173C2.92 6.87972 3.23 6.14151 3.74 5.56735C3.66 5.36229 3.38 4.52155 3.82 3.39372C3.82 3.39372 4.49 3.17841 6.02 4.23446C6.66 4.04991 7.34 3.95763 8.02 3.95763C8.7 3.95763 9.38 4.04991 10.02 4.23446C11.55 3.16816 12.22 3.39372 12.22 3.39372C12.66 4.52155 12.38 5.36229 12.3 5.56735C12.81 6.14151 13.12 6.86947 13.12 7.77173C13.12 10.9194 11.25 11.6166 9.47 11.8216C9.76 12.078 10.01 12.5701 10.01 13.3391C10.01 14.4361 10 15.3179 10 15.5947C10 15.81 10.15 16.0664 10.55 15.9843C13.71 14.8975 16 11.8216 16 8.20235C16 3.67055 12.42 0 8 0Z" fill="#6B7279"/>
-</g>
-<defs>
-<clipPath id="clip0_1483_60262">
-<rect width="16" height="16" fill="white"/>
-</clipPath>
-</defs>
-</svg>
diff --git a/server/sonar-web/public/images/alm/gitlab.svg b/server/sonar-web/public/images/alm/gitlab.svg
deleted file mode 100644
index 1f796f609de..00000000000
--- a/server/sonar-web/public/images/alm/gitlab.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="90 95 200 190"><defs><style>.cls-1{fill:#e24329;}.cls-2{fill:#fc6d26;}.cls-3{fill:#fca326;}</style></defs><g id="LOGO"><path class="cls-1" d="M282.83,170.73l-.27-.69-26.14-68.22a6.81,6.81,0,0,0-2.69-3.24,7,7,0,0,0-8,.43,7,7,0,0,0-2.32,3.52l-17.65,54H154.29l-17.65-54A6.86,6.86,0,0,0,134.32,99a7,7,0,0,0-8-.43,6.87,6.87,0,0,0-2.69,3.24L97.44,170l-.26.69a48.54,48.54,0,0,0,16.1,56.1l.09.07.24.17,39.82,29.82,19.7,14.91,12,9.06a8.07,8.07,0,0,0,9.76,0l12-9.06,19.7-14.91,40.06-30,.1-.08A48.56,48.56,0,0,0,282.83,170.73Z"/><path class="cls-2" d="M282.83,170.73l-.27-.69a88.3,88.3,0,0,0-35.15,15.8L190,229.25c19.55,14.79,36.57,27.64,36.57,27.64l40.06-30,.1-.08A48.56,48.56,0,0,0,282.83,170.73Z"/><path class="cls-3" d="M153.43,256.89l19.7,14.91,12,9.06a8.07,8.07,0,0,0,9.76,0l12-9.06,19.7-14.91S209.55,244,190,229.25C170.45,244,153.43,256.89,153.43,256.89Z"/><path class="cls-2" d="M132.58,185.84A88.19,88.19,0,0,0,97.44,170l-.26.69a48.54,48.54,0,0,0,16.1,56.1l.09.07.24.17,39.82,29.82s17-12.85,36.57-27.64Z"/></g></svg> \ No newline at end of file
diff --git a/server/sonar-web/public/images/alm/gitlab_grey.svg b/server/sonar-web/public/images/alm/gitlab_grey.svg
deleted file mode 100644
index 2c086963c89..00000000000
--- a/server/sonar-web/public/images/alm/gitlab_grey.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
-<g clip-path="url(#clip0_1483_60264)">
-<path d="M15.7337 6.09936L15.7112 6.04188L13.5335 0.358462C13.4892 0.24707 13.4107 0.152576 13.3094 0.0885373C13.2079 0.0255869 13.0897 -0.00473207 12.9705 0.00167412C12.8513 0.00808031 12.7369 0.0509032 12.6429 0.124361C12.5498 0.199927 12.4824 0.302323 12.4496 0.417612L10.9792 4.91636H5.025L3.55457 0.417612C3.52268 0.301695 3.45505 0.198786 3.36129 0.123527C3.26722 0.0500699 3.15287 0.00724703 3.03368 0.000840838C2.9145 -0.00556535 2.79622 0.0247536 2.69481 0.087704C2.5937 0.152001 2.51531 0.246413 2.47071 0.357629L0.288816 6.03855L0.267156 6.09603C-0.046338 6.91514 -0.0850337 7.81397 0.156903 8.65699C0.398839 9.50001 0.908292 10.2415 1.60845 10.7697L1.61595 10.7756L1.63594 10.7897L4.95335 13.274L6.59456 14.5162L7.59428 15.271C7.71122 15.3598 7.85401 15.4078 8.00083 15.4078C8.14766 15.4078 8.29045 15.3598 8.40739 15.271L9.40711 14.5162L11.0483 13.274L14.3857 10.7747L14.3941 10.7681C15.0926 10.2398 15.6009 9.49901 15.8425 8.65713C16.084 7.81524 16.0459 6.9177 15.7337 6.09936V6.09936Z" fill="#747474"/>
-<path d="M15.7337 6.09948L15.7112 6.04199C14.6501 6.2598 13.6501 6.70927 12.7828 7.35829L8 10.9748C9.62871 12.2069 11.0467 13.2775 11.0467 13.2775L14.3841 10.7782L14.3924 10.7715C15.092 10.2432 15.601 9.502 15.8429 8.65939C16.0848 7.81679 16.0465 6.91841 15.7337 6.09948Z" fill="#A6A6A6"/>
-<path d="M4.95312 13.2773L6.59434 14.5195L7.59406 15.2742C7.711 15.363 7.85378 15.4111 8.00061 15.4111C8.14743 15.4111 8.29022 15.363 8.40716 15.2742L9.40688 14.5195L11.0481 13.2773C11.0481 13.2773 9.62849 12.2034 7.99978 10.9746C6.37106 12.2034 4.95312 13.2773 4.95312 13.2773Z" fill="#CCCCCC"/>
-<path d="M3.21633 7.35772C2.34974 6.70736 1.35002 6.25672 0.288816 6.03809L0.267156 6.09557C-0.046338 6.91468 -0.0850337 7.81351 0.156903 8.65653C0.398839 9.49955 0.908292 10.2411 1.60845 10.7693L1.61595 10.7751L1.63594 10.7893L4.95335 13.2736C4.95335 13.2736 6.36962 12.203 8 10.9709L3.21633 7.35772Z" fill="#A6A6A6"/>
-</g>
-<defs>
-<clipPath id="clip0_1483_60264">
-<rect width="16" height="16" fill="white"/>
-</clipPath>
-</defs>
-</svg>
diff --git a/server/sonar-web/public/images/check.svg b/server/sonar-web/public/images/check.svg
deleted file mode 100644
index 30051d62119..00000000000
--- a/server/sonar-web/public/images/check.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg width="43" height="31" viewBox="0 0 43 31" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M41.6187 0.881256C42.7906 2.05313 42.7906 3.95626 41.6187 5.12813L17.6187 29.1281C16.4468 30.3 14.5437 30.3 13.3718 29.1281L1.37183 17.1281C0.199951 15.9563 0.199951 14.0531 1.37183 12.8813C2.5437 11.7094 4.44683 11.7094 5.6187 12.8813L15.5 22.7531L37.3812 0.881256C38.5531 -0.290619 40.4562 -0.290619 41.6281 0.881256H41.6187Z" fill="#008A25"/>
-</svg>
diff --git a/server/sonar-web/public/images/cross.svg b/server/sonar-web/public/images/cross.svg
deleted file mode 100644
index 9ca7781bec9..00000000000
--- a/server/sonar-web/public/images/cross.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg width="39" height="39" viewBox="0 0 39 39" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M35.0487 27.464L26.5823 19.0057L35.04 10.54C35.0402 10.5398 35.0404 10.5395 35.0407 10.5393C36.9929 8.58635 36.9927 5.41739 35.04 3.46469C33.0871 1.51177 29.9176 1.51177 27.9647 3.46469L27.964 3.46536L19.5057 11.9317L11.04 3.47407C11.0399 3.47396 11.0398 3.47385 11.0397 3.47374C11.0396 3.47363 11.0394 3.47351 11.0393 3.4734C9.08634 1.52114 5.91739 1.52137 3.96469 3.47407C2.01177 5.42699 2.01177 8.59645 3.96469 10.5494L3.96536 10.55L12.4317 19.0084L3.97407 27.4741C3.97398 27.4741 3.9739 27.4742 3.97382 27.4743C3.97368 27.4745 3.97354 27.4746 3.9734 27.4747C2.02114 29.4277 2.02137 32.5967 3.97407 34.5494C5.92699 36.5023 9.09645 36.5023 11.0494 34.5494L11.05 34.5487L19.5084 26.0823L27.9741 34.54C27.9743 34.5402 27.9745 34.5404 27.9747 34.5407C29.9277 36.4929 33.0967 36.4927 35.0494 34.54C37.0023 32.5871 37.0023 29.4176 35.0494 27.4647L35.0487 27.464Z" fill="#D02F3A" stroke="white" stroke-width="4"/>
-</svg>
diff --git a/server/sonar-web/public/images/embed-doc/sq-icon.svg b/server/sonar-web/public/images/embed-doc/sq-icon.svg
deleted file mode 100644
index da6e96895ed..00000000000
--- a/server/sonar-web/public/images/embed-doc/sq-icon.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M11.939 13.282h-.756C11.183 7.203 6.167 2.256 0 2.256v-.755c6.585 0 11.939 5.286 11.939 11.781zm.522-4.053c-.906-3.816-3.997-7-7.872-8.111l.173-.603c4.09 1.174 7.353 4.538 8.311 8.57l-.612.144zm.581-3.575A11.572 11.572 0 0 0 8.562.648l.261-.43a12.081 12.081 0 0 1 4.677 5.22l-.458.216z" fill="#4e9bcd" fill-rule="nonzero"/></svg> \ No newline at end of file
diff --git a/server/sonar-web/public/images/embed-doc/x-icon-black.svg b/server/sonar-web/public/images/embed-doc/x-icon-black.svg
deleted file mode 100644
index 56368dd4b30..00000000000
--- a/server/sonar-web/public/images/embed-doc/x-icon-black.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg width="1200" height="1227" viewBox="0 0 1200 1227" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M714.163 519.284L1160.89 0H1055.03L667.137 450.887L357.328 0H0L468.492 681.821L0 1226.37H105.866L515.491 750.218L842.672 1226.37H1200L714.137 519.284H714.163ZM569.165 687.828L521.697 619.934L144.011 79.6944H306.615L611.412 515.685L658.88 583.579L1055.08 1150.3H892.476L569.165 687.854V687.828Z" fill="black"/>
-</svg>
diff --git a/server/sonar-web/public/images/filter-large.svg b/server/sonar-web/public/images/filter-large.svg
deleted file mode 100644
index c7798884092..00000000000
--- a/server/sonar-web/public/images/filter-large.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="80" height="83" xmlns="http://www.w3.org/2000/svg"><g fill="#236A97" fill-rule="nonzero"><path d="M79.03 3.78A4.27 4.27 0 0074.88 0H4.24A3.94 3.94 0 00.28 3.97v10.97c0 .37.09.65.37.92L31.9 52.2v29.23a1.44 1.44 0 001.38 1.39c.28 0 .56-.1.74-.19l12.73-7.93c.37-.28.64-.74.64-1.2V52.2l31.27-36.34c.18-.27.36-.55.36-.92V3.97v-.19zm-2.76 10.6L45 50.73c-.18.28-.36.56-.36.92v21.12l-9.96 6.18v-27.3c0-.36-.1-.64-.37-.92L3.04 14.4V3.97c0-.56.46-1.2 1.2-1.2h70.64c.65 0 1.3.55 1.39 1.29v10.33z"/><path d="M55.33 13.56H9.5c-.74 0-1.38.64-1.38 1.38 0 .74.64 1.38 1.38 1.38h45.83c.74 0 1.39-.64 1.39-1.38 0-.74-.65-1.38-1.39-1.38zM68.98 13.56h-7c-.74 0-1.39.64-1.39 1.38 0 .74.65 1.38 1.38 1.38h7.01c.74 0 1.39-.64 1.39-1.38 0-.74-.65-1.38-1.39-1.38z"/></g></svg>
diff --git a/server/sonar-web/public/images/hotspot-large.svg b/server/sonar-web/public/images/hotspot-large.svg
deleted file mode 100644
index edfcb684a6c..00000000000
--- a/server/sonar-web/public/images/hotspot-large.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="75" height="83" xmlns="http://www.w3.org/2000/svg"><path d="M74.03 13.28a5.89 5.89 0 00-3.96-4.52L39.02.18a6.3 6.3 0 00-2.96 0L5.01 8.76a5.54 5.54 0 00-3.96 4.52c-.48 3.35-4.38 33.09 6.74 48.84a53.22 53.22 0 0028.39 20.33c.45.07.9.07 1.36 0 .43.07.87.07 1.3 0A52.8 52.8 0 0067.3 62.12c10.94-15.75 7.16-45.49 6.74-48.84zM67 42a39.5 39.5 0 01-5.92 15.97A54.33 54.33 0 0138 75V42h29zM38 8v33H8.5a158.2 158.2 0 010-25.21L38 8z" fill="#236A97" fill-rule="nonzero"/></svg>
diff --git a/server/sonar-web/public/images/loading.gif b/server/sonar-web/public/images/loading.gif
deleted file mode 100644
index 60834b831fa..00000000000
--- a/server/sonar-web/public/images/loading.gif
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/images/mode-tour/step1.png b/server/sonar-web/public/images/mode-tour/step1.png
deleted file mode 100644
index c2fde69108a..00000000000
--- a/server/sonar-web/public/images/mode-tour/step1.png
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/images/mode-tour/step2.png b/server/sonar-web/public/images/mode-tour/step2.png
deleted file mode 100644
index 0acbf1f087a..00000000000
--- a/server/sonar-web/public/images/mode-tour/step2.png
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/images/mode-tour/step3.png b/server/sonar-web/public/images/mode-tour/step3.png
deleted file mode 100644
index edbe1d96be9..00000000000
--- a/server/sonar-web/public/images/mode-tour/step3.png
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/images/mode-tour/step4.png b/server/sonar-web/public/images/mode-tour/step4.png
deleted file mode 100644
index 80a606a5680..00000000000
--- a/server/sonar-web/public/images/mode-tour/step4.png
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/images/mode-tour/step4_se.png b/server/sonar-web/public/images/mode-tour/step4_se.png
deleted file mode 100644
index 6475bbdcaf3..00000000000
--- a/server/sonar-web/public/images/mode-tour/step4_se.png
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/images/saml.png b/server/sonar-web/public/images/saml.png
deleted file mode 100644
index 173c5b1e5be..00000000000
--- a/server/sonar-web/public/images/saml.png
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/images/sonar-logo-horizontal.png b/server/sonar-web/public/images/sonar-logo-horizontal.png
deleted file mode 100644
index 310c519f9bf..00000000000
--- a/server/sonar-web/public/images/sonar-logo-horizontal.png
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/images/source-code.svg b/server/sonar-web/public/images/source-code.svg
deleted file mode 100644
index dd597d4f7ee..00000000000
--- a/server/sonar-web/public/images/source-code.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="57" height="51" xmlns="http://www.w3.org/2000/svg"><g fill="#236A97" fill-rule="nonzero"><path d="M47.002 50.629H2.42a2.203 2.203 0 01-2.19-2.21V9.932c0-1.218.982-2.21 2.19-2.21h6.158c.506 0 .916.415.916.925s-.41.925-.916.925H2.42a.359.359 0 00-.357.36v38.487c0 .199.16.36.357.36h44.582a.359.359 0 00.357-.36v-6.206c0-.51.41-.925.917-.925.506 0 .917.414.917.925v6.206c0 1.218-.983 2.21-2.191 2.21z"/><path d="M8.387 18.15h-6.39a.921.921 0 01-.917-.926c0-.51.41-.924.917-.924h6.39c.505 0 .916.414.916.924a.92.92 0 01-.916.925z"/><g><path d="M54.433 43.137H9.851a2.202 2.202 0 01-2.19-2.209V2.44c0-1.218.983-2.209 2.19-2.209h44.582c1.208 0 2.191.991 2.191 2.21v38.487c0 1.218-.983 2.21-2.19 2.21zM9.851 2.081a.358.358 0 00-.356.36v38.487c0 .199.16.36.356.36h44.582a.359.359 0 00.357-.36V2.44c0-.198-.16-.36-.357-.36H9.851z"/><path d="M55.707 10.658H9.428a.921.921 0 01-.917-.925c0-.51.41-.925.917-.925h46.279c.506 0 .917.415.917.925s-.41.925-.917.925zM17.231 6.186h-3.403a.921.921 0 01-.917-.924c0-.51.411-.925.917-.925h3.403c.506 0 .917.414.917.925a.92.92 0 01-.917.924zM24.98 6.186h-3.403a.921.921 0 01-.917-.924c0-.51.41-.925.917-.925h3.403c.506 0 .917.414.917.925 0 .51-.411.924-.918.924z"/><g stroke="#236A97"><path d="M19.685 25.593l7.37 3.048-.54 1.607-8.968-3.82v-1.67l8.968-3.82.54 1.607zM29.63 35.697h-1.973l7.039-20.208h1.93zM37.23 22.546l.539-1.608 8.968 3.82v1.67l-8.968 3.82-.54-1.607 7.37-3.047z"/></g></g></g></svg> \ No newline at end of file
diff --git a/server/sonar-web/public/images/tutorials/azure-pipelines.svg b/server/sonar-web/public/images/tutorials/azure-pipelines.svg
deleted file mode 100644
index 51314cd621d..00000000000
--- a/server/sonar-web/public/images/tutorials/azure-pipelines.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32"><defs><linearGradient id="a" x1=".069" y1="31.569" x2="1.069" y2="31.569" gradientTransform="matrix(0 29.091 29.091 0 -902.364 -.545)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><linearGradient id="c" x1=".069" y1="31.194" x2="1.069" y2="31.194" xlink:href="#a"/><mask id="b" x="1.455" y="1.455" width="29.091" height="29.091" maskUnits="userSpaceOnUse"><path d="M5.7 20.974l1.464-1.565 1.819 1.819L7.5 22.707 9.293 24.5l1.479-1.479 1.828 1.831-1.449 1.448 4.242 4.242h6.667a1.212 1.212 0 001.212-1.212v-9.7l6.195-4.129a2.425 2.425 0 001.078-2.016V2.667a1.212 1.212 0 00-1.212-1.212H18.509a2.425 2.425 0 00-2.016 1.078l-4.129 6.194h-9.7A1.212 1.212 0 001.455 9.94v6.666zM3.636 23.273H1.455v7.273h7.272v-2.182H3.636z" fill="#fff"/></mask></defs><g mask="url(#b)"><path d="M1.455 23.273h2.181v5.091h5.091v2.182H1.455z" fill="#91b0f2"/><path d="M1.455 9.939v6.667L5.7 20.974l1.815-1.944 5.455 5.455-1.819 1.815 4.242 4.242h6.667a1.212 1.212 0 001.212-1.212v-9.7L12.364 8.727h-9.7a1.212 1.212 0 00-1.209 1.212z" fill="#0f46bd"/><path d="M6 18.249L17.212 1.455h13.333v13.333L13.751 26z" fill="#062aa9"/><path d="M6.7 18.952a1.212 1.212 0 01-.151-1.53l9.94-14.889a2.424 2.424 0 012.016-1.078h10.828a1.212 1.212 0 011.212 1.212v10.825a2.424 2.424 0 01-1.078 2.016l-14.889 9.94a1.212 1.212 0 01-1.53-.151z" fill="#2560e0"/><path d="M7.5 22.707l9.255-9.255 1.792 1.792L9.293 24.5z" fill="#0a44c2"/><path d="M7.5 22.707l9.255-9.255 1.792 1.792L9.293 24.5z" fill="#729af2"/><path d="M10.772 23.02L8.98 21.228l7.776-7.775 1.792 1.792z" fill="#4c80f0"/><path d="M23.273 12.364a3.636 3.636 0 10-3.636-3.636 3.636 3.636 0 003.636 3.636z" fill="#0a44c2"/><path d="M23.273 12.364a3.636 3.636 0 10-3.636-3.636 3.636 3.636 0 003.636 3.636z" fill="#91b0f2"/><g opacity=".2"><path d="M5.7 20.974l1.464-1.565 1.819 1.819L7.5 22.707 9.293 24.5l1.479-1.479 1.828 1.831-1.449 1.448 4.242 4.242h6.667a1.212 1.212 0 001.212-1.212v-9.7l6.195-4.129a2.425 2.425 0 001.078-2.016V2.667a1.212 1.212 0 00-1.212-1.212H18.509a2.425 2.425 0 00-2.016 1.078l-4.129 6.194h-9.7A1.212 1.212 0 001.455 9.94v6.666z" fill="url(#a)"/><path d="M3.636 23.273H1.455v7.273h7.272v-2.182H3.636z" fill="url(#c)"/></g></g></svg> \ No newline at end of file
diff --git a/server/sonar-web/public/images/tutorials/commit.svg b/server/sonar-web/public/images/tutorials/commit.svg
deleted file mode 100644
index f60f7e5500e..00000000000
--- a/server/sonar-web/public/images/tutorials/commit.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="27" height="27"><g fill="none" fill-rule="evenodd" transform="rotate(-90 13.5 18.5)"><path fill="#236A97" fill-rule="nonzero" d="M23.755102 18.5408163L19.7526885 14.5v3.0306122H12v2.0204082h7.7526885v3.0306123z"/><path d="M0 0h36v36H0z"/><circle cx="18.5" cy="18.5" r="12" stroke="#236A97" stroke-width="3"/></g></svg> \ No newline at end of file
diff --git a/server/sonar-web/public/images/tutorials/github-actions.svg b/server/sonar-web/public/images/tutorials/github-actions.svg
deleted file mode 100644
index 97c8f324e50..00000000000
--- a/server/sonar-web/public/images/tutorials/github-actions.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="-738.601 -3545.014 54.017 52.551">
- <path fill="#191717" fill-rule="evenodd" d="M-711.675-3545.014a26.975 26.975 0 0 0-8.59 52.53c1.322.165 1.817-.661 1.817-1.322v-4.625c-7.433 1.652-9.085-3.634-9.085-3.634-1.156-3.139-2.973-3.965-2.973-3.965-2.478-1.652.165-1.652.165-1.652 2.643.165 4.13 2.808 4.13 2.808 2.478 4.13 6.277 2.973 7.764 2.313a5.752 5.752 0 0 1 1.646-3.634c-5.947-.661-12.224-2.973-12.224-13.38a10.24 10.24 0 0 1 2.808-7.268 9.781 9.781 0 0 1 .33-6.938s2.313-.661 7.433 2.808a23.083 23.083 0 0 1 6.773-.826 30.4 30.4 0 0 1 6.773.826c5.121-3.469 7.433-2.808 7.433-2.808a10.343 10.343 0 0 1 .33 7.1 10.684 10.684 0 0 1 2.815 7.267c0 10.407-6.277 12.554-12.224 13.215.991.826 1.817 2.478 1.817 4.956v7.433c0 .661.5 1.487 1.817 1.322a26.976 26.976 0 0 0-8.755-52.526z"/>
-</svg> \ No newline at end of file
diff --git a/server/sonar-web/public/images/tutorials/jenkins.svg b/server/sonar-web/public/images/tutorials/jenkins.svg
deleted file mode 100644
index 4a4538daf6f..00000000000
--- a/server/sonar-web/public/images/tutorials/jenkins.svg
+++ /dev/null
@@ -1,283 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- id="svg2"
- version="1.1"
- inkscape:version="0.48.0 r9654"
- width="226"
- height="312"
- xml:space="preserve"
- sodipodi:docname="logo.svg"><metadata
- id="metadata8"><rdf:RDF><cc:Work
- rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
- id="defs6"><clipPath
- clipPathUnits="userSpaceOnUse"
- id="clipPath18"><path
- d="M 0,2494.84 0,0 l 1804.34,0 0,2494.84 -1804.34,0 z"
- id="path20"
- inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1"
- objecttolerance="10"
- gridtolerance="10"
- guidetolerance="10"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:window-width="1500"
- inkscape:window-height="844"
- id="namedview4"
- showgrid="false"
- inkscape:zoom="1"
- inkscape:cx="-65.859116"
- inkscape:cy="172.53076"
- inkscape:window-x="2189"
- inkscape:window-y="496"
- inkscape:window-maximized="0"
- inkscape:current-layer="g10" /><g
- id="g10"
- inkscape:groupmode="layer"
- inkscape:label="ink_ext_XXXXXX"
- transform="matrix(1.25,0,0,-1.25,0,312)"><g
- id="g3393"><path
- d="m 177.718,129.264 c 0,-49.4288 -39.175,-89.4992 -87.5,-89.4992 -48.3242,0 -87.49925,40.0704 -87.49925,89.4992 0,49.43 39.17505,89.501 87.49925,89.501 48.325,0 87.5,-40.071 87.5,-89.501"
- style="fill:#d33833;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path22"
- inkscape:connector-curvature="0" /><path
- d="m 6.28438,107.098 c 0,0 -6.33438,93.333 79.66602,96 l -5.9996,10 -46.6664,-15.667 -13.3336,-15.333 -11.66642,-22.334 -6.66719,-26 2,-17.333"
- style="fill:#ef3d3a;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path24"
- inkscape:connector-curvature="0" /><path
- d="M 30.2883,190.319 C 14.9363,174.611 5.43633,152.923 5.43633,128.93 l 0,0 c 0,-23.988 9.49997,-45.6788 24.85197,-61.3839 l 0,0 C 45.6477,51.841 66.8152,42.15 90.2168,42.15 l 0,0 c 23.4022,0 44.5712,9.691 59.9292,25.3961 l 0,0 c 15.351,15.7051 24.853,37.3959 24.853,61.3839 l 0,0 c 0,23.993 -9.502,45.681 -24.853,61.389 l 0,0 c -15.358,15.702 -36.527,25.393 -59.9292,25.395 l 0,0 C 66.8152,215.712 45.6477,206.021 30.2883,190.319 l 0,0 z M 26.4023,63.7469 C 10.0867,80.4328 0,103.493 0,128.93 l 0,0 c 0,25.441 10.0867,48.499 26.4023,65.186 l 0,0 c 16.3118,16.69 38.8915,27.035 63.8145,27.032 l 0,0 c 24.9232,0.003 47.5052,-10.342 63.8142,-27.032 l 0,0 c 16.317,-16.687 26.405,-39.747 26.403,-65.186 l 0,0 c 0.002,-25.437 -10.086,-48.4972 -26.403,-65.1831 l 0,0 C 137.722,47.0578 115.14,36.7141 90.2168,36.7141 l 0,0 c -24.923,0 -47.5027,10.3437 -63.8145,27.0328 l 0,0"
- style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path26"
- inkscape:connector-curvature="0" /><path
- d="m 127.051,128.768 -13.334,-2 -18.0002,-2 -11.6672,-0.333 -11.3328,0.333 -8.6672,2.667 -7.6668,8.333 -6,17 -1.3332,3.667 -8,2.666 -4.6668,7.667 -3.3332,11 3.6672,9.667 8.666,3 7,-3.334 3.334,-7.333 4,0.667 1.3328,1.666 -1.3328,7.667 -0.334,9.667 2,13.333 -0.0781,7.616 6.0781,9.717 10.6668,7.667 18.6672,8 20.6662,-3 18,-13 8.334,-13.333 5.333,-9.667 1.333,-24 -4,-20.667 -7.333,-18.333 -7,-9.667"
- style="fill:#f0d6b7;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path28"
- inkscape:connector-curvature="0" /><path
- d="m 115.717,71.102 -47.6674,-2 0,-8 4,-28 -2,-2.334 -33.3328,11.334 -2.334,4 -3.3332,37.666 -7.6656,22.667 -1.6672,5.333 26.666,18.333 8.334,3.334 7.3328,-9 6.3332,-5.667 7.334,-2.333 3.3328,-1 4,-17.333 3,-3.6668 7.6672,2.6668 -5.334,-10.334 29.0002,-13.666 -3.666,-2"
- style="fill:#335061;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path30"
- inkscape:connector-curvature="0" /><path
- d="m 36.7168,187.435 8.666,3 7,-3.334 3.334,-7.333 4,0.667 1,4 -2,7.666 2,18.334 -1.6672,10 6,7 13,10.333 -3.6668,5 -18.3332,-9 -7.6668,-6 -4.3332,-9.333 -6.6668,-9 -2,-10.667 1.334,-11.333"
- style="fill:#6d6b6d;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path32"
- inkscape:connector-curvature="0" /><path
- d="m 50.3828,218.768 c 0,0 5,12.333 25,18.333 20,6 1,4.334 1,4.334 l -21.666,-8.334 -8.334,-8.333 -3.666,-6.667 7.666,0.667"
- style="fill:#dcd9d8;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path34"
- inkscape:connector-curvature="0" /><path
- d="m 40.3828,189.768 c 0,0 -7,23.334 19.6668,26.667 l -1,4 -18.3328,-4.334 -5.334,-17.333 1.334,-11.333 3.666,2.333"
- style="fill:#dcd9d8;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path36"
- inkscape:connector-curvature="0" /><path
- d="m 51.0496,158.768 4.3645,4.229 c 0,0 1.9699,-0.229 2.3027,-2.562 0.3328,-2.334 1.3328,-23.334 15.666,-34.668 1.3074,-1.034 -10.666,1.668 -10.666,1.668 l -10.6672,16.666"
- style="fill:#f7e4cd;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path38"
- inkscape:connector-curvature="0" /><path
- d="m 112.385,165.101 c 0,0 0.777,10.104 3.498,9.327 2.721,-0.777 2.721,-3.498 2.721,-3.498 0,0 -6.608,-4.275 -6.219,-5.829"
- style="fill:#f7e4cd;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path40"
- inkscape:connector-curvature="0" /><path
- d="m 140.05,202.101 c 0,0 -5.494,-1.16 -6,-6 -0.506,-4.841 6,-1 7,-0.667"
- style="fill:#f7e4cd;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path42"
- inkscape:connector-curvature="0" /><path
- d="m 99.7168,201.767 c 0,0 -7.334,-1 -7.334,-5.666 0,-4.667 8.3342,-4.334 10.6672,-2.334"
- style="fill:#f7e4cd;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path44"
- inkscape:connector-curvature="0" /><path
- d="m 54.3828,180.101 c 0,0 -12.6672,7.667 -14,0.333 -1.3332,-7.333 -4.334,-12.667 2,-20.333 l -4.3332,1.333 -4,10.333 -1.3328,10 7.666,8.001 8.6668,-0.667 5,-4 0.3332,-5"
- style="fill:#f7e4cd;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path46"
- inkscape:connector-curvature="0" /><path
- d="m 60.3828,201.101 c 0,0 5.6668,29.333 34.334,35 23.6012,4.665 35.9992,-1 40.6662,-6.333 0,0 -21,24.999 -41.0002,17.333 -20,-7.667 -34.666,-21.667 -34.3332,-30.666 0.5676,-15.328 0.3332,-15.334 0.3332,-15.334"
- style="fill:#f7e4cd;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path48"
- inkscape:connector-curvature="0" /><path
- d="m 137.717,226.435 c 0,0 -9.666,0.333 -10,-8.334 0,0 -0.001,-1.333 0.666,-2.666 0,0 7.668,8.667 12.334,4"
- style="fill:#f7e4cd;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path50"
- inkscape:connector-curvature="0" /><path
- d="m 95.3887,214.532 c 0,0 -1.6641,13.303 -13.0059,5.569 -7.3332,-5 -6.666,-12 -5.3332,-13.333 1.3332,-1.334 0.9707,-4.019 1.9856,-2.176 1.0144,1.843 0.6804,7.843 4.3476,9.509 3.6668,1.667 9.6777,3.529 12.0059,0.431"
- style="fill:#f7e4cd;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path52"
- inkscape:connector-curvature="0" /><path
- d="m 64.0496,124.435 -31.3328,-14 c 0,0 13,-51.667 6.3328,-67.667 l -4.6668,1.666 -0.3332,19.6672 -8.6656,37.3328 -3.6672,10.334 32.666,21.999 9.6668,-9.332"
- style="fill:#49728b;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path54"
- inkscape:connector-curvature="0" /><path
- d="m 67.2715,95.8578 4.4453,-5.4238 0,-20 -5.334,0 c 0,0 -0.666,14 -0.666,15.6672 0,1.6668 0.666,7.6668 0.666,7.6668"
- style="fill:#49728b;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path56"
- inkscape:connector-curvature="0" /><path
- d="m 67.3828,67.434 -15,-0.666 4.334,-3 10.666,-1.6668"
- style="fill:#49728b;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path58"
- inkscape:connector-curvature="0" /><path
- d="m 118.717,70.768 12.333,0.3332 3,-30.6672 -12.667,-1.666 -2.666,32"
- style="fill:#335061;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path60"
- inkscape:connector-curvature="0" /><path
- d="m 122.05,70.768 18.667,1 c 0,0 7.666,19.3332 7.666,20.3332 0,1 6.667,27.9998 6.667,27.9998 l -15,15.666 -3,2.667 -8,-8 0,-31 -7,-28.666"
- style="fill:#335061;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path62"
- inkscape:connector-curvature="0" /><path
- d="m 130.383,73.1012 -11.666,-2.3332 1.666,-9.334 c 4.333,-2 11.667,3.334 11.667,3.334"
- style="fill:#49728b;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path64"
- inkscape:connector-curvature="0" /><path
- d="m 130.717,131.434 23.333,-17.333 0.667,8 -17.667,16.333 -6.333,-7"
- style="fill:#49728b;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path66"
- inkscape:connector-curvature="0" /><path
- d="M 78.9508,5.09805 72.0496,33.102 68.6172,53.7648 68.0496,69.102 l 31.2348,1.6628 19.4326,0.0032 -1.767,-35.0032 3,-26.99996 -0.333,-5 -25.3326,-2 -15.3336,3.33321"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path68"
- inkscape:connector-curvature="0" /><path
- d="m 114.383,71.1012 c 0,0 -1.666,-34.6672 3.334,-59.3332 0,0 -10,-6.33402 -24.6674,-8.00003 l 28.0004,1 3.333,2 -4,54.66603 -1,11.668"
- style="fill:#dcd9d8;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path70"
- inkscape:connector-curvature="0" /><path
- d="m 134.618,43.098 13,3.6668 24.666,1.3332 3.667,11.3329 -6.667,19.6671 -7.666,1 -10.667,-3.3332 -10.234,-4.9968 -5.433,0.9968 -4.234,-1.6636"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path72"
- inkscape:connector-curvature="0" /><path
- d="m 134.383,49.768 c 0,0 8.666,3.9992 10,3.666 l -3.666,18.334 4.333,1.666 c 0,0 3,-17.3328 3,-19.3328 0,0 18.666,-1 20.333,-1 0,0 4,7.6668 3,15.6668 l 3.667,-10.6668 0.333,-6 -5.333,-8 -6,-1.3332 -10,0.3332 -3.333,4.3328 -11.667,-1.666 -3.667,-1.334"
- style="fill:#dcd9d8;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path74"
- inkscape:connector-curvature="0" /><path
- d="m 121.284,73.4309 -7.333,18.6671 -7.667,11 c 0,0 1.666,4.667 4,4.667 2.334,0 7.667,0 7.667,0 l 7.333,-2.667 -0.666,-12.3332 -3.334,-19.3339"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path76"
- inkscape:connector-curvature="0" /><path
- d="m 122.717,79.768 c 0,0 -9.334,17.9992 -9.334,20.666 0,0 1.666,4 4,3 2.334,-1 7.334,-3.666 7.334,-3.666 l 0,6.333 -11.334,2.334 -7.666,-1 13,-30.667 2.666,-0.334"
- style="fill:#dcd9d8;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path78"
- inkscape:connector-curvature="0" /><path
- d="m 81.9512,123.764 -9.2344,1.004 -8.6672,2.667 0,-3 4.2348,-4.67 13.3332,-6"
- style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="path80"
- inkscape:connector-curvature="0" /><path
- d="m 67.0508,122.765 c 0,0 10.334,-4.334 13.6672,-3.334 l 0.3316,-3.996 -9.3316,1.996 -5.6672,4 1,1.334"
- style="fill:#dcd9d8;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path82"
- inkscape:connector-curvature="0" /><path
- d="m 134.582,106.63 c -5.656,0.166 -10.766,0.838 -15.24,2.1 0.304,1.834 -0.265,3.634 0.192,4.955 1.247,0.898 3.337,0.884 5.222,1.095 -1.63,0.801 -3.92,1.118 -5.801,0.655 -0.044,1.273 -0.615,2.062 -0.961,3.058 3.18,1.135 10.687,8.576 14.91,6.112 2.012,-1.172 2.867,-7.866 3.023,-11.121 0.13,-2.7 -0.245,-5.424 -1.345,-6.854"
- style="fill:#d33833;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path84"
- inkscape:connector-curvature="0" /><path
- d="m 134.582,106.63 c -5.656,0.166 -10.766,0.838 -15.24,2.1 0.304,1.834 -0.265,3.634 0.192,4.955 1.247,0.898 3.337,0.884 5.222,1.095 -1.63,0.801 -3.92,1.118 -5.801,0.655 -0.044,1.273 -0.615,2.062 -0.961,3.058 3.18,1.135 10.687,8.576 14.91,6.112 2.012,-1.172 2.867,-7.866 3.023,-11.121 0.13,-2.7 -0.245,-5.424 -1.345,-6.854 z"
- style="fill:none;stroke:#d33833;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path86"
- inkscape:connector-curvature="0" /><path
- d="m 107.535,115.876 c -0.015,-0.428 -0.033,-0.859 -0.05,-1.291 -1.766,-1.16 -4.617,-1.146 -6.555,-2.121 2.857,-0.125 5.106,-0.813 7.052,-1.783 -0.043,-1.078 -0.084,-2.155 -0.126,-3.233 -3.237,-2.216 -6.194,-5.516 -10.0052,-7.5941 -1.802,-0.9828 -8.1262,-3.5117 -10.0434,-3.0648 -1.0847,0.2519 -1.1824,1.598 -1.616,2.8668 -0.9238,2.7171 -3.0508,7.0421 -3.2363,11.1321 -0.2363,5.166 -0.7578,13.824 4.8094,12.76 4.4914,-0.857 9.7152,-2.926 13.1925,-4.826 2.125,-1.162 3.354,-2.598 6.578,-2.846"
- style="fill:#d33833;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path88"
- inkscape:connector-curvature="0" /><path
- d="m 107.535,115.876 c -0.015,-0.428 -0.033,-0.859 -0.05,-1.291 -1.766,-1.16 -4.617,-1.146 -6.555,-2.121 2.857,-0.125 5.106,-0.813 7.052,-1.783 -0.043,-1.078 -0.084,-2.155 -0.126,-3.233 -3.237,-2.216 -6.194,-5.516 -10.0052,-7.5941 -1.802,-0.9828 -8.1262,-3.5117 -10.0434,-3.0648 -1.0847,0.2519 -1.1824,1.598 -1.616,2.8668 -0.9238,2.7171 -3.0508,7.0421 -3.2363,11.1321 -0.2363,5.166 -0.7578,13.824 4.8094,12.76 4.4914,-0.857 9.7152,-2.926 13.1925,-4.826 2.125,-1.162 3.354,-2.598 6.578,-2.846 z"
- style="fill:none;stroke:#d33833;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path90"
- inkscape:connector-curvature="0" /><path
- d="m 110.75,109.712 c -0.494,2.814 -1.065,3.617 -0.844,6.072 7.505,5.004 8.914,-8.595 0.844,-6.072"
- style="fill:#d33833;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path92"
- inkscape:connector-curvature="0" /><path
- d="m 110.75,109.712 c -0.494,2.814 -1.065,3.617 -0.844,6.072 7.505,5.004 8.914,-8.595 0.844,-6.072 z"
- style="fill:none;stroke:#d33833;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path94"
- inkscape:connector-curvature="0" /><path
- d="m 121.617,107.431 c 0,0 -2.334,3.334 -0.667,4.334 1.667,1 3.334,-0.001 4.334,1.666 1,1.667 0,2.667 0.333,4.667 0.333,2 2.001,2.334 3.667,2.667 1.666,0.333 6.334,1 7,-0.667 l -2,6 -4,1.333 -12.667,-7.333 -0.667,-3.667 0,-7.333"
- style="fill:#ef3d3a;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path96"
- inkscape:connector-curvature="0" /><path
- d="m 86.6172,96.4309 c -0.4004,5.2021 -0.8242,10.3971 -1.2957,15.5941 -0.7055,7.76 1.864,6.406 8.5906,6.406 1.0274,0 6.3259,-1.225 6.7049,-2 1.818,-3.713 -3.04,-2.888 2.094,-5.688 4.334,-2.363 11.99,1.435 10.239,6.688 -0.98,1.168 -5.106,0.364 -6.585,1.131 -2.604,1.35 -5.208,2.7 -7.8123,4.05 -3.3132,1.719 -10.9707,4.225 -14.5031,1.823 -8.9504,-6.087 0.5649,-21.296 3.7578,-27.6459"
- style="fill:#ef3d3a;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path98"
- inkscape:connector-curvature="0" /><path
- d="m 95.3887,214.532 c -9.0852,2.116 -13.5996,-3.802 -16.3535,-9.94 -2.459,0.596 -1.4805,3.94 -0.8594,5.644 1.6262,4.472 8.1797,10.425 13.5344,9.618 2.3043,-0.347 5.4226,-2.454 3.6785,-5.322"
- style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path100"
- inkscape:connector-curvature="0" /><path
- d="m 139.655,204.186 c 0.143,-0.006 0.288,-0.011 0.431,-0.017 2.053,-4.265 3.83,-8.783 6.42,-12.548 -1.735,-4.041 -13.138,-7.617 -12.962,-0.361 2.466,1.078 6.723,0.22 8.909,1.597 -1.264,3.469 -3.088,6.422 -2.798,11.329"
- style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path102"
- inkscape:connector-curvature="0" /><path
- d="m 100.04,204.075 c 1.948,-3.571 2.582,-7.323 5.351,-10.022 1.247,-1.215 3.672,-2.696 2.47,-6.075 -0.281,-0.797 -2.334,-2.574 -3.519,-2.923 -4.329,-1.278 -14.4162,-0.264 -11.0002,5.133 3.5801,-0.167 8.3922,-2.325 11.0682,0.274 -2.055,3.285 -5.7186,9.784 -4.37,13.613"
- style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path104"
- inkscape:connector-curvature="0" /><path
- d="m 138.03,167.781 c -6.518,-4.187 -13.786,-8.74 -24.466,-7.684 -2.282,1.984 -3.152,6.399 -0.935,9.315 1.154,-1.984 0.429,-5.633 3.645,-6.182 6.06,-1.037 13.113,3.707 17.472,5.365 2.703,4.557 -0.233,6.233 -2.668,9.166 -4.985,6.009 -11.672,13.457 -11.429,22.453 2.015,1.461 2.189,-2.23 2.478,-2.902 2.603,-6.092 9.154,-13.883 13.935,-19.097 1.174,-1.284 3.107,-2.516 3.322,-3.365 0.62,-2.469 -1.613,-5.427 -1.354,-7.069"
- style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path106"
- inkscape:connector-curvature="0" /><path
- d="m 52.1016,172.189 c -2.043,1.166 -2.5293,6.302 -4.9278,6.448 -3.4277,0.208 -2.8027,-6.663 -2.789,-10.681 -2.3594,2.142 -2.7743,8.737 -1.041,12.124 -1.9754,0.97 -2.8575,-1.07 -3.9532,-1.789 1.4082,10.23 14.9649,4.745 12.711,-6.102"
- style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path108"
- inkscape:connector-curvature="0" /><path
- d="m 142.18,163.521 c -3.034,-5.775 -7.326,-12.135 -16.229,-12.32 -0.181,1.865 -0.32,4.703 0.01,5.826 6.806,0.654 11.008,4.118 16.219,6.494"
- style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path110"
- inkscape:connector-curvature="0" /><path
- d="m 99.5266,159.777 c 5.6784,-2.986 16.1144,-3.307 23.8324,-3.081 0.414,-1.691 0.404,-3.78 0.42,-5.842 -9.921,-0.495 -21.651,1.96 -24.2524,8.923"
- style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path112"
- inkscape:connector-curvature="0" /><path
- d="m 98.4473,154.209 c 3.9267,-9.859 17.4227,-8.724 28.8037,-8.452 -0.501,-1.28 -1.587,-2.792 -2.937,-3.339 -3.647,-1.484 -13.706,-2.61 -18.769,0.079 -3.211,1.707 -5.274,5.564 -7.0333,7.825 -0.8496,1.092 -5.0801,3.881 -0.0644,3.887"
- style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path114"
- inkscape:connector-curvature="0" /><path
- d="m 137.556,99.8262 c -4.608,-7.8922 -9.017,-15.9981 -14.484,-22.9594 2.292,6.7391 3.273,18.0184 3.619,26.6172 4.795,2.244 8.901,-0.505 10.865,-3.6578"
- style="fill:#81b0c4;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path116"
- inkscape:connector-curvature="0" /><path
- d="m 162.352,71.4609 c -5.159,-1.0328 -8.784,-6.0468 -13.817,-5.725 2.766,3.8993 7.613,5.543 13.817,5.725"
- style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path118"
- inkscape:connector-curvature="0" /><path
- d="m 164.628,63.3871 c -4.205,-0.4441 -9.144,-1.125 -13.409,-0.7742 2.019,3.084 9.798,2.0199 13.409,0.7742"
- style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path120"
- inkscape:connector-curvature="0" /><path
- d="m 166.085,56.4262 c -4.726,-0.1024 -10.6,-0.0082 -15.092,0.3687 2.657,2.8539 12.027,1.059 15.092,-0.3687"
- style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path122"
- inkscape:connector-curvature="0" /><path
- d="m 128.664,37.377 c 0.678,-5.9352 3.031,-11.9489 2.736,-18.4489 -2.613,-0.8812 -4.114,-1.6519 -7.615,-1.6472 -0.247,5.5242 -0.986,13.9691 -0.765,19.2351 1.722,-0.114 4.261,1.2301 5.644,0.861"
- style="fill:#dcd9d8;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path124"
- inkscape:connector-curvature="0" /><path
- d="m 121.045,124.849 c -2.373,-1.549 -4.394,-3.483 -6.673,-5.137 -5.054,-0.25 -7.812,0.35 -11.525,3.252 0.061,0.233 0.434,0.129 0.448,0.415 5.41,-2.411 12.287,0.982 17.75,1.47"
- style="fill:#f0d6b7;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path126"
- inkscape:connector-curvature="0" /><path
- d="m 92.6445,87.9711 c 1.4864,6.441 7.3106,9.7769 12.5995,13.3239 5.459,-6.9282 8.779,-15.838 12.435,-24.436 -8.638,2.6039 -17.464,6.8289 -25.0345,11.1121"
- style="fill:#81b0c4;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path128"
- inkscape:connector-curvature="0" /><path
- d="m 123.02,36.516 c -0.221,-5.266 0.518,-13.7109 0.765,-19.2351 3.501,-0.0047 5.002,0.766 7.615,1.6472 0.295,6.5 -2.058,12.5137 -2.736,18.4489 -1.383,0.3691 -3.922,-0.975 -5.644,-0.861 z M 68.5059,66.4648 C 70.8145,45.2418 74.1582,27.4012 80.291,8.60781 93.9023,4.475 110.311,4.11484 122.342,7.84414 120.133,18.4512 121.098,31.3648 119.807,42.684 c -0.973,8.5078 -0.477,17.068 -1.811,25.748 -14.578,3.0328 -35.1835,0.709 -49.4901,-1.9672 z m 52.9371,1.834 c -0.123,-9.1148 0.408,-18.1058 1.104,-27.232 3.5,0.5254 5.875,0.8762 9.127,1.5891 -1.056,8.7859 -0.926,18.6722 -3.077,26.4441 -2.486,-0.0238 -4.675,0.0289 -7.154,-0.8012 z m 17.755,1.4692 c -1.661,0.3808 -3.595,0.0148 -5.182,-0.016 0.746,-7.4301 2.556,-15.629 3.193,-23.4282 2.497,-0.0777 3.831,1.1 5.885,1.4961 0.11,6.8461 -0.598,16.2781 -3.896,21.9481 z m 26.884,-24.5629 c 5.205,1.264 8.478,7.639 7.022,14.1859 -0.977,4.4 -2.717,12.6852 -4.579,15.5 -1.376,2.082 -5.107,4.8078 -8.086,2.9 -4.846,-3.1031 -13.383,-4.0039 -16.917,-7.7601 1.772,-5.9 2.322,-14.0039 3.053,-21.4797 6.054,-0.3774 13.503,1.666 18.538,-0.5024 -3.515,-1.1386 -8.076,-1.1476 -11.113,-2.807 2.482,-1.1988 8.293,-0.9566 12.082,-0.0367 z M 117.679,76.859 c -3.656,8.598 -6.976,17.5078 -12.435,24.436 C 99.9551,97.748 94.1309,94.4121 92.6445,87.9711 100.215,83.6879 109.041,79.4629 117.679,76.859 z m 9.012,26.625 c -0.346,-8.5988 -1.327,-19.8781 -3.619,-26.6172 5.467,6.9613 9.876,15.0672 14.484,22.9594 -1.964,3.1528 -6.07,5.9018 -10.865,3.6578 z m -10.216,3.63 c -2.071,0.223 -3.829,-2.381 -6.522,-1.255 -0.617,-0.682 -1.178,-1.421 -1.807,-2.087 5.948,-7.1681 8.651,-17.338 13.245,-25.7618 2.465,8.0918 2.181,16.957 2.724,25.7888 -3.387,-0.215 -5.266,3.063 -7.64,3.315 z m -6.569,8.67 c -0.221,-2.455 0.35,-3.258 0.844,-6.072 8.07,-2.523 6.661,11.076 -0.844,6.072 z m -8.949,2.938 c -3.4773,1.9 -8.7011,3.969 -13.1925,4.826 -5.5672,1.065 -5.0457,-7.594 -4.8094,-12.76 0.1855,-4.09 2.3125,-8.415 3.2363,-11.1321 0.4336,-1.2688 0.5313,-2.6149 1.616,-2.8668 1.9172,-0.4469 8.2414,2.082 10.0434,3.0648 3.8112,2.0781 6.7682,5.3781 10.0052,7.5941 0.042,1.078 0.083,2.155 0.126,3.233 -1.946,0.97 -4.195,1.658 -7.052,1.783 1.938,0.975 4.789,0.961 6.555,2.121 0.017,0.432 0.035,0.863 0.05,1.291 -3.224,0.248 -4.453,1.684 -6.578,2.846 z m -33.2136,6.033 c -2.886,-2.93 8.0945,-6.924 11.5906,-7.139 -0.0195,1.854 1.0566,3.602 0.8398,4.932 -4.1523,0.729 -9.6093,0.248 -12.4304,2.207 z m 35.5516,-1.376 c -0.014,-0.286 -0.387,-0.182 -0.448,-0.415 3.713,-2.902 6.471,-3.502 11.525,-3.252 2.279,1.654 4.3,3.588 6.673,5.137 -5.463,-0.488 -12.34,-3.881 -17.75,-1.47 z m 32.632,-9.895 c -0.156,3.255 -1.011,9.949 -3.023,11.121 -4.223,2.465 -11.73,-4.977 -14.91,-6.112 0.346,-0.996 0.917,-1.785 0.961,-3.058 1.881,0.463 4.171,0.146 5.801,-0.655 -1.885,-0.211 -3.975,-0.197 -5.222,-1.095 -0.457,-1.321 0.112,-3.121 -0.192,-4.955 4.474,-1.262 9.584,-1.934 15.24,-2.1 1.1,1.43 1.475,4.154 1.345,6.854 z m -73.0422,8.437 c -0.9063,0.646 -7.0371,8.623 -7.877,8.292 C 43.9141,125.838 33.541,118.273 24.2715,111.118 33.1094,92.1539 36.677,68.9199 37.3074,46.5262 47.4316,41.791 56.3242,34.9648 70.0625,34.252 68.4727,45.5 67.0215,55.5352 66.1191,66.125 c -3.4519,1.4551 -8.4043,-0.066 -11.6347,0.4512 -0.0274,3.8929 4.9336,1.7047 5.3468,4.3226 0.3114,1.9801 -2.7296,2.1301 -1.7394,5.2481 2.5254,-0.918 3.8516,-2.9457 6.5449,-3.7071 2.461,5.384 -0.0344,14.9102 0.3203,19.4102 0.0672,0.8449 0.4219,4.6809 2.3145,4.0078 1.675,-0.5957 -0.0957,-10.2019 0.0879,-14.4609 0.1672,-3.9239 -0.4739,-7.7207 1.1152,-10.184 13.2754,1.807 26.7656,2.975 41.1294,3.3691 -3.16,1.3559 -6.914,2.6391 -11.0298,4.959 -2.2312,1.2578 -9.2644,3.875 -9.9082,5.9942 -1.0273,3.3769 2.6953,5.1757 3.332,8.0707 -6.7011,-3.6547 -8.0085,3.5031 -9.5937,8.5741 -1.4363,4.593 -2.2539,8.024 -2.6063,10.673 -5.7726,2.752 -11.9445,5.539 -16.9132,9.068 z m 67.1792,7.327 c 9.243,4.482 10.909,-16.751 7.286,-23.591 0.56,-2.04 2.486,-2.821 3.272,-4.655 -5.158,-9.2399 -10.887,-17.8649 -16.15,-26.9961 3.915,2.4371 9.507,0.4359 14.114,2.2601 1.684,0.666 2.903,4.5211 4.178,7.6051 3.507,8.4848 7.189,19.1819 8.827,27.2789 0.37,1.845 1.378,5.865 1.152,7.507 -0.403,2.94 -4.392,5.12 -6.421,6.938 -3.738,3.358 -6.092,6.313 -9.991,9.453 -1.581,-2.334 -4.974,-3.902 -6.267,-5.8 z m -88.3179,81.968 c -4.4043,-4.846 -3.4824,-13.926 -2.9492,-20.386 7.9609,5.008 18.5273,-0.396 18.4277,-8.914 3.8008,0.101 1.4199,4.747 0.7324,7.74 -2.2468,9.776 3.7852,20.397 0.2735,29.337 -6.8184,-0.517 -12.42,-3.302 -16.4844,-7.777 z m 31.5137,28.126 c -9.9707,-2.826 -22.7493,-10.071 -26.8465,-19.028 3.1726,0.461 5.375,2.061 8.5047,2.259 1.1828,0.077 2.7324,-0.496 4.0918,-0.158 2.709,0.672 4.9953,6.746 7.039,9.006 1.9922,2.207 4.3867,3.15 6.0254,5.162 1.0528,0.508 2.6094,0.473 2.6692,2.054 -0.4563,0.488 -0.9368,0.86 -1.4836,0.705 z m 51.9032,-2.658 c -10.349,5.839 -27.8661,10.231 -38.8747,4.743 -8.8828,-4.429 -20.8899,-11.757 -24.9836,-21.043 3.8242,-8.961 -1.1328,-17.172 -1.4492,-26.27 -0.168,-4.841 2.2793,-9.067 2.4668,-14.337 -1.3086,-2.159 -5.3067,-2.425 -8.0743,-2.277 -0.9316,4.662 -2.5625,9.902 -7.3632,10.428 -6.793,0.743 -11.7598,-4.879 -12.0684,-10.754 -0.3652,-6.909 5.3066,-18.36 13.3457,-17.565 3.1055,0.307 3.8684,3.42 7.252,3.388 1.8339,-3.659 -2.8289,-4.808 -3.3086,-7.425 -0.125,-0.676 0.3867,-3.318 0.6843,-4.557 1.4602,-6.033 4.7153,-13.841 7.9192,-18.434 4.0664,-5.826 12.0555,-6.704 20.6504,-7.275 1.5351,3.307 7.1902,3.035 10.875,2.17 -4.416,1.749 -8.5215,5.989 -11.9239,9.742 -3.9082,4.306 -7.8671,8.925 -8.0671,14.553 7.3855,-10.246 13.4871,-19.194 26.9168,-23.701 10.1618,-3.408 22.0298,1.562 29.8378,7.045 3.24,2.279 5.174,5.895 7.477,9.205 8.617,12.395 12.638,30.087 11.754,47.235 -0.364,7.072 -0.348,14.12 -2.721,18.878 -2.48,4.975 -10.868,9.426 -15.778,4.926 -0.91,4.838 4.083,7.83 9.948,6.089 -4.182,5.397 -8.571,11.882 -14.515,15.236 z M 144.444,77.1168 c 8.087,4.0203 23.197,10.8211 28.267,-0.0148 1.871,-3.9942 4.066,-10.7461 5.035,-14.8692 1.369,-5.8168 -1.484,-18.043 -7.463,-19.9949 -5.281,-1.7238 -11.443,-1.6188 -17.804,-0.341 -0.749,0.623 -1.583,1.709 -2.166,2.841 -4.542,0.1762 -8.795,-0.2438 -12.383,-2.1109 0.34,-3.359 -1.932,-3.8981 -4.062,-4.5899 -1.579,-6.2609 3.159,-14.4371 2.025,-20.1461 -0.809,-4.0672 -5.813,-4.6961 -9.491,-5.457 -0.12,-2.2602 0.161,-4.14689 0.412,-6.059 -0.841,-3.09883 -4.613,-4.86289 -8.187,-5.29492 -11.759,-1.414064 -29.6133,-2.049221 -40.9239,2.01797 -3.1562,7.74175 -5.6426,17.15785 -8.2715,25.99805 -11.0312,-1.1781 -19.9531,4.7598 -28.364,8.65 -2.9121,1.35 -6.9406,2.0937 -8.0285,4.4117 -1.0547,2.2442 -0.6231,6.5453 -0.8848,10.6082 -0.666,10.377 -1.2363,20.386 -3.9766,31.011 -1.2304,4.7679 -3.375,8.975 -4.8711,13.5691 -1.3828,4.2579 -3.7988,9.5199 -4.4289,13.7659 -0.9343,6.293 4.9914,6.643 8.7805,9.37 5.8574,4.217 10.4551,6.549 16.7988,10.355 1.8789,1.127 7.545,3.98 8.1895,5.294 1.2812,2.605 -2.1992,6.278 -3.1297,8.32 -1.4719,3.229 -2.2395,5.972 -2.4504,9.158 -5.3215,0.841 -9.3555,4.008 -11.7922,7.579 -4.0308,5.91 -6.8262,16.844 -3.3387,25.161 0.2735,0.655 1.6375,1.943 1.8387,2.949 0.3969,1.981 -0.7469,4.615 -0.818,6.722 -0.3664,10.81 1.829,20.124 9.1063,23.384 2.9543,11.769 13.5281,15.682 23.4902,21.531 3.7239,2.186 7.8289,3.583 12.0684,5.143 15.2082,5.597 38.5419,4.543 51.1639,-5.003 5.352,-4.048 13.907,-12.595 16.967,-18.783 8.082,-16.337 7.508,-43.64 1.855,-63.513 -0.76,-2.668 -1.862,-6.59 -3.401,-9.795 -1.073,-2.238 -4.408,-6.716 -4.003,-8.692 0.417,-2.043 7.604,-7.5 9.145,-8.986 2.775,-2.677 8.047,-6.23 8.474,-9.608 0.459,-3.595 -1.584,-8.513 -2.619,-11.982 -3.46,-11.5769 -6.836,-22.2781 -10.759,-32.5992"
- style="fill:#231f20;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path130"
- inkscape:connector-curvature="0" /><path
- d="m 90.491,157.255 c 0.4387,0.584 2.8508,1.471 6.2258,-0.154 0,0 -4,-0.667 -3.6672,-7.336 l -1.6668,0.334 c 0,0 -1.7226,6.047 -0.8918,7.156"
- style="fill:#f7e4cd;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path132"
- inkscape:connector-curvature="0" /><path
- d="m 119.717,99.934 c 0,-1.0121 -0.821,-1.8328 -1.834,-1.8328 -1.012,0 -1.833,0.8207 -1.833,1.8328 0,1.012 0.821,1.834 1.833,1.834 1.013,0 1.834,-0.822 1.834,-1.834"
- style="fill:#1d1919;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path134"
- inkscape:connector-curvature="0" /><path
- d="m 121.55,91.434 c 0,-1.0121 -0.821,-1.8328 -1.834,-1.8328 -1.012,0 -1.833,0.8207 -1.833,1.8328 0,1.0121 0.821,1.834 1.833,1.834 1.013,0 1.834,-0.8219 1.834,-1.834"
- style="fill:#1d1919;fill-opacity:1;fill-rule:evenodd;stroke:none"
- id="path136"
- inkscape:connector-curvature="0" /></g></g></svg> \ No newline at end of file
diff --git a/server/sonar-web/public/images/tutorials/manual.svg b/server/sonar-web/public/images/tutorials/manual.svg
deleted file mode 100644
index 62f9591903e..00000000000
--- a/server/sonar-web/public/images/tutorials/manual.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-<svg width="62" height="76"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <path id="a" d="M0 76h62V0H0z"/>
- </defs>
- <g fill="none" fill-rule="evenodd">
- <path d="M24 37v4.667c0 .597.244 1.194.733 1.65A2.584 2.584 0 0 0 26.5 44c.64 0 1.279-.227 1.767-.684a2.246 2.246 0 0 0 .733-1.65V37" stroke="#236A97" stroke-width="2"/>
- <path d="M28 37v5.714c0 .585.244 1.17.733 1.616.488.447 1.127.67 1.767.67.64 0 1.279-.223 1.767-.67A2.18 2.18 0 0 0 33 42.714V37M33 36.53v14.117c0 .602.244 1.205.733 1.664.488.46 1.127.689 1.767.689.64 0 1.279-.23 1.767-.69A2.273 2.273 0 0 0 38 50.648V33" stroke="#236A97" stroke-width="2"/>
- <path d="M23.8 36.958v3.625c0 .619-.234 1.238-.703 1.709A2.382 2.382 0 0 1 21.4 43a2.382 2.382 0 0 1-1.697-.708A2.414 2.414 0 0 1 19 40.583V23.667L21.4 14h16.8v3.625l4.8 8.458v7.25c0 .619-.234 1.238-.703 1.709a2.382 2.382 0 0 1-1.697.708 2.382 2.382 0 0 1-1.697-.708 2.414 2.414 0 0 1-.703-1.709V28.5M40 0v14H19V0M36 10V8M56 47V29M60 41l-4.5 5-4.5-5M56 26v-2M56 21v-2M6 47V29M10 41l-4.5 5L1 41M6 26v-2M6 21v-2M41.8 54h18c.307 0 .614.114.848.342.234.227.352.526.352.825v18.666c0 .299-.118.598-.352.825A1.214 1.214 0 0 1 59.8 75H2.2c-.307 0-.614-.114-.848-.342A1.147 1.147 0 0 1 1 73.833V55.167c0-.299.118-.598.352-.825.234-.228.54-.342.848-.342h27.6M25 64h2M30 64h2M35 64h2" stroke="#236A97" stroke-width="2"/>
- <mask id="b" fill="#fff">
- <use xlink:href="#a"/>
- </mask>
- <path stroke="#236A97" stroke-width="2" mask="url(#b)" d="M6 70h50V58H6z"/>
- </g>
-</svg> \ No newline at end of file
diff --git a/server/sonar-web/public/images/tutorials/refresh.svg b/server/sonar-web/public/images/tutorials/refresh.svg
deleted file mode 100644
index 04579ae7e54..00000000000
--- a/server/sonar-web/public/images/tutorials/refresh.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28"><g fill="none" fill-rule="evenodd" transform="translate(-4 -4)"><path d="M0 0h36v36H0z"/><path fill="#236A97" fill-rule="nonzero" d="M31.3333333 15.2148148H21.28821l4.0595336-4.1777778c-4.0447178-3.99999996-10.5933086-4.14814811-14.6380264-.1481481-4.04471779 4.0148148-4.04471779 10.4888889 0 14.5037037 4.0447178 4.0148148 10.5933086 4.0148148 14.6380264 0 2.014951-1.9851852 3.0224265-4.3111111 3.0224265-7.2444445h2.9631632c0 2.9333334-1.3037918 6.7407408-3.9113754 9.3185186-5.2003515 5.1555555-13.6453667 5.1555555-18.84571821 0-5.18553566-5.1407408-5.2299831-13.4962963-.02963163-18.63703707 5.20035144-5.14074074 13.54165594-5.14074074 18.74200744 0l4.0447178-4.16296296V15.2148148zm-12.5934437-3.1407407v6.2962963l5.1855356 3.0814815-1.0667387 1.7925925-6.3411693-3.7629629v-7.4074074h2.2223724z"/></g></svg> \ No newline at end of file
diff --git a/server/sonar-web/public/mstile-512x512.png b/server/sonar-web/public/mstile-512x512.png
deleted file mode 100644
index c5f9bac3231..00000000000
--- a/server/sonar-web/public/mstile-512x512.png
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/public/robots.txt b/server/sonar-web/public/robots.txt
deleted file mode 100644
index 06fde6d0680..00000000000
--- a/server/sonar-web/public/robots.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-# We don't want robots to click all Sonar links
-User-agent: *
-Disallow: / \ No newline at end of file
diff --git a/server/sonar-web/scripts/update-cwes.js b/server/sonar-web/scripts/update-cwes.js
deleted file mode 100644
index 63df5390ea9..00000000000
--- a/server/sonar-web/scripts/update-cwes.js
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable no-console */
-
-/**
- * Execute this script by passing the path to the CWE XML definition file.
- *
- * You can download the full CWE database in XML format here: https://cwe.mitre.org/data/downloads.html
- * Make sure to unzip the downloaded file first before passing it to this script.
- *
- * Usage:
- * node scripts/update-cwes.js PATH
- * or:
- * yarn update-cwes PATH
- *
- * Example:
- * node scripts/update-cwes.js ~/Downloads/cwec_v4.6.xml
- * or:
- * yarn update-cwes ~/Downloads/cwec_v4.6.xml
- */
-
-const fs = require('fs');
-const chalk = require('chalk');
-const jsdom = require('jsdom');
-const { trim } = require('lodash');
-const path = require('path');
-
-const STANDARDS_JSON_FILE = path.join(
- __dirname,
- '..',
- 'src',
- 'main',
- 'js',
- 'helpers',
- 'standards.json',
-);
-
-const xmlContent = readXMLContent(process.argv[2]);
-const newCWEs = getCWEs(xmlContent);
-writeToStandardsJson(newCWEs);
-
-function readXMLContent(xmlPath) {
- if (fs.existsSync(xmlPath)) {
- try {
- fs.accessSync(xmlPath, fs.constants.R_OK);
- return fs.readFileSync(xmlPath).toString();
- } catch (e) {
- console.error(chalk.red(`No read access for XML file '${xmlPath}'`));
- throw e;
- }
- } else {
- console.error(chalk.red(`Cannot find XML file '${xmlPath}'`));
- throw Error('');
- }
-}
-
-function getCWEs(xml) {
- const document = new jsdom.JSDOM(xml);
- const weaknesses = document.window.document.querySelectorAll('Weaknesses Weakness');
- const cwes = {
- unknown: {
- title: 'No CWE associated',
- },
- };
-
- weaknesses.forEach((weakness) => {
- const id = weakness.getAttribute('ID');
- const title = weakness.getAttribute('Name');
- let description = '';
-
- if (!id) {
- return;
- }
-
- if (!title) {
- console.log(chalk.yellow(`No Name attribute found for CWE '${id}'. Skipping.`));
- return;
- }
-
- const descriptionEl = weakness.querySelector('Description');
- if (descriptionEl) {
- description = trim(descriptionEl.textContent);
- }
-
- cwes[id] = { title, description };
- });
-
- return cwes;
-}
-
-function writeToStandardsJson(cwes) {
- try {
- fs.accessSync(STANDARDS_JSON_FILE, fs.constants.W_OK);
- } catch (e) {
- console.error(chalk.red(`No write access for standards.json ('${STANDARDS_JSON_FILE}') file`));
- throw e;
- }
-
- try {
- const json = JSON.parse(fs.readFileSync(STANDARDS_JSON_FILE).toString());
- json.cwe = cwes;
- fs.writeFileSync(STANDARDS_JSON_FILE, JSON.stringify(json, undefined, 2));
- } catch (e) {
- console.error(
- chalk.red(`Failed to write data to standards.json ('${STANDARDS_JSON_FILE}') file`),
- );
- throw e;
- }
-}
diff --git a/server/sonar-web/scripts/validate-package-json.js b/server/sonar-web/scripts/validate-package-json.js
deleted file mode 100644
index 9ce80af1831..00000000000
--- a/server/sonar-web/scripts/validate-package-json.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-const { dependencies, devDependencies } = require('../package.json');
-
-const dependenciesArray = Object.entries(dependencies);
-const devDependenciesArray = Object.entries(devDependencies);
-
-const violatingDependencies = [...dependenciesArray, ...devDependenciesArray].filter(
- ([id, version]) => !/^\d+\.\d+\.\d+(-rc\d+)?$/.test(version),
-);
-
-if (violatingDependencies.length > 0) {
- throw new Error(
- `Following dependencies must be locked to an exact version:
-${violatingDependencies.map(([id, version]) => ` - "${id}": "${version}"`).join('\n')}
-`,
- );
-}
diff --git a/server/sonar-web/src/main/js/@types/css.d.ts b/server/sonar-web/src/main/js/@types/css.d.ts
deleted file mode 100644
index c705508154d..00000000000
--- a/server/sonar-web/src/main/js/@types/css.d.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import 'csstype';
-
-declare module 'csstype' {
- interface Properties {
- // Support any CSS Custom Property in style prop of components
- [index: `--${string}`]: string | number;
- }
-}
diff --git a/server/sonar-web/src/main/js/@types/emotion.d.ts b/server/sonar-web/src/main/js/@types/emotion.d.ts
deleted file mode 100644
index 4d80913ad6d..00000000000
--- a/server/sonar-web/src/main/js/@types/emotion.d.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import '@emotion/react';
-import { Theme as SQTheme } from '~design-system';
-
-declare module '@emotion/react' {
- export interface Theme extends SQTheme {}
-}
diff --git a/server/sonar-web/src/main/js/@types/highlightjs-apex.d.ts b/server/sonar-web/src/main/js/@types/highlightjs-apex.d.ts
deleted file mode 100644
index b7b1a7dc2ff..00000000000
--- a/server/sonar-web/src/main/js/@types/highlightjs-apex.d.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-declare module 'highlightjs-apex' {
- import { LanguageFn } from 'highlight.js';
-
- const defineLanguage: LanguageFn;
- // eslint-disable-next-line import/no-default-export
- export default defineLanguage;
-}
diff --git a/server/sonar-web/src/main/js/@types/highlightjs-sap-abap.d.ts b/server/sonar-web/src/main/js/@types/highlightjs-sap-abap.d.ts
deleted file mode 100644
index 1e8c0f4b2c2..00000000000
--- a/server/sonar-web/src/main/js/@types/highlightjs-sap-abap.d.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-declare module 'highlightjs-sap-abap' {
- import { LanguageFn } from 'highlight.js';
-
- const defineLanguage: LanguageFn;
- // eslint-disable-next-line import/no-default-export
- export default defineLanguage;
-}
diff --git a/server/sonar-web/src/main/js/@types/json.d.ts b/server/sonar-web/src/main/js/@types/json.d.ts
deleted file mode 100644
index 9eb9035f5ff..00000000000
--- a/server/sonar-web/src/main/js/@types/json.d.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-declare module '*.json' {
- const value: any;
- export default value;
-}
diff --git a/server/sonar-web/src/main/js/@types/lunr.d.ts b/server/sonar-web/src/main/js/@types/lunr.d.ts
deleted file mode 100644
index 0ac1160ceb0..00000000000
--- a/server/sonar-web/src/main/js/@types/lunr.d.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-declare module 'lunr' {
- export interface Lunr {
- add(doc: any): void;
-
- field(field: string, options?: { boost?: number }): void;
-
- metadataWhitelist?: string[];
-
- ref(field: string): void;
-
- use(fn: Function): void;
- }
-
- export interface LunrBuilder {
- metadataWhitelist: string[];
- pipeline: any;
- }
-
- export interface LunrIndex {
- search(query: string): LunrMatch[];
- }
-
- export interface LunrInit {
- (this: Lunr): void;
- }
-
- export interface LunrMatch {
- matchData: { metadata: any };
- ref: string;
- score: number;
- }
-
- export interface LunrToken {
- metadata: any;
- str: string;
- }
-
- function lunr(initializer: LunrInit): LunrIndex;
-
- export default lunr;
-}
diff --git a/server/sonar-web/src/main/js/@types/md.d.ts b/server/sonar-web/src/main/js/@types/md.d.ts
deleted file mode 100644
index cfacf21e1c6..00000000000
--- a/server/sonar-web/src/main/js/@types/md.d.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-declare module '*.md' {
- const value: string;
- export default value;
-}
diff --git a/server/sonar-web/src/main/js/api/ai-code-assurance.ts b/server/sonar-web/src/main/js/api/ai-code-assurance.ts
deleted file mode 100644
index 1a45230df71..00000000000
--- a/server/sonar-web/src/main/js/api/ai-code-assurance.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-
-export enum AiCodeAssuranceStatus {
- CONTAINS_AI_CODE = 'CONTAINS_AI_CODE',
- AI_CODE_ASSURED = 'AI_CODE_ASSURED',
- NONE = 'NONE',
-}
-
-export function getProjectAiCodeAssuranceStatus(project: string): Promise<AiCodeAssuranceStatus> {
- return getJSON('/api/projects/get_ai_code_assurance', { project })
- .then((response) => response.aiCodeAssurance)
- .catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/alm-integrations.ts b/server/sonar-web/src/main/js/api/alm-integrations.ts
deleted file mode 100644
index 565de5b5659..00000000000
--- a/server/sonar-web/src/main/js/api/alm-integrations.ts
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { get, parseError, post, postJSON } from '../helpers/request';
-import {
- AzureProject,
- AzureRepository,
- BitbucketCloudRepository,
- BitbucketProject,
- BitbucketRepository,
- GithubOrganization,
- GithubRepository,
- GitlabProject,
-} from '../types/alm-integration';
-import { Paging } from '../types/types';
-import { ProjectBase } from './components';
-
-export function setAlmPersonalAccessToken(
- almSetting: string,
- pat: string,
- username?: string,
-): Promise<void> {
- return post('/api/alm_integrations/set_pat', { almSetting, pat, username }).catch(
- throwGlobalError,
- );
-}
-
-export function checkPersonalAccessTokenIsValid(
- almSetting: string,
-): Promise<{ error?: string; status: boolean }> {
- return get('/api/alm_integrations/check_pat', { almSetting })
- .then(() => ({ status: true }))
- .catch(async (response: Response) => {
- if (response.status === 400) {
- const error = await parseError(response);
- return { status: false, error };
- }
- return throwGlobalError(response);
- });
-}
-
-export function getAzureProjects(almSetting: string): Promise<{ projects: AzureProject[] }> {
- return getJSON('/api/alm_integrations/list_azure_projects', { almSetting }).catch(
- throwGlobalError,
- );
-}
-
-export function getAzureRepositories(
- almSetting: string,
- projectName: string,
-): Promise<{ repositories: AzureRepository[] }> {
- return getJSON('/api/alm_integrations/search_azure_repos', { almSetting, projectName }).catch(
- throwGlobalError,
- );
-}
-
-export function searchAzureRepositories(
- almSetting: string,
- searchQuery: string,
-): Promise<{ repositories: AzureRepository[] }> {
- return getJSON('/api/alm_integrations/search_azure_repos', { almSetting, searchQuery }).catch(
- throwGlobalError,
- );
-}
-
-export function setupAzureProjectCreation(data: {
- almSetting: string;
- projectName: string;
- repositoryName: string;
-}) {
- return (newCodeDefinitionType?: string, newCodeDefinitionValue?: string) =>
- importAzureRepository({ ...data, newCodeDefinitionType, newCodeDefinitionValue });
-}
-
-export function importAzureRepository(data: {
- almSetting: string;
- newCodeDefinitionType?: string;
- newCodeDefinitionValue?: string;
- projectName: string;
- repositoryName: string;
-}): Promise<{ project: ProjectBase }> {
- return postJSON('/api/alm_integrations/import_azure_project', data).catch(throwGlobalError);
-}
-
-export function getBitbucketServerProjects(
- almSetting: string,
- start?: number,
- pageSize?: number,
-): Promise<{ isLastPage: boolean; nextPageStart: number; projects: BitbucketProject[] }> {
- return getJSON('/api/alm_integrations/list_bitbucketserver_projects', {
- almSetting,
- pageSize,
- start,
- });
-}
-
-export function getBitbucketServerRepositories(
- almSetting: string,
- projectName?: string,
- repositoryName?: string,
- start?: number,
- pageSize?: number,
-): Promise<{
- isLastPage: boolean;
- nextPageStart: number;
- repositories: BitbucketRepository[];
-}> {
- return getJSON('/api/alm_integrations/search_bitbucketserver_repos', {
- almSetting,
- pageSize,
- projectName,
- repositoryName,
- start,
- });
-}
-
-export function setupBitbucketServerProjectCreation(data: {
- almSetting: string;
- projectKey: string;
- repositorySlug: string;
-}) {
- return (newCodeDefinitionType?: string, newCodeDefinitionValue?: string) =>
- importBitbucketServerProject({ ...data, newCodeDefinitionType, newCodeDefinitionValue });
-}
-
-export function importBitbucketServerProject(data: {
- almSetting: string;
- newCodeDefinitionType?: string;
- newCodeDefinitionValue?: string;
- projectKey: string;
- repositorySlug: string;
-}): Promise<{ project: ProjectBase }> {
- return postJSON('/api/alm_integrations/import_bitbucketserver_project', data).catch(
- throwGlobalError,
- );
-}
-
-export function searchForBitbucketCloudRepositories(
- almSetting: string,
- repositoryName: string,
- pageSize: number,
- page?: number,
-): Promise<{
- isLastPage: boolean;
- repositories: BitbucketCloudRepository[];
-}> {
- return getJSON('/api/alm_integrations/search_bitbucketcloud_repos', {
- almSetting,
- repositoryName,
- p: page,
- ps: pageSize,
- });
-}
-
-export function getGithubClientId(almSetting: string): Promise<{ clientId?: string }> {
- return getJSON('/api/alm_integrations/get_github_client_id', { almSetting });
-}
-
-export function setupBitbucketCloudProjectCreation(data: {
- almSetting: string;
- repositorySlug: string;
-}) {
- return (newCodeDefinitionType?: string, newCodeDefinitionValue?: string) =>
- importBitbucketCloudRepository({ ...data, newCodeDefinitionType, newCodeDefinitionValue });
-}
-
-export function importBitbucketCloudRepository(data: {
- almSetting: string;
- newCodeDefinitionType?: string;
- newCodeDefinitionValue?: string;
- repositorySlug: string;
-}): Promise<{ project: ProjectBase }> {
- return postJSON('/api/alm_integrations/import_bitbucketcloud_repo', data).catch(throwGlobalError);
-}
-
-export function setupGithubProjectCreation(data: {
- almSetting: string;
- organization: string;
- repositoryKey: string;
-}) {
- return (newCodeDefinitionType?: string, newCodeDefinitionValue?: string) =>
- importGithubRepository({ ...data, newCodeDefinitionType, newCodeDefinitionValue });
-}
-
-export function importGithubRepository(data: {
- almSetting: string;
- newCodeDefinitionType?: string;
- newCodeDefinitionValue?: string;
- repositoryKey: string;
-}): Promise<{ project: ProjectBase }> {
- return postJSON('/api/alm_integrations/import_github_project', data).catch(throwGlobalError);
-}
-
-export function getGithubOrganizations(
- almSetting: string,
- token: string,
-): Promise<{ organizations: GithubOrganization[] }> {
- return getJSON('/api/alm_integrations/list_github_organizations', {
- almSetting,
- token,
- }).catch((response?: Response) => {
- if (response && response.status !== 400) {
- throwGlobalError(response);
- }
- });
-}
-
-export function getGithubRepositories(data: {
- almSetting: string;
- organization: string;
- page?: number;
- pageSize: number;
- query?: string;
-}): Promise<{ paging: Paging; repositories: GithubRepository[] }> {
- const { almSetting, organization, pageSize, page = 1, query } = data;
- return getJSON('/api/alm_integrations/list_github_repositories', {
- almSetting,
- organization,
- p: page,
- ps: pageSize,
- q: query || undefined,
- }).catch(throwGlobalError);
-}
-
-export function getGitlabProjects(data: {
- almSetting: string;
- page?: number;
- pageSize?: number;
- query?: string;
-}): Promise<{ projects: GitlabProject[]; projectsPaging: Paging }> {
- const { almSetting, pageSize, page, query } = data;
- return getJSON('/api/alm_integrations/search_gitlab_repos', {
- almSetting,
- projectName: query || undefined,
- p: page,
- ps: pageSize,
- })
- .then(({ repositories, paging }) => ({ projects: repositories, projectsPaging: paging }))
- .catch(throwGlobalError);
-}
-
-export function setupGitlabProjectCreation(data: { almSetting: string; gitlabProjectId: string }) {
- return (newCodeDefinitionType?: string, newCodeDefinitionValue?: string) =>
- importGitlabProject({ ...data, newCodeDefinitionType, newCodeDefinitionValue });
-}
-
-export function importGitlabProject(data: {
- almSetting: string;
- gitlabProjectId: string;
- newCodeDefinitionType?: string;
- newCodeDefinitionValue?: string;
-}): Promise<{ project: ProjectBase }> {
- return postJSON('/api/alm_integrations/import_gitlab_project', data).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/alm-settings.ts b/server/sonar-web/src/main/js/api/alm-settings.ts
deleted file mode 100644
index 04d745c804f..00000000000
--- a/server/sonar-web/src/main/js/api/alm-settings.ts
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { get, HttpStatus, parseError, parseJSON, post } from '../helpers/request';
-import {
- AlmSettingsBindingDefinitions,
- AlmSettingsInstance,
- AzureBindingDefinition,
- AzureProjectAlmBindingParams,
- BitbucketCloudBindingDefinition,
- BitbucketCloudProjectAlmBindingParams,
- BitbucketProjectAlmBindingParams,
- BitbucketServerBindingDefinition,
- GithubBindingDefinition,
- GithubProjectAlmBindingParams,
- GitlabBindingDefinition,
- GitlabProjectAlmBindingParams,
- ProjectAlmBindingConfigurationErrors,
- ProjectAlmBindingResponse,
-} from '../types/alm-settings';
-
-export function getAlmDefinitions(): Promise<AlmSettingsBindingDefinitions> {
- return getJSON('/api/alm_settings/list_definitions');
-}
-
-export function getAlmSettings(project?: string): Promise<AlmSettingsInstance[]> {
- return getAlmSettingsNoCatch(project).catch(throwGlobalError);
-}
-
-export function getAlmSettingsNoCatch(project?: string): Promise<AlmSettingsInstance[]> {
- return getJSON('/api/alm_settings/list', { project }).then(({ almSettings }) => almSettings);
-}
-
-export function validateAlmSettings(key: string): Promise<string> {
- return get('/api/alm_settings/validate', { key })
- .then(() => {
- return '';
- })
- .catch((response: Response) => {
- if (response.status === HttpStatus.BadRequest) {
- return parseError(response);
- } else {
- return throwGlobalError(response);
- }
- });
-}
-
-export function createGithubConfiguration(data: GithubBindingDefinition) {
- return post('/api/alm_settings/create_github', data).catch(throwGlobalError);
-}
-
-export function updateGithubConfiguration(data: GithubBindingDefinition & { newKey: string }) {
- return post('/api/alm_settings/update_github', data).catch(throwGlobalError);
-}
-
-export function createAzureConfiguration(data: AzureBindingDefinition) {
- return post('/api/alm_settings/create_azure', data).catch(throwGlobalError);
-}
-
-export function updateAzureConfiguration(data: AzureBindingDefinition & { newKey: string }) {
- return post('/api/alm_settings/update_azure', data).catch(throwGlobalError);
-}
-
-export function createBitbucketServerConfiguration(data: BitbucketServerBindingDefinition) {
- return post('/api/alm_settings/create_bitbucket', data).catch(throwGlobalError);
-}
-
-export function updateBitbucketServerConfiguration(
- data: BitbucketServerBindingDefinition & { newKey: string },
-) {
- return post('/api/alm_settings/update_bitbucket', data).catch(throwGlobalError);
-}
-
-export function createBitbucketCloudConfiguration(data: BitbucketCloudBindingDefinition) {
- return post('/api/alm_settings/create_bitbucketcloud', data).catch(throwGlobalError);
-}
-
-export function updateBitbucketCloudConfiguration(
- data: BitbucketCloudBindingDefinition & { newKey: string },
-) {
- return post('/api/alm_settings/update_bitbucketcloud', data).catch(throwGlobalError);
-}
-
-export function createGitlabConfiguration(data: GitlabBindingDefinition) {
- return post('/api/alm_settings/create_gitlab', data).catch(throwGlobalError);
-}
-
-export function updateGitlabConfiguration(data: GitlabBindingDefinition & { newKey: string }) {
- return post('/api/alm_settings/update_gitlab', data).catch(throwGlobalError);
-}
-
-export function deleteConfiguration(key: string) {
- return post('/api/alm_settings/delete', { key }).catch(throwGlobalError);
-}
-
-export function countBoundProjects(almSetting: string) {
- return getJSON('/api/alm_settings/count_binding', { almSetting })
- .then(({ projects }) => projects)
- .catch(throwGlobalError);
-}
-
-export function getProjectAlmBinding(project: string): Promise<ProjectAlmBindingResponse> {
- return getJSON('/api/alm_settings/get_binding', { project });
-}
-
-export function deleteProjectAlmBinding(project: string): Promise<void> {
- return post('/api/alm_settings/delete_binding', { project }).catch(throwGlobalError);
-}
-
-export function setProjectAzureBinding(data: AzureProjectAlmBindingParams) {
- return post('/api/alm_settings/set_azure_binding', data).catch(throwGlobalError);
-}
-
-export function setProjectBitbucketBinding(data: BitbucketProjectAlmBindingParams) {
- return post('/api/alm_settings/set_bitbucket_binding', data).catch(throwGlobalError);
-}
-
-export function setProjectBitbucketCloudBinding(data: BitbucketCloudProjectAlmBindingParams) {
- return post('/api/alm_settings/set_bitbucketcloud_binding', data).catch(throwGlobalError);
-}
-
-export function setProjectGithubBinding(data: GithubProjectAlmBindingParams) {
- return post('/api/alm_settings/set_github_binding', data).catch(throwGlobalError);
-}
-
-export function setProjectGitlabBinding(data: GitlabProjectAlmBindingParams) {
- return post('/api/alm_settings/set_gitlab_binding', data).catch(throwGlobalError);
-}
-
-export function validateProjectAlmBinding(
- projectKey: string,
-): Promise<ProjectAlmBindingConfigurationErrors | undefined> {
- return get('/api/alm_settings/validate_binding', { project: projectKey })
- .then(() => undefined)
- .catch((response: Response) => {
- if (response.status === HttpStatus.BadRequest) {
- return parseJSON(response);
- }
- return throwGlobalError(response);
- });
-}
diff --git a/server/sonar-web/src/main/js/api/application.ts b/server/sonar-web/src/main/js/api/application.ts
deleted file mode 100644
index dc35a60c483..00000000000
--- a/server/sonar-web/src/main/js/api/application.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { Visibility } from '~sonar-aligned/types/component';
-import { post, postJSON } from '../helpers/request';
-import { Application, ApplicationPeriod } from '../types/application';
-
-export function getApplicationLeak(
- application: string,
- branch?: string,
-): Promise<ApplicationPeriod[]> {
- return getJSON('/api/applications/show_leak', { application, branch }).then(
- (r) => r.leaks,
- throwGlobalError,
- );
-}
-
-export function getApplicationDetails(application: string, branch?: string): Promise<Application> {
- return getJSON('/api/applications/show', { application, branch }).then(
- (r) => r.application,
- throwGlobalError,
- );
-}
-
-export function createApplication(
- name: string,
- description: string,
- key: string | undefined,
- visibility: string,
-): Promise<{
- application: {
- description?: string;
- key: string;
- name: string;
- visibility: Visibility;
- };
-}> {
- return postJSON('/api/applications/create', { description, key, name, visibility }).catch(
- throwGlobalError,
- );
-}
-
-export function deleteApplication(application: string) {
- return post('/api/applications/delete', { application }).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/auth.ts b/server/sonar-web/src/main/js/api/auth.ts
deleted file mode 100644
index 32a5a9a4bf9..00000000000
--- a/server/sonar-web/src/main/js/api/auth.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { request } from '../helpers/request';
-
-export function logIn(login: string, password: string): Promise<Response> {
- return request('/api/authentication/login')
- .setMethod('POST')
- .setData({ login, password })
- .submit()
- .then(basicCheckStatus);
-}
-
-export function logOut(): Promise<Response> {
- return request('/api/authentication/logout').setMethod('POST').submit().then(basicCheckStatus);
-}
-
-function basicCheckStatus(response: Response): Promise<Response> {
- if (response.status >= 200 && response.status < 300) {
- return Promise.resolve(response);
- } else {
- return Promise.reject(response);
- }
-}
diff --git a/server/sonar-web/src/main/js/api/branches.ts b/server/sonar-web/src/main/js/api/branches.ts
deleted file mode 100644
index 531d7c522a5..00000000000
--- a/server/sonar-web/src/main/js/api/branches.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post } from '../helpers/request';
-import { Branch, PullRequest } from '../types/branch-like';
-
-export function getBranches(project: string): Promise<Branch[]> {
- return getJSON('/api/project_branches/list', { project }).then(
- (r) => r.branches,
- throwGlobalError,
- );
-}
-
-export function getPullRequests(project: string): Promise<PullRequest[]> {
- return getJSON('/api/project_pull_requests/list', { project }).then(
- (r) => r.pullRequests,
- throwGlobalError,
- );
-}
-
-export function deleteBranch(data: { branch: string; project: string }) {
- return post('/api/project_branches/delete', data).catch(throwGlobalError);
-}
-
-export function deletePullRequest(data: { project: string; pullRequest: string }) {
- return post('/api/project_pull_requests/delete', data).catch(throwGlobalError);
-}
-
-export function renameBranch(project: string, name: string) {
- return post('/api/project_branches/rename', { project, name }).catch(throwGlobalError);
-}
-
-export function excludeBranchFromPurge(projectKey: string, branchName: string, excluded: boolean) {
- return post('/api/project_branches/set_automatic_deletion_protection', {
- project: projectKey,
- branch: branchName,
- value: excluded,
- }).catch(throwGlobalError);
-}
-
-export function setMainBranch(project: string, branch: string) {
- return post('/api/project_branches/set_main', { project, branch }).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/ce.ts b/server/sonar-web/src/main/js/api/ce.ts
deleted file mode 100644
index ed6b049e723..00000000000
--- a/server/sonar-web/src/main/js/api/ce.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post } from '../helpers/request';
-import { IndexationStatus } from '../types/indexation';
-import { ActivityRequestParameters, Task, TaskWarning } from '../types/tasks';
-import { Paging } from '../types/types';
-
-export function getAnalysisStatus(data: {
- branch?: string;
- component: string;
- pullRequest?: string;
-}): Promise<{
- component: {
- branch?: string;
- key: string;
- name: string;
- pullRequest?: string;
- warnings: TaskWarning[];
- };
-}> {
- return getJSON('/api/ce/analysis_status', data).catch(throwGlobalError);
-}
-
-export function getActivity(
- data: ActivityRequestParameters,
-): Promise<{ paging: Paging; tasks: Task[] }> {
- return getJSON('/api/ce/activity', data);
-}
-
-export function getStatus(
- component?: string,
-): Promise<{ failing: number; inProgress: number; pending: number; pendingTime?: number }> {
- return getJSON('/api/ce/activity_status', { component });
-}
-
-export function getTask(id: string, additionalFields?: string[]): Promise<Task> {
- return getJSON('/api/ce/task', { id, additionalFields }).then((r) => r.task);
-}
-
-export function cancelTask(id: string): Promise<any> {
- return post('/api/ce/cancel', { id }).then(
- () => getTask(id),
- () => getTask(id),
- );
-}
-
-export function cancelAllTasks(): Promise<any> {
- return post('/api/ce/cancel_all');
-}
-
-export function getTasksForComponent(
- component: string,
-): Promise<{ current?: Task; queue: Task[] }> {
- return getJSON('/api/ce/component', { component }).catch(throwGlobalError);
-}
-
-export function getTypes(): Promise<string[]> {
- return getJSON('/api/ce/task_types').then((r) => r.taskTypes);
-}
-
-export function getWorkers(): Promise<{ canSetWorkerCount: boolean; value: number }> {
- return getJSON('/api/ce/worker_count').catch(throwGlobalError);
-}
-
-export function setWorkerCount(count: number): Promise<void | Response> {
- return post('/api/ce/set_worker_count', { count }).catch(throwGlobalError);
-}
-
-export function getIndexationStatus(): Promise<IndexationStatus> {
- return getJSON('/api/ce/indexation_status').catch(throwGlobalError);
-}
-
-export function dismissAnalysisWarning(component: string, warning: string) {
- return post('/api/ce/dismiss_analysis_warning', { component, warning }).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/component-report.ts b/server/sonar-web/src/main/js/api/component-report.ts
deleted file mode 100644
index f540d92c2c8..00000000000
--- a/server/sonar-web/src/main/js/api/component-report.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post } from '../helpers/request';
-import { getBaseUrl } from '../helpers/system';
-import { ComponentReportStatus } from '../types/component-report';
-
-export function getReportStatus(
- componentKey: string,
- branchKey?: string,
-): Promise<ComponentReportStatus> {
- return getJSON('/api/governance_reports/status', { componentKey, branchKey }).catch(
- throwGlobalError,
- );
-}
-
-export function getReportUrl(componentKey: string, branchKey?: string): string {
- let url = `${getBaseUrl()}/api/governance_reports/download?componentKey=${encodeURIComponent(
- componentKey,
- )}`;
-
- if (branchKey) {
- url += `&branchKey=${branchKey}`;
- }
-
- return url;
-}
-
-export function subscribeToEmailReport(
- componentKey: string,
- branchKey?: string,
-): Promise<void | Response> {
- return post('/api/governance_reports/subscribe', { componentKey, branchKey }).catch(
- throwGlobalError,
- );
-}
-
-export function unsubscribeFromEmailReport(
- componentKey: string,
- branchKey?: string,
-): Promise<void | Response> {
- return post('/api/governance_reports/unsubscribe', { componentKey, branchKey }).catch(
- throwGlobalError,
- );
-}
diff --git a/server/sonar-web/src/main/js/api/components.ts b/server/sonar-web/src/main/js/api/components.ts
deleted file mode 100644
index c9483e53c0b..00000000000
--- a/server/sonar-web/src/main/js/api/components.ts
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { ComponentQualifier, Visibility } from '~sonar-aligned/types/component';
-import { RequestData, post } from '../helpers/request';
-import { TreeComponent, TreeComponentWithPath } from '../types/component';
-import {
- ComponentMeasure,
- Dict,
- DuplicatedFile,
- Duplication,
- Metric,
- MyProject,
- Paging,
- SourceLine,
- SourceViewerFile,
-} from '../types/types';
-import { AiCodeAssuranceStatus } from './ai-code-assurance';
-
-export interface BaseSearchProjectsParameters {
- analyzedBefore?: string;
- onProvisionedOnly?: boolean;
- projects?: string;
- q?: string;
- qualifiers?: string;
- visibility?: Visibility;
-}
-
-export interface ProjectBase {
- key: string;
- name: string;
- qualifier: string;
- visibility: Visibility;
-}
-
-export interface ComponentRaw {
- aiCodeAssurance?: AiCodeAssuranceStatus;
- analysisDate?: string;
- isAiCodeFixEnabled?: boolean;
- isFavorite?: boolean;
- key: string;
- leakPeriodDate?: string;
- name: string;
- needIssueSync?: boolean;
- qualifier: ComponentQualifier;
- tags: string[];
- visibility: Visibility;
-}
-
-export function searchProjectTags(data?: { ps?: number; q?: string }): Promise<any> {
- return getJSON('/api/project_tags/search', data).catch(throwGlobalError);
-}
-
-export function setApplicationTags(data: { application: string; tags: string }): Promise<void> {
- return post('/api/applications/set_tags', data);
-}
-
-export function setProjectTags(data: { project: string; tags: string }): Promise<void> {
- return post('/api/project_tags/set', data);
-}
-
-export function getComponentTree(
- strategy: string,
- component: string,
- metrics: string[] = [],
- additional: RequestData = {},
-): Promise<{
- baseComponent: ComponentMeasure;
- components: ComponentMeasure[];
- metrics: Metric[];
- paging: Paging;
-}> {
- const url = '/api/measures/component_tree';
- const data = { ...additional, component, metricKeys: metrics.join(','), strategy };
- return getJSON(url, data).catch(throwGlobalError);
-}
-
-export function getComponent(
- data: { component: string; metricKeys: string } & BranchParameters,
-): Promise<{ component: ComponentMeasure }> {
- return getJSON('/api/measures/component', data);
-}
-
-export type GetTreeParams = {
- asc?: boolean;
- component: string;
- p?: number;
- ps?: number;
- q?: string;
- s?: string;
- strategy?: 'all' | 'leaves' | 'children';
-} & BranchParameters;
-
-export function getTree<T = TreeComponent>(
- data: GetTreeParams & { qualifiers?: string },
-): Promise<{ baseComponent: TreeComponent; components: T[]; paging: Paging }> {
- return getJSON('/api/components/tree', data).catch(throwGlobalError);
-}
-
-export function getFiles(data: GetTreeParams) {
- return getTree<TreeComponentWithPath>({ ...data, qualifiers: 'FIL' });
-}
-
-export function getDirectories(data: GetTreeParams) {
- return getTree<TreeComponentWithPath>({ ...data, qualifiers: 'DIR' });
-}
-
-export function getComponentData(data: { component: string } & BranchParameters): Promise<{
- ancestors: Array<Omit<ComponentRaw, 'tags'>>;
- component: Omit<ComponentRaw, 'tags'>;
-}> {
- return getJSON('/api/components/show', data);
-}
-
-export function doesComponentExists(
- data: { component: string } & BranchParameters,
-): Promise<boolean> {
- return getComponentData(data).then(
- ({ component }) => component !== undefined,
- () => false,
- );
-}
-
-export function getComponentShow(data: { component: string } & BranchParameters): Promise<any> {
- return getComponentData(data).catch(throwGlobalError);
-}
-
-export function getBreadcrumbs(
- data: { component: string } & BranchParameters,
-): Promise<Array<Omit<ComponentRaw, 'tags'>>> {
- return getComponentShow(data).then((r) => {
- const reversedAncestors = [...r.ancestors].reverse();
- return [...reversedAncestors, r.component];
- });
-}
-
-export function getMyProjects(data: {
- p?: number;
- ps?: number;
-}): Promise<{ paging: Paging; projects: MyProject[] }> {
- return getJSON('/api/projects/search_my_projects', data);
-}
-
-export interface Facet {
- property: string;
- values: Array<{ count: number; val: string }>;
-}
-
-export function searchProjects(data: RequestData): Promise<{
- components: ComponentRaw[];
- facets: Facet[];
- paging: Paging;
-}> {
- const url = '/api/components/search_projects';
- return getJSON(url, data);
-}
-
-export function searchComponents(data?: {
- ps?: number;
- q?: string;
- qualifiers?: string;
-}): Promise<any> {
- return getJSON('/api/components/search', data);
-}
-
-export function changeKey(data: { from: string; to: string }) {
- return post('/api/projects/update_key', data).catch(throwGlobalError);
-}
-
-export interface SuggestionsResponse {
- projects: Array<{ key: string; name: string }>;
- results: Array<{
- items: Array<{
- isFavorite: boolean;
- isRecentlyBrowsed: boolean;
- key: string;
- match: string;
- name: string;
- project: string;
- }>;
- more: number;
- q: string;
- }>;
- warning?: string;
-}
-
-export function getSuggestions(
- query?: string,
- recentlyBrowsed?: string[],
- more?: string,
-): Promise<SuggestionsResponse> {
- const data: RequestData = {};
- if (query) {
- data.s = query;
- }
- if (recentlyBrowsed) {
- data.recentlyBrowsed = recentlyBrowsed.join();
- }
- if (more) {
- data.more = more;
- }
- return getJSON('/api/components/suggestions', data).catch(throwGlobalError);
-}
-
-export function getComponentForSourceViewer(
- data: { component: string } & BranchParameters,
-): Promise<SourceViewerFile> {
- return getJSON('/api/components/app', data);
-}
-
-export function getSources(
- data: { from?: number; key: string; to?: number } & BranchParameters,
-): Promise<SourceLine[]> {
- return getJSON('/api/sources/lines', data).then((r) => r.sources);
-}
-
-export function getDuplications(
- data: { key: string } & BranchParameters,
-): Promise<{ duplications: Duplication[]; files: Dict<DuplicatedFile> }> {
- return getJSON('/api/duplications/show', data).catch(throwGlobalError);
-}
-
-export function getTests(
- data: { sourceFileKey: string; sourceFileLineNumber: number | string } & BranchParameters,
-): Promise<any> {
- return getJSON('/api/tests/list', data).then((r) => r.tests);
-}
-
-interface ProjectResponse {
- key: string;
- name: string;
-}
-
-export function getScannableProjects(): Promise<{ projects: ProjectResponse[] }> {
- return getJSON('/api/projects/search_my_scannable_projects').catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/cves.ts b/server/sonar-web/src/main/js/api/cves.ts
deleted file mode 100644
index 91ca28f0a6c..00000000000
--- a/server/sonar-web/src/main/js/api/cves.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import axios from 'axios';
-import { Cve } from '../types/cves';
-
-const CVE_BASE_URL = '/api/v2/analysis/cves';
-
-export function getCve(cveId: string): Promise<Cve> {
- return axios.get(`${CVE_BASE_URL}/${cveId}`);
-}
diff --git a/server/sonar-web/src/main/js/api/dependencies.ts b/server/sonar-web/src/main/js/api/dependencies.ts
deleted file mode 100644
index 58c3129179a..00000000000
--- a/server/sonar-web/src/main/js/api/dependencies.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import axios from 'axios';
-import { BranchLikeParameters } from '../sonar-aligned/types/branch-like';
-import { DependenciesResponse } from '../types/dependencies';
-
-const DEPENDENCY_PATH = '/api/v2/analysis/dependencies';
-
-export function getDependencies({
- pageParam,
- projectKey,
- q,
- ...branchParameters
-}: { pageParam: number; projectKey: string; q?: string } & BranchLikeParameters) {
- const params = {
- pageIndex: pageParam,
- projectKey,
- q,
- ...branchParameters,
- };
- return axios.get<DependenciesResponse>(DEPENDENCY_PATH, { params });
-}
diff --git a/server/sonar-web/src/main/js/api/dop-translation.ts b/server/sonar-web/src/main/js/api/dop-translation.ts
deleted file mode 100644
index ad5e5b7093d..00000000000
--- a/server/sonar-web/src/main/js/api/dop-translation.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import axios from 'axios';
-import {
- BoundProject,
- DopSetting,
- GitHubConfigurationPayload,
- GitHubConfigurationResponse,
- ProjectBinding,
-} from '../types/dop-translation';
-import { Paging } from '../types/types';
-
-const DOP_TRANSLATION_PATH = '/api/v2/dop-translation';
-const BOUND_PROJECTS_PATH = `${DOP_TRANSLATION_PATH}/bound-projects`;
-const DOP_SETTINGS_PATH = `${DOP_TRANSLATION_PATH}/dop-settings`;
-const PROJECT_BINDINGS_PATH = `${DOP_TRANSLATION_PATH}/project-bindings`;
-const GITHUB_CONFIGURATIONS_PATH = `${DOP_TRANSLATION_PATH}/github-configurations`;
-
-export function createBoundProject(data: BoundProject) {
- return axios.post(BOUND_PROJECTS_PATH, data);
-}
-
-export function getDopSettings() {
- return axios.get<{ dopSettings: DopSetting[]; page: Paging }>(DOP_SETTINGS_PATH);
-}
-
-export function getProjectBindings(data: {
- dopSettingId?: string;
- pageIndex?: number;
- pageSize?: number;
- repository?: string;
-}) {
- return axios.get<{ page: Paging; projectBindings: ProjectBinding[] }>(PROJECT_BINDINGS_PATH, {
- params: data,
- });
-}
-
-export function searchGitHubConfigurations() {
- return axios.get<{ githubConfigurations: GitHubConfigurationResponse[]; page: Paging }>(
- GITHUB_CONFIGURATIONS_PATH,
- );
-}
-
-export function fetchGitHubConfiguration(id: string) {
- return axios.get<GitHubConfigurationResponse>(`${GITHUB_CONFIGURATIONS_PATH}/${id}`);
-}
-
-export function createGitHubConfiguration(gitHubConfiguration: GitHubConfigurationPayload) {
- return axios.post<GitHubConfigurationResponse, GitHubConfigurationPayload>(
- GITHUB_CONFIGURATIONS_PATH,
- gitHubConfiguration,
- );
-}
-
-export function updateGitHubConfiguration(
- id: string,
- gitHubConfiguration: Partial<GitHubConfigurationPayload>,
-) {
- return axios.patch<GitHubConfigurationResponse>(
- `${GITHUB_CONFIGURATIONS_PATH}/${id}`,
- gitHubConfiguration,
- );
-}
-
-export function deleteGitHubConfiguration(id: string) {
- return axios.delete(`${GITHUB_CONFIGURATIONS_PATH}/${id}`);
-}
diff --git a/server/sonar-web/src/main/js/api/editions.ts b/server/sonar-web/src/main/js/api/editions.ts
deleted file mode 100644
index 2e3c2025b00..00000000000
--- a/server/sonar-web/src/main/js/api/editions.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { License } from '../types/editions';
-
-export function isValidLicense(): Promise<{ isValidLicense: boolean }> {
- return getJSON('/api/editions/is_valid_license');
-}
-
-export function showLicense(): Promise<License> {
- return getJSON('/api/editions/show_license').catch((response: Response) => {
- if (response && response.status === 404) {
- return undefined;
- }
- return throwGlobalError(response);
- });
-}
diff --git a/server/sonar-web/src/main/js/api/favorites.ts b/server/sonar-web/src/main/js/api/favorites.ts
deleted file mode 100644
index 5f0e90a4aae..00000000000
--- a/server/sonar-web/src/main/js/api/favorites.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post } from '../helpers/request';
-
-export function getFavorites(): Promise<any> {
- return getJSON('/api/favorites/search');
-}
-
-export function addFavorite(component: string): Promise<void> {
- return post('/api/favorites/add', { component });
-}
-
-export function removeFavorite(component: string): Promise<void> {
- return post('/api/favorites/remove', { component });
-}
diff --git a/server/sonar-web/src/main/js/api/features.ts b/server/sonar-web/src/main/js/api/features.ts
deleted file mode 100644
index e1e518781a2..00000000000
--- a/server/sonar-web/src/main/js/api/features.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { Feature } from '../types/features';
-
-export function getAvailableFeatures(): Promise<Feature[]> {
- return getJSON('/api/features/list');
-}
diff --git a/server/sonar-web/src/main/js/api/fix-suggestions.ts b/server/sonar-web/src/main/js/api/fix-suggestions.ts
deleted file mode 100644
index d3c374e3fe5..00000000000
--- a/server/sonar-web/src/main/js/api/fix-suggestions.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { axiosToCatch } from '../helpers/request';
-import { AiCodeFixFeatureEnablement, SuggestedFix } from '../types/fix-suggestions';
-
-export interface FixParam {
- issueId: string;
-}
-
-export interface AiIssue {
- aiSuggestion: 'AVAILABLE' | 'NOT_AVAILABLE_FILE_LEVEL_ISSUE' | 'NOT_AVAILABLE_UNSUPPORTED_RULE';
- id: string;
-}
-
-export type SuggestionServiceStatus =
- | 'SUCCESS'
- | 'TIMEOUT'
- | 'UNAUTHORIZED'
- | 'CONNECTION_ERROR'
- | 'SERVICE_ERROR';
-
-export type SubscriptionType = 'EARLY_ACCESS' | 'PAID' | 'NOT_PAID';
-
-export interface ServiceInfo {
- isEnabled?: boolean;
- status: SuggestionServiceStatus;
- subscriptionType?: SubscriptionType;
-}
-
-export interface UpdateFeatureEnablementParams {
- changes: {
- disabledProjectKeys: string[];
- enabledProjectKeys: string[];
- };
- enablement: AiCodeFixFeatureEnablement;
-}
-
-export function getSuggestions(data: FixParam): Promise<SuggestedFix> {
- return axiosToCatch.post<SuggestedFix>('/api/v2/fix-suggestions/ai-suggestions', data);
-}
-
-export function getFixSuggestionsIssues(data: FixParam): Promise<AiIssue> {
- return axiosToCatch.get(`/api/v2/fix-suggestions/issues/${data.issueId}`);
-}
-
-export function getFixSuggestionServiceInfo(): Promise<ServiceInfo> {
- return axiosToCatch.get(`/api/v2/fix-suggestions/service-info`);
-}
-
-export function updateFeatureEnablement(
- featureEnablementParams: UpdateFeatureEnablementParams,
-): Promise<void> {
- return axiosToCatch.patch(`/api/v2/fix-suggestions/feature-enablements`, featureEnablementParams);
-}
diff --git a/server/sonar-web/src/main/js/api/github-provisioning.ts b/server/sonar-web/src/main/js/api/github-provisioning.ts
deleted file mode 100644
index cebc5010068..00000000000
--- a/server/sonar-web/src/main/js/api/github-provisioning.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import axios from 'axios';
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post, postJSON } from '../helpers/request';
-import { DevopsRolesMapping, GitHubConfigurationStatus, GithubStatus } from '../types/provisioning';
-
-const GITHUB_PERMISSION_MAPPINGS = '/api/v2/dop-translation/github-permission-mappings';
-
-export function fetchGithubProvisioningStatus(): Promise<GithubStatus> {
- return getJSON('/api/github_provisioning/status').catch(throwGlobalError);
-}
-
-export function checkConfigurationValidity(): Promise<GitHubConfigurationStatus> {
- return postJSON('/api/github_provisioning/check').catch(throwGlobalError);
-}
-
-export function syncNowGithubProvisioning(): Promise<void> {
- return post('/api/github_provisioning/sync').catch(throwGlobalError);
-}
-
-export function fetchGithubRolesMapping() {
- return axios
- .get<{ permissionMappings: DevopsRolesMapping[] }>(GITHUB_PERMISSION_MAPPINGS)
- .then((data) => data.permissionMappings);
-}
-
-export function updateGithubRolesMapping(
- role: string,
- data: Partial<Pick<DevopsRolesMapping, 'permissions'>>,
-) {
- return axios.patch<DevopsRolesMapping>(
- `${GITHUB_PERMISSION_MAPPINGS}/${encodeURIComponent(role)}`,
- data,
- );
-}
-
-export function addGithubRolesMapping(data: Omit<DevopsRolesMapping, 'id'>) {
- return axios.post<DevopsRolesMapping>(GITHUB_PERMISSION_MAPPINGS, data);
-}
-
-export function deleteGithubRolesMapping(role: string) {
- return axios.delete(`${GITHUB_PERMISSION_MAPPINGS}/${encodeURIComponent(role)}`);
-}
diff --git a/server/sonar-web/src/main/js/api/gitlab-provisioning.ts b/server/sonar-web/src/main/js/api/gitlab-provisioning.ts
deleted file mode 100644
index 14335c8ec04..00000000000
--- a/server/sonar-web/src/main/js/api/gitlab-provisioning.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import axios from 'axios';
-import {
- DevopsRolesMapping,
- GitLabConfigurationCreateBody,
- GitLabConfigurationUpdateBody,
- GitlabConfiguration,
- ProvisioningType,
-} from '../types/provisioning';
-import { Paging } from '../types/types';
-
-const GITLAB_CONFIGURATIONS = '/api/v2/dop-translation/gitlab-configurations';
-const GITLAB_PERMISSION_MAPPINGS = '/api/v2/dop-translation/gitlab-permission-mappings';
-
-export function fetchGitLabConfigurations() {
- return axios.get<{ gitlabConfigurations: GitlabConfiguration[]; page: Paging }>(
- GITLAB_CONFIGURATIONS,
- );
-}
-
-export function fetchGitLabConfiguration(id: string): Promise<GitlabConfiguration> {
- return axios.get<GitlabConfiguration>(`${GITLAB_CONFIGURATIONS}/${id}`);
-}
-
-export function createGitLabConfiguration(
- data: GitLabConfigurationCreateBody,
-): Promise<GitlabConfiguration> {
- return axios.post(GITLAB_CONFIGURATIONS, {
- ...data,
- provisioningType: ProvisioningType.jit,
- allowedGroups: [],
- allowUsersToSignUp: false,
- enabled: true,
- });
-}
-
-export function updateGitLabConfiguration(
- id: string,
- data: Partial<GitLabConfigurationUpdateBody>,
-) {
- return axios.patch<GitlabConfiguration>(`${GITLAB_CONFIGURATIONS}/${id}`, data);
-}
-
-export function deleteGitLabConfiguration(id: string): Promise<void> {
- return axios.delete(`${GITLAB_CONFIGURATIONS}/${id}`);
-}
-
-export function syncNowGitLabProvisioning(): Promise<void> {
- return axios.post('/api/v2/dop-translation/gitlab-synchronization-runs');
-}
-
-export function fetchGitlabRolesMapping() {
- return axios
- .get<{ permissionMappings: DevopsRolesMapping[] }>(GITLAB_PERMISSION_MAPPINGS)
- .then((data) => data.permissionMappings);
-}
-
-export function updateGitlabRolesMapping(
- role: string,
- data: Partial<Pick<DevopsRolesMapping, 'permissions'>>,
-) {
- return axios.patch<DevopsRolesMapping>(
- `${GITLAB_PERMISSION_MAPPINGS}/${encodeURIComponent(role)}`,
- data,
- );
-}
-
-export function addGitlabRolesMapping(data: Omit<DevopsRolesMapping, 'id'>) {
- return axios.post<DevopsRolesMapping>(GITLAB_PERMISSION_MAPPINGS, data);
-}
-
-export function deleteGitlabRolesMapping(role: string) {
- return axios.delete(`${GITLAB_PERMISSION_MAPPINGS}/${encodeURIComponent(role)}`);
-}
diff --git a/server/sonar-web/src/main/js/api/group-memberships.ts b/server/sonar-web/src/main/js/api/group-memberships.ts
deleted file mode 100644
index 310f7b7a193..00000000000
--- a/server/sonar-web/src/main/js/api/group-memberships.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import axios from 'axios';
-import { GroupMembership, Paging } from '../types/types';
-
-const GROUPS_MEMBERSHIPS_ENDPOINT = '/api/v2/authorizations/group-memberships';
-
-export function getGroupMemberships(data: {
- groupId?: string;
- pageIndex?: number;
- pageSize?: number;
- userId?: string;
-}) {
- return axios.get<{ groupMemberships: GroupMembership[]; page: Paging }>(
- GROUPS_MEMBERSHIPS_ENDPOINT,
- { params: data },
- );
-}
-
-export function addGroupMembership(data: { groupId: string; userId: string }) {
- return axios.post<GroupMembership>(GROUPS_MEMBERSHIPS_ENDPOINT, data);
-}
-
-export function removeGroupMembership(id: string) {
- return axios.delete(`${GROUPS_MEMBERSHIPS_ENDPOINT}/${id}`);
-}
diff --git a/server/sonar-web/src/main/js/api/issue-filters.ts b/server/sonar-web/src/main/js/api/issue-filters.ts
deleted file mode 100644
index 0a115b85dbd..00000000000
--- a/server/sonar-web/src/main/js/api/issue-filters.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { post } from '../helpers/request';
-
-export function toggleIssueFilter(id: string): Promise<void> {
- return post('/issues/toggle_fav', { id });
-}
diff --git a/server/sonar-web/src/main/js/api/issues.ts b/server/sonar-web/src/main/js/api/issues.ts
deleted file mode 100644
index 050acb32f53..00000000000
--- a/server/sonar-web/src/main/js/api/issues.ts
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import getCoverageStatus from '../components/SourceViewer/helpers/getCoverageStatus';
-import { get, HttpStatus, parseJSON, post, postJSON, RequestData } from '../helpers/request';
-import {
- FacetName,
- IssueResponse,
- IssueSeverity,
- ListIssuesResponse,
- RawIssuesResponse,
-} from '../types/issues';
-import { Dict, FacetValue, IssueChangelog, SnippetsByComponent, SourceLine } from '../types/types';
-
-export function searchIssues(query: RequestData): Promise<RawIssuesResponse> {
- return getJSON('/api/issues/search', query).catch(throwGlobalError);
-}
-
-export function listIssues(query: RequestData): Promise<ListIssuesResponse> {
- return getJSON('/api/issues/list', query).catch(throwGlobalError);
-}
-
-export function getFacets(
- query: RequestData,
- facets: FacetName[],
-): Promise<{
- facets: Array<{ property: string; values: FacetValue[] }>;
- response: RawIssuesResponse;
-}> {
- const data = {
- ...query,
- facets: facets.join(),
- ps: 1,
- additionalFields: '_all',
- };
- return searchIssues(data).then((r) => {
- return { facets: r.facets, response: r };
- });
-}
-
-export function getFacet(
- query: RequestData,
- facet: FacetName,
-): Promise<{ facet: { count: number; val: string }[]; response: RawIssuesResponse }> {
- return getFacets(query, [facet]).then((r) => {
- return { facet: r.facets[0].values, response: r.response };
- });
-}
-
-export function searchIssueTags(data: {
- all?: boolean;
- branch?: string;
- project?: string;
- ps?: number;
- q?: string;
-}): Promise<string[]> {
- return getJSON('/api/issues/tags', data)
- .then((r) => r.tags)
- .catch(throwGlobalError);
-}
-
-export function getIssueChangelog(issue: string): Promise<{ changelog: IssueChangelog[] }> {
- return getJSON('/api/issues/changelog', { issue }).catch(throwGlobalError);
-}
-
-export function getIssueFilters() {
- return getJSON('/api/issue_filters/search').then((r) => r.issueFilters);
-}
-
-export function addIssueComment(data: { issue: string; text: string }): Promise<IssueResponse> {
- return postJSON('/api/issues/add_comment', data);
-}
-
-export function deleteIssueComment(data: { comment: string }): Promise<IssueResponse> {
- return postJSON('/api/issues/delete_comment', data);
-}
-
-export function editIssueComment(data: { comment: string; text: string }): Promise<IssueResponse> {
- return postJSON('/api/issues/edit_comment', data);
-}
-
-export function setIssueAssignee(data: {
- assignee?: string;
- issue: string;
-}): Promise<IssueResponse> {
- return postJSON('/api/issues/assign', data);
-}
-
-export function setIssueSeverity(data: {
- impact?: string;
- issue: string;
- severity?: IssueSeverity;
-}): Promise<IssueResponse> {
- return postJSON('/api/issues/set_severity', data);
-}
-
-export function setIssueTags(data: { issue: string; tags: string }): Promise<IssueResponse> {
- return postJSON('/api/issues/set_tags', data);
-}
-
-export function setIssueTransition(data: {
- issue: string;
- transition: string;
-}): Promise<IssueResponse> {
- return postJSON('/api/issues/do_transition', data);
-}
-
-export function setIssueType(data: { issue: string; type: string }): Promise<IssueResponse> {
- return postJSON('/api/issues/set_type', data);
-}
-
-export function bulkChangeIssues(issueKeys: string[], query: RequestData): Promise<void> {
- return post('/api/issues/bulk_change', { issues: issueKeys.join(), ...query });
-}
-
-export function searchIssueAuthors(data: {
- project?: string;
- ps?: number;
- q?: string;
-}): Promise<string[]> {
- return getJSON('/api/issues/authors', data).then((r) => r.authors, throwGlobalError);
-}
-
-export function getIssueFlowSnippets(issueKey: string): Promise<Dict<SnippetsByComponent>> {
- return get('/api/sources/issue_snippets', { issueKey })
- .then((r) => {
- if (r.status === HttpStatus.NoContent) {
- return {} as any;
- }
- return parseJSON(r);
- })
- .then((result) => {
- Object.keys(result).forEach((k) => {
- if (result[k].sources) {
- result[k].sources = result[k].sources.reduce(
- (lineMap: Dict<SourceLine>, line: SourceLine) => {
- line.coverageStatus = getCoverageStatus(line);
- lineMap[line.line] = line;
- return lineMap;
- },
- {},
- );
- }
- });
- return result;
- });
-}
diff --git a/server/sonar-web/src/main/js/api/l10n.ts b/server/sonar-web/src/main/js/api/l10n.ts
deleted file mode 100644
index ee1ae273fd4..00000000000
--- a/server/sonar-web/src/main/js/api/l10n.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { L10nBundleRequestParams, L10nBundleRequestResponse } from '../types/l10nBundle';
-
-export function fetchL10nBundle(
- params: L10nBundleRequestParams,
-): Promise<L10nBundleRequestResponse> {
- return getJSON('/api/l10n/index', params);
-}
diff --git a/server/sonar-web/src/main/js/api/languages.ts b/server/sonar-web/src/main/js/api/languages.ts
deleted file mode 100644
index f23cf1d6e75..00000000000
--- a/server/sonar-web/src/main/js/api/languages.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { Language } from '../types/languages';
-
-export function getLanguages(): Promise<Language[]> {
- return getJSON('/api/languages/list').then((r) => r.languages, throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/measures.ts b/server/sonar-web/src/main/js/api/measures.ts
deleted file mode 100644
index 84fc70b5341..00000000000
--- a/server/sonar-web/src/main/js/api/measures.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import {
- MeasuresAndMetaWithMetrics,
- MeasuresAndMetaWithPeriod,
- MeasuresForProjects,
-} from '../types/measures';
-import { Measure } from '../types/types';
-
-const COMPONENT_URL = '/api/measures/component';
-
-export function getMeasures(
- data: { component: string; metricKeys: string } & BranchParameters,
-): Promise<Measure[]> {
- return getJSON(COMPONENT_URL, data).then((r) => r.component.measures, throwGlobalError);
-}
-
-export function getMeasuresWithPeriodAndMetrics(
- component: string,
- metrics: string[],
- branchParameters?: BranchParameters,
-): Promise<MeasuresAndMetaWithPeriod & MeasuresAndMetaWithMetrics> {
- return getJSON(COMPONENT_URL, {
- additionalFields: 'period,metrics',
- component,
- metricKeys: metrics.join(','),
- ...branchParameters,
- }).catch(throwGlobalError);
-}
-
-export function getMeasuresForProjects(
- projectKeys: string[],
- metricKeys: string[],
-): Promise<MeasuresForProjects[]> {
- return getJSON('/api/measures/search', {
- projectKeys: projectKeys.join(),
- metricKeys: metricKeys.join(),
- }).then((r) => r.measures);
-}
diff --git a/server/sonar-web/src/main/js/api/messages.ts b/server/sonar-web/src/main/js/api/messages.ts
deleted file mode 100644
index deee9b7a5b7..00000000000
--- a/server/sonar-web/src/main/js/api/messages.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post } from '../helpers/request';
-
-export enum MessageTypes {
- GlobalNcd90 = 'GLOBAL_NCD_90',
- GlobalNcdPage90 = 'GLOBAL_NCD_PAGE_90',
- ProjectNcd90 = 'PROJECT_NCD_90',
- ProjectNcdPage90 = 'PROJECT_NCD_PAGE_90',
- BranchNcd90 = 'BRANCH_NCD_90',
- UnresolvedFindingsInAIGeneratedCode = 'UNRESOLVED_FINDINGS_IN_AI_GENERATED_CODE',
-}
-
-export interface MessageDismissParams {
- messageType: MessageTypes;
- projectKey?: string;
-}
-
-export function checkMessageDismissed(data: MessageDismissParams): Promise<{
- dismissed: boolean;
-}> {
- return getJSON('/api/dismiss_message/check', data).catch(throwGlobalError);
-}
-
-export function setMessageDismissed(data: MessageDismissParams): Promise<void> {
- return post('/api/dismiss_message/dismiss', data).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/metrics.ts b/server/sonar-web/src/main/js/api/metrics.ts
deleted file mode 100644
index 1645e946e6f..00000000000
--- a/server/sonar-web/src/main/js/api/metrics.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { Metric } from '../types/types';
-
-export interface MetricsResponse {
- metrics: Metric[];
- p: number;
- ps: number;
- total: number;
-}
-
-export function getMetrics(data?: {
- isCustom?: boolean;
- p?: number;
- ps?: number;
-}): Promise<MetricsResponse> {
- return getJSON('/api/metrics/search', data).catch(throwGlobalError);
-}
-
-export function getAllMetrics(data?: {
- isCustom?: boolean;
- p?: number;
- ps?: number;
-}): Promise<Metric[]> {
- return inner(data);
-
- function inner(
- data: { p?: number; ps?: number } = { ps: 500 },
- prev?: MetricsResponse,
- ): Promise<Metric[]> {
- return getMetrics(data).then((r) => {
- const result = prev ? prev.metrics.concat(r.metrics) : r.metrics;
- if (r.p * r.ps >= r.total) {
- return result;
- }
- return inner({ ...data, p: r.p + 1 }, { ...r, metrics: result });
- });
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/AiCodeAssuredServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/AiCodeAssuredServiceMock.ts
deleted file mode 100644
index 825b48c2ea9..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/AiCodeAssuredServiceMock.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { AiCodeAssuranceStatus, getProjectAiCodeAssuranceStatus } from '../ai-code-assurance';
-
-jest.mock('../ai-code-assurance');
-
-export const PROJECT_WITH_AI_ASSURED_QG = 'Sonar AI way';
-export const PROJECT_WITHOUT_AI_ASSURED_QG = 'Sonar way';
-
-export class AiCodeAssuredServiceMock {
- noAiProject = 'no-ai';
-
- constructor() {
- jest
- .mocked(getProjectAiCodeAssuranceStatus)
- .mockImplementation(this.handleProjectAiGeneratedCode);
- }
-
- handleProjectAiGeneratedCode = (project: string) => {
- if (project === PROJECT_WITH_AI_ASSURED_QG) {
- return Promise.resolve(AiCodeAssuranceStatus.AI_CODE_ASSURED);
- } else if (project === PROJECT_WITHOUT_AI_ASSURED_QG) {
- return Promise.resolve(AiCodeAssuranceStatus.CONTAINS_AI_CODE);
- }
- return Promise.resolve(AiCodeAssuranceStatus.NONE);
- };
-
- reset() {
- this.noAiProject = 'no-ai';
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/AlmIntegrationsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/AlmIntegrationsServiceMock.ts
deleted file mode 100644
index 2c3848c4f4d..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/AlmIntegrationsServiceMock.ts
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep, uniqueId } from 'lodash';
-import { Visibility } from '~sonar-aligned/types/component';
-import {
- mockAzureProject,
- mockAzureRepository,
- mockBitbucketCloudRepository,
- mockBitbucketProject,
- mockBitbucketRepository,
- mockGitHubRepository,
- mockGitlabProject,
-} from '../../helpers/mocks/alm-integrations';
-import {
- AzureProject,
- AzureRepository,
- BitbucketCloudRepository,
- BitbucketProject,
- BitbucketRepository,
- GithubRepository,
- GitlabProject,
-} from '../../types/alm-integration';
-import { Paging } from '../../types/types';
-import {
- checkPersonalAccessTokenIsValid,
- getAzureProjects,
- getAzureRepositories,
- getBitbucketServerProjects,
- getBitbucketServerRepositories,
- getGithubClientId,
- getGithubOrganizations,
- getGithubRepositories,
- getGitlabProjects,
- importAzureRepository,
- importBitbucketCloudRepository,
- importBitbucketServerProject,
- importGithubRepository,
- importGitlabProject,
- searchAzureRepositories,
- searchForBitbucketCloudRepositories,
- setAlmPersonalAccessToken,
- setupAzureProjectCreation,
- setupBitbucketCloudProjectCreation,
- setupBitbucketServerProjectCreation,
- setupGithubProjectCreation,
- setupGitlabProjectCreation,
-} from '../alm-integrations';
-
-function createUniqueNumber() {
- return Math.floor(Date.now() * Math.random());
-}
-
-export default class AlmIntegrationsServiceMock {
- almInstancePATMap: { [key: string]: boolean } = {};
- gitlabProjects: GitlabProject[];
- azureProjects: AzureProject[];
- azureRepositories: AzureRepository[];
- githubRepositories: GithubRepository[];
- pagination: Paging;
- bitbucketCloudRepositories: BitbucketCloudRepository[];
- bitbucketProjectsIsLastPage: boolean;
- bitbucketReposIsLastPage: boolean;
- bitbucketRepositories: BitbucketRepository[];
- bitbucketProjects: BitbucketProject[];
- defaultAlmInstancePATMap: { [key: string]: boolean } = {
- 'conf-final-1': false,
- 'conf-final-2': true,
- 'conf-github-1': false,
- 'conf-github-2': true,
- 'conf-azure-1': false,
- 'conf-azure-2': true,
- 'conf-bitbucketcloud-1': false,
- 'conf-bitbucketcloud-2': true,
- 'conf-bitbucketserver-1': false,
- 'conf-bitbucketserver-2': true,
- };
-
- defaultGitlabProjects: GitlabProject[] = [
- mockGitlabProject({
- name: 'Gitlab project 1',
- id: '1',
- sqProjectKey: 'key',
- sqProjectName: 'Gitlab project 1',
- slug: 'Gitlab_project_1',
- }),
- mockGitlabProject({ name: 'Gitlab project 2', id: '2', slug: 'Gitlab_project_2' }),
- mockGitlabProject({ name: 'Gitlab project 3', id: '3', slug: 'Gitlab_project_3' }),
- ];
-
- defaultPagination = {
- pageIndex: 1,
- pageSize: 30,
- total: 30,
- };
-
- defaultAzureProjects: AzureProject[] = [
- mockAzureProject({ name: 'Azure project', description: 'Description project 1' }),
- mockAzureProject({ name: 'Azure project 2', description: 'Description project 2' }),
- ];
-
- defaultBitbucketCloudRepositories: BitbucketCloudRepository[] = [
- mockBitbucketCloudRepository({
- uuid: 1000,
- name: 'BitbucketCloud Repo 1',
- slug: 'bitbucketcloud_repo_1',
- sqProjectKey: 'key',
- }),
- mockBitbucketCloudRepository({
- uuid: 10001,
- name: 'BitbucketCloud Repo 2',
- slug: 'bitbucketcloud_repo_2',
- }),
- ];
-
- defaultBitbucketRepositories: BitbucketRepository[] = [
- mockBitbucketRepository({
- name: 'Bitbucket Repo 1',
- slug: 'bitbucket_repo_1',
- projectKey: 'bitbucket_project_1',
- sqProjectKey: 'key',
- }),
- mockBitbucketRepository({
- id: 2,
- name: 'Bitbucket Repo 2',
- slug: 'bitbucket_repo_2',
- projectKey: 'bitbucket_project_1',
- }),
- ];
-
- defaultBitbucketProjects: BitbucketProject[] = [
- mockBitbucketProject({ name: 'Bitbucket Project 1', key: 'bitbucket_project_1' }),
- mockBitbucketProject({ name: 'Bitbucket Project 2', key: 'bitbucket_project_2' }),
- ];
-
- defaultAzureRepositories: AzureRepository[] = [
- mockAzureRepository({ sqProjectKey: 'random', projectName: 'Azure project' }),
- mockAzureRepository({ name: 'Azure repo 2', projectName: 'Azure project' }),
- mockAzureRepository({ name: 'Azure repo 3', projectName: 'Azure project 2' }),
- ];
-
- defaultGithubRepositories: GithubRepository[] = [
- mockGitHubRepository({ name: 'Github repo 1', sqProjectKey: 'key123' }),
- mockGitHubRepository({
- name: 'Github repo 2',
- id: 'id1231',
- key: 'key1231',
- }),
- ];
-
- defaultOrganizations = {
- paging: {
- pageIndex: 1,
- pageSize: 100,
- total: 1,
- },
- organizations: [
- {
- key: 'org-1',
- name: 'org-1',
- },
- ],
- };
-
- constructor() {
- this.almInstancePATMap = cloneDeep(this.defaultAlmInstancePATMap);
- this.azureProjects = cloneDeep(this.defaultAzureProjects);
- this.azureRepositories = cloneDeep(this.defaultAzureRepositories);
- this.bitbucketCloudRepositories = cloneDeep(this.defaultBitbucketCloudRepositories);
- this.gitlabProjects = cloneDeep(this.defaultGitlabProjects);
- this.pagination = cloneDeep(this.defaultPagination);
- this.githubRepositories = cloneDeep(this.defaultGithubRepositories);
- this.bitbucketRepositories = cloneDeep(this.defaultBitbucketRepositories);
- this.bitbucketProjects = cloneDeep(this.defaultBitbucketProjects);
- this.bitbucketProjectsIsLastPage = true;
- this.bitbucketReposIsLastPage = true;
- jest
- .mocked(checkPersonalAccessTokenIsValid)
- .mockImplementation(this.checkPersonalAccessTokenIsValid);
- jest.mocked(setAlmPersonalAccessToken).mockImplementation(this.setAlmPersonalAccessToken);
- jest.mocked(getGitlabProjects).mockImplementation(this.getGitlabProjects);
- jest.mocked(setupGitlabProjectCreation).mockReturnValue(() => this.importProject());
- jest.mocked(importGitlabProject).mockImplementation(this.importProject);
- jest.mocked(setupBitbucketCloudProjectCreation).mockReturnValue(() => this.importProject());
- jest.mocked(importBitbucketCloudRepository).mockImplementation(this.importProject);
- jest.mocked(getGithubClientId).mockImplementation(this.getGithubClientId);
- jest.mocked(getGithubOrganizations).mockImplementation(this.getGithubOrganizations);
- jest.mocked(getAzureProjects).mockImplementation(this.getAzureProjects);
- jest.mocked(getAzureRepositories).mockImplementation(this.getAzureRepositories);
- jest.mocked(getGithubRepositories).mockImplementation(this.getGithubRepositories);
- jest.mocked(searchAzureRepositories).mockImplementation(this.searchAzureRepositories);
- jest.mocked(setupAzureProjectCreation).mockReturnValue(() => this.importAzureRepository());
- jest.mocked(importAzureRepository).mockImplementation(this.importAzureRepository);
- jest.mocked(setupGithubProjectCreation).mockReturnValue(() => this.importGithubRepository());
- jest.mocked(importGithubRepository).mockImplementation(this.importGithubRepository);
- jest
- .mocked(searchForBitbucketCloudRepositories)
- .mockImplementation(this.searchForBitbucketCloudRepositories);
- jest.mocked(getBitbucketServerProjects).mockImplementation(this.getBitbucketServerProjects);
- jest
- .mocked(getBitbucketServerRepositories)
- .mockImplementation(this.getBitbucketServerRepositories);
- jest.mocked(importBitbucketServerProject).mockImplementation(this.importBitbucketServerProject);
- jest
- .mocked(setupBitbucketServerProjectCreation)
- .mockReturnValue(() => this.importBitbucketServerProject());
- }
-
- checkPersonalAccessTokenIsValid = (conf: string) => {
- return Promise.resolve({ status: this.almInstancePATMap[conf] });
- };
-
- setAlmPersonalAccessToken = (conf: string) => {
- this.almInstancePATMap[conf] = true;
- return Promise.resolve();
- };
-
- getAzureProjects = () => {
- return Promise.resolve({ projects: this.azureProjects });
- };
-
- getAzureRepositories: typeof getAzureRepositories = (_, projectName) => {
- return Promise.resolve({
- repositories: this.azureRepositories.filter((repo) => repo.projectName === projectName),
- });
- };
-
- searchAzureRepositories: typeof searchAzureRepositories = (_, searchQuery) => {
- return Promise.resolve({
- repositories: this.azureRepositories.filter((repo) => repo.name.includes(searchQuery)),
- });
- };
-
- setSearchAzureRepositories = (azureRepositories: AzureRepository[]) => {
- this.azureRepositories = azureRepositories;
- };
-
- importAzureRepository = () => {
- return Promise.resolve({
- project: {
- key: 'key',
- name: 'name',
- qualifier: 'qualifier',
- visibility: Visibility.Private,
- },
- });
- };
-
- searchForBitbucketCloudRepositories = () => {
- return Promise.resolve({
- isLastPage: this.bitbucketReposIsLastPage,
- repositories: this.bitbucketCloudRepositories,
- });
- };
-
- setBitbucketCloudRepositories(bitbucketCloudRepositories: BitbucketCloudRepository[]) {
- this.bitbucketCloudRepositories = bitbucketCloudRepositories;
- }
-
- getGitlabProjects = () => {
- return Promise.resolve({
- projects: this.gitlabProjects,
- projectsPaging: this.pagination,
- });
- };
-
- importProject = () => {
- return Promise.resolve({
- project: {
- key: 'key',
- name: 'name',
- qualifier: 'qualifier',
- visibility: Visibility.Private,
- },
- });
- };
-
- createRandomGitlabProjectsWithLoadMore(quantity: number, total: number) {
- const generatedProjects = Array.from(Array(quantity).keys()).map((index) => {
- return mockGitlabProject({ name: `Gitlab project ${index}`, id: uniqueId() });
- });
- this.gitlabProjects = generatedProjects;
- this.pagination = { ...this.defaultPagination, total };
- }
-
- createRandomBitbucketCloudProjectsWithLoadMore(quantity: number, total: number) {
- const generatedRepositories = Array.from(Array(quantity).keys()).map((index) => {
- return mockBitbucketCloudRepository({
- name: `Gitlab project ${index}`,
- uuid: createUniqueNumber(),
- });
- });
-
- this.bitbucketCloudRepositories = generatedRepositories;
- this.bitbucketReposIsLastPage = quantity >= total;
- }
-
- createRandomGithubRepositoriessWithLoadMore(quantity: number, total: number) {
- const generatedProjects = Array.from(Array(quantity).keys()).map(() => {
- const id = uniqueId();
- return mockGitHubRepository({
- name: `Github repo ${id}`,
- key: `key_${id}`,
- id,
- });
- });
- this.githubRepositories = generatedProjects;
- this.pagination = { ...this.defaultPagination, total };
- }
-
- importGithubRepository = () => {
- return Promise.resolve({
- project: {
- key: 'key',
- name: 'name',
- qualifier: 'qualifier',
- visibility: Visibility.Private,
- },
- });
- };
-
- getGithubRepositories = () => {
- return Promise.resolve({
- repositories: this.githubRepositories,
- paging: this.pagination,
- });
- };
-
- setGithubRepositories(githubProjects: GithubRepository[]) {
- this.githubRepositories = githubProjects;
- }
-
- setGitlabProjects(gitlabProjects: GitlabProject[]) {
- this.gitlabProjects = gitlabProjects;
- }
-
- getGithubClientId = () => {
- return Promise.resolve({ clientId: 'clientId' });
- };
-
- getGithubOrganizations = () => {
- return Promise.resolve(this.defaultOrganizations);
- };
-
- getBitbucketServerProjects = () => {
- return Promise.resolve({
- isLastPage: this.bitbucketProjectsIsLastPage,
- nextPageStart: this.bitbucketProjects.length - Number(this.bitbucketProjectsIsLastPage),
- projects: this.bitbucketProjects,
- });
- };
-
- getBitbucketServerRepositories = () => {
- return Promise.resolve({
- isLastPage: this.bitbucketReposIsLastPage,
- nextPageStart: this.bitbucketRepositories.length - Number(this.bitbucketReposIsLastPage),
- repositories: this.bitbucketRepositories,
- });
- };
-
- setBitbucketServerProjects = (bitbucketProjects: BitbucketProject[]) => {
- this.bitbucketProjects = bitbucketProjects;
- };
-
- importBitbucketServerProject = () => {
- return Promise.resolve({
- project: {
- key: 'key',
- name: 'name',
- qualifier: 'qualifier',
- visibility: Visibility.Private,
- },
- });
- };
-
- reset = () => {
- this.almInstancePATMap = cloneDeep(this.defaultAlmInstancePATMap);
- this.gitlabProjects = cloneDeep(this.defaultGitlabProjects);
- this.azureRepositories = cloneDeep(this.defaultAzureRepositories);
- this.pagination = cloneDeep(this.defaultPagination);
- this.bitbucketCloudRepositories = cloneDeep(this.defaultBitbucketCloudRepositories);
- this.bitbucketRepositories = cloneDeep(this.defaultBitbucketRepositories);
- this.bitbucketProjects = cloneDeep(this.defaultBitbucketProjects);
- this.bitbucketProjectsIsLastPage = true;
- this.bitbucketReposIsLastPage = true;
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/AlmSettingsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/AlmSettingsServiceMock.ts
deleted file mode 100644
index e701e92f6e4..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/AlmSettingsServiceMock.ts
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { mockAlmSettingsInstance } from '../../helpers/mocks/alm-settings';
-import {
- AlmKeys,
- AlmSettingsBindingDefinitions,
- AlmSettingsInstance,
- AzureBindingDefinition,
- AzureProjectAlmBindingParams,
- BitbucketCloudBindingDefinition,
- BitbucketCloudProjectAlmBindingParams,
- BitbucketProjectAlmBindingParams,
- BitbucketServerBindingDefinition,
- GithubBindingDefinition,
- GithubProjectAlmBindingParams,
- GitlabBindingDefinition,
- GitlabProjectAlmBindingParams,
- ProjectAlmBindingConfigurationErrors,
- ProjectAlmBindingParams,
- ProjectAlmBindingResponse,
-} from '../../types/alm-settings';
-import {
- countBoundProjects,
- createAzureConfiguration,
- createBitbucketCloudConfiguration,
- createBitbucketServerConfiguration,
- createGithubConfiguration,
- createGitlabConfiguration,
- deleteConfiguration,
- deleteProjectAlmBinding,
- getAlmDefinitions,
- getAlmSettings,
- getAlmSettingsNoCatch,
- getProjectAlmBinding,
- setProjectAzureBinding,
- setProjectBitbucketBinding,
- setProjectBitbucketCloudBinding,
- setProjectGithubBinding,
- setProjectGitlabBinding,
- updateAzureConfiguration,
- updateBitbucketCloudConfiguration,
- updateBitbucketServerConfiguration,
- updateGithubConfiguration,
- updateGitlabConfiguration,
- validateAlmSettings,
- validateProjectAlmBinding,
-} from '../alm-settings';
-
-const defaultAlmDefinitions = {
- [AlmKeys.Azure]: [],
- [AlmKeys.BitbucketServer]: [],
- [AlmKeys.BitbucketCloud]: [],
- [AlmKeys.GitHub]: [],
- [AlmKeys.GitLab]: [],
-};
-
-const defaultAlmSettings = [
- mockAlmSettingsInstance({ key: 'conf-final-1', alm: AlmKeys.GitLab }),
- mockAlmSettingsInstance({ key: 'conf-final-2', alm: AlmKeys.GitLab }),
- mockAlmSettingsInstance({ key: 'conf-github-1', alm: AlmKeys.GitHub, url: 'http://url' }),
- mockAlmSettingsInstance({ key: 'conf-github-2', alm: AlmKeys.GitHub, url: 'http://url' }),
- mockAlmSettingsInstance({ key: 'conf-github-3', alm: AlmKeys.GitHub, url: 'javascript://url' }),
- mockAlmSettingsInstance({ key: 'conf-azure-1', alm: AlmKeys.Azure, url: 'url' }),
- mockAlmSettingsInstance({ key: 'conf-azure-2', alm: AlmKeys.Azure, url: 'url' }),
- mockAlmSettingsInstance({
- key: 'conf-bitbucketcloud-1',
- alm: AlmKeys.BitbucketCloud,
- url: 'url',
- }),
- mockAlmSettingsInstance({
- key: 'conf-bitbucketcloud-2',
- alm: AlmKeys.BitbucketCloud,
- url: 'url',
- }),
- mockAlmSettingsInstance({
- key: 'conf-bitbucketserver-1',
- alm: AlmKeys.BitbucketServer,
- url: 'url',
- }),
- mockAlmSettingsInstance({
- key: 'conf-bitbucketserver-2',
- alm: AlmKeys.BitbucketServer,
- url: 'url',
- }),
-];
-
-interface EnhancedProjectAlmBindingParam extends ProjectAlmBindingParams {
- projectName?: string;
- repository?: string;
- repositoryName?: string;
- slug?: string;
- summaryCommentEnabled?: boolean;
-}
-
-jest.mock('../alm-settings');
-
-export default class AlmSettingsServiceMock {
- #almDefinitions: AlmSettingsBindingDefinitions;
- #almSettings: AlmSettingsInstance[];
- #definitionError = '';
- #projectsBindings: { [key: string]: ProjectAlmBindingResponse | undefined } = {};
- #projectBindingConfigurationErrors: ProjectAlmBindingConfigurationErrors | undefined = undefined;
-
- constructor() {
- this.#almSettings = cloneDeep(defaultAlmSettings);
- this.#almDefinitions = cloneDeep(defaultAlmDefinitions);
- jest.mocked(getAlmSettings).mockImplementation(this.handleGetAlmSettings);
- jest.mocked(getAlmSettingsNoCatch).mockImplementation(this.handleGetAlmSettings);
- jest.mocked(getAlmDefinitions).mockImplementation(this.handleGetAlmDefinitions);
- jest.mocked(countBoundProjects).mockImplementation(this.handleCountBoundProjects);
- jest.mocked(validateAlmSettings).mockImplementation(this.handleValidateAlmSettings);
- jest.mocked(deleteConfiguration).mockImplementation(this.handleDeleteConfiguration);
- jest.mocked(createGithubConfiguration).mockImplementation(this.handleCreateGithubConfiguration);
- jest.mocked(createGitlabConfiguration).mockImplementation(this.handleCreateGitlabConfiguration);
- jest.mocked(createAzureConfiguration).mockImplementation(this.handleCreateAzureConfiguration);
- jest
- .mocked(createBitbucketServerConfiguration)
- .mockImplementation(this.handleCreateBitbucketServerConfiguration);
- jest
- .mocked(createBitbucketCloudConfiguration)
- .mockImplementation(this.handleCreateBitbucketCloudConfiguration);
- jest.mocked(updateGithubConfiguration).mockImplementation(this.handleUpdateGithubConfiguration);
- jest.mocked(updateGitlabConfiguration).mockImplementation(this.handleUpdateGitlabConfiguration);
- jest.mocked(updateAzureConfiguration).mockImplementation(this.handleUpdateAzureConfiguration);
- jest
- .mocked(updateBitbucketServerConfiguration)
- .mockImplementation(this.handleUpdateBitbucketServerConfiguration);
- jest
- .mocked(updateBitbucketCloudConfiguration)
- .mockImplementation(this.handleUpdateBitbucketCloudConfiguration);
- jest.mocked(getProjectAlmBinding).mockImplementation(this.handleGetProjectBinding);
- jest.mocked(deleteProjectAlmBinding).mockImplementation(this.handleDeleteProjectAlmBinding);
- jest.mocked(setProjectAzureBinding).mockImplementation(this.handleSetProjectAzureBinding);
- jest
- .mocked(setProjectBitbucketBinding)
- .mockImplementation(this.handleSetProjectBitbucketBinding);
- jest
- .mocked(setProjectBitbucketCloudBinding)
- .mockImplementation(this.handleSetProjectBitbucketCloudBinding);
- jest.mocked(setProjectGithubBinding).mockImplementation(this.handleSetProjectGithubBinding);
- jest.mocked(setProjectGitlabBinding).mockImplementation(this.handleSetProjectGitlabBinding);
- jest.mocked(validateProjectAlmBinding).mockImplementation(this.handleValidateProjectAlmBinding);
- }
-
- handleGetAlmDefinitions = () => {
- return this.reply(this.#almDefinitions);
- };
-
- handleGetAlmSettings = () => {
- return this.reply(this.#almSettings);
- };
-
- handleValidateAlmSettings = () => {
- return this.reply(this.#definitionError);
- };
-
- handleCountBoundProjects = () => {
- return this.reply({ projects: 5 });
- };
-
- setDefinitionErrorMessage = (message: string) => {
- this.#definitionError = message;
- };
-
- handleDeleteConfiguration = (key: string) => {
- for (const definitionsGroup of Object.values(this.#almDefinitions) as [
- GithubBindingDefinition[],
- GitlabBindingDefinition[],
- AzureBindingDefinition[],
- BitbucketCloudBindingDefinition[],
- BitbucketServerBindingDefinition[],
- ]) {
- const foundIndex = definitionsGroup.findIndex((definition) => definition.key === key);
- if (foundIndex !== -1) {
- definitionsGroup.splice(foundIndex, 1);
- break;
- }
- }
- return this.reply(undefined);
- };
-
- removeFromAlmSettings = (almKey: string) => {
- this.#almSettings = cloneDeep(defaultAlmSettings).filter(
- (almSetting) => almSetting.alm !== almKey,
- );
- };
-
- handleCreateGithubConfiguration = (data: GithubBindingDefinition) => {
- this.#almDefinitions[AlmKeys.GitHub].push(data);
-
- return this.reply(undefined);
- };
-
- handleCreateGitlabConfiguration = (data: GitlabBindingDefinition) => {
- this.#almDefinitions[AlmKeys.GitLab].push(data);
-
- return this.reply(undefined);
- };
-
- handleCreateAzureConfiguration = (data: AzureBindingDefinition) => {
- this.#almDefinitions[AlmKeys.Azure].push(data);
-
- return this.reply(undefined);
- };
-
- handleCreateBitbucketServerConfiguration = (data: BitbucketServerBindingDefinition) => {
- this.#almDefinitions[AlmKeys.BitbucketServer].push(data);
-
- return this.reply(undefined);
- };
-
- handleCreateBitbucketCloudConfiguration = (data: BitbucketCloudBindingDefinition) => {
- this.#almDefinitions[AlmKeys.BitbucketCloud].push(data);
-
- return this.reply(undefined);
- };
-
- handleUpdateGithubConfiguration = (data: GithubBindingDefinition & { newKey: string }) => {
- const definition = this.#almDefinitions[AlmKeys.GitHub].find(
- (item) => item.key === data.key,
- ) as GithubBindingDefinition;
- Object.assign(definition, { ...data, key: data.newKey });
-
- return this.reply(undefined);
- };
-
- handleUpdateGitlabConfiguration = (data: GitlabBindingDefinition & { newKey: string }) => {
- const definition = this.#almDefinitions[AlmKeys.GitLab].find(
- (item) => item.key === data.key,
- ) as GitlabBindingDefinition;
- Object.assign(definition, { ...data, key: data.newKey });
-
- return this.reply(undefined);
- };
-
- handleUpdateAzureConfiguration = (data: AzureBindingDefinition & { newKey: string }) => {
- const definition = this.#almDefinitions[AlmKeys.Azure].find(
- (item) => item.key === data.key,
- ) as AzureBindingDefinition;
- Object.assign(definition, { ...data, key: data.newKey });
-
- return this.reply(undefined);
- };
-
- handleUpdateBitbucketServerConfiguration = (
- data: BitbucketServerBindingDefinition & { newKey: string },
- ) => {
- const definition = this.#almDefinitions[AlmKeys.BitbucketServer].find(
- (item) => item.key === data.key,
- ) as BitbucketServerBindingDefinition;
- Object.assign(definition, { ...data, key: data.newKey });
-
- return this.reply(undefined);
- };
-
- handleUpdateBitbucketCloudConfiguration = (
- data: BitbucketCloudBindingDefinition & { newKey: string },
- ) => {
- const definition = this.#almDefinitions[AlmKeys.BitbucketCloud].find(
- (item) => item.key === data.key,
- ) as BitbucketCloudBindingDefinition;
- Object.assign(definition, { ...data, key: data.newKey });
-
- return this.reply(undefined);
- };
-
- handleGetProjectBinding = (project: string) => {
- const projectBinding = this.#projectsBindings[project];
-
- if (projectBinding === undefined) {
- return Promise.reject(
- new Response('', {
- status: 404,
- }),
- );
- }
-
- return this.reply(projectBinding);
- };
-
- handleSetProjectBinding = (alm: AlmKeys, data: EnhancedProjectAlmBindingParam) => {
- this.#projectsBindings[data.project] = {
- alm,
- key: data.almSetting,
- repository: data.repositoryName ?? (data.repository as string),
- monorepo: data.monorepo,
- slug: data.projectName ?? data.slug,
- summaryCommentEnabled: data.summaryCommentEnabled ?? false,
- url: 'https://company.com/project',
- };
- return this.reply(undefined);
- };
-
- handleSetProjectAzureBinding = (data: AzureProjectAlmBindingParams) => {
- return this.handleSetProjectBinding(AlmKeys.Azure, data);
- };
-
- handleSetProjectBitbucketBinding = (data: BitbucketProjectAlmBindingParams) => {
- return this.handleSetProjectBinding(AlmKeys.BitbucketServer, data);
- };
-
- handleSetProjectBitbucketCloudBinding = (data: BitbucketCloudProjectAlmBindingParams) => {
- return this.handleSetProjectBinding(AlmKeys.BitbucketCloud, data);
- };
-
- handleSetProjectGithubBinding = (data: GithubProjectAlmBindingParams) => {
- return this.handleSetProjectBinding(AlmKeys.GitHub, data);
- };
-
- handleSetProjectGitlabBinding = (data: GitlabProjectAlmBindingParams) => {
- return this.handleSetProjectBinding(AlmKeys.GitLab, data);
- };
-
- handleValidateProjectAlmBinding = () => {
- return this.reply(this.#projectBindingConfigurationErrors);
- };
-
- setProjectBindingConfigurationErrors = (errors?: ProjectAlmBindingConfigurationErrors) => {
- this.#projectBindingConfigurationErrors = errors;
- };
-
- handleDeleteProjectAlmBinding = (project: string) => {
- this.#projectsBindings[project] = undefined;
- return this.reply(undefined);
- };
-
- reset = () => {
- this.#almSettings = cloneDeep(defaultAlmSettings);
- this.#almDefinitions = cloneDeep(defaultAlmDefinitions);
- this.#projectsBindings = {};
- this.#projectBindingConfigurationErrors = undefined;
- this.setDefinitionErrorMessage('');
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/ApplicationServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/ApplicationServiceMock.ts
deleted file mode 100644
index d9af117c009..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/ApplicationServiceMock.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { Visibility } from '~sonar-aligned/types/component';
-import { getApplicationDetails, getApplicationLeak } from '../application';
-
-jest.mock('../application');
-
-export default class ApplicationServiceMock {
- constructor() {
- jest.mocked(getApplicationLeak).mockImplementation(this.handleGetApplicationLeak);
- jest.mocked(getApplicationDetails).mockImplementation(this.handleGetApplicationDetails);
- }
-
- handleGetApplicationLeak = () => {
- return this.reply([
- {
- project: 'org.sonarsource.scanner.cli:sonar-scanner-cli',
- projectName: 'SonarScanner CLI',
- date: '2022-12-23T11:02:26+0100',
- },
- {
- project: 'org.sonarsource.scanner.maven:sonar-maven-plugin',
- projectName: 'SonarQube Scanner for Maven',
- date: '2021-11-09T13:59:13+0100',
- },
- ]);
- };
-
- handleGetApplicationDetails = () => {
- return this.reply({
- branches: [],
- key: 'key-1',
- name: 'app',
- projects: [
- {
- branch: 'foo',
- key: 'KEY-P1',
- name: 'P1',
- isMain: true,
- },
- ],
- visibility: Visibility.Private,
- });
- };
-
- reset = () => {};
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/BranchesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/BranchesServiceMock.ts
deleted file mode 100644
index e3ccc71338b..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/BranchesServiceMock.ts
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { Branch, PullRequest } from '../../types/branch-like';
-import {
- deleteBranch,
- deletePullRequest,
- excludeBranchFromPurge,
- getBranches,
- getPullRequests,
- renameBranch,
- setMainBranch,
-} from '../branches';
-import { mockBranchList, mockPullRequestList } from './data/branches';
-
-jest.mock('../branches');
-
-export default class BranchesServiceMock {
- branches: Branch[];
- pullRequests: PullRequest[];
-
- constructor() {
- this.branches = mockBranchList();
- this.pullRequests = mockPullRequestList();
-
- jest.mocked(getBranches).mockImplementation(this.getBranchesHandler);
- jest.mocked(getPullRequests).mockImplementation(this.getPullRequestsHandler);
- jest.mocked(deleteBranch).mockImplementation(this.deleteBranchHandler);
- jest.mocked(deletePullRequest).mockImplementation(this.deletePullRequestHandler);
- jest.mocked(renameBranch).mockImplementation(this.renameBranchHandler);
- jest.mocked(excludeBranchFromPurge).mockImplementation(this.excludeBranchFromPurgeHandler);
- jest.mocked(setMainBranch).mockImplementation(this.setMainBranchHandler);
- }
-
- getBranchesHandler = () => {
- return this.reply(this.branches);
- };
-
- getPullRequestsHandler = () => {
- return this.reply(this.pullRequests);
- };
-
- deleteBranchHandler: typeof deleteBranch = ({ branch }) => {
- this.branches = this.branches.filter((b) => b.name !== branch);
- return this.reply(null);
- };
-
- deletePullRequestHandler: typeof deletePullRequest = ({ pullRequest }) => {
- this.pullRequests = this.pullRequests.filter((b) => b.key !== pullRequest);
- return this.reply(null);
- };
-
- renameBranchHandler: typeof renameBranch = (_, name) => {
- this.branches = this.branches.map((b) => (b.isMain ? { ...b, name } : b));
- return this.reply(null);
- };
-
- excludeBranchFromPurgeHandler: typeof excludeBranchFromPurge = (_, name, value) => {
- this.branches = this.branches.map((b) =>
- b.name === name ? { ...b, excludedFromPurge: value } : b,
- );
- return this.reply(null);
- };
-
- setMainBranchHandler: typeof setMainBranch = (_, branch) => {
- this.branches = this.branches.map((b) => ({
- ...b,
- excludedFromPurge: b.excludedFromPurge || b.isMain || b.name === branch,
- isMain: b.name === branch,
- }));
- return this.reply(null);
- };
-
- emptyBranches = () => {
- this.branches = [];
- };
-
- emptyBranchesAndPullRequest = () => {
- this.branches = [];
- this.pullRequests = [];
- };
-
- addBranch = (branch: Branch) => {
- this.branches.push(branch);
- };
-
- addPullRequest = (branch: PullRequest) => {
- this.pullRequests.push(branch);
- };
-
- reset = () => {
- this.branches = mockBranchList();
- this.pullRequests = mockPullRequestList();
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/CodingRulesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/CodingRulesServiceMock.ts
deleted file mode 100644
index 9627db0956d..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/CodingRulesServiceMock.ts
+++ /dev/null
@@ -1,768 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { HttpStatusCode } from 'axios';
-import { cloneDeep, countBy, isEqual, pick, trim } from 'lodash';
-import { ComponentQualifier, Visibility } from '~sonar-aligned/types/component';
-import { RuleDescriptionSections } from '../../apps/coding-rules/rule';
-import { mapRestRuleToRule } from '../../apps/coding-rules/utils';
-import { getStandards } from '../../helpers/security-standard';
-import {
- mockCurrentUser,
- mockPaging,
- mockRestRuleDetails,
- mockRuleActivation,
- mockRuleRepository,
-} from '../../helpers/testMocks';
-import { SoftwareImpactSeverity, SoftwareQuality } from '../../types/clean-code-taxonomy';
-import { RuleRepository, SearchRulesResponse } from '../../types/coding-rules';
-import { IssueSeverity, RawIssuesResponse } from '../../types/issues';
-import { RuleStatus, SearchRulesQuery } from '../../types/rules';
-import { SecurityStandard } from '../../types/security';
-import {
- Dict,
- Rule,
- RuleActivation,
- RuleDetails,
- RuleParameter,
- RulesUpdateRequest,
-} from '../../types/types';
-import { NoticeType } from '../../types/users';
-import { getComponentData } from '../components';
-import { getFacet } from '../issues';
-import {
- Profile,
- SearchQualityProfilesParameters,
- SearchQualityProfilesResponse,
- activateRule,
- bulkActivateRules,
- bulkDeactivateRules,
- deactivateRule,
- searchQualityProfiles,
-} from '../quality-profiles';
-import {
- CreateRuleData,
- createRule,
- deleteRule,
- getRuleDetails,
- getRuleRepositories,
- getRuleTags,
- getRulesApp,
- searchRules,
- updateRule,
-} from '../rules';
-import { dismissNotice, getCurrentUser } from '../users';
-import { STANDARDS_TO_RULES } from './data/ids';
-import { mockQualityProfilesList } from './data/qualityProfiles';
-import { mockRuleDetailsList, mockRulesActivationsInQP } from './data/rules';
-
-jest.mock('../rules');
-jest.mock('../issues');
-jest.mock('../users');
-jest.mock('../quality-profiles');
-jest.mock('../components');
-
-type FacetFilter = Pick<
- SearchRulesQuery,
- | 'impactSeverities'
- | 'impactSoftwareQualities'
- | 'languages'
- | 'tags'
- | 'available_since'
- | 'q'
- | 'types'
- | 'repositories'
- | 'qprofile'
- | 'activation'
- | 'severities'
- | 'sonarsourceSecurity'
- | 'owaspTop10'
- | 'owaspTop10-2021'
- | 'cwe'
- | 'is_template'
- | 'cleanCodeAttributeCategories'
- | 'prioritizedRule'
->;
-
-const FACET_RULE_MAP: { [key: string]: keyof Rule } = {
- languages: 'lang',
- types: 'type',
- severities: 'severity',
- statuses: 'status',
- tags: 'tags',
-};
-
-const MQRtoStandardSeverityMap = {
- [SoftwareImpactSeverity.Info]: IssueSeverity.Info,
- [SoftwareImpactSeverity.Low]: IssueSeverity.Minor,
- [SoftwareImpactSeverity.Medium]: IssueSeverity.Major,
- [SoftwareImpactSeverity.High]: IssueSeverity.Critical,
- [SoftwareImpactSeverity.Blocker]: IssueSeverity.Blocker,
-};
-
-const StandardtoMQRSeverityMap = {
- [IssueSeverity.Info]: SoftwareImpactSeverity.Info,
- [IssueSeverity.Minor]: SoftwareImpactSeverity.Low,
- [IssueSeverity.Major]: SoftwareImpactSeverity.Medium,
- [IssueSeverity.Critical]: SoftwareImpactSeverity.High,
- [IssueSeverity.Blocker]: SoftwareImpactSeverity.Blocker,
-};
-
-export const RULE_TAGS_MOCK = ['awesome', 'cute', 'nice'];
-
-export default class CodingRulesServiceMock {
- rulesActivations: Dict<RuleActivation[]> = {};
- rules: RuleDetails[] = [];
- qualityProfile: Profile[] = [];
- repositories: RuleRepository[] = [];
- isAdmin = false;
- applyWithWarning = false;
- dismissedNoticesEP = false;
-
- constructor() {
- this.repositories = [
- mockRuleRepository({ key: 'repo1', name: 'Repository 1' }),
- mockRuleRepository({ key: 'repo2', name: 'Repository 2' }),
- ];
- this.qualityProfile = mockQualityProfilesList();
- this.rules = mockRuleDetailsList();
- this.rulesActivations = mockRulesActivationsInQP();
-
- jest.mocked(updateRule).mockImplementation(this.handleUpdateRule);
- jest.mocked(createRule).mockImplementation(this.handleCreateRule);
- jest.mocked(deleteRule).mockImplementation(this.handleDeleteRule);
- jest.mocked(searchRules).mockImplementation(this.handleSearchRules);
- jest.mocked(getRuleDetails).mockImplementation(this.handleGetRuleDetails);
- jest.mocked(getRuleRepositories).mockImplementation(this.handleGetRuleRepositories);
- jest.mocked(searchQualityProfiles).mockImplementation(this.handleSearchQualityProfiles);
- jest.mocked(getRulesApp).mockImplementation(this.handleGetRulesApp);
- jest.mocked(bulkActivateRules).mockImplementation(this.handleBulkActivateRules);
- jest.mocked(bulkDeactivateRules).mockImplementation(this.handleBulkDeactivateRules);
- jest.mocked(activateRule).mockImplementation(this.handleActivateRule);
- jest.mocked(deactivateRule).mockImplementation(this.handleDeactivateRule);
- jest.mocked(getFacet).mockImplementation(this.handleGetFacet);
- jest.mocked(getRuleTags).mockImplementation(this.handleGetRuleTags);
- jest.mocked(getCurrentUser).mockImplementation(this.handleGetCurrentUser);
- jest.mocked(dismissNotice).mockImplementation(this.handleDismissNotification);
- jest.mocked(getComponentData).mockImplementation(this.handleGetComponentData);
- }
-
- getRulesWithoutDetails(rules: RuleDetails[]) {
- return rules.map((r) =>
- pick(r, [
- 'isTemplate',
- 'key',
- 'lang',
- 'langName',
- 'name',
- 'params',
- 'severity',
- 'status',
- 'sysTags',
- 'tags',
- 'type',
- 'cleanCodeAttributeCategory',
- 'cleanCodeAttribute',
- 'impacts',
- ]),
- );
- }
-
- filterFacet({
- impactSeverities,
- impactSoftwareQualities,
- cleanCodeAttributeCategories,
- languages,
- available_since,
- q,
- types,
- tags,
- is_template,
- repositories,
- qprofile,
- severities,
- sonarsourceSecurity,
- owaspTop10,
- 'owaspTop10-2021': owasp2021Top10,
- cwe,
- activation,
- prioritizedRule,
- }: FacetFilter) {
- let filteredRules = this.getRulesFilteredByRemovedStatus();
- if (cleanCodeAttributeCategories) {
- filteredRules = filteredRules.filter(
- (r) =>
- r.cleanCodeAttributeCategory &&
- cleanCodeAttributeCategories.includes(r.cleanCodeAttributeCategory),
- );
- }
- if (impactSoftwareQualities) {
- filteredRules = filteredRules.filter(
- (r) =>
- r.impacts &&
- r.impacts.some(({ softwareQuality }) =>
- impactSoftwareQualities.includes(softwareQuality),
- ),
- );
- }
- if (impactSeverities) {
- filteredRules = filteredRules.filter(
- (r) => r.impacts && r.impacts.some(({ severity }) => impactSeverities.includes(severity)),
- );
- }
- if (severities) {
- filteredRules = filteredRules.filter(
- (r) =>
- r.severity && severities.split(',').some((severity: string) => r.severity === severity),
- );
- }
- if (types) {
- filteredRules = filteredRules.filter((r) => types.includes(r.type));
- }
- if (languages) {
- filteredRules = filteredRules.filter((r) => r.lang && languages.includes(r.lang));
- }
- if (qprofile) {
- const qProfileLang = this.qualityProfile.find((p) => p.key === qprofile)?.language;
- filteredRules = filteredRules
- .filter((r) => r.lang === qProfileLang)
- .filter((r) => {
- const qProfilesInRule = this.rulesActivations[r.key]?.map((ra) => ra.qProfile) ?? [];
- const ruleHasQueriedProfile = qProfilesInRule.includes(qprofile);
- return activation === 'true' ? ruleHasQueriedProfile : !ruleHasQueriedProfile;
- });
- }
- if (available_since) {
- filteredRules = filteredRules.filter(
- (r) => r.createdAt && new Date(r.createdAt) > new Date(available_since),
- );
- }
- if (is_template !== undefined) {
- filteredRules = filteredRules.filter((r) => (is_template ? r.isTemplate : !r.isTemplate));
- }
- if (repositories) {
- filteredRules = filteredRules.filter((r) => r.lang && repositories.includes(r.repo));
- }
- if (sonarsourceSecurity) {
- const matchingRules =
- STANDARDS_TO_RULES[SecurityStandard.SONARSOURCE]?.[sonarsourceSecurity] ?? [];
- filteredRules = filteredRules.filter((r) => matchingRules.includes(r.key));
- }
- if (owasp2021Top10) {
- const matchingRules =
- STANDARDS_TO_RULES[SecurityStandard.OWASP_TOP10_2021]?.[owasp2021Top10] ?? [];
- filteredRules = filteredRules.filter((r) => matchingRules.includes(r.key));
- }
- if (owaspTop10) {
- const matchingRules = STANDARDS_TO_RULES[SecurityStandard.OWASP_TOP10]?.[owaspTop10] ?? [];
- filteredRules = filteredRules.filter((r) => matchingRules.includes(r.key));
- }
- if (cwe) {
- const matchingRules = STANDARDS_TO_RULES[SecurityStandard.CWE]?.[cwe] ?? [];
- filteredRules = filteredRules.filter((r) => matchingRules.includes(r.key));
- }
- if (q && q.length > 2) {
- filteredRules = filteredRules.filter((r) => r.name.includes(q) || r.key.includes(q));
- }
- if (tags) {
- filteredRules = filteredRules.filter((r) => r.tags && r.tags.some((t) => tags.includes(t)));
- }
- if (qprofile && prioritizedRule !== undefined) {
- filteredRules = filteredRules.filter((r) => {
- const qProfilesInRule = this.rulesActivations[r.key] ?? [];
- const ruleHasQueriedProfile = qProfilesInRule.find((q) => q.qProfile === qprofile);
- return prioritizedRule === 'true'
- ? ruleHasQueriedProfile?.prioritizedRule
- : !ruleHasQueriedProfile?.prioritizedRule;
- });
- }
- return this.getRulesWithoutDetails(filteredRules);
- }
-
- setIsAdmin() {
- this.isAdmin = true;
- }
-
- activateWithWarning() {
- this.applyWithWarning = true;
- }
-
- reset() {
- this.isAdmin = false;
- this.applyWithWarning = false;
- this.dismissedNoticesEP = false;
- this.rules = mockRuleDetailsList();
- this.rulesActivations = mockRulesActivationsInQP();
- }
-
- getRulesFilteredByRemovedStatus() {
- return this.rules.filter((r) => r.status !== RuleStatus.Removed);
- }
-
- allRulesCount() {
- return this.getRulesFilteredByRemovedStatus().length;
- }
-
- allRulesName() {
- return this.getRulesFilteredByRemovedStatus().map((r) => r.name);
- }
-
- allQualityProfile(language: string) {
- return this.qualityProfile.filter((qp) => qp.language === language);
- }
-
- handleGetFacet = (): Promise<{
- facet: { count: number; val: string }[];
- response: RawIssuesResponse;
- }> => {
- return this.reply({
- facet: [
- { count: 135, val: 'project-1' },
- { count: 65, val: 'project-2' },
- { count: 13, val: 'project-3' },
- ],
- response: {
- components: [],
- effortTotal: 0,
- facets: [],
- issues: [],
- languages: [],
- paging: { total: 213, pageIndex: 1, pageSize: 1 },
- },
- });
- };
-
- handleGetRuleDetails = (parameters: {
- actives?: boolean;
- key: string;
- }): Promise<{ actives?: RuleActivation[]; rule: RuleDetails }> => {
- const rule = this.rules.find((r) => r.key === parameters.key);
- if (!rule) {
- return Promise.reject({
- errors: [{ msg: `No rule has been found for id ${parameters.key}` }],
- });
- }
- return this.reply({
- actives: parameters.actives ? (this.rulesActivations[rule.key] ?? []) : undefined,
- rule,
- });
- };
-
- handleGetRuleRepositories = (parameters: {
- q: string;
- }): Promise<Array<{ key: string; language: string; name: string }>> => {
- return this.reply(this.repositories.filter((r) => r.name.includes(parameters.q)));
- };
-
- handleUpdateRule = (data: RulesUpdateRequest): Promise<RuleDetails> => {
- // find rule if key is in the list of rules or key is a part of 'repo:key'
- const rule = this.rules.find((r) => data.key.split(':').some((part) => part === r.key));
- if (rule === undefined) {
- return Promise.reject({
- errors: [{ msg: `No rule has been found for id ${data.key}` }],
- });
- }
-
- const template = this.rules.find((r) => r.key === rule.templateKey);
-
- // Lets not convert the md to html in test.
- rule.mdDesc = data.markdownDescription !== undefined ? data.markdownDescription : rule.mdDesc;
- rule.htmlDesc =
- data.markdownDescription !== undefined ? data.markdownDescription : rule.htmlDesc;
- rule.mdNote = data.markdown_note !== undefined ? data.markdown_note : rule.mdNote;
- rule.htmlNote = data.markdown_note !== undefined ? data.markdown_note : rule.htmlNote;
- rule.name = data.name !== undefined ? data.name : rule.name;
- rule.status = rule.status === RuleStatus.Removed ? RuleStatus.Ready : rule.status;
- rule.cleanCodeAttribute =
- data.cleanCodeAttribute !== undefined ? data.cleanCodeAttribute : rule.cleanCodeAttribute;
- rule.impacts = data.impacts !== undefined ? data.impacts : rule.impacts;
- rule.type = data.type !== undefined ? data.type : rule.type;
- rule.severity = data.severity !== undefined ? data.severity : rule.severity;
-
- if (template && data.params) {
- rule.params = [];
- data.params.split(';').forEach((param) => {
- const parts = param.split('=');
- const paramsDef = template.params?.find((p) => p.key === parts[0]);
- rule.params?.push({
- key: parts[0],
- type: paramsDef?.type || 'STRING',
- defaultValue: trim(parts[1], '" '),
- htmlDesc: paramsDef?.htmlDesc,
- });
- });
- }
-
- rule.remFnBaseEffort =
- data.remediation_fn_base_effort !== undefined
- ? data.remediation_fn_base_effort
- : rule.remFnBaseEffort;
- rule.remFnType =
- data.remediation_fn_type !== undefined ? data.remediation_fn_type : rule.remFnType;
- rule.status = data.status !== undefined ? data.status : rule.status;
- rule.tags = data.tags !== undefined ? data.tags.split(',') : rule.tags;
-
- return this.reply(rule);
- };
-
- handleCreateRule = (data: CreateRuleData) => {
- const newRule = mockRestRuleDetails({
- descriptionSections: [
- { key: RuleDescriptionSections.DEFAULT, content: data.markdownDescription },
- ],
- ...pick(data, ['templateKey', 'name', 'status', 'cleanCodeAttribute', 'impacts', 'key']),
- parameters: data.parameters as RuleParameter[],
- });
-
- const ruleFromTemplateWithSameKey = this.rules.find(
- (rule) => rule.templateKey === newRule.templateKey && newRule.key.split(':')[1] === rule.key,
- );
-
- if (ruleFromTemplateWithSameKey?.status === RuleStatus.Removed) {
- return Promise.reject({
- status: HttpStatusCode.Conflict,
- errors: [{ msg: `Rule with the same was removed before` }],
- });
- } else if (ruleFromTemplateWithSameKey) {
- return Promise.reject({
- errors: [{ msg: `A rule with key ${newRule.key} already exists` }],
- });
- }
-
- this.rules.push(mapRestRuleToRule(newRule));
-
- return this.reply(newRule);
- };
-
- handleDeleteRule = (data: { key: string }) => {
- this.rules = this.rules.filter((r) => r.key !== data.key);
- return this.reply(undefined);
- };
-
- handleSearchRules = async ({
- facets,
- types,
- languages,
- p,
- ps,
- available_since,
- impactSeverities,
- impactSoftwareQualities,
- severities,
- repositories,
- qprofile,
- sonarsourceSecurity,
- owaspTop10,
- 'owaspTop10-2021': owasp2021Top10,
- cwe,
- tags,
- q,
- rule_key,
- is_template,
- activation,
- cleanCodeAttributeCategories,
- prioritizedRule,
- }: SearchRulesQuery): Promise<SearchRulesResponse> => {
- const standards = await getStandards();
- const facetCounts: Array<{ property: string; values: { count: number; val: string }[] }> = [];
- for (const facet of facets?.split(',') ?? []) {
- // If we can count facet values from the list of rules
- if (FACET_RULE_MAP[facet]) {
- const counts = countBy(this.rules.map((r) => r[FACET_RULE_MAP[facet]]));
- const values = Object.keys(counts).map((val) => ({ val, count: counts[val] }));
- facetCounts.push({
- property: facet,
- values,
- });
- } else if (facet === 'repositories') {
- facetCounts.push({
- property: facet,
- values: this.repositories.map((repo) => ({
- val: repo.key,
- count: this.rules.filter((r) => r.repo === repo.key).length,
- })),
- });
- } else if (typeof (standards as Dict<object>)[facet] === 'object') {
- // When a standards facet is requested, we return all the values with a count of 1
- facetCounts.push({
- property: facet,
- values: Object.keys((standards as any)[facet]).map((val: string) => ({
- val,
- count: 1,
- })),
- });
- } else {
- facetCounts.push({
- property: facet,
- values: [],
- });
- }
- }
- const currentPs = ps ?? 10;
- const currentP = p ?? 1;
- let filteredRules: Rule[] = [];
- if (rule_key) {
- filteredRules = this.getRulesWithoutDetails(this.rules).filter((r) => r.key === rule_key);
- } else {
- filteredRules = this.filterFacet({
- qprofile,
- languages,
- available_since,
- q,
- impactSeverities,
- impactSoftwareQualities,
- cleanCodeAttributeCategories,
- repositories,
- types,
- tags,
- is_template,
- severities,
- sonarsourceSecurity,
- owaspTop10,
- 'owaspTop10-2021': owasp2021Top10,
- cwe,
- activation,
- prioritizedRule,
- });
- }
-
- const responseRules = filteredRules.slice((currentP - 1) * currentPs, currentP * currentPs);
- return this.reply({
- actives: qprofile ? this.rulesActivations : undefined,
- rules: responseRules,
- facets: facetCounts,
- paging: mockPaging({
- total: filteredRules.length,
- pageIndex: currentP,
- pageSize: currentPs,
- }),
- });
- };
-
- handleBulkActivateRules = () => {
- if (this.applyWithWarning) {
- return this.reply({
- succeeded: this.getRulesFilteredByRemovedStatus().length - 1,
- failed: 1,
- errors: [{ msg: 'c rule c:S6069 cannot be activated on cpp profile SonarSource' }],
- });
- }
- return this.reply({
- succeeded: this.getRulesFilteredByRemovedStatus().length,
- failed: 0,
- errors: [],
- });
- };
-
- handleBulkDeactivateRules = () => {
- return this.reply({
- succeeded: this.getRulesFilteredByRemovedStatus().length,
- failed: 0,
- });
- };
-
- handleActivateRule: typeof activateRule = (data) => {
- if (data.reset) {
- const parentQP = this.qualityProfile.find((p) => p.key === data.key)?.parentKey!;
- const parentActivation = this.rulesActivations[data.rule]?.find(
- (activation) => activation.qProfile === parentQP,
- )!;
- const parentParams = parentActivation?.params ?? [];
- const activation = this.rulesActivations[data.rule]?.find(
- ({ qProfile }) => qProfile === data.key,
- )!;
- activation.inherit = 'INHERITED';
- activation.prioritizedRule = parentActivation?.prioritizedRule ?? false;
- activation.severity = parentActivation?.severity ?? 'MAJOR';
- activation.impacts = parentActivation?.impacts ?? [
- {
- softwareQuality: SoftwareQuality.Maintainability,
- severity: SoftwareImpactSeverity.Medium,
- },
- ];
- activation.params = parentParams;
-
- return this.reply(undefined);
- }
-
- const currentActivation = this.rulesActivations[data.rule]?.find(
- (a) => a.qProfile === data.key,
- );
- if (
- currentActivation &&
- isEqual(
- currentActivation.params,
- Object.entries(data.params ?? {}).map(([key, value]) => ({ key, value })),
- ) &&
- (!data.severity || currentActivation.severity === data.severity) &&
- currentActivation.prioritizedRule === data.prioritizedRule &&
- (!data.impacts ||
- isEqual(
- currentActivation.impacts,
- Object.entries(data.impacts).map(([softwareQuality, severity]) => ({
- softwareQuality,
- severity,
- })),
- ))
- ) {
- return this.reply(undefined);
- }
-
- const ruleImpacts = this.rules.find((r) => r.key === data.rule)?.impacts ?? [];
- const inheritedImpacts =
- this.rulesActivations[data.rule]?.find(({ qProfile }) => qProfile === data.key)?.impacts ??
- [];
- const severity = data.impacts
- ? MQRtoStandardSeverityMap[data.impacts[SoftwareQuality.Maintainability]]
- : data.severity;
- const impacts = data.severity
- ? [
- ...ruleImpacts.filter(
- (impact) =>
- impact.softwareQuality !== SoftwareQuality.Maintainability &&
- !inheritedImpacts.some((i) => i.softwareQuality === impact.softwareQuality),
- ),
- ...inheritedImpacts.filter(
- (impact) => impact.softwareQuality !== SoftwareQuality.Maintainability,
- ),
- {
- softwareQuality: SoftwareQuality.Maintainability,
- severity:
- StandardtoMQRSeverityMap[data.severity as keyof typeof StandardtoMQRSeverityMap],
- },
- ]
- : Object.entries(data.impacts ?? {}).map(
- ([softwareQuality, severity]: [SoftwareQuality, SoftwareImpactSeverity]) => ({
- softwareQuality,
- severity,
- }),
- );
-
- const nextActivations = [
- mockRuleActivation({
- qProfile: data.key,
- severity,
- impacts,
- prioritizedRule: data.prioritizedRule,
- params: Object.entries(data.params ?? {}).map(([key, value]) => ({ key, value })),
- }),
- ];
-
- const inheritingProfiles = this.qualityProfile.filter(
- (p) => p.isInherited && p.parentKey === data.key,
- );
- nextActivations.push(
- ...inheritingProfiles.map((profile) =>
- mockRuleActivation({
- qProfile: profile.key,
- severity,
- impacts,
- prioritizedRule: data.prioritizedRule,
- inherit: 'INHERITED',
- params: Object.entries(data.params ?? {}).map(([key, value]) => ({ key, value })),
- }),
- ),
- );
-
- if (!this.rulesActivations[data.rule]) {
- this.rulesActivations[data.rule] = nextActivations;
- return this.reply(undefined);
- }
-
- nextActivations.forEach((nextActivation) => {
- const activationIndex = this.rulesActivations[data.rule]?.findIndex(
- ({ qProfile }) => qProfile === nextActivation.qProfile,
- );
-
- if (activationIndex !== -1) {
- this.rulesActivations[data.rule][activationIndex] = {
- ...nextActivation,
- inherit: 'OVERRIDES',
- };
- } else {
- this.rulesActivations[data.rule].push(nextActivation);
- }
- });
-
- return this.reply(undefined);
- };
-
- handleDeactivateRule = (data: { key: string; rule: string }) => {
- this.rulesActivations[data.rule] = this.rulesActivations[data.rule]?.filter(
- (activation) => activation.qProfile !== data.key,
- );
- return this.reply(undefined);
- };
-
- handleSearchQualityProfiles = ({
- language,
- }: SearchQualityProfilesParameters = {}): Promise<SearchQualityProfilesResponse> => {
- let profiles: Profile[] = this.isAdmin
- ? this.qualityProfile.map((p) => ({ ...p, actions: { edit: true } }))
- : this.qualityProfile;
- if (language) {
- profiles = profiles.filter((p) => p.language === language);
- }
- return this.reply({ profiles });
- };
-
- handleGetRuleTags = (data: { ps?: number; q: string }) => {
- return this.reply(RULE_TAGS_MOCK.filter((tag) => tag.includes(data.q)));
- };
-
- handleGetRulesApp = () => {
- return this.reply({ canWrite: this.isAdmin, repositories: this.repositories });
- };
-
- handleGetCurrentUser = () => {
- return this.reply(
- mockCurrentUser({
- dismissedNotices: {
- educationPrinciples: this.dismissedNoticesEP,
- },
- }),
- );
- };
-
- handleDismissNotification = (noticeType: NoticeType) => {
- if (noticeType === NoticeType.EDUCATION_PRINCIPLES) {
- this.dismissedNoticesEP = true;
- return this.reply(true);
- }
-
- return Promise.reject();
- };
-
- handleGetComponentData = (data: { component: string }) => {
- return Promise.resolve({
- ancestors: [],
- component: {
- key: data.component,
- name: data.component.toUpperCase().split(/[ -.]/g).join(' '),
- qualifier: ComponentQualifier.Project,
- visibility: Visibility.Public,
- },
- });
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/ComponentsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/ComponentsServiceMock.ts
deleted file mode 100644
index ff3e47932e9..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/ComponentsServiceMock.ts
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep, pick } from 'lodash';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { Visibility } from '~sonar-aligned/types/component';
-import { DEFAULT_METRICS } from '../../helpers/mocks/metrics';
-import { HttpStatus, RequestData } from '../../helpers/request';
-import { mockMetric } from '../../helpers/testMocks';
-import { isDefined } from '../../helpers/types';
-import { TreeComponent } from '../../types/component';
-import {
- Component,
- ComponentMeasure,
- Dict,
- DuplicatedFile,
- Duplication,
- Metric,
- Paging,
-} from '../../types/types';
-import {
- ComponentRaw,
- GetTreeParams,
- changeKey,
- doesComponentExists,
- getBreadcrumbs,
- getComponent,
- getComponentData,
- getComponentForSourceViewer,
- getComponentTree,
- getDuplications,
- getSources,
- getTree,
- searchProjects,
- setApplicationTags,
- setProjectTags,
-} from '../components';
-import {
- ComponentTree,
- SourceFile,
- mockFullComponentTree,
- mockFullSourceViewerFileList,
-} from './data/components';
-import { mockIssuesList } from './data/issues';
-import { MeasureRecords, mockFullMeasureData } from './data/measures';
-import { mockProjects } from './data/projects';
-import { listAllComponent, listChildComponent, listLeavesComponent } from './data/utils';
-
-jest.mock('../components');
-
-export default class ComponentsServiceMock {
- failLoadingComponentStatus: HttpStatus | undefined = undefined;
- defaultComponents: ComponentTree[];
- defaultProjects: ComponentRaw[];
- components: ComponentTree[];
- defaultSourceFiles: SourceFile[];
- sourceFiles: SourceFile[];
- defaultMeasures: MeasureRecords;
- measures: MeasureRecords;
- projects: ComponentRaw[];
-
- constructor(components?: ComponentTree[], sourceFiles?: SourceFile[], measures?: MeasureRecords) {
- this.defaultComponents = components || [mockFullComponentTree()];
- this.defaultSourceFiles = sourceFiles || mockFullSourceViewerFileList();
- const issueList = mockIssuesList();
- this.defaultMeasures =
- measures ||
- this.defaultComponents.reduce(
- (acc, tree) => ({ ...acc, ...mockFullMeasureData(tree, issueList) }),
- {},
- );
- this.defaultProjects = mockProjects();
-
- this.components = cloneDeep(this.defaultComponents);
- this.sourceFiles = cloneDeep(this.defaultSourceFiles);
- this.measures = cloneDeep(this.defaultMeasures);
- this.projects = cloneDeep(this.defaultProjects);
-
- jest.mocked(getComponent).mockImplementation(this.handleGetComponent);
- jest.mocked(getComponentTree).mockImplementation(this.handleGetComponentTree);
- jest.mocked(getTree).mockImplementation(this.handleGetTree);
- jest.mocked(getComponentData).mockImplementation(this.handleGetComponentData);
- jest
- .mocked(getComponentForSourceViewer)
- .mockImplementation(this.handleGetComponentForSourceViewer);
- jest.mocked(getDuplications).mockImplementation(this.handleGetDuplications);
- jest.mocked(getSources).mockImplementation(this.handleGetSources);
- jest.mocked(changeKey).mockImplementation(this.handleChangeKey);
- jest.mocked(getBreadcrumbs).mockImplementation(this.handleGetBreadcrumbs);
- jest.mocked(setProjectTags).mockImplementation(this.handleSetProjectTags);
- jest.mocked(setApplicationTags).mockImplementation(this.handleSetApplicationTags);
- jest.mocked(searchProjects).mockImplementation(this.handleSearchProjects);
- jest.mocked(doesComponentExists).mockImplementation(this.handleDoesComponentExists);
- }
-
- handleSearchProjects: typeof searchProjects = (data) => {
- const pageIndex = data.p ?? 1;
- const pageSize = data.ps ?? 100;
-
- const components = this.projects
- .filter((c) => {
- if (data.filter && data.filter.startsWith('query')) {
- const query = data.filter.split('query=')[1];
- return c.key.includes(query) || c.name.includes(query);
- }
- return true;
- })
- .map((c) => c);
-
- return this.reply({
- components: components.slice((pageIndex - 1) * pageSize, pageIndex * pageSize),
- facets: [],
- paging: {
- pageSize,
- pageIndex,
- total: components.length,
- },
- });
- };
-
- findComponentTree = (key: string, from?: ComponentTree) => {
- let tree: ComponentTree | undefined;
- const recurse = (node: ComponentTree): boolean => {
- if (node.component.key === key) {
- tree = node;
- return true;
- }
- return node.children.some((child) => recurse(child));
- };
-
- if (from !== undefined) {
- recurse(from);
- return tree;
- }
-
- for (let i = 0, len = this.components.length; i < len; i++) {
- if (recurse(this.components[i])) {
- return tree;
- }
- }
-
- throw new Error(`Couldn't find component tree for key ${key}`);
- };
-
- findSourceFile = (key: string): SourceFile => {
- const sourceFile = this.sourceFiles.find((s) => s.component.key === key);
- if (sourceFile) {
- return sourceFile;
- }
- throw new Error(`Couldn't find source file for key ${key}`);
- };
-
- registerProject = (project: ComponentRaw) => {
- this.projects.push(project);
- };
-
- registerComponent = (component: Component, ancestors: Component[] = []) => {
- this.components.push({ component, ancestors, children: [] });
- };
-
- registerComponentTree = (componentTree: ComponentTree, replace = true) => {
- if (replace) {
- this.components = [];
- }
- this.components.push(componentTree);
- };
-
- registerComponentMeasures = (measures: MeasureRecords) => {
- this.measures = measures;
- };
-
- setFailLoadingComponentStatus = (status: HttpStatus.Forbidden | HttpStatus.NotFound) => {
- this.failLoadingComponentStatus = status;
- };
-
- getHugeFileKey = () => {
- const { sourceFile } = this.sourceFiles.reduce(
- (acc, sourceFile) => {
- if (sourceFile.lines.length > acc.size) {
- return {
- sourceFile,
- size: sourceFile.lines.length,
- };
- }
- return acc;
- },
- { sourceFile: undefined, size: -Infinity },
- );
- if (sourceFile) {
- return sourceFile.component.key;
- }
- throw new Error('Could not find a large source file');
- };
-
- getEmptyFileKey = () => {
- const sourceFile = this.sourceFiles.find((sourceFile) => {
- if (sourceFile.lines.length === 0) {
- return sourceFile;
- }
- });
- if (sourceFile) {
- return sourceFile.component.key;
- }
- throw new Error('Could not find an empty source file');
- };
-
- getNonEmptyFileKey = (preferredKey = 'foo:test1.js') => {
- let sourceFile = this.sourceFiles.find((sourceFile) => {
- if (sourceFile.component.key === preferredKey) {
- return sourceFile;
- }
- });
-
- if (!sourceFile) {
- sourceFile = this.sourceFiles.find((sourceFile) => {
- if (sourceFile.lines.length > 0) {
- return sourceFile;
- }
- });
- }
-
- if (sourceFile) {
- return sourceFile.component.key;
- }
- throw new Error('Could not find a non-empty source file');
- };
-
- reset = () => {
- this.components = cloneDeep(this.defaultComponents);
- this.sourceFiles = cloneDeep(this.defaultSourceFiles);
- this.measures = cloneDeep(this.defaultMeasures);
- };
-
- handleGetComponentTree = (
- strategy: string,
- key: string,
- metricKeys: string[] = [],
- { p = 1, ps = 100 }: RequestData = {},
- ): Promise<{
- baseComponent: ComponentMeasure;
- components: ComponentMeasure[];
- metrics: Metric[];
- paging: Paging;
- }> => {
- const base = this.findComponentTree(key);
- let components: Component[] = [];
- if (base === undefined) {
- return Promise.reject({
- errors: [{ msg: `No component has been found for id ${key}` }],
- });
- }
- if (strategy === 'all' || strategy === '') {
- components = listAllComponent(base);
- } else if (strategy === 'children') {
- components = listChildComponent(base);
- } else if (strategy === 'leaves') {
- components = listLeavesComponent(base);
- }
-
- const componentsMeasures: ComponentMeasure[] = components.map((c) => {
- return {
- measures: metricKeys
- .map((metric) => this.measures[c.key] && this.measures[c.key][metric])
- .filter(isDefined),
- ...pick(c, ['analysisDate', 'key', 'name', 'qualifier']),
- };
- });
-
- return this.reply({
- baseComponent: base.component,
- components: componentsMeasures.slice(ps * (p - 1), ps * (p - 1) + ps),
- metrics: metricKeys.map((metric) => DEFAULT_METRICS[metric] ?? mockMetric({ key: metric })),
- paging: {
- pageSize: ps,
- pageIndex: p,
- total: componentsMeasures.length,
- },
- });
- };
-
- handleGetTree = ({
- component: key,
- q = '',
- qualifiers,
- }: GetTreeParams & { qualifiers?: string }): Promise<{
- baseComponent: TreeComponent;
- components: TreeComponent[];
- paging: Paging;
- }> => {
- const base = this.findComponentTree(key);
- if (base === undefined) {
- return Promise.reject({
- errors: [{ msg: `No component has been found for key ${key}` }],
- });
- }
- const components: TreeComponent[] = listAllComponent(base)
- .filter(({ name, key }) => name.includes(q) || key.includes(q))
- .filter(({ qualifier }) => (qualifiers?.length ? qualifiers.includes(qualifier) : true))
- .map((c) => ({ ...c, visibility: Visibility.Public }));
-
- return this.reply({
- baseComponent: { ...base.component, visibility: Visibility.Public },
- components,
- paging: {
- pageIndex: 1,
- pageSize: 100,
- total: components.length,
- },
- });
- };
-
- handleGetComponentData = (data: { component: string } & BranchParameters) => {
- if (this.failLoadingComponentStatus !== undefined) {
- return Promise.reject({ status: this.failLoadingComponentStatus });
- }
- const tree = this.findComponentTree(data.component);
- if (tree) {
- const { component, ancestors } = tree;
- return this.reply({ component, ancestors } as {
- ancestors: ComponentRaw[];
- component: ComponentRaw;
- });
- }
- throw new Error(`Couldn't find component with key ${data.component}`);
- };
-
- handleGetComponent: typeof getComponent = (data: { component: string } & BranchParameters) => {
- if (this.failLoadingComponentStatus !== undefined) {
- return Promise.reject({ status: this.failLoadingComponentStatus });
- }
- const tree = this.findComponentTree(data.component);
- if (tree) {
- const { component } = tree;
- return this.reply({ component });
- }
- throw new Error(`Couldn't find component with key ${data.component}`);
- };
-
- handleGetComponentForSourceViewer = ({ component }: { component: string } & BranchParameters) => {
- const sourceFile = this.findSourceFile(component);
- return this.reply(sourceFile.component);
- };
-
- handleGetDuplications = ({
- key,
- }: { key: string } & BranchParameters): Promise<{
- duplications: Duplication[];
- files: Dict<DuplicatedFile>;
- }> => {
- const { duplication } = this.findSourceFile(key);
- if (duplication) {
- return this.reply(duplication);
- }
- return this.reply({ duplications: [], files: {} });
- };
-
- handleGetSources = (data: { from?: number; key: string; to?: number } & BranchParameters) => {
- const { lines } = this.findSourceFile(data.key);
- const from = data.from || 1;
- const to = data.to || lines.length;
- return this.reply(lines.slice(from - 1, to));
- };
-
- handleChangeKey = (data: { from: string; to: string }) => {
- const treeItem = this.components.find(({ component }) => component.key === data.from);
- if (treeItem) {
- treeItem.component.key = data.to;
- return this.reply(undefined);
- }
- return Promise.reject({ status: 404, message: 'Component not found' });
- };
-
- handleGetBreadcrumbs = ({ component: key }: { component: string } & BranchParameters) => {
- const base = this.findComponentTree(key);
- if (base === undefined) {
- return Promise.reject({
- errors: [{ msg: `No component has been found for id ${key}` }],
- });
- }
- return this.reply([...(base.ancestors as ComponentRaw[]), base.component as ComponentRaw]);
- };
-
- handleSetProjectTags: typeof setProjectTags = ({ project, tags }) => {
- const base = this.findComponentTree(project);
- if (base !== undefined) {
- base.component.tags = tags.split(',');
- }
- return this.reply();
- };
-
- handleSetApplicationTags: typeof setApplicationTags = ({ application, tags }) => {
- const base = this.findComponentTree(application);
- if (base !== undefined) {
- base.component.tags = tags.split(',');
- }
- return this.reply();
- };
-
- handleDoesComponentExists: typeof doesComponentExists = ({ component }) => {
- const exists = this.components.some(({ component: { key } }) => key === component);
- return this.reply(exists);
- };
-
- reply<T>(): Promise<void>;
- reply<T>(response: T): Promise<T>;
- reply<T>(response?: T): Promise<T | void> {
- return Promise.resolve(response ? cloneDeep(response) : undefined);
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/ComputeEngineServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/ComputeEngineServiceMock.ts
deleted file mode 100644
index 70fba8a61ae..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/ComputeEngineServiceMock.ts
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { differenceInMilliseconds, isAfter, isBefore } from 'date-fns';
-import { cloneDeep, groupBy, sortBy } from 'lodash';
-import { PAGE_SIZE } from '../../apps/background-tasks/constants';
-import { parseDate } from '../../helpers/dates';
-import { mockTask } from '../../helpers/mocks/tasks';
-import { isDefined } from '../../helpers/types';
-import {
- ActivityRequestParameters,
- Task,
- TaskStatuses,
- TaskTypes,
- TaskWarning,
-} from '../../types/tasks';
-import {
- cancelAllTasks,
- cancelTask,
- getActivity,
- getAnalysisStatus,
- getStatus,
- getTask,
- getTasksForComponent,
- getTypes,
- getWorkers,
- setWorkerCount,
-} from '../ce';
-
-const RANDOM_RADIX = 36;
-const RANDOM_PREFIX = 2;
-
-const TASK_TYPES = [
- TaskTypes.Report,
- TaskTypes.IssueSync,
- TaskTypes.AuditPurge,
- TaskTypes.ProjectExport,
- TaskTypes.AppRefresh,
- TaskTypes.ProjectImport,
- TaskTypes.ViewRefresh,
- TaskTypes.ReportSubmit,
- TaskTypes.GithubProvisioning,
-];
-
-const DEFAULT_TASKS: Task[] = [mockTask()];
-const DEFAULT_WORKERS = {
- canSetWorkerCount: true,
- value: 2,
-};
-
-const CANCELABLE_TASK_STATUSES = [TaskStatuses.Pending];
-
-jest.mock('../ce');
-
-export default class ComputeEngineServiceMock {
- tasks: Task[];
- taskWarnings: TaskWarning[] = [];
- workers = { ...DEFAULT_WORKERS };
-
- constructor() {
- jest.mocked(cancelAllTasks).mockImplementation(this.handleCancelAllTasks);
- jest.mocked(cancelTask).mockImplementation(this.handleCancelTask);
- jest.mocked(getActivity).mockImplementation(this.handleGetActivity);
- jest.mocked(getStatus).mockImplementation(this.handleGetStatus);
- jest.mocked(getTypes).mockImplementation(this.handleGetTypes);
- jest.mocked(getTask).mockImplementation(this.handleGetTask);
- jest.mocked(getWorkers).mockImplementation(this.handleGetWorkers);
- jest.mocked(setWorkerCount).mockImplementation(this.handleSetWorkerCount);
- jest.mocked(getTasksForComponent).mockImplementation(this.handleGetTaskForComponent);
- jest.mocked(getAnalysisStatus).mockImplementation(this.handleAnalysisStatus);
-
- this.tasks = cloneDeep(DEFAULT_TASKS);
- }
-
- handleCancelAllTasks = () => {
- this.tasks.forEach((t) => {
- if (CANCELABLE_TASK_STATUSES.includes(t.status)) {
- t.status = TaskStatuses.Canceled;
- }
- });
-
- return Promise.resolve();
- };
-
- setTaskWarnings = (taskWarnings: TaskWarning[] = []) => {
- this.taskWarnings = taskWarnings;
- };
-
- handleAnalysisStatus = (data: { branch?: string; component: string; pullRequest?: string }) => {
- return Promise.resolve({
- component: {
- key: data.component,
- name: data.component,
- branch: data.branch,
- pullRequest: data.pullRequest,
- warnings: this.taskWarnings,
- },
- });
- };
-
- handleCancelTask = (id: string) => {
- const task = this.tasks.find((t) => t.id === id);
-
- if (task && CANCELABLE_TASK_STATUSES.includes(task.status)) {
- task.status = TaskStatuses.Canceled;
- return Promise.resolve(task);
- }
-
- return Promise.reject();
- };
-
- handleGetActivity = (data: ActivityRequestParameters) => {
- let results = cloneDeep(this.tasks);
- results = results.filter((task) => {
- return !(
- (data.component && task.componentKey !== data.component) ||
- (data.status && !data.status.split(',').includes(task.status)) ||
- (data.type && task.type !== data.type) ||
- (data.minSubmittedAt &&
- isBefore(parseDate(task.submittedAt), parseDate(data.minSubmittedAt))) ||
- (data.maxExecutedAt &&
- (!task.executedAt ||
- isAfter(parseDate(task.executedAt), parseDate(data.maxExecutedAt)))) ||
- (data.q &&
- !task.id.includes(data.q) &&
- !task.componentName?.includes(data.q) &&
- !task.componentKey?.includes(data.q))
- );
- });
-
- results.sort((a, b) => {
- const getMaxDate = (t: Task) =>
- Math.max(
- +new Date(t.submittedAt),
- +new Date(t.startedAt ?? 0),
- +new Date(t.executedAt ?? 0),
- );
-
- return getMaxDate(b) - getMaxDate(a);
- });
-
- if (data.onlyCurrents) {
- // This is more complex in real life, but it's a good enough approximation to suit tests.
- results = Object.values(groupBy(results, (t) => t.componentKey))
- .map((tasks) => sortBy(tasks, (t) => t.executedAt).pop())
- .filter(isDefined);
- }
-
- const page = data.p ?? 1;
- const pageSize = data.ps ?? PAGE_SIZE;
- const paginationIndex = (page - 1) * pageSize;
-
- return Promise.resolve({
- tasks: results.slice(paginationIndex, paginationIndex + pageSize),
- paging: {
- pageIndex: page,
- pageSize,
- total: results.length,
- },
- });
- };
-
- handleGetStatus = (component?: string) => {
- return Promise.resolve(
- this.tasks
- .filter((task) => !component || task.componentKey === component)
- .reduce(
- (stats, task) => {
- switch (task.status) {
- case TaskStatuses.Failed:
- stats.failing += 1;
- break;
- case TaskStatuses.InProgress:
- stats.inProgress += 1;
- break;
- case TaskStatuses.Pending:
- stats.pendingTime = Math.max(
- stats.pendingTime,
- differenceInMilliseconds(parseDate(task.submittedAt), Date.now()),
- );
- stats.pending += 1;
- break;
- }
-
- return stats;
- },
- { failing: 0, inProgress: 0, pending: 0, pendingTime: 0 },
- ),
- );
- };
-
- handleGetTypes = () => Promise.resolve([...TASK_TYPES]);
-
- handleGetTask = (id: string) => {
- const task = this.tasks.find((t) => t.id === id);
-
- if (task) {
- return Promise.resolve(task);
- }
-
- return Promise.reject();
- };
-
- handleGetWorkers = () => Promise.resolve({ ...this.workers });
-
- handleSetWorkerCount = (count: number) => {
- this.workers.value = count;
- return Promise.resolve();
- };
-
- handleGetTaskForComponent = (componentKey: string) => {
- const tasks = this.tasks.filter((t) => t.componentKey === componentKey);
- return Promise.resolve({
- queue: tasks.filter(
- (t) => t.status === TaskStatuses.InProgress || t.status === TaskStatuses.Pending,
- ),
- current: tasks.find(
- (t) => t.status === TaskStatuses.Success || t.status === TaskStatuses.Failed,
- ),
- });
- };
-
- /*
- * Helpers
- */
-
- reset() {
- this.tasks = cloneDeep(DEFAULT_TASKS);
- this.taskWarnings = [];
- this.workers = { ...DEFAULT_WORKERS };
- }
-
- toggleCanSetWorkerCount = (flag?: boolean) => {
- this.workers.canSetWorkerCount = flag ?? !this.workers.canSetWorkerCount;
- };
-
- addTask = (overrides: Partial<Task> = {}) => {
- const id = Math.random().toString(RANDOM_RADIX).slice(RANDOM_PREFIX);
-
- this.tasks.push(
- mockTask({
- id,
- ...overrides,
- }),
- );
- };
-
- createTasks = (count: number, status = TaskStatuses.Success) => {
- for (let i = 0; i < count; i++) {
- this.addTask({ status });
- }
- };
-
- clearTasks = () => {
- this.tasks = [];
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/CveServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/CveServiceMock.ts
deleted file mode 100644
index 6456bddc697..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/CveServiceMock.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { mockCve } from '../../helpers/testMocks';
-import { Cve } from '../../types/cves';
-import { getCve } from '../cves';
-
-jest.mock('../../api/cves');
-
-export const DEFAULT_CVE_LIST = [
- mockCve({ id: 'CVE-2021-12345' }),
- mockCve({ id: 'CVE-2021-12346' }),
-];
-
-export default class CveServiceMock {
- private cveList: Cve[];
-
- constructor() {
- this.cveList = cloneDeep(DEFAULT_CVE_LIST);
- jest.mocked(getCve).mockImplementation(this.handleGetCve);
- }
-
- setCveList(cveList: Cve[]) {
- this.cveList = cveList;
- }
-
- handleGetCve = (cveId: string) => {
- const cve = this.cveList.find((cve) => cve.id === cveId);
- if (!cve) {
- return Promise.reject(new Error('Cve not found'));
- }
- return this.reply(cve);
- };
-
- reset = () => {
- this.cveList = cloneDeep(DEFAULT_CVE_LIST);
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/DependenciesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/DependenciesServiceMock.ts
deleted file mode 100644
index 9fed3a7692e..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/DependenciesServiceMock.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { DependenciesResponse } from '../../types/dependencies';
-import { getDependencies } from '../dependencies';
-
-jest.mock('../dependencies');
-
-export const DEFAULT_DEPENDENCIES_MOCK: DependenciesResponse = {
- page: {
- pageIndex: 1,
- pageSize: 50,
- total: 0,
- },
- dependencies: [],
-};
-
-export default class DependenciesServiceMock {
- #defaultDependenciesData: DependenciesResponse = DEFAULT_DEPENDENCIES_MOCK;
-
- constructor() {
- jest.mocked(getDependencies).mockImplementation(this.handleGetDependencies);
- }
-
- reset = () => {
- this.#defaultDependenciesData = cloneDeep(DEFAULT_DEPENDENCIES_MOCK);
- return this;
- };
-
- setDefaultDependencies = (response: DependenciesResponse) => {
- this.#defaultDependenciesData = response;
- };
-
- handleGetDependencies = (data: { pageParam: number; q?: string }) => {
- const { pageSize } = this.#defaultDependenciesData.page;
- const totalDependencies = this.#defaultDependenciesData.dependencies.length;
-
- if (pageSize < totalDependencies) {
- const startIndex = (data.pageParam - 1) * pageSize;
- const endIndex = startIndex + pageSize;
-
- return Promise.resolve({
- ...this.#defaultDependenciesData,
- dependencies: this.#defaultDependenciesData.dependencies.slice(startIndex, endIndex),
- });
- }
-
- return Promise.resolve({
- ...this.#defaultDependenciesData,
- dependencies: this.#defaultDependenciesData.dependencies.filter(
- (dependency) =>
- typeof data.q !== 'string' ||
- dependency.name.toLowerCase().includes(data.q.toLowerCase()),
- ),
- });
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/DopTranslationServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/DopTranslationServiceMock.ts
deleted file mode 100644
index adf7c33c8ea..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/DopTranslationServiceMock.ts
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep, omit } from 'lodash';
-import { mockGitHubConfiguration } from '../../helpers/mocks/dop-translation';
-import { mockPaging } from '../../helpers/testMocks';
-import { AlmKeys } from '../../types/alm-settings';
-import {
- DopSetting,
- GitHubConfigurationResponse,
- ProjectBinding,
-} from '../../types/dop-translation';
-import {
- createBoundProject,
- createGitHubConfiguration,
- deleteGitHubConfiguration,
- fetchGitHubConfiguration,
- getDopSettings,
- getProjectBindings,
- searchGitHubConfigurations,
- updateGitHubConfiguration,
-} from '../dop-translation';
-import { mockDopSetting, mockProjectBinding } from './data/dop-translation';
-
-jest.mock('../dop-translation');
-
-const defaultDopSettings = [
- mockDopSetting({ key: 'conf-final-1', type: AlmKeys.GitLab }),
- mockDopSetting({ key: 'conf-final-2', type: AlmKeys.GitLab }),
- mockDopSetting({ key: 'conf-github-1', type: AlmKeys.GitHub, url: 'http://url' }),
- mockDopSetting({ key: 'conf-github-2', type: AlmKeys.GitHub, url: 'http://url' }),
- mockDopSetting({ key: 'conf-github-3', type: AlmKeys.GitHub, url: 'javascript://url' }),
- mockDopSetting({ key: 'conf-azure-1', type: AlmKeys.Azure, url: 'url' }),
- mockDopSetting({ key: 'conf-azure-2', type: AlmKeys.Azure, url: 'url' }),
- mockDopSetting({
- key: 'conf-bitbucketcloud-1',
- type: AlmKeys.BitbucketCloud,
- url: 'url',
- }),
- mockDopSetting({
- key: 'conf-bitbucketcloud-2',
- type: AlmKeys.BitbucketCloud,
- url: 'url',
- }),
- mockDopSetting({
- key: 'conf-bitbucketserver-1',
- type: AlmKeys.BitbucketServer,
- url: 'url',
- }),
- mockDopSetting({
- key: 'conf-bitbucketserver-2',
- type: AlmKeys.BitbucketServer,
- url: 'url',
- }),
- mockDopSetting(),
- mockDopSetting({ id: 'dop-setting-test-id-2', key: 'Test/DopSetting2' }),
-];
-const defaultProjectBindings = [
- mockProjectBinding({
- dopSetting: 'conf-github-1',
- id: 'project-binding-1',
- projectId: 'key123',
- projectKey: 'key123',
- repository: 'Github repo 1',
- slug: 'Slug/Repository-1',
- }),
-];
-
-export default class DopTranslationServiceMock {
- projectBindings: ProjectBinding[] = [];
- dopSettings: DopSetting[] = [];
- gitHubConfigurations: GitHubConfigurationResponse[] = [];
-
- constructor() {
- this.reset();
- jest.mocked(createBoundProject).mockImplementation(this.createBoundProject);
- jest.mocked(getDopSettings).mockImplementation(this.getDopSettings);
- jest.mocked(getProjectBindings).mockImplementation(this.getProjectBindings);
- jest
- .mocked(searchGitHubConfigurations)
- .mockImplementation(this.handleSearchGitHubConfigurations);
- jest.mocked(fetchGitHubConfiguration).mockImplementation(this.handleFetchGitHubConfiguration);
- jest.mocked(createGitHubConfiguration).mockImplementation(this.handleCreateGitHubConfiguration);
- jest.mocked(updateGitHubConfiguration).mockImplementation(this.handleUpdateGitHubConfiguration);
- jest.mocked(deleteGitHubConfiguration).mockImplementation(this.handleDeleteGitHubConfiguration);
- }
-
- /*
- * Project bindings
- */
- createBoundProject: typeof createBoundProject = (data) => {
- this.projectBindings.push(
- mockProjectBinding({
- dopSetting: data.devOpsPlatformSettingId,
- id: `${data.devOpsPlatformSettingId}-${data.repositoryIdentifier}-${data.projectKey}`,
- projectId: data.projectKey,
- repository: data.repositoryIdentifier,
- }),
- );
- return Promise.resolve({});
- };
-
- getDopSettings = () => {
- const total = this.getDopSettings.length;
- return Promise.resolve({
- dopSettings: this.dopSettings,
- page: mockPaging({ pageSize: total, total }),
- });
- };
-
- getProjectBindings: typeof getProjectBindings = (params) => {
- const pageIndex = params.pageIndex ?? 1;
- const pageSize = params.pageSize ?? 50;
-
- return this.reply({
- page: {
- pageIndex,
- pageSize,
- total: this.projectBindings.length,
- },
- projectBindings: this.projectBindings.slice((pageIndex - 1) * pageSize, pageIndex * pageSize),
- });
- };
-
- removeDopTypeFromSettings = (type: AlmKeys) => {
- this.dopSettings = cloneDeep(defaultDopSettings).filter(
- (dopSetting) => dopSetting.type !== type,
- );
- };
-
- /*
- * GitHub configurations
- */
- handleSearchGitHubConfigurations: typeof searchGitHubConfigurations = () => {
- return Promise.resolve({
- githubConfigurations: this.gitHubConfigurations,
- page: mockPaging({ total: this.gitHubConfigurations.length }),
- });
- };
-
- handleFetchGitHubConfiguration: typeof fetchGitHubConfiguration = (id: string) => {
- const configuration = this.gitHubConfigurations.find((c) => c.id === id);
- if (!configuration) {
- return Promise.reject();
- }
- return Promise.resolve(configuration);
- };
-
- handleCreateGitHubConfiguration: typeof createGitHubConfiguration = (gitHubConfiguration) => {
- const newConfig = mockGitHubConfiguration({
- ...omit(gitHubConfiguration, 'clientId', 'clientSecret', 'privateKey'),
- id: '1',
- enabled: false,
- });
- this.gitHubConfigurations = [...this.gitHubConfigurations, newConfig];
- return Promise.resolve(newConfig);
- };
-
- handleUpdateGitHubConfiguration: typeof updateGitHubConfiguration = (id, gitHubConfiguration) => {
- const index = this.gitHubConfigurations.findIndex((c) => c.id === id);
- this.gitHubConfigurations[index] = {
- ...this.gitHubConfigurations[index],
- ...gitHubConfiguration,
- };
- return Promise.resolve(this.gitHubConfigurations[index]);
- };
-
- handleDeleteGitHubConfiguration: typeof deleteGitHubConfiguration = (id) => {
- this.gitHubConfigurations = this.gitHubConfigurations.filter((c) => c.id !== id);
- return Promise.resolve();
- };
-
- reset() {
- this.projectBindings = cloneDeep(defaultProjectBindings);
- this.dopSettings = cloneDeep(defaultDopSettings);
- this.gitHubConfigurations = [];
- }
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/FixSuggestionsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/FixSuggestionsServiceMock.ts
deleted file mode 100644
index 38d0f8ea62c..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/FixSuggestionsServiceMock.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import {
- FixParam,
- getFixSuggestionServiceInfo,
- getFixSuggestionsIssues,
- getSuggestions,
- ServiceInfo,
- SubscriptionType,
- SuggestionServiceStatus,
- updateFeatureEnablement,
- UpdateFeatureEnablementParams,
-} from '../fix-suggestions';
-import { ISSUE_101, ISSUE_1101 } from './data/ids';
-
-jest.mock('../fix-suggestions');
-
-export type MockFixSuggestionServiceInfo = {
- isEnabled?: boolean;
- status: SuggestionServiceStatus | 'WTF';
- subscriptionType?: SubscriptionType | 'WTF';
-};
-
-export default class FixSuggestionsServiceMock {
- fixSuggestion = {
- id: '70b14d4c-d302-4979-9121-06ac7d563c5c',
- issueId: 'AYsVhClEbjXItrbcN71J',
- explanation:
- "Replaced 'require' statements with 'import' statements to comply with ECMAScript 2015 module management standards.",
- changes: [
- {
- startLine: 6,
- endLine: 7,
- newCode: "import { glob } from 'glob';\nimport fs from 'fs';",
- },
- ],
- };
-
- serviceInfo: MockFixSuggestionServiceInfo | undefined = {
- status: 'SUCCESS',
- subscriptionType: 'PAID',
- };
-
- constructor() {
- jest.mocked(getSuggestions).mockImplementation(this.handleGetFixSuggestion);
- jest.mocked(getFixSuggestionsIssues).mockImplementation(this.handleGetFixSuggestionsIssues);
- jest.mocked(getFixSuggestionServiceInfo).mockImplementation(this.handleGetServiceInfo);
- jest.mocked(updateFeatureEnablement).mockImplementation(this.handleUpdateFeatureEnablement);
- }
-
- handleGetFixSuggestionsIssues = (data: FixParam) => {
- if (data.issueId === ISSUE_1101) {
- return this.reply({ aiSuggestion: 'NOT_AVAILABLE_FILE_LEVEL_ISSUE', id: 'id1' } as const);
- }
- return this.reply({ aiSuggestion: 'AVAILABLE', id: 'id1' } as const);
- };
-
- handleGetFixSuggestion = (data: FixParam) => {
- if (data.issueId === ISSUE_101) {
- return Promise.reject({ error: { msg: 'Invalid issue' } });
- }
- return this.reply(this.fixSuggestion);
- };
-
- handleGetServiceInfo = () => {
- if (this.serviceInfo) {
- return this.reply(this.serviceInfo as ServiceInfo);
- }
- return Promise.reject({ error: { msg: 'Error' } });
- };
-
- handleUpdateFeatureEnablement = (_: UpdateFeatureEnablementParams) => {
- return Promise.resolve();
- };
-
- reply<T>(response: T): Promise<T> {
- return new Promise((resolve) => {
- setTimeout(() => {
- resolve(cloneDeep(response));
- }, 10);
- });
- }
-
- setServiceInfo(info: MockFixSuggestionServiceInfo | undefined) {
- this.serviceInfo = info;
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/GithubProvisioningServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/GithubProvisioningServiceMock.ts
deleted file mode 100644
index 31a9c31d4a3..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/GithubProvisioningServiceMock.ts
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { mockTask } from '../../helpers/mocks/tasks';
-import {
- DevopsRolesMapping,
- GitHubConfigurationStatus,
- GitHubProvisioningStatus,
- ProvisioningType,
-} from '../../types/provisioning';
-import { Task, TaskStatuses, TaskTypes } from '../../types/tasks';
-import {
- addGithubRolesMapping,
- checkConfigurationValidity,
- deleteGithubRolesMapping,
- fetchGithubProvisioningStatus,
- fetchGithubRolesMapping,
- updateGithubRolesMapping,
-} from '../github-provisioning';
-import DopTranslationServiceMock from './DopTranslationServiceMock';
-
-jest.mock('../github-provisioning');
-
-const defaultConfigurationStatus: GitHubConfigurationStatus = {
- application: {
- jit: {
- status: GitHubProvisioningStatus.Success,
- },
- autoProvisioning: {
- status: GitHubProvisioningStatus.Success,
- },
- },
- installations: [
- {
- organization: 'testOrg',
- autoProvisioning: {
- status: GitHubProvisioningStatus.Success,
- },
- jit: {
- status: GitHubProvisioningStatus.Success,
- },
- },
- ],
-};
-
-const githubMappingMock = (
- id: string,
- permissions: (keyof DevopsRolesMapping['permissions'])[],
- baseRole = false,
-) => ({
- id,
- role: id,
- baseRole,
- permissions: {
- user: permissions.includes('user'),
- codeViewer: permissions.includes('codeViewer'),
- issueAdmin: permissions.includes('issueAdmin'),
- securityHotspotAdmin: permissions.includes('securityHotspotAdmin'),
- admin: permissions.includes('admin'),
- scan: permissions.includes('scan'),
- },
-});
-
-const defaultMapping: DevopsRolesMapping[] = [
- githubMappingMock('read', ['user', 'codeViewer'], true),
- githubMappingMock(
- 'write',
- ['user', 'codeViewer', 'issueAdmin', 'securityHotspotAdmin', 'scan'],
- true,
- ),
- githubMappingMock('triage', ['user', 'codeViewer'], true),
- githubMappingMock(
- 'maintain',
- ['user', 'codeViewer', 'issueAdmin', 'securityHotspotAdmin', 'scan'],
- true,
- ),
- githubMappingMock(
- 'admin',
- ['user', 'codeViewer', 'issueAdmin', 'securityHotspotAdmin', 'admin', 'scan'],
- true,
- ),
-];
-
-export default class GithubProvisioningServiceMock {
- dopTranslationServiceMock?: DopTranslationServiceMock;
- githubConfigurationStatus: GitHubConfigurationStatus;
- githubMapping: DevopsRolesMapping[];
- tasks: Task[];
-
- constructor(dopTranslationServiceMock?: DopTranslationServiceMock) {
- this.dopTranslationServiceMock = dopTranslationServiceMock;
- this.githubConfigurationStatus = cloneDeep(defaultConfigurationStatus);
- this.githubMapping = cloneDeep(defaultMapping);
- this.tasks = [];
- jest
- .mocked(fetchGithubProvisioningStatus)
- .mockImplementation(this.handleFetchGithubProvisioningStatus);
- jest
- .mocked(checkConfigurationValidity)
- .mockImplementation(this.handleCheckConfigurationValidity);
- jest.mocked(fetchGithubRolesMapping).mockImplementation(this.handleFetchGithubRolesMapping);
- jest.mocked(updateGithubRolesMapping).mockImplementation(this.handleUpdateGithubRolesMapping);
- jest.mocked(addGithubRolesMapping).mockImplementation(this.handleAddGithubRolesMapping);
- jest.mocked(deleteGithubRolesMapping).mockImplementation(this.handleDeleteGithubRolesMapping);
- }
-
- addProvisioningTask = (overrides: Partial<Omit<Task, 'type'>> = {}) => {
- this.tasks.push(
- mockTask({
- id: Math.random().toString(),
- type: TaskTypes.GithubProvisioning,
- ...overrides,
- }),
- );
- };
-
- setConfigurationValidity = (overrides: Partial<GitHubConfigurationStatus> = {}) => {
- this.githubConfigurationStatus = {
- ...this.githubConfigurationStatus,
- ...overrides,
- };
- };
-
- handleFetchGithubProvisioningStatus = () => {
- if (
- this.dopTranslationServiceMock?.gitHubConfigurations[0]?.enabled !== true ||
- this.dopTranslationServiceMock?.gitHubConfigurations[0]?.provisioningType !==
- ProvisioningType.auto
- ) {
- return Promise.resolve({ enabled: false });
- }
-
- const nextSync = this.tasks.find((t: Task) =>
- [TaskStatuses.InProgress, TaskStatuses.Pending].includes(t.status),
- );
- const lastSync = this.tasks.find(
- (t: Task) => ![TaskStatuses.InProgress, TaskStatuses.Pending].includes(t.status),
- );
-
- return Promise.resolve({
- enabled: true,
- nextSync: nextSync ? { status: nextSync.status } : undefined,
- lastSync: lastSync
- ? {
- status: lastSync.status,
- finishedAt: lastSync.executedAt,
- startedAt: lastSync.startedAt,
- executionTimeMs: lastSync.executionTimeMs,
- summary: lastSync.status === TaskStatuses.Success ? 'Test summary' : undefined,
- errorMessage: lastSync.errorMessage,
- warningMessage: lastSync.warnings?.join() ?? undefined,
- }
- : undefined,
- });
- };
-
- handleCheckConfigurationValidity = () => {
- return Promise.resolve(this.githubConfigurationStatus);
- };
-
- handleFetchGithubRolesMapping: typeof fetchGithubRolesMapping = () => {
- return Promise.resolve(this.githubMapping);
- };
-
- handleUpdateGithubRolesMapping: typeof updateGithubRolesMapping = (id, data) => {
- this.githubMapping = this.githubMapping.map((mapping) =>
- mapping.id === id ? { ...mapping, ...data } : mapping,
- );
-
- return Promise.resolve(
- this.githubMapping.find((mapping) => mapping.id === id) as DevopsRolesMapping,
- );
- };
-
- handleAddGithubRolesMapping: typeof addGithubRolesMapping = (data) => {
- const newRole = { ...data, id: data.role };
- this.githubMapping = [...this.githubMapping, newRole];
-
- return Promise.resolve(newRole);
- };
-
- handleDeleteGithubRolesMapping: typeof deleteGithubRolesMapping = (id) => {
- this.githubMapping = this.githubMapping.filter((el) => el.id !== id);
- return Promise.resolve();
- };
-
- addGitHubCustomRole = (id: string, permissions: (keyof DevopsRolesMapping['permissions'])[]) => {
- this.githubMapping = [...this.githubMapping, githubMappingMock(id, permissions)];
- };
-
- reset = () => {
- this.githubConfigurationStatus = cloneDeep(defaultConfigurationStatus);
- this.githubMapping = cloneDeep(defaultMapping);
- this.tasks = [];
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/GitlabProvisioningServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/GitlabProvisioningServiceMock.ts
deleted file mode 100644
index df81238eb66..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/GitlabProvisioningServiceMock.ts
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep, omit } from 'lodash';
-import { mockGitlabConfiguration } from '../../helpers/mocks/alm-integrations';
-import { mockPaging } from '../../helpers/testMocks';
-import { DevopsRolesMapping, GitlabConfiguration } from '../../types/provisioning';
-import {
- addGitlabRolesMapping,
- createGitLabConfiguration,
- deleteGitLabConfiguration,
- deleteGitlabRolesMapping,
- fetchGitLabConfiguration,
- fetchGitLabConfigurations,
- fetchGitlabRolesMapping,
- updateGitLabConfiguration,
- updateGitlabRolesMapping,
-} from '../gitlab-provisioning';
-
-jest.mock('../gitlab-provisioning');
-
-const defaultGitlabConfiguration: GitlabConfiguration[] = [
- mockGitlabConfiguration({ id: '1', enabled: true }),
-];
-
-const gitlabMappingMock = (
- id: string,
- permissions: (keyof DevopsRolesMapping['permissions'])[],
- baseRole = false,
-) => ({
- id,
- role: id,
- baseRole,
- permissions: {
- user: permissions.includes('user'),
- codeViewer: permissions.includes('codeViewer'),
- issueAdmin: permissions.includes('issueAdmin'),
- securityHotspotAdmin: permissions.includes('securityHotspotAdmin'),
- admin: permissions.includes('admin'),
- scan: permissions.includes('scan'),
- },
-});
-
-const defaultMapping: DevopsRolesMapping[] = [
- gitlabMappingMock('guest', ['user', 'codeViewer'], true),
- gitlabMappingMock('reporter', ['user', 'codeViewer'], true),
- gitlabMappingMock(
- 'developer',
- ['user', 'codeViewer', 'issueAdmin', 'securityHotspotAdmin', 'scan'],
- true,
- ),
- gitlabMappingMock(
- 'maintainer',
- ['user', 'codeViewer', 'issueAdmin', 'securityHotspotAdmin', 'scan'],
- true,
- ),
- gitlabMappingMock(
- 'owner',
- ['user', 'codeViewer', 'issueAdmin', 'securityHotspotAdmin', 'admin', 'scan'],
- true,
- ),
-];
-
-export default class GitlabProvisioningServiceMock {
- gitlabConfigurations: GitlabConfiguration[];
- gitlabMapping: DevopsRolesMapping[];
-
- constructor() {
- this.gitlabConfigurations = cloneDeep(defaultGitlabConfiguration);
- this.gitlabMapping = cloneDeep(defaultMapping);
- jest.mocked(fetchGitLabConfigurations).mockImplementation(this.handleFetchGitLabConfigurations);
- jest.mocked(fetchGitLabConfiguration).mockImplementation(this.handleFetchGitLabConfiguration);
- jest.mocked(createGitLabConfiguration).mockImplementation(this.handleCreateGitLabConfiguration);
- jest.mocked(updateGitLabConfiguration).mockImplementation(this.handleUpdateGitLabConfiguration);
- jest.mocked(deleteGitLabConfiguration).mockImplementation(this.handleDeleteGitLabConfiguration);
- jest.mocked(fetchGitlabRolesMapping).mockImplementation(this.handleFetchGilabRolesMapping);
- jest.mocked(updateGitlabRolesMapping).mockImplementation(this.handleUpdateGitlabRolesMapping);
- }
-
- handleFetchGitLabConfigurations: typeof fetchGitLabConfigurations = () => {
- return Promise.resolve({
- gitlabConfigurations: this.gitlabConfigurations,
- page: mockPaging({ total: this.gitlabConfigurations.length }),
- });
- };
-
- handleFetchGitLabConfiguration: typeof fetchGitLabConfiguration = (id: string) => {
- const configuration = this.gitlabConfigurations.find((c) => c.id === id);
- if (!configuration) {
- return Promise.reject();
- }
- return Promise.resolve(configuration);
- };
-
- handleCreateGitLabConfiguration: typeof createGitLabConfiguration = (data) => {
- const newConfig = mockGitlabConfiguration({
- ...omit(data, 'applicationId', 'clientSecret'),
- id: '1',
- enabled: true,
- });
- this.gitlabConfigurations = [...this.gitlabConfigurations, newConfig];
- return Promise.resolve(newConfig);
- };
-
- handleUpdateGitLabConfiguration: typeof updateGitLabConfiguration = (id, data) => {
- const index = this.gitlabConfigurations.findIndex((c) => c.id === id);
- this.gitlabConfigurations[index] = { ...this.gitlabConfigurations[index], ...data };
- return Promise.resolve(this.gitlabConfigurations[index]);
- };
-
- handleDeleteGitLabConfiguration: typeof deleteGitLabConfiguration = (id) => {
- this.gitlabConfigurations = this.gitlabConfigurations.filter((c) => c.id !== id);
- return Promise.resolve();
- };
-
- setGitlabConfigurations = (gitlabConfigurations: GitlabConfiguration[]) => {
- this.gitlabConfigurations = gitlabConfigurations;
- };
-
- handleFetchGilabRolesMapping: typeof fetchGitlabRolesMapping = () => {
- return Promise.resolve(this.gitlabMapping);
- };
-
- handleUpdateGitlabRolesMapping: typeof updateGitlabRolesMapping = (id, data) => {
- this.gitlabMapping = this.gitlabMapping.map((mapping) =>
- mapping.id === id ? { ...mapping, ...data } : mapping,
- );
-
- return Promise.resolve(
- this.gitlabMapping.find((mapping) => mapping.id === id) as DevopsRolesMapping,
- );
- };
-
- handleAddGitlabRolesMapping: typeof addGitlabRolesMapping = (data) => {
- const newRole = { ...data, id: data.role };
- this.gitlabMapping = [...this.gitlabMapping, newRole];
-
- return Promise.resolve(newRole);
- };
-
- handleDeleteGitlabRolesMapping: typeof deleteGitlabRolesMapping = (id) => {
- this.gitlabMapping = this.gitlabMapping.filter((el) => el.id !== id);
- return Promise.resolve();
- };
-
- addGitLabCustomRole = (id: string, permissions: (keyof DevopsRolesMapping['permissions'])[]) => {
- this.gitlabMapping = [...this.gitlabMapping, gitlabMappingMock(id, permissions)];
- };
-
- reset = () => {
- this.gitlabConfigurations = cloneDeep(defaultGitlabConfiguration);
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/GroupMembersipsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/GroupMembersipsServiceMock.ts
deleted file mode 100644
index 95bc2496b93..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/GroupMembersipsServiceMock.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { mockGroupMembership } from '../../helpers/testMocks';
-import { GroupMembership } from '../../types/types';
-import {
- addGroupMembership,
- getGroupMemberships,
- removeGroupMembership,
-} from '../group-memberships';
-
-jest.mock('../group-memberships');
-
-export default class GroupMembershipsServiceMock {
- memberships: GroupMembership[];
-
- defaultMemberships = [];
-
- constructor() {
- this.memberships = cloneDeep(this.defaultMemberships);
-
- jest.mocked(getGroupMemberships).mockImplementation(this.handleGetGroupMemberships);
- jest.mocked(addGroupMembership).mockImplementation(this.handleAddGroupMembership);
- jest.mocked(removeGroupMembership).mockImplementation(this.handleRemoveGroupMembership);
- }
-
- handleAddGroupMembership: typeof addGroupMembership = ({
- userId,
- groupId,
- }: {
- groupId: string;
- userId: string;
- }): Promise<GroupMembership> => {
- const newMembership = mockGroupMembership({ userId, groupId });
- this.memberships.push(newMembership);
- return this.reply(newMembership);
- };
-
- handleRemoveGroupMembership: typeof removeGroupMembership = (id: string) => {
- if (!this.memberships.some((g) => g.id === id)) {
- return Promise.reject();
- }
-
- this.memberships = this.memberships.filter((g) => g.id !== id);
- return this.reply(undefined);
- };
-
- handleGetGroupMemberships: typeof getGroupMemberships = ({
- userId,
- groupId,
- pageSize = 50,
- pageIndex = 1,
- }) => {
- const allMemberships = this.memberships
- .filter((m) => userId === undefined || m.userId === userId)
- .filter((m) => groupId === undefined || m.groupId === groupId);
- const groupMemberships = allMemberships.slice((pageIndex - 1) * pageSize, pageIndex * pageSize);
- return this.reply({
- page: { pageIndex, pageSize, total: allMemberships.length },
- groupMemberships,
- });
- };
-
- reset() {
- this.memberships = cloneDeep(this.defaultMemberships);
- }
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/GroupsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/GroupsServiceMock.ts
deleted file mode 100644
index 735c7bd707c..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/GroupsServiceMock.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { mockGroup, mockIdentityProvider } from '../../helpers/testMocks';
-import { Group, IdentityProvider, Paging, Provider } from '../../types/types';
-import { createGroup, deleteGroup, getUsersGroups, updateGroup } from '../user_groups';
-
-jest.mock('../user_groups');
-
-export default class GroupsServiceMock {
- provider: Provider | undefined;
- groups: Group[];
- readOnlyGroups = [
- mockGroup({ name: 'managed-group', managed: true, id: '1' }),
- mockGroup({ name: 'local-group', managed: false, id: '2' }),
- ];
-
- constructor() {
- this.groups = cloneDeep(this.readOnlyGroups);
-
- jest.mocked(getUsersGroups).mockImplementation((p) => this.handleSearchUsersGroups(p));
- jest.mocked(createGroup).mockImplementation((g) => this.handleCreateGroup(g));
- jest.mocked(deleteGroup).mockImplementation((id) => this.handleDeleteGroup(id));
- jest.mocked(updateGroup).mockImplementation((id, data) => this.handleUpdateGroup(id, data));
- }
-
- reset() {
- this.groups = cloneDeep(this.readOnlyGroups);
- }
-
- handleCreateGroup = (group: { description?: string; name: string }): Promise<Group> => {
- const newGroup = mockGroup(group);
- this.groups.push(newGroup);
- return this.reply(newGroup);
- };
-
- handleDeleteGroup: typeof deleteGroup = (id: string) => {
- if (!this.groups.some((g) => g.id === id)) {
- return Promise.reject();
- }
-
- const groupToDelete = this.groups.find((g) => g.id === id);
- if (groupToDelete?.managed) {
- return Promise.reject();
- }
-
- this.groups = this.groups.filter((g) => g.id !== id);
- return this.reply(undefined);
- };
-
- handleUpdateGroup: typeof updateGroup = (id, data): Promise<Record<string, never>> => {
- const group = this.groups.find((g) => g.id === id);
- if (group === undefined) {
- return Promise.reject();
- }
-
- if (data.description !== undefined) {
- group.description = data.description;
- }
-
- if (data.name !== undefined) {
- group.name = data.name;
- }
-
- return this.reply({});
- };
-
- handleSearchUsersGroups = (
- params: Parameters<typeof getUsersGroups>[0],
- ): Promise<{ groups: Group[]; page: Paging }> => {
- const pageIndex = params.pageIndex ?? 1;
- const pageSize = params.pageSize ?? 10;
- const groups = this.groups
- .filter((g) => !params.q || g.name.includes(params.q))
- .filter((g) => params.managed === undefined || g.managed === params.managed);
- return this.reply({
- page: {
- pageIndex,
- pageSize,
- total: groups.length,
- },
- groups: groups.slice((pageIndex - 1) * pageSize, pageIndex * pageSize),
- });
- };
-
- handleGetIdentityProviders = (): Promise<{ identityProviders: IdentityProvider[] }> => {
- return this.reply({ identityProviders: [mockIdentityProvider()] });
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts
deleted file mode 100644
index aa20fa13185..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/IssuesServiceMock.ts
+++ /dev/null
@@ -1,756 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep, uniqueId } from 'lodash';
-import { RuleDescriptionSections } from '../../apps/coding-rules/rule';
-
-import { ISSUE_STATUSES, ISSUE_TYPES, SEVERITIES, SOURCE_SCOPES } from '../../helpers/constants';
-import { mockIssueAuthors, mockIssueChangelog } from '../../helpers/mocks/issues';
-import { RequestData } from '../../helpers/request';
-import { getStandards } from '../../helpers/security-standard';
-import { mockLoggedInUser, mockPaging, mockRuleDetails } from '../../helpers/testMocks';
-import {
- CleanCodeAttributeCategory,
- SoftwareImpactSeverity,
- SoftwareQuality,
-} from '../../types/clean-code-taxonomy';
-import { SearchRulesResponse } from '../../types/coding-rules';
-import {
- ASSIGNEE_ME,
- IssueDeprecatedStatus,
- IssueResolution,
- IssueSeverity,
- IssueStatus,
- IssueTransition,
- IssueType,
- ListIssuesResponse,
- RawFacet,
- RawIssue,
- RawIssuesResponse,
- ReferencedComponent,
-} from '../../types/issues';
-import { SearchRulesQuery } from '../../types/rules';
-import { Standards } from '../../types/security';
-import { Dict, Rule, RuleActivation, RuleDetails, SnippetsByComponent } from '../../types/types';
-import {
- addIssueComment,
- bulkChangeIssues,
- deleteIssueComment,
- editIssueComment,
- getIssueChangelog,
- getIssueFlowSnippets,
- listIssues,
- searchIssueAuthors,
- searchIssues,
- searchIssueTags,
- setIssueAssignee,
- setIssueSeverity,
- setIssueTags,
- setIssueTransition,
- setIssueType,
-} from '../issues';
-import { getRuleDetails, searchRules } from '../rules';
-import { IssueData, mockIssuesList } from './data/issues';
-import { mockRuleList } from './data/rules';
-import UsersServiceMock from './UsersServiceMock';
-
-jest.mock('../../api/issues');
-// The following 2 mocks are needed, because IssuesServiceMock mocks more than it should.
-// This should be removed once IssuesServiceMock is cleaned up.
-jest.mock('../../api/rules');
-
-function mockReferenceComponent(override?: Partial<ReferencedComponent>) {
- return {
- key: 'component1',
- name: 'Component1',
- uuid: 'id1',
- enabled: true,
- ...override,
- };
-}
-
-function generateReferenceComponentsForIssues(issueData: IssueData[]) {
- return issueData
- .reduce((componentKeys, response) => {
- const componentKey = response.issue.component;
- if (!componentKeys.includes(componentKey)) {
- return [...componentKeys, componentKey];
- }
-
- return componentKeys;
- }, [] as string[])
- .map((key) => mockReferenceComponent({ key, enabled: true }));
-}
-
-const DEFAULT_PAGE_SIZE = 7;
-
-export default class IssuesServiceMock {
- isAdmin = false;
- standards?: Standards;
- usersServiceMock?: UsersServiceMock;
- defaultList: IssueData[];
- rulesList: Rule[];
- list: IssueData[];
- pageSize: number;
-
- constructor(usersServiceMock?: UsersServiceMock) {
- this.usersServiceMock = usersServiceMock;
- this.defaultList = mockIssuesList();
- this.rulesList = mockRuleList();
- this.pageSize = DEFAULT_PAGE_SIZE;
-
- this.list = cloneDeep(this.defaultList);
-
- jest.mocked(addIssueComment).mockImplementation(this.handleAddComment);
- jest.mocked(bulkChangeIssues).mockImplementation(this.handleBulkChangeIssues);
- jest.mocked(deleteIssueComment).mockImplementation(this.handleDeleteComment);
- jest.mocked(editIssueComment).mockImplementation(this.handleEditComment);
- jest.mocked(getIssueChangelog).mockImplementation(this.handleGetIssueChangelog);
- jest.mocked(getIssueFlowSnippets).mockImplementation(this.handleGetIssueFlowSnippets);
- jest.mocked(getRuleDetails).mockImplementation(this.handleGetRuleDetails);
- jest.mocked(listIssues).mockImplementation(this.handleListIssues);
- jest.mocked(searchIssueAuthors).mockImplementation(this.handleSearchIssueAuthors);
- jest.mocked(searchIssues).mockImplementation(this.handleSearchIssues);
- jest.mocked(searchIssueTags).mockImplementation(this.handleSearchIssueTags);
- jest.mocked(searchRules).mockImplementation(this.handleSearchRules);
- jest.mocked(setIssueAssignee).mockImplementation(this.handleSetIssueAssignee);
- jest.mocked(setIssueSeverity).mockImplementation(this.handleSetIssueSeverity);
- jest.mocked(setIssueTags).mockImplementation(this.handleSetIssueTags);
- jest.mocked(setIssueTransition).mockImplementation(this.handleSetIssueTransition);
- jest.mocked(setIssueType).mockImplementation(this.handleSetIssueType);
- }
-
- reset = () => {
- this.list = cloneDeep(this.defaultList);
- this.pageSize = DEFAULT_PAGE_SIZE;
- };
-
- setIssueList = (list: IssueData[]) => {
- this.list = list;
- };
-
- async getStandards(): Promise<Standards> {
- if (this.standards) {
- return this.standards;
- }
- this.standards = await getStandards();
- return this.standards;
- }
-
- owasp2021FacetList(): RawFacet {
- return {
- property: 'owaspTop10-2021',
- values: [{ val: 'a1', count: 0 }],
- };
- }
-
- setIsAdmin(isAdmin: boolean) {
- this.isAdmin = isAdmin;
- }
-
- handleBulkChangeIssues = (issueKeys: string[], query: RequestData) => {
- // For now we only check for issue type and status change.
- this.list
- .filter((i) => issueKeys.includes(i.issue.key))
- .forEach((data) => {
- data.issue.type = query.set_type ?? data.issue.type;
- data.issue.status = query.do_transition ?? data.issue.status;
- });
- return this.reply(undefined);
- };
-
- handleGetIssueFlowSnippets = (issueKey: string): Promise<Dict<SnippetsByComponent>> => {
- const issue = this.list.find((i) => i.issue.key === issueKey);
- if (issue === undefined) {
- return Promise.reject({ errors: [{ msg: `No issue has been found for id ${issueKey}` }] });
- }
- return this.reply(issue.snippets);
- };
-
- handleSearchRules = (req: SearchRulesQuery): Promise<SearchRulesResponse> => {
- const rules = this.rulesList.filter((rule) => {
- const query = req.q?.toLowerCase() || '';
- const nameMatches = rule.name.toLowerCase().includes(query);
- const keyMatches = rule.key.toLowerCase().includes(query);
- const isTypeRight = req.types?.includes(rule.type);
- return isTypeRight && (nameMatches || keyMatches);
- });
- return this.reply({
- rules,
- paging: mockPaging({
- total: rules.length,
- pageIndex: 1,
- pageSize: 30,
- }),
- });
- };
-
- handleGetRuleDetails = (parameters: {
- actives?: boolean;
- key: string;
- }): Promise<{ actives?: RuleActivation[]; rule: RuleDetails }> => {
- if (parameters.key === 'advancedRuleId') {
- return this.reply({
- rule: mockRuleDetails({
- key: parameters.key,
- name: 'Advanced rule',
- htmlNote: '<h1>Extended Description</h1>',
- educationPrinciples: ['defense_in_depth'],
- descriptionSections: [
- {
- key: RuleDescriptionSections.INTRODUCTION,
- content: '<h1>Introduction to this rule</h1>',
- },
- { key: RuleDescriptionSections.ROOT_CAUSE, content: '<h1>Because</h1>' },
- { key: RuleDescriptionSections.HOW_TO_FIX, content: '<h1>Fix with</h1>' },
- {
- content: '<p> Context 1 content<p>',
- key: RuleDescriptionSections.HOW_TO_FIX,
- context: {
- key: 'spring',
- displayName: 'Spring',
- },
- },
- {
- content: '<p> Context 2 content<p>',
- key: RuleDescriptionSections.HOW_TO_FIX,
- context: {
- key: 'context_2',
- displayName: 'Context 2',
- },
- },
- {
- content: '<p> Context 3 content<p>',
- key: RuleDescriptionSections.HOW_TO_FIX,
- context: {
- key: 'context_3',
- displayName: 'Context 3',
- },
- },
- { key: RuleDescriptionSections.RESOURCES, content: '<h1>Link</h1>' },
- ],
- }),
- });
- }
- return this.reply({
- rule: mockRuleDetails({
- key: parameters.key,
- name: 'Simple rule',
- htmlNote: '<h1>Note</h1>',
- descriptionSections: [
- {
- key: RuleDescriptionSections.DEFAULT,
- content: '<h1>Default</h1> Default description',
- },
- ],
- }),
- });
- };
-
- mockFacetDetailResponse = (query: RequestData): RawFacet[] => {
- const facets = (query.facets ?? '').split(',');
- const cleanCodeCategories: CleanCodeAttributeCategory[] = (
- query.cleanCodeAttributeCategories ?? Object.values(CleanCodeAttributeCategory).join(',')
- ).split(',');
- return facets.map((name: string): RawFacet => {
- if (name === 'owaspTop10-2021') {
- return this.owasp2021FacetList();
- }
-
- if (name === 'codeVariants') {
- return {
- property: 'codeVariants',
- values: this.list.reduce(
- (acc, { issue }) => {
- if (issue.codeVariants?.length) {
- issue.codeVariants.forEach((codeVariant) => {
- const item = acc.find(({ val }) => val === codeVariant);
- if (item) {
- item.count++;
- } else {
- acc.push({
- val: codeVariant,
- count: 1,
- });
- }
- });
- }
- return acc;
- },
- [] as RawFacet['values'],
- ),
- };
- }
-
- if (name === 'languages') {
- const counters = {
- [CleanCodeAttributeCategory.Intentional]: { java: 4100, ts: 500 },
- [CleanCodeAttributeCategory.Consistent]: { java: 100, ts: 200 },
- [CleanCodeAttributeCategory.Adaptable]: { java: 21000, ts: 2000 },
- [CleanCodeAttributeCategory.Responsible]: { java: 111, ts: 674 },
- };
- return {
- property: name,
- values: [
- {
- val: 'java',
- count: cleanCodeCategories.reduce<number>(
- (acc, category) => acc + counters[category].java,
- 0,
- ),
- },
- {
- val: 'ts',
- count: cleanCodeCategories.reduce<number>(
- (acc, category) => acc + counters[category].ts,
- 0,
- ),
- },
- ],
- };
- }
-
- return {
- property: name,
- values: (
- {
- severities: SEVERITIES,
- issueStatuses: ISSUE_STATUSES,
- types: ISSUE_TYPES,
- scopes: SOURCE_SCOPES.map(({ scope }) => scope),
- projects: ['org.project1', 'org.sonarsource.javascript:javascript'],
- impactSoftwareQualities: Object.values(SoftwareQuality),
- impactSeverities: Object.values(SoftwareImpactSeverity),
- cleanCodeAttributeCategories: cleanCodeCategories,
- tags: ['unused', 'confusing'],
- rules: ['simpleRuleId', 'advancedRuleId', 'other'],
- assignees: ['email1@sonarsource.com', 'email2@sonarsource.com'],
- author: ['email3@sonarsource.com', 'email4@sonarsource.com'],
- prioritizedRule: ['true', 'false'],
- }[name] ?? []
- ).map((val) => ({
- val,
- count: 1, // if 0, the facet can't be clicked in tests
- })),
- };
- });
- };
-
- handleListIssues = (query: RequestData): Promise<ListIssuesResponse> => {
- const filteredList = this.list
- .filter((item) => !query.types || query.types.split(',').includes(item.issue.type))
- .filter(
- (item) =>
- !query.inNewCodePeriod || new Date(item.issue.creationDate) > new Date('2023-01-10'),
- );
-
- // Splice list items according to paging using a fixed page size
- const pageIndex = query.p || 1;
- const listItems = filteredList.slice(
- (pageIndex - 1) * this.pageSize,
- pageIndex * this.pageSize,
- );
-
- // Generate response
- return this.reply({
- components: generateReferenceComponentsForIssues(filteredList),
- issues: listItems.map((line) => line.issue),
- paging: mockPaging({
- pageIndex,
- pageSize: this.pageSize,
- total: filteredList.length,
- }),
- rules: this.rulesList,
- });
- };
-
- handleSearchIssues = (query: RequestData): Promise<RawIssuesResponse> => {
- const facets = this.mockFacetDetailResponse(query);
-
- // Filter list (only supports assignee, type and severity)
- const filteredList = this.list
- .filter(
- (item) =>
- !query.issueStatuses || query.issueStatuses.split(',').includes(item.issue.issueStatus),
- )
- .filter((item) => {
- if (!query.cleanCodeAttributeCategories) {
- return true;
- }
-
- return query.cleanCodeAttributeCategories
- .split(',')
- .includes(item.issue.cleanCodeAttributeCategory);
- })
- .filter((item) => {
- if (!query.impactSoftwareQualities) {
- return true;
- }
-
- return item.issue.impacts.some(({ softwareQuality }) =>
- query.impactSoftwareQualities.split(',').includes(softwareQuality),
- );
- })
- .filter((item) => {
- if (!query.impactSeverities) {
- return true;
- }
-
- return item.issue.impacts.some(({ severity }) =>
- query.impactSeverities.split(',').includes(severity),
- );
- })
- .filter((item) => {
- if (!query.severities) {
- return true;
- }
-
- return query.severities
- .split(',')
- .some((severity: string) => item.issue.severity.toLowerCase() === severity.toLowerCase());
- })
- .filter((item) => {
- if (!query.assignees) {
- return true;
- }
- if (query.assignees === ASSIGNEE_ME) {
- return item.issue.assignee === mockLoggedInUser().login;
- }
- return query.assignees.split(',').includes(item.issue.assignee);
- })
- .filter((item) => {
- if (!query.tags) {
- return true;
- }
- if (!item.issue.tags) {
- return false;
- }
- return item.issue.tags.some((tag) => query.tags?.split(',').includes(tag));
- })
- .filter(
- (item) =>
- !query.createdBefore ||
- new Date(item.issue.creationDate) <= new Date(query.createdBefore),
- )
- .filter(
- (item) =>
- !query.createdAfter || new Date(item.issue.creationDate) >= new Date(query.createdAfter),
- )
- .filter((item) => !query.types || query.types.split(',').includes(item.issue.type))
- .filter(
- (item) => !query.severities || query.severities.split(',').includes(item.issue.severity),
- )
- .filter((item) => !query.scopes || query.scopes.split(',').includes(item.issue.scope))
- .filter((item) => !query.projects || query.projects.split(',').includes(item.issue.project))
- .filter((item) => !query.rules || query.rules.split(',').includes(item.issue.rule))
- .filter(
- (item) =>
- !query.inNewCodePeriod || new Date(item.issue.creationDate) > new Date('2023-01-10'),
- )
- .filter((item) => {
- if (!query.codeVariants) {
- return true;
- }
- if (!item.issue.codeVariants) {
- return false;
- }
- return item.issue.codeVariants.some((codeVariant) =>
- query.codeVariants?.split(',').includes(codeVariant),
- );
- })
- .filter((item) => {
- if (!query.issues) {
- return true;
- }
- return query.issues.split(',').includes(item.issue.key);
- })
- .filter((item) => {
- if (!query.prioritizedRule) {
- return true;
- }
- return item.issue.prioritizedRule === true;
- });
-
- // Splice list items according to paging using a fixed page size
- const pageIndex = query.p || 1;
- const listItems = filteredList.slice(
- (pageIndex - 1) * this.pageSize,
- pageIndex * this.pageSize,
- );
-
- // Generate response
- return this.reply({
- components: generateReferenceComponentsForIssues(filteredList),
- effortTotal: 199629,
- facets,
- issues: listItems.map((line) => line.issue),
- languages: [{ name: 'java' }, { name: 'python' }, { name: 'ts' }],
- paging: mockPaging({
- pageIndex,
- pageSize: this.pageSize,
- total: filteredList.length,
- }),
- rules: this.rulesList,
- users: [
- { login: 'login0' },
- { login: 'login1', name: 'Login 1' },
- { login: 'login2', name: 'Login 2' },
- ],
- });
- };
-
- handleSetIssueType = (data: { issue: string; type: IssueType }) => {
- return this.getActionsResponse({ type: data.type }, data.issue);
- };
-
- handleSetIssueSeverity = (data: { impact?: string; issue: string; severity?: string }) => {
- const issueDataSelected = this.list.find((l) => l.issue.key === data.issue);
-
- if (!issueDataSelected) {
- throw new Error(`Coulnd't find issue for key ${data.issue}`);
- }
-
- const parsedImpact = data.impact?.split('=');
-
- return this.getActionsResponse(
- data.impact
- ? {
- impacts: issueDataSelected.issue.impacts.map((impact) =>
- impact.softwareQuality === parsedImpact?.[0]
- ? { ...impact, severity: parsedImpact?.[1] as SoftwareImpactSeverity }
- : impact,
- ),
- }
- : { severity: data.severity },
- data.issue,
- );
- };
-
- handleSetIssueAssignee = (data: { assignee?: string; issue: string }) => {
- return this.getActionsResponse(
- {
- assignee:
- data.assignee === '_me' ? this.usersServiceMock?.currentUser.login : data.assignee,
- },
- data.issue,
- );
- };
-
- handleSetIssueTransition = (data: { issue: string; transition: string }) => {
- const issueStatusMap: { [key: string]: IssueStatus } = {
- [IssueTransition.Accept]: IssueStatus.Accepted,
- [IssueTransition.Confirm]: IssueStatus.Confirmed,
- [IssueTransition.UnConfirm]: IssueStatus.Open,
- [IssueTransition.Reopen]: IssueStatus.Open,
- [IssueTransition.Resolve]: IssueStatus.Fixed,
- [IssueTransition.WontFix]: IssueStatus.Accepted,
- [IssueTransition.FalsePositive]: IssueStatus.FalsePositive,
- };
-
- const transitionMap: Dict<IssueTransition[]> = {
- [IssueStatus.Open]: [
- IssueTransition.Accept,
- IssueTransition.Confirm,
- IssueTransition.Resolve,
- IssueTransition.FalsePositive,
- IssueTransition.WontFix,
- ],
- [IssueStatus.Confirmed]: [
- IssueTransition.Accept,
- IssueTransition.Resolve,
- IssueTransition.UnConfirm,
- IssueTransition.FalsePositive,
- IssueTransition.WontFix,
- ],
- [IssueStatus.FalsePositive]: [IssueTransition.Reopen],
- [IssueStatus.Accepted]: [IssueTransition.Reopen],
- [IssueStatus.Fixed]: [IssueTransition.Reopen],
- };
-
- return this.getActionsResponse(
- {
- issueStatus: issueStatusMap[data.transition],
- transitions: transitionMap[issueStatusMap[data.transition]],
- },
- data.issue,
- );
- };
-
- handleSetIssueTags = (data: { issue: string; tags: string }) => {
- const tagsArr = data.tags.split(',');
- return this.getActionsResponse({ tags: tagsArr }, data.issue);
- };
-
- setPageSize = (size: number) => {
- this.pageSize = size;
- };
-
- handleAddComment = (data: { issue: string; text: string }) => {
- return this.getActionsResponse(
- {
- comments: [
- {
- createdAt: '2022-07-28T11:30:04+0200',
- htmlText: data.text,
- key: uniqueId(),
- login: 'admin',
- markdown: data.text,
- updatable: true,
- },
- ],
- },
- data.issue,
- );
- };
-
- handleEditComment = (data: { comment: string; text: string }) => {
- const issueKey = this.list.find((i) => i.issue.comments?.some((c) => c.key === data.comment))
- ?.issue.key;
- if (!issueKey) {
- throw new Error(`Couldn't find issue for comment ${data.comment}`);
- }
- return this.getActionsResponse(
- {
- comments: [
- {
- createdAt: '2022-07-28T11:30:04+0200',
- htmlText: data.text,
- key: data.comment,
- login: 'admin',
- markdown: data.text,
- updatable: true,
- },
- ],
- },
- issueKey,
- );
- };
-
- handleDeleteComment = (data: { comment: string }) => {
- const issue = this.list.find((i) =>
- i.issue.comments?.some((c) => c.key === data.comment),
- )?.issue;
- if (!issue) {
- throw new Error(`Couldn't find issue for comment ${data.comment}`);
- }
- return this.getActionsResponse(
- {
- comments: issue.comments?.filter((c) => c.key !== data.comment),
- },
- issue.key,
- );
- };
-
- handleSearchIssueAuthors = () => {
- return this.reply(mockIssueAuthors());
- };
-
- handleSearchIssueTags = () => {
- return this.reply(['accessibility', 'android', 'unused']);
- };
-
- handleGetIssueChangelog = (_issue: string) => {
- return this.reply({
- changelog: [
- mockIssueChangelog({
- creationDate: '2018-09-01',
- diffs: [
- {
- key: 'status',
- newValue: IssueDeprecatedStatus.Reopened,
- oldValue: IssueDeprecatedStatus.Confirmed,
- },
- ],
- }),
- mockIssueChangelog({
- creationDate: '2018-10-01',
- diffs: [
- {
- key: 'assign',
- newValue: 'darth.vader',
- oldValue: 'luke.skywalker',
- },
- ],
- }),
- mockIssueChangelog({
- creationDate: '2018-11-01',
- diffs: [
- {
- key: 'status',
- newValue: IssueDeprecatedStatus.Reopened,
- oldValue: IssueDeprecatedStatus.Resolved,
- },
- {
- key: 'resolution',
- newValue: IssueResolution.Unresolved,
- oldValue: IssueResolution.WontFix,
- },
- {
- key: 'issueStatus',
- newValue: IssueStatus.Accepted,
- oldValue: IssueStatus.Open,
- },
- ],
- }),
- mockIssueChangelog({
- creationDate: '2018-12-01',
- diffs: [
- {
- key: 'severity',
- newValue: IssueSeverity.Blocker,
- oldValue: IssueSeverity.Major,
- },
- ],
- }),
- mockIssueChangelog({
- creationDate: '2018-12-02',
- diffs: [
- {
- key: 'impactSeverity',
- newValue: `${SoftwareQuality.Maintainability}:${SoftwareImpactSeverity.Blocker}`,
- oldValue: `${SoftwareQuality.Maintainability}:${SoftwareImpactSeverity.High}`,
- },
- ],
- }),
- ],
- });
- };
-
- getActionsResponse = (overrides: Partial<RawIssue>, issueKey: string) => {
- const issueDataSelected = this.list.find((l) => l.issue.key === issueKey);
-
- if (!issueDataSelected) {
- throw new Error(`Coulnd't find issue for key ${issueKey}`);
- }
-
- issueDataSelected.issue = {
- ...issueDataSelected.issue,
- ...overrides,
- };
-
- return this.reply({
- issue: issueDataSelected.issue,
- });
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/MeasuresServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/MeasuresServiceMock.ts
deleted file mode 100644
index 55316ab652c..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/MeasuresServiceMock.ts
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { mockMetric, mockPeriod } from '../../helpers/testMocks';
-import { Metric, Period } from '../../types/types';
-import { getMeasures, getMeasuresWithPeriodAndMetrics } from '../measures';
-import { ComponentTree, mockFullComponentTree } from './data/components';
-import { mockIssuesList } from './data/issues';
-import { MeasureRecords, getMetricTypeFromKey, mockFullMeasureData } from './data/measures';
-
-jest.mock('../measures');
-
-const defaultComponents = mockFullComponentTree();
-const defaultMeasures = mockFullMeasureData(defaultComponents, mockIssuesList());
-const defaultPeriod = mockPeriod();
-
-export class MeasuresServiceMock {
- components: ComponentTree;
- measures: MeasureRecords;
- period: Period;
- reset: () => void;
-
- constructor(components?: ComponentTree, measures?: MeasureRecords, period?: Period) {
- this.components = components ?? cloneDeep(defaultComponents);
- this.measures = measures ?? cloneDeep(defaultMeasures);
- this.period = period ?? cloneDeep(defaultPeriod);
-
- this.reset = () => {
- this.components = components ?? cloneDeep(defaultComponents);
- this.measures = measures ?? cloneDeep(defaultMeasures);
- this.period = period ?? cloneDeep(defaultPeriod);
- };
-
- jest.mocked(getMeasures).mockImplementation(this.handleGetMeasures);
- jest
- .mocked(getMeasuresWithPeriodAndMetrics)
- .mockImplementation(this.handleGetMeasuresWithPeriodAndMetrics);
- }
-
- registerComponentMeasures = (measures: MeasureRecords) => {
- this.measures = measures;
- };
-
- deleteComponentMeasure = (componentKey: string, measureKey: MetricKey) => {
- delete this.measures[componentKey][measureKey];
- };
-
- getComponentMeasures = () => {
- return this.measures;
- };
-
- setComponents = (components: ComponentTree) => {
- this.components = components;
- };
-
- findComponentTree = (key: string, from?: ComponentTree): ComponentTree => {
- const recurse = (node: ComponentTree): ComponentTree | undefined => {
- if (node.component.key === key) {
- return node;
- }
- return node.children.find((child) => recurse(child));
- };
-
- const tree = recurse(from ?? this.components);
- if (!tree) {
- throw new Error(`Couldn't find component tree for key ${key}`);
- }
-
- return tree;
- };
-
- filterMeasures = (componentKey: string, metricKeys: string[]) => {
- return this.measures[componentKey]
- ? Object.values(this.measures[componentKey]).filter(({ metric }) =>
- metricKeys.includes(metric),
- )
- : [];
- };
-
- handleGetMeasures = ({
- component,
- metricKeys,
- }: { component: string; metricKeys: string } & BranchParameters) => {
- const entry = this.findComponentTree(component);
- const measures = this.filterMeasures(entry.component.key, metricKeys.split(','));
-
- return this.reply(measures);
- };
-
- handleGetMeasuresWithPeriodAndMetrics = (componentKey: string, metricKeys: string[]) => {
- const { component } = this.findComponentTree(componentKey);
- const measures = this.filterMeasures(component.key, metricKeys);
-
- const metrics: Metric[] = measures.map((measure) =>
- mockMetric({
- key: measure.metric,
- name: measure.metric,
- type: getMetricTypeFromKey(measure.metric),
- }),
- );
-
- return this.reply({
- component: {
- ...component,
- measures,
- },
- period: this.period,
- metrics,
- });
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/MessagesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/MessagesServiceMock.ts
deleted file mode 100644
index f7c8529ad33..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/MessagesServiceMock.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import {
- checkMessageDismissed,
- MessageDismissParams,
- MessageTypes,
- setMessageDismissed,
-} from '../messages';
-
-jest.mock('../messages');
-
-interface Dismissed {
- dismissed: boolean;
-}
-
-interface ProjectDismissed {
- [projectKey: string]: Dismissed;
-}
-
-export default class MessagesServiceMock {
- #messageResponse: {
- [key in MessageTypes]?: ProjectDismissed | Dismissed;
- };
-
- constructor() {
- this.#messageResponse = {};
- jest.mocked(checkMessageDismissed).mockImplementation(this.handleCheckMessageDismissed);
- jest.mocked(setMessageDismissed).mockImplementation(this.handleSetMessageDismissed);
- }
-
- handleCheckMessageDismissed = (data: MessageDismissParams) => {
- const result = this.getMessageDismissed(data);
- return this.reply(result as Dismissed);
- };
-
- handleSetMessageDismissed = (data: MessageDismissParams) => {
- this.setMessageDismissed(data);
- return Promise.resolve();
- };
-
- setMessageDismissed = ({ projectKey, messageType }: MessageDismissParams) => {
- if (projectKey) {
- this.#messageResponse[messageType] ||= {
- [projectKey]: {
- dismissed: true,
- },
- };
- } else {
- this.#messageResponse[messageType] = {
- ...this.#messageResponse[messageType],
- dismissed: true,
- };
- }
- };
-
- getMessageDismissed = ({ projectKey, messageType }: MessageDismissParams) => {
- const dismissed = projectKey
- ? (this.#messageResponse[messageType] as ProjectDismissed)?.[projectKey]
- : this.#messageResponse[messageType];
- return dismissed || { dismissed: false };
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-
- reset = () => {
- this.#messageResponse = {};
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/ModeServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/ModeServiceMock.ts
deleted file mode 100644
index 7b2d053deb8..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/ModeServiceMock.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { Mode, ModeResponse } from '../../types/mode';
-import { getMode, updateMode } from '../mode';
-
-jest.mock('../mode');
-
-const defaultMode: ModeResponse = {
- mode: Mode.MQR,
- modified: false,
-};
-
-export class ModeServiceMock {
- mode: ModeResponse;
-
- constructor() {
- this.mode = cloneDeep(defaultMode);
-
- jest.mocked(getMode).mockImplementation(this.handleGetMode);
- jest.mocked(updateMode).mockImplementation(this.handleUpdateMode);
- }
-
- setMode = (mode: Mode) => {
- this.mode.mode = mode;
- };
-
- setModified = () => {
- this.mode.modified = true;
- };
-
- handleGetMode: typeof getMode = () => {
- return this.reply(this.mode);
- };
-
- handleUpdateMode: typeof updateMode = (mode: Mode) => {
- this.mode.mode = mode;
- this.mode.modified = true;
- return this.reply(this.mode);
- };
-
- reset = () => {
- this.mode = cloneDeep(defaultMode);
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/NavigationServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/NavigationServiceMock.ts
deleted file mode 100644
index 1492deaedc8..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/NavigationServiceMock.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { mockAppState } from '../../helpers/testMocks';
-import { AppState } from '../../types/appstate';
-import { Extension, NavigationComponent } from '../../types/types';
-import {
- getComponentNavigation,
- getGlobalNavigation,
- getMarketplaceNavigation,
- getSettingsNavigation,
-} from '../navigation';
-
-jest.mock('../navigation');
-
-const defaultComponentNavigation: NavigationComponent = {
- name: 'foo',
- key: 'foo',
- breadcrumbs: [],
-};
-
-export class NavigationServiceMock {
- componentNavigation: NavigationComponent;
-
- constructor() {
- this.componentNavigation = cloneDeep(defaultComponentNavigation);
-
- jest.mocked(getComponentNavigation).mockImplementation(this.handleGetComponentNavigation);
- jest.mocked(getMarketplaceNavigation).mockImplementation(this.handleGetMarketplaceNavigation);
- jest.mocked(getSettingsNavigation).mockImplementation(this.handleGetSettingsNavigation);
- jest.mocked(getGlobalNavigation).mockImplementation(this.handleGetGlobalNavigation);
- }
-
- setComponentNavigation = (componentNavigation: NavigationComponent) => {
- this.componentNavigation = cloneDeep(componentNavigation);
- };
-
- handleGetComponentNavigation = (): Promise<NavigationComponent> => {
- return Promise.resolve(this.componentNavigation);
- };
-
- handleGetMarketplaceNavigation(): Promise<{ ncloc: number; serverId: string }> {
- return Promise.resolve({ serverId: 'foo', ncloc: 0 });
- }
-
- handleGetSettingsNavigation(): Promise<{
- extensions: Extension[];
- showUpdateCenter: boolean;
- }> {
- return Promise.resolve({ extensions: [], showUpdateCenter: false });
- }
-
- handleGetGlobalNavigation(): Promise<AppState> {
- return Promise.resolve(mockAppState());
- }
-
- reset = () => {
- this.componentNavigation = cloneDeep(defaultComponentNavigation);
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/NewCodeDefinitionServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/NewCodeDefinitionServiceMock.ts
deleted file mode 100644
index f2640e1818d..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/NewCodeDefinitionServiceMock.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import {
- mockNewCodePeriod,
- mockNewCodePeriodBranch,
-} from '../../helpers/mocks/new-code-definition';
-import {
- NewCodeDefinition,
- NewCodeDefinitionBranch,
- NewCodeDefinitionType,
-} from '../../types/new-code-definition';
-import {
- getNewCodeDefinition,
- listBranchesNewCodeDefinition,
- resetNewCodeDefinition,
- setNewCodeDefinition,
-} from '../newCodeDefinition';
-
-jest.mock('../newCodeDefinition');
-export default class NewCodeDefinitionServiceMock {
- #defaultNewCodePeriod = mockNewCodePeriod({ inherited: true });
- #defaultListBranchesNewCode = [
- mockNewCodePeriodBranch({ inherited: true, branchKey: 'main' }),
- mockNewCodePeriodBranch({
- branchKey: 'feature',
- type: NewCodeDefinitionType.NumberOfDays,
- value: '1',
- }),
- ];
-
- #newCodePeriod: NewCodeDefinition;
- #listBranchesNewCode: NewCodeDefinitionBranch[];
-
- constructor() {
- this.#newCodePeriod = cloneDeep(this.#defaultNewCodePeriod);
- this.#listBranchesNewCode = cloneDeep(this.#defaultListBranchesNewCode);
- jest.mocked(getNewCodeDefinition).mockImplementation(this.handleGetNewCodePeriod);
- jest.mocked(setNewCodeDefinition).mockImplementation(this.handleSetNewCodePeriod);
- jest.mocked(resetNewCodeDefinition).mockImplementation(this.handleResetNewCodePeriod);
- jest
- .mocked(listBranchesNewCodeDefinition)
- .mockImplementation(this.handleListBranchesNewCodePeriod);
- }
-
- handleGetNewCodePeriod = (data?: { branch?: string; project?: string }) => {
- if (data?.branch !== undefined) {
- return this.reply(
- this.#listBranchesNewCode.find((b) => b.branchKey === data?.branch) as NewCodeDefinition,
- );
- }
-
- return this.reply(this.#newCodePeriod);
- };
-
- handleSetNewCodePeriod = (data: {
- branch?: string;
- project?: string;
- type: NewCodeDefinitionType;
- value?: string;
- }) => {
- const { project, type, value, branch } = data;
- if (project !== undefined && branch !== undefined) {
- this.#listBranchesNewCode = this.#listBranchesNewCode.filter((b) => b.branchKey !== branch);
- this.#listBranchesNewCode.push(
- mockNewCodePeriodBranch({ type, value, branchKey: branch, projectKey: project }),
- );
- } else {
- this.#newCodePeriod = mockNewCodePeriod({ projectKey: project, type, value });
- }
-
- return this.reply(undefined);
- };
-
- handleResetNewCodePeriod = (data: { branch?: string; project?: string }) => {
- const { branch } = data;
- if (branch) {
- const index = this.#listBranchesNewCode.findIndex((bNew) => bNew.branchKey === branch);
- if (index >= 0) {
- Object.assign(this.#listBranchesNewCode[index], cloneDeep(this.#defaultNewCodePeriod));
- }
- } else {
- this.#newCodePeriod = cloneDeep(this.#defaultNewCodePeriod);
- }
-
- return this.reply(undefined);
- };
-
- handleListBranchesNewCodePeriod = () => {
- return this.reply({ newCodePeriods: this.#listBranchesNewCode });
- };
-
- setNewCodePeriod = (newCodePeriod: NewCodeDefinition) => {
- this.#newCodePeriod = newCodePeriod;
- };
-
- setListBranchesNewCode = (listBranchesNewCode: NewCodeDefinitionBranch[]) => {
- this.#listBranchesNewCode = listBranchesNewCode;
- };
-
- reset = () => {
- this.#newCodePeriod = cloneDeep(this.#defaultNewCodePeriod);
- this.#listBranchesNewCode = cloneDeep(this.#defaultListBranchesNewCode);
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/NotificationsMock.ts b/server/sonar-web/src/main/js/api/mocks/NotificationsMock.ts
deleted file mode 100644
index bdfd0b07d29..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/NotificationsMock.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import {
- AddRemoveNotificationParameters,
- Notification,
- NotificationGlobalType,
- NotificationProjectType,
- NotificationsResponse,
-} from '../../types/notifications';
-import { addNotification, getNotifications, removeNotification } from '../notifications';
-
-jest.mock('../notifications');
-
-/* Constants */
-const channels = ['EmailNotificationChannel'];
-const defaultNotifications: Notification[] = [
- { channel: 'EmailNotificationChannel', type: 'ChangesOnMyIssue' },
-];
-
-export default class NotificationsMock {
- notifications: Notification[];
-
- constructor() {
- this.notifications = cloneDeep(defaultNotifications);
-
- (getNotifications as jest.Mock).mockImplementation(this.handleGetNotifications);
- (addNotification as jest.Mock).mockImplementation(this.handleAddNotification);
- (removeNotification as jest.Mock).mockImplementation(this.handleRemoveNotification);
- }
-
- handleGetNotifications: () => Promise<NotificationsResponse> = () => {
- return Promise.resolve({
- channels: [...channels],
- globalTypes: Object.values(NotificationGlobalType),
- notifications: cloneDeep(this.notifications),
- perProjectTypes: Object.values(NotificationProjectType),
- });
- };
-
- handleAddNotification = (params: AddRemoveNotificationParameters) => {
- this.notifications.push(params);
-
- return Promise.resolve();
- };
-
- handleRemoveNotification = (params: AddRemoveNotificationParameters) => {
- const index = this.notifications.findIndex(
- (n) => n.project === params.project && n.type === params.type && n.channel === params.channel,
- );
-
- if (index < 0) {
- return Promise.reject({ errors: [{ msg: "Notification doesn't exist" }] });
- }
-
- this.notifications.splice(index, 1);
-
- return Promise.resolve();
- };
-
- reset = () => {
- this.notifications = cloneDeep(defaultNotifications);
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/PermissionsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/PermissionsServiceMock.ts
deleted file mode 100644
index ff0a2150172..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/PermissionsServiceMock.ts
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { chunk, cloneDeep, remove, uniq } from 'lodash';
-import { ComponentQualifier, Visibility } from '~sonar-aligned/types/component';
-import {
- mockPermission,
- mockPermissionGroup,
- mockPermissionTemplate,
- mockPermissionTemplateGroup,
- mockPermissionUser,
-} from '../../helpers/mocks/permissions';
-import { PERMISSIONS_ORDER_FOR_PROJECT_TEMPLATE } from '../../helpers/permissions';
-import { Permissions } from '../../types/permissions';
-import { Permission, PermissionGroup, PermissionTemplate, PermissionUser } from '../../types/types';
-import { BaseSearchProjectsParameters } from '../components';
-import {
- addProjectCreatorToTemplate,
- applyTemplateToProject,
- bulkApplyTemplate,
- changeProjectVisibility,
- createPermissionTemplate,
- deletePermissionTemplate,
- getGlobalPermissionsGroups,
- getGlobalPermissionsUsers,
- getPermissionTemplateGroups,
- getPermissionTemplateUsers,
- getPermissionTemplates,
- getPermissionsGroupsForComponent,
- getPermissionsUsersForComponent,
- grantPermissionToGroup,
- grantPermissionToUser,
- grantTemplatePermissionToGroup,
- grantTemplatePermissionToUser,
- removeProjectCreatorFromTemplate,
- revokePermissionFromGroup,
- revokePermissionFromUser,
- revokeTemplatePermissionFromGroup,
- revokeTemplatePermissionFromUser,
- setDefaultPermissionTemplate,
- updatePermissionTemplate,
-} from '../permissions';
-
-const MAX_PROJECTS_TO_APPLY_PERMISSION_TEMPLATE = 10;
-
-const defaultUsers = [
- mockPermissionUser(),
- mockPermissionUser({
- login: 'gooduser1',
- name: 'John',
- managed: true,
- permissions: [
- Permissions.IssueAdmin,
- Permissions.SecurityHotspotAdmin,
- Permissions.Browse,
- Permissions.Admin,
- ],
- }),
- mockPermissionUser({
- login: 'gooduser2',
- name: 'Alexa',
- permissions: [Permissions.IssueAdmin, Permissions.Browse],
- }),
- mockPermissionUser({
- name: 'Siri',
- login: 'gooduser3',
- managed: true,
- }),
- mockPermissionUser({
- login: 'gooduser4',
- name: 'Cool',
- permissions: [Permissions.Browse],
- }),
- mockPermissionUser({
- name: 'White',
- login: 'baduser1',
- }),
- mockPermissionUser({
- name: 'Green',
- login: 'baduser2',
- }),
-];
-
-const defaultGroups = [
- mockPermissionGroup({ name: 'sonar-users', permissions: [Permissions.Browse] }),
- mockPermissionGroup({
- name: 'sonar-admins',
- managed: true,
- permissions: [Permissions.Admin, Permissions.Browse],
- }),
- mockPermissionGroup({ name: 'sonar-losers', permissions: [] }),
-];
-
-const defaultTemplates: PermissionTemplate[] = [
- mockPermissionTemplate({
- id: 'template1',
- name: 'Permission Template 1',
- description: 'This is permission template 1',
- defaultFor: [
- ComponentQualifier.Project,
- ComponentQualifier.Application,
- ComponentQualifier.Portfolio,
- ],
- permissions: PERMISSIONS_ORDER_FOR_PROJECT_TEMPLATE.map((key) =>
- mockPermissionTemplateGroup({
- key,
- groupsCount: defaultGroups.filter((g) => g.permissions.includes(key)).length,
- usersCount: defaultUsers.filter((g) => g.permissions.includes(key)).length,
- withProjectCreator: false,
- }),
- ),
- }),
- mockPermissionTemplate({
- id: 'template2',
- name: 'Permission Template 2',
- permissions: PERMISSIONS_ORDER_FOR_PROJECT_TEMPLATE.map((key) =>
- mockPermissionTemplateGroup({
- key,
- groupsCount: 0,
- usersCount: 0,
- withProjectCreator: [Permissions.Browse, Permissions.CodeViewer].includes(key),
- }),
- ),
- }),
-];
-
-const PAGE_SIZE = 5;
-const MIN_QUERY_LENGTH = 3;
-const DEFAULT_PAGE = 1;
-
-jest.mock('../permissions');
-
-export default class PermissionsServiceMock {
- #permissionTemplates: PermissionTemplate[] = [];
- #permissions: Permission[];
- #defaultTemplates: Array<{ qualifier: string; templateId: string }> = [];
- #groups: PermissionGroup[];
- #users: PermissionUser[];
- #isAllowedToChangePermissions = true;
-
- constructor() {
- this.#permissionTemplates = cloneDeep(defaultTemplates);
- this.#permissions = PERMISSIONS_ORDER_FOR_PROJECT_TEMPLATE.map((key) =>
- mockPermission({ key, name: key }),
- );
- this.#groups = cloneDeep(defaultGroups);
- this.#users = cloneDeep(defaultUsers);
- this.updateDefaults();
-
- jest.mocked(getPermissionTemplates).mockImplementation(this.handleGetPermissionTemplates);
- jest.mocked(bulkApplyTemplate).mockImplementation(this.handleBulkApplyTemplate);
- jest.mocked(applyTemplateToProject).mockImplementation(this.handleApplyTemplateToProject);
- jest
- .mocked(getPermissionTemplateUsers)
- .mockImplementation(this.handleGetPermissionTemplateUsers);
- jest
- .mocked(getPermissionTemplateGroups)
- .mockImplementation(this.handleGetPermissionTemplateGroups);
- jest.mocked(addProjectCreatorToTemplate).mockImplementation(this.handlePermissionChange);
- jest.mocked(removeProjectCreatorFromTemplate).mockImplementation(this.handlePermissionChange);
- jest.mocked(grantTemplatePermissionToGroup).mockImplementation(this.handlePermissionChange);
- jest.mocked(revokeTemplatePermissionFromGroup).mockImplementation(this.handlePermissionChange);
- jest.mocked(grantTemplatePermissionToUser).mockImplementation(this.handlePermissionChange);
- jest.mocked(revokeTemplatePermissionFromUser).mockImplementation(this.handlePermissionChange);
- jest.mocked(createPermissionTemplate).mockImplementation(this.handleCreatePermissionTemplate);
- jest.mocked(updatePermissionTemplate).mockImplementation(this.handleUpdatePermissionTemplate);
- jest.mocked(deletePermissionTemplate).mockImplementation(this.handleDeletePermissionTemplate);
- jest
- .mocked(setDefaultPermissionTemplate)
- .mockImplementation(this.handleSetDefaultPermissionTemplate);
- jest.mocked(changeProjectVisibility).mockImplementation(this.handleChangeProjectVisibility);
- jest.mocked(getGlobalPermissionsUsers).mockImplementation(this.handleGetPermissionUsers);
- jest.mocked(getGlobalPermissionsGroups).mockImplementation(this.handleGetPermissionGroups);
- jest
- .mocked(getPermissionsGroupsForComponent)
- .mockImplementation(this.handleGetPermissionGroupsForComponent);
- jest
- .mocked(getPermissionsUsersForComponent)
- .mockImplementation(this.handleGetPermissionUsersForComponent);
- jest.mocked(grantPermissionToGroup).mockImplementation(this.handleGrantPermissionToGroup);
- jest.mocked(revokePermissionFromGroup).mockImplementation(this.handleRevokePermissionFromGroup);
- jest.mocked(grantPermissionToUser).mockImplementation(this.handleGrantPermissionToUser);
- jest.mocked(revokePermissionFromUser).mockImplementation(this.handleRevokePermissionFromUser);
- }
-
- handleGetPermissionTemplates = () => {
- return this.reply({
- permissionTemplates: this.#permissionTemplates,
- defaultTemplates: this.#defaultTemplates,
- permissions: this.#permissions,
- });
- };
-
- handleApplyTemplateToProject = (_data: { projectKey: string; templateId: string }) => {
- return this.reply(undefined);
- };
-
- handleBulkApplyTemplate = (params: BaseSearchProjectsParameters) => {
- if (
- params.projects &&
- params.projects.split(',').length > MAX_PROJECTS_TO_APPLY_PERMISSION_TEMPLATE
- ) {
- const response = new Response(
- JSON.stringify({ errors: [{ msg: 'bulk apply permission template error message' }] }),
- );
- return Promise.reject(response);
- }
-
- return Promise.resolve();
- };
-
- handleGetPermissionTemplateUsers = (data: {
- p?: number;
- permission?: string;
- ps?: number;
- q?: string;
- templateId: string;
- }) => {
- return this.handleGetPermissionUsers(data);
- };
-
- handleGetPermissionTemplateGroups = (data: {
- p?: number;
- permission?: string;
- ps?: number;
- q?: string;
- templateId: string;
- }) => {
- return this.handleGetPermissionGroups(data);
- };
-
- handleChangeProjectVisibility = (_project: string, _visibility: Visibility) => {
- return this.reply(undefined);
- };
-
- handleGetPermissionUsers = (data: {
- p?: number;
- permission?: string;
- ps?: number;
- q?: string;
- }) => {
- const { ps = PAGE_SIZE, p = DEFAULT_PAGE, q, permission } = data;
-
- const users =
- q && q.length >= MIN_QUERY_LENGTH
- ? this.#users.filter(
- (user) =>
- user.name.toLowerCase().includes(q.toLowerCase()) ||
- user.login.toLowerCase().includes(q.toLowerCase()),
- )
- : this.#users;
-
- const usersChunked = chunk(
- permission ? users.filter((u) => u.permissions.includes(permission)) : users,
- ps,
- );
-
- return this.reply({
- paging: { pageSize: ps, total: users.length, pageIndex: p },
- users: usersChunked[p - 1] ?? [],
- });
- };
-
- handleGetPermissionGroups = (data: {
- p?: number;
- permission?: string;
- ps?: number;
- q?: string;
- }) => {
- const { ps = PAGE_SIZE, p = DEFAULT_PAGE, q, permission } = data;
-
- const groups =
- q && q.length >= MIN_QUERY_LENGTH
- ? this.#groups.filter((group) => group.name.toLowerCase().includes(q.toLowerCase()))
- : this.#groups;
-
- const groupsChunked = chunk(
- permission ? groups.filter((g) => g.permissions.includes(permission)) : groups,
- ps,
- );
-
- return this.reply({
- paging: { pageSize: ps, total: groups.length, pageIndex: p },
- groups: groupsChunked[p - 1] ?? [],
- });
- };
-
- handleGetPermissionGroupsForComponent = (data: {
- p?: number;
- permission?: string;
- projectKey: string;
- ps?: number;
- q?: string;
- }) => {
- return this.handleGetPermissionGroups(data);
- };
-
- handleGetPermissionUsersForComponent = (data: {
- p?: number;
- permission?: string;
- projectKey: string;
- ps?: number;
- q?: string;
- }) => {
- return this.handleGetPermissionUsers(data);
- };
-
- handleGrantPermissionToGroup = (data: {
- groupName: string;
- permission: string;
- projectKey?: string;
- }) => {
- if (!this.#isAllowedToChangePermissions) {
- return Promise.reject();
- }
-
- const { groupName, permission } = data;
- const group = this.#groups.find((g) => g.name === groupName);
- if (group === undefined) {
- throw new Error(`Could not find group with name ${groupName}`);
- }
- group.permissions = uniq([...group.permissions, permission]);
- return this.reply(undefined);
- };
-
- handleRevokePermissionFromGroup = (data: {
- groupName: string;
- permission: string;
- projectKey?: string;
- }) => {
- if (!this.#isAllowedToChangePermissions) {
- return Promise.reject();
- }
-
- const { groupName, permission } = data;
- const group = this.#groups.find((g) => g.name === groupName);
- if (group === undefined) {
- throw new Error(`Could not find group with name ${groupName}`);
- }
- group.permissions = remove(group.permissions, permission);
- return this.reply(undefined);
- };
-
- handleGrantPermissionToUser = (data: {
- login: string;
- permission: string;
- projectKey?: string;
- }) => {
- if (!this.#isAllowedToChangePermissions) {
- return Promise.reject();
- }
-
- const { login, permission } = data;
- const user = this.#users.find((u) => u.login === login);
- if (user === undefined) {
- throw new Error(`Could not find user with login ${login}`);
- }
- user.permissions = uniq([...user.permissions, permission]);
- return this.reply(undefined);
- };
-
- handleRevokePermissionFromUser = (data: {
- login: string;
- permission: string;
- projectKey?: string;
- }) => {
- if (!this.#isAllowedToChangePermissions) {
- return Promise.reject();
- }
-
- const { login, permission } = data;
- const user = this.#users.find((u) => u.login === login);
- if (user === undefined) {
- throw new Error(`Could not find user with name ${login}`);
- }
- user.permissions = remove(user.permissions, permission);
- return this.reply(undefined);
- };
-
- handlePermissionChange = () => {
- return this.#isAllowedToChangePermissions ? Promise.resolve() : Promise.reject();
- };
-
- handleCreatePermissionTemplate = (data: {
- description?: string;
- name: string;
- projectKeyPattern?: string;
- }) => {
- const newTemplate = mockPermissionTemplate({
- id: `template-${this.#permissionTemplates.length + 1}`,
- ...data,
- });
- this.#permissionTemplates.push(newTemplate);
- return this.reply({ permissionTemplate: newTemplate });
- };
-
- handleUpdatePermissionTemplate = (data: {
- description?: string;
- id: string;
- name?: string;
- projectKeyPattern?: string;
- }) => {
- const { id } = data;
- const template = this.#permissionTemplates.find((t) => t.id === id);
- if (template === undefined) {
- throw new Error(`Couldn't find template with id ${id}`);
- }
- Object.assign(template, data);
-
- return this.reply(undefined);
- };
-
- handleDeletePermissionTemplate = (data: { templateId?: string; templateName?: string }) => {
- const { templateId } = data;
- this.#permissionTemplates = this.#permissionTemplates.filter((t) => t.id !== templateId);
- return this.reply(undefined);
- };
-
- handleSetDefaultPermissionTemplate = (templateId: string, qualifier: ComponentQualifier) => {
- this.#permissionTemplates = this.#permissionTemplates.map((t) => ({
- ...t,
- defaultFor: t.defaultFor.filter((q) => q !== qualifier),
- }));
-
- const template = this.#permissionTemplates.find((t) => t.id === templateId);
- if (template === undefined) {
- throw new Error(`Couldn't find template with id ${templateId}`);
- }
- template.defaultFor = uniq([...template.defaultFor, qualifier]);
-
- this.updateDefaults();
-
- return this.reply(undefined);
- };
-
- setIsAllowedToChangePermissions = (val: boolean) => {
- this.#isAllowedToChangePermissions = val;
- };
-
- setGroups = (groups: PermissionGroup[]) => {
- this.#groups = groups;
- };
-
- setUsers = (users: PermissionUser[]) => {
- this.#users = users;
- };
-
- getTemplates = () => {
- return this.#permissionTemplates;
- };
-
- updateDefaults = () => {
- this.#defaultTemplates = [
- ComponentQualifier.Project,
- ComponentQualifier.Application,
- ComponentQualifier.Portfolio,
- ].map((qualifier) => ({
- templateId:
- this.#permissionTemplates.find((t) => t.defaultFor.includes(qualifier))?.id ??
- this.#permissionTemplates[0].id,
- qualifier,
- }));
- };
-
- reset = () => {
- this.#permissionTemplates = cloneDeep(defaultTemplates);
- this.#groups = cloneDeep(defaultGroups);
- this.#users = cloneDeep(defaultUsers);
- this.setIsAllowedToChangePermissions(true);
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/PluginsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/PluginsServiceMock.ts
deleted file mode 100644
index ca61b843a87..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/PluginsServiceMock.ts
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep, omit } from 'lodash';
-import {
- mockAvailablePlugin,
- mockInstalledPlugin,
- mockRelease,
- mockUpdate,
-} from '../../helpers/mocks/plugins';
-import { AvailablePlugin, InstalledPlugin, PendingPluginResult } from '../../types/plugins';
-import {
- cancelPendingPlugins,
- getAvailablePlugins,
- getInstalledPlugins,
- getPendingPlugins,
- getUpdatesPlugins,
- installPlugin,
- uninstallPlugin,
- updatePlugin,
-} from '../plugins';
-
-jest.mock('../plugins');
-
-const defaultAvailable: AvailablePlugin[] = [
- mockAvailablePlugin({
- key: 'foo',
- name: 'CFoo',
- category: 'Languages',
- description: 'Description',
- homepageUrl: 'https://www.sonarsource.com/',
- issueTrackerUrl: 'https://www.sonarsource.com/',
- organizationName: 'SonarSource',
- organizationUrl: 'https://www.sonarsource.com/',
- release: mockRelease({
- version: '1.0.0',
- description: 'release description',
- date: '2020-01-01',
- changeLogUrl: 'https://www.sonarsource.com/',
- }),
- }),
- mockAvailablePlugin({
- key: 'bar',
- name: 'DTest',
- editionBundled: true,
- release: mockRelease({
- version: '2.0.0',
- }),
- }),
- mockAvailablePlugin({
- description: 'Mocked Plugin',
- termsAndConditionsUrl: 'https://www.sonarsource.com/',
- }),
-];
-const defaultInstalled: InstalledPlugin[] = [
- mockInstalledPlugin({
- key: 'test',
- name: 'ATest_install',
- version: '1.1.0',
- }),
- mockInstalledPlugin({
- key: 'one-update',
- name: 'ZTest',
- version: '1.1.1',
- updates: [
- mockUpdate({
- status: 'COMPATIBLE',
- release: mockRelease({
- version: '1.2.0',
- date: '2020-01-01',
- changeLogUrl: 'https://www.sonarsource.com/',
- }),
- }),
- ],
- }),
- mockInstalledPlugin({
- key: 'multiple_updates',
- name: 'BTest_update',
- version: '1.2.0',
- editionBundled: true,
- updates: [
- mockUpdate({
- status: 'COMPATIBLE',
- release: mockRelease({ version: '1.2.1', changeLogUrl: 'https://www.sonarsource.com/' }),
- }),
- mockUpdate({
- status: 'COMPATIBLE',
- release: mockRelease({ version: '1.3.0', changeLogUrl: 'https://www.sonarsource.com/' }),
- }),
- mockUpdate({
- status: 'NON-COMPATIBLE',
- release: mockRelease({ version: '1.4.0', changeLogUrl: 'https://www.sonarsource.com/' }),
- }),
- ],
- }),
-];
-const defaultPending: PendingPluginResult = {
- installing: [],
- removing: [],
- updating: [],
-};
-
-export default class PluginsServiceMock {
- #available: AvailablePlugin[];
- #installed: InstalledPlugin[];
- #pending: PendingPluginResult;
-
- constructor() {
- this.#available = cloneDeep(defaultAvailable);
- this.#installed = cloneDeep(defaultInstalled);
- this.#pending = cloneDeep(defaultPending);
-
- jest.mocked(getAvailablePlugins).mockImplementation(this.handleGetAvailablePlugins);
- jest.mocked(getPendingPlugins).mockImplementation(this.handleGetPendingPlugins);
- jest.mocked(getInstalledPlugins).mockImplementation(this.handleGetInstalledPlugins);
- jest.mocked(getUpdatesPlugins).mockImplementation(this.handleGetUpdatesPlugins);
- jest.mocked(installPlugin).mockImplementation(this.handleInstallPlugin);
- jest.mocked(uninstallPlugin).mockImplementation(this.handleUninstallPlugin);
- jest.mocked(updatePlugin).mockImplementation(this.handleUpdatePlugin);
- jest.mocked(cancelPendingPlugins).mockImplementation(this.handleCancelPendingPlugins);
- }
-
- handleGetAvailablePlugins = () => {
- return this.reply({
- plugins: this.#available,
- updateCenterRefresh: '2021-01-01T00:00:00+0000',
- });
- };
-
- handleGetPendingPlugins = () => {
- return this.reply(this.#pending);
- };
-
- handleGetInstalledPlugins = () => {
- return this.reply(this.#installed.map((plugin) => omit(plugin, 'updates')));
- };
-
- handleGetUpdatesPlugins = () => {
- return this.reply({
- plugins: this.#installed
- .filter((plugin) => plugin.updates && plugin.updates.length > 0)
- .map((plugin) => omit(plugin, 'version', 'updatedAt')),
- updateCenterRefresh: '2021-01-01T00:00:00+0000',
- });
- };
-
- handleGetPluginUpdates = () => {
- return this.reply(
- this.#installed.filter((plugin) => plugin.updates && plugin.updates.length > 0),
- );
- };
-
- handleInstallPlugin: typeof installPlugin = (data) => {
- const plugin = this.#available.find((plugin) => plugin.key === data.key);
- if (plugin === undefined) {
- return Promise.reject(new Error('Plugin not found'));
- }
- this.#pending.installing.push({
- ...omit(plugin, 'release', 'update'),
- version: plugin.release.version,
- implementationBuild: '20210101-000000',
- });
- return this.reply();
- };
-
- handleUninstallPlugin: typeof uninstallPlugin = (data) => {
- const plugin = this.#installed.find((plugin) => plugin.key === data.key);
- if (plugin === undefined) {
- return Promise.reject(new Error('Plugin not found'));
- }
- this.#pending.removing.push({
- ...omit(
- plugin,
- 'updates',
- 'updatedAt',
- 'sonarLintSupported',
- 'hash',
- 'filename',
- 'documentationPath',
- ),
- implementationBuild: '20210101-000000',
- });
- return this.reply();
- };
-
- handleUpdatePlugin: typeof updatePlugin = (data) => {
- const plugin = this.#installed
- .filter((plugin) => plugin.updates && plugin.updates.length > 0)
- .find((plugin) => plugin.key === data.key);
- if (plugin === undefined || plugin.updates === undefined || plugin.updates.length === 0) {
- return Promise.reject(new Error('Plugin not found'));
- }
- this.#pending.updating.push({
- ...omit(
- plugin,
- 'updates',
- 'updatedAt',
- 'sonarLintSupported',
- 'hash',
- 'filename',
- 'documentationPath',
- ),
- version: plugin.updates[plugin.updates.length - 1].release?.version ?? '',
- implementationBuild: '20210101-000000',
- });
- return this.reply();
- };
-
- handleCancelPendingPlugins: typeof cancelPendingPlugins = () => {
- this.#pending = cloneDeep(defaultPending);
- return this.reply();
- };
-
- reset = () => {
- this.#available = cloneDeep(defaultAvailable);
- this.#installed = cloneDeep(defaultInstalled);
- this.#pending = cloneDeep(defaultPending);
- };
-
- reply<T>(): Promise<void>;
- reply<T>(response: T): Promise<T>;
- reply<T>(response?: T): Promise<T | void> {
- return Promise.resolve(response ? cloneDeep(response) : undefined);
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/ProjectActivityServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/ProjectActivityServiceMock.ts
deleted file mode 100644
index 752fb327392..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/ProjectActivityServiceMock.ts
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { chunk, cloneDeep, uniqueId } from 'lodash';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { parseDate } from '../../helpers/dates';
-import { mockAnalysis, mockAnalysisEvent } from '../../helpers/mocks/project-activity';
-import { Analysis, ProjectAnalysisEventCategory } from '../../types/project-activity';
-import {
- changeEvent,
- createEvent,
- deleteAnalysis,
- deleteEvent,
- getAllTimeProjectActivity,
- getProjectActivity,
-} from '../projectActivity';
-
-jest.mock('../projectActivity');
-
-const PAGE_SIZE = 10;
-const DEFAULT_PAGE = 1;
-const UNKNOWN_PROJECT = 'unknown';
-
-const defaultAnalysesList = [
- mockAnalysis({
- key: 'AXJMbIUGPAOIsUIE3eNT',
- date: parseDate('2017-03-03T22:00:00.000Z').toDateString(),
- projectVersion: '1.1',
- buildString: '1.1.0.2',
- events: [
- mockAnalysisEvent({
- category: ProjectAnalysisEventCategory.Version,
- key: 'IsUIEAXJMbIUGPAO3eND',
- name: '1.1',
- }),
- ],
- }),
- mockAnalysis({
- key: 'AXJMbIUGPAOIsUIE3eND',
- date: parseDate('2017-03-02T22:00:00.000Z').toDateString(),
- projectVersion: '1.1',
- buildString: '1.1.0.1',
- }),
- mockAnalysis({
- key: 'AXJMbIUGPAOIsUIE3eNE',
- date: parseDate('2017-03-01T22:00:00.000Z').toDateString(),
- projectVersion: '1.0',
- events: [
- mockAnalysisEvent({
- category: ProjectAnalysisEventCategory.Version,
- key: 'IUGPAOAXJMbIsUIE3eNE',
- name: '1.0',
- }),
- ],
- }),
- mockAnalysis({
- key: 'AXJMbIUGPAOIsUIE3eNC',
- date: parseDate('2017-02-28T22:00:00.000Z').toDateString(),
- projectVersion: '1.0',
- buildString: '1.0.0.1',
- }),
-];
-
-export class ProjectActivityServiceMock {
- #analysisList: Analysis[];
-
- constructor() {
- this.#analysisList = cloneDeep(defaultAnalysesList);
-
- jest.mocked(getProjectActivity).mockImplementation(this.getActivityHandler);
- jest
- .mocked(getAllTimeProjectActivity)
- .mockImplementation(this.getAllTimeProjectActivityHandler);
- jest.mocked(deleteAnalysis).mockImplementation(this.deleteAnalysisHandler);
- jest.mocked(createEvent).mockImplementation(this.createEventHandler);
- jest.mocked(changeEvent).mockImplementation(this.changeEventHandler);
- jest.mocked(deleteEvent).mockImplementation(this.deleteEventHandler);
- }
-
- reset = () => {
- this.#analysisList = cloneDeep(defaultAnalysesList);
- };
-
- getAnalysesList = () => {
- return this.#analysisList;
- };
-
- setAnalysesList = (analyses: Analysis[]) => {
- this.#analysisList = analyses;
- };
-
- getActivityHandler = (
- data: {
- category?: string;
- from?: string;
- p?: number;
- project: string;
- ps?: number;
- statuses?: string;
- } & BranchParameters,
- ) => {
- const { project, ps = PAGE_SIZE, p = DEFAULT_PAGE, category, from } = data;
-
- if (project === UNKNOWN_PROJECT) {
- throw new Error(`Could not find project "${UNKNOWN_PROJECT}"`);
- }
-
- let analyses = category
- ? this.#analysisList.filter((a) => a.events.some((e) => e.category === category))
- : this.#analysisList;
-
- if (from !== undefined) {
- const fromTime = parseDate(from).getTime();
- analyses = analyses.filter((a) => parseDate(a.date).getTime() >= fromTime);
- }
-
- const analysesChunked = chunk(analyses, ps);
-
- return this.reply({
- paging: { pageSize: ps, total: analyses.length, pageIndex: p },
- analyses: analysesChunked[p - 1] ?? [],
- });
- };
-
- getAllTimeProjectActivityHandler = (
- data: {
- category?: string;
- from?: string;
- p?: number;
- project: string;
- ps?: number;
- statuses?: string;
- } & BranchParameters,
- ) => {
- const { project, p = DEFAULT_PAGE, category, from } = data;
-
- if (project === UNKNOWN_PROJECT) {
- throw new Error(`Could not find project "${UNKNOWN_PROJECT}"`);
- }
-
- let analyses = category
- ? this.#analysisList.filter((a) => a.events.some((e) => e.category === category))
- : this.#analysisList;
-
- if (from !== undefined) {
- const fromTime = parseDate(from).getTime();
- analyses = analyses.filter((a) => parseDate(a.date).getTime() >= fromTime);
- }
- return this.reply({
- paging: { pageSize: PAGE_SIZE, total: this.#analysisList.length, pageIndex: p },
- analyses: this.#analysisList,
- });
- };
-
- deleteAnalysisHandler = (analysisKey: string) => {
- const i = this.#analysisList.findIndex(({ key }) => key === analysisKey);
- if (i === undefined) {
- throw new Error(`Could not find analysis with key: ${analysisKey}`);
- }
- this.#analysisList.splice(i, 1);
- return this.reply(undefined);
- };
-
- createEventHandler = (data: {
- analysis: string;
- category?: ProjectAnalysisEventCategory;
- description?: string;
- name: string;
- }) => {
- const {
- analysis: analysisKey,
- name,
- category = ProjectAnalysisEventCategory.Other,
- description,
- } = data;
- const analysis = this.findAnalysis(analysisKey);
-
- const key = uniqueId(analysisKey);
- analysis.events.push({ key, name, category, description });
-
- return this.reply({
- analysis: analysisKey,
- key,
- name,
- category,
- description,
- });
- };
-
- changeEventHandler = (data: { description?: string; event: string; name: string }) => {
- const { event: eventKey, name, description } = data;
- const [eventIndex, analysisKey] = this.findEvent(eventKey);
- const analysis = this.findAnalysis(analysisKey);
- const event = analysis.events[eventIndex];
-
- event.name = name;
- event.description = description;
-
- return this.reply({ analysis: analysisKey, ...event });
- };
-
- deleteEventHandler = (eventKey: string) => {
- const [eventIndex, analysisKey] = this.findEvent(eventKey);
- const analysis = this.findAnalysis(analysisKey);
-
- analysis.events.splice(eventIndex, 1);
-
- return this.reply(undefined);
- };
-
- findEvent = (eventKey: string): [number, string] => {
- let analysisKey;
- const eventIndex = this.#analysisList.reduce((acc, { key, events }) => {
- if (acc === undefined) {
- const i = events.findIndex(({ key }) => key === eventKey);
- if (i > -1) {
- analysisKey = key;
- return i;
- }
- }
-
- return acc;
- }, undefined);
-
- if (eventIndex !== undefined && analysisKey !== undefined) {
- return [eventIndex, analysisKey];
- }
-
- throw new Error(`Could not find event with key: ${eventKey}`);
- };
-
- findAnalysis = (analysisKey: string) => {
- const analysis = this.#analysisList.find(({ key }) => key === analysisKey);
-
- if (analysis !== undefined) {
- return analysis;
- }
-
- throw new Error(`Could not find analysis with key: ${analysisKey}`);
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/ProjectBadgesServiceMock.tsx b/server/sonar-web/src/main/js/api/mocks/ProjectBadgesServiceMock.tsx
deleted file mode 100644
index a1bbab25d5e..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/ProjectBadgesServiceMock.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getProjectBadgesToken, renewProjectBadgesToken } from '../project-badges';
-
-jest.mock('../project-badges');
-jest.mock('../project-badges');
-
-const defaultToken = 'sqb_2b5052cef8eac91a921ac71be9227a27f6b6b38b';
-
-export class ProjectBadgesServiceMock {
- token: string;
-
- constructor() {
- this.token = defaultToken;
-
- jest.mocked(getProjectBadgesToken).mockImplementation(this.handleGetProjectBadgesToken);
- jest.mocked(renewProjectBadgesToken).mockImplementation(this.handleRenewProjectBadgesToken);
- }
-
- handleGetProjectBadgesToken = () => {
- return Promise.resolve(this.token);
- };
-
- handleRenewProjectBadgesToken = () => {
- const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
- this.token =
- 'sqb-' +
- new Array(40)
- .fill(null)
- .map(() => chars.charAt(Math.floor(Math.random() * chars.length)))
- .join('');
-
- return Promise.resolve(this.token);
- };
-
- reset = () => {
- this.token = defaultToken;
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/ProjectDumpServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/ProjectDumpServiceMock.ts
deleted file mode 100644
index b2f68ee1ccb..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/ProjectDumpServiceMock.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { TaskStatuses, TaskTypes } from '../../types/tasks';
-import { doExport, doImport, getStatus } from '../project-dump';
-import ComputeEngineServiceMock from './ComputeEngineServiceMock';
-
-jest.mock('../project-dump');
-
-export class ProjectDumpServiceMock {
- #ceService: ComputeEngineServiceMock;
- canBeExported = true;
- canBeImported = false;
- #customTasks = false;
- exportedDump: string | undefined = undefined;
- dumpToImport: string | undefined = undefined;
-
- constructor(ceService: ComputeEngineServiceMock) {
- this.#ceService = ceService;
-
- jest.mocked(doExport).mockImplementation(this.doExportHandler);
- jest.mocked(doImport).mockImplementation(this.doImportHandler);
- jest.mocked(getStatus).mockImplementation(this.getStatusHandler);
- }
-
- reset = () => {
- this.canBeImported = false;
- this.canBeExported = true;
- this.#customTasks = false;
- this.exportedDump = undefined;
- this.dumpToImport = undefined;
- };
-
- setImportState = () => {
- this.canBeImported = true;
- this.canBeExported = false;
- this.dumpToImport = 'tmp/test.zip';
- };
-
- useCustomTasks = () => {
- this.#customTasks = true;
- };
-
- doExportHandler = (componentKey: string) => {
- if (!this.#customTasks) {
- this.#ceService.addTask({
- componentKey,
- type: TaskTypes.ProjectExport,
- status: TaskStatuses.Success,
- executedAt: '2023-06-08T12:00:00Z',
- });
- }
- this.exportedDump = `/tmp/${componentKey}.zip`;
- return this.reply({});
- };
-
- doImportHandler = (componentKey: string) => {
- if (!this.#customTasks) {
- this.#ceService.addTask({
- componentKey,
- type: TaskTypes.ProjectImport,
- status: TaskStatuses.Success,
- executedAt: '2023-06-08T12:00:00Z',
- });
- }
- return this.reply({});
- };
-
- getStatusHandler = () => {
- return this.reply({
- canBeExported: this.canBeExported,
- canBeImported: this.canBeImported,
- exportedDump: this.exportedDump,
- dumpToImport: this.dumpToImport,
- });
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/ProjectLinksServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/ProjectLinksServiceMock.ts
deleted file mode 100644
index 69b207fb240..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/ProjectLinksServiceMock.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { ProjectLink } from '../../types/types';
-import { createLink, deleteLink, getProjectLinks } from '../projectLinks';
-
-jest.mock('../projectLinks');
-
-export default class ProjectLinksServiceMock {
- projectLinks: ProjectLink[] = [];
- idCounter: number = 0;
-
- constructor() {
- jest.mocked(getProjectLinks).mockImplementation(this.handleGetProjectLinks);
- jest.mocked(createLink).mockImplementation(this.handleCreateLink);
- jest.mocked(deleteLink).mockImplementation(this.handleDeleteLink);
- }
-
- handleGetProjectLinks = () => {
- return this.reply(this.projectLinks);
- };
-
- handleCreateLink = ({ name, url }: { name: string; url: string }) => {
- const link = {
- id: `id${this.idCounter++}`,
- name,
- type: name,
- url,
- };
- this.projectLinks.push(link);
-
- return this.reply(link);
- };
-
- handleDeleteLink = (id: string) => {
- this.projectLinks.filter((link) => link.id !== id);
-
- return this.reply(undefined);
- };
-
- reset = () => {
- this.projectLinks = [];
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/ProjectsManagementServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/ProjectsManagementServiceMock.ts
deleted file mode 100644
index 946c89eeea0..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/ProjectsManagementServiceMock.ts
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { ComponentQualifier, Visibility } from '~sonar-aligned/types/component';
-import { mockProject } from '../../helpers/mocks/projects';
-import { SettingsKey } from '../../types/settings';
-import {
- Project,
- bulkDeleteProjects,
- changeProjectDefaultVisibility,
- createProject,
- deletePortfolio,
- deleteProject,
- getComponents,
-} from '../project-management';
-import SettingsServiceMock from './SettingsServiceMock';
-
-jest.mock('../project-management');
-
-const defaultProject = [
- mockProject({ key: 'project1', name: 'Project 1' }),
- mockProject({ key: 'project2', name: 'Project 2', visibility: Visibility.Private }),
- mockProject({ key: 'project3', name: 'Project 3', lastAnalysisDate: undefined }),
- mockProject({ key: 'projectProvisioned', name: 'Project 4', managed: true }),
- mockProject({ key: 'portfolio1', name: 'Portfolio 1', qualifier: ComponentQualifier.Portfolio }),
- mockProject({
- key: 'portfolio2',
- name: 'Portfolio 2',
- qualifier: ComponentQualifier.Portfolio,
- visibility: Visibility.Private,
- }),
- mockProject({
- key: 'portfolio3',
- name: 'Portfolio 3',
- qualifier: ComponentQualifier.Portfolio,
- lastAnalysisDate: undefined,
- }),
- mockProject({
- key: 'application1',
- name: 'Application 1',
- qualifier: ComponentQualifier.Application,
- }),
- mockProject({
- key: 'application2',
- name: 'Application 2',
- qualifier: ComponentQualifier.Application,
- visibility: Visibility.Private,
- }),
- mockProject({
- key: 'application3',
- name: 'Application 3',
- qualifier: ComponentQualifier.Application,
- lastAnalysisDate: undefined,
- }),
-];
-
-export default class ProjectManagementServiceMock {
- #projects: Project[];
- #settingsService: SettingsServiceMock;
-
- constructor(settingsService: SettingsServiceMock) {
- this.#projects = cloneDeep(defaultProject);
- this.#settingsService = settingsService;
- jest.mocked(getComponents).mockImplementation(this.handleGetComponents);
- jest.mocked(createProject).mockImplementation(this.handleCreateProject);
- jest.mocked(bulkDeleteProjects).mockImplementation(this.handleBulkDeleteProjects);
- jest.mocked(deleteProject).mockImplementation(this.handleDeleteProject);
- jest.mocked(deletePortfolio).mockImplementation(this.handleDeletePortfolio);
- jest
- .mocked(changeProjectDefaultVisibility)
- .mockImplementation(this.handleChangeProjectDefaultVisibility);
- }
-
- setProjects = (projects: Project[]) => {
- this.#projects = cloneDeep(projects);
- };
-
- handleGetComponents: typeof getComponents = (params) => {
- const pageIndex = params.p || 1;
- const pageSize = params.ps || 50;
- const components = this.#projects.filter((item) => {
- if (params.qualifiers && item.qualifier !== params.qualifiers) {
- return false;
- }
- if (params.visibility && item.visibility !== params.visibility) {
- return false;
- }
- if (
- params.analyzedBefore &&
- (!item.lastAnalysisDate ||
- new Date(item.lastAnalysisDate) > new Date(params.analyzedBefore))
- ) {
- return false;
- }
- if (params.onProvisionedOnly && !item.key.includes('Provisioned')) {
- return false;
- }
- if (
- params.q &&
- !item.key.toLowerCase().includes(params.q.toLowerCase()) &&
- !item.name.toLowerCase().includes(params.q.toLowerCase())
- ) {
- return false;
- }
- if (params.projects !== undefined && !params.projects.split(',').includes(item.key)) {
- return false;
- }
- return true;
- });
-
- return this.reply({
- components: components.slice((pageIndex - 1) * pageSize, pageSize * pageIndex),
- paging: { pageIndex, pageSize, total: components.length },
- });
- };
-
- handleCreateProject: typeof createProject = ({ project, name, visibility }) => {
- this.#projects.unshift(
- mockProject({
- key: project,
- name,
- visibility,
- lastAnalysisDate: undefined,
- }),
- );
- return this.reply({ project: this.#projects[0] });
- };
-
- handleBulkDeleteProjects: typeof bulkDeleteProjects = ({ projects }) => {
- if (projects === undefined) {
- return Promise.reject();
- }
-
- this.#projects = this.#projects.filter((item) => !projects.split(',').includes(item.key));
- return this.reply();
- };
-
- handleDeleteProject: typeof deleteProject = (key) => {
- const projectToDelete = this.#projects.find((item) => key === item.key);
- if (projectToDelete?.qualifier !== ComponentQualifier.Project) {
- return Promise.reject();
- }
- this.#projects = this.#projects.filter((p) => p.key !== key);
- return this.reply();
- };
-
- handleDeletePortfolio: typeof deletePortfolio = (key) => {
- const portfolioToDelete = this.#projects.find((item) => key === item.key);
- if (portfolioToDelete?.qualifier !== ComponentQualifier.Portfolio) {
- return Promise.reject();
- }
- this.#projects = this.#projects.filter((p) => p.key !== key);
- return this.reply();
- };
-
- handleChangeProjectDefaultVisibility: typeof changeProjectDefaultVisibility = (visibility) => {
- this.#settingsService.set(SettingsKey.DefaultProjectVisibility, visibility);
- return this.reply();
- };
-
- reset = () => {
- this.#projects = cloneDeep(defaultProject);
- };
-
- reply<T>(): Promise<void>;
- reply<T>(response: T): Promise<T>;
- reply<T>(response?: T): Promise<T | void> {
- return Promise.resolve(response ? cloneDeep(response) : undefined);
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/ProjectsServiceMock.tsx b/server/sonar-web/src/main/js/api/mocks/ProjectsServiceMock.tsx
deleted file mode 100644
index dd0f98528b2..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/ProjectsServiceMock.tsx
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { MeasuresForProjects } from '../../types/measures';
-import { Dict } from '../../types/types';
-import { ComponentRaw, Facet, getScannableProjects, searchProjects } from '../components';
-import { addFavorite } from '../favorites';
-import { getMeasuresForProjects } from '../measures';
-import { mockFacets, mockProjectMeasures, mockProjects } from './data/projects';
-
-export class ProjectsServiceMock {
- projects: ComponentRaw[];
- measuresByProjectByMetric: Dict<Dict<MeasuresForProjects>> = {};
- facets: Facet[];
-
- constructor() {
- const { projects, measures, facets } = this.initData();
-
- this.projects = projects;
- this.measuresByProjectByMetric = measures;
- this.facets = facets;
-
- jest.mocked(searchProjects).mockImplementation(this.handleSearchProjects);
- jest.mocked(getMeasuresForProjects).mockImplementation(this.handleGetMeasuresForProjects);
- jest.mocked(getScannableProjects).mockImplementation(this.handleGetScannableProjects);
- jest.mocked(addFavorite).mockImplementation(this.handleAddFavorite);
- }
-
- nclocSort = (a: ComponentRaw, b: ComponentRaw) => {
- const { value: va = '0' } = (this.measuresByProjectByMetric[a.key] ?? { ncloc: { value: 0 } })
- .ncloc;
- const { value: vb = '0' } = (this.measuresByProjectByMetric[b.key] ?? { ncloc: { value: 0 } })
- .ncloc;
-
- return parseInt(va, 10) - parseInt(vb, 10);
- };
-
- handleSearchProjects = ({
- ps,
- facets = '',
- filter = '',
- s,
- }: {
- facets: string;
- filter: string;
- ps: number;
- s?: string;
- }) => {
- /*
- * Parse params
- */
- const facetKeys = facets.split(',');
-
- const filters = filter.split('and');
- const favorite = filters.includes('isFavorite');
-
- /*
- * Build response
- */
- const results = this.projects.filter((p) => {
- return !favorite || p.isFavorite === favorite;
- });
-
- const sorted = s === 'ncloc' ? results.sort(this.nclocSort) : results;
-
- return Promise.resolve({
- components: sorted.slice(0, ps),
- facets: this.facets.filter(({ property }) => {
- return facetKeys.includes(property);
- }),
- paging: {
- pageIndex: 1,
- pageSize: ps,
- total: sorted.length,
- },
- });
- };
-
- handleGetMeasuresForProjects = (projectKeys: string[] = [], metricKeys: string[] = []) => {
- const measures = projectKeys.flatMap((projectKey) => {
- const projectMeasures = this.measuresByProjectByMetric[projectKey] ?? {};
-
- return metricKeys.map((key) => projectMeasures[key]).filter((v) => v !== undefined);
- });
-
- return Promise.resolve(measures);
- };
-
- handleGetScannableProjects = () => {
- return Promise.resolve({
- projects: [],
- });
- };
-
- handleAddFavorite = (componentKey: string) => {
- const project = this.projects.find(({ key }) => componentKey === key);
-
- if (project) {
- project.isFavorite = true;
- return Promise.resolve();
- }
-
- return Promise.reject('project not found');
- };
-
- initData = () => {
- const projects = mockProjects();
- const measures = mockProjectMeasures();
- const facets = mockFacets();
-
- return { projects, measures, facets };
- };
-
- reset = () => {
- this.initData();
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts
deleted file mode 100644
index e79d8e43166..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts
+++ /dev/null
@@ -1,837 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep, flatten, omit, remove } from 'lodash';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { Project } from '../../apps/quality-gates/components/Projects';
-import { MQR_CONDITIONS_MAP, STANDARD_CONDITIONS_MAP } from '../../apps/quality-gates/utils';
-import {
- mockQualityGate,
- mockQualityGateApplicationStatus,
- mockQualityGateProjectStatus,
-} from '../../helpers/mocks/quality-gates';
-import { mockUserBase } from '../../helpers/mocks/users';
-import { mockCondition, mockGroup } from '../../helpers/testMocks';
-import {
- QualityGateApplicationStatus,
- QualityGateProjectStatus,
- SearchPermissionsParameters,
-} from '../../types/quality-gates';
-import { CaycStatus, Condition, QualityGate } from '../../types/types';
-import { AiCodeAssuranceStatus } from '../ai-code-assurance';
-import {
- addGroup,
- addUser,
- associateGateWithProject,
- copyQualityGate,
- createCondition,
- createQualityGate,
- deleteCondition,
- deleteQualityGate,
- dissociateGateWithProject,
- fetchQualityGate,
- fetchQualityGates,
- getAllQualityGateProjects,
- getApplicationQualityGate,
- getGateForProject,
- getQualityGateProjectStatus,
- renameQualityGate,
- searchGroups,
- searchProjects,
- searchUsers,
- setQualityGateAiQualified,
- setQualityGateAsDefault,
- updateCondition,
-} from '../quality-gates';
-
-jest.mock('../quality-gates');
-
-export class QualityGatesServiceMock {
- isAdmin = false;
- readOnlyList: QualityGate[];
- list: QualityGate[];
- projects: Project[];
- getGateForProjectGateName: string;
- throwOnGetGateForProject: boolean;
- qualityGateProjectStatus: QualityGateProjectStatus;
- applicationQualityGate: QualityGateApplicationStatus;
-
- constructor(list?: QualityGate[]) {
- this.readOnlyList = list || [
- mockQualityGate({
- name: 'SonarSource way',
- conditions: [
- {
- id: 'AXJMbIUGPAOIsUIE3eNC',
- metric: 'new_coverage',
- op: 'LT',
- error: '85',
- isCaycCondition: true,
- },
- {
- id: 'AXJMbIUGPAOIsUIE3eNF',
- metric: 'new_violations',
- op: 'GT',
- error: '0',
- isCaycCondition: true,
- },
- { id: 'AXJMbIUGPAOIsUIE3eNE', metric: 'reliability_rating', op: 'GT', error: '4' },
- { id: 'AXJMbIUGPAOIsUIE3eND', metric: 'security_rating', op: 'GT', error: '4' },
- {
- id: 'AXJMbIUGPAOIsUIE3eNT',
- metric: 'new_maintainability_rating',
- op: 'GT',
- error: '1',
- },
- { id: 'AXJMbIUGPAOIsUIE3eNU', metric: 'new_reliability_rating', op: 'GT', error: '1' },
- { id: 'AXJMbIUGPAOIsUIE3eNV', metric: 'new_security_rating', op: 'GT', error: '1' },
- {
- id: 'AXJMbIUHPAOIsUIE3eNc',
- metric: 'new_duplicated_lines_density',
- op: 'GT',
- error: '3',
- isCaycCondition: true,
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eOi',
- metric: 'new_security_hotspots_reviewed',
- op: 'LT',
- error: '100',
- isCaycCondition: true,
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eNfc',
- metric: MetricKey.new_line_coverage,
- op: 'GT',
- error: '3',
- },
- ],
- hasStandardConditions: true,
- hasMQRConditions: false,
- isDefault: true,
- isBuiltIn: false,
- caycStatus: CaycStatus.Compliant,
- isAiCodeSupported: false,
- }),
- mockQualityGate({
- name: 'SonarSource way - CFamily',
- conditions: [
- {
- id: 'AXJMbIUHPAOIsUIE3eOi',
- metric: 'new_security_hotspots_reviewed',
- op: 'LT',
- error: '100',
- isCaycCondition: true,
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eOu',
- metric: 'new_coverage',
- op: 'LT',
- error: '0',
- isCaycCondition: true,
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eOl',
- metric: MetricKey.new_software_quality_security_rating,
- op: 'GT',
- error: '1',
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eOd',
- metric: MetricKey.new_software_quality_security_rating,
- op: 'GT',
- error: '0',
- },
- { id: 'deprecated', metric: 'public_api', op: 'LT', error: '1' },
- ],
- isDefault: false,
- isBuiltIn: false,
- hasStandardConditions: false,
- hasMQRConditions: true,
- caycStatus: CaycStatus.NonCompliant,
- }),
- mockQualityGate({
- name: 'Sonar way',
- conditions: [
- {
- id: 'AXJMbIUHPAOIsUIE3eQQ',
- metric: 'new_violations',
- op: 'GT',
- error: '0',
- isCaycCondition: true,
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eOF',
- metric: 'new_coverage',
- op: 'LT',
- error: '80',
- isCaycCondition: true,
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eOG',
- metric: 'new_duplicated_lines_density',
- op: 'GT',
- error: '3',
- isCaycCondition: true,
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eOk',
- metric: 'new_security_hotspots_reviewed',
- op: 'LT',
- error: '100',
- isCaycCondition: true,
- },
- ],
- isDefault: false,
- isBuiltIn: true,
- hasStandardConditions: false,
- hasMQRConditions: false,
- caycStatus: CaycStatus.Compliant,
- isAiCodeSupported: false,
- }),
- mockQualityGate({
- name: 'Sonar way for AI code',
- conditions: [
- {
- id: 'AXJMbIUHPAOIsUIE3eQQ',
- metric: 'new_violations',
- op: 'GT',
- error: '0',
- isCaycCondition: true,
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eOF',
- metric: 'new_coverage',
- op: 'LT',
- error: '80',
- isCaycCondition: true,
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eOG',
- metric: 'new_duplicated_lines_density',
- op: 'GT',
- error: '3',
- isCaycCondition: true,
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eOk',
- metric: 'new_security_hotspots_reviewed',
- op: 'LT',
- error: '100',
- isCaycCondition: true,
- },
- {
- id: '0cf34ce4-7760-4bbb-8d8c-41e32b1913c8',
- metric: 'software_quality_security_rating',
- op: 'GT',
- error: '1',
- isCaycCondition: false,
- },
- {
- id: 'fc3d8a6e-e020-48a8-8bcb-ceccd1f9ca63',
- metric: 'security_hotspots_reviewed',
- op: 'LT',
- error: '100',
- isCaycCondition: false,
- },
- {
- id: 'eae5888d-92d6-463a-bd81-9911debaa88d',
- metric: 'software_quality_reliability_rating',
- op: 'GT',
- error: '3',
- isCaycCondition: false,
- },
- ],
- isDefault: false,
- isBuiltIn: true,
- hasStandardConditions: false,
- hasMQRConditions: false,
- isAiCodeSupported: true,
- caycStatus: CaycStatus.Compliant,
- }),
- mockQualityGate({
- name: 'Non Cayc QG',
- conditions: [
- {
- id: 'AXJMbIUHPAOIsUIE3eCC',
- metric: MetricKey.new_software_quality_security_rating,
- op: 'LT',
- error: '80',
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eOD',
- metric: MetricKey.new_software_quality_reliability_rating,
- op: 'LT',
- error: '80',
- },
- { id: 'AXJMbIUHPAOIsUIE3eOA', metric: MetricKey.new_coverage, op: 'LT', error: '80' },
- ],
- isDefault: false,
- isBuiltIn: false,
- caycStatus: CaycStatus.NonCompliant,
- hasStandardConditions: false,
- hasMQRConditions: true,
- }),
- mockQualityGate({
- name: 'Non Cayc Compliant QG',
- conditions: [
- {
- id: 'AXJMbIUHPAOIsUIE3eDD',
- metric: MetricKey.new_software_quality_security_rating,
- op: 'GT',
- error: '1',
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eDA',
- metric: MetricKey.new_software_quality_reliability_rating,
- op: 'GT',
- error: '1',
- },
- { id: 'AXJMbIUHPAOIsUIE3eDK', metric: MetricKey.new_coverage, op: 'LT', error: '80' },
- ],
- isDefault: false,
- isBuiltIn: false,
- hasStandardConditions: false,
- hasMQRConditions: true,
- caycStatus: CaycStatus.Compliant,
- }),
- mockQualityGate({
- name: 'Over Compliant CaYC QG',
- conditions: [
- { id: 'deprecatedoc', metric: 'public_api', op: 'LT', error: '1' },
- { id: 'AXJMbIUHPAOIsUIE3eOFoc', metric: 'new_coverage', op: 'LT', error: '80' },
- { id: 'AXJMbIUHPAOIsUIE3eNsoc', metric: 'new_security_rating', op: 'GT', error: '1' },
- { id: 'AXJMbIUHPAOIsUIE3eODoc', metric: 'new_reliability_rating', op: 'GT', error: '1' },
- {
- id: 'AXJMbIUHPAOIsUIE3eOEoc',
- metric: 'new_maintainability_rating',
- op: 'GT',
- error: '1',
- },
- { id: 'AXJMbIUHPAOIsUIE3eOFocdl', metric: 'new_coverage', op: 'LT', error: '80' },
- {
- id: 'AXJMbIUHPAOIsUIE3eOGoc',
- metric: 'new_duplicated_lines_density',
- op: 'GT',
- error: '3',
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eOkoc',
- metric: 'new_security_hotspots_reviewed',
- op: 'LT',
- error: '100',
- },
- ],
- isDefault: false,
- isBuiltIn: false,
- hasStandardConditions: true,
- hasMQRConditions: false,
- caycStatus: CaycStatus.OverCompliant,
- }),
- mockQualityGate({
- name: 'QG without conditions',
- conditions: [],
- isDefault: false,
- isBuiltIn: false,
- hasStandardConditions: false,
- hasMQRConditions: false,
- caycStatus: CaycStatus.NonCompliant,
- }),
- mockQualityGate({
- name: 'QG without new code conditions',
- conditions: [
- { id: 'AXJMbIUHPAOIsUIE3eAA', metric: 'security_rating', op: 'GT', error: '1' },
- ],
- isDefault: false,
- isBuiltIn: false,
- hasStandardConditions: true,
- hasMQRConditions: false,
- caycStatus: CaycStatus.NonCompliant,
- }),
- mockQualityGate({
- name: 'QG with MQR conditions',
- conditions: [
- {
- id: 'AXJMbIUHPAOIsUIE3eWW',
- metric: MetricKey.software_quality_security_rating,
- op: 'GT',
- error: '1',
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eW1',
- metric: MetricKey.new_software_quality_blocker_issues,
- op: 'GT',
- error: '1',
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eW2',
- metric: MetricKey.new_software_quality_high_issues,
- op: 'GT',
- error: '1',
- },
- {
- id: 'AXJMbIUHPAOIsUIE3eW3',
- metric: MetricKey.high_impact_accepted_issues,
- op: 'GT',
- error: '1',
- },
- ],
- isDefault: false,
- isBuiltIn: false,
- hasStandardConditions: false,
- hasMQRConditions: true,
- caycStatus: CaycStatus.NonCompliant,
- }),
- ];
-
- this.list = cloneDeep(this.readOnlyList);
-
- this.projects = [
- {
- key: 'test1',
- name: 'test1',
- selected: false,
- aiCodeAssurance: AiCodeAssuranceStatus.NONE,
- },
- {
- key: 'test2',
- name: 'test2',
- selected: false,
- aiCodeAssurance: AiCodeAssuranceStatus.NONE,
- },
- {
- key: 'test3',
- name: 'test3',
- selected: true,
- aiCodeAssurance: AiCodeAssuranceStatus.NONE,
- },
- {
- key: 'test4',
- name: 'test4',
- selected: true,
- aiCodeAssurance: AiCodeAssuranceStatus.NONE,
- },
- {
- key: 'test5',
- name: 'test5',
- selected: true,
- aiCodeAssurance: AiCodeAssuranceStatus.CONTAINS_AI_CODE,
- },
- {
- key: 'test6',
- name: 'test6',
- selected: false,
- aiCodeAssurance: AiCodeAssuranceStatus.CONTAINS_AI_CODE,
- },
- {
- key: 'test7',
- name: 'test7',
- selected: true,
- aiCodeAssurance: AiCodeAssuranceStatus.AI_CODE_ASSURED,
- },
- ];
-
- this.getGateForProjectGateName = 'SonarSource way';
- this.throwOnGetGateForProject = false;
-
- jest.mocked(fetchQualityGate).mockImplementation(this.showHandler);
- jest.mocked(fetchQualityGates).mockImplementation(this.listHandler);
- jest.mocked(createQualityGate).mockImplementation(this.createHandler);
- jest.mocked(deleteQualityGate).mockImplementation(this.destroyHandler);
- jest.mocked(copyQualityGate).mockImplementation(this.copyHandler);
- (renameQualityGate as jest.Mock).mockImplementation(this.renameHandler);
- jest.mocked(createCondition).mockImplementation(this.createConditionHandler);
- jest.mocked(updateCondition).mockImplementation(this.updateConditionHandler);
- jest.mocked(deleteCondition).mockImplementation(this.deleteConditionHandler);
- jest.mocked(searchProjects).mockImplementation(this.searchProjectsHandler);
- jest
- .mocked(getAllQualityGateProjects)
- .mockImplementation(this.getAllQualityGateProjectsHandler);
- jest.mocked(searchUsers).mockImplementation(this.searchUsersHandler);
- jest.mocked(searchGroups).mockImplementation(this.searchGroupsHandler);
- jest.mocked(associateGateWithProject).mockImplementation(this.selectHandler);
- jest.mocked(dissociateGateWithProject).mockImplementation(this.deSelectHandler);
- jest.mocked(setQualityGateAsDefault).mockImplementation(this.setDefaultHandler);
- jest.mocked(getGateForProject).mockImplementation(this.projectGateHandler);
- jest.mocked(getQualityGateProjectStatus).mockImplementation(this.handleQualityGetProjectStatus);
- jest.mocked(getApplicationQualityGate).mockImplementation(this.handleGetApplicationQualityGate);
- jest.mocked(setQualityGateAiQualified).mockImplementation(this.handleSetQualityGateAiQualified);
-
- this.qualityGateProjectStatus = mockQualityGateProjectStatus({});
- this.applicationQualityGate = mockQualityGateApplicationStatus({});
-
- // To be implemented.
- (addUser as jest.Mock).mockResolvedValue({});
- (addGroup as jest.Mock).mockResolvedValue({});
- }
-
- getCorruptedQualityGateName() {
- return 'SonarSource way - CFamily';
- }
-
- reset() {
- this.setIsAdmin(false);
- this.list = cloneDeep(this.readOnlyList);
- this.getGateForProjectGateName = 'SonarSource way';
- }
-
- getDefaultQualityGate() {
- return this.list.find((q) => q.isDefault) || mockQualityGate({ isDefault: true });
- }
-
- getBuiltInQualityGate() {
- return this.list.find((q) => q.isBuiltIn) || mockQualityGate({ isBuiltIn: true });
- }
-
- setIsAdmin(isAdmin: boolean) {
- this.isAdmin = isAdmin;
- }
-
- setGetGateForProjectName(name: string) {
- this.getGateForProjectGateName = name;
- }
-
- setThrowOnGetGateForProject(value: boolean) {
- this.throwOnGetGateForProject = value;
- }
-
- computeActions(q: QualityGate) {
- return {
- rename: q.isBuiltIn ? false : this.isAdmin,
- setAsDefault: q.isDefault ? false : this.isAdmin,
- copy: this.isAdmin,
- associateProjects: this.isAdmin,
- delete: q.isBuiltIn ? false : this.isAdmin,
- manageConditions: this.isAdmin,
- delegate: this.isAdmin,
- manageAiCodeAssurance: this.isAdmin && !q.isBuiltIn,
- };
- }
-
- listHandler = () => {
- return this.reply({
- qualitygates: this.list
- .map((q) => omit(q, 'conditions'))
- .map((q) => ({
- ...q,
- actions: this.computeActions(q),
- })),
- default: this.getDefaultQualityGate().name,
- actions: { create: this.isAdmin },
- });
- };
-
- showHandler = ({ name }: { name: string }) => {
- const qualityGate = omit(
- this.list.find((q) => q.name === name),
- 'isDefault',
- );
- return this.reply({ ...qualityGate, actions: this.computeActions(qualityGate) });
- };
-
- createHandler = ({ name }: { name: string }) => {
- this.list.push(
- mockQualityGate({
- name,
- conditions: [
- mockCondition({
- id: `${MetricKey.new_reliability_rating}1`,
- metric: MetricKey.new_reliability_rating,
- error: '1',
- }),
- mockCondition({
- id: `${MetricKey.new_maintainability_rating}1`,
- metric: MetricKey.new_maintainability_rating,
- error: '1',
- }),
- mockCondition({
- id: `${MetricKey.new_security_rating}1`,
- metric: MetricKey.new_security_rating,
- error: '1',
- }),
- mockCondition({
- id: `${MetricKey.new_security_hotspots_reviewed}1`,
- metric: MetricKey.new_security_hotspots_reviewed,
- error: '100',
- }),
- ],
- isDefault: false,
- isBuiltIn: false,
- caycStatus: CaycStatus.Compliant,
- }),
- );
- return this.reply({
- name,
- });
- };
-
- destroyHandler = ({ name }: { name: string }) => {
- this.list = this.list.filter((q) => q.name !== name);
- return Promise.resolve();
- };
-
- copyHandler = ({ sourceName, name }: { name: string; sourceName: string }) => {
- const newQG = cloneDeep(this.list.find((q) => q.name === sourceName));
- if (newQG === undefined) {
- return Promise.reject({
- errors: [{ msg: `No quality gate has been found for name ${sourceName}` }],
- });
- }
- newQG.name = name;
-
- newQG.isDefault = false;
- newQG.isBuiltIn = false;
-
- this.list.push(newQG);
-
- return this.reply({
- name,
- });
- };
-
- renameHandler = ({ currentName, name }: { currentName: string; name: string }) => {
- const renameQG = this.list.find((q) => q.name === currentName);
- if (renameQG === undefined) {
- return Promise.reject({
- errors: [{ msg: `No quality gate has been found for name ${currentName}` }],
- });
- }
- renameQG.name = name;
- return this.reply({
- name,
- });
- };
-
- setDefaultHandler = ({ name }: { name: string }) => {
- this.list.forEach((q) => {
- q.isDefault = false;
- });
- const selectedQG = this.list.find((q) => q.name === name);
- if (selectedQG === undefined) {
- return Promise.reject({
- errors: [{ msg: `No quality gate has been found for name ${name}` }],
- });
- }
- selectedQG.isDefault = true;
- return Promise.resolve();
- };
-
- createConditionHandler = (
- data: {
- gateName: string;
- } & Omit<Condition, 'id'>,
- ) => {
- const { metric, gateName, op, error, isCaycCondition } = data;
- const qg = this.list.find((q) => q.name === gateName);
- if (qg === undefined) {
- return Promise.reject({
- errors: [{ msg: `No quality gate has been found for name ${gateName}` }],
- });
- }
-
- const conditions = qg.conditions || [];
- const id = `condId${qg.name}${conditions.length}`;
- const newCondition = { metric, op, error, id, isCaycCondition };
-
- conditions.push(newCondition);
- qg.conditions = conditions;
- qg.hasMQRConditions =
- qg.hasMQRConditions || MQR_CONDITIONS_MAP[metric as MetricKey] !== undefined;
- qg.hasStandardConditions =
- qg.hasStandardConditions || STANDARD_CONDITIONS_MAP[metric as MetricKey] !== undefined;
- return this.reply(newCondition);
- };
-
- updateConditionHandler = ({ id, metric, op, error, isCaycCondition }: Condition) => {
- const condition = flatten(this.list.map((q) => q.conditions || [])).find((q) => q.id === id);
- if (condition === undefined) {
- return Promise.reject({ errors: [{ msg: `No condition has been found for id ${id}` }] });
- }
-
- condition.metric = metric;
- condition.op = op;
- condition.error = error;
- condition.isCaycCondition = isCaycCondition;
-
- const qg = this.list.find((qg) => qg.conditions?.find((c) => c.id === id));
-
- if (qg) {
- qg.hasMQRConditions =
- qg.conditions?.some((c) => MQR_CONDITIONS_MAP[c.metric as MetricKey] !== undefined) ||
- false;
- qg.hasStandardConditions =
- qg.conditions?.some((c) => STANDARD_CONDITIONS_MAP[c.metric as MetricKey] !== undefined) ||
- false;
- }
-
- return this.reply(condition);
- };
-
- deleteConditionHandler = ({ id }: { id: string }) => {
- this.list.forEach((q) => {
- remove(q.conditions || [], (c) => c.id === id);
- });
-
- const qg = this.list.find((qg) => qg.conditions?.find((c) => c.id === id));
-
- if (qg) {
- qg.hasMQRConditions =
- qg.conditions?.some((c) => MQR_CONDITIONS_MAP[c.metric as MetricKey] !== undefined) ||
- false;
- qg.hasStandardConditions =
- qg.conditions?.some((c) => STANDARD_CONDITIONS_MAP[c.metric as MetricKey] !== undefined) ||
- false;
- }
-
- return Promise.resolve();
- };
-
- searchProjectsHandler = ({
- selected,
- query,
- }: {
- gateName: string;
- query: string | undefined;
- selected: string;
- }) => {
- let filteredProjects = this.projects;
- if (selected === 'selected') {
- filteredProjects = this.projects.filter((p) => p.selected);
- } else if (selected === 'deselected') {
- filteredProjects = this.projects.filter((p) => !p.selected);
- }
-
- if (query !== '' && query !== undefined) {
- filteredProjects = filteredProjects.filter((p) => p.name.includes(query));
- }
-
- const response = {
- paging: { pageIndex: 1, pageSize: 3, total: 55 },
- results: filteredProjects,
- };
- return this.reply(response);
- };
-
- getAllQualityGateProjectsHandler = async ({
- gateName,
- selected,
- query,
- }: {
- gateName: string;
- query: string | undefined;
- selected: string;
- }) => {
- const initialResponse = await this.searchProjectsHandler({ gateName: '', query, selected });
-
- const response = {
- paging: { pageIndex: 3, pageSize: 3, total: 55 },
- results:
- gateName === 'SonarSource way'
- ? initialResponse.results.filter((p) => p.aiCodeAssurance !== 'AI_CODE_ASSURED')
- : initialResponse.results,
- };
- return this.reply(response);
- };
-
- searchUsersHandler = ({ selected }: SearchPermissionsParameters) => {
- if (selected === 'selected') {
- return this.reply({ users: [] });
- }
-
- return this.reply({ users: [mockUserBase()] });
- };
-
- searchGroupsHandler = ({ selected }: SearchPermissionsParameters) => {
- if (selected === 'selected') {
- return this.reply({ groups: [] });
- }
-
- return this.reply({ groups: [mockGroup()] });
- };
-
- selectHandler = ({ projectKey }: { projectKey: string }) => {
- const changedProject = this.projects.find((p) => p.key === projectKey);
- if (changedProject) {
- changedProject.selected = true;
- }
- return Promise.resolve();
- };
-
- deSelectHandler = ({ projectKey }: { projectKey: string }) => {
- const changedProject = this.projects.find((p) => p.key === projectKey);
- if (changedProject) {
- changedProject.selected = false;
- }
- return Promise.resolve();
- };
-
- projectGateHandler = () => {
- if (this.throwOnGetGateForProject) {
- return Promise.reject('unknown');
- }
-
- const qualityGate = this.list.find((qg) => qg.name === this.getGateForProjectGateName);
-
- if (!qualityGate) {
- return Promise.reject('Unable to find quality gate');
- }
-
- return this.reply({
- name: qualityGate.name,
- isDefault: qualityGate.isDefault,
- });
- };
-
- handleGetApplicationQualityGate = () => {
- return this.reply(this.applicationQualityGate);
- };
-
- setApplicationQualityGateStatus = (status: Partial<QualityGateApplicationStatus>) => {
- this.applicationQualityGate = mockQualityGateApplicationStatus(status);
- };
-
- handleQualityGetProjectStatus = () => {
- return this.reply(this.qualityGateProjectStatus);
- };
-
- setQualityGateProjectStatus = (status: Partial<QualityGateProjectStatus>) => {
- this.qualityGateProjectStatus = mockQualityGateProjectStatus(status);
- };
-
- setCaycStatusForQualityGate = (name: string, caycStatus: CaycStatus) => {
- const qg = this.list.find((q) => q.name === name);
- if (qg) {
- qg.caycStatus = caycStatus;
- }
- };
-
- handleSetQualityGateAiQualified = (gateName: string, aiCodeAssurance: boolean) => {
- const targetQG = this.list.find((q) => q.name === gateName);
- if (targetQG === undefined) {
- return Promise.reject(new Error(`No quality gate has been found for name ${gateName}`));
- }
- targetQG.isAiCodeSupported = aiCodeAssurance;
- return this.reply(undefined);
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/QualityProfilesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/QualityProfilesServiceMock.ts
deleted file mode 100644
index b7bec2d3d18..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/QualityProfilesServiceMock.ts
+++ /dev/null
@@ -1,846 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { ProfileChangelogEvent } from '../../apps/quality-profiles/types';
-import { RequestData } from '../../helpers/request';
-import {
- mockCompareResult,
- mockGroup,
- mockPaging,
- mockQualityProfile,
- mockQualityProfileChangelogEvent,
- mockRuleDetails,
- mockUserSelected,
-} from '../../helpers/testMocks';
-import {
- CleanCodeAttribute,
- CleanCodeAttributeCategory,
- SoftwareImpactSeverity,
- SoftwareQuality,
-} from '../../types/clean-code-taxonomy';
-import { SearchRulesResponse } from '../../types/coding-rules';
-import { IssueSeverity } from '../../types/issues';
-import { QualityProfileChangelogFilterMode } from '../../types/quality-profiles';
-import { SearchRulesQuery } from '../../types/rules';
-import { Dict, Paging, ProfileInheritanceDetails, RuleDetails } from '../../types/types';
-import {
- activateRule,
- addGroup,
- addUser,
- associateProject,
- changeProfileParent,
- compareProfiles,
- CompareResponse,
- copyProfile,
- createQualityProfile,
- deactivateRule,
- deleteProfile,
- dissociateProject,
- getExporters,
- getImporters,
- getProfileChangelog,
- getProfileInheritance,
- getProfileProjects,
- getQualityProfile,
- getQualityProfileExporterUrl,
- Profile,
- ProfileProject,
- removeGroup,
- removeUser,
- renameProfile,
- restoreQualityProfile,
- searchGroups,
- searchQualityProfiles,
- SearchQualityProfilesParameters,
- SearchQualityProfilesResponse,
- searchUsers,
- setDefaultProfile,
-} from '../quality-profiles';
-import { getRuleDetails, listRules, searchRules } from '../rules';
-
-jest.mock('../../api/rules');
-
-export default class QualityProfilesServiceMock {
- isAdmin = false;
- listQualityProfile: Profile[] = [];
- languageMapping: Dict<Partial<Profile>> = {
- c: { language: 'c', languageName: 'C' },
- php: { language: 'php', languageName: 'PHP' },
- java: { language: 'java', languageName: 'Java' },
- };
-
- comparisonResult: CompareResponse = mockCompareResult();
- searchRulesResponse: SearchRulesResponse = {
- rules: [],
- paging: mockPaging(),
- };
-
- profileProjects: {
- [profileKey: string]: ProfileProject[];
- } = {};
-
- changelogEvents: ProfileChangelogEvent[] = [];
-
- constructor() {
- this.resetQualityProfile();
- this.resetComparisonResult();
- this.resetChangelogEvents();
-
- jest.mocked(searchQualityProfiles).mockImplementation(this.handleSearchQualityProfiles);
- jest.mocked(createQualityProfile).mockImplementation(this.handleCreateQualityProfile);
- jest.mocked(changeProfileParent).mockImplementation(this.handleChangeProfileParent);
- jest.mocked(getProfileInheritance).mockImplementation(this.handleGetProfileInheritance);
- jest.mocked(getProfileProjects).mockImplementation(this.handleGetProfileProjects);
- jest.mocked(copyProfile).mockImplementation(this.handleCopyProfile);
- jest.mocked(getImporters).mockImplementation(this.handleGetImporters);
- jest.mocked(searchRules).mockImplementation(this.handleSearchRules);
- jest.mocked(listRules).mockImplementation(this.handleListRules);
- jest.mocked(compareProfiles).mockImplementation(this.handleCompareQualityProfiles);
- jest.mocked(activateRule).mockImplementation(this.handleActivateRule);
- jest.mocked(deactivateRule).mockImplementation(this.handleDeactivateRule);
- jest.mocked(getRuleDetails).mockImplementation(this.handleGetRuleDetails);
- jest.mocked(restoreQualityProfile).mockImplementation(this.handleRestoreQualityProfile);
- jest.mocked(searchUsers).mockImplementation(this.handleSearchUsers);
- jest.mocked(addUser).mockImplementation(this.handleAddUser);
- jest.mocked(searchGroups).mockImplementation(this.handleSearchGroups);
- jest.mocked(addGroup).mockImplementation(this.handleAddGroup);
- jest.mocked(removeGroup).mockImplementation(this.handleRemoveGroup);
- jest.mocked(removeUser).mockImplementation(this.handleRemoveUser);
- jest.mocked(associateProject).mockImplementation(this.handleAssociateProject);
- jest.mocked(getProfileChangelog).mockImplementation(this.handleGetProfileChangelog);
- jest.mocked(dissociateProject).mockImplementation(this.handleDissociateProject);
- jest.mocked(getQualityProfile).mockImplementation(this.handleGetQualityProfile);
- jest.mocked(getExporters).mockImplementation(this.handleGetExporters);
- jest.mocked(deleteProfile).mockImplementation(this.handleDeleteProfile);
- jest.mocked(renameProfile).mockImplementation(this.handleRenameProfile);
- jest.mocked(setDefaultProfile).mockImplementation(this.handleSetDefaultProfile);
- jest
- .mocked(getQualityProfileExporterUrl)
- .mockImplementation(() => '/api/qualityprofiles/export');
- }
-
- resetQualityProfile() {
- this.listQualityProfile = [
- mockQualityProfile({
- key: 'c-qp',
- language: 'c',
- languageName: 'C',
- name: 'c quality profile',
- activeDeprecatedRuleCount: 0,
- }),
- mockQualityProfile({
- key: 'java-qp',
- language: 'java',
- languageName: 'Java',
- name: 'java quality profile',
- activeDeprecatedRuleCount: 0,
- }),
- mockQualityProfile({
- key: 'java-qp-1',
- language: 'java',
- languageName: 'Java',
- name: 'java quality profile #2',
- activeDeprecatedRuleCount: 1,
- actions: {
- edit: this.isAdmin,
- },
- }),
- mockQualityProfile({
- key: 'sonar',
- language: 'java',
- languageName: 'Java',
- name: 'Sonar way',
- isBuiltIn: true,
- isDefault: true,
- }),
- mockQualityProfile({
- key: 'old-php-qp',
- language: 'php',
- languageName: 'PHP',
- name: 'Good old PHP quality profile',
- activeDeprecatedRuleCount: 8,
- rulesUpdatedAt: '2019-09-16T21:10:36+0000',
- parentKey: 'php-sonar-way-1',
- actions: {
- edit: this.isAdmin,
- associateProjects: this.isAdmin,
- delete: this.isAdmin,
- setAsDefault: this.isAdmin,
- copy: this.isAdmin,
- },
- }),
- mockQualityProfile({
- key: 'no-rule-qp',
- activeRuleCount: 0,
- actions: {
- associateProjects: true,
- setAsDefault: this.isAdmin,
- },
- }),
- mockQualityProfile({
- activeRuleCount: 6,
- isBuiltIn: true,
- key: 'php-sonar-way-1',
- name: 'PHP Sonar way 1',
- language: 'php',
- languageName: 'PHP',
- }),
- mockQualityProfile({
- activeRuleCount: 6,
- isBuiltIn: false,
- key: 'php-sonar-way-2',
- name: 'PHP Sonar way 2',
- language: 'php',
- languageName: 'PHP',
- }),
- mockQualityProfile({
- activeRuleCount: 3,
- isBuiltIn: false,
- key: 'php-sonar-way',
- parentKey: 'old-php-qp',
- name: 'PHP way',
- language: 'php',
- languageName: 'PHP',
- }),
- ];
- }
-
- resetComparisonResult() {
- this.comparisonResult = mockCompareResult();
- }
-
- resetChangelogEvents() {
- this.changelogEvents = [
- mockQualityProfileChangelogEvent({
- date: '2019-05-23T04:12:32+0100',
- }),
- mockQualityProfileChangelogEvent({
- date: '2019-05-23T03:12:32+0100',
- action: 'DEACTIVATED',
- ruleKey: 'php:rule1',
- ruleName: 'PHP Rule',
- params: {
- severity: IssueSeverity.Critical,
- newCleanCodeAttribute: CleanCodeAttribute.Complete,
- newCleanCodeAttributeCategory: CleanCodeAttributeCategory.Intentional,
- oldCleanCodeAttribute: CleanCodeAttribute.Clear,
- oldCleanCodeAttributeCategory: CleanCodeAttributeCategory.Responsible,
- },
- }),
- mockQualityProfileChangelogEvent({
- date: '2019-05-23T03:12:32+0100',
- action: 'ACTIVATED',
- ruleKey: 'c:rule0',
- ruleName: 'Rule 0',
- params: {},
- }),
- mockQualityProfileChangelogEvent({
- date: '2019-04-23T03:12:32+0100',
- action: 'DEACTIVATED',
- ruleKey: 'c:rule0',
- ruleName: 'Rule 0',
- }),
- mockQualityProfileChangelogEvent({
- date: '2019-04-23T03:12:32+0100',
- action: 'DEACTIVATED',
- ruleKey: 'c:rule1',
- ruleName: 'Rule 1',
- params: {
- severity: IssueSeverity.Critical,
- newCleanCodeAttribute: CleanCodeAttribute.Complete,
- newCleanCodeAttributeCategory: CleanCodeAttributeCategory.Intentional,
- oldCleanCodeAttribute: CleanCodeAttribute.Lawful,
- oldCleanCodeAttributeCategory: CleanCodeAttributeCategory.Responsible,
- impactChanges: [
- {
- newSeverity: SoftwareImpactSeverity.Medium,
- newSoftwareQuality: SoftwareQuality.Reliability,
- },
- {
- oldSeverity: SoftwareImpactSeverity.High,
- oldSoftwareQuality: SoftwareQuality.Maintainability,
- },
- ],
- },
- }),
- mockQualityProfileChangelogEvent({
- date: '2019-04-23T02:12:32+0100',
- action: 'DEACTIVATED',
- ruleKey: 'c:rule2',
- ruleName: 'Rule 2',
- authorName: 'John Doe',
- }),
- mockQualityProfileChangelogEvent({
- date: '2019-03-23T02:12:32+0100',
- ruleKey: 'c:rule2',
- ruleName: 'Rule 2',
- authorName: 'John Doe',
- params: {
- severity: IssueSeverity.Critical,
- credentialWords: 'foo,bar',
- },
- }),
- mockQualityProfileChangelogEvent({
- date: '2019-02-23T03:12:32+0100',
- action: 'UPDATED',
- ruleKey: 'c:rule4',
- ruleName: 'Rule 5',
- params: {
- newCleanCodeAttribute: CleanCodeAttribute.Complete,
- newCleanCodeAttributeCategory: CleanCodeAttributeCategory.Intentional,
- oldCleanCodeAttribute: CleanCodeAttribute.Lawful,
- oldCleanCodeAttributeCategory: CleanCodeAttributeCategory.Responsible,
- impactChanges: [
- {
- newSeverity: SoftwareImpactSeverity.Medium,
- newSoftwareQuality: SoftwareQuality.Reliability,
- },
- {
- oldSeverity: SoftwareImpactSeverity.High,
- oldSoftwareQuality: SoftwareQuality.Maintainability,
- },
- ],
- },
- }),
- mockQualityProfileChangelogEvent({
- date: '2019-01-23T03:12:32+0100',
- action: 'UPDATED',
- ruleKey: 'c:rule6',
- ruleName: 'Rule 6',
- params: {
- severity: IssueSeverity.Critical,
- },
- }),
- ];
- }
-
- resetSearchRulesResponse() {
- this.searchRulesResponse = {
- facets: [
- {
- property: 'types',
- values: [
- { val: 'CODE_SMELL', count: 250 },
- { val: 'BUG', count: 60 },
- { val: 'VULNERABILITY', count: 40 },
- { val: 'SECURITY_HOTSPOT', count: 50 },
- ],
- },
- ],
- rules: [],
- paging: {
- pageIndex: 1,
- pageSize: 400,
- total: 400,
- },
- };
- }
-
- resetProfileProjects() {
- this.profileProjects = {
- 'old-php-qp': [
- {
- key: 'Benflix',
- name: 'Benflix',
- selected: true,
- },
- {
- key: 'Twitter',
- name: 'Twitter',
- selected: false,
- },
- ],
- };
- }
-
- handleGetImporters = () => {
- return this.reply([
- {
- key: 'sonar-importer-a',
- name: 'Importer A',
- languages: ['c'],
- },
- {
- key: 'sonar-importer-b',
- name: 'Importer B',
- languages: ['c'],
- },
- ]);
- };
-
- handleCopyProfile = (fromKey: string, name: string): Promise<Profile> => {
- const profile = this.listQualityProfile.find((p) => p.key === fromKey);
- if (!profile) {
- return Promise.reject({
- errors: [{ msg: `No profile has been found for ${fromKey}` }],
- });
- }
-
- const copiedQualityProfile = mockQualityProfile({
- ...profile,
- name,
- key: `qp${this.listQualityProfile.length}`,
- });
-
- this.listQualityProfile.push(copiedQualityProfile);
-
- return this.reply(copiedQualityProfile);
- };
-
- handleGetProfileProjects = (
- data: RequestData,
- ): Promise<{
- more: boolean;
- paging: Paging;
- results: ProfileProject[];
- }> => {
- const results = (this.profileProjects[data.key] ?? []).filter(
- (project) =>
- project.selected ===
- (data.selected !== undefined ? Boolean(data.selected === 'selected') : true),
- );
-
- return this.reply({
- more: false,
- paging: {
- pageIndex: 0,
- pageSize: 10,
- total: 0,
- },
- results,
- });
- };
-
- handleGetProfileInheritance = ({
- language,
- name,
- }: Profile): Promise<{
- ancestors: ProfileInheritanceDetails[];
- children: ProfileInheritanceDetails[];
- profile: ProfileInheritanceDetails;
- }> => {
- const profileToProfileInheritanceDetails = (profile: Profile): ProfileInheritanceDetails => ({
- ...profile,
- inactiveRuleCount: 3,
- isBuiltIn: false,
- });
-
- const profile = this.listQualityProfile.find((p) => p.name === name && p.language === language);
- if (!profile) {
- return Promise.reject({
- errors: [{ msg: `No profile has been found for ${language} ${name}` }],
- });
- }
-
- const ancestors = this.listQualityProfile
- .filter((p) => p.key === profile.parentKey)
- .map(profileToProfileInheritanceDetails);
- const children = this.listQualityProfile
- .filter((p) => p.parentKey === profile.key)
- .map(profileToProfileInheritanceDetails);
-
- return this.reply({
- ancestors,
- children,
- profile: profileToProfileInheritanceDetails(profile),
- });
- };
-
- handleChangeProfileParent = ({ language, name }: Profile, parentProfile?: Profile) => {
- const profile = this.listQualityProfile.find((p) => p.name === name && p.language === language);
-
- if (!profile) {
- return Promise.reject({
- errors: [{ msg: `No profile has been found for ${language} ${name}` }],
- });
- }
-
- profile.parentKey = parentProfile?.key;
- profile.parentName = parentProfile?.name;
-
- return Promise.resolve({});
- };
-
- handleCreateQualityProfile = (data: RequestData | FormData) => {
- if (data instanceof FormData) {
- const name = data.get('name') as string;
- const language = data.get('language') as string;
- const newQualityProfile = mockQualityProfile({
- name,
- ...this.languageMapping[language],
- key: `qp${this.listQualityProfile.length}`,
- });
-
- this.listQualityProfile.push(newQualityProfile);
-
- return this.reply({ profile: newQualityProfile });
- }
- const newQualityProfile = mockQualityProfile({
- name: data.name,
- ...this.languageMapping[data.language],
- key: `qp${this.listQualityProfile.length}`,
- });
-
- this.listQualityProfile.push(newQualityProfile);
-
- return this.reply({ profile: newQualityProfile });
- };
-
- handleSearchRules = (data: SearchRulesQuery): Promise<SearchRulesResponse> => {
- // Special case when we want rule breakdown
- if (data.facets === 'cleanCodeAttributeCategories,impactSoftwareQualities') {
- const activation = data.activation === 'true';
- return this.reply({
- facets: [
- {
- property: 'cleanCodeAttributeCategories',
- values: [
- {
- val: CleanCodeAttributeCategory.Intentional,
- count: activation ? 23 : 27,
- },
- {
- val: CleanCodeAttributeCategory.Consistent,
- count: activation ? 2 : 20,
- },
- {
- val: CleanCodeAttributeCategory.Adaptable,
- count: activation ? 1 : 12,
- },
- {
- val: CleanCodeAttributeCategory.Responsible,
- count: 0,
- },
- ],
- },
- {
- property: 'impactSoftwareQualities',
- values: [
- {
- val: SoftwareQuality.Maintainability,
- count: activation ? 9 : 53,
- },
- {
- val: SoftwareQuality.Reliability,
- count: activation ? 16 : 17,
- },
- {
- val: SoftwareQuality.Security,
- count: activation ? 0 : 14,
- },
- ],
- },
- ],
- rules: [],
- paging: mockPaging(),
- });
- }
- return this.reply(this.searchRulesResponse);
- };
-
- handleListRules = (data: SearchRulesQuery): Promise<SearchRulesResponse> => {
- // Both APIs are mocked the same way, this method is only here to make it explicit.
- return this.handleSearchRules(data);
- };
-
- handleGetQualityProfile = () => {
- return this.reply({
- profile: mockQualityProfile(),
- compareToSonarWay: {
- profile: '',
- profileName: 'Sonar way',
- missingRuleCount: 29,
- },
- });
- };
-
- handleSearchQualityProfiles = (
- parameters: SearchQualityProfilesParameters = {},
- ): Promise<SearchQualityProfilesResponse> => {
- const { language } = parameters;
- let profiles = this.listQualityProfile;
- if (language) {
- profiles = profiles.filter((p) => p.language === language);
- }
- if (this.isAdmin) {
- profiles = profiles.map((p) => ({ ...p, actions: { ...p.actions, copy: true } }));
- }
-
- return this.reply({
- actions: { create: this.isAdmin },
- profiles,
- });
- };
-
- handleActivateRule = (data: {
- key: string;
- params?: Dict<string>;
- reset?: boolean;
- rule: string;
- severity?: string;
- }): Promise<undefined> => {
- this.comparisonResult.inRight = this.comparisonResult.inRight.filter(
- ({ key }) => key !== data.rule,
- );
-
- return this.reply(undefined);
- };
-
- handleDeactivateRule = (data: { key: string; rule: string }) => {
- this.comparisonResult.inLeft = this.comparisonResult.inLeft.filter(
- ({ key }) => key !== data.rule,
- );
-
- return this.reply(undefined);
- };
-
- handleCompareQualityProfiles = (leftKey: string, rightKey: string): Promise<CompareResponse> => {
- const comparedProfiles = this.listQualityProfile.reduce((profiles, profile) => {
- if (profile.key === leftKey || profile.key === rightKey) {
- profiles.push(profile);
- }
- return profiles;
- }, [] as Profile[]);
- const [leftName, rightName] = comparedProfiles.map((profile) => profile.name);
-
- this.comparisonResult.left = { name: leftName };
- this.comparisonResult.right = { name: rightName };
-
- return this.reply(this.comparisonResult);
- };
-
- handleGetRuleDetails = (params: { key: string }): Promise<{ rule: RuleDetails }> => {
- return this.reply({
- rule: mockRuleDetails({
- key: params.key,
- }),
- });
- };
-
- handleRestoreQualityProfile = () => {
- return this.reply({
- profile: {
- key: 'c-sonarsource-06756',
- name: 'SonarSource',
- language: 'c',
- isDefault: false,
- isInherited: false,
- languageName: 'C',
- },
- ruleSuccesses: 231,
- ruleFailures: 0,
- });
- };
-
- handleSearchUsers = () => {
- return this.reply({
- users: [
- mockUserSelected({
- login: 'buzz',
- name: 'Buzz',
- }),
- ],
- paging: mockPaging(),
- });
- };
-
- handleAddUser = () => {
- return this.reply(undefined);
- };
-
- handleRemoveUser = () => {
- return this.reply(undefined);
- };
-
- handleSearchGroups = () => {
- return this.reply({
- groups: [mockGroup({ name: 'ACDC' })],
- paging: mockPaging(),
- });
- };
-
- handleAddGroup = () => {
- return this.reply(undefined);
- };
-
- handleRemoveGroup = () => {
- return this.reply(undefined);
- };
-
- handleAssociateProject = ({ key }: Profile, project: string) => {
- const projects = this.profileProjects[key].map((profileProject) => {
- if (profileProject.key === project) {
- return {
- ...profileProject,
- selected: true,
- };
- }
- return profileProject;
- });
- this.profileProjects[key] = projects;
-
- return this.reply({});
- };
-
- handleDissociateProject = ({ key }: Profile, project: string) => {
- const projects = this.profileProjects[key].map((profileProject) => {
- if (profileProject.key === project) {
- return {
- ...profileProject,
- selected: false,
- };
- }
- return profileProject;
- });
- this.profileProjects[key] = projects;
-
- return this.reply({});
- };
-
- handleGetProfileChangelog: typeof getProfileChangelog = (data) => {
- const {
- profile: { language },
- since,
- to,
- page,
- filterMode = QualityProfileChangelogFilterMode.MQR,
- } = data;
- const PAGE_SIZE = 50;
- const p = page ?? 1;
- const events = this.changelogEvents.filter((event) => {
- if (event.ruleKey.split(':')[0] !== language) {
- return false;
- }
- if (since && new Date(since) >= new Date(event.date)) {
- return false;
- }
- if (to && new Date(to) <= new Date(event.date)) {
- return false;
- }
- if (
- filterMode === QualityProfileChangelogFilterMode.MQR &&
- event.action === 'UPDATED' &&
- event.params &&
- !Object.keys(event.params).includes('impactChanges')
- ) {
- return false;
- }
-
- if (
- filterMode === QualityProfileChangelogFilterMode.STANDARD &&
- event.action === 'UPDATED' &&
- !event.params?.severity
- ) {
- return false;
- }
-
- return true;
- });
-
- return this.reply({
- events: events.slice((p - 1) * PAGE_SIZE, (p - 1) * PAGE_SIZE + PAGE_SIZE),
- paging: mockPaging({
- total: events.length,
- pageSize: PAGE_SIZE,
- pageIndex: p,
- }),
- });
- };
-
- handleGetExporters = () => {
- return this.reply([
- {
- key: 'sonarlint-vs',
- name: 'SonarLint for Visual Studio',
- languages: ['php'],
- },
- {
- key: 'sonarlint-eclipse',
- name: 'SonarLint for Eclipse',
- languages: ['php'],
- },
- ]);
- };
-
- handleDeleteProfile = ({ name }: Profile) => {
- // delete Children
- const qualityProfileToDelete = this.listQualityProfile.find((profile) => profile.name === name);
- this.listQualityProfile = this.listQualityProfile.filter(
- (profile) => profile.parentKey !== qualityProfileToDelete?.key,
- );
-
- // delete profile
- this.listQualityProfile = this.listQualityProfile.filter((profile) => profile.name !== name);
-
- return this.reply({});
- };
-
- handleRenameProfile = (key: string, newName: string) => {
- this.listQualityProfile = this.listQualityProfile.map((profile) => {
- if (profile.key === key) {
- return {
- ...profile,
- name: newName,
- };
- }
- return profile;
- });
- return this.reply({});
- };
-
- handleSetDefaultProfile = ({ name }: Profile) => {
- this.listQualityProfile = this.listQualityProfile.map((profile) => {
- if (profile.name === name) {
- return {
- ...profile,
- isDefault: true,
- };
- }
- return profile;
- });
- return Promise.resolve();
- };
-
- setAdmin() {
- this.isAdmin = true;
- this.resetQualityProfile();
- }
-
- setRulesSearchResponse(overrides: Partial<SearchRulesResponse>) {
- this.searchRulesResponse = {
- ...this.searchRulesResponse,
- ...overrides,
- };
- }
-
- reset() {
- this.isAdmin = false;
- this.resetQualityProfile();
- this.resetComparisonResult();
- this.resetSearchRulesResponse();
- this.resetProfileProjects();
- this.resetChangelogEvents();
- }
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/ScimProvisioningServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/ScimProvisioningServiceMock.ts
deleted file mode 100644
index bf3b2358058..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/ScimProvisioningServiceMock.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { activateScim, deactivateScim, fetchIsScimEnabled } from '../scim-provisioning';
-
-jest.mock('../scim-provisioning');
-
-export default class ScimProvisioningServiceMock {
- scimStatus: boolean;
-
- constructor() {
- this.scimStatus = false;
- jest.mocked(activateScim).mockImplementation(this.handleActivateScim);
- jest.mocked(deactivateScim).mockImplementation(this.handleDeactivateScim);
- jest.mocked(fetchIsScimEnabled).mockImplementation(this.handleFetchIsScimEnabled);
- }
-
- handleActivateScim = () => {
- this.scimStatus = true;
- return Promise.resolve();
- };
-
- handleDeactivateScim = () => {
- this.scimStatus = false;
- return Promise.resolve();
- };
-
- handleFetchIsScimEnabled = () => {
- return Promise.resolve(this.scimStatus);
- };
-
- reset = () => {
- this.scimStatus = false;
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/SecurityHotspotServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/SecurityHotspotServiceMock.ts
deleted file mode 100644
index ecc70a7b852..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/SecurityHotspotServiceMock.ts
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep, times } from 'lodash';
-import {
- mockHotspot,
- mockHotspotComment,
- mockHotspotRule,
- mockRawHotspot,
- mockStandards,
-} from '../../helpers/mocks/security-hotspots';
-import { mockSourceLine } from '../../helpers/mocks/sources';
-import { getStandards } from '../../helpers/security-standard';
-import { mockPaging, mockRestUser } from '../../helpers/testMocks';
-import {
- Hotspot,
- HotspotAssignRequest,
- HotspotComment,
- HotspotResolution,
- HotspotStatus,
-} from '../../types/security-hotspots';
-import { RestUser } from '../../types/users';
-import { getSources } from '../components';
-import { getMeasures } from '../measures';
-import {
- assignSecurityHotspot,
- commentSecurityHotspot,
- deleteSecurityHotspotComment,
- editSecurityHotspotComment,
- getSecurityHotspotDetails,
- getSecurityHotspotList,
- getSecurityHotspots,
- setSecurityHotspotStatus,
-} from '../security-hotspots';
-import { getUsers } from '../users';
-
-const NUMBER_OF_LINES = 20;
-
-export default class SecurityHotspotServiceMock {
- hotspots: Hotspot[] = [];
- nextAssignee: string | undefined;
- canChangeStatus: boolean = true;
- hotspotsComments: HotspotComment[] = [];
-
- constructor() {
- this.reset();
-
- jest.mocked(getMeasures).mockImplementation(this.handleGetMeasures);
- jest.mocked(getSecurityHotspots).mockImplementation(this.handleGetSecurityHotspots);
- jest.mocked(getSecurityHotspotDetails).mockImplementation(this.handleGetSecurityHotspotDetails);
- jest.mocked(getSecurityHotspotList).mockImplementation(this.handleGetSecurityHotspotList);
- jest.mocked(assignSecurityHotspot).mockImplementation(this.handleAssignSecurityHotspot);
- jest.mocked(setSecurityHotspotStatus).mockImplementation(this.handleSetSecurityHotspotStatus);
- jest.mocked(getUsers).mockImplementation((p) => this.handleGetUsers(p));
- jest.mocked(getSources).mockResolvedValue(
- times(NUMBER_OF_LINES, (n) =>
- mockSourceLine({
- line: n,
- code: ' <span class="sym-35 sym">symbole</span>',
- }),
- ),
- );
- jest.mocked(commentSecurityHotspot).mockImplementation(this.handleCommentSecurityHotspot);
- jest
- .mocked(deleteSecurityHotspotComment)
- .mockImplementation(this.handleDeleteSecurityHotspotComment);
- jest
- .mocked(editSecurityHotspotComment)
- .mockImplementation(this.handleEditSecurityHotspotComment);
- jest.mocked(getStandards).mockImplementation(this.handleGetStandards);
- }
-
- handleCommentSecurityHotspot = () => {
- this.hotspotsComments = [
- mockHotspotComment({
- htmlText: 'This is a comment from john doe',
- markdown: 'This is a comment from john doe',
- updatable: true,
- }),
- ];
- return Promise.resolve();
- };
-
- handleDeleteSecurityHotspotComment = () => {
- this.hotspotsComments = [];
- return Promise.resolve();
- };
-
- handleEditSecurityHotspotComment = () => {
- const response = mockHotspotComment({
- htmlText: 'This is a comment from john doe test',
- markdown: 'This is a comment from john doe test',
- updatable: true,
- });
- this.hotspotsComments = [response];
- return Promise.resolve(response);
- };
-
- handleGetStandards = () => {
- return Promise.resolve(mockStandards());
- };
-
- handleSetSecurityHotspotStatus = () => {
- return Promise.resolve();
- };
-
- handleGetUsers: typeof getUsers<RestUser> = () => {
- return this.reply({
- users: [
- mockRestUser({ name: 'User John', login: 'user.john' }),
- mockRestUser({ name: 'User Doe', login: 'user.doe' }),
- mockRestUser({ name: 'User Foo', login: 'user.foo' }),
- ],
- page: mockPaging(),
- });
- };
-
- handleGetSecurityHotspotList = (
- hotspotKeys: string[],
- data: {
- branch?: string;
- project: string;
- },
- ) => {
- if (data?.branch === 'normal-branch') {
- return this.reply({
- paging: mockPaging(),
- hotspots: [
- mockRawHotspot({
- assignee: 'John Doe',
- key: 'b1-test-1',
- message: "'F' is a magic number.",
- }),
- mockRawHotspot({ assignee: 'John Doe', key: 'b1-test-2' }),
- ].filter((h) => hotspotKeys.includes(h.key) || hotspotKeys.length === 0),
- components: [
- {
- key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed:index.php',
- qualifier: 'FIL',
- name: 'index.php',
- longName: 'index.php',
- path: 'index.php',
- },
- {
- key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed',
- qualifier: 'TRK',
- name: 'benflix',
- longName: 'benflix',
- },
- ],
- });
- }
- return this.reply({
- paging: mockPaging(),
- hotspots: this.mockRawHotspots(false).filter(
- (h) => hotspotKeys.includes(h.key) || hotspotKeys.length === 0,
- ),
- components: [
- {
- key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed:index.php',
- qualifier: 'FIL',
- name: 'index.php',
- longName: 'index.php',
- path: 'index.php',
- },
- {
- key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed',
- qualifier: 'TRK',
- name: 'benflix',
- longName: 'benflix',
- },
- ],
- });
- };
-
- handleGetSecurityHotspots = (data: {
- branch?: string;
- inNewCodePeriod?: boolean;
- onlyMine?: boolean;
- p: number;
- project: string;
- ps: number;
- resolution?: HotspotResolution;
- status?: HotspotStatus;
- }) => {
- if (data?.branch === 'normal-branch') {
- return this.reply({
- paging: mockPaging({ pageIndex: 1, pageSize: data.ps, total: 2 }),
- hotspots: [
- mockRawHotspot({
- assignee: 'John Doe',
- key: 'b1-test-1',
- message: "'F' is a magic number.",
- }),
- mockRawHotspot({ assignee: 'John Doe', key: 'b1-test-2' }),
- ],
- components: [
- {
- key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed:index.php',
- qualifier: 'FIL',
- name: 'index.php',
- longName: 'index.php',
- path: 'index.php',
- },
- {
- key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed',
- qualifier: 'TRK',
- name: 'benflix',
- longName: 'benflix',
- },
- ],
- });
- }
-
- return this.reply({
- paging: mockPaging({ pageIndex: 1, pageSize: data.ps, total: this.hotspots.length }),
- hotspots: this.mockRawHotspots(data.onlyMine),
- components: [
- {
- key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed:index.php',
- qualifier: 'FIL',
- name: 'index.php',
- longName: 'index.php',
- path: 'index.php',
- },
- {
- key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed',
- qualifier: 'TRK',
- name: 'benflix',
- longName: 'benflix',
- },
- ],
- });
- };
-
- mockRawHotspots = (onlyMine: boolean | undefined) => {
- if (onlyMine) {
- return [];
- }
- return [
- mockRawHotspot({ assignee: 'John Doe', key: 'test-1' }),
- mockRawHotspot({ assignee: 'John Doe', key: 'test-2' }),
- mockRawHotspot({ assignee: 'John Doe', key: 'test-cve', cveId: 'CVE-2021-12345' }),
- ];
- };
-
- handleGetSecurityHotspotDetails = (securityHotspotKey: string) => {
- const hotspot = this.hotspots.find((h) => h.key === securityHotspotKey);
-
- if (hotspot === undefined) {
- return Promise.reject({
- errors: [{ msg: `No security hotspot for key ${securityHotspotKey}` }],
- });
- }
-
- if (this.nextAssignee !== undefined) {
- hotspot.assigneeUser = {
- ...hotspot.assigneeUser,
- login: this.nextAssignee,
- name: this.nextAssignee,
- };
- this.nextAssignee = undefined;
- }
-
- hotspot.canChangeStatus = this.canChangeStatus;
- hotspot.comment = this.hotspotsComments;
-
- return this.reply(hotspot);
- };
-
- handleGetMeasures = () => {
- return this.reply([
- {
- key: 'guillaume-peoch-sonarsource_benflix_AYGpXq2bd8qy4i0eO9ed',
- name: 'benflix',
- qualifier: 'TRK',
- metric: 'security_hotspots_reviewed',
- measures: [{ metric: 'security_hotspots_reviewed', value: '0.0', bestValue: false }],
- },
- ]);
- };
-
- handleAssignSecurityHotspot = (_: string, data: HotspotAssignRequest) => {
- this.nextAssignee = data.assignee;
- return Promise.resolve();
- };
-
- setHotspotChangeStatusPermission = (value: boolean) => (this.canChangeStatus = value);
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-
- reset = () => {
- this.hotspots = [
- mockHotspot({
- rule: mockHotspotRule({ key: 'rule2' }),
- assignee: 'John Doe',
- key: 'b1-test-1',
- message: "'F' is a magic number.",
- }),
- mockHotspot({
- rule: mockHotspotRule({ key: 'rule2' }),
- assignee: 'John Doe',
- key: 'b1-test-2',
- }),
- mockHotspot({
- rule: mockHotspotRule({ key: 'rule2' }),
- key: 'test-1',
- status: HotspotStatus.TO_REVIEW,
- }),
- mockHotspot({
- rule: mockHotspotRule({ key: 'rule2' }),
- key: 'test-2',
- status: HotspotStatus.TO_REVIEW,
- message: "'2' is a magic number.",
- codeVariants: ['variant 1', 'variant 2'],
- }),
- mockHotspot({
- rule: mockHotspotRule({ key: 'rule2' }),
- key: 'test-cve',
- status: HotspotStatus.TO_REVIEW,
- message: 'CVE on jackson',
- cveId: 'CVE-2021-12345',
- }),
- ];
- this.canChangeStatus = true;
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts
deleted file mode 100644
index 505406295e5..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep, isArray, isObject, isString } from 'lodash';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { HousekeepingPolicy } from '../../apps/audit-logs/utils';
-import { mockDefinition, mockSettingFieldDefinition } from '../../helpers/mocks/settings';
-import { isDefined } from '../../helpers/types';
-import {
- ExtendedSettingDefinition,
- SettingDefinition,
- SettingType,
- SettingValue,
- SettingsKey,
-} from '../../types/settings';
-import { Dict } from '../../types/types';
-import {
- checkSecretKey,
- encryptValue,
- generateSecretKey,
- getAllValues,
- getDefinitions,
- getValue,
- getValues,
- resetSettingValue,
- setSettingValue,
- setSimpleSettingValue,
-} from '../settings';
-
-jest.mock('../settings');
-
-const isEmptyField = (o: any) => isObject(o) && Object.values(o).some(isEmptyString);
-const isEmptyString = (i: any) => isString(i) && i.trim() === '';
-
-export const DEFAULT_DEFINITIONS_MOCK = [
- mockDefinition({
- category: 'general',
- key: 'sonar.announcement.message',
- subCategory: 'Announcement',
- name: 'Announcement message',
- description: 'Enter message',
- type: SettingType.TEXT,
- }),
- mockDefinition({
- category: 'general',
- key: 'sonar.ce.parallelProjectTasks',
- subCategory: 'Compute Engine',
- name: 'Run analysis in paralel',
- description: 'Enter message',
- type: SettingType.TEXT,
- }),
- mockDefinition({
- category: 'javascript',
- key: 'sonar.javascript.globals',
- subCategory: 'General',
- name: 'Global Variables',
- description: 'List of Global variables',
- multiValues: true,
- defaultValue: 'angular,google,d3',
- }),
- mockDefinition({
- category: 'javascript',
- key: 'sonar.javascript.file.suffixes',
- subCategory: 'General',
- name: 'JavaScript File Suffixes',
- description: 'List of suffixes for files to analyze',
- multiValues: true,
- defaultValue: '.js,.jsx,.cjs,.vue,.mjs',
- }),
- mockDefinition({
- category: 'External Analyzers',
- key: 'sonar.androidLint.reportPaths',
- subCategory: 'Android',
- name: 'Android Lint Report Files',
- description: 'Paths to xml files',
- multiValues: true,
- }),
- mockDefinition({
- category: 'COBOL',
- key: 'sonar.cobol.compilationConstants',
- subCategory: 'Preprocessor',
- name: 'Compilation Constants',
- description: 'Lets do it',
- type: SettingType.PROPERTY_SET,
- fields: [
- mockSettingFieldDefinition(),
- mockSettingFieldDefinition({ key: 'value', name: 'Value' }),
- ],
- }),
- mockDefinition({
- category: 'authentication',
- defaultValue: 'true',
- key: 'sonar.auth.github.allowUsersToSignUp',
- subCategory: 'github',
- name: 'Compilation Constants',
- description: 'Lets do it',
- type: SettingType.BOOLEAN,
- }),
- mockDefinition({
- category: 'authentication',
- defaultValue: 'false',
- key: 'provisioning.github.project.visibility.enabled',
- subCategory: 'github',
- name: 'Compilation Constants',
- description: 'Lets do it',
- type: SettingType.BOOLEAN,
- }),
- mockDefinition({
- category: 'Mode',
- defaultValue: 'true',
- key: 'sonar.multi-quality-mode.enabled',
- name: 'Enable Multi-Quality Rule Mode',
- options: [],
- subCategory: 'Mode',
- type: SettingType.BOOLEAN,
- }),
-];
-
-export default class SettingsServiceMock {
- #defaultValues: SettingValue[] = [
- {
- key: SettingsKey.AuditHouseKeeping,
- value: HousekeepingPolicy.Weekly,
- },
- {
- key: 'sonar.javascript.globals',
- values: ['angular', 'google', 'd3'],
- },
- {
- key: SettingsKey.QPAdminCanDisableInheritedRules,
- value: 'true',
- },
- ];
-
- #settingValues: SettingValue[] = cloneDeep(this.#defaultValues);
-
- #definitions: ExtendedSettingDefinition[] = cloneDeep(DEFAULT_DEFINITIONS_MOCK);
-
- #secretKeyAvailable: boolean = false;
-
- constructor() {
- jest.mocked(getDefinitions).mockImplementation(this.handleGetDefinitions);
- jest.mocked(getValue).mockImplementation(this.handleGetValue);
- jest.mocked(getValues).mockImplementation(this.handleGetValues);
- jest.mocked(getAllValues).mockImplementation(this.handleGetAllValues);
- jest.mocked(setSettingValue).mockImplementation(this.handleSetSettingValue);
- jest.mocked(setSimpleSettingValue).mockImplementation(this.handleSetSimpleSettingValue);
- jest.mocked(resetSettingValue).mockImplementation(this.handleResetSettingValue);
- jest.mocked(checkSecretKey).mockImplementation(this.handleCheckSecretKey);
- jest.mocked(generateSecretKey).mockImplementation(this.handleGenerateSecretKey);
- jest.mocked(encryptValue).mockImplementation(this.handleEcnryptValue);
- }
-
- handleGetValue = (data: { component?: string; key: string } & BranchParameters) => {
- const setting = this.#settingValues.find((s) => s.key === data.key) as SettingValue;
- const definition = this.#definitions.find(
- (d) => d.key === data.key,
- ) as ExtendedSettingDefinition;
- if (!setting && definition?.defaultValue !== undefined) {
- const fields = definition.multiValues
- ? { values: definition.defaultValue?.split(',') }
- : { value: definition.defaultValue };
- return this.reply({ key: data.key, ...fields });
- }
- return this.reply(setting ?? undefined);
- };
-
- handleGetValues = (data: { component?: string; keys: string[] } & BranchParameters) => {
- const settings = data.keys
- .map((k) => {
- const def = this.#definitions.find((d) => d.key === k);
- const v = this.#settingValues.find((s) => s.key === k);
- if (v === undefined && def?.type === SettingType.BOOLEAN) {
- return { key: k, value: def.defaultValue, inherited: true };
- }
- return v;
- })
- .filter(isDefined);
-
- return this.reply(settings);
- };
-
- handleGetAllValues = () => {
- return this.reply(this.#settingValues);
- };
-
- handleGetDefinitions = () => {
- return this.reply(this.#definitions);
- };
-
- handleSetSettingValue = (definition: SettingDefinition, value: any): Promise<void> => {
- if (
- isEmptyString(value) ||
- (isArray(value) && value.some(isEmptyString)) ||
- isEmptyField(value)
- ) {
- throw new ResponseError('validation error', {
- errors: [{ msg: 'A non empty value must be provided' }],
- });
- }
-
- this.set(definition.key, value);
- const def = this.#definitions.find((d) => d.key === definition.key);
- if (def === undefined) {
- this.#definitions.push(definition as ExtendedSettingDefinition);
- }
-
- return this.reply(undefined);
- };
-
- handleResetSettingValue = (data: { component?: string; keys: string } & BranchParameters) => {
- const setting = this.#settingValues.find((s) => s.key === data.keys) as SettingValue;
- const definition = this.#definitions.find(
- (d) => d.key === data.keys,
- ) as ExtendedSettingDefinition;
- if (data.keys === 'sonar.auth.github.userConsentForPermissionProvisioningRequired') {
- this.#settingValues = this.#settingValues.filter(
- (s) => s.key !== 'sonar.auth.github.userConsentForPermissionProvisioningRequired',
- );
- } else if (data.keys === 'sonar.auth.gitlab.userConsentForPermissionProvisioningRequired') {
- this.#settingValues = this.#settingValues.filter(
- (s) => s.key !== 'sonar.auth.gitlab.userConsentForPermissionProvisioningRequired',
- );
- } else if (definition.type === SettingType.PROPERTY_SET) {
- const fieldValues: Dict<string>[] = [];
- if (setting) {
- setting.fieldValues = fieldValues;
- } else {
- this.#settingValues.push({ key: data.keys, fieldValues });
- }
- } else if (definition.multiValues === true) {
- const values = definition.defaultValue?.split(',') ?? [];
- if (setting) {
- setting.values = values;
- } else {
- this.#settingValues.push({ key: data.keys, values });
- }
- } else {
- const value = definition.defaultValue ?? '';
- if (setting) {
- setting.value = value;
- } else {
- this.#settingValues.push({ key: data.keys, value });
- }
- }
-
- return this.reply(undefined);
- };
-
- emptySettings = () => {
- this.#settingValues = [];
- return this;
- };
-
- set = (key: string | SettingsKey, value: any) => {
- const setting = this.#settingValues.find((s) => s.key === key);
- if (setting) {
- setting.value = String(value);
- setting.values = value;
- setting.fieldValues = value;
- } else {
- this.#settingValues.push({ key, value: String(value), values: value, fieldValues: value });
- }
- return this;
- };
-
- setDefinition = (definition: ExtendedSettingDefinition) => {
- this.#definitions.push(definition);
- };
-
- setDefinitions = (definitions: ExtendedSettingDefinition[]) => {
- this.#definitions = definitions;
- };
-
- handleCheckSecretKey = () => {
- return this.reply({ secretKeyAvailable: this.#secretKeyAvailable });
- };
-
- handleGenerateSecretKey = () => {
- return this.reply({ secretKey: 'secretKey' });
- };
-
- handleEcnryptValue = () => {
- return this.reply({ encryptedValue: 'encryptedValue' });
- };
-
- handleSetSimpleSettingValue: typeof setSimpleSettingValue = (data) => {
- this.set(data.key, data.value);
- return this.reply(undefined);
- };
-
- setSecretKeyAvailable = (val = false) => {
- this.#secretKeyAvailable = val;
- };
-
- reset = () => {
- this.#settingValues = cloneDeep(this.#defaultValues);
- this.#definitions = cloneDeep(DEFAULT_DEFINITIONS_MOCK);
- this.#secretKeyAvailable = false;
- return this;
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
-
-class ResponseError extends Error {
- #response: any;
- constructor(name: string, response: any) {
- super(name);
- this.#response = response;
- }
-
- json = () => Promise.resolve(this.#response);
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/SourcesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/SourcesServiceMock.ts
deleted file mode 100644
index 7a053b22594..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/SourcesServiceMock.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { getRawSource } from '../sources';
-import { mockIpynbFile } from './data/sources';
-
-jest.mock('../sources');
-
-export default class SourcesServiceMock {
- private source: string;
-
- constructor() {
- this.source = mockIpynbFile;
-
- jest.mocked(getRawSource).mockImplementation(this.handleGetRawSource);
- }
-
- setSource(source: string) {
- this.source = source;
- }
-
- handleGetRawSource = () => {
- return this.reply(this.source);
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-
- reset = () => {
- this.source = mockIpynbFile;
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/SystemServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/SystemServiceMock.ts
deleted file mode 100644
index 6ee53bb29c8..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/SystemServiceMock.ts
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep, uniqueId } from 'lodash';
-import { Provider, SysInfoCluster, SysInfoLogging, SysInfoStandalone } from '../../types/types';
-
-import { LogsLevels } from '../../apps/system/utils';
-import { mockEmailConfiguration } from '../../helpers/mocks/system';
-import {
- mockClusterSysInfo,
- mockLogs,
- mockPaging,
- mockStandaloneSysInfo,
-} from '../../helpers/testMocks';
-import { EmailConfiguration } from '../../types/system';
-import {
- getEmailConfigurations,
- getSystemInfo,
- getSystemUpgrades,
- patchEmailConfiguration,
- postEmailConfiguration,
- setLogLevel,
-} from '../system';
-
-jest.mock('../system');
-
-type SystemUpgrades = {
- installedVersionActive: boolean;
- latestLTA: string;
- updateCenterRefresh: string;
- upgrades: [];
-};
-
-export default class SystemServiceMock {
- isCluster: boolean = false;
- logging: SysInfoLogging = mockLogs();
- systemInfo: SysInfoCluster | SysInfoStandalone = mockStandaloneSysInfo();
- systemUpgrades: SystemUpgrades = {
- upgrades: [],
- latestLTA: '7.9',
- updateCenterRefresh: '2021-09-01',
- installedVersionActive: true,
- };
-
- emailConfigurations: EmailConfiguration[] = [];
-
- constructor() {
- this.updateSystemInfo();
- jest.mocked(getSystemInfo).mockImplementation(this.handleGetSystemInfo);
- jest.mocked(setLogLevel).mockImplementation(this.handleSetLogLevel);
- jest.mocked(getSystemUpgrades).mockImplementation(this.handleGetSystemUpgrades);
- jest.mocked(getEmailConfigurations).mockImplementation(this.handleGetEmailConfigurations);
- jest.mocked(postEmailConfiguration).mockImplementation(this.handlePostEmailConfiguration);
- jest.mocked(patchEmailConfiguration).mockImplementation(this.handlePatchEmailConfiguration);
- }
-
- handleGetSystemInfo = () => {
- return this.reply(this.systemInfo);
- };
-
- handleGetSystemUpgrades = () => {
- return this.reply(this.systemUpgrades);
- };
-
- setSystemUpgrades(systemUpgrades: Partial<SystemUpgrades>) {
- this.systemUpgrades = {
- ...this.systemUpgrades,
- ...systemUpgrades,
- };
- }
-
- setProvider(provider: Provider | null) {
- this.systemInfo = mockStandaloneSysInfo({
- ...this.systemInfo,
- System: {
- ...this.systemInfo.System,
- ...(provider ? { 'External Users and Groups Provisioning': provider } : {}),
- },
- });
- }
-
- handleSetLogLevel = (logsLevel: LogsLevels) => {
- this.logging = mockLogs(logsLevel);
- this.updateSystemInfo();
-
- return this.reply(undefined);
- };
-
- updateSystemInfo = () => {
- const logs = {
- 'Web Logging': this.logging,
- 'Compute Engine Logging': this.logging,
- };
-
- this.systemInfo = this.isCluster ? mockClusterSysInfo(logs) : mockStandaloneSysInfo(logs);
- };
-
- setIsCluster = (isCluster: boolean = false) => {
- this.isCluster = isCluster;
- this.updateSystemInfo();
- };
-
- handleGetEmailConfigurations: typeof getEmailConfigurations = () => {
- return this.reply({
- emailConfigurations: this.emailConfigurations,
- page: mockPaging({ total: this.emailConfigurations.length }),
- });
- };
-
- handlePostEmailConfiguration: typeof postEmailConfiguration = (configuration) => {
- const returnVal = mockEmailConfiguration(configuration.authMethod, {
- ...configuration,
- id: uniqueId('email-configuration-'),
- });
-
- this.emailConfigurations.push(returnVal);
- return this.reply(returnVal);
- };
-
- handlePatchEmailConfiguration: typeof patchEmailConfiguration = (id, configuration) => {
- const index = this.emailConfigurations.findIndex((c) => c.id === id);
- this.emailConfigurations[index] = mockEmailConfiguration(configuration.authMethod, {
- ...this.emailConfigurations[index],
- ...configuration,
- });
- return this.reply(this.emailConfigurations[index]);
- };
-
- addEmailConfiguration = (configuration: EmailConfiguration) => {
- this.emailConfigurations.push(configuration);
- };
-
- reset = () => {
- this.logging = mockLogs();
- this.setIsCluster(false);
- this.updateSystemInfo();
- this.emailConfigurations = [];
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/TimeMachineServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/TimeMachineServiceMock.ts
deleted file mode 100644
index 8b5f501a4e1..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/TimeMachineServiceMock.ts
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { chunk, cloneDeep, times } from 'lodash';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { parseDate } from '../../helpers/dates';
-import { mockHistoryItem, mockMeasureHistory } from '../../helpers/mocks/project-activity';
-import { MeasureHistory } from '../../types/project-activity';
-import { TimeMachineResponse, getAllTimeMachineData, getTimeMachineData } from '../time-machine';
-
-jest.mock('../time-machine');
-
-const PAGE_SIZE = 10;
-const DEFAULT_PAGE = 0;
-const HISTORY_COUNT = 10;
-const START_DATE = '2016-01-01T00:00:00.000Z';
-
-const defaultMeasureHistory = [
- MetricKey.bugs,
- MetricKey.code_smells,
- MetricKey.confirmed_issues,
- MetricKey.vulnerabilities,
- MetricKey.blocker_violations,
- MetricKey.lines_to_cover,
- MetricKey.uncovered_lines,
- MetricKey.security_hotspots_reviewed,
- MetricKey.coverage,
- MetricKey.duplicated_lines_density,
- MetricKey.test_success_density,
-].map((metric) => {
- return mockMeasureHistory({
- metric,
- history: times(HISTORY_COUNT, (i) => {
- const date = parseDate(START_DATE);
- date.setDate(date.getDate() + i);
- return mockHistoryItem({ value: i.toString(), date });
- }),
- });
-});
-
-export class TimeMachineServiceMock {
- #measureHistory: MeasureHistory[];
- toISO = false;
-
- constructor() {
- this.#measureHistory = cloneDeep(defaultMeasureHistory);
-
- jest.mocked(getTimeMachineData).mockImplementation(this.handleGetTimeMachineData);
- jest.mocked(getAllTimeMachineData).mockImplementation(this.handleGetAllTimeMachineData);
- }
-
- handleGetTimeMachineData = (
- data: {
- component: string;
- from?: string;
- metrics: string;
- p?: number;
- ps?: number;
- to?: string;
- } & BranchParameters,
- ) => {
- const { ps = PAGE_SIZE, p = DEFAULT_PAGE } = data;
-
- const measureHistoryChunked = chunk(this.#measureHistory, ps);
-
- return this.reply({
- paging: { pageSize: ps, total: this.#measureHistory.length, pageIndex: p },
- measures: measureHistoryChunked[p - 1] ? this.map(measureHistoryChunked[p - 1]) : [],
- });
- };
-
- handleGetAllTimeMachineData = (
- data: {
- component: string;
- from?: string;
- metrics: string;
- p?: number;
- to?: string;
- } & BranchParameters,
- _prev?: TimeMachineResponse,
- ) => {
- const { p = DEFAULT_PAGE } = data;
- return this.reply({
- paging: { pageSize: PAGE_SIZE, total: this.#measureHistory.length, pageIndex: p },
- measures: this.map(this.#measureHistory),
- });
- };
-
- setMeasureHistory = (list: MeasureHistory[]) => {
- this.#measureHistory = list;
- };
-
- map = (list: MeasureHistory[]) => {
- return list.map((item) => ({
- ...item,
- history: item.history.map((h) => ({
- ...h,
- date: this.toISO ? h.date.toISOString() : h.date.toDateString(),
- })),
- }));
- };
-
- reset = () => {
- this.#measureHistory = cloneDeep(defaultMeasureHistory);
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/UserTokensMock.ts b/server/sonar-web/src/main/js/api/mocks/UserTokensMock.ts
deleted file mode 100644
index a59e468f35e..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/UserTokensMock.ts
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep, last } from 'lodash';
-import { mockUserToken } from '../../helpers/mocks/token';
-import { NewUserToken, TokenType, UserToken } from '../../types/token';
-import { generateToken, getTokens, revokeToken } from '../user-tokens';
-
-jest.mock('../../api/user-tokens');
-
-const defaultTokens = [
- mockUserToken({
- name: 'local-scanner',
- createdAt: '2022-03-07T09:02:59+0000',
- lastConnectionDate: '2022-04-07T09:51:48+0000',
- }),
- mockUserToken({
- name: 'test',
- createdAt: '2020-01-23T19:25:19+0000',
- }),
-];
-
-export default class UserTokensMock {
- tokens: Array<Partial<NewUserToken> & UserToken>;
- failGeneration = false;
-
- constructor() {
- this.tokens = cloneDeep(defaultTokens);
-
- jest.mocked(getTokens).mockImplementation(this.handleGetTokens);
- jest.mocked(generateToken).mockImplementation(this.handleGenerateToken);
- jest.mocked(revokeToken).mockImplementation(this.handleRevokeToken);
- }
-
- handleGetTokens = () => {
- return Promise.resolve(cloneDeep(this.tokens));
- };
-
- handleGenerateToken = ({
- name,
- login,
- type,
- projectKey,
- expirationDate,
- }: {
- expirationDate?: string;
- login: string;
- name: string;
- projectKey: string;
- type: TokenType;
- }) => {
- if (this.failGeneration) {
- this.failGeneration = false;
- return Promise.reject('x_x');
- }
-
- if (this.tokens.some((t) => t.name === name)) {
- return Promise.reject('This name is already used');
- }
-
- const token = {
- name,
- login,
- type,
- projectKey,
- isExpired: false,
- token: `generatedtoken${this.tokens.length}`,
- createdAt: '2022-04-04T04:04:04+0000',
- expirationDate,
- };
-
- this.tokens.push(token);
-
- return Promise.resolve(token);
- };
-
- handleRevokeToken = ({ name }: { login?: string; name: string }) => {
- this.tokens = this.tokens.filter((t) => t.name !== name);
-
- return Promise.resolve();
- };
-
- failNextTokenGeneration = () => {
- this.failGeneration = true;
- };
-
- getTokens = () => {
- return cloneDeep(this.tokens);
- };
-
- getLastToken = () => {
- return last(this.getTokens());
- };
-
- reset = () => {
- this.tokens = cloneDeep(defaultTokens);
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/UsersServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/UsersServiceMock.ts
deleted file mode 100644
index 1a3614476f0..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/UsersServiceMock.ts
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { isAfter, isBefore } from 'date-fns';
-import { cloneDeep, isEmpty, isUndefined, omitBy } from 'lodash';
-import { HttpStatus } from '../../helpers/request';
-import { mockIdentityProvider, mockLoggedInUser, mockRestUser } from '../../helpers/testMocks';
-import { IdentityProvider } from '../../types/types';
-import {
- ChangePasswordResults,
- LoggedInUser,
- NoticeType,
- RestUserDetailed,
-} from '../../types/users';
-import {
- changePassword,
- deleteUser,
- dismissNotice,
- getCurrentUser,
- getIdentityProviders,
- getUsers,
- postUser,
- updateUser,
-} from '../users';
-import GroupMembershipsServiceMock from './GroupMembersipsServiceMock';
-
-jest.mock('../users');
-
-const DEFAULT_USERS = [
- mockRestUser({
- managed: true,
- login: 'bob.marley',
- name: 'Bob Marley',
- sonarQubeLastConnectionDate: '2023-06-27T17:08:59+0200',
- sonarLintLastConnectionDate: '2023-06-27T17:08:59+0200',
- id: '1',
- }),
- mockRestUser({
- managed: false,
- login: 'alice.merveille',
- name: 'Alice Merveille',
- sonarQubeLastConnectionDate: '2023-06-27T17:08:59+0200',
- sonarLintLastConnectionDate: '2023-05-27T17:08:59+0200',
- email: 'alice.merveille@wonderland.com',
- id: '2',
- }),
- mockRestUser({
- managed: false,
- local: false,
- login: 'charlie.cox',
- name: 'Charlie Cox',
- sonarQubeLastConnectionDate: '2023-06-25T17:08:59+0200',
- sonarLintLastConnectionDate: '2023-06-20T12:10:59+0200',
- externalProvider: 'test',
- externalLogin: 'ExternalTest',
- id: '3',
- }),
- mockRestUser({
- managed: true,
- local: false,
- externalProvider: 'test2',
- externalLogin: 'UnknownExternalProvider',
- login: 'denis.villeneuve',
- name: 'Denis Villeneuve',
- sonarQubeLastConnectionDate: '2023-06-20T15:08:59+0200',
- sonarLintLastConnectionDate: '2023-05-25T10:08:59+0200',
- id: '4',
- }),
- mockRestUser({
- managed: true,
- login: 'eva.green',
- name: 'Eva Green',
- sonarQubeLastConnectionDate: '2023-05-27T17:08:59+0200',
- id: '5',
- }),
- mockRestUser({
- managed: false,
- login: 'franck.grillo',
- name: 'Franck Grillo',
- id: '6',
- }),
-];
-
-const DEFAULT_PASSWORD = 'test';
-
-export default class UsersServiceMock {
- isManaged = true;
- users = cloneDeep(DEFAULT_USERS);
- currentUser = mockLoggedInUser();
- password = DEFAULT_PASSWORD;
- groupMembershipsServiceMock?: GroupMembershipsServiceMock = undefined;
- constructor(groupMembershipsServiceMock?: GroupMembershipsServiceMock) {
- this.groupMembershipsServiceMock = groupMembershipsServiceMock;
- jest.mocked(getIdentityProviders).mockImplementation(this.handleGetIdentityProviders);
- jest.mocked(getUsers).mockImplementation(this.handleGetUsers);
- jest.mocked(postUser).mockImplementation(this.handlePostUser);
- jest.mocked(updateUser).mockImplementation(this.handleUpdateUser);
- jest.mocked(changePassword).mockImplementation(this.handleChangePassword);
- jest.mocked(deleteUser).mockImplementation(this.handleDeactivateUser);
- jest.mocked(dismissNotice).mockImplementation(this.handleDismissNotification);
- jest.mocked(getCurrentUser).mockImplementation(this.handleGetCurrentUser);
- }
-
- getFilteredRestUsers = (filterParams: Parameters<typeof getUsers>[0]) => {
- const {
- managed,
- q,
- sonarQubeLastConnectionDateFrom,
- sonarQubeLastConnectionDateTo,
- sonarLintLastConnectionDateFrom,
- sonarLintLastConnectionDateTo,
- groupId,
- 'groupId!': groupIdExclude,
- } = filterParams;
- let { users } = this;
- if (groupId || groupIdExclude) {
- if (!this.groupMembershipsServiceMock) {
- throw new Error(
- 'groupMembershipsServiceMock is not defined. Please provide GroupMembershipsServiceMock to UsersServiceMock constructor',
- );
- }
- const groupMemberships = this.groupMembershipsServiceMock?.memberships.filter(
- (m) => m.groupId === (groupId ?? groupIdExclude),
- );
- const userIds = groupMemberships?.map((m) => m.userId);
- users = users.filter((u) => (groupId ? userIds?.includes(u.id) : !userIds?.includes(u.id)));
- }
-
- return users.filter((user) => {
- if (this.isManaged && managed !== undefined && user.managed !== managed) {
- return false;
- }
-
- if (q && !user.login.includes(q) && !user.name?.includes(q) && !user.email?.includes(q)) {
- return false;
- }
-
- if (
- sonarQubeLastConnectionDateFrom &&
- (user.sonarQubeLastConnectionDate === null ||
- isBefore(
- new Date(user.sonarQubeLastConnectionDate),
- new Date(sonarQubeLastConnectionDateFrom),
- ))
- ) {
- return false;
- }
-
- if (
- sonarQubeLastConnectionDateTo &&
- user.sonarQubeLastConnectionDate &&
- isAfter(new Date(user.sonarQubeLastConnectionDate), new Date(sonarQubeLastConnectionDateTo))
- ) {
- return false;
- }
-
- if (
- sonarLintLastConnectionDateFrom &&
- (user.sonarLintLastConnectionDate === null ||
- isBefore(
- new Date(user.sonarLintLastConnectionDate),
- new Date(sonarLintLastConnectionDateFrom),
- ))
- ) {
- return false;
- }
-
- if (
- sonarLintLastConnectionDateTo &&
- user.sonarLintLastConnectionDate &&
- isAfter(new Date(user.sonarLintLastConnectionDate), new Date(sonarLintLastConnectionDateTo))
- ) {
- return false;
- }
-
- return true;
- });
- };
-
- handleGetUsers: typeof getUsers<RestUserDetailed> = (data) => {
- const pageIndex = data.pageIndex ?? 1;
- const pageSize = data.pageSize ?? 10;
-
- const users = this.getFilteredRestUsers(data);
-
- return this.reply({
- page: {
- pageIndex,
- pageSize,
- total: users.length,
- },
- users: users.slice((pageIndex - 1) * pageSize, pageIndex * pageSize),
- });
- };
-
- handlePostUser = (data: {
- email?: string;
- local?: boolean;
- login: string;
- name: string;
- password?: string;
- scmAccounts: string[];
- }) => {
- const { email, local, login, name, scmAccounts } = data;
- if (scmAccounts.some((a) => isEmpty(a.trim()))) {
- return Promise.reject({
- response: {
- status: HttpStatus.BadRequest,
- data: { message: 'Error: Empty SCM' },
- },
- });
- }
- const newUser = mockRestUser({
- email,
- local,
- login,
- name,
- scmAccounts,
- });
- this.users.push(newUser);
- return this.reply(newUser);
- };
-
- handleUpdateUser: typeof updateUser = (id, data) => {
- const { email, name, scmAccounts } = data;
- const user = this.users.find((u) => u.id === id);
- if (!user) {
- return Promise.reject('No such user');
- }
- Object.assign(user, {
- ...omitBy({ name, email, scmAccounts }, isUndefined),
- });
- return this.reply(user);
- };
-
- handleGetIdentityProviders = (): Promise<{ identityProviders: IdentityProvider[] }> => {
- return this.reply({
- identityProviders: [mockIdentityProvider({ key: 'test' })],
- });
- };
-
- handleChangePassword: typeof changePassword = (data) => {
- if (data.previousPassword !== this.password) {
- return Promise.reject(ChangePasswordResults.OldPasswordIncorrect);
- }
- if (data.password === this.password) {
- return Promise.reject(ChangePasswordResults.NewPasswordSameAsOld);
- }
- this.password = data.password;
- return this.reply({});
- };
-
- handleDeactivateUser: typeof deleteUser = (data) => {
- const index = this.users.findIndex((u) => u.id === data.id);
- const user = this.users.splice(index, 1)[0];
- user.active = false;
- return this.reply(undefined);
- };
-
- handleDismissNotification: typeof dismissNotice = (noticeType: NoticeType) => {
- if (Object.values(NoticeType).includes(noticeType)) {
- return this.reply(true);
- }
-
- return Promise.reject();
- };
-
- setCurrentUser = (user: LoggedInUser) => {
- this.currentUser = user;
- };
-
- handleGetCurrentUser: typeof getCurrentUser = () => {
- return this.reply(this.currentUser);
- };
-
- reset = () => {
- this.isManaged = true;
- this.users = cloneDeep(DEFAULT_USERS);
- this.password = DEFAULT_PASSWORD;
- this.currentUser = mockLoggedInUser();
- };
-
- reply<T>(response: T): Promise<T> {
- return Promise.resolve(cloneDeep(response));
- }
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/WebApiServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/WebApiServiceMock.ts
deleted file mode 100644
index b2ea2630e11..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/WebApiServiceMock.ts
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { OpenAPIV3 } from 'openapi-types';
-import { mockAction } from '../../helpers/mocks/webapi';
-import { MetricKey } from '../../sonar-aligned/types/metrics';
-import { fetchOpenAPI, fetchWebApi } from '../web-api';
-import { openApiTestData } from './data/web-api';
-
-jest.mock('../web-api');
-
-const BASE_DOMAINS = [
- {
- actions: [
- mockAction(),
- mockAction({ key: 'memos', description: 'get normal memos' }),
- mockAction({
- key: 'deprecated',
- description: 'deprecated action',
- deprecatedSince: '2012-07-23',
- }),
- ],
- description: 'foo',
- internal: false,
- path: 'foo/bar',
- since: '1.0',
- },
- {
- actions: [mockAction({ key: 'ia', description: 'get internal memos', internal: true })],
- description: 'internal stuff',
- internal: false,
- path: 'internal/thing1',
- since: '1.3',
- },
- {
- path: 'api/project_badges',
- actions: [
- mockAction({
- key: 'measure',
- params: [
- {
- key: 'metric',
- description: 'Badge Metric key',
- required: true,
- internal: false,
- possibleValues: [
- MetricKey.bugs,
- MetricKey.software_quality_reliability_issues,
- MetricKey.code_smells,
- MetricKey.software_quality_maintainability_issues,
- MetricKey.vulnerabilities,
- MetricKey.software_quality_security_issues,
- MetricKey.sqale_rating,
- MetricKey.software_quality_maintainability_rating,
- MetricKey.security_rating,
- MetricKey.software_quality_security_rating,
- MetricKey.reliability_rating,
- MetricKey.software_quality_reliability_rating,
- MetricKey.coverage,
- MetricKey.duplicated_lines_density,
- MetricKey.alert_status,
- MetricKey.security_hotspots,
- MetricKey.ncloc,
- ],
- },
- ],
- }),
- ],
- description: 'Badges API',
- internal: false,
- since: '1.3',
- },
-];
-
-export default class WebApiServiceMock {
- openApiDocument: OpenAPIV3.Document;
- domains;
-
- constructor() {
- this.openApiDocument = cloneDeep(openApiTestData);
- this.domains = cloneDeep(BASE_DOMAINS);
-
- jest.mocked(fetchOpenAPI).mockImplementation(this.handleFetchOpenAPI);
- jest.mocked(fetchWebApi).mockImplementation(this.handleFetchWebAPI);
- }
-
- handleFetchOpenAPI: typeof fetchOpenAPI = () => {
- return Promise.resolve(this.openApiDocument);
- };
-
- handleFetchWebAPI = () => {
- return Promise.resolve(this.domains);
- };
-
- reset = () => {
- this.openApiDocument = cloneDeep(openApiTestData);
- this.domains = cloneDeep(BASE_DOMAINS);
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/WebhooksMock.ts b/server/sonar-web/src/main/js/api/mocks/WebhooksMock.ts
deleted file mode 100644
index 2495cefc089..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/WebhooksMock.ts
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- createWebhook,
- deleteWebhook,
- getDelivery,
- searchDeliveries,
- searchWebhooks,
- updateWebhook,
-} from '../../api/webhooks';
-import { mockWebhook } from '../../helpers/mocks/webhook';
-import { mockPaging } from '../../helpers/testMocks';
-import {
- WebhookCreatePayload,
- WebhookResponse,
- WebhookSearchDeliveriesPayload,
- WebhookUpdatePayload,
-} from '../../types/webhook';
-import { deliveries, mockFullWebhookDeliveries, mockFullWebhookList } from './data/webhooks';
-
-jest.mock('../../api/webhooks');
-
-export default class WebhooksMock {
- static readonly DEFAULT_PAGE_SIZE = 10;
-
- project?: string;
- webhooks: Array<WebhookResponse>;
-
- constructor(project?: string) {
- this.project = project;
- this.webhooks = mockFullWebhookList(project);
-
- jest.mocked(createWebhook).mockImplementation(this.handleCreateWebhook);
- jest.mocked(searchWebhooks).mockImplementation(this.handleSearchWebhooks);
- jest.mocked(updateWebhook).mockImplementation(this.handleUpdateWebhook);
- jest.mocked(deleteWebhook).mockImplementation(this.handleDeleteWebhook);
- jest.mocked(searchDeliveries).mockImplementation(this.handleSearchDeliveries);
- jest.mocked(getDelivery).mockImplementation(this.handleGetDelivery);
- }
-
- reset = (project?: string) => {
- this.project = project;
- this.webhooks = mockFullWebhookList(project);
- };
-
- response = <T>(data: T): Promise<T> => {
- return Promise.resolve(data);
- };
-
- addWebhook = (...webhooks: WebhookResponse[]) => {
- this.webhooks.push(...webhooks);
- };
-
- handleCreateWebhook = (data: WebhookCreatePayload) => {
- const webhook = mockWebhook({
- name: data.name,
- url: data.url,
- hasSecret: Boolean(data.secret),
- });
- return this.response({
- webhook,
- });
- };
-
- handleSearchWebhooks = ({ project }: { project?: string }) => {
- if (project !== this.project) {
- throw new Error(
- 'You are asking for webhooks of a project that is not mocked. Reset first the mock with the correct project',
- );
- }
- return this.response({
- webhooks: this.webhooks,
- });
- };
-
- handleUpdateWebhook = (data: WebhookUpdatePayload) => {
- const webhook = this.webhooks.find((webhook) => webhook.key === data.webhook);
- if (!webhook) {
- return Promise.reject(new Error('Webhook not found'));
- }
- webhook.hasSecret = Boolean(data.secret);
- webhook.name = data.name;
- webhook.url = data.url;
- return this.response(undefined);
- };
-
- handleDeleteWebhook = ({ webhook }: { webhook: string }) => {
- const index = this.webhooks.findIndex((w) => w.key === webhook);
- if (index === -1) {
- return Promise.reject(new Error('Webhook not found'));
- }
- this.webhooks.splice(index, 1);
- return this.response(undefined);
- };
-
- handleSearchDeliveries = ({
- webhook,
- ps = WebhooksMock.DEFAULT_PAGE_SIZE,
- p = 1,
- }: WebhookSearchDeliveriesPayload) => {
- const deliveries = mockFullWebhookDeliveries(webhook);
- const start = (p - 1) * ps;
- const end = start + ps;
- const paging = mockPaging({ pageIndex: p, pageSize: ps, total: deliveries.length });
- const page = deliveries.slice(start, end);
- return this.response({
- deliveries: page,
- paging,
- });
- };
-
- handleGetDelivery = ({ deliveryId }: { deliveryId: string }) => {
- const delivery = deliveries.find((delivery) => delivery.id === deliveryId);
- if (!delivery) {
- return Promise.reject(new Error('Delivery not found'));
- }
- return this.response({
- delivery: {
- ...delivery,
- payload: JSON.stringify({ id: delivery.id }),
- },
- });
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/data/branches.ts b/server/sonar-web/src/main/js/api/mocks/data/branches.ts
deleted file mode 100644
index 737439dba32..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/data/branches.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { mockBranch, mockPullRequest } from '../../../helpers/mocks/branch-like';
-
-export function mockBranchList() {
- return [
- mockBranch({
- isMain: true,
- name: 'main',
- status: { qualityGateStatus: 'OK' },
- }),
- mockBranch({
- excludedFromPurge: false,
- name: 'delete-branch',
- analysisDate: '2018-01-30',
- status: { qualityGateStatus: 'ERROR' },
- }),
- mockBranch({ name: 'normal-branch', status: { qualityGateStatus: 'ERROR' } }),
- ];
-}
-
-export function mockPullRequestList() {
- return [
- mockPullRequest({
- title: 'TEST-191 update master',
- key: '01',
- status: { qualityGateStatus: 'OK' },
- }),
- mockPullRequest({
- title: 'TEST-192 update normal-branch',
- key: '02',
- analysisDate: '2018-01-30',
- base: 'normal-branch',
- target: 'normal-branch',
- status: { qualityGateStatus: 'ERROR' },
- }),
- mockPullRequest({
- title: 'TEST-193 dumb commit',
- key: '03',
- target: 'normal-branch',
- status: { qualityGateStatus: 'ERROR' },
- }),
- ];
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/data/components.ts b/server/sonar-web/src/main/js/api/mocks/data/components.ts
deleted file mode 100644
index 8f3289cc082..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/data/components.ts
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { times } from 'lodash';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { mockComponent } from '../../../helpers/mocks/component';
-import {
- mockDuplicatedFile,
- mockDuplication,
- mockDuplicationBlock,
- mockSourceLine,
- mockSourceViewerFile,
-} from '../../../helpers/mocks/sources';
-import {
- Component,
- Dict,
- DuplicatedFile,
- Duplication,
- SourceLine,
- SourceViewerFile,
-} from '../../../types/types';
-import {
- FILE1_KEY,
- FILE2_KEY,
- FILE3_KEY,
- FILE4_KEY,
- FILE5_KEY,
- FILE6_KEY,
- FILE7_KEY,
- FILE8_KEY,
- FOLDER1_KEY,
- PARENT_COMPONENT_KEY,
-} from './ids';
-
-export interface ComponentTree {
- ancestors: Component[];
- children: ComponentTree[];
- component: Component;
-}
-
-export interface SourceFile {
- component: SourceViewerFile;
- duplication?: {
- duplications: Duplication[];
- files: Dict<DuplicatedFile>;
- };
- lines: SourceLine[];
-}
-
-export function mockFullComponentTree(
- baseComponent = mockComponent({
- key: PARENT_COMPONENT_KEY,
- name: 'Foo',
- breadcrumbs: [
- { key: PARENT_COMPONENT_KEY, name: 'Foo', qualifier: ComponentQualifier.Project },
- ],
- }),
-): ComponentTree {
- const folderComponent = mockComponent({
- key: `${baseComponent.key}:${FOLDER1_KEY}`,
- name: FOLDER1_KEY,
- path: FOLDER1_KEY,
- qualifier: ComponentQualifier.Directory,
- breadcrumbs: [
- ...baseComponent.breadcrumbs,
- {
- key: `${baseComponent.key}:${FOLDER1_KEY}`,
- name: FOLDER1_KEY,
- qualifier: ComponentQualifier.Directory,
- },
- ],
- });
- return {
- component: baseComponent,
- ancestors: [],
- children: [
- {
- component: folderComponent,
- ancestors: [baseComponent],
- children: [
- {
- component: mockComponent({
- key: `${baseComponent.key}:${FOLDER1_KEY}/${FILE7_KEY}`,
- name: FILE7_KEY,
- path: `${FOLDER1_KEY}/${FILE7_KEY}`,
- qualifier: ComponentQualifier.File,
- breadcrumbs: [
- ...folderComponent.breadcrumbs,
- {
- key: `${baseComponent.key}:${FOLDER1_KEY}/${FILE7_KEY}`,
- name: FILE7_KEY,
- qualifier: ComponentQualifier.File,
- },
- ],
- }),
- ancestors: [baseComponent, folderComponent],
- children: [],
- },
- {
- component: mockComponent({
- key: `${baseComponent.key}:${FOLDER1_KEY}/${FILE8_KEY}`,
- name: FILE8_KEY,
- path: `${FOLDER1_KEY}/${FILE8_KEY}`,
- qualifier: ComponentQualifier.File,
- breadcrumbs: [
- ...folderComponent.breadcrumbs,
- {
- key: `${baseComponent.key}:${FOLDER1_KEY}/${FILE8_KEY}`,
- name: FILE8_KEY,
- qualifier: ComponentQualifier.File,
- },
- ],
- }),
- ancestors: [baseComponent, folderComponent],
- children: [],
- },
- ],
- },
- {
- component: mockComponent({
- key: `${baseComponent.key}:${FILE1_KEY}`,
- name: FILE1_KEY,
- path: FILE1_KEY,
- qualifier: ComponentQualifier.File,
- breadcrumbs: [
- ...baseComponent.breadcrumbs,
- {
- key: `${baseComponent.key}:${FILE1_KEY}`,
- name: FILE1_KEY,
- qualifier: ComponentQualifier.File,
- },
- ],
- }),
- ancestors: [baseComponent],
- children: [],
- },
- {
- component: mockComponent({
- key: `${baseComponent.key}:${FILE2_KEY}`,
- name: FILE2_KEY,
- path: FILE2_KEY,
- qualifier: ComponentQualifier.File,
- breadcrumbs: [
- ...baseComponent.breadcrumbs,
- {
- key: `${baseComponent.key}:${FILE2_KEY}`,
- name: FILE2_KEY,
- qualifier: ComponentQualifier.File,
- },
- ],
- }),
- ancestors: [baseComponent],
- children: [],
- },
- {
- component: mockComponent({
- key: `${baseComponent.key}:${FILE3_KEY}`,
- name: FILE3_KEY,
- path: FILE3_KEY,
- qualifier: ComponentQualifier.File,
- breadcrumbs: [
- ...baseComponent.breadcrumbs,
- {
- key: `${baseComponent.key}:${FILE3_KEY}`,
- name: FILE3_KEY,
- qualifier: ComponentQualifier.File,
- },
- ],
- }),
- ancestors: [baseComponent],
- children: [],
- },
- {
- component: mockComponent({
- key: `${baseComponent.key}:${FILE4_KEY}`,
- name: FILE4_KEY,
- path: FILE4_KEY,
- qualifier: ComponentQualifier.File,
- breadcrumbs: [
- ...baseComponent.breadcrumbs,
- {
- key: `${baseComponent.key}:${FILE4_KEY}`,
- name: FILE4_KEY,
- qualifier: ComponentQualifier.File,
- },
- ],
- }),
- ancestors: [baseComponent],
- children: [],
- },
- {
- component: mockComponent({
- key: `${baseComponent.key}:${FILE5_KEY}`,
- name: FILE5_KEY,
- path: FILE5_KEY,
- qualifier: ComponentQualifier.File,
- breadcrumbs: [
- ...baseComponent.breadcrumbs,
- {
- key: `${baseComponent.key}:${FILE5_KEY}`,
- name: FILE5_KEY,
- qualifier: ComponentQualifier.File,
- },
- ],
- }),
- ancestors: [baseComponent],
- children: [],
- },
- {
- component: mockComponent({
- key: `${baseComponent.key}:${FILE6_KEY}`,
- name: FILE6_KEY,
- path: FILE6_KEY,
- qualifier: ComponentQualifier.File,
- breadcrumbs: [
- ...baseComponent.breadcrumbs,
- {
- key: `${baseComponent.key}:${FILE6_KEY}`,
- name: FILE6_KEY,
- qualifier: ComponentQualifier.File,
- },
- ],
- }),
- ancestors: [baseComponent],
- children: [],
- },
- ],
- };
-}
-
-export function mockFullSourceViewerFileList(baseComponentKey = PARENT_COMPONENT_KEY) {
- return [
- {
- component: mockSourceViewerFile(FILE1_KEY, baseComponentKey),
- lines: times(50, (n) =>
- mockSourceLine({
- line: n,
- code: 'function Test() {}',
- }),
- ),
- },
- {
- component: mockSourceViewerFile(`${FOLDER1_KEY}/${FILE7_KEY}`, baseComponentKey),
- lines: times(50, (n) =>
- mockSourceLine({
- line: n,
- code: 'function Test() {}',
- }),
- ),
- },
- {
- component: mockSourceViewerFile(`${FOLDER1_KEY}/${FILE8_KEY}`, baseComponentKey),
- lines: times(50, (n) =>
- mockSourceLine({
- line: n,
- code: 'function Test() {}',
- }),
- ),
- },
- {
- component: mockSourceViewerFile(FILE2_KEY, baseComponentKey),
- lines: [
- {
- line: 1,
- code: '\u003cspan class\u003d"cd"\u003e/*\u003c/span\u003e',
- scmRevision: 'f09ee6b610528aa37b7b51be395c93524cebae8f',
- scmAuthor: 'stas.vilchik@sonarsource.com',
- scmDate: '2018-07-10T20:21:20+0200',
- duplicated: false,
- isNew: false,
- lineHits: 1,
- coveredConditions: 1,
- },
- {
- line: 2,
- code: '\u003cspan class\u003d"cd"\u003e * SonarQube\u003c/span\u003e',
- scmRevision: 'f09ee6b610528aa37b7b51be395c93524cebae8f',
- scmAuthor: 'stas.vilchik@sonarsource.com',
- scmDate: '2018-07-10T20:21:20+0200',
- duplicated: false,
- isNew: false,
- lineHits: 0,
- conditions: 1,
- },
- {
- line: 3,
- code: '\u003cspan class\u003d"cd"\u003e * Copyright\u003c/span\u003e',
- scmRevision: '89a3d21bc28f2fa6201b5e8b1185d5358481b3dd',
- scmAuthor: 'pierre.guillot@sonarsource.com',
- scmDate: '2022-01-28T21:03:07+0100',
- duplicated: false,
- isNew: false,
- lineHits: 1,
- },
- {
- line: 4,
- code: '\u003cspan class\u003d"cd"\u003e * mailto:info AT sonarsource DOT com\u003c/span\u003e',
- scmRevision: 'f09ee6b610528aa37b7b51be395c93524cebae8f',
- scmAuthor: 'stas.vilchik@sonarsource.com',
- duplicated: false,
- isNew: false,
- lineHits: 1,
- conditions: 1,
- coveredConditions: 1,
- },
- {
- line: 5,
- code: '\u003cspan class\u003d"cd"\u003e * 5\u003c/span\u003e',
- scmRevision: 'f04ee6b610528aa37b7b51be395c93524cebae8f',
- duplicated: false,
- isNew: false,
- lineHits: 2,
- conditions: 2,
- coveredConditions: 1,
- },
- {
- line: 6,
- code: '\u003cspan class\u003d"cd"\u003e * 6\u003c/span\u003e',
- scmRevision: 'f04ee6b610528aa37b7b51be395c93524cebae8f',
- duplicated: false,
- isNew: false,
- lineHits: 0,
- },
- {
- line: 7,
- code: '\u003cspan class\u003d"cd"\u003e * 7\u003c/span\u003e',
- scmRevision: 'f04ee6b610528aa37b7b51be395c93524cebae8f',
- duplicated: true,
- isNew: true,
- },
- {
- code: '\u003cspan class\u003d"cd"\u003e * This program is free software; you can redistribute it and/or\u003c/span\u003e',
- scmRevision: 'f09ee6b610528aa37b7b51be395c93524cebae8f',
- scmAuthor: 'stas.vilchik@sonarsource.com',
- scmDate: '2018-07-10T20:21:20+0200',
- duplicated: false,
- isNew: false,
- },
- ],
- duplication: {
- duplications: [
- mockDuplication({
- blocks: [
- mockDuplicationBlock({ from: 7, size: 1, _ref: '1' }),
- mockDuplicationBlock({ from: 1, size: 1, _ref: '2' }),
- ],
- }),
- ],
- files: {
- '1': mockDuplicatedFile({ key: `${baseComponentKey}:${FILE2_KEY}` }),
- '2': mockDuplicatedFile({ key: `${baseComponentKey}:${FILE3_KEY}` }),
- },
- },
- },
- {
- component: mockSourceViewerFile(FILE3_KEY, baseComponentKey),
- lines: times(50, (n) =>
- mockSourceLine({
- line: n,
- code: `\u003cspan class\u003d"cd"\u003eLine ${n}\u003c/span\u003e`,
- }),
- ),
- },
- {
- component: mockSourceViewerFile(FILE5_KEY, baseComponentKey),
- lines: [],
- },
- {
- component: mockSourceViewerFile(FILE6_KEY, baseComponentKey),
- lines: times(200, (n) =>
- mockSourceLine({
- line: n,
- code: `\u003cspan class\u003d"cd"\u003eLine ${n}\u003c/span\u003e`,
- }),
- ),
- },
- {
- component: mockSourceViewerFile(FILE4_KEY, baseComponentKey),
- lines: times(20, (n) =>
- mockSourceLine({
- line: n,
- code: ' <span class="sym-35 sym">symbole</span>',
- }),
- ),
- },
- ] as SourceFile[];
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/data/dop-translation.ts b/server/sonar-web/src/main/js/api/mocks/data/dop-translation.ts
deleted file mode 100644
index fbb5fa88df3..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/data/dop-translation.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable local-rules/use-metrickey-enum */
-
-import { AlmKeys } from '../../../types/alm-settings';
-import { DopSetting, ProjectBinding } from '../../../types/dop-translation';
-
-export function mockDopSetting(overrides?: Partial<DopSetting>): DopSetting {
- return {
- id: overrides?.id ?? overrides?.key ?? 'dop-setting-test-id',
- key: 'Test/DopSetting',
- type: AlmKeys.GitHub,
- url: 'https://github.com',
- ...overrides,
- };
-}
-
-export function mockProjectBinding(overrides?: Partial<ProjectBinding>): ProjectBinding {
- return {
- dopSetting: 'dop-setting-test-id',
- id: 'project-binding-test-id',
- projectId: 'project-id',
- projectKey: 'project-key',
- repository: 'repository',
- slug: 'Slug/Project',
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/data/ids.ts b/server/sonar-web/src/main/js/api/mocks/data/ids.ts
deleted file mode 100644
index a0ed7f2d489..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/data/ids.ts
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { SecurityStandard, Standards } from '../../../types/security';
-
-// Component tree.
-export const PARENT_COMPONENT_KEY = 'foo';
-//// Root folder.
-export const FILE1_KEY = 'index.tsx';
-export const FILE2_KEY = 'test1.js';
-export const FILE3_KEY = 'test2.js';
-export const FILE4_KEY = 'testSymb.tsx';
-export const FILE5_KEY = 'empty.js';
-export const FILE6_KEY = 'huge.js';
-export const FOLDER1_KEY = 'folderA';
-//// Inside folderA.
-export const FILE7_KEY = 'out.tsx';
-export const FILE8_KEY = 'in.tsx';
-
-// Rules.
-export const SIMPLE_RULE = 'simpleRuleId';
-export const ADVANCED_RULE = 'advancedRuleId';
-export const S6069_RULE = 'cpp:S6069';
-export const S131_RULE = 'tsql:S131';
-export const RULE_1 = 'rule1';
-export const RULE_2 = 'rule2';
-export const RULE_3 = 'rule3';
-export const RULE_4 = 'rule4';
-export const RULE_5 = 'rule5';
-export const RULE_6 = 'rule6';
-export const RULE_7 = 'rule7';
-export const RULE_8 = 'rule8';
-export const RULE_9 = 'rule9';
-export const RULE_10 = 'rule10';
-export const RULE_11 = 'rule11';
-export const RULE_12 = 'rule12';
-
-// Quality Profiles.
-export const QP_1 = 'p1';
-export const QP_2_Parent = 'p2parent';
-export const QP_2 = 'p2';
-export const QP_3 = 'p3';
-export const QP_4 = 'p4';
-export const QP_5 = 'p5';
-export const QP_6 = 'p6';
-
-// Issues.
-export const ISSUE_0 = 'issue0';
-export const ISSUE_1 = 'issue1';
-export const ISSUE_2 = 'issue2';
-export const ISSUE_3 = 'issue3';
-export const ISSUE_4 = 'issue4';
-export const ISSUE_5 = 'issue5';
-export const ISSUE_11 = 'issue11';
-export const ISSUE_101 = 'issue101';
-export const ISSUE_1101 = 'issue1101';
-export const ISSUE_1102 = 'issue1102';
-export const ISSUE_1103 = 'issue1103';
-
-// Issue to rule map.
-export const ISSUE_TO_RULE = {
- [ISSUE_0]: SIMPLE_RULE,
- [ISSUE_1]: SIMPLE_RULE,
- [ISSUE_2]: ADVANCED_RULE,
- [ISSUE_3]: 'other',
- [ISSUE_4]: 'other',
- [ISSUE_5]: 'other',
- [ISSUE_11]: SIMPLE_RULE,
- [ISSUE_101]: SIMPLE_RULE,
- [ISSUE_1101]: SIMPLE_RULE,
- [ISSUE_1102]: SIMPLE_RULE,
- [ISSUE_1103]: SIMPLE_RULE,
-};
-
-// Issue to files map.
-export const ISSUE_TO_FILES = {
- [ISSUE_0]: [FILE2_KEY],
- [ISSUE_1]: [FILE6_KEY],
- [ISSUE_2]: [FILE3_KEY],
- [ISSUE_3]: [FILE3_KEY],
- [ISSUE_4]: [FILE3_KEY],
- [ISSUE_5]: [FILE3_KEY],
- [ISSUE_11]: [FILE2_KEY, FILE3_KEY],
- [ISSUE_101]: [FILE2_KEY, FILE3_KEY],
- [ISSUE_1101]: [`${FOLDER1_KEY}/${FILE7_KEY}`],
- [ISSUE_1102]: [`${FOLDER1_KEY}/${FILE8_KEY}`],
- [ISSUE_1103]: [`${FOLDER1_KEY}/${FILE8_KEY}`],
-};
-
-export const STANDARDS_TO_RULES: Partial<{
- [category in keyof Standards]: { [standard: string]: string[] };
-}> = {
- [SecurityStandard.SONARSOURCE]: {
- 'buffer-overflow': [RULE_1, RULE_2, RULE_3, RULE_4, RULE_5, RULE_6],
- },
- [SecurityStandard.OWASP_TOP10_2021]: {
- a2: [RULE_1, RULE_2, RULE_3, RULE_4, RULE_5],
- },
- [SecurityStandard.OWASP_TOP10]: {
- a3: [RULE_1, RULE_2, RULE_3, RULE_4],
- },
- [SecurityStandard.CWE]: {
- '102': [RULE_1, RULE_2, RULE_3],
- '297': [RULE_1, RULE_4],
- },
-};
-
-// Webhooks.
-export const WEBHOOK_GLOBAL_1 = 'global-webhook1';
-export const WEBHOOK_GLOBAL_1_LATEST_DELIVERY_ID = 'global-delivery1';
-export const WEBHOOK_GLOBAL_2 = 'global-webhook2';
-export const WEBHOOK_PROJECT_1 = 'project1';
-export const WEBHOOK_PROJECT_1_1 = 'project1-webhook1';
-export const WEBHOOK_PROJECT_1_2 = 'project1-webhook2';
diff --git a/server/sonar-web/src/main/js/api/mocks/data/issues.ts b/server/sonar-web/src/main/js/api/mocks/data/issues.ts
deleted file mode 100644
index 0a62a929b9c..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/data/issues.ts
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { keyBy, times } from 'lodash';
-import { mockSnippetsByComponent } from '../../../helpers/mocks/sources';
-import { mockLoggedInUser, mockRawIssue } from '../../../helpers/testMocks';
-import {
- CleanCodeAttributeCategory,
- SoftwareImpactSeverity,
- SoftwareQuality,
-} from '../../../types/clean-code-taxonomy';
-import {
- IssueActions,
- IssueDeprecatedStatus,
- IssueResolution,
- IssueScope,
- IssueSeverity,
- IssueStatus,
- IssueTransition,
- IssueType,
- RawIssue,
-} from '../../../types/issues';
-import { Dict, FlowType, SnippetsByComponent } from '../../../types/types';
-import {
- ISSUE_0,
- ISSUE_1,
- ISSUE_101,
- ISSUE_11,
- ISSUE_1101,
- ISSUE_1102,
- ISSUE_1103,
- ISSUE_2,
- ISSUE_3,
- ISSUE_4,
- ISSUE_5,
- ISSUE_TO_FILES,
- ISSUE_TO_RULE,
- PARENT_COMPONENT_KEY,
-} from './ids';
-
-export interface IssueData {
- issue: RawIssue;
- snippets: Dict<SnippetsByComponent>;
-}
-
-export function mockIssuesList(baseComponentKey = PARENT_COMPONENT_KEY): IssueData[] {
- return [
- {
- issue: mockRawIssue(false, {
- key: ISSUE_101,
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_101][0]}`,
- creationDate: '2023-01-05T09:36:01+0100',
- message: 'Issue with no location message',
- cleanCodeAttributeCategory: CleanCodeAttributeCategory.Consistent,
- type: IssueType.Vulnerability,
- rule: ISSUE_TO_RULE[ISSUE_101],
- textRange: {
- startLine: 10,
- endLine: 10,
- startOffset: 0,
- endOffset: 2,
- },
- flows: [
- {
- locations: [
- {
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_101][0]}`,
- textRange: {
- startLine: 1,
- endLine: 1,
- startOffset: 0,
- endOffset: 1,
- },
- },
- ],
- },
- {
- locations: [
- {
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_101][1]}`,
- textRange: {
- startLine: 20,
- endLine: 20,
- startOffset: 0,
- endOffset: 1,
- },
- },
- ],
- },
- ],
- resolution: IssueResolution.WontFix,
- scope: IssueScope.Main,
- tags: ['tag0', 'tag1'],
- }),
- snippets: keyBy(
- [
- mockSnippetsByComponent(
- ISSUE_TO_FILES[ISSUE_101][0],
- baseComponentKey,
- times(40, (i) => i + 1),
- ),
- mockSnippetsByComponent(
- ISSUE_TO_FILES[ISSUE_101][1],
- baseComponentKey,
- times(40, (i) => i + 1),
- ),
- ],
- 'component.key',
- ),
- },
- {
- issue: mockRawIssue(false, {
- key: ISSUE_11,
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_11][0]}`,
- creationDate: '2022-01-01T09:36:01+0100',
- message: 'FlowIssue',
- type: IssueType.CodeSmell,
- severity: IssueSeverity.Minor,
- rule: ISSUE_TO_RULE[ISSUE_11],
- textRange: {
- startLine: 10,
- endLine: 10,
- startOffset: 0,
- endOffset: 2,
- },
- flows: [
- {
- type: FlowType.DATA,
- description: 'Backtracking 1',
- locations: [
- {
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_11][0]}`,
- msg: 'Data location 1',
- textRange: {
- startLine: 20,
- endLine: 20,
- startOffset: 0,
- endOffset: 1,
- },
- },
- {
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_11][0]}`,
- msg: 'Data location 2',
- textRange: {
- startLine: 21,
- endLine: 21,
- startOffset: 0,
- endOffset: 1,
- },
- },
- ],
- },
- {
- type: FlowType.EXECUTION,
- locations: [
- {
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_11][1]}`,
- msg: 'Execution location 1',
- textRange: {
- startLine: 20,
- endLine: 20,
- startOffset: 0,
- endOffset: 1,
- },
- },
- {
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_11][1]}`,
- msg: 'Execution location 2',
- textRange: {
- startLine: 22,
- endLine: 22,
- startOffset: 0,
- endOffset: 1,
- },
- },
- {
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_11][1]}`,
- msg: 'Execution location 3',
- textRange: {
- startLine: 5,
- endLine: 5,
- startOffset: 0,
- endOffset: 1,
- },
- },
- ],
- },
- ],
- tags: ['tag1'],
- }),
- snippets: keyBy(
- [
- mockSnippetsByComponent(
- ISSUE_TO_FILES[ISSUE_11][0],
- baseComponentKey,
- times(40, (i) => i + 1),
- ),
- mockSnippetsByComponent(
- ISSUE_TO_FILES[ISSUE_11][1],
- baseComponentKey,
- times(40, (i) => i + 1),
- ),
- ],
- 'component.key',
- ),
- },
- {
- issue: mockRawIssue(false, {
- key: ISSUE_0,
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_0][0]}`,
- message: 'Issue on file',
- assignee: mockLoggedInUser().login,
- rule: ISSUE_TO_RULE[ISSUE_0],
- textRange: undefined,
- line: undefined,
- scope: IssueScope.Test,
- }),
- snippets: {},
- },
- {
- issue: mockRawIssue(false, {
- key: ISSUE_1,
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_1][0]}`,
- message: 'Fix this',
- type: IssueType.Vulnerability,
- scope: IssueScope.Test,
- rule: ISSUE_TO_RULE[ISSUE_1],
- textRange: {
- startLine: 10,
- endLine: 10,
- startOffset: 0,
- endOffset: 2,
- },
- flows: [
- {
- locations: [
- {
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_1][0]}`,
- msg: 'location 1',
- textRange: {
- startLine: 1,
- endLine: 1,
- startOffset: 0,
- endOffset: 1,
- },
- },
- ],
- },
- {
- locations: [
- {
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_1][0]}`,
- msg: 'location 2',
- textRange: {
- startLine: 50,
- endLine: 50,
- startOffset: 0,
- endOffset: 1,
- },
- },
- ],
- },
- ],
- }),
- snippets: keyBy(
- [
- mockSnippetsByComponent(
- ISSUE_TO_FILES[ISSUE_1][0],
- baseComponentKey,
- times(80, (i) => i + 1),
- ),
- mockSnippetsByComponent(
- ISSUE_TO_FILES[ISSUE_1][0],
- baseComponentKey,
- times(80, (i) => i + 1),
- ),
- ],
- 'component.key',
- ),
- },
- {
- issue: mockRawIssue(false, {
- key: ISSUE_2,
- actions: Object.values(IssueActions),
- transitions: [
- IssueTransition.Accept,
- IssueTransition.Confirm,
- IssueTransition.Resolve,
- IssueTransition.FalsePositive,
- IssueTransition.WontFix,
- ],
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_2][0]}`,
- message: 'Fix that',
- rule: ISSUE_TO_RULE[ISSUE_2],
- textRange: {
- startLine: 25,
- endLine: 25,
- startOffset: 0,
- endOffset: 1,
- },
- impacts: [
- { softwareQuality: SoftwareQuality.Security, severity: SoftwareImpactSeverity.High },
- ],
- resolution: IssueResolution.Unresolved,
- status: IssueDeprecatedStatus.Open,
- issueStatus: IssueStatus.Open,
- ruleDescriptionContextKey: 'spring',
- author: 'bob.marley@test.com',
- cveId: 'CVE-2021-12345',
- }),
- snippets: keyBy(
- [
- mockSnippetsByComponent(
- ISSUE_TO_FILES[ISSUE_2][0],
- baseComponentKey,
- times(40, (i) => i + 20),
- ),
- ],
- 'component.key',
- ),
- },
- {
- issue: mockRawIssue(false, {
- key: ISSUE_3,
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_3][0]}`,
- message: 'Second issue',
- rule: ISSUE_TO_RULE[ISSUE_3],
- textRange: {
- startLine: 28,
- endLine: 28,
- startOffset: 0,
- endOffset: 1,
- },
- resolution: IssueResolution.Fixed,
- status: IssueDeprecatedStatus.Confirmed,
- issueStatus: IssueStatus.Confirmed,
- author: 'unknownemail@test.com',
- }),
- snippets: keyBy(
- [
- mockSnippetsByComponent(
- ISSUE_TO_FILES[ISSUE_3][0],
- baseComponentKey,
- times(40, (i) => i + 20),
- ),
- ],
- 'component.key',
- ),
- },
- {
- issue: mockRawIssue(false, {
- key: ISSUE_4,
- actions: Object.values(IssueActions),
- transitions: [
- IssueTransition.Confirm,
- IssueTransition.Resolve,
- IssueTransition.FalsePositive,
- IssueTransition.WontFix,
- ],
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_4][0]}`,
- message: 'Issue with tags',
- rule: ISSUE_TO_RULE[ISSUE_4],
- textRange: {
- startLine: 25,
- endLine: 25,
- startOffset: 0,
- endOffset: 1,
- },
- ruleDescriptionContextKey: 'spring',
- ruleStatus: 'DEPRECATED',
- quickFixAvailable: true,
- tags: ['unused'],
- codeVariants: ['variant 1', 'variant 2'],
- project: 'org.sonarsource.javascript:javascript',
- assignee: 'email1@sonarsource.com',
- author: 'email3@sonarsource.com',
- issueStatus: IssueStatus.Confirmed,
- }),
- snippets: keyBy(
- [
- mockSnippetsByComponent(
- ISSUE_TO_FILES[ISSUE_4][0],
- baseComponentKey,
- times(40, (i) => i + 20),
- ),
- ],
- 'component.key',
- ),
- },
- {
- issue: mockRawIssue(false, {
- key: ISSUE_1101,
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_1101][0]}`,
- message: 'Issue on page 2',
- impacts: [
- {
- softwareQuality: SoftwareQuality.Maintainability,
- severity: SoftwareImpactSeverity.High,
- },
- ],
- rule: ISSUE_TO_RULE[ISSUE_1101],
- textRange: undefined,
- line: undefined,
- }),
- snippets: {},
- },
- {
- issue: mockRawIssue(false, {
- key: ISSUE_1102,
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_1102][0]}`,
- message: 'Issue inside folderA',
- creationDate: '2022-01-15T09:36:01+0100',
- type: IssueType.CodeSmell,
- rule: ISSUE_TO_RULE[ISSUE_1102],
- textRange: {
- startLine: 10,
- endLine: 10,
- startOffset: 0,
- endOffset: 2,
- },
- }),
- snippets: {},
- },
- {
- issue: mockRawIssue(false, {
- key: ISSUE_1103,
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_1103][0]}`,
- creationDate: '2022-01-15T09:36:01+0100',
- message: 'Issue 2 inside folderA',
- type: IssueType.CodeSmell,
- rule: ISSUE_TO_RULE[ISSUE_1103],
- textRange: {
- startLine: 10,
- endLine: 10,
- startOffset: 0,
- endOffset: 2,
- },
- }),
- snippets: {},
- },
- {
- issue: mockRawIssue(false, {
- key: ISSUE_5,
- actions: Object.values(IssueActions),
- transitions: [
- IssueTransition.Confirm,
- IssueTransition.Resolve,
- IssueTransition.FalsePositive,
- IssueTransition.WontFix,
- ],
- component: `${baseComponentKey}:${ISSUE_TO_FILES[ISSUE_5][0]}`,
- message: 'Issue with prioritized rule',
- rule: ISSUE_TO_RULE[ISSUE_5],
- textRange: {
- startLine: 25,
- endLine: 25,
- startOffset: 0,
- endOffset: 1,
- },
- ruleDescriptionContextKey: 'spring',
- ruleStatus: 'DEPRECATED',
- quickFixAvailable: true,
- tags: ['unused'],
- codeVariants: ['variant 1', 'variant 2'],
- project: 'org.sonarsource.javascript:javascript',
- assignee: 'email1@sonarsource.com',
- author: 'email3@sonarsource.com',
- issueStatus: IssueStatus.Confirmed,
- prioritizedRule: true,
- }),
- snippets: keyBy(
- [
- mockSnippetsByComponent(
- ISSUE_TO_FILES[ISSUE_5][0],
- baseComponentKey,
- times(40, (i) => i + 20),
- ),
- ],
- 'component.key',
- ),
- },
- ];
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/data/measures.ts b/server/sonar-web/src/main/js/api/mocks/data/measures.ts
deleted file mode 100644
index aafef6c4635..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/data/measures.ts
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { keyBy } from 'lodash';
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import { isDiffMetric } from '../../../helpers/measures';
-import { mockMeasure } from '../../../helpers/testMocks';
-import { IssueDeprecatedStatus, IssueType, RawIssue } from '../../../types/issues';
-import { Measure } from '../../../types/types';
-import { ComponentTree } from './components';
-import { IssueData } from './issues';
-import { listAllComponent, listAllComponentTrees } from './utils';
-
-const MAX_RATING = 5;
-export type MeasureRecords = Record<string, Record<string, Measure>>;
-
-export function mockFullMeasureData(tree: ComponentTree, issueList: IssueData[]) {
- const measures: MeasureRecords = {};
- listAllComponentTrees(tree).forEach((tree) => {
- measures[tree.component.key] = keyBy(
- Object.values(MetricKey).map((metricKey) => mockComponentMeasure(tree, issueList, metricKey)),
- 'metric',
- );
- });
- return measures;
-}
-
-function mockComponentMeasure(tree: ComponentTree, issueList: IssueData[], metricKey: MetricKey) {
- const componentKeys = listAllComponent(tree).map(({ key }) => key);
-
- switch (metricKey) {
- case MetricKey.ncloc:
- return mockMeasure({
- metric: metricKey,
- value: '16000',
- });
-
- case MetricKey.ncloc_language_distribution:
- return mockMeasure({
- metric: metricKey,
- value: 'java=10000;javascript=5000;css=1000',
- });
-
- case MetricKey.software_quality_security_issues:
- return mockMeasure({
- metric: metricKey,
- value: '1',
- });
-
- case MetricKey.new_software_quality_security_issues:
- return mockMeasure({
- metric: metricKey,
- period: {
- index: 1,
- value: '3',
- },
- value: undefined,
- });
-
- case MetricKey.software_quality_reliability_issues:
- return mockMeasure({
- metric: metricKey,
- value: '3',
- });
-
- case MetricKey.new_software_quality_reliability_issues:
- return mockMeasure({
- metric: metricKey,
- period: {
- index: 1,
- value: '2',
- },
- value: undefined,
- });
-
- case MetricKey.software_quality_maintainability_issues:
- return mockMeasure({
- metric: metricKey,
- value: '2',
- });
-
- case MetricKey.new_software_quality_maintainability_issues:
- return mockMeasure({
- metric: metricKey,
- period: {
- index: 1,
- value: '5',
- },
- value: undefined,
- });
- }
-
- const issues = issueList
- .map(({ issue }) => issue)
- .filter(({ component }) => componentKeys.includes(component))
- .filter(({ status }) =>
- [
- IssueDeprecatedStatus.Open,
- IssueDeprecatedStatus.Reopened,
- IssueDeprecatedStatus.Confirmed,
- ].includes(status as IssueDeprecatedStatus),
- );
-
- if (isIssueType(metricKey)) {
- switch (metricKey) {
- case MetricKey.bugs:
- return mockMeasure({
- metric: metricKey,
- period: undefined,
- value: String(issues.filter(({ type }) => type === IssueType.Bug).length),
- });
-
- case MetricKey.new_bugs:
- return mockMeasure({
- metric: metricKey,
- period: {
- index: 0,
- value: String(issues.filter(({ type }) => type === IssueType.Bug).length),
- },
- value: undefined,
- });
-
- case MetricKey.code_smells:
- return mockMeasure({
- metric: metricKey,
- period: undefined,
- value: String(issues.filter(({ type }) => type === IssueType.CodeSmell).length),
- });
-
- case MetricKey.new_code_smells:
- return mockMeasure({
- metric: metricKey,
- period: {
- index: 0,
- value: String(issues.filter(({ type }) => type === IssueType.CodeSmell).length),
- },
- value: undefined,
- });
-
- case MetricKey.vulnerabilities:
- return mockMeasure({
- metric: metricKey,
- period: undefined,
- value: String(issues.filter(({ type }) => type === IssueType.Vulnerability).length),
- });
-
- case MetricKey.new_vulnerabilities:
- return mockMeasure({
- metric: metricKey,
- period: {
- index: 0,
- value: String(issues.filter(({ type }) => type === IssueType.Vulnerability).length),
- },
- value: undefined,
- });
-
- case MetricKey.open_issues:
- return mockMeasure({
- metric: metricKey,
- value: String(issues.length),
- });
- }
- }
-
- if (isIssueRelatedRating(metricKey)) {
- switch (metricKey) {
- case MetricKey.reliability_rating:
- return mockMeasure({
- metric: metricKey,
- period: undefined,
- ...computeRating(issues, IssueType.Bug),
- });
-
- case MetricKey.software_quality_reliability_rating: {
- const rating = computeRating(issues, IssueType.Bug);
- if (rating.value === '5.0') {
- rating.value = '4.0';
- }
- return mockMeasure({
- metric: metricKey,
- period: undefined,
- ...computeRating(issues, IssueType.Bug),
- });
- }
-
- case MetricKey.new_reliability_rating:
- return mockMeasure({
- metric: metricKey,
- period: {
- index: 0,
- ...computeRating(issues, IssueType.Bug),
- },
- value: undefined,
- });
-
- case MetricKey.new_software_quality_reliability_rating: {
- const rating = computeRating(issues, IssueType.Bug);
- if (rating.value === '5.0') {
- rating.value = '4.0';
- }
- return mockMeasure({
- metric: metricKey,
- period: {
- index: 0,
- ...rating,
- },
- value: undefined,
- });
- }
-
- case MetricKey.sqale_rating:
- return mockMeasure({
- metric: metricKey,
- period: undefined,
- ...computeRating(issues, IssueType.CodeSmell),
- });
-
- case MetricKey.software_quality_maintainability_rating: {
- const rating = computeRating(issues, IssueType.CodeSmell);
- if (rating.value === '5.0') {
- rating.value = '4.0';
- }
- return mockMeasure({
- metric: metricKey,
- period: undefined,
- ...rating,
- });
- }
-
- case MetricKey.new_maintainability_rating:
- return mockMeasure({
- metric: metricKey,
- period: {
- index: 0,
- ...computeRating(issues, IssueType.CodeSmell),
- },
- value: undefined,
- });
-
- case MetricKey.new_software_quality_maintainability_rating: {
- const rating = computeRating(issues, IssueType.CodeSmell);
- if (rating.value === '5.0') {
- rating.value = '4.0';
- }
- return mockMeasure({
- metric: metricKey,
- period: {
- index: 0,
- ...rating,
- },
- value: undefined,
- });
- }
-
- case MetricKey.security_rating:
- return mockMeasure({
- metric: metricKey,
- period: undefined,
- ...computeRating(issues, IssueType.Vulnerability),
- });
-
- case MetricKey.software_quality_security_rating: {
- const rating = computeRating(issues, IssueType.Vulnerability);
- if (rating.value === '5.0') {
- rating.value = '4.0';
- }
- return mockMeasure({
- metric: metricKey,
- period: undefined,
- ...rating,
- });
- }
-
- case MetricKey.new_security_rating:
- return mockMeasure({
- metric: metricKey,
- period: {
- index: 0,
- ...computeRating(issues, IssueType.Vulnerability),
- },
- value: undefined,
- });
-
- case MetricKey.new_software_quality_security_rating: {
- const rating = computeRating(issues, IssueType.Vulnerability);
- if (rating.value === '5.0') {
- rating.value = '4.0';
- }
- return mockMeasure({
- metric: metricKey,
- period: {
- index: 0,
- ...rating,
- },
- value: undefined,
- });
- }
- }
- }
-
- // Defaults.
- if (isDiffMetric(metricKey)) {
- return mockMeasure({
- metric: metricKey,
- value: undefined,
- });
- }
- return mockMeasure({
- metric: metricKey,
- period: undefined,
- });
-}
-
-export function getMetricTypeFromKey(metricKey: string) {
- if (/(coverage|duplication)$/.test(metricKey)) {
- return MetricType.Percent;
- } else if (metricKey.includes('_rating')) {
- return MetricType.Rating;
- }
- return MetricType.Integer;
-}
-
-function isIssueType(metricKey: MetricKey) {
- return [
- MetricKey.bugs,
- MetricKey.new_bugs,
- MetricKey.code_smells,
- MetricKey.new_code_smells,
- MetricKey.vulnerabilities,
- MetricKey.new_vulnerabilities,
- MetricKey.open_issues,
- ].includes(metricKey);
-}
-
-function isIssueRelatedRating(metricKey: MetricKey) {
- return [
- MetricKey.reliability_rating,
- MetricKey.software_quality_reliability_rating,
- MetricKey.new_reliability_rating,
- MetricKey.new_software_quality_reliability_rating,
- MetricKey.sqale_rating,
- MetricKey.software_quality_maintainability_rating,
- MetricKey.new_maintainability_rating,
- MetricKey.new_software_quality_maintainability_rating,
- MetricKey.security_rating,
- MetricKey.software_quality_security_rating,
- MetricKey.new_security_rating,
- MetricKey.new_software_quality_security_rating,
- ].includes(metricKey);
-}
-
-/**
- * Ratings are not only based on the number of issues, but also their severity, and sometimes their
- * ratio to the LOC. But using the number will suffice as an approximation in our tests.
- */
-function computeRating(issues: RawIssue[], type: IssueType) {
- const value = Math.max(Math.min(issues.filter((i) => i.type === type).length, MAX_RATING), 1);
- return {
- value: `${value}.0`,
- bestValue: value === 1,
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/data/projects.ts b/server/sonar-web/src/main/js/api/mocks/data/projects.ts
deleted file mode 100644
index edbd6d42c29..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/data/projects.ts
+++ /dev/null
@@ -1,1955 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable local-rules/use-metrickey-enum */
-
-import { ComponentQualifier, Visibility } from '~sonar-aligned/types/component';
-import { ComponentRaw } from '../../components';
-
-export function mockProjects(): ComponentRaw[] {
- return [
- {
- key: 'linux-autotools-gitlab-ci-sq_AYAYuaB5_scXWD3WLpNC',
- name: 'linux-autotools-gitlab-ci-sq',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-21T03:50:39+0000',
- tags: [],
- visibility: Visibility.Public,
- leakPeriodDate: '2023-06-22T14:30:22+0000',
- },
- {
- key: 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus',
- name: 'linux-cmake-gitlab-ci-vulnerability-reports-sq',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-16T08:23:35+0000',
- tags: [],
- visibility: Visibility.Public,
- leakPeriodDate: '2023-08-11T15:24:00+0000',
- },
- {
- key: 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9',
- name: 'macos-cmake-azure-sq',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-21T07:42:10+0000',
- tags: [],
- visibility: Visibility.Public,
- leakPeriodDate: '2022-04-29T14:32:34+0000',
- },
- {
- key: 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK',
- name: 'macos-cmake-compdb-gh-actions-sq',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-21T03:29:41+0000',
- tags: [],
- visibility: Visibility.Public,
- leakPeriodDate: '2022-05-23T03:47:21+0000',
- },
- {
- key: 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_',
- name: 'macos-cmake-gh-actions-sq',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-21T03:29:57+0000',
- tags: [],
- visibility: Visibility.Public,
- leakPeriodDate: '2022-04-29T14:31:56+0000',
- },
- {
- key: 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua',
- name: 'macos-xcode-azure-sq',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-21T03:30:16+0000',
- tags: [],
- visibility: Visibility.Public,
- leakPeriodDate: '2022-04-29T14:32:59+0000',
- },
- {
- key: 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ',
- name: 'macos-xcode-gh-actions-sq',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-21T03:30:20+0000',
- tags: [],
- visibility: Visibility.Public,
- leakPeriodDate: '2022-04-29T14:32:54+0000',
- },
- {
- key: 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc',
- name: 'macos-xcode-otherci-sq',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-21T03:30:00+0000',
- tags: [],
- visibility: Visibility.Public,
- leakPeriodDate: '2022-08-23T13:58:25+0000',
- },
- {
- key: 'org.sonarsource.orchestrator:orchestrator-parent',
- name: 'Orchestrator :: Parent',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-21T05:06:09+0000',
- tags: ['platform'],
- visibility: Visibility.Public,
- leakPeriodDate: '2023-08-15T05:06:15+0000',
- },
- {
- key: 'org.sonarsource.python:python',
- name: 'Python',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-21T08:25:53+0000',
- tags: [],
- visibility: Visibility.Public,
- leakPeriodDate: '2023-08-03T09:08:44+0000',
- },
- {
- key: 'rspec-frontend',
- name: 'rspec-frontend',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-21T09:25:03+0000',
- tags: [],
- visibility: Visibility.Public,
- leakPeriodDate: '2022-01-14T16:10:11+0000',
- isFavorite: true,
- },
- {
- key: 'org.sonarsource.api.plugin:sonar-plugin-api',
- name: 'sonar-plugin-api',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-21T00:05:56+0000',
- tags: ['sonarqube'],
- visibility: Visibility.Public,
- leakPeriodDate: '2023-08-10T12:28:45+0000',
- isAiCodeFixEnabled: true,
- },
- {
- key: 'org.sonarsource.javascript:javascript',
- name: 'SonarJS',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-21T09:52:44+0000',
- tags: [],
- visibility: Visibility.Public,
- leakPeriodDate: '2023-08-07T00:10:25+0000',
- },
- {
- key: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- name: 'SonarLint Core',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-08T13:51:31+0000',
- tags: ['sonarlint'],
- visibility: Visibility.Public,
- leakPeriodDate: '2023-08-07T08:44:02+0000',
- },
- {
- key: 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent',
- name: 'SonarLint Daemon',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2022-03-15T07:59:51+0000',
- tags: [],
- visibility: Visibility.Public,
- leakPeriodDate: '2020-07-10T12:07:28+0000',
- },
- {
- key: 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent',
- name: 'SonarLint for Eclipse',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-18T12:14:54+0000',
- tags: ['sonarlint'],
- visibility: Visibility.Public,
- leakPeriodDate: '2023-07-24T20:24:58+0000',
- },
- {
- key: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- name: 'SonarLint for IntelliJ IDEA',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-17T08:46:18+0000',
- tags: ['sonarlint'],
- visibility: Visibility.Public,
- leakPeriodDate: '2023-08-14T09:50:38+0000',
- },
- {
- key: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- name: 'SonarLint for VSCode',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-15T08:16:48+0000',
- tags: ['sonarlint'],
- visibility: Visibility.Public,
- leakPeriodDate: '2023-08-03T09:01:23+0000',
- },
- {
- key: 'sonarlint-omnisharp-dotnet',
- name: 'sonarlint-omnisharp-dotnet',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-14T08:44:19+0000',
- tags: [],
- visibility: Visibility.Public,
- leakPeriodDate: '2023-07-26T08:13:47+0000',
- },
- {
- key: 'sonarqube',
- name: 'SonarQube',
- qualifier: ComponentQualifier.Project,
- analysisDate: '2023-08-16T20:33:15+0000',
- tags: [],
- visibility: Visibility.Public,
- leakPeriodDate: '2023-06-19T20:29:31+0000',
- isFavorite: true,
- },
- ];
-}
-
-export function mockFacets() {
- return [
- {
- property: 'coverage',
- values: [
- {
- val: 'NO_DATA',
- count: 0,
- },
- {
- val: '*-30.0',
- count: 20,
- },
- {
- val: '30.0-50.0',
- count: 2,
- },
- {
- val: '50.0-70.0',
- count: 3,
- },
- {
- val: '70.0-80.0',
- count: 1,
- },
- {
- val: '80.0-*',
- count: 8,
- },
- ],
- },
- {
- property: 'alert_status',
- values: [
- {
- val: 'ERROR',
- count: 0,
- },
- {
- val: 'OK',
- count: 34,
- },
- ],
- },
- {
- property: 'reliability_rating',
- values: [
- {
- val: '1',
- count: 35,
- },
- {
- val: '2',
- count: 0,
- },
- {
- val: '3',
- count: 30,
- },
- {
- val: '4',
- count: 4,
- },
- {
- val: '5',
- count: 0,
- },
- ],
- },
- {
- property: 'duplicated_lines_density',
- values: [
- {
- val: '*-3.0',
- count: 34,
- },
- {
- val: '3.0-5.0',
- count: 0,
- },
- {
- val: '5.0-10.0',
- count: 0,
- },
- {
- val: '10.0-20.0',
- count: 0,
- },
- {
- val: '20.0-*',
- count: 0,
- },
- {
- val: 'NO_DATA',
- count: 0,
- },
- ],
- },
- {
- property: 'languages',
- values: [
- {
- val: 'cpp',
- count: 20,
- },
- {
- val: 'java',
- count: 11,
- },
- {
- val: 'xml',
- count: 6,
- },
- {
- val: 'ts',
- count: 4,
- },
- {
- val: 'css',
- count: 2,
- },
- {
- val: 'web',
- count: 2,
- },
- {
- val: 'cs',
- count: 1,
- },
- {
- val: 'js',
- count: 1,
- },
- {
- val: 'kotlin',
- count: 1,
- },
- {
- val: 'py',
- count: 1,
- },
- ],
- },
- {
- property: 'security_rating',
- values: [
- {
- val: '1',
- count: 34,
- },
- {
- val: '2',
- count: 0,
- },
- {
- val: '3',
- count: 0,
- },
- {
- val: '4',
- count: 0,
- },
- {
- val: '5',
- count: 0,
- },
- ],
- },
- {
- property: 'qualifier',
- values: [
- {
- val: 'APP',
- count: 0,
- },
- {
- val: 'TRK',
- count: 34,
- },
- ],
- },
- {
- property: 'ncloc',
- values: [
- {
- val: '*-1000.0',
- count: 21,
- },
- {
- val: '1000.0-10000.0',
- count: 5,
- },
- {
- val: '10000.0-100000.0',
- count: 7,
- },
- {
- val: '100000.0-500000.0',
- count: 1,
- },
- {
- val: '500000.0-*',
- count: 0,
- },
- ],
- },
- {
- property: 'security_review_rating',
- values: [
- {
- val: '1',
- count: 30,
- },
- {
- val: '2',
- count: 0,
- },
- {
- val: '3',
- count: 1,
- },
- {
- val: '4',
- count: 0,
- },
- {
- val: '5',
- count: 3,
- },
- ],
- },
- {
- property: 'tags',
- values: [
- {
- val: 'sonarlint',
- count: 4,
- },
- {
- val: 'sonarqube',
- count: 2,
- },
- {
- val: 'platform',
- count: 1,
- },
- {
- val: 'scanner',
- count: 1,
- },
- ],
- },
- {
- property: 'sqale_rating',
- values: [
- {
- val: '1',
- count: 14,
- },
- {
- val: '2',
- count: 20,
- },
- {
- val: '3',
- count: 0,
- },
- {
- val: '4',
- count: 0,
- },
- {
- val: '5',
- count: 0,
- },
- ],
- },
- ];
-}
-
-export function mockProjectMeasures() {
- return {
- 'org.sonarsource.orchestrator:orchestrator-parent': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'org.sonarsource.orchestrator:orchestrator-parent',
- },
- bugs: {
- metric: 'bugs',
- value: '8',
- component: 'org.sonarsource.orchestrator:orchestrator-parent',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '248',
- component: 'org.sonarsource.orchestrator:orchestrator-parent',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '89.2',
- component: 'org.sonarsource.orchestrator:orchestrator-parent',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.0',
- component: 'org.sonarsource.orchestrator:orchestrator-parent',
- bestValue: true,
- },
- new_lines: {
- metric: 'new_lines',
- value: '69',
- component: 'org.sonarsource.orchestrator:orchestrator-parent',
- },
- ncloc: {
- metric: 'ncloc',
- value: '6669',
- component: 'org.sonarsource.orchestrator:orchestrator-parent',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'java=6273;xml=396',
- component: 'org.sonarsource.orchestrator:orchestrator-parent',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '4.0',
- component: 'org.sonarsource.orchestrator:orchestrator-parent',
- bestValue: false,
- },
- security_hotspots_reviewed: {
- metric: 'security_hotspots_reviewed',
- value: '0.0',
- component: 'org.sonarsource.orchestrator:orchestrator-parent',
- bestValue: false,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'org.sonarsource.orchestrator:orchestrator-parent',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '5.0',
- component: 'org.sonarsource.orchestrator:orchestrator-parent',
- bestValue: false,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '1.0',
- component: 'org.sonarsource.orchestrator:orchestrator-parent',
- bestValue: true,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'org.sonarsource.orchestrator:orchestrator-parent',
- bestValue: true,
- },
- },
- 'org.sonarsource.python:python': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'org.sonarsource.python:python',
- },
- bugs: {
- metric: 'bugs',
- value: '5',
- component: 'org.sonarsource.python:python',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '396',
- component: 'org.sonarsource.python:python',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '98.4',
- component: 'org.sonarsource.python:python',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.2',
- component: 'org.sonarsource.python:python',
- bestValue: false,
- },
- new_lines: {
- metric: 'new_lines',
- value: '59',
- component: 'org.sonarsource.python:python',
- },
- ncloc: { metric: 'ncloc', value: '46759', component: 'org.sonarsource.python:python' },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'java=44895;py=827;xml=1037',
- component: 'org.sonarsource.python:python',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '4.0',
- component: 'org.sonarsource.python:python',
- bestValue: false,
- },
- security_hotspots_reviewed: {
- metric: 'security_hotspots_reviewed',
- value: '50.0',
- component: 'org.sonarsource.python:python',
- bestValue: false,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'org.sonarsource.python:python',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '3.0',
- component: 'org.sonarsource.python:python',
- bestValue: false,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '1.0',
- component: 'org.sonarsource.python:python',
- bestValue: true,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'org.sonarsource.python:python',
- bestValue: true,
- },
- },
- 'org.sonarsource.javascript:javascript': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'org.sonarsource.javascript:javascript',
- },
- bugs: {
- metric: 'bugs',
- value: '3',
- component: 'org.sonarsource.javascript:javascript',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '953',
- component: 'org.sonarsource.javascript:javascript',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '97.6',
- component: 'org.sonarsource.javascript:javascript',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.1',
- component: 'org.sonarsource.javascript:javascript',
- bestValue: false,
- },
- new_lines: {
- metric: 'new_lines',
- value: '189',
- component: 'org.sonarsource.javascript:javascript',
- },
- ncloc: {
- metric: 'ncloc',
- value: '59689',
- component: 'org.sonarsource.javascript:javascript',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'java=14530;ts=29254;web=15905',
- component: 'org.sonarsource.javascript:javascript',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '3.0',
- component: 'org.sonarsource.javascript:javascript',
- bestValue: false,
- },
- security_hotspots_reviewed: {
- metric: 'security_hotspots_reviewed',
- value: '100.0',
- component: 'org.sonarsource.javascript:javascript',
- bestValue: true,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'org.sonarsource.javascript:javascript',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'org.sonarsource.javascript:javascript',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '1.0',
- component: 'org.sonarsource.javascript:javascript',
- bestValue: true,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'org.sonarsource.javascript:javascript',
- bestValue: true,
- },
- },
- 'org.sonarsource.sonarlint.core:sonarlint-core-parent': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- },
- bugs: {
- metric: 'bugs',
- value: '1',
- component: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '443',
- component: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '91.1',
- component: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.7',
- component: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- bestValue: false,
- },
- new_lines: {
- metric: 'new_lines',
- value: '24',
- component: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- },
- ncloc: {
- metric: 'ncloc',
- value: '30686',
- component: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'java=28676;xml=2010',
- component: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '3.0',
- component: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- bestValue: false,
- },
- security_hotspots_reviewed: {
- metric: 'security_hotspots_reviewed',
- value: '100.0',
- component: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- bestValue: true,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- bestValue: true,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'org.sonarsource.sonarlint.core:sonarlint-core-parent',
- bestValue: true,
- },
- },
- 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent',
- },
- bugs: {
- metric: 'bugs',
- value: '2',
- component: 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '51',
- component: 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '42.9',
- component: 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '2.0',
- component: 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent',
- bestValue: false,
- },
- new_lines: {
- metric: 'new_lines',
- value: '38',
- component: 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent',
- },
- ncloc: {
- metric: 'ncloc',
- value: '938',
- component: 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'java=710;xml=228',
- component: 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '3.0',
- component: 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent',
- bestValue: false,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent',
- bestValue: true,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'org.sonarsource.sonarlint.daemon:sonarlint-daemon-parent',
- bestValue: true,
- },
- },
- 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent',
- },
- bugs: {
- metric: 'bugs',
- value: '15',
- component: 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '159',
- component: 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '64.7',
- component: 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.8',
- component: 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent',
- bestValue: false,
- },
- new_lines: {
- metric: 'new_lines',
- value: '26',
- component: 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent',
- },
- ncloc: {
- metric: 'ncloc',
- value: '22236',
- component: 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'java=21526;xml=710',
- component: 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '3.0',
- component: 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent',
- bestValue: false,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent',
- bestValue: true,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'org.sonarsource.sonarlint.eclipse:sonarlint-eclipse-parent',
- bestValue: true,
- },
- },
- 'org.sonarsource.sonarlint.intellij:sonarlint-intellij': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- },
- bugs: {
- metric: 'bugs',
- value: '8',
- component: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '154',
- component: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '35.1',
- component: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.0',
- component: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- bestValue: true,
- },
- new_lines: {
- metric: 'new_lines',
- value: '76',
- component: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- },
- ncloc: {
- metric: 'ncloc',
- value: '23676',
- component: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'java=17147;kotlin=6529',
- component: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '3.0',
- component: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- bestValue: false,
- },
- security_hotspots_reviewed: {
- metric: 'security_hotspots_reviewed',
- value: '100.0',
- component: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- bestValue: true,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- bestValue: true,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'org.sonarsource.sonarlint.intellij:sonarlint-intellij',
- bestValue: true,
- },
- },
- 'org.sonarsource.sonarlint.vscode:sonarlint-vscode': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- },
- bugs: {
- metric: 'bugs',
- value: '13',
- component: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '31',
- component: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '66.9',
- component: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.0',
- component: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- bestValue: true,
- },
- new_lines: {
- metric: 'new_lines',
- value: '4',
- component: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- },
- ncloc: {
- metric: 'ncloc',
- value: '5704',
- component: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'ts=5704',
- component: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '4.0',
- component: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- bestValue: false,
- },
- security_hotspots_reviewed: {
- metric: 'security_hotspots_reviewed',
- value: '100.0',
- component: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- bestValue: true,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '1.0',
- component: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- bestValue: true,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'org.sonarsource.sonarlint.vscode:sonarlint-vscode',
- bestValue: true,
- },
- },
- sonarqube: {
- alert_status: { metric: 'alert_status', value: 'OK', component: 'sonarqube' },
- bugs: { metric: 'bugs', value: '21', component: 'sonarqube', bestValue: false },
- code_smells: {
- metric: 'code_smells',
- value: '3513',
- component: 'sonarqube',
- bestValue: false,
- },
- coverage: { metric: 'coverage', value: '91.1', component: 'sonarqube', bestValue: false },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.7',
- component: 'sonarqube',
- bestValue: false,
- },
- new_lines: {
- metric: 'new_lines',
- value: '389',
- component: 'sonarqube',
- },
- ncloc: { metric: 'ncloc', value: '338389', component: 'sonarqube' },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'css=7331;java=209272;js=180;ts=121606',
- component: 'sonarqube',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '4.0',
- component: 'sonarqube',
- bestValue: false,
- },
- security_hotspots_reviewed: {
- metric: 'security_hotspots_reviewed',
- value: '100.0',
- component: 'sonarqube',
- bestValue: true,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'sonarqube',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'sonarqube',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '1.0',
- component: 'sonarqube',
- bestValue: true,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'sonarqube',
- bestValue: true,
- },
- },
- 'linux-autotools-gitlab-ci-sq_AYAYuaB5_scXWD3WLpNC': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'linux-autotools-gitlab-ci-sq_AYAYuaB5_scXWD3WLpNC',
- },
- bugs: {
- metric: 'bugs',
- value: '1',
- component: 'linux-autotools-gitlab-ci-sq_AYAYuaB5_scXWD3WLpNC',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '8',
- component: 'linux-autotools-gitlab-ci-sq_AYAYuaB5_scXWD3WLpNC',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '0.0',
- component: 'linux-autotools-gitlab-ci-sq_AYAYuaB5_scXWD3WLpNC',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.0',
- component: 'linux-autotools-gitlab-ci-sq_AYAYuaB5_scXWD3WLpNC',
- bestValue: true,
- },
- ncloc: {
- metric: 'ncloc',
- value: '21',
- component: 'linux-autotools-gitlab-ci-sq_AYAYuaB5_scXWD3WLpNC',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'cpp=21',
- component: 'linux-autotools-gitlab-ci-sq_AYAYuaB5_scXWD3WLpNC',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '3.0',
- component: 'linux-autotools-gitlab-ci-sq_AYAYuaB5_scXWD3WLpNC',
- bestValue: false,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'linux-autotools-gitlab-ci-sq_AYAYuaB5_scXWD3WLpNC',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'linux-autotools-gitlab-ci-sq_AYAYuaB5_scXWD3WLpNC',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '2.0',
- component: 'linux-autotools-gitlab-ci-sq_AYAYuaB5_scXWD3WLpNC',
- bestValue: false,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'linux-autotools-gitlab-ci-sq_AYAYuaB5_scXWD3WLpNC',
- bestValue: true,
- },
- },
- 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus',
- },
- bugs: {
- metric: 'bugs',
- value: '1',
- component: 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '8',
- component: 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '0.0',
- component: 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.0',
- component: 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus',
- bestValue: true,
- },
- new_lines: {
- metric: 'new_lines',
- value: '0',
- component: 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus',
- },
- ncloc: {
- metric: 'ncloc',
- value: '21',
- component: 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'cpp=21',
- component: 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '3.0',
- component: 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus',
- bestValue: false,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '2.0',
- component: 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus',
- bestValue: false,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'linux-cmake-gitlab-ci-vulnerability-reports-sq_AYnApJhM3jwBWLzm5nus',
- bestValue: true,
- },
- },
- 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9',
- },
- bugs: {
- metric: 'bugs',
- value: '1',
- component: 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '8',
- component: 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '0.0',
- component: 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.0',
- component: 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9',
- bestValue: true,
- },
- new_lines: {
- metric: 'new_lines',
- value: '1',
- component: 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9',
- },
- ncloc: {
- metric: 'ncloc',
- value: '21',
- component: 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'cpp=21',
- component: 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '3.0',
- component: 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9',
- bestValue: false,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '2.0',
- component: 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9',
- bestValue: false,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'macos-cmake-azure-sq_AYAYt3nkMi_-8diYBjJ9',
- bestValue: true,
- },
- },
- 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK',
- },
- bugs: {
- metric: 'bugs',
- value: '1',
- component: 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '8',
- component: 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '0.0',
- component: 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.0',
- component: 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK',
- bestValue: true,
- },
- new_lines: {
- metric: 'new_lines',
- value: '4',
- component: 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK',
- },
- ncloc: {
- metric: 'ncloc',
- value: '21',
- component: 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'cpp=21',
- component: 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '3.0',
- component: 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK',
- bestValue: false,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '2.0',
- component: 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK',
- bestValue: false,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'macos-cmake-compdb-gh-actions-sq_AYCKCNO5nBwJQJjdVHcK',
- bestValue: true,
- },
- },
- 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_',
- },
- bugs: {
- metric: 'bugs',
- value: '1',
- component: 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '8',
- component: 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '0.0',
- component: 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.0',
- component: 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_',
- bestValue: true,
- },
- new_lines: {
- metric: 'new_lines',
- value: '3',
- component: 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_',
- },
- ncloc: {
- metric: 'ncloc',
- value: '21',
- component: 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'cpp=21',
- component: 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '3.0',
- component: 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_',
- bestValue: false,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '2.0',
- component: 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_',
- bestValue: false,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'macos-cmake-gh-actions-sq_AYAYs22XMi_-8diYBjH_',
- bestValue: true,
- },
- },
- 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua',
- },
- bugs: {
- metric: 'bugs',
- value: '1',
- component: 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '7',
- component: 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '0.0',
- component: 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.0',
- component: 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua',
- bestValue: true,
- },
- new_lines: {
- metric: 'new_lines',
- value: '3',
- component: 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua',
- },
- ncloc: {
- metric: 'ncloc',
- value: '21',
- component: 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'cpp=21',
- component: 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '3.0',
- component: 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua',
- bestValue: false,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '2.0',
- component: 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua',
- bestValue: false,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'macos-xcode-azure-sq_AYAYr_NcQUWaRZD6h1ua',
- bestValue: true,
- },
- },
- 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ',
- },
- bugs: {
- metric: 'bugs',
- value: '1',
- component: 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '7',
- component: 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '0.0',
- component: 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.0',
- component: 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ',
- bestValue: true,
- },
- new_lines: {
- metric: 'new_lines',
- value: '1',
- component: 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ',
- },
- ncloc: {
- metric: 'ncloc',
- value: '21',
- component: 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'cpp=21',
- component: 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '3.0',
- component: 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ',
- bestValue: false,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '2.0',
- component: 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ',
- bestValue: false,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'macos-xcode-gh-actions-sq_AYAYsHe3y0k_ZlpkA-kQ',
- bestValue: true,
- },
- },
- 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc',
- },
- bugs: {
- metric: 'bugs',
- value: '1',
- component: 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '7',
- component: 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '0.0',
- component: 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.0',
- component: 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc',
- bestValue: true,
- },
- new_lines: {
- metric: 'new_lines',
- value: '19',
- component: 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc',
- },
- ncloc: {
- metric: 'ncloc',
- value: '21',
- component: 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'cpp=21',
- component: 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '3.0',
- component: 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc',
- bestValue: false,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '2.0',
- component: 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc',
- bestValue: false,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'macos-xcode-otherci-sq_AYAYrm2RwUGdjBp0BJBc',
- bestValue: true,
- },
- },
- 'rspec-frontend': {
- alert_status: { metric: 'alert_status', value: 'OK', component: 'rspec-frontend' },
- bugs: { metric: 'bugs', value: '4', component: 'rspec-frontend', bestValue: false },
- code_smells: {
- metric: 'code_smells',
- value: '59',
- component: 'rspec-frontend',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '88.5',
- component: 'rspec-frontend',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.0',
- component: 'rspec-frontend',
- bestValue: true,
- },
- new_lines: {
- metric: 'new_lines',
- value: '0',
- component: 'rspec-frontend',
- },
- ncloc: { metric: 'ncloc', value: '3128', component: 'rspec-frontend' },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'css=102;ts=1963;web=1063',
- component: 'rspec-frontend',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '4.0',
- component: 'rspec-frontend',
- bestValue: false,
- },
- security_hotspots_reviewed: {
- metric: 'security_hotspots_reviewed',
- value: '100.0',
- component: 'rspec-frontend',
- bestValue: true,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'rspec-frontend',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'rspec-frontend',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '1.0',
- component: 'rspec-frontend',
- bestValue: true,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'rspec-frontend',
- bestValue: true,
- },
- },
- 'org.sonarsource.api.plugin:sonar-plugin-api': {
- alert_status: {
- metric: 'alert_status',
- value: 'OK',
- component: 'org.sonarsource.api.plugin:sonar-plugin-api',
- },
- bugs: {
- metric: 'bugs',
- value: '13',
- component: 'org.sonarsource.api.plugin:sonar-plugin-api',
- bestValue: false,
- },
- code_smells: {
- metric: 'code_smells',
- value: '662',
- component: 'org.sonarsource.api.plugin:sonar-plugin-api',
- bestValue: false,
- },
- coverage: {
- metric: 'coverage',
- value: '80.0',
- component: 'org.sonarsource.api.plugin:sonar-plugin-api',
- bestValue: false,
- },
- duplicated_lines_density: {
- metric: 'duplicated_lines_density',
- value: '0.6',
- component: 'org.sonarsource.api.plugin:sonar-plugin-api',
- bestValue: false,
- },
- new_lines: {
- metric: 'new_lines',
- value: '642',
- component: 'org.sonarsource.api.plugin:sonar-plugin-api',
- },
- ncloc: {
- metric: 'ncloc',
- value: '15642',
- component: 'org.sonarsource.api.plugin:sonar-plugin-api',
- },
- ncloc_language_distribution: {
- metric: 'ncloc_language_distribution',
- value: 'java=15642',
- component: 'org.sonarsource.api.plugin:sonar-plugin-api',
- },
- reliability_rating: {
- metric: 'reliability_rating',
- value: '3.0',
- component: 'org.sonarsource.api.plugin:sonar-plugin-api',
- bestValue: false,
- },
- security_hotspots_reviewed: {
- metric: 'security_hotspots_reviewed',
- value: '100.0',
- component: 'org.sonarsource.api.plugin:sonar-plugin-api',
- bestValue: true,
- },
- security_rating: {
- metric: 'security_rating',
- value: '1.0',
- component: 'org.sonarsource.api.plugin:sonar-plugin-api',
- bestValue: true,
- },
- security_review_rating: {
- metric: 'security_review_rating',
- value: '1.0',
- component: 'org.sonarsource.api.plugin:sonar-plugin-api',
- bestValue: true,
- },
- sqale_rating: {
- metric: 'sqale_rating',
- value: '1.0',
- component: 'org.sonarsource.api.plugin:sonar-plugin-api',
- bestValue: true,
- },
- vulnerabilities: {
- metric: 'vulnerabilities',
- value: '0',
- component: 'org.sonarsource.api.plugin:sonar-plugin-api',
- bestValue: true,
- },
- },
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/data/qualityProfiles.ts b/server/sonar-web/src/main/js/api/mocks/data/qualityProfiles.ts
deleted file mode 100644
index 92c4a2be777..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/data/qualityProfiles.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { mockQualityProfile } from '../../../helpers/testMocks';
-import { QP_1, QP_2, QP_2_Parent, QP_3, QP_4, QP_5, QP_6 } from './ids';
-
-export function mockQualityProfilesList() {
- return [
- mockQualityProfile({
- key: QP_1,
- name: 'QP Foo',
- language: 'java',
- languageName: 'Java',
- actions: { edit: true },
- }),
- mockQualityProfile({
- key: QP_2_Parent,
- name: 'QP Bar Parent',
- language: 'py',
- languageName: 'Python',
- }),
- mockQualityProfile({
- key: QP_2,
- name: 'QP Bar',
- language: 'py',
- languageName: 'Python',
- isInherited: true,
- parentKey: QP_2_Parent,
- parentName: 'QP Bar Parent',
- }),
- mockQualityProfile({ key: QP_3, name: 'QP FooBar', language: 'java', languageName: 'Java' }),
- mockQualityProfile({
- key: QP_4,
- name: 'QP FooBarBaz',
- language: 'java',
- languageName: 'Java',
- }),
- mockQualityProfile({
- key: QP_5,
- name: 'QP FooBaz',
- language: 'java',
- languageName: 'Java',
- isInherited: true,
- parentKey: QP_4,
- parentName: 'QP FooBarBaz',
- }),
- mockQualityProfile({
- key: QP_6,
- isBuiltIn: true,
- name: 'QP Qux',
- language: 'java',
- languageName: 'Java',
- }),
- ];
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/data/rules.ts b/server/sonar-web/src/main/js/api/mocks/data/rules.ts
deleted file mode 100644
index 9da3532c4f4..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/data/rules.ts
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { RuleDescriptionSections } from '../../../apps/coding-rules/rule';
-import { mockRule, mockRuleActivation, mockRuleDetails } from '../../../helpers/testMocks';
-import {
- CleanCodeAttributeCategory,
- SoftwareImpactSeverity,
- SoftwareQuality,
-} from '../../../types/clean-code-taxonomy';
-import { RuleStatus } from '../../../types/rules';
-import {
- ADVANCED_RULE,
- QP_1,
- QP_2,
- QP_2_Parent,
- QP_4,
- QP_5,
- QP_6,
- RULE_1,
- RULE_10,
- RULE_11,
- RULE_12,
- RULE_2,
- RULE_3,
- RULE_4,
- RULE_5,
- RULE_6,
- RULE_7,
- RULE_8,
- RULE_9,
- S131_RULE,
- S6069_RULE,
- SIMPLE_RULE,
-} from './ids';
-
-export function mockRuleList() {
- return [
- mockRule({
- key: SIMPLE_RULE,
- name: 'Simple rule',
- lang: 'java',
- langName: 'Java',
- type: 'CODE_SMELL',
- }),
- mockRule({
- key: ADVANCED_RULE,
- name: 'Advanced rule',
- lang: 'web',
- langName: 'HTML',
- type: 'VULNERABILITY',
- }),
- mockRule({
- key: S6069_RULE,
- lang: 'cpp',
- langName: 'C++',
- name: 'Security hotspot rule',
- type: 'SECURITY_HOTSPOT',
- }),
- mockRule({
- key: S131_RULE,
- name: '"CASE" expressions should end with "ELSE" clauses',
- lang: 'tsql',
- langName: 'T-SQL',
- }),
- ];
-}
-
-export const resourceContent = 'Some link <a href="http://example.com">Awsome Reading</a>';
-export const introTitle = 'Introduction to this rule';
-export const rootCauseContent = 'Root cause';
-export const howToFixContent = 'This is how to fix';
-
-export function mockRuleDetailsList() {
- return [
- mockRuleDetails({
- key: RULE_1,
- repo: 'repo1',
- type: 'BUG',
- lang: 'java',
- langName: 'Java',
- name: 'Awsome java rule',
- tags: ['awesome'],
- params: [
- { key: '1', type: 'TEXT', htmlDesc: 'html description for key 1' },
- { key: '2', type: 'NUMBER', defaultValue: 'default value for key 2' },
- ],
- impacts: [
- {
- softwareQuality: SoftwareQuality.Maintainability,
- severity: SoftwareImpactSeverity.Medium,
- },
- ],
- }),
- mockRuleDetails({
- key: RULE_2,
- repo: 'repo1',
- name: 'Hot hotspot',
- tags: ['awesome'],
- type: 'SECURITY_HOTSPOT',
- lang: 'js',
- descriptionSections: [
- { key: RuleDescriptionSections.INTRODUCTION, content: introTitle },
- { key: RuleDescriptionSections.ROOT_CAUSE, content: rootCauseContent },
- { key: RuleDescriptionSections.HOW_TO_FIX, content: howToFixContent },
- { key: RuleDescriptionSections.ASSESS_THE_PROBLEM, content: 'Assess' },
- {
- key: RuleDescriptionSections.RESOURCES,
- content: resourceContent,
- },
- ],
- impacts: [],
- cleanCodeAttributeCategory: undefined,
- cleanCodeAttribute: undefined,
- langName: 'JavaScript',
- }),
- mockRuleDetails({
- key: RULE_3,
- repo: 'repo2',
- name: 'Unknown rule',
- impacts: [
- { softwareQuality: SoftwareQuality.Maintainability, severity: SoftwareImpactSeverity.Low },
- ],
- lang: 'js',
- langName: 'JavaScript',
- }),
- mockRuleDetails({
- key: RULE_4,
- type: 'BUG',
- lang: 'c',
- langName: 'C',
- name: 'Awsome C rule',
- }),
- mockRuleDetails({
- key: RULE_5,
- type: 'VULNERABILITY',
- lang: 'py',
- langName: 'Python',
- cleanCodeAttributeCategory: CleanCodeAttributeCategory.Consistent,
- name: 'Awsome Python rule',
- descriptionSections: [
- { key: RuleDescriptionSections.INTRODUCTION, content: introTitle },
- { key: RuleDescriptionSections.ROOT_CAUSE, content: rootCauseContent },
- { key: RuleDescriptionSections.HOW_TO_FIX, content: howToFixContent },
- {
- key: RuleDescriptionSections.RESOURCES,
- content: resourceContent,
- },
- ],
- impacts: [
- {
- softwareQuality: SoftwareQuality.Maintainability,
- severity: SoftwareImpactSeverity.Medium,
- },
- ],
- }),
- mockRuleDetails({
- key: RULE_6,
- type: 'BUG',
- lang: 'py',
- langName: 'Python',
- name: 'Bad Python rule',
- isExternal: true,
- descriptionSections: undefined,
- impacts: [
- {
- softwareQuality: SoftwareQuality.Maintainability,
- severity: SoftwareImpactSeverity.Medium,
- },
- {
- softwareQuality: SoftwareQuality.Security,
- severity: SoftwareImpactSeverity.Low,
- },
- ],
- }),
- mockRuleDetails({
- key: RULE_7,
- type: 'VULNERABILITY',
- severity: 'MINOR',
- lang: 'py',
- langName: 'Python',
- name: 'Python rule with context',
- descriptionSections: [
- {
- key: RuleDescriptionSections.INTRODUCTION,
- content: 'Introduction to this rule with context',
- },
- {
- key: RuleDescriptionSections.HOW_TO_FIX,
- content: 'This is how to fix for spring',
- context: { key: 'spring', displayName: 'Spring' },
- },
- {
- key: RuleDescriptionSections.HOW_TO_FIX,
- content: 'This is how to fix for spring boot',
- context: { key: 'spring_boot', displayName: 'Spring boot' },
- },
- {
- key: RuleDescriptionSections.RESOURCES,
- content: resourceContent,
- },
- ],
- impacts: [
- {
- softwareQuality: SoftwareQuality.Maintainability,
- severity: SoftwareImpactSeverity.Low,
- },
- ],
- }),
- mockRuleDetails({
- key: RULE_8,
- type: 'BUG',
- severity: 'MINOR',
- lang: 'py',
- langName: 'Python',
- tags: ['awesome'],
- name: 'Template rule',
- params: [
- { key: '1', type: 'TEXT', htmlDesc: 'html description for key 1' },
- { key: '2', type: 'NUMBER', defaultValue: 'default value for key 2' },
- ],
- isTemplate: true,
- }),
- mockRuleDetails({
- key: RULE_9,
- type: 'BUG',
- severity: 'MINOR',
- impacts: [
- { softwareQuality: SoftwareQuality.Reliability, severity: SoftwareImpactSeverity.Low },
- ],
- lang: 'py',
- langName: 'Python',
- tags: ['awesome', 'cute'],
- name: 'Custom Rule based on rule8',
- params: [
- { key: '1', type: 'TEXT', htmlDesc: 'html description for key 1' },
- { key: '2', type: 'NUMBER', defaultValue: 'default value for key 2' },
- ],
- templateKey: RULE_8,
- }),
- mockRuleDetails({
- createdAt: '2022-12-16T17:26:54+0100',
- key: RULE_10,
- type: 'VULNERABILITY',
- severity: 'MINOR',
- lang: 'py',
- langName: 'Python',
- tags: ['awesome'],
- name: 'Awesome Python rule with education principles',
- descriptionSections: [
- { key: RuleDescriptionSections.INTRODUCTION, content: introTitle },
- { key: RuleDescriptionSections.HOW_TO_FIX, content: rootCauseContent },
- {
- key: RuleDescriptionSections.RESOURCES,
- content: resourceContent,
- },
- ],
- impacts: [
- {
- softwareQuality: SoftwareQuality.Maintainability,
- severity: SoftwareImpactSeverity.Low,
- },
- {
- softwareQuality: SoftwareQuality.Reliability,
- severity: SoftwareImpactSeverity.High,
- },
- ],
- educationPrinciples: ['defense_in_depth', 'never_trust_user_input'],
- }),
- mockRuleDetails({
- key: RULE_11,
- type: 'BUG',
- lang: 'java',
- langName: 'Java',
- name: 'Common java rule',
- }),
- mockRuleDetails({
- key: RULE_12,
- type: 'BUG',
- severity: 'MINOR',
- lang: 'py',
- langName: 'Python',
- tags: ['awesome'],
- name: 'Deleted custom rule based on rule8',
- templateKey: RULE_8,
- status: RuleStatus.Removed,
- }),
- ];
-}
-
-export function mockRulesActivationsInQP() {
- return {
- [RULE_1]: [mockRuleActivation({ qProfile: QP_1 }), mockRuleActivation({ qProfile: QP_6 })],
- [RULE_7]: [
- mockRuleActivation({
- qProfile: QP_2,
- impacts: [
- {
- softwareQuality: SoftwareQuality.Maintainability,
- severity: SoftwareImpactSeverity.Medium,
- },
- { softwareQuality: SoftwareQuality.Reliability, severity: SoftwareImpactSeverity.High },
- { softwareQuality: SoftwareQuality.Security, severity: SoftwareImpactSeverity.High },
- ],
- }),
- ],
- [RULE_8]: [mockRuleActivation({ qProfile: QP_2 })],
- [RULE_9]: [
- mockRuleActivation({
- qProfile: QP_2,
- params: [
- { key: '1', value: '' },
- { key: '2', value: 'default value for key 2' },
- ],
- inherit: 'INHERITED',
- impacts: [
- { softwareQuality: SoftwareQuality.Reliability, severity: SoftwareImpactSeverity.Medium },
- ],
- }),
- ],
- [RULE_10]: [
- mockRuleActivation({
- qProfile: QP_2,
- inherit: 'OVERRIDES',
- impacts: [
- {
- softwareQuality: SoftwareQuality.Maintainability,
- severity: SoftwareImpactSeverity.Medium,
- },
- {
- softwareQuality: SoftwareQuality.Reliability,
- severity: SoftwareImpactSeverity.Info,
- },
- ],
- prioritizedRule: true,
- }),
- mockRuleActivation({
- qProfile: QP_2_Parent,
- severity: 'MINOR',
- impacts: [
- {
- softwareQuality: SoftwareQuality.Maintainability,
- severity: SoftwareImpactSeverity.Low,
- },
- {
- softwareQuality: SoftwareQuality.Reliability,
- severity: SoftwareImpactSeverity.Blocker,
- },
- ],
- }),
- ],
- [RULE_11]: [
- mockRuleActivation({ qProfile: QP_4 }),
- mockRuleActivation({ qProfile: QP_5, inherit: 'INHERITED' }),
- ],
- };
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/data/sources.ts b/server/sonar-web/src/main/js/api/mocks/data/sources.ts
deleted file mode 100644
index 7b1b1d28486..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/data/sources.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export const mockIpynbFile = JSON.stringify({
- cells: [
- {
- cell_type: 'markdown',
- metadata: {},
- source: ['# Learning a cosine with keras'],
- },
- {
- cell_type: 'code',
- execution_count: 2,
- metadata: {
- collapsed: false,
- jupyter: {
- outputs_hidden: false,
- },
- },
- outputs: [
- {
- name: 'stdout',
- output_type: 'stream',
- text: ['(7500,)\n', '(2500,)\n'],
- },
- ],
- source: [
- 'import numpy as np\n',
- 'import sklearn.cross_validation as skcv\n',
- '#x = np.linspace(0, 5*np.pi, num=10000, dtype=np.float32)\n',
- 'x = np.linspace(0, 4*np.pi, num=10000, dtype=np.float32)\n',
- 'y = np.cos(x)\n',
- '\n',
- 'train, test = skcv.train_test_split(np.arange(x.shape[0]))\n',
- 'print train.shape\n',
- 'print test.shape',
- ],
- },
- {
- cell_type: 'code',
- execution_count: 3,
- metadata: {
- collapsed: false,
- jupyter: {
- outputs_hidden: false,
- },
- },
- outputs: [
- {
- data: {
- 'text/plain': ['[<matplotlib.lines.Line2D at 0x7fb588176b90>]'],
- },
- execution_count: 3,
- metadata: {},
- output_type: 'execute_result',
- },
- {
- data: {
- 'image/png':
- 'iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAG0lEQVR4nGIJn1mo28/GzPDiV+yTNYAAAAD//yPBBfrGshAGAAAAAElFTkSuQmCC',
- 'text/plain': ['<matplotlib.figure.Figure at 0x7fb58e57c850>'],
- },
- metadata: {},
- output_type: 'display_data',
- },
- ],
- source: ['import pylab as pl\n', '%matplotlib inline\n', 'pl.plot(x, y)'],
- },
- {
- cell_type: 'markdown',
- metadata: {},
- source: '# markdown as a string',
- },
- ],
-});
diff --git a/server/sonar-web/src/main/js/api/mocks/data/utils.ts b/server/sonar-web/src/main/js/api/mocks/data/utils.ts
deleted file mode 100644
index f6f592a32e7..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/data/utils.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { flatMap, map } from 'lodash';
-import { Component } from '../../../types/types';
-import { ComponentTree } from './components';
-
-export function isLeaf(node: ComponentTree) {
- return node.children.length === 0;
-}
-
-export function listChildComponent(node: ComponentTree): Component[] {
- return map(node.children, (n) => n.component);
-}
-
-export function listAllComponent(node: ComponentTree): Component[] {
- if (isLeaf(node)) {
- return [node.component];
- }
-
- return [node.component, ...flatMap(node.children, listAllComponent)];
-}
-
-export function listAllComponentTrees(node: ComponentTree): ComponentTree[] {
- if (isLeaf(node)) {
- return [node];
- }
-
- return [node, ...flatMap(node.children, listAllComponentTrees)];
-}
-
-export function listLeavesComponent(node: ComponentTree): Component[] {
- if (isLeaf(node)) {
- return [node.component];
- }
- return flatMap(node.children, listLeavesComponent);
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/data/web-api.ts b/server/sonar-web/src/main/js/api/mocks/data/web-api.ts
deleted file mode 100644
index 7b849beb088..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/data/web-api.ts
+++ /dev/null
@@ -1,774 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { OpenAPIV3 } from 'openapi-types';
-import { InternalExtension } from '../../../apps/web-api-v2/types';
-
-export const openApiTestData: OpenAPIV3.Document<InternalExtension> = {
- openapi: '3.0.2',
- info: {
- title: 'Swagger Petstore - OpenAPI 3.0',
- description:
- "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)",
- termsOfService: 'http://swagger.io/terms/',
- contact: { email: 'apiteam@swagger.io' },
- license: { name: 'Apache 2.0', url: 'http://www.apache.org/licenses/LICENSE-2.0.html' },
- version: '1.0.17',
- },
- externalDocs: { description: 'Find out more about Swagger', url: 'http://swagger.io' },
- servers: [{ url: '/api/v3' }],
- tags: [
- {
- name: 'pet',
- description: 'Everything about your Pets',
- externalDocs: { description: 'Find out more', url: 'http://swagger.io' },
- },
- {
- name: 'store',
- description: 'Access to Petstore orders',
- externalDocs: { description: 'Find out more about our store', url: 'http://swagger.io' },
- },
- { name: 'user', description: 'Operations about user' },
- ],
- paths: {
- '/pet': {
- put: {
- tags: ['pet'],
- summary: 'Update an existing pet',
- description: 'Update an existing pet by Id',
- operationId: 'updatePet',
- requestBody: {
- description: 'Update an existent pet in the store',
- content: {
- 'application/json': { schema: { $ref: '#/components/schemas/Pet' } },
- 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } },
- 'application/x-www-form-urlencoded': {
- schema: { $ref: '#/components/schemas/Pet' },
- },
- },
- required: true,
- },
- responses: {
- '200': {
- description: 'Successful operation',
- content: {
- 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } },
- 'application/json': { schema: { $ref: '#/components/schemas/Pet' } },
- },
- },
- '400': { description: 'Invalid ID supplied' },
- '404': { description: 'Pet not found' },
- '405': { description: 'Validation exception' },
- },
- security: [{ petstore_auth: ['write:pets', 'read:pets'] }],
- },
- post: {
- tags: ['pet'],
- summary: 'Add a new pet to the store',
- description: 'Add a new pet to the store',
- operationId: 'addPet',
- requestBody: {
- description: 'Create a new pet in the store',
- content: {
- 'application/json': { schema: { $ref: '#/components/schemas/Pet' } },
- 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } },
- 'application/x-www-form-urlencoded': {
- schema: { $ref: '#/components/schemas/Pet' },
- },
- },
- required: true,
- },
- responses: {
- '200': {
- description: 'Successful operation',
- content: {
- 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } },
- 'application/json': { schema: { $ref: '#/components/schemas/Pet' } },
- },
- },
- '405': { description: 'Invalid input' },
- },
- security: [{ petstore_auth: ['write:pets', 'read:pets'] }],
- },
- },
- '/pet/findByStatus': {
- get: {
- tags: ['pet'],
- summary: 'Finds Pets by status',
- description: 'Multiple status values can be provided with comma separated strings',
- operationId: 'findPetsByStatus',
- parameters: [
- {
- name: 'status',
- in: 'query',
- description: 'Status values that need to be considered for filter',
- required: false,
- explode: true,
- schema: {
- type: 'string',
- default: 'available',
- enum: ['available', 'pending', 'sold'],
- },
- },
- ],
- responses: {
- '200': {
- description: 'successful operation',
- content: {
- 'application/xml': {
- schema: { type: 'array', items: { $ref: '#/components/schemas/Pet' } },
- },
- 'application/json': {
- schema: { type: 'array', items: { $ref: '#/components/schemas/Pet' } },
- },
- },
- },
- '400': { description: 'Invalid status value' },
- },
- security: [{ petstore_auth: ['write:pets', 'read:pets'] }],
- },
- },
- '/pet/findByTags': {
- get: {
- tags: ['pet'],
- summary: 'Finds Pets by tags',
- description:
- 'Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.',
- operationId: 'findPetsByTags',
- parameters: [
- {
- name: 'tags',
- in: 'query',
- description: 'Tags to filter by',
- required: false,
- explode: true,
- schema: { type: 'array', items: { type: 'string' } },
- },
- ],
- responses: {
- '200': {
- description: 'successful operation',
- content: {
- 'application/xml': {
- schema: { type: 'array', items: { $ref: '#/components/schemas/Pet' } },
- },
- 'application/json': {
- schema: { type: 'array', items: { $ref: '#/components/schemas/Pet' } },
- },
- },
- },
- '400': { description: 'Invalid tag value' },
- },
- security: [{ petstore_auth: ['write:pets', 'read:pets'] }],
- },
- },
- '/pet/{petId}': {
- get: {
- tags: ['pet'],
- summary: 'Find pet by ID',
- description: 'Returns a single pet',
- operationId: 'getPetById',
- parameters: [
- {
- name: 'petId',
- in: 'path',
- description: 'ID of pet to return',
- required: true,
- schema: { type: 'integer', format: 'int64' },
- },
- ],
- responses: {
- '200': {
- description: 'successful operation',
- content: {
- 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } },
- 'application/json': { schema: { $ref: '#/components/schemas/Pet' } },
- },
- },
- '400': { description: 'Invalid ID supplied' },
- '404': { description: 'Pet not found' },
- },
- security: [{ api_key: [] }, { petstore_auth: ['write:pets', 'read:pets'] }],
- },
- post: {
- tags: ['pet'],
- summary: 'Updates a pet in the store with form data',
- description: '',
- operationId: 'updatePetWithForm',
- parameters: [
- {
- name: 'petId',
- in: 'path',
- description: 'ID of pet that needs to be updated',
- required: true,
- schema: { type: 'integer', format: 'int64' },
- },
- {
- name: 'name',
- in: 'query',
- description: 'Name of pet that needs to be updated',
- deprecated: true,
- schema: { type: 'string' },
- },
- {
- name: 'status',
- in: 'query',
- description: 'Status of pet that needs to be updated',
- example: 3,
- schema: { type: 'integer', format: 'int32', maximum: 5, minimum: -1 },
- },
- ],
- responses: { '405': { description: 'Invalid input' } },
- security: [{ petstore_auth: ['write:pets', 'read:pets'] }],
- },
- delete: {
- tags: ['pet'],
- summary: 'Deletes a pet',
- description: '',
- operationId: 'deletePet',
- parameters: [
- {
- name: 'api_key',
- in: 'header',
- description: '',
- required: false,
- schema: { type: 'string' },
- },
- {
- name: 'petId',
- in: 'path',
- description: 'Pet id to delete',
- required: true,
- schema: { type: 'integer', format: 'int64' },
- },
- ],
- responses: { '400': { description: 'Invalid pet value' } },
- security: [{ petstore_auth: ['write:pets', 'read:pets'] }],
- },
- },
- '/pet/{petId}/uploadImage': {
- post: {
- tags: ['pet'],
- summary: 'uploads an image',
- description: '',
- operationId: 'uploadFile',
- parameters: [
- {
- name: 'petId',
- in: 'path',
- description: 'ID of pet to update',
- required: true,
- schema: { type: 'integer', format: 'int64' },
- },
- {
- name: 'additionalMetadata',
- in: 'query',
- description: 'Additional Metadata',
- required: false,
- schema: { type: 'string' },
- },
- ],
- requestBody: {
- content: {
- 'application/octet-stream': { schema: { type: 'string', format: 'binary' } },
- },
- },
- responses: {
- '200': {
- description: 'successful operation',
- content: {
- 'application/json': { schema: { $ref: '#/components/schemas/ApiResponse' } },
- },
- },
- },
- security: [{ petstore_auth: ['write:pets', 'read:pets'] }],
- },
- },
- '/store/inventory': {
- get: {
- tags: ['store'],
- summary: 'Returns pet inventories by status',
- description: 'Returns a map of status codes to quantities',
- operationId: 'getInventory',
- responses: {
- '200': {
- description: 'successful operation',
- content: {
- 'application/json': {
- schema: {
- type: 'object',
- additionalProperties: { type: 'integer', format: 'int32' },
- },
- },
- },
- },
- },
- 'x-internal': 'true',
- security: [{ api_key: [] }],
- },
- },
- '/store/order': {
- post: {
- tags: ['store'],
- summary: 'Place an order for a pet',
- description: 'Place a new order in the store',
- operationId: 'placeOrder',
- requestBody: {
- content: {
- 'application/json': { schema: { $ref: '#/components/schemas/Order' } },
- 'application/xml': { schema: { $ref: '#/components/schemas/Order' } },
- 'application/x-www-form-urlencoded': {
- schema: { $ref: '#/components/schemas/Order' },
- },
- },
- },
- responses: {
- '200': {
- description: 'successful operation',
- content: {
- 'application/json': { schema: { $ref: '#/components/schemas/Order' } },
- },
- },
- '405': { description: 'Invalid input' },
- },
- },
- },
- '/store/order/{orderId}': {
- get: {
- tags: ['store'],
- summary: 'Find purchase order by ID',
- description:
- 'For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.',
- operationId: 'getOrderById',
- parameters: [
- {
- name: 'orderId',
- in: 'path',
- description: 'ID of order that needs to be fetched',
- required: true,
- schema: { type: 'integer', format: 'int64' },
- },
- ],
- responses: {
- '200': {
- description: 'successful operation',
- content: {
- 'application/xml': { schema: { $ref: '#/components/schemas/Order' } },
- 'application/json': { schema: { $ref: '#/components/schemas/Order' } },
- },
- },
- '400': { description: 'Invalid ID supplied' },
- '404': { description: 'Order not found' },
- },
- },
- delete: {
- tags: ['store'],
- summary: 'Delete purchase order by ID',
- description:
- 'For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors',
- operationId: 'deleteOrder',
- parameters: [
- {
- name: 'orderId',
- in: 'path',
- description: 'ID of the order that needs to be deleted',
- required: true,
- schema: { type: 'integer', format: 'int64' },
- },
- ],
- responses: {
- '400': { description: 'Invalid ID supplied' },
- '404': { description: 'Order not found' },
- },
- },
- },
- '/test': {
- get: {
- summary: 'Test internal query params',
- description: 'For tests only',
- parameters: [
- {
- name: 'visible',
- in: 'query',
- description: 'parameter visible to anyone',
- schema: { type: 'integer', format: 'int64' },
- },
- {
- name: 'hidden',
- in: 'query',
- description: 'parameter is internal',
- schema: { type: 'integer', format: 'int64' },
- 'x-internal': 'true',
- } as OpenAPIV3.ParameterObject & InternalExtension,
- ],
- responses: {
- default: {
- description: 'successful operation',
- },
- },
- },
- post: {
- summary: 'Test internal query params',
- description: 'For tests only',
- requestBody: {
- content: {
- 'application/json': {
- schema: {
- type: 'object',
- properties: {
- visible: { type: 'string' },
- hidden: { type: 'string', 'x-internal': 'true' } as OpenAPIV3.SchemaObject &
- InternalExtension,
- },
- },
- },
- },
- },
- responses: {
- default: {
- description: 'successful operation',
- },
- },
- },
- },
- '/user': {
- post: {
- tags: ['user'],
- summary: 'Create user',
- description: 'This can only be done by the logged in user.',
- operationId: 'createUser',
- requestBody: {
- description: 'Created user object',
- content: {
- 'application/json': { schema: { $ref: '#/components/schemas/User' } },
- 'application/xml': { schema: { $ref: '#/components/schemas/User' } },
- 'application/x-www-form-urlencoded': {
- schema: { $ref: '#/components/schemas/User' },
- },
- },
- },
- responses: {
- default: {
- description: 'successful operation',
- content: {
- 'application/json': { schema: { $ref: '#/components/schemas/User' } },
- 'application/xml': { schema: { $ref: '#/components/schemas/User' } },
- },
- },
- },
- },
- },
- '/user/createWithList': {
- post: {
- tags: ['user'],
- summary: 'Creates list of users with given input array',
- description: 'Creates list of users with given input array',
- operationId: 'createUsersWithListInput',
- requestBody: {
- content: {
- 'application/json': {
- schema: { type: 'array', items: { $ref: '#/components/schemas/User' } },
- },
- },
- },
- responses: {
- '200': {
- description: 'Successful operation',
- content: {
- 'application/xml': { schema: { $ref: '#/components/schemas/User' } },
- 'application/json': { schema: { $ref: '#/components/schemas/User' } },
- },
- },
- default: { description: 'successful operation' },
- },
- },
- },
- '/user/login': {
- get: {
- tags: ['user'],
- summary: 'Logs user into the system',
- description: '',
- operationId: 'loginUser',
- parameters: [
- {
- name: 'username',
- in: 'query',
- description: 'The user name for login',
- required: false,
- schema: { type: 'string' },
- },
- {
- name: 'password',
- in: 'query',
- description: 'The password for login in clear text',
- required: false,
- schema: { type: 'string' },
- },
- ],
- responses: {
- '200': {
- description: 'successful operation',
- headers: {
- 'X-Rate-Limit': {
- description: 'calls per hour allowed by the user',
- schema: { type: 'integer', format: 'int32' },
- },
- 'X-Expires-After': {
- description: 'date in UTC when token expires',
- schema: { type: 'string', format: 'date-time' },
- },
- },
- content: {
- 'application/xml': { schema: { type: 'string' } },
- 'application/json': { schema: { type: 'string' } },
- },
- },
- '400': { description: 'Invalid username/password supplied' },
- },
- },
- },
- '/user/logout': {
- get: {
- tags: ['user'],
- summary: 'Logs out current logged in user session',
- description: '',
- operationId: 'logoutUser',
- parameters: [],
- responses: { default: { description: 'successful operation' } },
- },
- },
- '/user/{username}': {
- get: {
- tags: ['user'],
- summary: 'Get user by user name',
- description: '',
- operationId: 'getUserByName',
- parameters: [
- {
- name: 'username',
- in: 'path',
- description: 'The name that needs to be fetched. Use user1 for testing. ',
- required: true,
- schema: { type: 'string' },
- },
- ],
- responses: {
- '200': {
- description: 'successful operation',
- content: {
- 'application/xml': { schema: { $ref: '#/components/schemas/User' } },
- 'application/json': { schema: { $ref: '#/components/schemas/User' } },
- },
- },
- '400': { description: 'Invalid username supplied' },
- '404': { description: 'User not found' },
- },
- },
- put: {
- tags: ['user'],
- summary: 'Update user',
- description: 'This can only be done by the logged in user.',
- operationId: 'updateUser',
- parameters: [
- {
- name: 'username',
- in: 'path',
- description: 'name that need to be deleted',
- required: true,
- schema: { type: 'string' },
- },
- ],
- requestBody: {
- description: 'Update an existent user in the store',
- content: {
- 'application/json': { schema: { $ref: '#/components/schemas/User' } },
- 'application/xml': { schema: { $ref: '#/components/schemas/User' } },
- 'application/x-www-form-urlencoded': {
- schema: { $ref: '#/components/schemas/User' },
- },
- },
- },
- responses: { default: { description: 'successful operation' } },
- },
- delete: {
- tags: ['user'],
- summary: 'Delete user',
- description: 'This can only be done by the logged in user.',
- operationId: 'deleteUser',
- parameters: [
- {
- name: 'username',
- in: 'path',
- description: 'The name that needs to be deleted',
- required: true,
- schema: { type: 'string' },
- },
- ],
- responses: {
- '400': { description: 'Invalid username supplied' },
- '404': { description: 'User not found' },
- },
- },
- },
- },
- components: {
- schemas: {
- Order: {
- type: 'object',
- properties: {
- id: { type: 'integer', format: 'int64', example: 10 },
- petId: { type: 'integer', format: 'int64', example: 198772 },
- quantity: { type: 'integer', format: 'int32', example: 7 },
- shipDate: { type: 'string', format: 'date-time' },
- status: {
- type: 'string',
- description: 'Order Status',
- example: 'approved',
- enum: ['placed', 'approved', 'delivered'],
- },
- complete: { type: 'boolean' },
- },
- xml: { name: 'order' },
- },
- Customer: {
- type: 'object',
- properties: {
- id: { type: 'integer', format: 'int64', example: 100000 },
- username: { type: 'string', example: 'fehguy' },
- address: {
- type: 'array',
- xml: { name: 'addresses', wrapped: true },
- items: { $ref: '#/components/schemas/Address' },
- },
- },
- xml: { name: 'customer' },
- },
- Address: {
- type: 'object',
- properties: {
- street: { type: 'string', example: '437 Lytton' },
- city: { type: 'string', example: 'Palo Alto' },
- state: { type: 'string', example: 'CA' },
- zip: { type: 'string', example: '94301' },
- },
- xml: { name: 'address' },
- },
- Category: {
- type: 'object',
- properties: {
- id: { type: 'integer', format: 'int64', example: 1 },
- name: { type: 'string', example: 'Dogs' },
- },
- xml: { name: 'category' },
- },
- User: {
- type: 'object',
- properties: {
- id: { type: 'integer', format: 'int64', example: 10 },
- username: { type: 'string', example: 'theUser' },
- firstName: { type: 'string', example: 'John' },
- lastName: { type: 'string', example: 'James' },
- email: { type: 'string', example: 'john@email.com' },
- password: { type: 'string', example: '12345' },
- phone: { type: 'string', example: '12345' },
- userStatus: {
- type: 'integer',
- description: 'User Status',
- format: 'int32',
- example: 1,
- },
- },
- xml: { name: 'user' },
- },
- Tag: {
- type: 'object',
- properties: {
- id: { type: 'integer', format: 'int64' },
- name: { type: 'string' },
- },
- xml: { name: 'tag' },
- },
- Pet: {
- required: ['name', 'photoUrls'],
- type: 'object',
- properties: {
- id: { type: 'integer', format: 'int64', example: 10 },
- name: { type: 'string', minLength: 3, maxLength: 100, example: 'doggie' },
- category: { $ref: '#/components/schemas/Category' },
- photoUrls: {
- type: 'array',
- xml: { wrapped: true },
- items: { type: 'string', xml: { name: 'photoUrl' } },
- },
- tags: {
- type: 'array',
- xml: { wrapped: true },
- items: { $ref: '#/components/schemas/Tag' },
- },
- status: {
- type: 'string',
- description: 'pet status in the store',
- enum: ['available', 'pending', 'sold'],
- deprecated: true,
- },
- },
- xml: { name: 'pet' },
- },
- ApiResponse: {
- type: 'object',
- properties: {
- code: { type: 'integer', format: 'int32' },
- type: { type: 'string' },
- message: { type: 'string' },
- },
- xml: { name: '##default' },
- },
- },
- requestBodies: {
- Pet: {
- description: 'Pet object that needs to be added to the store',
- content: {
- 'application/json': { schema: { $ref: '#/components/schemas/Pet' } },
- 'application/xml': { schema: { $ref: '#/components/schemas/Pet' } },
- },
- },
- UserArray: {
- description: 'List of user object',
- content: {
- 'application/json': {
- schema: { type: 'array', items: { $ref: '#/components/schemas/User' } },
- },
- },
- },
- },
- securitySchemes: {
- petstore_auth: {
- type: 'oauth2',
- flows: {
- implicit: {
- authorizationUrl: 'https://petstore3.swagger.io/oauth/authorize',
- scopes: { 'write:pets': 'modify pets in your account', 'read:pets': 'read your pets' },
- },
- },
- },
- api_key: { type: 'apiKey', name: 'api_key', in: 'header' },
- },
- },
-};
diff --git a/server/sonar-web/src/main/js/api/mocks/data/webhooks.ts b/server/sonar-web/src/main/js/api/mocks/data/webhooks.ts
deleted file mode 100644
index 5ddfe55f17d..00000000000
--- a/server/sonar-web/src/main/js/api/mocks/data/webhooks.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { cloneDeep } from 'lodash';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { mockComponent } from '../../../helpers/mocks/component';
-import { mockWebhook, mockWebhookDelivery } from '../../../helpers/mocks/webhook';
-import { WebhookDelivery, WebhookResponse } from '../../../types/webhook';
-import {
- WEBHOOK_GLOBAL_1,
- WEBHOOK_GLOBAL_1_LATEST_DELIVERY_ID,
- WEBHOOK_GLOBAL_2,
- WEBHOOK_PROJECT_1,
- WEBHOOK_PROJECT_1_1,
- WEBHOOK_PROJECT_1_2,
-} from './ids';
-
-export const webhookProject = mockComponent({
- key: WEBHOOK_PROJECT_1,
- qualifier: ComponentQualifier.Project,
-});
-
-const globalWebhook1Deliveries = [
- mockWebhookDelivery({
- at: '2019-06-24T09:45:52+0200',
- id: WEBHOOK_GLOBAL_1_LATEST_DELIVERY_ID,
- }),
- ...Array.from({ length: 15 }).map((_, i) =>
- mockWebhookDelivery({
- id: `global-webhook-1-delivery-${i}`,
- at: `2019-06-${(23 - i).toString().padStart(2, '0')}T09:45:52+0200`,
- httpStatus: i % 2 === 0 ? 200 : undefined,
- success: i % 2 === 0,
- durationMs: 1000 + i * 100,
- }),
- ),
-];
-
-const project1Webhook1Deliveries = [
- mockWebhookDelivery({
- id: 'project-1-delivery-1',
- at: '2019-06-24T09:45:52+0200',
- }),
-];
-
-export const deliveries = [...globalWebhook1Deliveries, ...project1Webhook1Deliveries];
-
-export const webhooks: Record<string, Array<WebhookResponse>> = {
- global: [
- mockWebhook({
- key: WEBHOOK_GLOBAL_1,
- name: 'Global webhook 1',
- url: 'https://example.com/1',
- latestDelivery: globalWebhook1Deliveries[0],
- }),
- mockWebhook({
- key: WEBHOOK_GLOBAL_2,
- name: 'Global webhook 2',
- hasSecret: true,
- url: 'https://example.com/2',
- }),
- ],
- [webhookProject.key]: [
- mockWebhook({
- key: WEBHOOK_PROJECT_1_1,
- name: 'Project 1 webhook 1',
- url: 'https://example.com/1',
- latestDelivery: project1Webhook1Deliveries[0],
- }),
- mockWebhook({
- key: WEBHOOK_PROJECT_1_2,
- name: 'Project 1 webhook 2',
- url: 'https://example.com/2',
- }),
- ],
-};
-
-export function mockFullWebhookList(project?: string): Array<WebhookResponse> {
- return cloneDeep(webhooks[project ?? 'global'] ?? []);
-}
-
-export function mockFullWebhookDeliveries(webhook?: string): Array<WebhookDelivery> {
- return cloneDeep(webhook === WEBHOOK_GLOBAL_1 ? globalWebhook1Deliveries : []);
-}
diff --git a/server/sonar-web/src/main/js/api/mode.ts b/server/sonar-web/src/main/js/api/mode.ts
deleted file mode 100644
index 06ab5cf31cf..00000000000
--- a/server/sonar-web/src/main/js/api/mode.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import axios from 'axios';
-import { Mode, ModeResponse } from '../types/mode';
-
-const MODE_PATH = '/api/v2/clean-code-policy/mode';
-
-export function getMode() {
- return axios.get<ModeResponse>(MODE_PATH);
-}
-
-export function updateMode(mode: Mode) {
- return axios.patch<ModeResponse>(MODE_PATH, { mode });
-}
diff --git a/server/sonar-web/src/main/js/api/navigation.ts b/server/sonar-web/src/main/js/api/navigation.ts
deleted file mode 100644
index 76353a672fb..00000000000
--- a/server/sonar-web/src/main/js/api/navigation.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { AppState } from '../types/appstate';
-import { Extension, NavigationComponent } from '../types/types';
-
-export function getComponentNavigation(
- data: { component: string } & BranchParameters,
-): Promise<NavigationComponent> {
- return getJSON('/api/navigation/component', data);
-}
-
-export function getMarketplaceNavigation(): Promise<{ ncloc: number; serverId: string }> {
- return getJSON('/api/navigation/marketplace').catch(throwGlobalError);
-}
-
-export function getSettingsNavigation(): Promise<{
- extensions: Extension[];
- showUpdateCenter: boolean;
-}> {
- return getJSON('/api/navigation/settings').catch(throwGlobalError);
-}
-
-export function getGlobalNavigation(): Promise<AppState> {
- return getJSON('/api/navigation/global', undefined, { bypassRedirect: true });
-}
diff --git a/server/sonar-web/src/main/js/api/newCodeDefinition.ts b/server/sonar-web/src/main/js/api/newCodeDefinition.ts
deleted file mode 100644
index 8a9157dceb4..00000000000
--- a/server/sonar-web/src/main/js/api/newCodeDefinition.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post } from '../helpers/request';
-import {
- NewCodeDefinition,
- NewCodeDefinitionBranch,
- NewCodeDefinitionType,
-} from '../types/new-code-definition';
-
-export function getNewCodeDefinition(data?: {
- branch?: string;
- project?: string;
-}): Promise<Omit<NewCodeDefinition, 'effectiveValue'>> {
- return getJSON('/api/new_code_periods/show', data).catch(throwGlobalError);
-}
-
-export function setNewCodeDefinition(data: {
- branch?: string;
- project?: string;
- type: NewCodeDefinitionType;
- value?: string;
-}): Promise<void> {
- return post('/api/new_code_periods/set', data).catch(throwGlobalError);
-}
-
-export function resetNewCodeDefinition(data: { branch?: string; project?: string }): Promise<void> {
- return post('/api/new_code_periods/unset', data).catch(throwGlobalError);
-}
-
-export function listBranchesNewCodeDefinition(data: {
- project: string;
-}): Promise<{ newCodePeriods: NewCodeDefinitionBranch[] }> {
- return getJSON('/api/new_code_periods/list', data).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/notifications.ts b/server/sonar-web/src/main/js/api/notifications.ts
deleted file mode 100644
index 051ee91e0e6..00000000000
--- a/server/sonar-web/src/main/js/api/notifications.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post } from '../helpers/request';
-import { AddRemoveNotificationParameters, NotificationsResponse } from '../types/notifications';
-
-export function getNotifications(): Promise<NotificationsResponse> {
- return getJSON('/api/notifications/list').catch(throwGlobalError);
-}
-
-export function addNotification(data: AddRemoveNotificationParameters) {
- return post('/api/notifications/add', data).catch(throwGlobalError);
-}
-
-export function removeNotification(data: AddRemoveNotificationParameters) {
- return post('/api/notifications/remove', data).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/permissions.ts b/server/sonar-web/src/main/js/api/permissions.ts
deleted file mode 100644
index 6c92873c609..00000000000
--- a/server/sonar-web/src/main/js/api/permissions.ts
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { Visibility } from '~sonar-aligned/types/component';
-import { post, postJSON, RequestData } from '../helpers/request';
-import {
- Paging,
- Permission,
- PermissionGroup,
- PermissionTemplate,
- PermissionUser,
-} from '../types/types';
-import { BaseSearchProjectsParameters } from './components';
-
-const PAGE_SIZE = 100;
-
-export function grantPermissionToUser(data: {
- login: string;
- permission: string;
- projectKey?: string;
-}) {
- return post('/api/permissions/add_user', data).catch(throwGlobalError);
-}
-
-export function revokePermissionFromUser(data: {
- login: string;
- permission: string;
- projectKey?: string;
-}) {
- return post('/api/permissions/remove_user', data).catch(throwGlobalError);
-}
-
-export function grantPermissionToGroup(data: {
- groupName: string;
- permission: string;
- projectKey?: string;
-}) {
- return post('/api/permissions/add_group', data).catch(throwGlobalError);
-}
-
-export function revokePermissionFromGroup(data: {
- groupName: string;
- permission: string;
- projectKey?: string;
-}) {
- return post('/api/permissions/remove_group', data).catch(throwGlobalError);
-}
-
-interface GetPermissionTemplatesResponse {
- defaultTemplates: Array<{ qualifier: string; templateId: string }>;
- permissionTemplates: PermissionTemplate[];
- permissions: Array<Permission>;
-}
-
-export function getPermissionTemplates(): Promise<GetPermissionTemplatesResponse> {
- const url = '/api/permissions/search_templates';
- return getJSON(url);
-}
-
-export function createPermissionTemplate(data: {
- description?: string;
- name: string;
- projectKeyPattern?: string;
-}): Promise<{ permissionTemplate: Omit<PermissionTemplate, 'defaultFor'> }> {
- return postJSON('/api/permissions/create_template', data);
-}
-
-export function updatePermissionTemplate(data: {
- description?: string;
- id: string;
- name?: string;
- projectKeyPattern?: string;
-}): Promise<void> {
- return post('/api/permissions/update_template', data);
-}
-
-export function deletePermissionTemplate(data: { templateId?: string; templateName?: string }) {
- return post('/api/permissions/delete_template', data).catch(throwGlobalError);
-}
-
-/**
- * Set default permission template for a given qualifier
- */
-export function setDefaultPermissionTemplate(templateId: string, qualifier: string): Promise<void> {
- return post('/api/permissions/set_default_template', { templateId, qualifier });
-}
-
-export function applyTemplateToProject(data: { projectKey: string; templateId: string }) {
- return post('/api/permissions/apply_template', data).catch(throwGlobalError);
-}
-
-export function bulkApplyTemplate(data: BaseSearchProjectsParameters): Promise<void> {
- return post('/api/permissions/bulk_apply_template', data);
-}
-
-export function grantTemplatePermissionToUser(data: {
- login: string;
- permission: string;
- templateId: string;
-}): Promise<void> {
- return post('/api/permissions/add_user_to_template', data);
-}
-
-export function revokeTemplatePermissionFromUser(data: {
- login: string;
- permission: string;
- templateId: string;
-}): Promise<void> {
- return post('/api/permissions/remove_user_from_template', data);
-}
-
-export function grantTemplatePermissionToGroup(data: RequestData): Promise<void> {
- return post('/api/permissions/add_group_to_template', data);
-}
-
-export function revokeTemplatePermissionFromGroup(data: RequestData): Promise<void> {
- return post('/api/permissions/remove_group_from_template', data);
-}
-
-export function addProjectCreatorToTemplate(templateId: string, permission: string): Promise<void> {
- return post('/api/permissions/add_project_creator_to_template', { templateId, permission });
-}
-
-export function removeProjectCreatorFromTemplate(
- templateId: string,
- permission: string,
-): Promise<void> {
- return post('/api/permissions/remove_project_creator_from_template', { templateId, permission });
-}
-
-export function getPermissionsUsersForComponent(data: {
- p?: number;
- permission?: string;
- projectKey: string;
- ps?: number;
- q?: string;
-}): Promise<{ paging: Paging; users: PermissionUser[] }> {
- if (!data.ps) {
- data.ps = PAGE_SIZE;
- }
- return getJSON('/api/permissions/users', data).catch(throwGlobalError);
-}
-
-export function getPermissionsGroupsForComponent(data: {
- p?: number;
- permission?: string;
- projectKey: string;
- ps?: number;
- q?: string;
-}): Promise<{ groups: PermissionGroup[]; paging: Paging }> {
- if (!data.ps) {
- data.ps = PAGE_SIZE;
- }
- return getJSON('/api/permissions/groups', data).catch(throwGlobalError);
-}
-
-export function getGlobalPermissionsUsers(data: {
- p?: number;
- permission?: string;
- ps?: number;
- q?: string;
-}): Promise<{ paging: Paging; users: PermissionUser[] }> {
- if (!data.ps) {
- data.ps = PAGE_SIZE;
- }
- return getJSON('/api/permissions/users', data);
-}
-
-export function getGlobalPermissionsGroups(data: {
- p?: number;
- permission?: string;
- ps?: number;
- q?: string;
-}): Promise<{ groups: PermissionGroup[]; paging: Paging }> {
- if (!data.ps) {
- data.ps = PAGE_SIZE;
- }
- return getJSON('/api/permissions/groups', data);
-}
-
-export function getPermissionTemplateUsers(data: {
- p?: number;
- permission?: string;
- ps?: number;
- q?: string;
- templateId: string;
-}): Promise<{ paging: Paging; users: PermissionUser[] }> {
- if (data.ps === undefined) {
- data.ps = PAGE_SIZE;
- }
- return getJSON('/api/permissions/template_users', data).catch(throwGlobalError);
-}
-
-export function getPermissionTemplateGroups(data: {
- p?: number;
- permission?: string;
- ps?: number;
- q?: string;
- templateId: string;
-}): Promise<{ groups: PermissionGroup[]; paging: Paging }> {
- if (data.ps === undefined) {
- data.ps = PAGE_SIZE;
- }
- return getJSON('/api/permissions/template_groups', data).catch(throwGlobalError);
-}
-
-export function changeProjectVisibility(
- project: string,
- visibility: Visibility,
-): Promise<void | Response> {
- return post('/api/projects/update_visibility', { project, visibility }).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/plugins.ts b/server/sonar-web/src/main/js/api/plugins.ts
deleted file mode 100644
index 2c5a0b5d72f..00000000000
--- a/server/sonar-web/src/main/js/api/plugins.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post } from '../helpers/request';
-import {
- AvailablePlugin,
- InstalledPlugin,
- PendingPluginResult,
- PluginType,
-} from '../types/plugins';
-
-export function getAvailablePlugins(): Promise<{
- plugins: AvailablePlugin[];
- updateCenterRefresh: string;
-}> {
- return getJSON('/api/plugins/available').catch(throwGlobalError);
-}
-
-export function getPendingPlugins(): Promise<PendingPluginResult> {
- return getJSON('/api/plugins/pending').catch(throwGlobalError);
-}
-
-export function getInstalledPlugins(type = PluginType.External): Promise<InstalledPlugin[]> {
- return getJSON('/api/plugins/installed', { f: 'category', type }).then(
- ({ plugins }) => plugins,
- throwGlobalError,
- );
-}
-
-export function getUpdatesPlugins() {
- return getJSON('/api/plugins/updates');
-}
-
-export function installPlugin(data: { key: string }): Promise<void | Response> {
- return post('/api/plugins/install', data).catch(throwGlobalError);
-}
-
-export function uninstallPlugin(data: { key: string }): Promise<void | Response> {
- return post('/api/plugins/uninstall', data).catch(throwGlobalError);
-}
-
-export function updatePlugin(data: { key: string }): Promise<void | Response> {
- return post('/api/plugins/update', data).catch(throwGlobalError);
-}
-
-export function cancelPendingPlugins(): Promise<void | Response> {
- return post('/api/plugins/cancel_all').catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/project-badges.ts b/server/sonar-web/src/main/js/api/project-badges.ts
deleted file mode 100644
index d858465a7cb..00000000000
--- a/server/sonar-web/src/main/js/api/project-badges.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post } from '../helpers/request';
-
-export function getProjectBadgesToken(project: string) {
- return getJSON('/api/project_badges/token', { project })
- .then(({ token }) => token)
- .catch(throwGlobalError);
-}
-
-export function renewProjectBadgesToken(project: string) {
- return post('/api/project_badges/renew_token', { project }).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/project-dump.ts b/server/sonar-web/src/main/js/api/project-dump.ts
deleted file mode 100644
index 92d2bca0bf8..00000000000
--- a/server/sonar-web/src/main/js/api/project-dump.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post } from '../helpers/request';
-import { DumpStatus } from '../types/project-dump';
-
-export function getStatus(componentKey: string): Promise<DumpStatus> {
- return getJSON('/api/project_dump/status', { key: componentKey }).catch(throwGlobalError);
-}
-
-export function doExport(componentKey: string) {
- return post('/api/project_dump/export', { key: componentKey }).catch(throwGlobalError);
-}
-
-export function doImport(componentKey: string) {
- return post('/api/project_dump/import', { key: componentKey }).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/project-management.ts b/server/sonar-web/src/main/js/api/project-management.ts
deleted file mode 100644
index 073f0bc880b..00000000000
--- a/server/sonar-web/src/main/js/api/project-management.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { ComponentQualifier, Visibility } from '~sonar-aligned/types/component';
-import { post, postJSON } from '../helpers/request';
-import { Paging } from '../types/types';
-
-export interface BaseSearchProjectsParameters {
- analyzedBefore?: string;
- onProvisionedOnly?: boolean;
- projects?: string;
- q?: string;
- qualifiers?: string;
- visibility?: Visibility;
-}
-
-export interface ProjectBase {
- key: string;
- name: string;
- qualifier:
- | ComponentQualifier.Application
- | ComponentQualifier.Portfolio
- | ComponentQualifier.Project;
- visibility: Visibility;
-}
-
-export interface Project extends ProjectBase {
- lastAnalysisDate?: string;
- managed?: boolean;
-}
-
-export interface SearchProjectsParameters extends BaseSearchProjectsParameters {
- p?: number;
- ps?: number;
-}
-
-export function getComponents(parameters: SearchProjectsParameters): Promise<{
- components: Project[];
- paging: Paging;
-}> {
- return getJSON('/api/projects/search', parameters);
-}
-
-export function bulkDeleteProjects(
- parameters: BaseSearchProjectsParameters,
-): Promise<void | Response> {
- return post('/api/projects/bulk_delete', parameters).catch(throwGlobalError);
-}
-
-export function deleteProject(project: string): Promise<void | Response> {
- return post('/api/projects/delete', { project }).catch(throwGlobalError);
-}
-
-export function deletePortfolio(portfolio: string): Promise<void | Response> {
- return post('/api/views/delete', { key: portfolio }).catch(throwGlobalError);
-}
-
-export function createProject(data: {
- mainBranch: string;
- name: string;
- newCodeDefinitionType?: string;
- newCodeDefinitionValue?: string;
- project: string;
- visibility?: Visibility;
-}): Promise<{ project: ProjectBase }> {
- return postJSON('/api/projects/create', data).catch(throwGlobalError);
-}
-
-export function changeProjectDefaultVisibility(
- projectVisibility: Visibility,
-): Promise<void | Response> {
- return post('/api/projects/update_default_visibility', { projectVisibility }).catch(
- throwGlobalError,
- );
-}
diff --git a/server/sonar-web/src/main/js/api/projectActivity.ts b/server/sonar-web/src/main/js/api/projectActivity.ts
deleted file mode 100644
index 622d8370c11..00000000000
--- a/server/sonar-web/src/main/js/api/projectActivity.ts
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { post, postJSON } from '../helpers/request';
-import {
- Analysis,
- ApplicationAnalysisEventCategory,
- ProjectAnalysisEventCategory,
-} from '../types/project-activity';
-import { Paging } from '../types/types';
-
-export enum ProjectActivityStatuses {
- STATUS_PROCESSED = 'P',
- STATUS_UNPROCESSED = 'U',
- STATUS_LIVE_MEASURE_COMPUTE = 'L',
-}
-
-export type ProjectActivityParams = {
- category?: string;
- from?: string;
- p?: number;
- project?: string;
- ps?: number;
- statuses?: string;
-} & BranchParameters;
-
-export interface ProjectActivityResponse {
- analyses: Analysis[];
- paging: Paging;
-}
-
-export function getProjectActivity(data: ProjectActivityParams): Promise<ProjectActivityResponse> {
- return getJSON('/api/project_analyses/search', data).catch(throwGlobalError);
-}
-
-const PROJECT_ACTIVITY_PAGE_SIZE = 500;
-
-export function getAllTimeProjectActivity(
- data: ProjectActivityParams,
- prev?: ProjectActivityResponse,
-): Promise<ProjectActivityResponse> {
- return getProjectActivity({ ...data, ps: data.ps ?? PROJECT_ACTIVITY_PAGE_SIZE }).then((r) => {
- const result = prev
- ? {
- analyses: prev.analyses.concat(r.analyses),
- paging: r.paging,
- }
- : r;
-
- if (result.paging.pageIndex * result.paging.pageSize >= result.paging.total) {
- return result;
- }
-
- return getAllTimeProjectActivity(
- { ...data, ps: data.ps ?? PROJECT_ACTIVITY_PAGE_SIZE, p: result.paging.pageIndex + 1 },
- result,
- );
- });
-}
-
-export interface CreateEventResponse {
- analysis: string;
- category: ProjectAnalysisEventCategory | ApplicationAnalysisEventCategory;
- description?: string;
- key: string;
- name: string;
-}
-
-export function createEvent(data: {
- analysis: string;
- category?: string;
- description?: string;
- name: string;
-}): Promise<CreateEventResponse> {
- return postJSON('/api/project_analyses/create_event', data).then(
- (r) => r.event,
- throwGlobalError,
- );
-}
-
-export function deleteEvent(event: string): Promise<void | Response> {
- return post('/api/project_analyses/delete_event', { event }).catch(throwGlobalError);
-}
-
-export function changeEvent(data: {
- description?: string;
- event: string;
- name?: string;
-}): Promise<CreateEventResponse> {
- return postJSON('/api/project_analyses/update_event', data).then(
- (r) => r.event,
- throwGlobalError,
- );
-}
-
-export function deleteAnalysis(analysis: string): Promise<void | Response> {
- return post('/api/project_analyses/delete', { analysis }).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/projectLinks.ts b/server/sonar-web/src/main/js/api/projectLinks.ts
deleted file mode 100644
index 18b508e96bf..00000000000
--- a/server/sonar-web/src/main/js/api/projectLinks.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post, postJSON } from '../helpers/request';
-import { ProjectLink } from '../types/types';
-
-export function getProjectLinks(projectKey: string): Promise<ProjectLink[]> {
- return getJSON('/api/project_links/search', { projectKey }).then(
- (r) => r.links,
- throwGlobalError,
- );
-}
-
-export function deleteLink(linkId: string) {
- return post('/api/project_links/delete', { id: linkId }).catch(throwGlobalError);
-}
-
-export function createLink(data: {
- name: string;
- projectKey: string;
- url: string;
-}): Promise<ProjectLink> {
- return postJSON('/api/project_links/create', data).then((r) => r.link, throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/quality-gates.ts b/server/sonar-web/src/main/js/api/quality-gates.ts
deleted file mode 100644
index 3c5ceb95aec..00000000000
--- a/server/sonar-web/src/main/js/api/quality-gates.ts
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { post, postJSON } from '../helpers/request';
-import {
- AddDeleteGroupPermissionsParameters,
- AddDeleteUserPermissionsParameters,
- Group,
- QualityGateApplicationStatus,
- QualityGateProjectStatus,
- SearchPermissionsParameters,
-} from '../types/quality-gates';
-import { Condition, Paging, QualityGate, QualityGatePreview } from '../types/types';
-import { UserBase } from '../types/users';
-import { AiCodeAssuranceStatus } from './ai-code-assurance';
-
-export interface SearchQualityGateProjectsData {
- gateName: string;
- page?: number;
- pageSize?: number;
- query?: string;
- selected?: string;
-}
-
-export interface SearchQualityGateProjectsResponse {
- paging: Paging;
- results: Array<{
- aiCodeAssurance: AiCodeAssuranceStatus;
- key: string;
- name: string;
- selected: boolean;
- }>;
-}
-
-export function fetchQualityGates(): Promise<{
- actions: { create: boolean };
- qualitygates: QualityGate[];
-}> {
- return getJSON('/api/qualitygates/list').catch(throwGlobalError);
-}
-
-export function fetchQualityGate(data: { name: string }): Promise<QualityGate> {
- return getJSON('/api/qualitygates/show', data).catch(throwGlobalError);
-}
-
-export function createQualityGate(data: { name: string }): Promise<QualityGate> {
- return postJSON('/api/qualitygates/create', data).catch(throwGlobalError);
-}
-
-export function deleteQualityGate(data: { name: string }): Promise<void | Response> {
- return post('/api/qualitygates/destroy', data).catch(throwGlobalError);
-}
-
-export function renameQualityGate(data: {
- currentName: string;
- name: string;
-}): Promise<void | Response> {
- return post('/api/qualitygates/rename', data).catch(throwGlobalError);
-}
-
-export function copyQualityGate(data: { name: string; sourceName: string }): Promise<QualityGate> {
- return postJSON('/api/qualitygates/copy', data).catch(throwGlobalError);
-}
-
-export function setQualityGateAsDefault(data: { name: string }): Promise<void | Response> {
- return post('/api/qualitygates/set_as_default', data).catch(throwGlobalError);
-}
-
-export function setQualityGateAiQualified(
- gateName: string,
- aiCodeAssurance: boolean,
-): Promise<void> {
- return post('/api/qualitygates/set_ai_code_assurance', {
- aiCodeAssurance,
- gateName,
- }).catch(throwGlobalError);
-}
-
-export function createCondition(
- data: {
- gateName: string;
- } & Omit<Condition, 'id'>,
-): Promise<Condition> {
- return postJSON('/api/qualitygates/create_condition', data).catch(throwGlobalError);
-}
-
-export function updateCondition(data: Condition): Promise<Condition> {
- return postJSON('/api/qualitygates/update_condition', data).catch(throwGlobalError);
-}
-
-export function deleteCondition(data: { id: string }): Promise<void> {
- return post('/api/qualitygates/delete_condition', data);
-}
-
-export function getGateForProject(data: { project: string }): Promise<QualityGatePreview> {
- return getJSON('/api/qualitygates/get_by_project', data).then(
- ({ qualityGate }) => ({
- ...qualityGate,
- isDefault: qualityGate.default,
- }),
- throwGlobalError,
- );
-}
-
-export function searchProjects(
- data: SearchQualityGateProjectsData,
-): Promise<SearchQualityGateProjectsResponse> {
- return getJSON('/api/qualitygates/search', data).catch(throwGlobalError);
-}
-
-export function getAllQualityGateProjects(
- data: SearchQualityGateProjectsData,
- prev?: SearchQualityGateProjectsResponse,
-): Promise<SearchQualityGateProjectsResponse> {
- return searchProjects({ ...data, pageSize: 1000 }).then((r) => {
- const result = prev
- ? {
- results: [...prev.results, ...r.results],
- paging: r.paging,
- }
- : r;
-
- if (result.paging.pageIndex * result.paging.pageSize >= result.paging.total) {
- return result;
- }
- return getAllQualityGateProjects({ ...data, page: result.paging.pageIndex + 1 }, result);
- });
-}
-
-export function associateGateWithProject(data: {
- gateName: string;
- projectKey: string;
-}): Promise<void | Response> {
- return post('/api/qualitygates/select', data).catch(throwGlobalError);
-}
-
-export function dissociateGateWithProject(data: { projectKey: string }): Promise<void | Response> {
- return post('/api/qualitygates/deselect', data).catch(throwGlobalError);
-}
-
-export function getApplicationQualityGate(data: {
- application: string;
- branch?: string;
-}): Promise<QualityGateApplicationStatus> {
- return getJSON('/api/qualitygates/application_status', data).catch(throwGlobalError);
-}
-
-export function getQualityGateProjectStatus(
- data: {
- projectId?: string;
- projectKey?: string;
- } & BranchParameters,
-): Promise<QualityGateProjectStatus> {
- return getJSON('/api/qualitygates/project_status', data)
- .then((r) => r.projectStatus)
- .catch(throwGlobalError);
-}
-
-export function addUser(data: AddDeleteUserPermissionsParameters) {
- return post('/api/qualitygates/add_user', data).catch(throwGlobalError);
-}
-
-export function removeUser(data: AddDeleteUserPermissionsParameters) {
- return post('/api/qualitygates/remove_user', data).catch(throwGlobalError);
-}
-
-export function searchUsers(data: SearchPermissionsParameters): Promise<{ users: UserBase[] }> {
- return getJSON('/api/qualitygates/search_users', data).catch(throwGlobalError);
-}
-
-export function addGroup(data: AddDeleteGroupPermissionsParameters) {
- return post('/api/qualitygates/add_group', data).catch(throwGlobalError);
-}
-
-export function removeGroup(data: AddDeleteGroupPermissionsParameters) {
- return post('/api/qualitygates/remove_group', data).catch(throwGlobalError);
-}
-
-export function searchGroups(data: SearchPermissionsParameters): Promise<{ groups: Group[] }> {
- return getJSON('/api/qualitygates/search_groups', data).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/quality-profiles.ts b/server/sonar-web/src/main/js/api/quality-profiles.ts
deleted file mode 100644
index c01cfc20907..00000000000
--- a/server/sonar-web/src/main/js/api/quality-profiles.ts
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { map } from 'lodash';
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { Exporter, ProfileChangelogEvent } from '../apps/quality-profiles/types';
-import { csvEscape } from '../helpers/csv';
-import { RequestData, post, postJSON } from '../helpers/request';
-import {
- CleanCodeAttributeCategory,
- SoftwareImpact,
- SoftwareImpactSeverity,
- SoftwareQuality,
-} from '../types/clean-code-taxonomy';
-import { QualityProfileChangelogFilterMode } from '../types/quality-profiles';
-import { Dict, Paging, ProfileInheritanceDetails, UserSelected } from '../types/types';
-
-export interface ProfileActions {
- associateProjects?: boolean;
- copy?: boolean;
- delete?: boolean;
- edit?: boolean;
- setAsDefault?: boolean;
-}
-
-export interface Actions {
- create?: boolean;
-}
-
-export interface Profile {
- actions?: ProfileActions;
- activeDeprecatedRuleCount: number;
- activeRuleCount: number;
- isBuiltIn?: boolean;
- isDefault?: boolean;
- isInherited?: boolean;
- key: string;
- language: string;
- languageName: string;
- lastUsed?: string;
- name: string;
- parentKey?: string;
- parentName?: string;
- projectCount?: number;
- rulesUpdatedAt?: string;
- userUpdatedAt?: string;
-}
-
-export interface SearchQualityProfilesParameters {
- defaults?: boolean;
- language?: string;
- project?: string;
- qualityProfile?: string;
-}
-
-export interface SearchQualityProfilesResponse {
- actions?: Actions;
- profiles: Profile[];
-}
-
-export function searchQualityProfiles(
- parameters?: SearchQualityProfilesParameters,
-): Promise<SearchQualityProfilesResponse> {
- return getJSON('/api/qualityprofiles/search', parameters).catch(throwGlobalError);
-}
-
-export function getQualityProfile({
- compareToSonarWay,
- profile: { key },
-}: {
- compareToSonarWay?: boolean;
- profile: Profile;
-}): Promise<{
- compareToSonarWay?: { missingRuleCount: number; profile: string; profileName: string };
- profile: Profile;
-}> {
- return getJSON('/api/qualityprofiles/show', { compareToSonarWay, key });
-}
-
-export function createQualityProfile(data: RequestData): Promise<any> {
- return postJSON('/api/qualityprofiles/create', data).catch(throwGlobalError);
-}
-
-export function restoreQualityProfile(data: RequestData): Promise<any> {
- return postJSON('/api/qualityprofiles/restore', data).catch(throwGlobalError);
-}
-
-export interface ProfileProject {
- key: string;
- name: string;
- selected: boolean;
-}
-
-export function getProfileProjects(
- data: RequestData,
-): Promise<{ more: boolean; paging: Paging; results: ProfileProject[] }> {
- return getJSON('/api/qualityprofiles/projects', data).catch(throwGlobalError);
-}
-
-export function getProfileInheritance({
- language,
- name: qualityProfile,
-}: Pick<Profile, 'language' | 'name'>): Promise<{
- ancestors: ProfileInheritanceDetails[];
- children: ProfileInheritanceDetails[];
- profile: ProfileInheritanceDetails | null;
-}> {
- return getJSON('/api/qualityprofiles/inheritance', {
- language,
- qualityProfile,
- }).catch(throwGlobalError);
-}
-
-export function setDefaultProfile({ language, name: qualityProfile }: Profile) {
- return post('/api/qualityprofiles/set_default', {
- language,
- qualityProfile,
- });
-}
-
-export function renameProfile(key: string, name: string) {
- return post('/api/qualityprofiles/rename', { key, name }).catch(throwGlobalError);
-}
-
-export function copyProfile(fromKey: string, name: string): Promise<Profile> {
- return postJSON('/api/qualityprofiles/copy', { fromKey, toName: name }).catch(throwGlobalError);
-}
-
-export function deleteProfile({ language, name: qualityProfile }: Profile) {
- return post('/api/qualityprofiles/delete', { language, qualityProfile }).catch(throwGlobalError);
-}
-
-export function changeProfileParent(
- { language, name: qualityProfile }: Profile,
- parentProfile?: Profile,
-) {
- return post('/api/qualityprofiles/change_parent', {
- language,
- qualityProfile,
- parentQualityProfile: parentProfile ? parentProfile.name : undefined,
- }).catch(throwGlobalError);
-}
-
-export function getQualityProfileExporterUrl(
- { key: exporterKey }: Exporter,
- { language, name: qualityProfile }: Profile,
-) {
- const queryParams = Object.entries({ exporterKey, language, qualityProfile })
- .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
- .join('&');
- return `/api/qualityprofiles/export?${queryParams}`;
-}
-
-export function getImporters(): Promise<
- Array<{ key: string; languages: Array<string>; name: string }>
-> {
- return getJSON('/api/qualityprofiles/importers').then((r) => r.importers, throwGlobalError);
-}
-
-export function getExporters(): Promise<any> {
- return getJSON('/api/qualityprofiles/exporters').then((r) => r.exporters);
-}
-
-export interface ChangelogResponse {
- events: ProfileChangelogEvent[];
- paging: Paging;
-}
-
-interface ChangelogData {
- filterMode: QualityProfileChangelogFilterMode;
- page?: number;
- profile: Profile;
- since: string;
- to: string;
-}
-
-export function getProfileChangelog(data: ChangelogData): Promise<ChangelogResponse> {
- const {
- filterMode,
- page,
- profile: { language, name: qualityProfile },
- since,
- to,
- } = data;
- return getJSON('/api/qualityprofiles/changelog', {
- since,
- to,
- language,
- qualityProfile,
- filterMode,
- p: page,
- });
-}
-
-export interface RuleCompare {
- cleanCodeAttributeCategory?: CleanCodeAttributeCategory;
- impacts?: SoftwareImpact[];
- key: string;
- left?: { impacts?: SoftwareImpact[]; params?: Dict<string>; severity?: string };
- name: string;
- right?: { impacts?: SoftwareImpact[]; params?: Dict<string>; severity?: string };
-}
-
-export interface CompareResponse {
- inLeft: Array<RuleCompare>;
- inRight: Array<RuleCompare>;
- left: { name: string };
- modified: Array<RuleCompare & Required<Pick<RuleCompare, 'left' | 'right'>>>;
- right: { name: string };
-}
-
-export function compareProfiles(leftKey: string, rightKey: string): Promise<CompareResponse> {
- return getJSON('/api/qualityprofiles/compare', { leftKey, rightKey });
-}
-
-export function associateProject({ language, name: qualityProfile }: Profile, project: string) {
- return post('/api/qualityprofiles/add_project', {
- language,
- qualityProfile,
- project,
- }).catch(throwGlobalError);
-}
-
-export function dissociateProject({ language, name: qualityProfile }: Profile, project: string) {
- return post('/api/qualityprofiles/remove_project', {
- language,
- qualityProfile,
- project,
- }).catch(throwGlobalError);
-}
-
-export interface SearchUsersGroupsParameters {
- language: string;
- q?: string;
- qualityProfile: string;
- selected?: 'all' | 'selected' | 'deselected';
-}
-
-interface SearchUsersResponse {
- paging: Paging;
- users: UserSelected[];
-}
-
-export function searchUsers(parameters: SearchUsersGroupsParameters): Promise<SearchUsersResponse> {
- return getJSON('/api/qualityprofiles/search_users', parameters).catch(throwGlobalError);
-}
-
-export interface SearchGroupsResponse {
- groups: Array<{ name: string }>;
- paging: Paging;
-}
-
-export function searchGroups(
- parameters: SearchUsersGroupsParameters,
-): Promise<SearchGroupsResponse> {
- return getJSON('/api/qualityprofiles/search_groups', parameters).catch(throwGlobalError);
-}
-
-export interface AddRemoveUserParameters {
- language: string;
- login: string;
- qualityProfile: string;
-}
-
-export function addUser(parameters: AddRemoveUserParameters): Promise<void | Response> {
- return post('/api/qualityprofiles/add_user', parameters).catch(throwGlobalError);
-}
-
-export function removeUser(parameters: AddRemoveUserParameters): Promise<void | Response> {
- return post('/api/qualityprofiles/remove_user', parameters).catch(throwGlobalError);
-}
-
-export interface AddRemoveGroupParameters {
- group: string;
- language: string;
- qualityProfile: string;
-}
-
-export function addGroup(parameters: AddRemoveGroupParameters): Promise<void | Response> {
- return post('/api/qualityprofiles/add_group', parameters).catch(throwGlobalError);
-}
-
-export function removeGroup(parameters: AddRemoveGroupParameters): Promise<void | Response> {
- return post('/api/qualityprofiles/remove_group', parameters).catch(throwGlobalError);
-}
-
-export interface BulkActivateParameters {
- activation?: boolean;
- active_severities?: string;
- asc?: boolean;
- available_since?: string;
- compareToProfile?: string;
- inheritance?: string;
- is_template?: string;
- languages?: string;
- q?: string;
- qprofile?: string;
- repositories?: string;
- rule_key?: string;
- s?: string;
- severities?: string;
- statuses?: string;
- tags?: string;
- targetKey: string;
- targetSeverity?: string;
- template_key?: string;
- types?: string;
-}
-
-export function bulkActivateRules(data: BulkActivateParameters) {
- return postJSON('/api/qualityprofiles/activate_rules', data);
-}
-
-export function bulkDeactivateRules(data: BulkActivateParameters) {
- return postJSON('/api/qualityprofiles/deactivate_rules', data);
-}
-
-export interface ActivateRuleParameters {
- impacts?: Record<SoftwareQuality, SoftwareImpactSeverity>;
- key: string;
- params?: Record<string, string>;
- prioritizedRule?: boolean;
- reset?: boolean;
- rule: string;
- severity?: string;
-}
-
-export function activateRule(data: ActivateRuleParameters) {
- const params =
- data.params && map(data.params, (value, key) => `${key}=${csvEscape(value)}`).join(';');
- const impacts = data.impacts && map(data.impacts, (value, key) => `${key}=${value}`).join(';');
- return post('/api/qualityprofiles/activate_rule', {
- ...data,
- params,
- impacts,
- }).catch(throwGlobalError);
-}
-
-export interface DeactivateRuleParameters {
- key: string;
- rule: string;
-}
-
-export function deactivateRule(data: DeactivateRuleParameters) {
- return post('/api/qualityprofiles/deactivate_rule', data).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/regulatory-report.ts b/server/sonar-web/src/main/js/api/regulatory-report.ts
deleted file mode 100644
index 13aff7d1496..00000000000
--- a/server/sonar-web/src/main/js/api/regulatory-report.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getBaseUrl } from '../helpers/system';
-
-export function getRegulatoryReportUrl(project: string, branch?: string): string {
- const params = new URLSearchParams({ project });
- if (branch) {
- params.append('branch', branch);
- }
- return `${getBaseUrl()}/api/regulatory_reports/download?${params.toString()}`;
-}
diff --git a/server/sonar-web/src/main/js/api/rules.ts b/server/sonar-web/src/main/js/api/rules.ts
deleted file mode 100644
index 3b75ebed8a9..00000000000
--- a/server/sonar-web/src/main/js/api/rules.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { HttpStatusCode } from 'axios';
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { axiosToCatch, post, postJSON } from '../helpers/request';
-import { CleanCodeAttribute, SoftwareImpact } from '../types/clean-code-taxonomy';
-import { GetRulesAppResponse, SearchRulesResponse } from '../types/coding-rules';
-import { SearchRulesQuery } from '../types/rules';
-import {
- RestRuleDetails,
- RestRuleParameter,
- RuleActivation,
- RuleDetails,
- RulesUpdateRequest,
- RuleType,
-} from '../types/types';
-
-const RULES_ENDPOINT = '/api/v2/clean-code-policy/rules';
-
-export interface CreateRuleData {
- cleanCodeAttribute?: CleanCodeAttribute;
- impacts: SoftwareImpact[];
- key: string;
- markdownDescription: string;
- name: string;
- parameters?: Partial<RestRuleParameter>[];
- severity?: string;
- status?: string;
- templateKey: string;
- type?: RuleType;
-}
-
-export function getRulesApp(): Promise<GetRulesAppResponse> {
- return getJSON('/api/rules/app').catch(throwGlobalError);
-}
-
-export function searchRules(data: SearchRulesQuery): Promise<SearchRulesResponse> {
- return getJSON('/api/rules/search', data).catch(throwGlobalError);
-}
-
-export function listRules(data: SearchRulesQuery): Promise<SearchRulesResponse> {
- return getJSON('/api/rules/list', data).catch(throwGlobalError);
-}
-
-export function getRuleRepositories(parameters: {
- q: string;
-}): Promise<Array<{ key: string; language: string; name: string }>> {
- return getJSON('/api/rules/repositories', parameters).then(
- ({ repositories }) => repositories,
- throwGlobalError,
- );
-}
-
-export function getRuleDetails(parameters: {
- actives?: boolean;
- key: string;
-}): Promise<{ actives?: RuleActivation[]; rule: RuleDetails }> {
- return getJSON('/api/rules/show', parameters).catch(throwGlobalError);
-}
-
-export function getRuleTags(parameters: { ps?: number; q: string }): Promise<string[]> {
- return getJSON('/api/rules/tags', parameters).then((r) => r.tags, throwGlobalError);
-}
-
-export function createRule(data: CreateRuleData): Promise<RestRuleDetails> {
- return axiosToCatch.post<RuleDetails>(RULES_ENDPOINT, data).catch(({ response }) => {
- // do not show global error if the status code is 409
- // this case should be handled inside a component
- if (response && response.status === HttpStatusCode.Conflict) {
- return Promise.reject(response);
- }
- return throwGlobalError(response);
- });
-}
-
-export function deleteRule(parameters: { key: string }) {
- return post('/api/rules/delete', parameters).catch(throwGlobalError);
-}
-
-export function updateRule(data: RulesUpdateRequest): Promise<RuleDetails> {
- const impacts =
- data.impacts &&
- Object.values(data.impacts)
- .map((impact) => `${impact.softwareQuality}=${impact.severity}`)
- .join(';');
-
- return postJSON('/api/rules/update', { ...data, impacts }).then((r) => r.rule, throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/scim-provisioning.ts b/server/sonar-web/src/main/js/api/scim-provisioning.ts
deleted file mode 100644
index ac2632c8140..00000000000
--- a/server/sonar-web/src/main/js/api/scim-provisioning.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post } from '../helpers/request';
-
-export function fetchIsScimEnabled(): Promise<boolean> {
- return getJSON('/api/scim_management/status')
- .then((r) => r.enabled)
- .catch(throwGlobalError);
-}
-
-export function activateScim(): Promise<void> {
- return post('/api/scim_management/enable').catch(throwGlobalError);
-}
-
-export function deactivateScim(): Promise<void> {
- return post('/api/scim_management/disable').catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/security-hotspots.ts b/server/sonar-web/src/main/js/api/security-hotspots.ts
deleted file mode 100644
index bde0dac9dd9..00000000000
--- a/server/sonar-web/src/main/js/api/security-hotspots.ts
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { post } from '../helpers/request';
-import {
- Hotspot,
- HotspotAssignRequest,
- HotspotComment,
- HotspotResolution,
- HotspotSearchResponse,
- HotspotSetStatusRequest,
- HotspotStatus,
-} from '../types/security-hotspots';
-import { UserBase } from '../types/users';
-
-const HOTSPOTS_LIST_URL = '/api/hotspots/list';
-const HOTSPOTS_SEARCH_URL = '/api/hotspots/search';
-
-export function assignSecurityHotspot(
- hotspotKey: string,
- data: HotspotAssignRequest,
-): Promise<void> {
- return post('/api/hotspots/assign', { hotspot: hotspotKey, ...data }).catch(throwGlobalError);
-}
-
-export function setSecurityHotspotStatus(
- hotspotKey: string,
- data: HotspotSetStatusRequest,
-): Promise<void> {
- return post('/api/hotspots/change_status', { hotspot: hotspotKey, ...data }).catch(
- throwGlobalError,
- );
-}
-
-export function commentSecurityHotspot(hotspotKey: string, comment: string): Promise<void> {
- return post('/api/hotspots/add_comment', { hotspot: hotspotKey, comment }).catch(
- throwGlobalError,
- );
-}
-
-export function deleteSecurityHotspotComment(commentKey: string): Promise<void> {
- return post('/api/hotspots/delete_comment', { comment: commentKey }).catch(throwGlobalError);
-}
-
-export function editSecurityHotspotComment(
- commentKey: string,
- comment: string,
-): Promise<HotspotComment> {
- return post('/api/hotspots/edit_comment', { comment: commentKey, text: comment }).catch(
- throwGlobalError,
- );
-}
-
-export function getSecurityHotspots(
- data: {
- inNewCodePeriod?: boolean;
- onlyMine?: boolean;
- p: number;
- project: string;
- ps: number;
- resolution?: HotspotResolution;
- status?: HotspotStatus;
- } & BranchParameters,
- projectIsIndexing = false,
-): Promise<HotspotSearchResponse> {
- return getJSON(projectIsIndexing ? HOTSPOTS_LIST_URL : HOTSPOTS_SEARCH_URL, data).catch(
- throwGlobalError,
- );
-}
-
-export function getSecurityHotspotList(
- hotspotKeys: string[],
- data: {
- project: string;
- } & BranchParameters,
- projectIsIndexing = false,
-): Promise<HotspotSearchResponse> {
- return getJSON(projectIsIndexing ? HOTSPOTS_LIST_URL : HOTSPOTS_SEARCH_URL, {
- ...data,
- hotspots: hotspotKeys.join(),
- }).catch(throwGlobalError);
-}
-
-export function getSecurityHotspotDetails(securityHotspotKey: string): Promise<Hotspot> {
- return getJSON('/api/hotspots/show', { hotspot: securityHotspotKey })
- .then((response: Hotspot & { users: UserBase[] }) => {
- const { users, ...hotspot } = response;
-
- if (users) {
- if (hotspot.assignee) {
- hotspot.assigneeUser = users.find((u) => u.login === hotspot.assignee) || {
- active: true,
- login: hotspot.assignee,
- };
- }
-
- hotspot.authorUser = users.find((u) => u.login === hotspot.author) || {
- active: true,
- login: hotspot.author,
- };
-
- hotspot.comment.forEach((c) => {
- c.user = users.find((u) => u.login === c.login) || { active: true, login: c.login };
- });
- }
-
- return hotspot;
- })
- .catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/settings.ts b/server/sonar-web/src/main/js/api/settings.ts
deleted file mode 100644
index 321373079ca..00000000000
--- a/server/sonar-web/src/main/js/api/settings.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { omitBy } from 'lodash';
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { isCategoryDefinition } from '../apps/settings/utils';
-import { post, postJSON, RequestData } from '../helpers/request';
-import {
- ExtendedSettingDefinition,
- SettingDefinition,
- SettingType,
- SettingValue,
- SettingValueResponse,
-} from '../types/settings';
-
-export function getDefinitions(component?: string): Promise<ExtendedSettingDefinition[]> {
- return getJSON('/api/settings/list_definitions', { component }).then(
- (r) => r.definitions,
- throwGlobalError,
- );
-}
-
-export function getValue(
- data: { component?: string; key: string } & BranchParameters,
-): Promise<SettingValue | undefined> {
- return getValues({ keys: [data.key], component: data.component }).then(([result]) => result);
-}
-
-export function getValues(
- data: { component?: string; keys: string[] } & BranchParameters,
-): Promise<(SettingValue | undefined)[]> {
- return getJSON('/api/settings/values', {
- keys: data.keys.join(','),
- component: data.component,
- }).then((r: SettingValueResponse) => [
- ...r.settings,
- ...r.setSecuredSettings.map((key) => ({ key })),
- ]);
-}
-
-export function getAllValues(
- data: { component?: string } & BranchParameters = {},
-): Promise<SettingValue[]> {
- return getJSON('/api/settings/values', data).then((r: SettingValueResponse) => [
- ...r.settings,
- ...r.setSecuredSettings.map((key) => ({ key })),
- ]);
-}
-
-export function setSettingValue(
- definition: SettingDefinition,
- value: any,
- component?: string,
-): Promise<void> {
- const { key } = definition;
- const data: RequestData = { key, component };
-
- if (definition.type === SettingType.PROPERTY_SET) {
- data.fieldValues = value
- .map((fields: any) => omitBy(fields, (value) => value == null))
- .map(JSON.stringify);
- } else if (isCategoryDefinition(definition) && definition.multiValues) {
- data.values = value;
- } else {
- data.value = value;
- }
-
- return post('/api/settings/set', data);
-}
-
-export function setSimpleSettingValue(
- data: { component?: string; key: string; value?: string; values?: string[] } & BranchParameters,
-): Promise<void | Response> {
- return post('/api/settings/set', data).catch(throwGlobalError);
-}
-
-export function resetSettingValue(
- data: { component?: string; keys: string } & BranchParameters,
-): Promise<void> {
- return post('/api/settings/reset', data);
-}
-
-export function sendTestEmail(to: string, subject: string, message: string): Promise<void> {
- return post('/api/emails/send', { to, subject, message });
-}
-
-export function checkSecretKey(): Promise<{ secretKeyAvailable: boolean }> {
- return getJSON('/api/settings/check_secret_key').catch(throwGlobalError);
-}
-
-export function generateSecretKey(): Promise<{ secretKey: string }> {
- return getJSON('/api/settings/generate_secret_key').catch(throwGlobalError);
-}
-
-export function encryptValue(value: string): Promise<{ encryptedValue: string }> {
- return postJSON('/api/settings/encrypt', { value }).catch(throwGlobalError);
-}
-
-export function getLoginMessage(): Promise<{ message: string }> {
- return getJSON('/api/settings/login_message').catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/sources.ts b/server/sonar-web/src/main/js/api/sources.ts
deleted file mode 100644
index 0578126a19e..00000000000
--- a/server/sonar-web/src/main/js/api/sources.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { get, parseText } from '../helpers/request';
-import { BranchParameters } from '../sonar-aligned/types/branch-like';
-
-export function getRawSource(data: BranchParameters & { key: string }): Promise<string> {
- return get('/api/sources/raw', data).then(parseText);
-}
diff --git a/server/sonar-web/src/main/js/api/static.ts b/server/sonar-web/src/main/js/api/static.ts
deleted file mode 100644
index 909823d53b2..00000000000
--- a/server/sonar-web/src/main/js/api/static.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { checkStatus, request } from '../helpers/request';
-
-export function getPluginStaticFileContent(pluginKey: string, staticFilePath: string) {
- return request(`/static/${pluginKey}/${staticFilePath}`)
- .submit()
- .then(checkStatus)
- .then((response) => response.text());
-}
diff --git a/server/sonar-web/src/main/js/api/system.ts b/server/sonar-web/src/main/js/api/system.ts
deleted file mode 100644
index b2928529b18..00000000000
--- a/server/sonar-web/src/main/js/api/system.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import axios from 'axios';
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post, postJSON, requestTryAndRepeatUntil } from '../helpers/request';
-import {
- EmailConfiguration,
- MigrationStatus,
- MigrationsStatusResponse,
- SystemUpgrade,
-} from '../types/system';
-import { Paging, SysInfoCluster, SysInfoStandalone, SysStatus } from '../types/types';
-
-const MIGRATIONS_STATUS_ENDPOINT = '/api/v2/system/migrations-status';
-const EMAIL_NOTIFICATION_PATH = '/api/v2/system/email-configurations';
-
-export function setLogLevel(level: string): Promise<void | Response> {
- return post('/api/system/change_log_level', { level }).catch(throwGlobalError);
-}
-
-export function getSystemInfo(): Promise<SysInfoCluster | SysInfoStandalone> {
- return getJSON('/api/system/info').catch(throwGlobalError);
-}
-
-export function getSystemStatus(): Promise<{ id: string; status: SysStatus; version: string }> {
- return getJSON('/api/system/status');
-}
-
-export function getSystemUpgrades(): Promise<{
- installedVersionActive?: boolean;
- latestLTA?: string;
- updateCenterRefresh?: string;
- upgrades: SystemUpgrade[];
-}> {
- return getJSON('/api/system/upgrades');
-}
-
-export function getMigrationsStatus() {
- return axios.get<MigrationsStatusResponse>(MIGRATIONS_STATUS_ENDPOINT);
-}
-
-export function migrateDatabase(): Promise<{
- message?: string;
- startedAt?: string;
- state: MigrationStatus;
-}> {
- return postJSON('/api/system/migrate_db');
-}
-
-export function restart(): Promise<void | Response> {
- return post('/api/system/restart').catch(throwGlobalError);
-}
-
-export function waitSystemUPStatus(): Promise<{
- id: string;
- status: SysStatus;
- version: string;
-}> {
- return requestTryAndRepeatUntil(
- getSystemStatus,
- { max: -1, slowThreshold: -15 },
- ({ status }) => status === 'UP',
- );
-}
-
-export function getEmailConfigurations(): Promise<{
- emailConfigurations: EmailConfiguration[];
- page: Paging;
-}> {
- return axios.get(EMAIL_NOTIFICATION_PATH);
-}
-
-export function postEmailConfiguration(data: EmailConfiguration): Promise<EmailConfiguration> {
- return axios.post<EmailConfiguration, EmailConfiguration>(EMAIL_NOTIFICATION_PATH, data);
-}
-
-export function patchEmailConfiguration(
- id: string,
- emailConfiguration: EmailConfiguration,
-): Promise<EmailConfiguration> {
- return axios.patch<EmailConfiguration, EmailConfiguration>(
- `${EMAIL_NOTIFICATION_PATH}/${id}`,
- emailConfiguration,
- );
-}
diff --git a/server/sonar-web/src/main/js/api/time-machine.ts b/server/sonar-web/src/main/js/api/time-machine.ts
deleted file mode 100644
index b5db251fde9..00000000000
--- a/server/sonar-web/src/main/js/api/time-machine.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { Paging } from '../types/types';
-
-export interface TimeMachineResponse {
- measures: {
- history: Array<{ date: string; value?: string }>;
- metric: MetricKey;
- }[];
- paging: Paging;
-}
-
-export function getTimeMachineData(
- data: {
- component?: string;
- from?: string;
- metrics: string;
- p?: number;
- ps?: number;
- to?: string;
- } & BranchParameters,
-): Promise<TimeMachineResponse> {
- return getJSON('/api/measures/search_history', data).catch(throwGlobalError);
-}
-
-export function getAllTimeMachineData(
- data: {
- component?: string;
- from?: string;
- metrics: string;
- p?: number;
- to?: string;
- } & BranchParameters,
- prev?: TimeMachineResponse,
-): Promise<TimeMachineResponse> {
- return getTimeMachineData({ ...data, ps: 1000 }).then((r) => {
- const result = prev
- ? {
- measures: prev.measures.map((measure, idx) => ({
- ...measure,
- history: measure.history.concat(r.measures[idx].history),
- })),
- paging: r.paging,
- }
- : r;
-
- if (result.paging.pageIndex * result.paging.pageSize >= result.paging.total) {
- return result;
- }
- return getAllTimeMachineData({ ...data, p: result.paging.pageIndex + 1 }, result);
- });
-}
diff --git a/server/sonar-web/src/main/js/api/user-tokens.ts b/server/sonar-web/src/main/js/api/user-tokens.ts
deleted file mode 100644
index 6a16cc3b1f9..00000000000
--- a/server/sonar-web/src/main/js/api/user-tokens.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post, postJSON } from '../helpers/request';
-import { NewUserToken, UserToken } from '../types/token';
-
-/** List tokens for given user login */
-export function getTokens(login: string): Promise<UserToken[]> {
- return getJSON('/api/user_tokens/search', { login }).then((r) => r.userTokens, throwGlobalError);
-}
-
-export function generateToken(data: {
- expirationDate?: string;
- login?: string;
- name: string;
- projectKey?: string;
- type?: string;
-}): Promise<NewUserToken> {
- return postJSON('/api/user_tokens/generate', data).catch(throwGlobalError);
-}
-
-export function revokeToken(data: { login?: string; name: string }) {
- return post('/api/user_tokens/revoke', data).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/user_groups.ts b/server/sonar-web/src/main/js/api/user_groups.ts
deleted file mode 100644
index 9c69a7e8b63..00000000000
--- a/server/sonar-web/src/main/js/api/user_groups.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import axios from 'axios';
-import { Group, Paging } from '../types/types';
-
-const GROUPS_ENDPOINT = '/api/v2/authorizations/groups';
-
-export function getUsersGroups(params: {
- managed?: boolean;
- pageIndex?: number;
- pageSize?: number;
- q?: string;
-}): Promise<{ groups: Group[]; page: Paging }> {
- return axios.get(GROUPS_ENDPOINT, { params });
-}
-
-export function createGroup(data: { description?: string; name: string }): Promise<Group> {
- return axios.post(GROUPS_ENDPOINT, data).then((r) => r.group);
-}
-
-export function updateGroup(
- id: string,
- data: {
- description?: string;
- name?: string;
- },
-) {
- return axios.patch(`${GROUPS_ENDPOINT}/${id}`, data);
-}
-
-export function deleteGroup(id: string) {
- return axios.delete(`${GROUPS_ENDPOINT}/${id}`);
-}
diff --git a/server/sonar-web/src/main/js/api/users.ts b/server/sonar-web/src/main/js/api/users.ts
deleted file mode 100644
index d3e094f0a03..00000000000
--- a/server/sonar-web/src/main/js/api/users.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import axios from 'axios';
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { HttpStatus, parseJSON, post } from '../helpers/request';
-import { IdentityProvider, Paging } from '../types/types';
-import {
- ChangePasswordResults,
- CurrentUser,
- HomePage,
- NoticeType,
- RestUserBase,
- RestUserDetailed,
-} from '../types/users';
-
-const USERS_ENDPOINT = '/api/v2/users-management/users';
-
-export function getCurrentUser(): Promise<CurrentUser> {
- return getJSON('/api/users/current', undefined, { bypassRedirect: true });
-}
-
-export function dismissNotice(notice: NoticeType) {
- return post('/api/users/dismiss_notice', { notice }).catch(throwGlobalError);
-}
-
-export function changePassword(data: {
- login: string;
- password: string;
- previousPassword?: string;
-}) {
- return post('/api/users/change_password', data).catch(async (response) => {
- if (response.status === HttpStatus.BadRequest) {
- const { result } = await parseJSON(response);
- return Promise.reject<ChangePasswordResults>(result);
- }
-
- return throwGlobalError(response);
- });
-}
-
-export function getIdentityProviders(): Promise<{ identityProviders: IdentityProvider[] }> {
- return getJSON('/api/users/identity_providers').catch(throwGlobalError);
-}
-
-export function getUsers<T extends RestUserBase>(data: {
- active?: boolean;
- groupId?: string;
- 'groupId!'?: string;
- managed?: boolean;
- pageIndex?: number;
- pageSize?: number;
- q: string;
- sonarLintLastConnectionDateFrom?: string;
- sonarLintLastConnectionDateTo?: string;
- sonarQubeLastConnectionDateFrom?: string;
- sonarQubeLastConnectionDateTo?: string;
-}) {
- return axios.get<{ page: Paging; users: T[] }>(USERS_ENDPOINT, {
- params: data,
- });
-}
-
-export function postUser(data: {
- email?: string;
- login: string;
- name: string;
- password?: string;
- scmAccounts: string[];
-}) {
- return axios.post<RestUserDetailed>(USERS_ENDPOINT, data);
-}
-
-export function updateUser(
- id: string,
- data: Partial<Pick<RestUserDetailed, 'email' | 'name' | 'scmAccounts'>>,
-) {
- return axios.patch<RestUserDetailed>(`${USERS_ENDPOINT}/${id}`, data);
-}
-
-export function deleteUser({ id, anonymize }: { anonymize?: boolean; id: string }) {
- return axios.delete(`${USERS_ENDPOINT}/${id}`, { params: { anonymize } });
-}
-
-export function setHomePage(homepage: HomePage): Promise<void | Response> {
- return post('/api/users/set_homepage', homepage).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/web-api.ts b/server/sonar-web/src/main/js/api/web-api.ts
deleted file mode 100644
index acea083ee99..00000000000
--- a/server/sonar-web/src/main/js/api/web-api.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { OpenAPIV3 } from 'openapi-types';
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { WebApi } from '../types/types';
-
-interface RawDomain {
- actions: WebApi.Action[];
- deprecatedSince?: string;
- description: string;
- internal: boolean;
- path: string;
- since?: string;
-}
-
-export function fetchWebApi(showInternal = true): Promise<RawDomain[]> {
- return getJSON('/api/webservices/list', { include_internals: showInternal })
- .then((r) => r.webServices)
- .catch(throwGlobalError);
-}
-
-export function fetchResponseExample(domain: string, action: string): Promise<WebApi.Example> {
- return getJSON('/api/webservices/response_example', { controller: domain, action }).catch(
- throwGlobalError,
- );
-}
-
-export function fetchOpenAPI(): Promise<OpenAPIV3.Document> {
- return getJSON('/api/v2/api-docs').catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/api/webhooks.ts b/server/sonar-web/src/main/js/api/webhooks.ts
deleted file mode 100644
index 20047594b22..00000000000
--- a/server/sonar-web/src/main/js/api/webhooks.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { post, postJSON } from '../helpers/request';
-import { Paging } from '../types/types';
-import {
- WebhookCreatePayload,
- WebhookDelivery,
- WebhookResponse,
- WebhookSearchDeliveriesPayload,
- WebhookUpdatePayload,
-} from '../types/webhook';
-
-export function createWebhook(data: WebhookCreatePayload): Promise<{ webhook: WebhookResponse }> {
- return postJSON('/api/webhooks/create', data).catch(throwGlobalError);
-}
-
-export function deleteWebhook(data: { webhook: string }): Promise<void | Response> {
- return post('/api/webhooks/delete', data).catch(throwGlobalError);
-}
-
-export function searchWebhooks(data: {
- project?: string;
-}): Promise<{ webhooks: WebhookResponse[] }> {
- return getJSON('/api/webhooks/list', data).catch(throwGlobalError);
-}
-
-export function updateWebhook(data: WebhookUpdatePayload): Promise<void | Response> {
- return post('/api/webhooks/update', data).catch(throwGlobalError);
-}
-
-export function searchDeliveries(data: WebhookSearchDeliveriesPayload): Promise<{
- deliveries: WebhookDelivery[];
- paging: Paging;
-}> {
- return getJSON('/api/webhooks/deliveries', data).catch(throwGlobalError);
-}
-
-export function getDelivery(data: {
- deliveryId: string;
-}): Promise<{ delivery: WebhookDelivery & { payload: string } }> {
- return getJSON('/api/webhooks/delivery', data).catch(throwGlobalError);
-}
diff --git a/server/sonar-web/src/main/js/app/components/AdminContainer.tsx b/server/sonar-web/src/main/js/app/components/AdminContainer.tsx
deleted file mode 100644
index 65e122d5618..00000000000
--- a/server/sonar-web/src/main/js/app/components/AdminContainer.tsx
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { createPortal } from 'react-dom';
-import { Helmet } from 'react-helmet-async';
-import { Outlet } from 'react-router-dom';
-import { getSettingsNavigation } from '../../api/navigation';
-import { getPendingPlugins } from '../../api/plugins';
-import { getSystemStatus, waitSystemUPStatus } from '../../api/system';
-import handleRequiredAuthorization from '../../app/utils/handleRequiredAuthorization';
-import { translate } from '../../helpers/l10n';
-import { getIntl } from '../../helpers/l10nBundle';
-import { AdminPagesContext } from '../../types/admin';
-import { AppState } from '../../types/appstate';
-import { PendingPluginResult } from '../../types/plugins';
-import { Extension, SysStatus } from '../../types/types';
-import AdminContext, { defaultPendingPlugins, defaultSystemStatus } from './AdminContext';
-import withAppStateContext from './app-state/withAppStateContext';
-import SettingsNav from './nav/settings/SettingsNav';
-
-export interface AdminContainerProps {
- appState: AppState;
-}
-
-interface State {
- adminPages: Extension[];
- pendingPlugins: PendingPluginResult;
- systemStatus: SysStatus;
-}
-
-export class AdminContainer extends React.PureComponent<AdminContainerProps, State> {
- intl = getIntl();
- mounted = false;
- portalAnchor: Element | null = null;
- state: State = {
- pendingPlugins: defaultPendingPlugins,
- systemStatus: defaultSystemStatus,
- adminPages: [],
- };
-
- componentDidMount() {
- this.mounted = true;
- this.portalAnchor = document.getElementById('component-nav-portal');
- if (!this.props.appState.canAdmin) {
- handleRequiredAuthorization();
- } else {
- this.fetchNavigationSettings();
- this.fetchPendingPlugins();
- this.fetchSystemStatus();
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchNavigationSettings = () => {
- getSettingsNavigation().then(
- (r) => this.setState({ adminPages: r.extensions }),
- () => {},
- );
- };
-
- fetchPendingPlugins = () => {
- getPendingPlugins().then(
- (pendingPlugins) => {
- if (this.mounted) {
- this.setState({ pendingPlugins });
- }
- },
- () => {},
- );
- };
-
- fetchSystemStatus = () => {
- getSystemStatus().then(
- ({ status }) => {
- if (this.mounted) {
- this.setState({ systemStatus: status });
- if (status === 'RESTARTING') {
- this.waitRestartingDone();
- }
- }
- },
- () => {},
- );
- };
-
- waitRestartingDone = () => {
- waitSystemUPStatus().then(
- ({ status }) => {
- if (this.mounted) {
- this.setState({ systemStatus: status });
- window.location.reload();
- }
- },
- () => {},
- );
- };
-
- render() {
- const { adminPages } = this.state;
-
- // Check that the adminPages are loaded
- if (!adminPages) {
- return null;
- }
-
- const { pendingPlugins, systemStatus } = this.state;
- const adminPagesContext: AdminPagesContext = { adminPages };
-
- return (
- <>
- <Helmet
- defer={false}
- titleTemplate={this.intl.formatMessage(
- { id: 'page_title.template.with_category' },
- { page: translate('layout.settings') },
- )}
- />
- {this.portalAnchor &&
- createPortal(
- <SettingsNav
- extensions={adminPages}
- fetchPendingPlugins={this.fetchPendingPlugins}
- fetchSystemStatus={this.fetchSystemStatus}
- pendingPlugins={pendingPlugins}
- systemStatus={systemStatus}
- />,
- this.portalAnchor,
- )}
-
- <AdminContext.Provider
- value={{
- fetchSystemStatus: this.fetchSystemStatus,
- fetchPendingPlugins: this.fetchPendingPlugins,
- pendingPlugins,
- systemStatus,
- }}
- >
- <Outlet context={adminPagesContext} />
- </AdminContext.Provider>
- </>
- );
- }
-}
-
-export default withAppStateContext(AdminContainer);
diff --git a/server/sonar-web/src/main/js/app/components/AdminContext.tsx b/server/sonar-web/src/main/js/app/components/AdminContext.tsx
deleted file mode 100644
index f54cc2416c2..00000000000
--- a/server/sonar-web/src/main/js/app/components/AdminContext.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { PendingPluginResult } from '../../types/plugins';
-import { SysStatus } from '../../types/types';
-
-export interface AdminContextInterface {
- fetchPendingPlugins: () => void;
- fetchSystemStatus: () => void;
- pendingPlugins: PendingPluginResult;
- systemStatus: SysStatus;
-}
-
-export const defaultPendingPlugins = { installing: [], removing: [], updating: [] };
-export const defaultSystemStatus = 'UP';
-
-const AdminContext = React.createContext<AdminContextInterface>({
- fetchSystemStatus: () => {},
- fetchPendingPlugins: () => {},
- pendingPlugins: defaultPendingPlugins,
- systemStatus: defaultSystemStatus,
-});
-export default AdminContext;
diff --git a/server/sonar-web/src/main/js/app/components/AlmSynchronisationWarning.tsx b/server/sonar-web/src/main/js/app/components/AlmSynchronisationWarning.tsx
deleted file mode 100644
index ff930ec835a..00000000000
--- a/server/sonar-web/src/main/js/app/components/AlmSynchronisationWarning.tsx
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { Link, Spinner } from '@sonarsource/echoes-react';
-import { formatDistance } from 'date-fns';
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { CheckIcon, FlagMessage, FlagWarningIcon, themeColor } from '~design-system';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { AlmKeys } from '../../types/alm-settings';
-import { AlmSyncStatus } from '../../types/provisioning';
-import { TaskStatuses } from '../../types/tasks';
-
-interface SynchronisationWarningProps {
- data: AlmSyncStatus;
- provisionedBy: AlmKeys.GitHub | AlmKeys.GitLab;
- short?: boolean;
-}
-
-interface LastSyncProps {
- info: AlmSyncStatus['lastSync'];
- provisionedBy: AlmKeys.GitHub | AlmKeys.GitLab;
- short?: boolean;
-}
-
-function LastSyncAlert({ info, provisionedBy, short }: Readonly<LastSyncProps>) {
- if (info === undefined) {
- return null;
- }
-
- const { finishedAt, errorMessage, status, summary, warningMessage } = info;
-
- const formattedDate = finishedAt ? formatDistance(new Date(finishedAt), new Date()) : '';
-
- if (short) {
- return status === TaskStatuses.Success ? (
- <div>
- <IconWrapper className="sw-ml-2">
- {warningMessage ? (
- <FlagWarningIcon className="sw-mr-2" />
- ) : (
- <CheckIcon width={32} height={32} className="sw-mr-2" />
- )}
- </IconWrapper>
-
- <i>
- {warningMessage ? (
- <FormattedMessage
- defaultMessage={translate(
- 'settings.authentication.synchronization_successful.with_warning',
- )}
- id="settings.authentication.synchronization_successful.with_warning"
- values={{
- date: formattedDate,
- details: (
- <Link
- className="sw-ml-2"
- to={`/admin/settings?category=authentication&tab=${provisionedBy}`}
- >
- {translate('settings.authentication.synchronization_details_link')}
- </Link>
- ),
- }}
- />
- ) : (
- translateWithParameters(
- 'settings.authentication.synchronization_successful',
- formattedDate,
- )
- )}
- </i>
- </div>
- ) : (
- <FlagMessage variant="error">
- <div>
- <FormattedMessage
- defaultMessage={translate('settings.authentication.synchronization_failed_short')}
- id="settings.authentication.synchronization_failed_short"
- values={{
- details: (
- <Link
- className="sw-ml-2"
- to={`/admin/settings?category=authentication&tab=${provisionedBy}`}
- >
- {translate('settings.authentication.synchronization_details_link')}
- </Link>
- ),
- }}
- />
- </div>
- </FlagMessage>
- );
- }
-
- return (
- <>
- <FlagMessage
- aria-live="assertive"
- role="alert"
- variant={status === TaskStatuses.Success ? 'success' : 'error'}
- >
- <div>
- {status === TaskStatuses.Success ? (
- <>
- {translateWithParameters(
- 'settings.authentication.synchronization_successful',
- formattedDate,
- )}
-
- <br />
-
- {summary ?? ''}
- </>
- ) : (
- <React.Fragment key={`synch-alert-${finishedAt}`}>
- <div>
- {translateWithParameters(
- 'settings.authentication.synchronization_failed',
- formattedDate,
- )}
- </div>
-
- <br />
-
- {errorMessage ?? ''}
- </React.Fragment>
- )}
- </div>
- </FlagMessage>
-
- <FlagMessage variant="warning" role="alert" aria-live="assertive">
- {warningMessage}
- </FlagMessage>
- </>
- );
-}
-
-export default function AlmSynchronisationWarning(props: Readonly<SynchronisationWarningProps>) {
- const { data, provisionedBy, short } = props;
- const loadingLabel =
- data.nextSync &&
- translate(
- data.nextSync.status === TaskStatuses.Pending
- ? 'settings.authentication.synchronization_pending'
- : 'settings.authentication.synchronization_in_progress',
- );
-
- return (
- <>
- {!short && (
- <div className={data.nextSync ? 'sw-flex sw-gap-2 sw-mb-4' : ''}>
- <Spinner ariaLabel={loadingLabel} isLoading={!!data.nextSync} />
-
- <div>{data.nextSync && loadingLabel}</div>
- </div>
- )}
-
- <LastSyncAlert short={short} info={data.lastSync} provisionedBy={provisionedBy} />
- </>
- );
-}
-
-const IconWrapper = styled.span`
- color: ${themeColor('iconSuccess')};
-`;
diff --git a/server/sonar-web/src/main/js/app/components/App.tsx b/server/sonar-web/src/main/js/app/components/App.tsx
deleted file mode 100644
index 1d360cdbc1d..00000000000
--- a/server/sonar-web/src/main/js/app/components/App.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Outlet } from 'react-router-dom';
-import { AppState } from '../../types/appstate';
-import { GlobalSettingKeys } from '../../types/settings';
-import KeyboardShortcutsModal from './KeyboardShortcutsModal';
-import PageTracker from './PageTracker';
-import withAppStateContext from './app-state/withAppStateContext';
-
-interface Props {
- appState: AppState;
-}
-
-export class App extends React.PureComponent<Props> {
- mounted = false;
-
- componentDidMount() {
- this.mounted = true;
- this.setScrollbarWidth();
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- setScrollbarWidth = () => {
- // See https://stackoverflow.com/questions/13382516/getting-scroll-bar-width-using-javascript
- const outer = document.createElement('div');
- outer.style.visibility = 'hidden';
- outer.style.width = '100px';
- outer.style.setProperty('msOverflowStyle', 'scrollbar');
-
- document.body.appendChild(outer);
-
- const widthNoScroll = outer.offsetWidth;
- outer.style.overflow = 'scroll';
-
- const inner = document.createElement('div');
- inner.style.width = '100%';
- outer.appendChild(inner);
-
- const widthWithScroll = inner.offsetWidth;
-
- if (outer.parentNode) {
- outer.parentNode.removeChild(outer);
- }
-
- document.body.style.setProperty('--sbw', `${widthNoScroll - widthWithScroll}px`);
- };
-
- renderPreconnectLink = () => {
- const {
- appState: { settings },
- } = this.props;
-
- const enableGravatar = settings[GlobalSettingKeys.EnableGravatar] === 'true';
- const gravatarServerUrl = settings[GlobalSettingKeys.GravatarServerUrl];
-
- if (!enableGravatar || !gravatarServerUrl) {
- return null;
- }
-
- const parser = document.createElement('a');
- parser.href = gravatarServerUrl;
- if (parser.hostname !== window.location.hostname) {
- return <link href={parser.origin} rel="preconnect" />;
- }
- return null;
- };
-
- render() {
- return (
- <>
- <PageTracker>{this.renderPreconnectLink()}</PageTracker>
- <Outlet />
- <KeyboardShortcutsModal />
- </>
- );
- }
-}
-
-export default withAppStateContext(App);
diff --git a/server/sonar-web/src/main/js/app/components/ChangeInCalculationPill.tsx b/server/sonar-web/src/main/js/app/components/ChangeInCalculationPill.tsx
deleted file mode 100644
index cb708ba4639..00000000000
--- a/server/sonar-web/src/main/js/app/components/ChangeInCalculationPill.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Popover } from '@sonarsource/echoes-react';
-import { noop } from 'lodash';
-import { Pill, PillVariant } from '~design-system';
-import DocumentationLink from '../../components/common/DocumentationLink';
-import { DocLink } from '../../helpers/doc-links';
-import { translate } from '../../helpers/l10n';
-import { useStandardExperienceModeQuery } from '../../queries/mode';
-import { ComponentQualifier } from '../../sonar-aligned/types/component';
-
-interface Props {
- qualifier: ComponentQualifier;
-}
-
-export default function ChangeInCalculation({ qualifier }: Readonly<Props>) {
- const { data: isStandardMode, isLoading } = useStandardExperienceModeQuery();
-
- if (isStandardMode || isLoading) {
- return null;
- }
-
- return (
- <Popover
- title={translate('projects.awaiting_scan.title')}
- description={translate(`projects.awaiting_scan.description.${qualifier}`)}
- footer={
- <DocumentationLink shouldOpenInNewTab standalone to={DocLink.MetricDefinitions}>
- {translate('projects.awaiting_scan.learn_more')}
- </DocumentationLink>
- }
- >
- <Pill variant={PillVariant.Info} className="sw-ml-2" onClick={noop}>
- {translate('projects.awaiting_scan')}
- </Pill>
- </Popover>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx
deleted file mode 100644
index 0fb75d5edc3..00000000000
--- a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { differenceBy } from 'lodash';
-import * as React from 'react';
-import { createPortal } from 'react-dom';
-import { Helmet } from 'react-helmet-async';
-import { useIntl } from 'react-intl';
-import { Outlet } from 'react-router-dom';
-import { CenteredLayout, Spinner } from '~design-system';
-import { useLocation, useRouter } from '~sonar-aligned/components/hoc/withRouter';
-import { isPortfolioLike } from '~sonar-aligned/helpers/component';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { validateProjectAlmBinding } from '../../api/alm-settings';
-import { getTasksForComponent } from '../../api/ce';
-import { getComponentData } from '../../api/components';
-import { getComponentNavigation } from '../../api/navigation';
-import { HttpStatus } from '../../helpers/request';
-import { getPortfolioUrl, getProjectUrl, getPullRequestUrl } from '../../helpers/urls';
-import { useCurrentBranchQuery } from '../../queries/branch';
-import { useStandardExperienceModeQuery } from '../../queries/mode';
-import { ProjectAlmBindingConfigurationErrors } from '../../types/alm-settings';
-import { Branch } from '../../types/branch-like';
-import { isFile } from '../../types/component';
-import { Feature } from '../../types/features';
-import { Task, TaskStatuses, TaskTypes } from '../../types/tasks';
-import { Component } from '../../types/types';
-import handleRequiredAuthorization from '../utils/handleRequiredAuthorization';
-import ComponentContainerNotFound from './ComponentContainerNotFound';
-import withAvailableFeatures, {
- WithAvailableFeaturesProps,
-} from './available-features/withAvailableFeatures';
-import { ComponentContext } from './componentContext/ComponentContext';
-import ComponentNav from './nav/component/ComponentNav';
-
-const FETCH_STATUS_WAIT_TIME = 3000;
-
-function ComponentContainer({ hasFeature }: Readonly<WithAvailableFeaturesProps>) {
- const watchStatusTimer = React.useRef<number>();
- const portalAnchor = React.useRef<Element | null>(null);
- const oldTasksInProgress = React.useRef<Task[]>();
- const oldCurrentTask = React.useRef<Task>();
- const {
- query: { id: key, branch, pullRequest, fixedInPullRequest },
- pathname,
- } = useLocation();
- const router = useRouter();
-
- const intl = useIntl();
-
- const [component, setComponent] = React.useState<Component>();
- const [currentTask, setCurrentTask] = React.useState<Task>();
- const [tasksInProgress, setTasksInProgress] = React.useState<Task[]>();
- const [projectBindingErrors, setProjectBindingErrors] =
- React.useState<ProjectAlmBindingConfigurationErrors>();
- const [loading, setLoading] = React.useState(true);
- const [isPending, setIsPending] = React.useState(false);
- const { data: branchLike, isFetching } = useCurrentBranchQuery(
- fixedInPullRequest ? component : undefined,
- );
-
- //prefetch isStandardExperienceMode
- useStandardExperienceModeQuery();
-
- const isInTutorials = pathname.includes('tutorials');
-
- const fetchComponent = React.useCallback(
- async (branchName?: string) => {
- // Only show loader if we're changing components
- if (component?.key !== key) {
- setLoading(true);
- }
- let componentWithQualifier;
- const targetBranch = branch ?? branchName;
- try {
- const [nav, { component }] = await Promise.all([
- getComponentNavigation({ component: key, branch: targetBranch, pullRequest }),
- getComponentData({ component: key, branch: targetBranch, pullRequest }),
- ]);
-
- componentWithQualifier = addQualifier({ ...nav, ...component });
- } catch (e) {
- if (e instanceof Response && e.status === HttpStatus.Forbidden) {
- handleRequiredAuthorization();
- }
- } finally {
- setComponent(componentWithQualifier);
- setLoading(false);
- }
- },
- // eslint-disable-next-line react-hooks/exhaustive-deps
- [key, branch, pullRequest],
- );
-
- const fetchStatus = React.useCallback(
- async (componentKey: string) => {
- try {
- const { current, queue } = await getTasksForComponent(componentKey);
- const newCurrentTask = getCurrentTask(current, branch, pullRequest, isInTutorials);
- const pendingTasks = getReportRelatedPendingTasks(
- queue,
- branch,
- pullRequest,
- isInTutorials,
- );
- const newTasksInProgress = getInProgressTasks(pendingTasks);
-
- const isPending = pendingTasks.some((task) => task.status === TaskStatuses.Pending);
-
- setIsPending(isPending);
- setCurrentTask(newCurrentTask);
- setTasksInProgress(newTasksInProgress);
- } catch {
- // noop
- }
- },
- [branch, isInTutorials, pullRequest],
- );
-
- const fetchProjectBindingErrors = React.useCallback(
- async (component: Component) => {
- if (
- component.qualifier === ComponentQualifier.Project &&
- component.analysisDate === undefined &&
- hasFeature(Feature.BranchSupport)
- ) {
- try {
- const projectBindingErrors = await validateProjectAlmBinding(component.key);
-
- setProjectBindingErrors(projectBindingErrors);
- } catch {
- // noop
- }
- }
- },
- [hasFeature],
- );
-
- const handleComponentChange = React.useCallback(
- (changes: Partial<Component>) => {
- if (!component) {
- return;
- }
-
- setComponent({ ...component, ...changes });
- },
- [component],
- );
-
- React.useEffect(() => {
- if (key) {
- fetchComponent();
- }
- }, [key, fetchComponent]);
-
- // Fetch status and errors when component has changed
- React.useEffect(() => {
- if (component) {
- fetchStatus(component.key);
- fetchProjectBindingErrors(component);
- }
- }, [component, fetchStatus, fetchProjectBindingErrors]);
-
- // Refetch status when tasks in progress/current task have changed
- // Or refetch component based on computeHasUpdatedTasks
- React.useEffect(() => {
- // Stop here if tasks are not fetched yet
- if (!tasksInProgress) {
- return;
- }
-
- const tasks = tasksInProgress ?? [];
- const hasUpdatedTasks = computeHasUpdatedTasks(
- oldTasksInProgress.current,
- tasks,
- oldCurrentTask.current,
- currentTask,
- component,
- );
-
- if (isInTutorials && hasUpdatedTasks) {
- const { branch: branchName, pullRequest: pullRequestKey } = currentTask ?? tasks[0];
- const url =
- pullRequestKey !== undefined
- ? getPullRequestUrl(key, pullRequestKey)
- : getProjectUrl(key, branchName);
- router.replace(url);
- }
-
- if (needsAnotherCheck(hasUpdatedTasks, component, tasks)) {
- // Refresh the status as long as there are tasks in progress or no analysis
- window.clearTimeout(watchStatusTimer.current);
-
- watchStatusTimer.current = window.setTimeout(() => {
- fetchStatus(component?.key ?? '');
- }, FETCH_STATUS_WAIT_TIME);
- } else if (hasUpdatedTasks) {
- fetchComponent();
- }
-
- oldCurrentTask.current = currentTask;
- oldTasksInProgress.current = tasks;
- }, [
- component,
- currentTask,
- fetchComponent,
- fetchStatus,
- isInTutorials,
- key,
- router,
- tasksInProgress,
- ]);
-
- // Refetch component when a new branch is analyzed
- React.useEffect(() => {
- if (branchLike?.analysisDate && !component?.analysisDate) {
- fetchComponent();
- }
- }, [branchLike, component, fetchComponent]);
-
- // Refetch component when target branch for fixing pull request is fetched
- React.useEffect(() => {
- const branch = branchLike as Branch;
-
- if (fixedInPullRequest && !isFetching && branch && component?.branch !== branch.name) {
- fetchComponent(branch.name);
- }
- }, [fetchComponent, component, branchLike, fixedInPullRequest, isFetching]);
-
- // Redirects
- React.useEffect(() => {
- /*
- * There used to be a redirect from /dashboard to /portfolio which caused issues.
- * Links should be fixed to not rely on this redirect, but:
- * This is a fail-safe in case there are still some faulty links remaining.
- */
- if (pathname.includes('dashboard') && component && isPortfolioLike(component.qualifier)) {
- router.replace(getPortfolioUrl(component.key));
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [component]);
-
- // Set portal anchor on mount
- React.useEffect(() => {
- portalAnchor.current = document.querySelector('#component-nav-portal');
- }, []);
-
- const isInProgress = tasksInProgress && tasksInProgress.length > 0;
-
- const componentProviderProps = React.useMemo(
- () => ({
- component,
- currentTask,
- isInProgress,
- isPending,
- onComponentChange: handleComponentChange,
- fetchComponent,
- }),
- [component, currentTask, isInProgress, isPending, handleComponentChange, fetchComponent],
- );
-
- // Show not found component when, after loading:
- // - component is not found
- // - target branch is not found (for pull requests fixing issues in a branch)
- if (!loading && (!component || (fixedInPullRequest && !isFetching && !branchLike))) {
- return <ComponentContainerNotFound isPortfolioLike={pathname.includes('portfolio')} />;
- }
-
- return (
- <div>
- <Helmet
- defer={false}
- titleTemplate={intl.formatMessage(
- { id: 'page_title.template.with_instance' },
- { project: component?.name ?? '' },
- )}
- />
- {component &&
- !isFile(component.qualifier) &&
- portalAnchor.current &&
- /* Use a portal to fix positioning until we can fully review the layout */
- createPortal(
- <ComponentNav
- component={component}
- isInProgress={isInProgress}
- isPending={isPending}
- projectBindingErrors={projectBindingErrors}
- />,
- portalAnchor.current,
- )}
- {loading ? (
- <CenteredLayout>
- <Spinner className="sw-mt-10" />
- </CenteredLayout>
- ) : (
- <ComponentContext.Provider value={componentProviderProps}>
- <Outlet />
- </ComponentContext.Provider>
- )}
- </div>
- );
-}
-
-function addQualifier(component: Component) {
- return {
- ...component,
- qualifier: component.breadcrumbs[component.breadcrumbs.length - 1].qualifier,
- };
-}
-
-function needsAnotherCheck(
- hasUpdatedTasks: boolean,
- component: Component | undefined,
- newTasksInProgress: Task[],
-) {
- return (
- !hasUpdatedTasks && component && (newTasksInProgress.length > 0 || !component.analysisDate)
- );
-}
-
-export function isSameBranch(
- task: Pick<Task, 'branch' | 'pullRequest'>,
- branch?: string,
- pullRequest?: string,
-) {
- if (!branch?.length && !pullRequest?.length) {
- return !task.branch && !task.pullRequest;
- }
-
- if (pullRequest?.length) {
- return pullRequest === task.pullRequest;
- }
-
- return branch === task.branch;
-}
-
-function getCurrentTask(
- current?: Task,
- branch?: string,
- pullRequest?: string,
- canBeDifferentBranchLike = false,
-) {
- if (!current || !isReportRelatedTask(current)) {
- return undefined;
- }
-
- return current.status === TaskStatuses.Failed ||
- canBeDifferentBranchLike ||
- isSameBranch(current, branch, pullRequest)
- ? current
- : undefined;
-}
-
-function getReportRelatedPendingTasks(
- pendingTasks: Task[],
- branch?: string,
- pullRequest?: string,
- canBeDifferentBranchLike = false,
-) {
- return pendingTasks.filter(
- (task) =>
- isReportRelatedTask(task) &&
- (canBeDifferentBranchLike || isSameBranch(task, branch, pullRequest)),
- );
-}
-
-function getInProgressTasks(pendingTasks: Task[]) {
- return pendingTasks.filter((task) => task.status === TaskStatuses.InProgress);
-}
-
-function isReportRelatedTask(task: Task) {
- return [TaskTypes.AppRefresh, TaskTypes.Report, TaskTypes.ViewRefresh].includes(task.type);
-}
-
-function computeHasUpdatedTasks(
- tasksInProgress: Task[] | undefined,
- newTasksInProgress: Task[],
- currentTask: Task | undefined,
- newCurrentTask: Task | undefined,
- component: Component | undefined,
-) {
- const progressHasChanged = Boolean(
- tasksInProgress &&
- (newTasksInProgress.length !== tasksInProgress.length ||
- differenceBy(newTasksInProgress, tasksInProgress, 'id').length > 0),
- );
-
- const currentTaskHasChanged = Boolean(
- (!currentTask && newCurrentTask) ||
- (currentTask && newCurrentTask && currentTask.id !== newCurrentTask.id),
- );
-
- if (progressHasChanged) {
- return true;
- } else if (currentTaskHasChanged && component) {
- // We return true if:
- // - there was no prior analysis date (means this is an empty project, and
- // a new analysis came in)
- // - OR, there was a prior analysis date (non-empty project) AND there were
- // some tasks in progress before
- return (
- Boolean(!component.analysisDate) || Boolean(component.analysisDate && tasksInProgress?.length)
- );
- }
- return false;
-}
-
-export default withAvailableFeatures(ComponentContainer);
diff --git a/server/sonar-web/src/main/js/app/components/ComponentContainerNotFound.tsx b/server/sonar-web/src/main/js/app/components/ComponentContainerNotFound.tsx
deleted file mode 100644
index 47010fd7931..00000000000
--- a/server/sonar-web/src/main/js/app/components/ComponentContainerNotFound.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Link } from '@sonarsource/echoes-react';
-import { Helmet } from 'react-helmet-async';
-import { Card, CenteredLayout, SubHeading } from '~design-system';
-import { translate } from '../../helpers/l10n';
-
-export interface ComponentContainerNotFoundProps {
- isPortfolioLike: boolean;
-}
-
-export default function ComponentContainerNotFound({
- isPortfolioLike,
-}: Readonly<ComponentContainerNotFoundProps>) {
- const componentType = isPortfolioLike ? 'portfolio' : 'project';
-
- return (
- <CenteredLayout className="sw-flex sw-justify-around" id="bd">
- <Helmet defaultTitle={translate('404_not_found')} defer={false} />
- <Card className="sw-mt-24" id="nonav">
- <SubHeading>{translate('dashboard', componentType, 'not_found')}</SubHeading>
- <p className="sw-mb-2">{translate('dashboard', componentType, 'not_found.2')}</p>
- <p>
- <Link to="/">{translate('go_back_to_homepage')}</Link>
- </p>
- </Card>
- </CenteredLayout>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/DocumentationRedirect.tsx b/server/sonar-web/src/main/js/app/components/DocumentationRedirect.tsx
deleted file mode 100644
index 18a19c796ed..00000000000
--- a/server/sonar-web/src/main/js/app/components/DocumentationRedirect.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkStandalone } from '@sonarsource/echoes-react';
-import { Helmet } from 'react-helmet-async';
-import { useLocation } from 'react-router-dom';
-import { useUncataloguedDocUrl } from '../../helpers/docs';
-
-const PAUSE_REDIRECT = 1;
-
-export default function DocumentationRedirect() {
- const location = useLocation();
- const url = useUncataloguedDocUrl(location.pathname.replace(/^\/documentation/, '')) as string;
-
- return (
- <>
- <Helmet>
- <meta httpEquiv="refresh" content={`${PAUSE_REDIRECT}; url='${url}'`} />
- </Helmet>
- <div className="sw-flex sw-flex-col sw-items-center sw-gap-4 sw-h-[100vh]">
- <div className="global-loading">
- <i className="global-loading-spinner" />
- <span className="global-loading-text">Redirecting...</span>
- </div>
- <div>
- <LinkStandalone to={url}>
- Click here if you&apos;re not being redirected automatically
- </LinkStandalone>
- </div>
- </div>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/FormattingHelp.tsx b/server/sonar-web/src/main/js/app/components/FormattingHelp.tsx
deleted file mode 100644
index 90d8b51aec2..00000000000
--- a/server/sonar-web/src/main/js/app/components/FormattingHelp.tsx
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Helmet } from 'react-helmet-async';
-import {
- CellComponent,
- ContentCell,
- HtmlFormatter,
- PageContentFontWrapper,
- Table,
- TableRow,
- Title,
-} from '~design-system';
-import { translate } from '../../helpers/l10n';
-
-const COLUMNS = ['50%', '50%'];
-
-export default function FormattingHelp() {
- return (
- <PageContentFontWrapper className="sw-typo-lg sw-p-6 sw-h-screen">
- <Helmet defer={false} title={translate('formatting.page')} />
- <Title>Formatting Syntax</Title>
- <Table
- columnCount={COLUMNS.length}
- columnWidths={COLUMNS}
- header={
- <TableRow>
- <ContentCell>Write:</ContentCell>
- <ContentCell>To display:</ContentCell>
- </TableRow>
- }
- >
- <TableRow>
- <ContentCell>*this text is bold*</ContentCell>
- <ContentCell>
- <HtmlFormatter>
- <strong>this text is bold</strong>
- </HtmlFormatter>
- </ContentCell>
- </TableRow>
- <TableRow>
- <ContentCell>https://www.sonarsource.com/products/sonarqube</ContentCell>
- <ContentCell>
- <HtmlFormatter>
- <a href="https://www.sonarsource.com/products/sonarqube">
- https://www.sonarsource.com/products/sonarqube
- </a>
- </HtmlFormatter>
- </ContentCell>
- </TableRow>
- <TableRow>
- <ContentCell>
- [SonarQube™ Home Page](https://www.sonarsource.com/products/sonarqube)
- </ContentCell>
- <ContentCell>
- <HtmlFormatter>
- <a href="https://www.sonarsource.com/products/sonarqube">SonarQube™ Home Page</a>
- </HtmlFormatter>
- </ContentCell>
- </TableRow>
- <TableRow>
- <ContentCell>
- * first item
- <br />* second item
- </ContentCell>
- <ContentCell>
- <HtmlFormatter>
- <ul>
- <li>first item</li>
- <li>second item</li>
- </ul>
- </HtmlFormatter>
- </ContentCell>
- </TableRow>
- <TableRow>
- <CellComponent>
- 1. first item
- <br />
- 1. second item
- </CellComponent>
- <ContentCell>
- <HtmlFormatter>
- <ol>
- <li>first item</li>
- <li>second item</li>
- </ol>
- </HtmlFormatter>
- </ContentCell>
- </TableRow>
- <TableRow>
- <ContentCell>
- = Heading Level 1<br />
- == Heading Level 2<br />
- === Heading Level 3<br />
- ==== Heading Level 4<br />
- ===== Heading Level 5<br />
- ====== Heading Level 6<br />
- </ContentCell>
- <ContentCell>
- <HtmlFormatter>
- <h1>Heading Level 1</h1>
- <h2>Heading Level 2</h2>
- <h3>Heading Level 3</h3>
- <h4>Heading Level 4</h4>
- <h5>Heading Level 5</h5>
- <h6>Heading Level 6</h6>
- </HtmlFormatter>
- </ContentCell>
- </TableRow>
- <TableRow>
- <ContentCell>``Lists#newArrayList()``</ContentCell>
- <ContentCell>
- <HtmlFormatter>
- <code>Lists#newArrayList()</code>
- </HtmlFormatter>
- </ContentCell>
- </TableRow>
- <TableRow>
- <ContentCell>
- ``
- <br />
- {'// code on multiple lines'}
- <br />
- {'public void foo() {'}
- <br />
- &nbsp;&nbsp;
- {'// do some logic here'}
- <br />
- {'}'}
- <br />
- ``
- </ContentCell>
- <ContentCell>
- <HtmlFormatter>
- <pre>
- {'// code on multiple lines\npublic void foo() {\n // do some logic here\n}'}
- </pre>
- </HtmlFormatter>
- </ContentCell>
- </TableRow>
- <TableRow>
- <ContentCell>
- Standard text
- <br />
- &gt; Blockquoted text
- <br />
- &gt; that spans multiple lines
- <br />
- </ContentCell>
- <ContentCell>
- <HtmlFormatter>
- <p>Standard text</p>
- <blockquote>
- Blockquoted text
- <br />
- that spans multiple lines
- <br />
- </blockquote>
- </HtmlFormatter>
- </ContentCell>
- </TableRow>
- </Table>
- </PageContentFontWrapper>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/GitHubSynchronisationWarning.tsx b/server/sonar-web/src/main/js/app/components/GitHubSynchronisationWarning.tsx
deleted file mode 100644
index 6a11aa2eac1..00000000000
--- a/server/sonar-web/src/main/js/app/components/GitHubSynchronisationWarning.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useGitHubSyncStatusQuery } from '../../queries/identity-provider/github';
-import { AlmKeys } from '../../types/alm-settings';
-import AlmSynchronisationWarning from './AlmSynchronisationWarning';
-
-interface Props {
- short?: boolean;
-}
-
-function GitHubSynchronisationWarning({ short }: Readonly<Props>) {
- const { data } = useGitHubSyncStatusQuery();
-
- if (!data) {
- return null;
- }
-
- return <AlmSynchronisationWarning short={short} data={data} provisionedBy={AlmKeys.GitHub} />;
-}
-
-export default GitHubSynchronisationWarning;
diff --git a/server/sonar-web/src/main/js/app/components/GitLabSynchronisationWarning.tsx b/server/sonar-web/src/main/js/app/components/GitLabSynchronisationWarning.tsx
deleted file mode 100644
index 1f8acfd27f1..00000000000
--- a/server/sonar-web/src/main/js/app/components/GitLabSynchronisationWarning.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useGitLabSyncStatusQuery } from '../../queries/identity-provider/gitlab';
-import { AlmKeys } from '../../types/alm-settings';
-import AlmSynchronisationWarning from './AlmSynchronisationWarning';
-
-interface Props {
- short?: boolean;
-}
-
-function GitLabSynchronisationWarning({ short }: Readonly<Props>) {
- const { data } = useGitLabSyncStatusQuery();
-
- if (!data) {
- return null;
- }
-
- return <AlmSynchronisationWarning short={short} data={data} provisionedBy={AlmKeys.GitLab} />;
-}
-
-export default GitLabSynchronisationWarning;
diff --git a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx
deleted file mode 100644
index ef1e27b7946..00000000000
--- a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ThemeProvider } from '@emotion/react';
-import styled from '@emotion/styled';
-import { Outlet, useLocation } from 'react-router-dom';
-import { lightTheme, themeColor } from '~design-system';
-import A11yProvider from '~sonar-aligned/components/a11y/A11yProvider';
-import A11ySkipLinks from '~sonar-aligned/components/a11y/A11ySkipLinks';
-import SuggestionsProvider from '../../components/embed-docs-modal/SuggestionsProvider';
-import NCDAutoUpdateMessage from '../../components/new-code-definition/NCDAutoUpdateMessage';
-import Workspace from '../../components/workspace/Workspace';
-import CalculationChangeMessage from './calculation-notification/CalculationChangeMessage';
-import GlobalFooter from './GlobalFooter';
-import IndexationContextProvider from './indexation/IndexationContextProvider';
-import IndexationNotification from './indexation/IndexationNotification';
-import LanguagesContextProvider from './languages/LanguagesContextProvider';
-import MetricsContextProvider from './metrics/MetricsContextProvider';
-import ModeTour from './ModeTour';
-import GlobalNav from './nav/global/GlobalNav';
-import PromotionNotification from './promotion-notification/PromotionNotification';
-import StartupModal from './StartupModal';
-import SystemAnnouncement from './SystemAnnouncement';
-import { UpdateNotification } from './update-notification/UpdateNotification';
-
-/*
- * These pages need a white background (aka 'secondary', rather than the default 'primary')
- * This should be revisited at some point (why the exception?)
- */
-const PAGES_WITH_SECONDARY_BACKGROUND = [
- '/tutorials',
- '/projects/create',
- '/project/baseline',
- '/project/branches',
- '/project/key',
- '/project/deletion',
- '/project/links',
- '/project/import_export',
- '/project/quality_gate',
- '/project/quality_profiles',
- '/project/webhooks',
- '/admin/webhooks',
- '/project_roles',
- '/admin/permissions',
- '/admin/permission_templates',
- '/project/background_tasks',
- '/admin/background_tasks',
- '/admin/groups',
- '/admin/marketplace',
- '/admin/system',
- '/admin/users',
- '/admin/settings',
- '/admin/settings/encryption',
- '/admin/extension/license/support',
- '/admin/audit',
- '/admin/projects_management',
- '/account/projects',
-];
-
-export default function GlobalContainer() {
- // it is important to pass `location` down to `GlobalNav` to trigger render on url change
- const location = useLocation();
-
- return (
- <ThemeProvider theme={lightTheme}>
- <SuggestionsProvider>
- <A11yProvider>
- <A11ySkipLinks />
- <GlobalContainerWrapper>
- <GlobalBackground
- secondary={PAGES_WITH_SECONDARY_BACKGROUND.includes(location.pathname)}
- className="sw-box-border sw-flex-[1_0_auto]"
- id="container"
- >
- <Workspace>
- <IndexationContextProvider>
- <LanguagesContextProvider>
- <MetricsContextProvider>
- <div className="sw-sticky sw-top-0 sw-z-global-navbar">
- <SystemAnnouncement />
- <IndexationNotification />
- <NCDAutoUpdateMessage />
- <UpdateNotification dismissable />
- <GlobalNav location={location} />
- <ModeTour />
- <CalculationChangeMessage />
- {/* The following is the portal anchor point for the component nav
- * See ComponentContainer.tsx
- */}
- <div id="component-nav-portal" />
- </div>
- <Outlet />
- </MetricsContextProvider>
- </LanguagesContextProvider>
- </IndexationContextProvider>
- </Workspace>
- <PromotionNotification />
- </GlobalBackground>
- <GlobalFooter />
- </GlobalContainerWrapper>
- <StartupModal />
- </A11yProvider>
- </SuggestionsProvider>
- </ThemeProvider>
- );
-}
-
-const GlobalContainerWrapper = styled.div`
- display: flex;
- flex-direction: column;
- height: 100%;
- min-height: 100vh;
-`;
-
-const GlobalBackground = styled.div<{ secondary: boolean }>`
- background-color: ${({ secondary }) =>
- themeColor(secondary ? 'backgroundSecondary' : 'backgroundPrimary')};
-`;
diff --git a/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx b/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx
deleted file mode 100644
index 25e56545b4a..00000000000
--- a/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { LinkHighlight, LinkStandalone } from '@sonarsource/echoes-react';
-import { useIntl } from 'react-intl';
-import {
- FlagMessage,
- LAYOUT_VIEWPORT_MIN_WIDTH,
- SeparatorCircleIcon,
- themeBorder,
- themeColor,
-} from '~design-system';
-import InstanceMessage from '../../components/common/InstanceMessage';
-import AppVersionStatus from '../../components/shared/AppVersionStatus';
-import { COMMUNITY_FORUM_URL, DocLink } from '../../helpers/doc-links';
-import { useDocUrl } from '../../helpers/docs';
-import { getEdition } from '../../helpers/editions';
-import { getInstanceVersionNumber } from '../../helpers/strings';
-import { useStandardExperienceModeQuery } from '../../queries/mode';
-import { EditionKey } from '../../types/editions';
-import GlobalFooterBranding from './GlobalFooterBranding';
-import { useAppState } from './app-state/withAppStateContext';
-
-interface GlobalFooterProps {
- hideLoggedInInfo?: boolean;
-}
-
-export default function GlobalFooter({ hideLoggedInInfo }: Readonly<GlobalFooterProps>) {
- const appState = useAppState();
- const { data: isStandardMode } = useStandardExperienceModeQuery({
- enabled: appState.version !== '',
- });
- const currentEdition = appState?.edition && getEdition(appState.edition);
- const intl = useIntl();
- const version = getInstanceVersionNumber(appState.version);
-
- const docUrl = useDocUrl();
-
- const isCommunityBuildRunning = appState.edition === EditionKey.community;
-
- return (
- <StyledFooter className="sw-p-6" id="footer">
- <div className="sw-h-full sw-flex sw-flex-col sw-items-stretch">
- {appState?.productionDatabase === false && (
- <FlagMessage className="sw-mb-4" id="evaluation_warning" variant="warning">
- <p>
- <span className="sw-typo-lg-semibold">
- {intl.formatMessage({ id: 'footer.production_database_warning' })}
- </span>
-
- <br />
-
- <InstanceMessage
- message={intl.formatMessage({ id: 'footer.production_database_explanation' })}
- />
- </p>
- </FlagMessage>
- )}
-
- <div className="sw-text-xs sw-flex sw-justify-between sw-items-center">
- <GlobalFooterBranding />
-
- {!hideLoggedInInfo && (
- <ul className="sw-code sw-flex sw-items-center sw-gap-1">
- {currentEdition && (
- <>
- <li>{currentEdition.name}</li>
- <SeparatorCircleIcon aria-hidden as="li" />
- </>
- )}
-
- {appState?.version && (
- <>
- <li>{intl.formatMessage({ id: 'footer.version.short' }, { version })}</li>
- <SeparatorCircleIcon aria-hidden as="li" />
- <li>
- <AppVersionStatus statusOnly />
- </li>
- </>
- )}
- {isStandardMode !== undefined && (
- <>
- <SeparatorCircleIcon aria-hidden as="li" />
- <li className="sw-uppercase">
- {intl.formatMessage({
- id: `footer.mode.${isStandardMode ? 'STANDARD' : 'MQR'}`,
- })}
- </li>
- </>
- )}
- </ul>
- )}
-
- <ul className="sw-flex sw-items-center sw-gap-3">
- <li>
- {isCommunityBuildRunning ? (
- <LinkStandalone
- shouldOpenInNewTab
- highlight={LinkHighlight.CurrentColor}
- to="https://www.gnu.org/licenses/lgpl-3.0.txt"
- >
- {intl.formatMessage({ id: 'footer.license.lgplv3' })}
- </LinkStandalone>
- ) : (
- <LinkStandalone
- shouldOpenInNewTab
- highlight={LinkHighlight.CurrentColor}
- to="https://www.sonarsource.com/legal/sonarqube/terms-and-conditions/"
- >
- {intl.formatMessage({ id: 'footer.license.sqs' })}
- </LinkStandalone>
- )}
- </li>
-
- <li>
- <LinkStandalone
- shouldOpenInNewTab
- highlight={LinkHighlight.CurrentColor}
- to={COMMUNITY_FORUM_URL}
- >
- {intl.formatMessage({ id: 'footer.community' })}
- </LinkStandalone>
- </li>
-
- <li>
- <LinkStandalone
- shouldOpenInNewTab
- highlight={LinkHighlight.CurrentColor}
- to={docUrl(DocLink.Root)}
- >
- {intl.formatMessage({ id: 'footer.documentation' })}
- </LinkStandalone>
- </li>
-
- <li>
- <LinkStandalone
- shouldOpenInNewTab
- highlight={LinkHighlight.CurrentColor}
- to={docUrl(DocLink.InstanceAdminPluginVersionMatrix)}
- >
- {intl.formatMessage({ id: 'footer.plugins' })}
- </LinkStandalone>
- </li>
-
- {!hideLoggedInInfo && (
- <li>
- <LinkStandalone highlight={LinkHighlight.CurrentColor} to="/web_api">
- {intl.formatMessage({ id: 'footer.web_api' })}
- </LinkStandalone>
- </li>
- )}
- </ul>
- </div>
- </div>
- </StyledFooter>
- );
-}
-
-const StyledFooter = styled.div`
- color: var(--echoes-color-text-subdued);
- background-color: ${themeColor('backgroundSecondary')};
- border-top: ${themeBorder('default')};
- box-sizing: border-box;
- min-width: ${LAYOUT_VIEWPORT_MIN_WIDTH}px;
-`;
diff --git a/server/sonar-web/src/main/js/app/components/GlobalFooterBranding.tsx b/server/sonar-web/src/main/js/app/components/GlobalFooterBranding.tsx
deleted file mode 100644
index 2f82db1f585..00000000000
--- a/server/sonar-web/src/main/js/app/components/GlobalFooterBranding.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Link, LinkHighlight } from '@sonarsource/echoes-react';
-import { isOfficial } from '../../helpers/system';
-
-export default function GlobalFooterBranding() {
- const official = isOfficial();
-
- return (
- <div className="max-[1400px]:sw-max-w-[12rem] sw-flex sw-items-center">
- {official ? (
- <span>
- SonarQube&trade; technology is powered by{' '}
- <Link
- shouldOpenInNewTab
- highlight={LinkHighlight.CurrentColor}
- to="https://www.sonarsource.com"
- >
- SonarSource SA
- </Link>
- </span>
- ) : (
- <span>
- This application is based on{' '}
- <Link
- shouldOpenInNewTab
- highlight={LinkHighlight.CurrentColor}
- to="https://www.sonarsource.com/products/sonarqube/?referrer=sonarqube"
- title="SonarQube™"
- >
- SonarQube™
- </Link>{' '}
- but is <strong>not</strong> an official version provided by{' '}
- <Link
- shouldOpenInNewTab
- highlight={LinkHighlight.CurrentColor}
- to="https://www.sonarsource.com"
- title="SonarSource SA"
- >
- SonarSource SA
- </Link>
- .
- </span>
- )}
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/KeyboardShortcutsModal.tsx b/server/sonar-web/src/main/js/app/components/KeyboardShortcutsModal.tsx
deleted file mode 100644
index 0c2b2a94c98..00000000000
--- a/server/sonar-web/src/main/js/app/components/KeyboardShortcutsModal.tsx
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkStandalone } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { ContentCell, Key, KeyboardHint, Modal, SubTitle, Table, TableRow } from '~design-system';
-import { isInput } from '../../helpers/keyboardEventHelpers';
-import { KeyboardKeys } from '../../helpers/keycodes';
-import { translate } from '../../helpers/l10n';
-import { getKeyboardShortcutEnabled } from '../../helpers/preferences';
-
-type Section = {
- rows: Array<{ command: string; description: string }>;
- subTitle: string;
-};
-
-const FILE_ROWS = [
- {
- command: `${Key.ArrowUp} ${Key.ArrowDown}`,
- description: 'keyboard_shortcuts_modal.code_page.select_files',
- },
- {
- command: `${Key.ArrowRight}`,
- description: 'keyboard_shortcuts_modal.code_page.open_file',
- },
- {
- command: `${Key.ArrowLeft}`,
- description: 'keyboard_shortcuts_modal.return_back_to_the_list',
- },
-];
-
-export const SECTIONS: Array<Section> = [
- {
- rows: [
- {
- command: 's',
- description: 'keyboard_shortcuts_modal.global.open_search_bar',
- },
- {
- command: '?',
- description: 'keyboard_shortcuts_modal.global.open_keyboard_shortcuts_modal',
- },
- ],
- subTitle: 'keyboard_shortcuts_modal.global',
- },
-
- {
- rows: [
- {
- command: `${Key.ArrowUp} ${Key.ArrowDown}`,
- description: 'keyboard_shortcuts_modal.navigate_between_issues',
- },
- {
- command: `${Key.ArrowRight}`,
- description: 'keyboard_shortcuts_modal.open_issue',
- },
- {
- command: `${Key.ArrowLeft}`,
- description: 'keyboard_shortcuts_modal.return_back_to_the_list',
- },
- {
- command: `${Key.Alt} + ${Key.ArrowUp} ${Key.ArrowDown}`,
- description: 'keyboard_shortcuts_modal.issue_details_page.navigate_issue_locations',
- },
- {
- command: `${Key.Alt} + ${Key.ArrowLeft} ${Key.ArrowRight}`,
- description: 'keyboard_shortcuts_modal.issue_details_page.switch_flows',
- },
- {
- command: 'f',
- description: 'keyboard_shortcuts_modal.do_issue_transition',
- },
- {
- command: 'a',
- description: 'keyboard_shortcuts_modal.assign_issue',
- },
- {
- command: 'm',
- description: 'keyboard_shortcuts_modal.assign_issue_to_me',
- },
- {
- command: 't',
- description: 'keyboard_shortcuts_modal.change_tags_of_issue',
- },
- {
- command: `${Key.Control} + ${Key.Enter}`,
- description: 'keyboard_shortcuts_modal.issue_details_page.submit_comment',
- },
- ],
- subTitle: 'keyboard_shortcuts_modal.issues_page',
- },
-
- {
- rows: FILE_ROWS,
- subTitle: 'keyboard_shortcuts_modal.code_page',
- },
-
- {
- rows: FILE_ROWS,
- subTitle: 'keyboard_shortcuts_modal.measures_page',
- },
-
- {
- rows: [
- {
- command: `${Key.ArrowUp} ${Key.ArrowDown}`,
- description: 'keyboard_shortcuts_modal.rules_page.navigate_between_rule',
- },
- {
- command: `${Key.ArrowRight}`,
- description: 'keyboard_shortcuts_modal.rules_page.open_rule',
- },
- {
- command: `${Key.ArrowLeft}`,
- description: 'keyboard_shortcuts_modal.return_back_to_the_list',
- },
- ],
- subTitle: 'keyboard_shortcuts_modal.rules_page',
- },
-];
-
-function renderSection() {
- return SECTIONS.map((section) => (
- <div key={section.subTitle} className="sw-mb-4">
- <SubTitle>{translate(section.subTitle)}</SubTitle>
-
- <Table columnCount={2} columnWidths={['30%', '70%']}>
- {section.rows.map((row) => (
- <TableRow key={row.command}>
- <ContentCell className="sw-justify-center">
- <KeyboardHint command={row.command} title="" />
- </ContentCell>
-
- <ContentCell>{translate(row.description)}</ContentCell>
- </TableRow>
- ))}
- </Table>
- </div>
- ));
-}
-
-export default function KeyboardShortcutsModal() {
- const [display, setDisplay] = React.useState(false);
-
- React.useEffect(() => {
- const handleKeyDown = (event: KeyboardEvent) => {
- if (!getKeyboardShortcutEnabled()) {
- return true;
- }
-
- if (isInput(event)) {
- return true;
- }
-
- if (event.key === KeyboardKeys.KeyQuestionMark) {
- setDisplay((d) => !d);
- }
- };
-
- document.addEventListener('keydown', handleKeyDown);
-
- return () => {
- document.removeEventListener('keydown', handleKeyDown);
- };
- }, [setDisplay]);
-
- if (!display) {
- return null;
- }
-
- const title = translate('keyboard_shortcuts_modal.title');
-
- const body = (
- <>
- <LinkStandalone
- onClick={() => {
- setDisplay(false);
- return true;
- }}
- to="/account"
- >
- {translate('keyboard_shortcuts_modal.disable_link')}
- </LinkStandalone>
-
- <div className="sw-mt-4">{renderSection()}</div>
- </>
- );
-
- return (
- <Modal
- body={body}
- headerTitle={title}
- onClose={() => setDisplay(false)}
- secondaryButtonLabel={translate('close')}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/Landing.tsx b/server/sonar-web/src/main/js/app/components/Landing.tsx
deleted file mode 100644
index 359906b6f42..00000000000
--- a/server/sonar-web/src/main/js/app/components/Landing.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Navigate, To } from 'react-router-dom';
-import { getHomePageUrl } from '../../helpers/urls';
-import { CurrentUser, isLoggedIn } from '../../types/users';
-import withCurrentUserContext from './current-user/withCurrentUserContext';
-
-export interface LandingProps {
- currentUser: CurrentUser;
-}
-
-export function Landing({ currentUser }: LandingProps) {
- let redirectUrl: To;
- if (isLoggedIn(currentUser) && currentUser.homepage) {
- redirectUrl = getHomePageUrl(currentUser.homepage);
- } else {
- redirectUrl = '/projects';
- }
-
- return <Navigate to={redirectUrl} replace />;
-}
-
-export default withCurrentUserContext(Landing);
diff --git a/server/sonar-web/src/main/js/app/components/LicensePromptModal.tsx b/server/sonar-web/src/main/js/app/components/LicensePromptModal.tsx
deleted file mode 100644
index 2129d6e3e4b..00000000000
--- a/server/sonar-web/src/main/js/app/components/LicensePromptModal.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, Link, Modal } from '@sonarsource/echoes-react';
-import { FormattedMessage } from 'react-intl';
-import { translate } from '../../helpers/l10n';
-
-interface Props {
- isOpen?: boolean;
- onClose: () => void;
-}
-
-export default function LicensePromptModal({ isOpen, onClose }: Readonly<Props>) {
- return (
- <Modal
- isOpen={isOpen ?? false}
- content={
- <FormattedMessage
- id="license.prompt.description"
- values={{
- url: (
- <Link onClick={onClose} to="/admin/extension/license/app">
- {translate('license.prompt.link')}
- </Link>
- ),
- }}
- />
- }
- onOpenChange={(open) => !open && onClose()}
- title={translate('license.prompt.title')}
- secondaryButton={<Button onClick={onClose}>{translate('cancel')}</Button>}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/MigrationContainer.tsx b/server/sonar-web/src/main/js/app/components/MigrationContainer.tsx
deleted file mode 100644
index 9d58cb9ca6f..00000000000
--- a/server/sonar-web/src/main/js/app/components/MigrationContainer.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Navigate, Outlet } from 'react-router-dom';
-import { getSystemStatus } from '../../helpers/system';
-
-export function MigrationContainer() {
- if (getSystemStatus() !== 'UP') {
- const returnTo = window.location.pathname + window.location.search + window.location.hash;
- const to = {
- pathname: '/maintenance',
- search: new URLSearchParams({
- return_to: returnTo,
- }).toString(),
- };
-
- return <Navigate to={to} />;
- }
- return <Outlet />;
-}
-
-export default MigrationContainer;
diff --git a/server/sonar-web/src/main/js/app/components/ModeTour.tsx b/server/sonar-web/src/main/js/app/components/ModeTour.tsx
deleted file mode 100644
index faed47193d3..00000000000
--- a/server/sonar-web/src/main/js/app/components/ModeTour.tsx
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, ButtonVariety, Modal, ModalSize } from '@sonarsource/echoes-react';
-import { debounce } from 'lodash';
-import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
-import { useIntl } from 'react-intl';
-import { CallBackProps } from 'react-joyride';
-import { SpotlightTour, SpotlightTourStep } from '~design-system';
-import { Image } from '~sonar-aligned/components/common/Image';
-import { dismissNotice } from '../../api/users';
-import DocumentationLink from '../../components/common/DocumentationLink';
-import { CustomEvents } from '../../helpers/constants';
-import { DocLink } from '../../helpers/doc-links';
-import { useStandardExperienceModeQuery } from '../../queries/mode';
-import { Permissions } from '../../types/permissions';
-import { NoticeType } from '../../types/users';
-import { useAppState } from './app-state/withAppStateContext';
-import { CurrentUserContext } from './current-user/CurrentUserContext';
-
-const MAX_STEPS = 4;
-
-export default function ModeTour() {
- const { currentUser, updateDismissedNotices } = useContext(CurrentUserContext);
- const appState = useAppState();
- const intl = useIntl();
- const { data: isStandardMode } = useStandardExperienceModeQuery();
- const [step, setStep] = useState(1);
- const [runManually, setRunManually] = useState(false);
-
- const dismissedTour = currentUser.dismissedNotices[NoticeType.MODE_TOUR];
-
- const nextStep = (next?: number) => {
- if (step === MAX_STEPS || next === 5) {
- document.dispatchEvent(new CustomEvent(CustomEvents.OpenHelpMenu));
- setTimeout(() => setStep(5));
- } else {
- setStep(next ?? step + 1);
- }
- };
-
- const dismissTourWithDebounce = useMemo(
- () =>
- debounce(() => {
- dismissNotice(NoticeType.MODE_TOUR)
- .then(() => {
- updateDismissedNotices(NoticeType.MODE_TOUR, true);
- })
- .catch(() => {
- /* noop */
- });
- }, 500),
- [updateDismissedNotices],
- );
-
- const dismissTour = useCallback(() => {
- document.dispatchEvent(new CustomEvent(CustomEvents.CloseHelpMenu));
- setStep(6);
- if (!dismissedTour) {
- dismissTourWithDebounce();
- }
- }, [dismissedTour, dismissTourWithDebounce]);
-
- const onLater = () => {
- nextStep(5);
- };
-
- const onToggle = (props: CallBackProps) => {
- switch (props.action) {
- case 'close':
- case 'skip':
- case 'reset':
- // ideally we should trigger onLater here, but spotlight tour will be closed on close/skip/reset.
- // So it is not possible without a dirty hack.
- dismissTour();
- break;
- case 'next':
- if (props.lifecycle === 'complete') {
- nextStep();
- }
- break;
- default:
- break;
- }
- };
-
- useEffect(() => {
- const listener = () => {
- setStep(1);
- setRunManually(true);
- };
- document.addEventListener(CustomEvents.RunTourMode, listener);
-
- return () => document.removeEventListener(CustomEvents.RunTourMode, listener);
- }, []);
-
- useEffect(() => {
- const listener = () => {
- // dismiss tour if help menu is closed and user has not completed all steps
- if (step >= MAX_STEPS) {
- dismissTour();
- }
- };
- document.addEventListener(CustomEvents.HelpMenuClosed, listener);
-
- return () => document.removeEventListener(CustomEvents.HelpMenuClosed, listener);
- }, [dismissTour, step]);
-
- const isAdmin = currentUser.permissions?.global.includes(Permissions.Admin);
- const isAdminOrQGAdmin =
- isAdmin || currentUser.permissions?.global.includes(Permissions.QualityGateAdmin);
-
- useEffect(() => {
- if (currentUser.isLoggedIn && !isAdminOrQGAdmin && !dismissedTour) {
- dismissTour();
- }
- }, [currentUser.isLoggedIn, isAdminOrQGAdmin, dismissedTour, dismissTour]);
-
- if (!runManually && (currentUser.dismissedNotices[NoticeType.MODE_TOUR] || !isAdminOrQGAdmin)) {
- return null;
- }
-
- const steps: SpotlightTourStep[] = [
- ...(isAdmin
- ? [
- {
- target: '[data-guiding-id="mode-tour-1"]',
- content: intl.formatMessage(
- { id: 'mode_tour.step4.description' },
- {
- mode: intl.formatMessage({
- id: `settings.mode.${isStandardMode ? 'standard' : 'mqr'}.name`,
- }),
- p1: (text) => <p>{text}</p>,
- p: (text) => <p className="sw-mt-2">{text}</p>,
- b: (text) => <b>{text}</b>,
- },
- ),
- title: intl.formatMessage({ id: 'mode_tour.step4.title' }),
- placement: 'bottom' as const,
- },
- ]
- : []),
- {
- target: '[data-guiding-id="mode-tour-2"]',
- title: intl.formatMessage({ id: 'mode_tour.step5.title' }),
- content: null,
- placement: 'left',
- },
- ];
-
- const maxModalSteps = isAdmin ? MAX_STEPS - 1 : MAX_STEPS;
-
- return (
- <>
- <Modal
- size={ModalSize.Wide}
- isOpen={step <= maxModalSteps}
- onOpenChange={(isOpen) => isOpen === false && onLater()}
- title={
- step <= maxModalSteps &&
- intl.formatMessage({ id: `mode_tour.step${step}.title` }, { version: appState.version })
- }
- content={
- <>
- {step <= maxModalSteps && (
- <>
- <Image
- alt={intl.formatMessage({ id: `mode_tour.step${step}.img_alt` })}
- className="sw-w-full sw-mb-4"
- src={`/images/mode-tour/step${isStandardMode && step === 4 ? step + '_se' : step}.png`}
- />
- {intl.formatMessage(
- {
- id: `mode_tour.step${step}.description`,
- },
- {
- mode: intl.formatMessage({
- id: `settings.mode.${isStandardMode ? 'standard' : 'mqr'}.name`,
- }),
- p1: (text) => <p>{text}</p>,
- p: (text) => <p className="sw-mt-4">{text}</p>,
- b: (text) => <b>{text}</b>,
- },
- )}
- <div className="sw-mt-6">
- <b>
- {intl.formatMessage({ id: 'guiding.step_x_of_y' }, { 0: step, 1: MAX_STEPS })}
- </b>
- </div>
- </>
- )}
- </>
- }
- footerLink={
- <DocumentationLink standalone to={DocLink.ModeMQR}>
- {intl.formatMessage({ id: `mode_tour.link` })}
- </DocumentationLink>
- }
- primaryButton={
- <Button variety={ButtonVariety.Primary} onClick={() => nextStep()}>
- {intl.formatMessage({ id: step === 1 ? 'lets_go' : 'next' })}
- </Button>
- }
- secondaryButton={
- step === 1 && (
- <Button variety={ButtonVariety.Default} onClick={onLater}>
- {intl.formatMessage({ id: 'later' })}
- </Button>
- )
- }
- />
- <SpotlightTour
- callback={onToggle}
- steps={steps}
- run={step > maxModalSteps}
- continuous
- disableOverlay
- showProgress={step !== 5}
- stepIndex={step - maxModalSteps - 1}
- nextLabel={intl.formatMessage({ id: 'next' })}
- closeLabel={intl.formatMessage({ id: 'got_it' })}
- backLabel=""
- stepXofYLabel={(x: number) =>
- x + maxModalSteps <= MAX_STEPS
- ? intl.formatMessage(
- { id: 'guiding.step_x_of_y' },
- { 0: x + maxModalSteps, 1: MAX_STEPS },
- )
- : ''
- }
- />
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/NonAdminPagesContainer.tsx b/server/sonar-web/src/main/js/app/components/NonAdminPagesContainer.tsx
deleted file mode 100644
index 448a8531a54..00000000000
--- a/server/sonar-web/src/main/js/app/components/NonAdminPagesContainer.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Outlet } from 'react-router-dom';
-import { CenteredLayout, FlagMessage } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { isApplication } from '../../types/component';
-import { ComponentContext } from './componentContext/ComponentContext';
-
-export default function NonAdminPagesContainer() {
- const { component } = React.useContext(ComponentContext);
-
- /*
- * Catch Applications for which the user does not have access to all child projects
- * and prevent displaying whatever page was requested.
- * This doesn't apply to admin pages (those are not within this container)
- */
- if (component && isApplication(component.qualifier) && !component.canBrowseAllChildProjects) {
- return (
- <CenteredLayout
- className="sw-py-8 sw-typo-lg sw-flex sw-flex-col sw-items-center"
- id="code-page"
- >
- <FlagMessage className="it__alert-no-access-all-child-project sw-mt-10" variant="error">
- <p>
- {translate('application.cannot_access_all_child_projects1')}
- <br />
- {translate('application.cannot_access_all_child_projects2')}
- </p>
- </FlagMessage>
- </CenteredLayout>
- );
- }
-
- return <Outlet />;
-}
diff --git a/server/sonar-web/src/main/js/app/components/NotFound.tsx b/server/sonar-web/src/main/js/app/components/NotFound.tsx
deleted file mode 100644
index 241722a5702..00000000000
--- a/server/sonar-web/src/main/js/app/components/NotFound.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Helmet } from 'react-helmet-async';
-import { Card, CenteredLayout, Link, PageContentFontWrapper, Title } from '~design-system';
-import { translate } from '../../helpers/l10n';
-
-export default function NotFound() {
- return (
- <>
- <Helmet defaultTitle={translate('404_not_found')} defer={false} />
- <PageContentFontWrapper className="sw-typo-lg">
- <CenteredLayout className="sw-flex sw-flex-col sw-items-center">
- <Card className="sw-m-14 sw-w-abs-600">
- <Title>{translate('page_not_found')}</Title>
- <p className="sw-mb-2">{translate('address_mistyped_or_page_moved')}</p>
- <p>
- <Link to="/">{translate('go_back_to_homepage')}</Link>
- </p>
- </Card>
- </CenteredLayout>
- </PageContentFontWrapper>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/PageTracker.tsx b/server/sonar-web/src/main/js/app/components/PageTracker.tsx
deleted file mode 100644
index 5439a51a66b..00000000000
--- a/server/sonar-web/src/main/js/app/components/PageTracker.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Helmet } from 'react-helmet-async';
-import { withRouter } from '~sonar-aligned/components/hoc/withRouter';
-import { Location } from '~sonar-aligned/types/router';
-import { installScript } from '../../helpers/extensions';
-import { getWebAnalyticsPageHandlerFromCache } from '../../helpers/extensionsHandler';
-import { getInstance } from '../../helpers/system';
-import { AppState } from '../../types/appstate';
-import withAppStateContext from './app-state/withAppStateContext';
-
-interface Props {
- appState: AppState;
- location: Location;
-}
-
-interface State {
- lastLocation?: string;
-}
-
-export class PageTracker extends React.Component<React.PropsWithChildren<Props>, State> {
- state: State = {};
-
- componentDidMount() {
- const { appState } = this.props;
-
- if (appState.webAnalyticsJsPath && !getWebAnalyticsPageHandlerFromCache()) {
- installScript(appState.webAnalyticsJsPath, 'head');
- }
- }
-
- trackPage = () => {
- const { location } = this.props;
- const { lastLocation } = this.state;
- const locationChanged = location.pathname !== lastLocation;
- const webAnalyticsPageChange = getWebAnalyticsPageHandlerFromCache();
-
- if (webAnalyticsPageChange && locationChanged) {
- this.setState({ lastLocation: location.pathname });
- setTimeout(() => webAnalyticsPageChange(location.pathname), 500);
- }
- };
-
- render() {
- const { appState } = this.props;
-
- return (
- <Helmet
- defaultTitle={getInstance()}
- defer={false}
- onChangeClientState={appState.webAnalyticsJsPath ? this.trackPage : undefined}
- >
- {this.props.children}
- </Helmet>
- );
- }
-}
-
-export default withRouter(withAppStateContext(PageTracker));
diff --git a/server/sonar-web/src/main/js/app/components/PluginRiskConsent.tsx b/server/sonar-web/src/main/js/app/components/PluginRiskConsent.tsx
deleted file mode 100644
index 6b035ddbfd6..00000000000
--- a/server/sonar-web/src/main/js/app/components/PluginRiskConsent.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, ButtonVariety } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { Helmet } from 'react-helmet-async';
-import { Card, CenteredLayout, Title } from '~design-system';
-import { withRouter } from '~sonar-aligned/components/hoc/withRouter';
-import { Router } from '~sonar-aligned/types/router';
-import { setSimpleSettingValue } from '../../api/settings';
-import { whenLoggedIn } from '../../components/hoc/whenLoggedIn';
-import { translate } from '../../helpers/l10n';
-import { getBaseUrl } from '../../helpers/system';
-import { hasGlobalPermission } from '../../helpers/users';
-import { Permissions } from '../../types/permissions';
-import { RiskConsent } from '../../types/plugins';
-import { SettingsKey } from '../../types/settings';
-import { LoggedInUser } from '../../types/users';
-
-export interface PluginRiskConsentProps {
- currentUser: LoggedInUser;
- router: Router;
-}
-
-export function PluginRiskConsent(props: Readonly<PluginRiskConsentProps>) {
- const { currentUser, router } = props;
-
- const isAdmin = hasGlobalPermission(currentUser, Permissions.Admin);
-
- React.useEffect(() => {
- if (!isAdmin) {
- router.replace('/');
- }
- }, [isAdmin, router]);
-
- if (!isAdmin) {
- return null;
- }
-
- const acknowledgeRisk = async () => {
- try {
- await setSimpleSettingValue({
- key: SettingsKey.PluginRiskConsent,
- value: RiskConsent.Accepted,
- });
-
- // force a refresh for the backend
- window.location.href = `${getBaseUrl()}/`;
- } catch (_) {
- /* Do nothing */
- }
- };
-
- return (
- <CenteredLayout className="sw-h-screen sw-pt-[10vh]">
- <Helmet defer={false} title={translate('plugin_risk_consent.page')} />
-
- <Card
- className="sw-typo-lg sw-min-w-[500px] sw-mx-auto sw-w-[40%] sw-text-center"
- data-testid="plugin-risk-consent-page"
- >
- <Title className="sw-mb-4">{translate('plugin_risk_consent.title')}</Title>
-
- <p className="sw-mb-4">{translate('plugin_risk_consent.description')}</p>
-
- <p className="sw-mb-6">{translate('plugin_risk_consent.description2')}</p>
-
- <Button className="sw-my-4" onClick={acknowledgeRisk} variety={ButtonVariety.Primary}>
- {translate('plugin_risk_consent.action')}
- </Button>
- </Card>
- </CenteredLayout>
- );
-}
-
-export default whenLoggedIn(withRouter(PluginRiskConsent));
diff --git a/server/sonar-web/src/main/js/app/components/ProjectAdminContainer.tsx b/server/sonar-web/src/main/js/app/components/ProjectAdminContainer.tsx
deleted file mode 100644
index 87a8360d756..00000000000
--- a/server/sonar-web/src/main/js/app/components/ProjectAdminContainer.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Outlet } from 'react-router-dom';
-import A11ySkipTarget from '~sonar-aligned/components/a11y/A11ySkipTarget';
-import { Component } from '../../types/types';
-import handleRequiredAuthorization from '../utils/handleRequiredAuthorization';
-import withComponentContext from './componentContext/withComponentContext';
-
-interface Props {
- component: Component;
-}
-
-export class ProjectAdminContainer extends React.PureComponent<Props> {
- mounted = false;
-
- componentDidMount() {
- // We need to check permissions *after* the parent ComponentContainer is updated.
- // This is why we wrap checkPermission() in a setTimeout().
- //
- // We want to prevent an edge-case where if you navigate from an admin component page
- // to another component page where you have "read" access but no admin access, and
- // then hit the browser's Back button, you will get redirected to the login page.
- //
- // The reason is that this component will get mounted *before* the parent
- // ComponentContainer is *updated*. The parent component still has the last component
- // stored in state, the one where the user might not have admin access. It will detect
- // the change in URL and trigger a refresh of its state, but this comes too late; the
- // checkPermission() here will already have triggered (because mounts happen before updates)
- // and redirected the user. Wrapping it in a setTimeout() allows the parent component
- // to refresh, unmounting this component, and only triggering the redirect if it makes sense.
- //
- // See https://sonarsource.atlassian.net/browse/SONAR-19437
- setTimeout(this.checkPermissions, 0);
- this.mounted = true;
- }
-
- componentDidUpdate() {
- this.checkPermissions();
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- checkPermissions = () => {
- if (this.mounted && !this.isProjectAdmin()) {
- handleRequiredAuthorization();
- }
- };
-
- isProjectAdmin = () => {
- const { configuration } = this.props.component;
- return configuration != null && configuration.showSettings;
- };
-
- render() {
- if (!this.isProjectAdmin()) {
- return null;
- }
-
- return (
- <main>
- <A11ySkipTarget anchor="admin_main" />
- <Outlet />
- </main>
- );
- }
-}
-
-export default withComponentContext(ProjectAdminContainer);
diff --git a/server/sonar-web/src/main/js/app/components/RecentHistory.ts b/server/sonar-web/src/main/js/app/components/RecentHistory.ts
deleted file mode 100644
index 7dfae6ee209..00000000000
--- a/server/sonar-web/src/main/js/app/components/RecentHistory.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { get, remove, save } from '../../helpers/storage';
-
-const RECENT_HISTORY = 'sonar_recent_history';
-const HISTORY_LIMIT = 10;
-
-export type History = Array<{
- icon: string;
- key: string;
- name: string;
-}>;
-
-export default class RecentHistory {
- static get(): History {
- const history = get(RECENT_HISTORY);
- if (history == null) {
- return [];
- } else {
- try {
- return JSON.parse(history);
- } catch {
- remove(RECENT_HISTORY);
- return [];
- }
- }
- }
-
- static set(newHistory: History) {
- save(RECENT_HISTORY, JSON.stringify(newHistory));
- }
-
- static clear() {
- remove(RECENT_HISTORY);
- }
-
- static add(componentKey: string, componentName: string, icon: string) {
- const sonarHistory = RecentHistory.get();
- const newEntry = { key: componentKey, name: componentName, icon };
- let newHistory = sonarHistory.filter((entry) => entry.key !== newEntry.key);
- newHistory.unshift(newEntry);
- newHistory = newHistory.slice(0, HISTORY_LIMIT);
- RecentHistory.set(newHistory);
- }
-
- static remove(componentKey: string) {
- const history = RecentHistory.get();
- const newHistory = history.filter((entry) => entry.key !== componentKey);
- RecentHistory.set(newHistory);
- }
-}
diff --git a/server/sonar-web/src/main/js/app/components/ResetPassword.tsx b/server/sonar-web/src/main/js/app/components/ResetPassword.tsx
deleted file mode 100644
index abc30f16fb5..00000000000
--- a/server/sonar-web/src/main/js/app/components/ResetPassword.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Helmet } from 'react-helmet-async';
-import {
- FlagMessage,
- LargeCenteredLayout,
- PageContentFontWrapper,
- SubHeading,
- Title,
-} from '~design-system';
-import ResetPasswordForm from '../../components/common/ResetPasswordForm';
-import { whenLoggedIn } from '../../components/hoc/whenLoggedIn';
-import { translate } from '../../helpers/l10n';
-import { getBaseUrl } from '../../helpers/system';
-import { LoggedInUser } from '../../types/users';
-
-export interface ResetPasswordProps {
- currentUser: LoggedInUser;
-}
-
-export function ResetPassword({ currentUser }: Readonly<ResetPasswordProps>) {
- return (
- <LargeCenteredLayout className="sw-h-screen sw-pt-10">
- <PageContentFontWrapper className="sw-typo-default">
- <Helmet defer={false} title={translate('my_account.reset_password.page')} />
- <div className="sw-flex sw-justify-center">
- <div>
- <Title>{translate('my_account.reset_password')}</Title>
- <FlagMessage variant="warning" className="sw-mb-4">
- {translate('my_account.reset_password.explain')}
- </FlagMessage>
- <SubHeading>{translate('my_profile.password.title')}</SubHeading>
- <ResetPasswordForm
- user={currentUser}
- onPasswordChange={() => {
- // Force a refresh for the backend to handle additional redirects.
- window.location.href = `${getBaseUrl()}/`;
- }}
- />
- </div>
- </div>
- </PageContentFontWrapper>
- </LargeCenteredLayout>
- );
-}
-
-export default whenLoggedIn(ResetPassword);
diff --git a/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx b/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx
deleted file mode 100644
index 8879c9c2453..00000000000
--- a/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Outlet } from 'react-router-dom';
-import GlobalFooter from './GlobalFooter';
-import MainSonarQubeBar from './nav/global/MainSonarQubeBar';
-
-/*
- * We need to render either children or the Outlet,
- * because this component is used both in the context of routes and as a regular container
- */
-export default function SimpleContainer({ children }: { children?: React.ReactNode }) {
- return (
- <div className="sw-flex sw-flex-col sw-h-full sw-min-h-[100vh]">
- <div className="sw-box-border sw-flex-auto" id="container">
- <MainSonarQubeBar />
- {children !== undefined ? children : <Outlet />}
- </div>
- <GlobalFooter />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/SimpleSessionsContainer.tsx b/server/sonar-web/src/main/js/app/components/SimpleSessionsContainer.tsx
deleted file mode 100644
index 98ccad33108..00000000000
--- a/server/sonar-web/src/main/js/app/components/SimpleSessionsContainer.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Outlet } from 'react-router-dom';
-import GlobalFooter from './GlobalFooter';
-import PageTracker from './PageTracker';
-
-export default function SimpleSessionsContainer() {
- return (
- <>
- <PageTracker />
-
- <div className="sw-flex sw-flex-col sw-h-full sw-min-h-[100vh]">
- <div className="sw-box-border sw-flex-auto" id="container">
- <Outlet />
- </div>
- <GlobalFooter hideLoggedInInfo />
- </div>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/SonarLintConnection.tsx b/server/sonar-web/src/main/js/app/components/SonarLintConnection.tsx
deleted file mode 100644
index 106ca9b1439..00000000000
--- a/server/sonar-web/src/main/js/app/components/SonarLintConnection.tsx
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, ButtonVariety, IconCheck, LinkStandalone } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { useSearchParams } from 'react-router-dom';
-import {
- Card,
- CardSeparator,
- ClipboardButton,
- InputField,
- ListItem,
- Note,
- OrderedList,
- Title,
-} from '~design-system';
-import { Image } from '~sonar-aligned/components/common/Image';
-import { SonarQubeConnectionIllustration } from '../../components/branding/SonarQubeConnectionIllustration';
-import { whenLoggedIn } from '../../components/hoc/whenLoggedIn';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { generateSonarLintUserToken, portIsValid, sendUserToken } from '../../helpers/sonarlint';
-import { NewUserToken } from '../../types/token';
-import { LoggedInUser } from '../../types/users';
-
-enum Status {
- request,
- tokenError,
- tokenCreated,
- tokenSent,
-}
-
-interface Props {
- currentUser: LoggedInUser;
-}
-
-export function SonarLintConnection({ currentUser }: Readonly<Props>) {
- const [searchParams] = useSearchParams();
- const [status, setStatus] = React.useState(Status.request);
- const [newToken, setNewToken] = React.useState<NewUserToken | undefined>(undefined);
-
- const port = parseInt(searchParams.get('port') ?? '0', 10);
- const ideName = searchParams.get('ideName') ?? translate('sonarlint-connection.unspecified-ide');
-
- const { login } = currentUser;
-
- const authorize = React.useCallback(async () => {
- const token = await generateSonarLintUserToken({ ideName, login }).catch(() => undefined);
-
- if (!token) {
- setStatus(Status.tokenError);
- return;
- }
-
- setNewToken(token);
-
- if (!portIsValid(port)) {
- setStatus(Status.tokenCreated);
- return;
- }
-
- try {
- await sendUserToken(port, token);
- setStatus(Status.tokenSent);
- } catch (_) {
- setStatus(Status.tokenCreated);
- }
- }, [port, ideName, login]);
-
- return (
- <Card className="sw-mt-[10vh] sw-mx-auto sw-w-[650px] sw-text-center">
- {status === Status.request && (
- <>
- <Title>{translate('sonarlint-connection.request.title')}</Title>
- <SonarQubeConnectionIllustration className="sw-my-4" connected={false} />
- <p className="sw-my-4">
- <FormattedMessage id="sonarlint-connection.request.description" values={{ ideName }} />
- </p>
- <p className="sw-mb-10">{translate('sonarlint-connection.request.description2')}</p>
-
- <Button
- prefix={<IconCheck className="sw-mr-1" />}
- onClick={authorize}
- variety={ButtonVariety.Primary}
- >
- {translate('sonarlint-connection.request.action')}
- </Button>
- </>
- )}
-
- {status === Status.tokenError && (
- <>
- <Image aria-hidden className="sw-my-4 sw-pt-2" src="/images/cross.svg" />
- <Title>{translate('sonarlint-connection.token-error.title')}</Title>
- <p className="sw-my-4">{translate('sonarlint-connection.token-error.description')}</p>
- <p className="sw-mb-4">
- <FormattedMessage
- id="sonarlint-connection.token-error.description2"
- defaultMessage={translate('sonarlint-connection.token-error.description2')}
- values={{
- link: (
- <LinkStandalone to="/account/security">
- {translate('sonarlint-connection.token-error.description2.link')}
- </LinkStandalone>
- ),
- }}
- />
- </p>
- </>
- )}
-
- {status === Status.tokenCreated && newToken && (
- <>
- <Image aria-hidden className="sw-my-4 sw-pt-2" src="/images/check.svg" />
- <Title>{translate('sonarlint-connection.connection-error.title')}</Title>
- <p className="sw-my-6">
- {translate('sonarlint-connection.connection-error.description')}
- </p>
- <div className="sw-flex sw-items-center">
- <Note className="sw-w-abs-150 sw-text-start">
- {translate('sonarlint-connection.connection-error.token-name')}
- </Note>
- {newToken.name}
- </div>
- <CardSeparator className="sw-my-3" />
- <div className="sw-flex sw-items-center">
- <Note className="sw-min-w-abs-150 sw-text-start">
- {translate('sonarlint-connection.connection-error.token-value')}
- </Note>
- <InputField className="sw-cursor-text" disabled size="full" value={newToken.token} />
- <ClipboardButton className="sw-ml-2" copyValue={newToken.token} />
- </div>
- <div className="sw-mt-10">
- <strong>{translate('sonarlint-connection.connection-error.next-steps')}</strong>
- </div>
- <OrderedList className="sw-list-inside sw-mb-4">
- <ListItem>{translate('sonarlint-connection.connection-error.step1')}</ListItem>
- <ListItem>{translate('sonarlint-connection.connection-error.step2')}</ListItem>
- </OrderedList>
- </>
- )}
-
- {status === Status.tokenSent && newToken && (
- <>
- <Title>{translate('sonarlint-connection.success.title')}</Title>
- <SonarQubeConnectionIllustration className="sw-mb-4" connected />
- <p className="sw-my-4">
- {translateWithParameters('sonarlint-connection.success.description', newToken.name)}
- </p>
- <div className="sw-mt-10">
- <strong>{translate('sonarlint-connection.success.last-step')}</strong>
- </div>
- <div className="sw-my-4">{translate('sonarlint-connection.success.step')}</div>
- </>
- )}
- </Card>
- );
-}
-
-export default whenLoggedIn(SonarLintConnection);
diff --git a/server/sonar-web/src/main/js/app/components/StartupModal.tsx b/server/sonar-web/src/main/js/app/components/StartupModal.tsx
deleted file mode 100644
index 5ef6b4e61f1..00000000000
--- a/server/sonar-web/src/main/js/app/components/StartupModal.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { differenceInDays } from 'date-fns';
-import * as React from 'react';
-import { showLicense } from '../../api/editions';
-import { parseDate, toShortISO8601String } from '../../helpers/dates';
-import { hasMessage } from '../../helpers/l10n';
-import { get, save } from '../../helpers/storage';
-import { AppState } from '../../types/appstate';
-import { EditionKey } from '../../types/editions';
-import { CurrentUser, isLoggedIn } from '../../types/users';
-import LicensePromptModal from './LicensePromptModal';
-import withAppStateContext from './app-state/withAppStateContext';
-import withCurrentUserContext from './current-user/withCurrentUserContext';
-
-interface Props {
- appState: AppState;
- currentUser: CurrentUser;
-}
-
-interface State {
- open?: boolean;
-}
-
-const LICENSE_PROMPT = 'sonarqube.license.prompt';
-
-export class StartupModal extends React.PureComponent<React.PropsWithChildren<Props>, State> {
- state: State = {};
-
- componentDidMount() {
- this.tryAutoOpenLicense();
- }
-
- closeLicense = () => {
- this.setState({ open: false });
- };
-
- tryAutoOpenLicense = () => {
- const { appState, currentUser } = this.props;
- const hasLicenseManager = hasMessage('license.prompt.title');
- const hasLicensedEdition = appState.edition && appState.edition !== EditionKey.community;
-
- if (appState.canAdmin && hasLicensedEdition && isLoggedIn(currentUser) && hasLicenseManager) {
- const lastPrompt = get(LICENSE_PROMPT, currentUser.login);
-
- if (!lastPrompt || differenceInDays(new Date(), parseDate(lastPrompt)) >= 1) {
- showLicense()
- .then((license) => {
- if (!license || !license.isValidEdition) {
- save(LICENSE_PROMPT, toShortISO8601String(new Date()), currentUser.login);
- this.setState({ open: true });
- }
- })
- .catch(() => {});
- }
- }
- };
-
- render() {
- const { open } = this.state;
- return <LicensePromptModal isOpen={open} onClose={this.closeLicense} />;
- }
-}
-
-export default withCurrentUserContext(withAppStateContext(StartupModal));
diff --git a/server/sonar-web/src/main/js/app/components/SystemAnnouncement.tsx b/server/sonar-web/src/main/js/app/components/SystemAnnouncement.tsx
deleted file mode 100644
index 63726204e27..00000000000
--- a/server/sonar-web/src/main/js/app/components/SystemAnnouncement.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { keyBy, throttle } from 'lodash';
-import * as React from 'react';
-import { FlagWarningIcon, themeBorder, themeColor } from '~design-system';
-import { getValues } from '../../api/settings';
-import { Feature } from '../../types/features';
-import { GlobalSettingKeys } from '../../types/settings';
-import withAvailableFeatures, {
- WithAvailableFeaturesProps,
-} from './available-features/withAvailableFeatures';
-
-const THROTTLE_TIME_MS = 10000;
-
-interface State {
- displayMessage: boolean;
- message: string;
-}
-
-export class SystemAnnouncement extends React.PureComponent<WithAvailableFeaturesProps, State> {
- state: State = { displayMessage: false, message: '' };
-
- componentDidMount() {
- if (this.props.hasFeature(Feature.Announcement)) {
- this.getSettings();
- window.addEventListener('focus', this.handleVisibilityChange);
- }
- }
-
- componentWillUnmount() {
- if (this.props.hasFeature(Feature.Announcement)) {
- window.removeEventListener('focus', this.handleVisibilityChange);
- }
- }
-
- getSettings = async () => {
- const values = await getValues({
- keys: [GlobalSettingKeys.DisplayAnnouncementMessage, GlobalSettingKeys.AnnouncementMessage],
- });
-
- const settings = keyBy(values, 'key');
-
- this.setState({
- displayMessage: settings?.[GlobalSettingKeys.DisplayAnnouncementMessage]?.value === 'true',
- message: settings?.[GlobalSettingKeys.AnnouncementMessage]?.value ?? '',
- });
- };
-
- // eslint-disable-next-line react/sort-comp
- handleVisibilityChange = throttle(() => {
- if (document.visibilityState === 'visible') {
- this.getSettings();
- }
- }, THROTTLE_TIME_MS);
-
- render() {
- const { displayMessage, message } = this.state;
-
- return (
- <StyledBanner
- className="sw-py-3 sw-px-4 sw-gap-3"
- style={!(displayMessage && message.length > 0) ? { display: 'none' } : {}}
- title={message}
- aria-live="assertive"
- role="alert"
- >
- <FlagWarningIcon />
- <span>{displayMessage && message}</span>
- </StyledBanner>
- );
- }
-}
-
-export default withAvailableFeatures(SystemAnnouncement);
-
-const StyledBanner = styled.div`
- display: flex;
- align-items: center;
- box-sizing: border-box;
- width: 100%;
-
- background-color: ${themeColor('warningBackground')};
- border-bottom: ${themeBorder('default', 'warningBorder')};
-`;
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/AdminContainer-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/AdminContainer-test.tsx
deleted file mode 100644
index 8dc51f4ca7c..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/AdminContainer-test.tsx
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import * as React from 'react';
-import { Route, useOutletContext } from 'react-router-dom';
-import { byLabelText, byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { getSystemStatus, waitSystemUPStatus } from '../../../api/system';
-import { mockAppState } from '../../../helpers/testMocks';
-import { renderAppRoutes } from '../../../helpers/testReactTestingUtils';
-import { AdminPagesContext } from '../../../types/admin';
-import { AdminContainer, AdminContainerProps } from '../AdminContainer';
-import AdminContext from '../AdminContext';
-
-jest.mock('../../../helpers/l10nBundle', () => {
- const bundle = jest.requireActual('../../../helpers/l10nBundle');
- return {
- ...bundle,
- getIntl: () => ({ formatMessage: jest.fn() }),
- };
-});
-
-jest.mock('../../../api/navigation', () => ({
- getSettingsNavigation: jest
- .fn()
- .mockResolvedValue({ extensions: [{ key: 'asd', name: 'asdf' }] }),
-}));
-
-jest.mock('../../../api/plugins', () => ({
- getPendingPlugins: jest.fn().mockResolvedValue({
- installing: [{ key: '1', name: 'installing' }],
- updating: [
- { key: '2', name: 'updating' },
- { key: '2b', name: 'update this too' },
- ],
- removing: [{ key: '3', name: 'removing' }],
- }),
-}));
-
-jest.mock('../../../api/system', () => ({
- getSystemStatus: jest.fn().mockResolvedValue({ status: 'DOWN' }),
- waitSystemUPStatus: jest.fn().mockResolvedValue({ status: 'RESTARTING' }),
-}));
-
-const originalLocation = window.location;
-const reload = jest.fn();
-
-beforeAll(() => {
- Object.defineProperty(window, 'location', {
- writable: true,
- value: { reload },
- });
-});
-
-afterAll(() => {
- Object.defineProperty(window, 'location', {
- writable: true,
- value: originalLocation,
- });
-});
-
-it('should render nav and provide context to children', async () => {
- const user = userEvent.setup();
- renderAdminContainer();
-
- expect(await ui.navHeader.find()).toBeInTheDocument();
-
- expect(ui.pagesList.byRole('listitem').getAll()).toHaveLength(1);
- expect(ui.pagesList.byText('asdf').get()).toBeInTheDocument();
-
- expect(ui.pluginsInstallingList.byRole('listitem').getAll()).toHaveLength(1);
- expect(ui.pluginsInstallingList.byText('installing').get()).toBeInTheDocument();
-
- expect(ui.pluginsUpdatingList.byRole('listitem').getAll()).toHaveLength(2);
- expect(ui.pluginsUpdatingList.byText('updating').get()).toBeInTheDocument();
- expect(ui.pluginsUpdatingList.byText('update this too').get()).toBeInTheDocument();
-
- expect(ui.pluginsRemovingList.byRole('listitem').getAll()).toHaveLength(1);
- expect(ui.pluginsRemovingList.byText('removing').get()).toBeInTheDocument();
-
- expect(byText('DOWN').get()).toBeInTheDocument();
-
- // Renders plugins notification
- expect(ui.pluginsNotification.get()).toBeInTheDocument();
-
- // Trigger a status update
- jest.mocked(getSystemStatus).mockResolvedValueOnce({ id: '', version: '', status: 'RESTARTING' });
- jest.mocked(waitSystemUPStatus).mockResolvedValueOnce({ id: '', version: '', status: 'UP' });
- await user.click(ui.fetchStatusButton.get());
-
- expect(await byText('UP').find()).toBeInTheDocument();
- expect(reload).toHaveBeenCalled();
-});
-
-function renderAdminContainer(props: Partial<AdminContainerProps> = {}) {
- return renderAppRoutes('admin', () => (
- <Route
- path="admin"
- element={
- <AdminContainer
- appState={mockAppState({
- canAdmin: true,
- })}
- {...props}
- />
- }
- >
- <Route index element={<TestChildComponent />} />
- </Route>
- ));
-}
-
-function TestChildComponent() {
- const { adminPages } = useOutletContext<AdminPagesContext>();
-
- const { fetchPendingPlugins, fetchSystemStatus, pendingPlugins, systemStatus } =
- React.useContext(AdminContext);
-
- return (
- <div>
- <div id="component-nav-portal" />
- <ul aria-label="pages">
- {adminPages.map((page) => (
- <li key={page.key}>{page.name}</li>
- ))}
- </ul>
-
- <ul aria-label="plugins - installing">
- {pendingPlugins.installing.map((p) => (
- <li key={p.key}>{p.name}</li>
- ))}
- </ul>
- <ul aria-label="plugins - removing">
- {pendingPlugins.removing.map((p) => (
- <li key={p.key}>{p.name}</li>
- ))}
- </ul>
- <ul aria-label="plugins - updating">
- {pendingPlugins.updating.map((p) => (
- <li key={p.key}>{p.name}</li>
- ))}
- </ul>
- <button type="button" onClick={fetchPendingPlugins}>
- fetch plugins
- </button>
-
- {systemStatus}
- <button type="button" onClick={fetchSystemStatus}>
- fetch status
- </button>
- </div>
- );
-}
-
-const ui = {
- navHeader: byRole('heading', { name: 'layout.settings' }),
- pagesList: byLabelText('pages'),
- pluginsNotification: byText('marketplace.instance_needs_to_be_restarted_to'),
- pluginsInstallingList: byLabelText('plugins - installing'),
- pluginsUpdatingList: byLabelText('plugins - updating'),
- pluginsRemovingList: byLabelText('plugins - removing'),
-
- fetchPluginsButton: byRole('button', { name: 'fetch plugins' }),
- fetchStatusButton: byRole('button', { name: 'fetch status' }),
-};
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/App-test.tsx
deleted file mode 100644
index 6bf918d255b..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/App-test.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { mockAppState } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { App } from '../App';
-
-it('should render correctly with gravatar', () => {
- renderApp({
- appState: mockAppState({
- settings: {
- 'sonar.lf.enableGravatar': 'true',
- 'sonar.lf.gravatarServerUrl': 'http://example.com',
- },
- }),
- });
-
- // eslint-disable-next-line testing-library/no-node-access
- expect(document.head.querySelector('link')).toHaveAttribute('href', 'http://example.com');
-});
-
-it('should correctly set the scrollbar width as a custom property', () => {
- renderApp();
- expect(document.body.style.getPropertyValue('--sbw')).toBe('0px');
-});
-
-function renderApp(props: Partial<App['props']> = {}) {
- return renderComponent(
- <App
- appState={mockAppState({
- settings: {
- 'sonar.lf.enableGravatar': 'false',
- 'sonar.lf.gravatarServerUrl': '',
- },
- })}
- {...props}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/CalculationChangeMessage-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/CalculationChangeMessage-test.tsx
deleted file mode 100644
index aac469f7bee..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/CalculationChangeMessage-test.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Outlet, Route } from 'react-router-dom';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { ModeServiceMock } from '../../../api/mocks/ModeServiceMock';
-import { renderAppRoutes } from '../../../helpers/testReactTestingUtils';
-import { Mode } from '../../../types/mode';
-import CalculationChangeMessage from '../calculation-notification/CalculationChangeMessage';
-
-const ui = {
- alert: byRole('alert'),
- learnMoreLink: byRole('link', {
- name: 'notification.calculation_change.message_link open_in_new_tab',
- }),
-
- alertText: byText('notification.calculation_change.message'),
-};
-
-const modeHandler = new ModeServiceMock();
-
-beforeEach(() => {
- modeHandler.reset();
-});
-
-it.each([
- ['Project', '/projects'],
- ['Portfolios', '/portfolios'],
-])('should render on %s page', (_, path) => {
- render(path);
- expect(ui.alert.get()).toBeInTheDocument();
- expect(ui.alertText.get()).toBeInTheDocument();
- expect(ui.learnMoreLink.get()).toBeInTheDocument();
-});
-
-it.each([
- ['Project', '/projects'],
- ['Portfolios', '/portfolios'],
-])('should not render on %s page if isStandardMode', (_, path) => {
- modeHandler.setMode(Mode.Standard);
- render(path);
- expect(ui.alert.get()).toBeInTheDocument();
- expect(ui.alertText.get()).toBeInTheDocument();
- expect(ui.learnMoreLink.get()).toBeInTheDocument();
-});
-
-it('should not render on other page', () => {
- render('/other');
- expect(ui.alert.query()).not.toBeInTheDocument();
- expect(ui.alertText.query()).not.toBeInTheDocument();
- expect(ui.learnMoreLink.query()).not.toBeInTheDocument();
-});
-
-function render(indexPath = '/projects') {
- renderAppRoutes(indexPath, () => (
- <Route
- path="/"
- element={
- <>
- <CalculationChangeMessage />
- <Outlet />
- </>
- }
- >
- <Route path="projects" element={<div>Projects</div>} />
- <Route path="portfolios" element={<div>Portfolios</div>} />
- <Route path="other" element={<div>Other page</div>} />
- </Route>
- ));
-}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx
deleted file mode 100644
index ba421059107..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx
+++ /dev/null
@@ -1,672 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen, waitFor } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { useContext } from 'react';
-import { Route } from 'react-router-dom';
-import * as withRouter from '~sonar-aligned/components/hoc/withRouter';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { ComponentQualifier, Visibility } from '~sonar-aligned/types/component';
-import { validateProjectAlmBinding } from '../../../api/alm-settings';
-import { getTasksForComponent } from '../../../api/ce';
-import { getComponentData } from '../../../api/components';
-import { getComponentNavigation } from '../../../api/navigation';
-import { mockProjectAlmBindingConfigurationErrors } from '../../../helpers/mocks/alm-settings';
-import { mockBranch, mockPullRequest } from '../../../helpers/mocks/branch-like';
-import { mockComponent } from '../../../helpers/mocks/component';
-import { mockTask } from '../../../helpers/mocks/tasks';
-import { HttpStatus } from '../../../helpers/request';
-import { renderAppRoutes, renderComponent } from '../../../helpers/testReactTestingUtils';
-import { getProjectUrl, getPullRequestUrl } from '../../../helpers/urls';
-import { TaskStatuses, TaskTypes } from '../../../types/tasks';
-import handleRequiredAuthorization from '../../utils/handleRequiredAuthorization';
-import ComponentContainer, { isSameBranch } from '../ComponentContainer';
-import { WithAvailableFeaturesProps } from '../available-features/withAvailableFeatures';
-import { ComponentContext } from '../componentContext/ComponentContext';
-
-jest.mock('../../../api/ce', () => ({
- getTasksForComponent: jest.fn().mockResolvedValue({ queue: [] }),
-}));
-
-jest.mock('../../../api/components', () => ({
- getComponentData: jest
- .fn()
- .mockResolvedValue({ component: { name: 'component name', analysisDate: '2018-07-30' } }),
-}));
-
-jest.mock('../../../queries/mode', () => ({
- useStandardExperienceModeQuery: jest.fn(() => ({
- data: { mode: 'STANDARD_EXPERIENCE', modified: false },
- })),
-}));
-
-jest.mock('../../../api/navigation', () => ({
- getComponentNavigation: jest.fn().mockResolvedValue({
- breadcrumbs: [{ key: 'portfolioKey', name: 'portfolio', qualifier: 'VW' }],
- key: 'portfolioKey',
- }),
-}));
-
-jest.mock('../../../api/branches', () => ({
- getBranches: jest.fn().mockResolvedValue([mockBranch()]),
- getPullRequests: jest.fn().mockResolvedValue([mockPullRequest({ target: 'dropped-branch' })]),
-}));
-
-jest.mock('../../../api/alm-settings', () => ({
- validateProjectAlmBinding: jest.fn().mockResolvedValue(undefined),
-}));
-
-jest.mock('../../utils/handleRequiredAuthorization', () => ({
- __esModule: true,
- default: jest.fn(),
-}));
-
-jest.mock('~sonar-aligned/components/hoc/withRouter', () => ({
- __esModule: true,
- ...jest.requireActual('~sonar-aligned/components/hoc/withRouter'),
-}));
-
-const ui = {
- projectTitle: byRole('link', { name: 'Project' }),
- projectText: byText('project'),
- portfolioTitle: byRole('link', { name: 'portfolio' }),
- portfolioText: byText('portfolio'),
- overviewPageLink: byRole('link', { name: 'overview.page' }),
- issuesPageLink: byRole('link', { name: 'issues.page' }),
- hotspotsPageLink: byRole('link', { name: 'layout.security_hotspots' }),
- measuresPageLink: byRole('link', { name: 'layout.measures' }),
- codePageLink: byRole('link', { name: 'code.page' }),
- activityPageLink: byRole('link', { name: 'project_activity.page' }),
- projectInfoLink: byRole('link', { name: 'project.info.title' }),
- dashboardNotFound: byText('dashboard.project.not_found'),
- goBackToHomePageLink: byRole('link', { name: 'go_back_to_homepage' }),
-};
-
-afterEach(() => {
- jest.clearAllMocks();
-});
-
-it('should render the component nav correctly for portfolio', async () => {
- renderComponentContainerAsComponent();
- expect(await ui.portfolioTitle.find()).toHaveAttribute('href', '/portfolio?id=portfolioKey');
- expect(ui.issuesPageLink.get()).toHaveAttribute(
- 'href',
- '/project/issues?id=portfolioKey&issueStatuses=OPEN%2CCONFIRMED',
- );
- expect(ui.measuresPageLink.get()).toHaveAttribute('href', '/component_measures?id=portfolioKey');
- expect(ui.activityPageLink.get()).toHaveAttribute('href', '/project/activity?id=portfolioKey');
-
- await waitFor(() => {
- expect(getTasksForComponent).toHaveBeenCalledWith('portfolioKey');
- });
-});
-
-it('should render the component nav correctly for projects', async () => {
- const component = mockComponent({
- breadcrumbs: [{ key: 'project', name: 'Project', qualifier: ComponentQualifier.Project }],
- key: 'project-key',
- analysisDate: '2018-07-30',
- });
-
- jest
- .mocked(getComponentNavigation)
- .mockResolvedValueOnce({} as unknown as Awaited<ReturnType<typeof getComponentNavigation>>);
-
- jest
- .mocked(getComponentData)
- .mockResolvedValueOnce({ component } as unknown as Awaited<
- ReturnType<typeof getComponentData>
- >);
-
- renderComponentContainerAsComponent();
- expect(await ui.projectTitle.find()).toHaveAttribute('href', '/dashboard?id=project');
- expect(ui.overviewPageLink.get()).toHaveAttribute('href', '/dashboard?id=project-key');
- expect(ui.issuesPageLink.get()).toHaveAttribute(
- 'href',
- '/project/issues?id=project-key&issueStatuses=OPEN%2CCONFIRMED',
- );
- expect(ui.hotspotsPageLink.get()).toHaveAttribute('href', '/security_hotspots?id=project-key');
- expect(ui.measuresPageLink.get()).toHaveAttribute('href', '/component_measures?id=project-key');
- expect(ui.codePageLink.get()).toHaveAttribute('href', '/code?id=project-key');
- expect(ui.activityPageLink.get()).toHaveAttribute('href', '/project/activity?id=project-key');
- expect(ui.projectInfoLink.get()).toHaveAttribute('href', '/project/information?id=project-key');
-});
-
-it('should be able to change component', async () => {
- const user = userEvent.setup();
- renderComponentContainer();
- expect(await screen.findByText('This is a test component')).toBeInTheDocument();
- expect(screen.getByRole('button', { name: 'change component' })).toBeInTheDocument();
- expect(screen.getByText('component name')).toBeInTheDocument();
- await user.click(screen.getByRole('button', { name: 'change component' }));
- expect(screen.getByText('new component name')).toBeInTheDocument();
-});
-
-it('should show component not found if it does not exist', async () => {
- jest
- .mocked(getComponentNavigation)
- .mockRejectedValueOnce(new Response(null, { status: HttpStatus.NotFound }));
-
- renderComponentContainer();
-
- expect(await ui.dashboardNotFound.find()).toBeInTheDocument();
- expect(ui.goBackToHomePageLink.get()).toBeInTheDocument();
-});
-
-it('should show component not found if target branch is not found for fixing pull request', async () => {
- renderComponentContainer(
- { hasFeature: jest.fn().mockReturnValue(true) },
- '?id=foo&fixedInPullRequest=1001',
- );
-
- expect(await ui.dashboardNotFound.find()).toBeInTheDocument();
-});
-
-describe('getTasksForComponent', () => {
- beforeEach(() => {
- jest.useFakeTimers();
- });
- afterEach(() => {
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
- });
-
- it('reload component after task progress finished', async () => {
- jest
- .mocked(getTasksForComponent)
- .mockResolvedValueOnce({
- queue: [{ id: 'foo', status: TaskStatuses.InProgress, type: TaskTypes.ViewRefresh }],
- } as unknown as Awaited<ReturnType<typeof getTasksForComponent>>)
- .mockResolvedValueOnce({
- queue: [],
- } as unknown as Awaited<ReturnType<typeof getTasksForComponent>>);
-
- renderComponentContainer();
-
- // getComponentNavigation is called imidiately after the component is mounted
- expect(getComponentNavigation).toHaveBeenCalledTimes(1);
-
- jest.runOnlyPendingTimers();
-
- // we check that setTimeout is not yet set, because it requires getComponentNavigation to finish first (as a microtask)
- expect(jest.getTimerCount()).toBe(0);
-
- // First round, a pending task in the queue. This should trigger the setTimeout.
- // We need waitFor because getComponentNavigation is not done yet and it is waiting to be run as a microtask
- await waitFor(() => expect(getTasksForComponent).toHaveBeenCalledTimes(1));
-
- // getTasksForComponent updated the tasks, which triggers the setTimeout
- expect(jest.getTimerCount()).toBe(1);
- // we run the timer to trigger the next getTasksForComponent call
- jest.runOnlyPendingTimers();
-
- // Second round, the queue is now empty. This should trigger the component to reload.
- expect(getTasksForComponent).toHaveBeenCalledTimes(2);
-
- // Since the set of tasks is changed the component fetching is triggered
- // we need waitFor because getTasksForComponent is triggered, but not yet done, and it is waiting to be run as a microtask
- await waitFor(() => {
- expect(getComponentNavigation).toHaveBeenCalledTimes(2);
- });
-
- // since waitFor waited for all microtasks and state changes getTasksForComponent was called as well because of component change.
- expect(getTasksForComponent).toHaveBeenCalledTimes(3);
-
- // Make sure the timeout was cleared. It should not be called again.
- expect(jest.getTimerCount()).toBe(0);
- });
-
- it('reloads component after task progress finished, and moves straight to current', async () => {
- jest.mocked(getComponentData).mockResolvedValueOnce({
- component: { key: 'bar' },
- } as unknown as Awaited<ReturnType<typeof getComponentData>>);
-
- jest
- .mocked(getTasksForComponent)
- .mockResolvedValueOnce({ queue: [] } as unknown as Awaited<
- ReturnType<typeof getTasksForComponent>
- >)
- .mockResolvedValueOnce({
- queue: [],
- current: { id: 'foo', status: TaskStatuses.Success, type: TaskTypes.AppRefresh },
- } as unknown as Awaited<ReturnType<typeof getTasksForComponent>>);
-
- renderComponentContainer();
-
- // getComponentNavigation is called imidiately after the component is mounted
- expect(getComponentNavigation).toHaveBeenCalledTimes(1);
-
- // First round, no tasks in queue. This should trigger the setTimeout.
- // We need waitFor because getComponentNavigation is not done yet and it is waiting to be run as a microtask
- await waitFor(() => expect(getTasksForComponent).toHaveBeenCalledTimes(1));
-
- // Despite the fact taht we don't have any tasks in the queue, the component.analysisDate is undefined, so we trigger setTimeout
- expect(jest.getTimerCount()).toBe(1);
- jest.runOnlyPendingTimers();
-
- // Second round, nothing in the queue, BUT a success task is current. This
- // means the queue was processed too quick for us to see, and we didn't see
- // any pending tasks in the queue. So we immediately load the component again.
- expect(getTasksForComponent).toHaveBeenCalledTimes(2);
-
- // Since the set of tasks is changed the component fetching is triggered
- // we need waitFor because getTasksForComponent is triggered, but not yet done, and it is waiting to be run as a microtask
- await waitFor(() => {
- expect(getComponentNavigation).toHaveBeenCalledTimes(2);
- });
- // The status API call will be called 1 final time after the component is
- // fully loaded, so the total will be 3.
- expect(getTasksForComponent).toHaveBeenCalledTimes(3);
-
- // Make sure the timeout was cleared. It should not be called again.
- expect(jest.getTimerCount()).toBe(0);
- });
-
- it('only fully loads a non-empty component once', async () => {
- jest.mocked(getComponentData).mockResolvedValueOnce({
- component: { key: 'bar', analysisDate: '2019-01-01' },
- } as unknown as Awaited<ReturnType<typeof getComponentData>>);
-
- jest.mocked(getTasksForComponent).mockResolvedValueOnce({
- queue: [],
- current: { id: 'foo', status: TaskStatuses.Success, type: TaskTypes.Report },
- } as unknown as Awaited<ReturnType<typeof getTasksForComponent>>);
-
- renderComponentContainer();
-
- expect(getComponentNavigation).toHaveBeenCalledTimes(1);
-
- await waitFor(() => expect(getTasksForComponent).toHaveBeenCalledTimes(1));
-
- // Since the component has analysisDate, and the queue is empty, the setTimeout will not be triggered
- expect(jest.getTimerCount()).toBe(0);
- });
-
- it('only fully reloads a non-empty component if there was previously some task in progress', async () => {
- jest.mocked(getComponentData).mockResolvedValueOnce({
- component: { key: 'bar', analysisDate: '2019-01-01' },
- } as unknown as Awaited<ReturnType<typeof getComponentData>>);
-
- jest
- .mocked(getTasksForComponent)
- .mockResolvedValueOnce({
- queue: [{ id: 'foo', status: TaskStatuses.InProgress, type: TaskTypes.AppRefresh }],
- } as unknown as Awaited<ReturnType<typeof getTasksForComponent>>)
- .mockResolvedValueOnce({
- queue: [],
- current: { id: 'foo', status: TaskStatuses.Success, type: TaskTypes.AppRefresh },
- } as unknown as Awaited<ReturnType<typeof getTasksForComponent>>);
-
- renderComponentContainer();
-
- // First round, a pending task in the queue. This should trigger a reload of the
- // status endpoint.
- await waitFor(() => expect(getTasksForComponent).toHaveBeenCalledTimes(1));
-
- expect(jest.getTimerCount()).toBe(1);
- jest.runOnlyPendingTimers();
-
- // Second round, nothing in the queue, and a success task is current. This
- // implies the current task was updated, and previously we displayed some information
- // about a pending task. This new information must prompt the component to reload
- // all data.
- expect(getTasksForComponent).toHaveBeenCalledTimes(2);
-
- // The component was correctly re-loaded.
- await waitFor(() => {
- expect(getComponentNavigation).toHaveBeenCalledTimes(2);
- });
-
- // The status API call will be called 1 final time after the component is
- // fully loaded, so the total will be 3.
- expect(getTasksForComponent).toHaveBeenCalledTimes(3);
-
- // Make sure the timeout was cleared. It should not be called again.
- expect(jest.getTimerCount()).toBe(0);
- });
-});
-
-describe('should correctly validate the project binding depending on the context', () => {
- const COMPONENT = mockComponent({
- breadcrumbs: [{ key: 'foo', name: 'Foo', qualifier: ComponentQualifier.Project }],
- });
- const PROJECT_BINDING_ERRORS = mockProjectAlmBindingConfigurationErrors();
-
- it.each([
- ["has an analysis; won't perform any check", { ...COMPONENT, analysisDate: '2020-01' }],
- ['has a project binding; check is OK', COMPONENT, undefined, 1],
- ['has a project binding; check is not OK', COMPONENT, PROJECT_BINDING_ERRORS, 1],
- ])('%s', async (_, component, projectBindingErrors = undefined, n = 0) => {
- jest
- .mocked(getComponentNavigation)
- .mockResolvedValueOnce({} as unknown as Awaited<ReturnType<typeof getComponentNavigation>>);
-
- jest
- .mocked(getComponentData)
- .mockResolvedValueOnce({ component } as unknown as Awaited<
- ReturnType<typeof getComponentData>
- >);
-
- if (n > 0) {
- jest.mocked(validateProjectAlmBinding).mockResolvedValueOnce(projectBindingErrors);
- }
-
- renderComponentContainer({ hasFeature: jest.fn().mockReturnValue(true) });
- await waitFor(() => {
- expect(validateProjectAlmBinding).toHaveBeenCalledTimes(n);
- });
- });
-
- it('should show error message when check is not OK', async () => {
- jest
- .mocked(getComponentNavigation)
- .mockResolvedValueOnce({} as unknown as Awaited<ReturnType<typeof getComponentNavigation>>);
-
- jest
- .mocked(getComponentData)
- .mockResolvedValueOnce({ component: COMPONENT } as unknown as Awaited<
- ReturnType<typeof getComponentData>
- >);
-
- jest.mocked(validateProjectAlmBinding).mockResolvedValueOnce(PROJECT_BINDING_ERRORS);
-
- renderComponentContainerAsComponent({ hasFeature: jest.fn().mockReturnValue(true) });
- expect(
- await screen.findByText('component_navigation.pr_deco.error_detected_X', { exact: false }),
- ).toBeInTheDocument();
- });
-});
-
-describe('redirects', () => {
- it('should redirect if the user has no access', async () => {
- jest
- .mocked(getComponentNavigation)
- .mockRejectedValueOnce(new Response(null, { status: HttpStatus.Forbidden }));
-
- renderComponentContainer();
- await waitFor(() => {
- expect(handleRequiredAuthorization).toHaveBeenCalled();
- });
- });
-
- it('should redirect to portfolio when using dashboard path', async () => {
- renderComponentContainer(
- { hasFeature: jest.fn().mockReturnValue(true) },
- 'dashboard?id=foo',
- '/dashboard',
- );
-
- expect(await ui.portfolioText.find()).toBeInTheDocument();
- });
-});
-
-it.each([
- [ComponentQualifier.Application],
- [ComponentQualifier.Portfolio],
- [ComponentQualifier.SubPortfolio],
-])(
- 'should not care about PR decoration settings for %s',
- async (componentQualifier: ComponentQualifier) => {
- const component = mockComponent({
- breadcrumbs: [{ key: 'foo', name: 'Foo', qualifier: componentQualifier }],
- });
-
- jest
- .mocked(getComponentNavigation)
- .mockResolvedValueOnce({} as unknown as Awaited<ReturnType<typeof getComponentNavigation>>);
-
- jest
- .mocked(getComponentData)
- .mockResolvedValueOnce({ component } as unknown as Awaited<
- ReturnType<typeof getComponentData>
- >);
-
- renderComponentContainer({ hasFeature: jest.fn().mockReturnValue(true) });
- await waitFor(() => {
- expect(validateProjectAlmBinding).not.toHaveBeenCalled();
- });
- },
-);
-
-it('isSameBranch util returns expected result', () => {
- expect(isSameBranch(mockTask())).toBe(true);
- expect(isSameBranch(mockTask({ branch: 'branch' }), 'branch')).toBe(true);
- expect(isSameBranch(mockTask({ pullRequest: 'pr' }), undefined, 'pr')).toBe(true);
-});
-
-describe('tutorials', () => {
- it('should redirect to project main branch dashboard from tutorials when receiving new related scan report', async () => {
- const componentKey = 'foo-component';
- jest.mocked(getComponentData).mockResolvedValue({
- ancestors: [],
- component: {
- key: componentKey,
- name: 'component name',
- qualifier: ComponentQualifier.Project,
- visibility: Visibility.Public,
- },
- });
- jest
- .mocked(getTasksForComponent)
- .mockResolvedValueOnce({ queue: [] })
- .mockResolvedValue({
- queue: [{ status: TaskStatuses.InProgress, type: TaskTypes.Report }],
- } as unknown as Awaited<ReturnType<typeof getTasksForComponent>>);
-
- const mockedReplace = jest.fn();
- jest.spyOn(withRouter, 'useRouter').mockReturnValue({
- replace: mockedReplace,
- push: jest.fn(),
- navigate: jest.fn(),
- searchParams: new URLSearchParams(),
- setSearchParams: jest.fn(),
- });
-
- renderComponentContainer(
- { hasFeature: jest.fn().mockReturnValue(true) },
- `tutorials?id=${componentKey}`,
- '/',
- );
-
- jest.useFakeTimers();
-
- await waitFor(() => expect(getTasksForComponent).toHaveBeenCalledTimes(1));
- expect(mockedReplace).not.toHaveBeenCalled();
-
- // Since component.analysisDate is undefined we trigger setTimeout
- expect(jest.getTimerCount()).toBe(1);
- jest.runOnlyPendingTimers();
- expect(getTasksForComponent).toHaveBeenCalledTimes(2);
-
- // Since we have condition (component.analysisDate is undefined) that will lead to endless loop,
- // it is easier to enable realTimers to avoid act() warnings.
- jest.useRealTimers();
-
- // getTasksForComponent is called but not finished yet, so we need to wait for it to finish
- await waitFor(() => expect(mockedReplace).toHaveBeenCalledWith(getProjectUrl(componentKey)));
- });
-
- it('should redirect to project branch dashboard from tutorials when receiving new related scan report', async () => {
- const componentKey = 'foo-component';
- const branchName = 'fooBranch';
- jest.mocked(getComponentData).mockResolvedValue({
- ancestors: [],
- component: {
- key: componentKey,
- name: 'component name',
- qualifier: ComponentQualifier.Project,
- visibility: Visibility.Public,
- },
- });
- jest
- .mocked(getTasksForComponent)
- .mockResolvedValueOnce({ queue: [] })
- .mockResolvedValue({
- queue: [{ branch: branchName, status: TaskStatuses.InProgress, type: TaskTypes.Report }],
- } as unknown as Awaited<ReturnType<typeof getTasksForComponent>>);
-
- const mockedReplace = jest.fn();
- jest.spyOn(withRouter, 'useRouter').mockReturnValue({
- replace: mockedReplace,
- push: jest.fn(),
- navigate: jest.fn(),
- searchParams: new URLSearchParams(),
- setSearchParams: jest.fn(),
- });
-
- jest.useFakeTimers();
-
- renderComponentContainer(
- { hasFeature: jest.fn().mockReturnValue(true) },
- `tutorials?id=${componentKey}`,
- '/',
- );
-
- await waitFor(() => expect(getTasksForComponent).toHaveBeenCalledTimes(1));
- expect(mockedReplace).not.toHaveBeenCalled();
-
- // Since component.analysisDate is undefined we trigger setTimeout
- expect(jest.getTimerCount()).toBe(1);
- jest.runOnlyPendingTimers();
- expect(getTasksForComponent).toHaveBeenCalledTimes(2);
-
- // Since we have condition (component.analysisDate is undefined) that will lead to endless loop,
- // it is easier to enable realTimers to avoid act() warnings.
- jest.useRealTimers();
-
- // getTasksForComponent is called but not finished yet, so we need to wait for it to finish
- await waitFor(() =>
- expect(mockedReplace).toHaveBeenCalledWith(getProjectUrl(componentKey, branchName)),
- );
- });
-
- it('should redirect to project pull request dashboard from tutorials when receiving new related scan report', async () => {
- const componentKey = 'foo-component';
- const pullRequestKey = 'fooPR';
- jest.mocked(getComponentData).mockResolvedValue({
- ancestors: [],
- component: {
- key: componentKey,
- name: 'component name',
- qualifier: ComponentQualifier.Project,
- visibility: Visibility.Public,
- },
- });
- jest
- .mocked(getTasksForComponent)
- .mockResolvedValueOnce({ queue: [] })
- .mockResolvedValue({
- queue: [
- { pullRequest: pullRequestKey, status: TaskStatuses.InProgress, type: TaskTypes.Report },
- ],
- } as unknown as Awaited<ReturnType<typeof getTasksForComponent>>);
-
- const mockedReplace = jest.fn();
- jest.spyOn(withRouter, 'useRouter').mockReturnValue({
- replace: mockedReplace,
- push: jest.fn(),
- navigate: jest.fn(),
- searchParams: new URLSearchParams(),
- setSearchParams: jest.fn(),
- });
-
- jest.useFakeTimers();
-
- renderComponentContainer(
- { hasFeature: jest.fn().mockReturnValue(true) },
- `tutorials?id=${componentKey}`,
- '/',
- );
-
- await waitFor(() => expect(getTasksForComponent).toHaveBeenCalledTimes(1));
- expect(mockedReplace).not.toHaveBeenCalled();
-
- // Since component.analysisDate is undefined we trigger setTimeout
- expect(jest.getTimerCount()).toBe(1);
- jest.runOnlyPendingTimers();
- expect(getTasksForComponent).toHaveBeenCalledTimes(2);
-
- // Since we have condition (component.analysisDate is undefined) that will lead to endless loop,
- // it is easier to enable realTimers to avoid act() warnings.
- jest.useRealTimers();
-
- // getTasksForComponent is called but not finished yet, so we need to wait for it to finish
- await waitFor(() =>
- expect(mockedReplace).toHaveBeenCalledWith(getPullRequestUrl(componentKey, pullRequestKey)),
- );
- });
-});
-
-function renderComponentContainerAsComponent(props: Partial<WithAvailableFeaturesProps> = {}) {
- return renderComponent(
- <>
- <div id="component-nav-portal" />
- <ComponentContainer {...props} />
- </>,
- '/?id=foo',
- );
-}
-
-function renderComponentContainer(
- props: Partial<WithAvailableFeaturesProps> = {},
- navigateTo = '?id=foo',
- path = '/',
-) {
- renderAppRoutes(
- path,
- () => (
- <Route element={<ComponentContainer {...props} />}>
- <Route path="*" element={<TestComponent />} />
- <Route path="portfolio" element={<div>portfolio</div>} />
- <Route path="dashboard" element={<div>project</div>} />
- </Route>
- ),
- {
- navigateTo,
- },
- );
-}
-
-function TestComponent() {
- const { component, onComponentChange } = useContext(ComponentContext);
-
- return (
- <div>
- This is a test component
- <span>{component?.name}</span>
- <button
- onClick={() =>
- onComponentChange(
- mockComponent({
- name: 'new component name',
- breadcrumbs: [
- { key: 'portfolioKey', name: 'portfolio', qualifier: ComponentQualifier.Portfolio },
- ],
- }),
- )
- }
- type="button"
- >
- change component
- </button>
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainerNotFound-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainerNotFound-test.tsx
deleted file mode 100644
index a29e1904890..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainerNotFound-test.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import ComponentContainerNotFound from '../ComponentContainerNotFound';
-
-it('should render portfolio 404 correctly', () => {
- renderComponentContainerNotFound(true);
-
- expect(screen.getByText('dashboard.portfolio.not_found')).toBeInTheDocument();
- expect(screen.getByText('dashboard.portfolio.not_found.2')).toBeInTheDocument();
-});
-
-it('should render project 404 correctly', () => {
- renderComponentContainerNotFound(false);
-
- expect(screen.getByText('dashboard.project.not_found')).toBeInTheDocument();
- expect(screen.getByText('dashboard.project.not_found.2')).toBeInTheDocument();
-});
-
-function renderComponentContainerNotFound(isPortfolioLike: boolean) {
- return renderComponent(<ComponentContainerNotFound isPortfolioLike={isPortfolioLike} />);
-}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/DocumentationRedirect-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/DocumentationRedirect-test.tsx
deleted file mode 100644
index baaf4d89f6c..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/DocumentationRedirect-test.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { Route } from 'react-router-dom';
-import { mockAppState } from '../../../helpers/testMocks';
-import { renderAppRoutes } from '../../../helpers/testReactTestingUtils';
-import DocumentationRedirect from '../DocumentationRedirect';
-
-it('should redirect to static doc for specific version', async () => {
- renderDocumentationRedirect('land', '10.0');
-
- expect(await screen.findByRole('link')).toHaveAttribute(
- 'href',
- 'https://docs.sonarsource.com/sonarqube/10.0/land',
- );
-});
-
-function renderDocumentationRedirect(navigate: string, version?: string) {
- renderAppRoutes(
- `documentation/${navigate}`,
- () => <Route path="/documentation/*" element={<DocumentationRedirect />} />,
- { appState: mockAppState({ version }) },
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/FormattingHelp-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/FormattingHelp-test.tsx
deleted file mode 100644
index 0d0193fda67..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/FormattingHelp-test.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { byRole } from '~sonar-aligned/helpers/testSelector';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import FormattingHelp from '../FormattingHelp';
-
-it('should render correctly', () => {
- renderComponent(<FormattingHelp />);
-
- expect(byRole('row').getAll()).toHaveLength(10);
-});
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooter-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooter-test.tsx
deleted file mode 100644
index a00ba6c3d13..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooter-test.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { addDays, subDays } from 'date-fns';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { ModeServiceMock } from '../../../api/mocks/ModeServiceMock';
-import SystemServiceMock from '../../../api/mocks/SystemServiceMock';
-import { getEdition } from '../../../helpers/editions';
-import { mockAppState } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { AppState } from '../../../types/appstate';
-import { EditionKey } from '../../../types/editions';
-import { FCProps } from '../../../types/misc';
-import { Mode } from '../../../types/mode';
-import GlobalFooter from '../GlobalFooter';
-
-const systemMock = new SystemServiceMock();
-const modeHandler = new ModeServiceMock();
-
-const COMMUNITY = getEdition(EditionKey.community).name;
-
-afterEach(() => {
- modeHandler.reset();
- systemMock.reset();
-});
-
-it('should render the logged-in information', async () => {
- renderGlobalFooter({}, { edition: EditionKey.community });
-
- expect(ui.databaseWarningMessage.query()).not.toBeInTheDocument();
-
- expect(ui.footerListItems.getAll()).toHaveLength(8);
-
- expect(byText(COMMUNITY).get()).toBeInTheDocument();
- expect(await ui.versionLabel('4.2').find()).toBeInTheDocument();
- expect(ui.ltaDocumentationLinkActive.query()).not.toBeInTheDocument();
- expect(ui.apiLink.get()).toBeInTheDocument();
-});
-
-it('should render the inactive version and cleanup build number', async () => {
- systemMock.setSystemUpgrades({ installedVersionActive: false });
- renderGlobalFooter({}, { version: '4.2 (build 12345)' });
-
- expect(ui.versionLabel('4.2.12345').get()).toBeInTheDocument();
- expect(await ui.ltaDocumentationLinkInactive.find()).toBeInTheDocument();
-});
-
-it('should show active status if offline and did not reach EOL', async () => {
- systemMock.setSystemUpgrades({ installedVersionActive: undefined });
- renderGlobalFooter(
- {},
- { version: '4.2 (build 12345)', versionEOL: addDays(new Date(), 10).toISOString() },
- );
-
- expect(await ui.ltaDocumentationLinkActive.find()).toBeInTheDocument();
-});
-
-it('should show inactive status if offline and reached EOL', async () => {
- systemMock.setSystemUpgrades({ installedVersionActive: undefined });
- renderGlobalFooter(
- {},
- { version: '4.2 (build 12345)', versionEOL: subDays(new Date(), 10).toISOString() },
- );
-
- expect(await ui.ltaDocumentationLinkInactive.find()).toBeInTheDocument();
-});
-
-it.each([
- ['Standard', Mode.Standard, 'STANDARD'],
- ['MQR', Mode.MQR, 'MQR'],
-])('should show correct %s mode', async (_, mode, expected) => {
- modeHandler.setMode(mode);
- renderGlobalFooter();
-
- expect(await byText(`footer.mode.${expected}`).find()).toBeInTheDocument();
-});
-
-it('should not render missing logged-in information', () => {
- renderGlobalFooter({}, { edition: undefined, version: '' });
-
- expect(ui.footerListItems.getAll()).toHaveLength(5);
-
- expect(byText(COMMUNITY).query()).not.toBeInTheDocument();
- expect(ui.versionLabel().query()).not.toBeInTheDocument();
-});
-
-it('should not render the logged-in information', () => {
- renderGlobalFooter({ hideLoggedInInfo: true }, { edition: EditionKey.community });
-
- expect(ui.databaseWarningMessage.query()).not.toBeInTheDocument();
-
- expect(ui.footerListItems.getAll()).toHaveLength(4);
-
- expect(byText(COMMUNITY).query()).not.toBeInTheDocument();
- expect(ui.versionLabel().query()).not.toBeInTheDocument();
- expect(ui.apiLink.query()).not.toBeInTheDocument();
-});
-
-it('should show the db warning message', () => {
- renderGlobalFooter({}, { productionDatabase: false });
-
- expect(ui.databaseWarningMessage.get()).toBeInTheDocument();
-});
-
-function renderGlobalFooter(
- props: Partial<FCProps<typeof GlobalFooter>> = {},
- appStateOverride: Partial<AppState> = {},
-) {
- return renderComponent(<GlobalFooter {...props} />, '/', {
- appState: mockAppState({
- productionDatabase: true,
- edition: EditionKey.developer,
- version: '4.2',
- ...appStateOverride,
- }),
- });
-}
-
-const ui = {
- footerListItems: byRole('listitem'),
- databaseWarningMessage: byText('footer.production_database_warning'),
-
- versionLabel: (version?: string) =>
- version ? byText(/footer\.version\.short\.*(\d.\d)/) : byText(/footer\.version\.short/),
-
- // links
- websiteLink: byRole('link', { name: 'SonarQube™' }),
- companyLink: byRole('link', { name: 'SonarSource SA' }),
- licenseLink: byRole('link', { name: 'footer.license' }),
- communityLink: byRole('link', { name: 'footer.community' }),
- docsLink: byRole('link', { name: 'opens_in_new_window footer.documentation' }),
- pluginsLink: byRole('link', { name: 'opens_in_new_window footer.plugins' }),
- apiLink: byRole('link', { name: 'footer.web_api' }),
- ltaDocumentationLinkActive: byRole('link', {
- name: `footer.version.status.active`,
- }),
- ltaDocumentationLinkInactive: byRole('link', {
- name: `footer.version.status.inactive`,
- }),
-};
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/KeyboardShortcutsModal-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/KeyboardShortcutsModal-test.tsx
deleted file mode 100644
index 6a64ce4ca46..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/KeyboardShortcutsModal-test.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import { byRole } from '~sonar-aligned/helpers/testSelector';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import KeyboardShortcutsModal from '../KeyboardShortcutsModal';
-
-it('should render correctly', async () => {
- const user = userEvent.setup();
- renderKeyboardShortcutsModal();
-
- expect(ui.modalTitle.query()).not.toBeInTheDocument();
-
- await user.keyboard('?');
-
- expect(ui.modalTitle.get()).toBeInTheDocument();
-
- await user.click(ui.closeButton.get());
-
- expect(ui.modalTitle.query()).not.toBeInTheDocument();
-});
-
-it('should ignore other keydownes', async () => {
- const user = userEvent.setup();
- renderKeyboardShortcutsModal();
-
- await user.keyboard('!');
-
- expect(ui.modalTitle.query()).not.toBeInTheDocument();
-});
-
-it('should ignore events in an input', async () => {
- const user = userEvent.setup();
-
- renderKeyboardShortcutsModal();
-
- await user.click(ui.textInput.get());
- await user.keyboard('?');
-
- expect(ui.modalTitle.query()).not.toBeInTheDocument();
-});
-
-function renderKeyboardShortcutsModal() {
- return renderComponent(
- <>
- <KeyboardShortcutsModal />
- <input type="text" />
- </>,
- );
-}
-
-const ui = {
- modalTitle: byRole('heading', { name: 'keyboard_shortcuts_modal.title' }),
- closeButton: byRole('button', { name: 'close' }),
-
- textInput: byRole('textbox'),
-};
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/Landing-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/Landing-test.tsx
deleted file mode 100644
index 5cb372177db..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/Landing-test.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { byText } from '~sonar-aligned/helpers/testSelector';
-import { mockCurrentUser, mockLoggedInUser } from '../../../helpers/testMocks';
-import { renderApp } from '../../../helpers/testReactTestingUtils';
-import { CurrentUser } from '../../../types/users';
-import { Landing, LandingProps } from '../Landing';
-
-it.each([
- ['user not logged in', mockCurrentUser()],
- ['user has no homepage', mockLoggedInUser({ homepage: undefined })],
-])('should redirect to projects (%s)', (_, currentUser: CurrentUser) => {
- renderLanding({ currentUser });
- expect(byText('/projects').get()).toBeInTheDocument();
-});
-
-it('should redirect to homepage', () => {
- renderLanding({
- currentUser: mockLoggedInUser({
- homepage: { type: 'PROJECT', branch: undefined, component: 'pk1' },
- }),
- });
- expect(byText('/dashboard?id=pk1').get()).toBeInTheDocument();
-});
-
-function renderLanding(props: Partial<LandingProps> = {}) {
- return renderApp('/', <Landing currentUser={mockCurrentUser()} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/MigrationContainer-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/MigrationContainer-test.tsx
deleted file mode 100644
index 44197a385c7..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/MigrationContainer-test.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Route } from 'react-router-dom';
-import { byText } from '~sonar-aligned/helpers/testSelector';
-import { getSystemStatus } from '../../../helpers/system';
-import { renderAppRoutes } from '../../../helpers/testReactTestingUtils';
-import MigrationContainer from '../MigrationContainer';
-
-jest.mock('../../../helpers/system', () => ({
- getSystemStatus: jest.fn(),
-}));
-
-const originalLocation = window.location;
-
-beforeAll(() => {
- const location = {
- pathname: '/projects',
- search: '?query=toto',
- hash: '#hash',
- };
- Object.defineProperty(window, 'location', {
- writable: true,
- value: location,
- });
-});
-
-afterAll(() => {
- Object.defineProperty(window, 'location', {
- writable: true,
- value: originalLocation,
- });
-});
-
-it('should render correctly if system is up', () => {
- (getSystemStatus as jest.Mock).mockReturnValueOnce('UP');
-
- renderMigrationContainer();
-
- expect(byText('children').get()).toBeInTheDocument();
-});
-
-it('should render correctly if system is starting', () => {
- (getSystemStatus as jest.Mock).mockReturnValueOnce('STARTING');
-
- renderMigrationContainer();
-
- expect(
- byText('/maintenance?return_to=%2Fprojects%3Fquery%3Dtoto%23hash').get(),
- ).toBeInTheDocument();
-});
-
-function renderMigrationContainer() {
- return renderAppRoutes('/', () => (
- <Route element={<MigrationContainer />}>
- <Route index element={<div>children</div>} />
- </Route>
- ));
-}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/ModeTour-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/ModeTour-test.tsx
deleted file mode 100644
index a5767acc77a..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/ModeTour-test.tsx
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import { ModeServiceMock } from '../../../api/mocks/ModeServiceMock';
-import SettingsServiceMock from '../../../api/mocks/SettingsServiceMock';
-import UsersServiceMock from '../../../api/mocks/UsersServiceMock';
-import { mockAppState, mockCurrentUser, mockLocation } from '../../../helpers/testMocks';
-import { renderApp } from '../../../helpers/testReactTestingUtils';
-import { byRole } from '../../../sonar-aligned/helpers/testSelector';
-import { Permissions } from '../../../types/permissions';
-import { NoticeType } from '../../../types/users';
-import ModeTour from '../ModeTour';
-import GlobalNav from '../nav/global/GlobalNav';
-
-const ui = {
- dialog: byRole('dialog'),
- step1Dialog: byRole('dialog', { name: /mode_tour.step1.title/ }),
- step2Dialog: byRole('dialog', { name: /mode_tour.step2.title/ }),
- step3Dialog: byRole('dialog', { name: /mode_tour.step3.title/ }),
- step4Dialog: byRole('dialog', { name: /mode_tour.step4.title/ }),
- next: byRole('button', { name: 'next' }),
- later: byRole('button', { name: 'later' }),
- close: byRole('button', { name: 'modal.close' }),
- skip: byRole('button', { name: 'skip' }),
- letsgo: byRole('button', { name: 'lets_go' }),
- gotit: byRole('button', { name: 'got_it' }),
- help: byRole('button', { name: 'help' }),
- guidePopup: byRole('alertdialog'),
- tourTrigger: byRole('menuitem', { name: 'mode_tour.name' }),
-};
-
-const settingsHandler = new SettingsServiceMock();
-const modeHandler = new ModeServiceMock();
-const usersHandler = new UsersServiceMock();
-
-beforeEach(() => {
- settingsHandler.reset();
- modeHandler.reset();
- usersHandler.reset();
-});
-
-it('renders the tour for admin', async () => {
- const user = userEvent.setup();
- renderGlobalNav(mockCurrentUser({ permissions: { global: [Permissions.Admin] } }));
- expect(ui.step1Dialog.get()).toBeInTheDocument();
- expect(ui.later.get()).toBeInTheDocument();
- expect(ui.next.query()).not.toBeInTheDocument();
- expect(ui.letsgo.get()).toBeInTheDocument();
- expect(ui.step1Dialog.get()).toHaveTextContent('guiding.step_x_of_y.1.4');
- await user.click(ui.letsgo.get());
-
- expect(ui.step2Dialog.get()).toBeInTheDocument();
- expect(ui.step1Dialog.query()).not.toBeInTheDocument();
- expect(ui.later.query()).not.toBeInTheDocument();
- expect(ui.next.get()).toBeInTheDocument();
- expect(ui.letsgo.query()).not.toBeInTheDocument();
- expect(ui.step2Dialog.get()).toHaveTextContent('guiding.step_x_of_y.2.4');
- await user.click(ui.next.get());
-
- expect(ui.step3Dialog.get()).toBeInTheDocument();
- expect(ui.step2Dialog.query()).not.toBeInTheDocument();
- expect(ui.next.get()).toBeInTheDocument();
- expect(ui.step3Dialog.get()).toHaveTextContent('guiding.step_x_of_y.3.4');
- await user.click(ui.next.get());
-
- expect(ui.dialog.query()).not.toBeInTheDocument();
- expect(await ui.guidePopup.find()).toBeInTheDocument();
- expect(ui.guidePopup.get()).toHaveTextContent('guiding.step_x_of_y.4.4');
- expect(ui.guidePopup.by(ui.next).get()).toBeInTheDocument();
- expect(ui.tourTrigger.query()).not.toBeInTheDocument();
- await user.click(ui.next.get());
-
- expect(ui.tourTrigger.get()).toBeInTheDocument();
- expect(await ui.guidePopup.find()).toBeInTheDocument();
- expect(ui.guidePopup.query()).not.toHaveTextContent('guiding.step_x_of_y');
- expect(ui.next.query()).not.toBeInTheDocument();
- expect(ui.skip.get()).toBeInTheDocument();
- expect(ui.gotit.get()).toBeInTheDocument();
- await user.click(ui.skip.get());
-
- expect(ui.tourTrigger.query()).not.toBeInTheDocument();
- expect(ui.dialog.query()).not.toBeInTheDocument();
-
- // replay the tour
- await user.click(ui.help.get());
- await user.click(ui.tourTrigger.get());
- expect(ui.step1Dialog.get()).toBeInTheDocument();
- expect(ui.step1Dialog.get()).toHaveTextContent('guiding.step_x_of_y.1.4');
-});
-
-it('renders the tour for gateadmins', async () => {
- const user = userEvent.setup();
- renderGlobalNav(mockCurrentUser({ permissions: { global: [Permissions.QualityGateAdmin] } }));
- expect(ui.step1Dialog.get()).toBeInTheDocument();
- expect(ui.later.get()).toBeInTheDocument();
- expect(ui.next.query()).not.toBeInTheDocument();
- expect(ui.letsgo.get()).toBeInTheDocument();
- expect(ui.step1Dialog.get()).toHaveTextContent('guiding.step_x_of_y.1.4');
- await user.click(ui.letsgo.get());
-
- expect(ui.step2Dialog.get()).toBeInTheDocument();
- expect(ui.step1Dialog.query()).not.toBeInTheDocument();
- expect(ui.later.query()).not.toBeInTheDocument();
- expect(ui.next.get()).toBeInTheDocument();
- expect(ui.letsgo.query()).not.toBeInTheDocument();
- expect(ui.step2Dialog.get()).toHaveTextContent('guiding.step_x_of_y.2.4');
- await user.click(ui.next.get());
-
- expect(ui.step3Dialog.get()).toBeInTheDocument();
- expect(ui.step2Dialog.query()).not.toBeInTheDocument();
- expect(ui.next.get()).toBeInTheDocument();
- expect(ui.step3Dialog.get()).toHaveTextContent('guiding.step_x_of_y.3.4');
- await user.click(ui.next.get());
-
- expect(ui.step4Dialog.get()).toBeInTheDocument();
- expect(ui.step3Dialog.query()).not.toBeInTheDocument();
- expect(ui.next.get()).toBeInTheDocument();
- expect(ui.step4Dialog.get()).toHaveTextContent('guiding.step_x_of_y.4.4');
- await user.click(ui.next.get());
-
- expect(ui.dialog.query()).not.toBeInTheDocument();
- expect(ui.tourTrigger.get()).toBeInTheDocument();
- expect(await ui.guidePopup.find()).toBeInTheDocument();
- expect(ui.guidePopup.query()).not.toHaveTextContent('guiding.step_x_of_y');
- expect(ui.next.query()).not.toBeInTheDocument();
- expect(ui.skip.get()).toBeInTheDocument();
- expect(ui.gotit.get()).toBeInTheDocument();
- await user.click(ui.gotit.get());
-
- expect(ui.tourTrigger.query()).not.toBeInTheDocument();
- expect(ui.dialog.query()).not.toBeInTheDocument();
-
- // replay the tour
- await user.click(ui.help.get());
- await user.click(ui.tourTrigger.get());
- expect(ui.step1Dialog.get()).toBeInTheDocument();
- expect(ui.step1Dialog.get()).toHaveTextContent('guiding.step_x_of_y.1.4');
-});
-
-it('should highlight the replay button on "later"', async () => {
- const user = userEvent.setup();
- renderGlobalNav(mockCurrentUser({ permissions: { global: [Permissions.Admin] } }));
- expect(await ui.dialog.find()).toBeInTheDocument();
- await user.click(ui.later.get());
-
- expect(ui.dialog.query()).not.toBeInTheDocument();
- expect(ui.tourTrigger.get()).toBeInTheDocument();
- expect(await ui.guidePopup.find()).toBeInTheDocument();
- expect(ui.skip.get()).toBeInTheDocument();
- await user.click(ui.skip.get());
-});
-
-it('should highlight the replay button on closing the dialog', async () => {
- const user = userEvent.setup();
- renderGlobalNav(mockCurrentUser({ permissions: { global: [Permissions.Admin] } }));
- expect(await ui.dialog.find()).toBeInTheDocument();
- await user.click(ui.close.get());
-
- expect(ui.dialog.query()).not.toBeInTheDocument();
- expect(ui.tourTrigger.get()).toBeInTheDocument();
- expect(await ui.guidePopup.find()).toBeInTheDocument();
- expect(ui.skip.get()).toBeInTheDocument();
- expect(ui.gotit.get()).toBeInTheDocument();
- // Closing the help menu dismisses the tour as well
- await user.click(ui.help.get());
-
- expect(ui.guidePopup.query()).not.toBeInTheDocument();
-});
-
-it('should not render the tour for regular users', async () => {
- const user = userEvent.setup();
- renderGlobalNav(mockCurrentUser({ permissions: { global: [] } }));
- expect(ui.dialog.query()).not.toBeInTheDocument();
- await user.click(ui.help.get());
- expect(ui.tourTrigger.query()).not.toBeInTheDocument();
-});
-
-it('should not render the tour if it is already dismissed', async () => {
- const user = userEvent.setup();
- renderGlobalNav(
- mockCurrentUser({
- permissions: { global: [Permissions.Admin] },
- dismissedNotices: { [NoticeType.MODE_TOUR]: true },
- }),
- );
- expect(ui.dialog.query()).not.toBeInTheDocument();
- await user.click(ui.help.get());
- expect(ui.tourTrigger.get()).toBeInTheDocument();
-
- await user.click(ui.tourTrigger.get());
- expect(ui.step1Dialog.get()).toBeInTheDocument();
- expect(ui.step1Dialog.get()).toHaveTextContent('guiding.step_x_of_y.1.4');
-});
-
-function renderGlobalNav(currentUser = mockCurrentUser()) {
- renderApp(
- '/',
- <>
- <GlobalNav location={mockLocation()} />
- <ModeTour />
- </>,
- {
- currentUser,
- appState: mockAppState({ canAdmin: currentUser.permissions?.global.includes('admin') }),
- },
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/NonAdminPagesContainer-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/NonAdminPagesContainer-test.tsx
deleted file mode 100644
index 4e4e73d12ba..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/NonAdminPagesContainer-test.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render, screen } from '@testing-library/react';
-import { MemoryRouter, Route, Routes } from 'react-router-dom';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { mockComponent } from '../../../helpers/mocks/component';
-import { ComponentContextShape } from '../../../types/component';
-import { Component } from '../../../types/types';
-import NonAdminPagesContainer from '../NonAdminPagesContainer';
-import { ComponentContext } from '../componentContext/ComponentContext';
-
-function Child() {
- return <div>Test Child</div>;
-}
-
-it('should render correctly for an user that does not have access to all children', () => {
- renderNonAdminPagesContainer(
- mockComponent({ qualifier: ComponentQualifier.Application, canBrowseAllChildProjects: false }),
- );
- expect(screen.getByText(/^application.cannot_access_all_child_projects1/)).toBeInTheDocument();
-});
-
-it('should render correctly', () => {
- renderNonAdminPagesContainer(mockComponent());
- expect(screen.getByText('Test Child')).toBeInTheDocument();
-});
-
-function renderNonAdminPagesContainer(component: Component) {
- return render(
- <ComponentContext.Provider value={{ component } as ComponentContextShape}>
- <MemoryRouter>
- <Routes>
- <Route element={<NonAdminPagesContainer />}>
- <Route path="*" element={<Child />} />
- </Route>
- </Routes>
- </MemoryRouter>
- </ComponentContext.Provider>,
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/PageTracker-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/PageTracker-test.tsx
deleted file mode 100644
index 3dd4ff44f6d..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/PageTracker-test.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import * as React from 'react';
-import { Link } from 'react-router-dom';
-import { byRole } from '~sonar-aligned/helpers/testSelector';
-import { installScript } from '../../../helpers/extensions';
-import { getWebAnalyticsPageHandlerFromCache } from '../../../helpers/extensionsHandler';
-import { mockAppState } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import PageTracker from '../PageTracker';
-
-jest.mock('../../../helpers/extensions', () => ({
- installScript: jest.fn().mockResolvedValue({}),
-}));
-
-jest.mock('../../../helpers/extensionsHandler', () => ({
- getWebAnalyticsPageHandlerFromCache: jest.fn().mockReturnValue(undefined),
-}));
-
-beforeEach(() => {
- jest.clearAllMocks();
- jest.useFakeTimers();
-});
-
-afterEach(() => {
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
-});
-
-it('should not trigger if no analytics system is given', () => {
- renderPageTracker();
-
- expect(installScript).not.toHaveBeenCalled();
-});
-
-it('should work for WebAnalytics plugin', async () => {
- const user = userEvent.setup({ delay: null });
- const pageChange = jest.fn();
- const webAnalyticsJsPath = '/static/pluginKey/web_analytics.js';
- renderPageTracker(mockAppState({ webAnalyticsJsPath }));
-
- expect(installScript).toHaveBeenCalledWith(webAnalyticsJsPath, 'head');
-
- jest.mocked(getWebAnalyticsPageHandlerFromCache).mockClear().mockReturnValueOnce(pageChange);
-
- // trigger trackPage
- await user.click(byRole('link').get());
-
- jest.runAllTimers();
- expect(pageChange).toHaveBeenCalledWith('/newpath');
-});
-
-function renderPageTracker(appState = mockAppState()) {
- return renderComponent(<WrappingComponent />, '', { appState });
-}
-
-function WrappingComponent() {
- const [metatag, setmetatag] = React.useState<React.ReactNode>(null);
-
- return (
- <>
- <PageTracker>{metatag}</PageTracker>
- <Link to="newpath" onClick={() => setmetatag(<meta name="toto" />)}>
- trigger change
- </Link>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/PluginRiskConsent-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/PluginRiskConsent-test.tsx
deleted file mode 100644
index e2a31181693..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/PluginRiskConsent-test.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import { setImmediate } from 'timers';
-import { byRole } from '~sonar-aligned/helpers/testSelector';
-import { setSimpleSettingValue } from '../../../api/settings';
-import { mockLoggedInUser, mockRouter } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { PluginRiskConsent, PluginRiskConsentProps } from '../PluginRiskConsent';
-
-jest.mock('../../../api/settings', () => ({
- setSimpleSettingValue: jest.fn().mockResolvedValue({}),
-}));
-
-jest.mock('react', () => {
- return {
- ...jest.requireActual('react'),
- useEffect: jest.fn().mockImplementation((f) => f()),
- };
-});
-
-const originalLocation = window.location;
-
-beforeAll(() => {
- let href = '';
- const location = {
- ...window.location,
- get href() {
- return href;
- },
- set href(v: string) {
- href = v;
- },
- };
- Object.defineProperty(window, 'location', {
- writable: true,
- value: location,
- });
-});
-
-afterAll(() => {
- jest.clearAllMocks();
-
- Object.defineProperty(window, 'location', {
- writable: true,
- value: originalLocation,
- });
-});
-
-it('should redirect non-admin users', () => {
- const replace = jest.fn();
- renderPluginRiskConsent({
- currentUser: mockLoggedInUser(),
- router: mockRouter({ replace }),
- });
- expect(replace).toHaveBeenCalled();
-});
-
-it('should handle acknowledgement and redirect', async () => {
- const user = userEvent.setup();
- renderPluginRiskConsent();
-
- await user.click(ui.acknowledgeButton.get());
-
- await new Promise(setImmediate);
-
- expect(setSimpleSettingValue).toHaveBeenCalled();
- expect(window.location.href).toBe('/');
-});
-
-function renderPluginRiskConsent(props: Partial<PluginRiskConsentProps> = {}) {
- return renderComponent(
- <PluginRiskConsent
- currentUser={mockLoggedInUser({ permissions: { global: ['admin'] } })}
- router={mockRouter()}
- {...props}
- />,
- );
-}
-
-const ui = {
- acknowledgeButton: byRole('button', { name: 'plugin_risk_consent.action' }),
-};
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/ProjectAdminContainer-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/ProjectAdminContainer-test.tsx
deleted file mode 100644
index 4bbfd713e60..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/ProjectAdminContainer-test.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Route } from 'react-router-dom';
-import { byText } from '~sonar-aligned/helpers/testSelector';
-import handleRequiredAuthorization from '../../../app/utils/handleRequiredAuthorization';
-import { mockComponent } from '../../../helpers/mocks/component';
-import { renderAppRoutes } from '../../../helpers/testReactTestingUtils';
-import { ProjectAdminContainer } from '../ProjectAdminContainer';
-
-jest.mock('../../utils/handleRequiredAuthorization', () => {
- return jest.fn();
-});
-
-it('should render correctly', () => {
- renderProjectAdminContainer();
-
- expect(byText('children').get()).toBeInTheDocument();
-});
-
-it('should redirect for authorization if needed', () => {
- jest.useFakeTimers();
- renderProjectAdminContainer({
- component: mockComponent({ configuration: { showSettings: false } }),
- });
- jest.runAllTimers();
- expect(handleRequiredAuthorization).toHaveBeenCalled();
- jest.useRealTimers();
-});
-
-function renderProjectAdminContainer(props: Partial<ProjectAdminContainer['props']> = {}) {
- return renderAppRoutes('project/settings', () => (
- <Route
- path="project/settings"
- element={
- <ProjectAdminContainer
- component={mockComponent({ configuration: { showSettings: true } })}
- {...props}
- />
- }
- >
- <Route index element={<div>children</div>} />
- </Route>
- ));
-}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/RecentHistory-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/RecentHistory-test.tsx
deleted file mode 100644
index a9b491812f7..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/RecentHistory-test.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { get, remove, save } from '../../../helpers/storage';
-import RecentHistory, { History } from '../RecentHistory';
-
-jest.mock('../../../helpers/storage', () => ({
- get: jest.fn(),
- remove: jest.fn(),
- save: jest.fn(),
-}));
-
-beforeEach(() => {
- jest.mocked(get).mockClear();
- jest.mocked(remove).mockClear();
- jest.mocked(save).mockClear();
-});
-
-it('should get existing history', () => {
- const history = [{ key: 'foo', name: 'Foo', icon: ComponentQualifier.Project }];
- jest.mocked(get).mockReturnValueOnce(JSON.stringify(history));
- expect(RecentHistory.get()).toEqual(history);
- expect(get).toHaveBeenCalledWith('sonar_recent_history');
-});
-
-it('should get empty history', () => {
- jest.mocked(get).mockReturnValueOnce(null);
- expect(RecentHistory.get()).toEqual([]);
- expect(get).toHaveBeenCalledWith('sonar_recent_history');
-});
-
-it('should return [] and clear history in case of failure', () => {
- jest.mocked(get).mockReturnValueOnce('not a json');
- expect(RecentHistory.get()).toEqual([]);
- expect(get).toHaveBeenCalledWith('sonar_recent_history');
- expect(remove).toHaveBeenCalledWith('sonar_recent_history');
-});
-
-it('should save history', () => {
- const history = [{ key: 'foo', name: 'Foo', icon: ComponentQualifier.Project }];
- RecentHistory.set(history);
- expect(save).toHaveBeenCalledWith('sonar_recent_history', JSON.stringify(history));
-});
-
-it('should clear history', () => {
- RecentHistory.clear();
- expect(remove).toHaveBeenCalledWith('sonar_recent_history');
-});
-
-it('should add item to history', () => {
- const history = [{ key: 'foo', name: 'Foo', icon: ComponentQualifier.Project }];
- jest.mocked(get).mockReturnValueOnce(JSON.stringify(history));
- RecentHistory.add('bar', 'Bar', ComponentQualifier.Portfolio);
- expect(save).toHaveBeenCalledWith(
- 'sonar_recent_history',
- JSON.stringify([{ key: 'bar', name: 'Bar', icon: ComponentQualifier.Portfolio }, ...history]),
- );
-});
-
-it('should keep 10 items maximum', () => {
- const history: History = [];
- for (let i = 0; i < 10; i++) {
- history.push({ key: `key-${i}`, name: `name-${i}`, icon: ComponentQualifier.Project });
- }
- jest.mocked(get).mockReturnValueOnce(JSON.stringify(history));
- RecentHistory.add('bar', 'Bar', ComponentQualifier.Portfolio);
- expect(save).toHaveBeenCalledWith(
- 'sonar_recent_history',
- JSON.stringify([
- { key: 'bar', name: 'Bar', icon: ComponentQualifier.Portfolio },
- ...history.slice(0, 9),
- ]),
- );
-});
-
-it('should remove component from history', () => {
- const history: History = [];
- for (let i = 0; i < 10; i++) {
- history.push({ key: `key-${i}`, name: `name-${i}`, icon: ComponentQualifier.Project });
- }
- jest.mocked(get).mockReturnValueOnce(JSON.stringify(history));
- RecentHistory.remove('key-5');
- expect(save).toHaveBeenCalledWith(
- 'sonar_recent_history',
- JSON.stringify([...history.slice(0, 5), ...history.slice(6)]),
- );
-});
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/ResetPassword-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/ResetPassword-test.tsx
deleted file mode 100644
index c4697b5cb77..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/ResetPassword-test.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import { byLabelText, byRole } from '~sonar-aligned/helpers/testSelector';
-import { mockLoggedInUser } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { ResetPassword, ResetPasswordProps } from '../ResetPassword';
-
-jest.mock('../../../helpers/system', () => ({
- getBaseUrl: jest.fn().mockReturnValue('/context'),
-}));
-
-jest.mock('../../../api/users', () => ({
- changePassword: jest.fn().mockResolvedValue(true),
-}));
-
-const originalLocation = window.location;
-
-beforeAll(() => {
- const location = {
- ...window.location,
- href: null,
- };
- Object.defineProperty(window, 'location', {
- writable: true,
- value: location,
- });
-});
-
-afterAll(() => {
- Object.defineProperty(window, 'location', {
- writable: true,
- value: originalLocation,
- });
-});
-
-/*
- * Note: the form itself is also used in the context of the account page
- * and is tested there as well (i.e. Account-it.tsx)
- */
-it('should navigate to the homepage after submission', async () => {
- const user = userEvent.setup();
- renderResetPassword();
-
- // Make password strong
- await user.type(ui.oldPasswordInput.get(), '1234');
- await user.type(ui.passwordInput.get(), 'P@ssword12345');
- await user.type(ui.passwordConfirmationInput.get(), 'P@ssword12345');
-
- await user.click(ui.submitButton.get());
-
- expect(window.location.href).toBe('/context/');
-});
-
-function renderResetPassword(props: Partial<ResetPasswordProps> = {}) {
- return renderComponent(<ResetPassword currentUser={mockLoggedInUser()} {...props} />);
-}
-
-const ui = {
- oldPasswordInput: byLabelText(/my_profile\.password\.old/),
- passwordInput: byLabelText(/^password/),
- passwordConfirmationInput: byLabelText(/confirm_password\*/i),
- submitButton: byRole('button', { name: 'update_verb' }),
-};
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/SonarLintConnection-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/SonarLintConnection-test.tsx
deleted file mode 100644
index 09466e24fdb..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/SonarLintConnection-test.tsx
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import UserTokensMock from '../../../api/mocks/UserTokensMock';
-import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication';
-import { sendUserToken } from '../../../helpers/sonarlint';
-import { mockCurrentUser, mockLoggedInUser } from '../../../helpers/testMocks';
-import { renderApp } from '../../../helpers/testReactTestingUtils';
-import { CurrentUser } from '../../../types/users';
-import SonarLintConnection from '../SonarLintConnection';
-
-jest.mock('../../../helpers/handleRequiredAuthentication', () => ({
- __esModule: true,
- default: jest.fn(),
-}));
-
-jest.mock('../../../helpers/sonarlint', () => {
- const original = jest.requireActual('../../../helpers/sonarlint');
- return { ...original, sendUserToken: jest.fn() };
-});
-
-let tokenMock: UserTokensMock;
-
-beforeAll(() => {
- tokenMock = new UserTokensMock();
-});
-
-afterEach(() => {
- tokenMock.reset();
-});
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
-
-jest.mock('../../../api/settings', () => {
- const { SettingsKey } = jest.requireActual('../../../types/settings');
- return {
- ...jest.requireActual('../../../api/settings'),
- getAllValues: jest.fn().mockResolvedValue([
- {
- key: SettingsKey.TokenMaxAllowedLifetime,
- value: 'No expiration',
- },
- ]),
- };
-});
-
-it('should allow the user to accept the binding request', async () => {
- (sendUserToken as jest.Mock).mockReturnValueOnce({});
-
- const user = userEvent.setup();
- renderSonarLintConnection();
-
- expect(
- await screen.findByRole('heading', { name: 'sonarlint-connection.request.title' }),
- ).toBeInTheDocument();
-
- await user.click(screen.getByRole('button', { name: 'sonarlint-connection.request.action' }));
-
- expect(
- await screen.findByText('sonarlint-connection.success.description', { exact: false }),
- ).toBeInTheDocument();
-});
-
-it('should handle token generation errors', async () => {
- tokenMock.failNextTokenGeneration();
-
- const user = userEvent.setup();
- renderSonarLintConnection();
-
- await user.click(
- await screen.findByRole('button', { name: 'sonarlint-connection.request.action' }),
- );
-
- expect(
- await screen.findByText('sonarlint-connection.token-error.description'),
- ).toBeInTheDocument();
-});
-
-it('should handle connection errors', async () => {
- (sendUserToken as jest.Mock).mockRejectedValueOnce(new Error(''));
-
- const user = userEvent.setup();
- renderSonarLintConnection();
-
- await user.click(
- await screen.findByRole('button', { name: 'sonarlint-connection.request.action' }),
- );
-
- expect(
- await screen.findByText('sonarlint-connection.connection-error.description'),
- ).toBeInTheDocument();
-
- const tokenValue = tokenMock.getLastToken()?.token ?? '';
- expect(await screen.findByRole('textbox')).toHaveValue(tokenValue);
-});
-
-it('should require authentication if user is not logged in', () => {
- renderSonarLintConnection({ currentUser: mockCurrentUser() });
-
- expect(handleRequiredAuthentication).toHaveBeenCalled();
-});
-
-it('should let the user copy the token if the port is not valid', async () => {
- const user = userEvent.setup();
-
- renderSonarLintConnection({ port: '' });
-
- await user.click(
- await screen.findByRole('button', { name: 'sonarlint-connection.request.action' }),
- );
-
- expect(
- await screen.findByText('sonarlint-connection.connection-error.description'),
- ).toBeInTheDocument();
-});
-
-function renderSonarLintConnection(overrides: { currentUser?: CurrentUser; port?: string } = {}) {
- const { currentUser, port } = {
- currentUser: mockLoggedInUser(),
- port: '64120',
- ...overrides,
- };
-
- const searchParams = new URLSearchParams();
-
- if (port) {
- searchParams.set('port', port);
- }
-
- renderApp('sonarlint/auth', <SonarLintConnection />, {
- currentUser,
- navigateTo: `sonarlint/auth?${searchParams.toString()}`,
- });
-}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx
deleted file mode 100644
index 7a80d674f83..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { showLicense } from '../../../api/editions';
-import { getEdition } from '../../../helpers/editions';
-import { save } from '../../../helpers/storage';
-import { mockAppState, mockCurrentUser } from '../../../helpers/testMocks';
-import { renderApp } from '../../../helpers/testReactTestingUtils';
-import { EditionKey } from '../../../types/editions';
-import { LoggedInUser } from '../../../types/users';
-import { StartupModal } from '../StartupModal';
-
-jest.mock('../../../api/editions', () => ({
- showLicense: jest.fn().mockResolvedValue(undefined),
-}));
-
-jest.mock('../../../helpers/storage', () => ({
- get: jest.fn(),
- save: jest.fn(),
-}));
-
-jest.mock('../../../helpers/dates', () => ({
- parseDate: jest.fn().mockReturnValue('parsed-date'),
- toShortISO8601String: jest.fn().mockReturnValue('short-not-iso-date'),
-}));
-
-jest.mock('date-fns', () => ({
- ...jest.requireActual('date-fns'),
- differenceInDays: jest.fn().mockReturnValue(1),
-}));
-
-const LOGGED_IN_USER: LoggedInUser = {
- groups: [],
- isLoggedIn: true,
- login: 'luke',
- name: 'Skywalker',
- scmAccounts: [],
- dismissedNotices: {},
-};
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
-
-it('should check license and open on its own', async () => {
- const user = userEvent.setup();
- renderStartupModal();
-
- expect(await ui.modalHeader.find()).toBeInTheDocument();
- expect(save).toHaveBeenCalled();
-
- await user.click(ui.licensePageLink.get());
-
- expect(byText('/admin/extension/license/app').get()).toBeInTheDocument();
-});
-
-it.each([
- [
- getEdition(EditionKey.community).name,
- { appState: mockAppState({ canAdmin: true, edition: EditionKey.community }) },
- ],
- ['Cannot admin', { appState: mockAppState({ canAdmin: false, edition: EditionKey.enterprise }) }],
- ['User is not logged in', { currentUser: mockCurrentUser() }],
-])('should not open when not necessary: %s', (_, props: Partial<StartupModal['props']>) => {
- renderStartupModal(props);
-
- expect(showLicense).not.toHaveBeenCalled();
-
- expect(save).not.toHaveBeenCalled();
- expect(ui.modalHeader.query()).not.toBeInTheDocument();
-});
-
-function renderStartupModal(props: Partial<StartupModal['props']> = {}) {
- return renderApp(
- '/',
- <StartupModal
- appState={mockAppState({ edition: EditionKey.enterprise, canAdmin: true })}
- currentUser={LOGGED_IN_USER}
- {...props}
- >
- <div />
- </StartupModal>,
- );
-}
-
-const ui = {
- modalHeader: byRole('heading', { name: 'license.prompt.title' }),
- licensePageLink: byRole('link', { name: 'license.prompt.link' }),
- modalCancelButton: byRole('button', { name: 'cancel' }),
-};
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/SystemAnnouncement-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/SystemAnnouncement-test.tsx
deleted file mode 100644
index 5fd8f62c631..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/SystemAnnouncement-test.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { fireEvent, screen } from '@testing-library/react';
-import { getValues } from '../../../api/settings';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { Feature } from '../../../types/features';
-import SystemAnnouncement from '../SystemAnnouncement';
-import { AvailableFeaturesContext } from '../available-features/AvailableFeaturesContext';
-
-jest.mock('../../../api/settings', () => ({
- getValues: jest.fn(),
-}));
-
-jest.mock('lodash', () => {
- const lodash = jest.requireActual('lodash');
- lodash.throttle = (fn: any) => () => fn();
- return lodash;
-});
-
-it('should display system announcement', async () => {
- jest
- .mocked(getValues)
- .mockResolvedValueOnce([
- {
- key: 'sonar.announcement.displayMessage',
- value: 'false',
- inherited: true,
- },
- ])
- .mockResolvedValueOnce([
- {
- key: 'sonar.announcement.displayMessage',
- value: 'false',
- inherited: true,
- },
- ])
- .mockResolvedValueOnce([
- {
- key: 'sonar.announcement.displayMessage',
- value: 'true',
- },
- ])
- .mockResolvedValueOnce([
- {
- key: 'sonar.announcement.displayMessage',
- value: 'true',
- },
- {
- key: 'sonar.announcement.message',
- value: '',
- },
- ])
- .mockResolvedValueOnce([
- {
- key: 'sonar.announcement.displayMessage',
- value: 'true',
- },
- {
- key: 'sonar.announcement.message',
- value: 'Foo',
- },
- ]);
-
- renderSystemAnnouncement();
-
- expect(screen.queryByRole('alert')).not.toBeInTheDocument();
- fireEvent(window, new Event('focus'));
- expect(screen.queryByRole('alert')).not.toBeInTheDocument();
- fireEvent(window, new Event('focus'));
- expect(screen.queryByRole('alert')).not.toBeInTheDocument();
- fireEvent(window, new Event('focus'));
- expect(screen.queryByRole('alert')).not.toBeInTheDocument();
- fireEvent(window, new Event('focus'));
- expect(await screen.findByRole('alert')).toBeInTheDocument();
- expect(screen.getByText('Foo')).toBeInTheDocument();
-});
-
-function renderSystemAnnouncement() {
- return renderComponent(
- <AvailableFeaturesContext.Provider value={[Feature.Announcement]}>
- <SystemAnnouncement />
- </AvailableFeaturesContext.Provider>,
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/UpdateNotification-it.tsx b/server/sonar-web/src/main/js/app/components/__tests__/UpdateNotification-it.tsx
deleted file mode 100644
index 6ef0cf9ece1..00000000000
--- a/server/sonar-web/src/main/js/app/components/__tests__/UpdateNotification-it.tsx
+++ /dev/null
@@ -1,637 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { addDays, formatISO, subDays } from 'date-fns';
-import { byRole } from '~sonar-aligned/helpers/testSelector';
-import { getSystemUpgrades } from '../../../api/system';
-import { UpdateUseCase } from '../../../components/upgrade/utils';
-import { mockAppState, mockCurrentUser } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { AppState } from '../../../types/appstate';
-import { EditionKey } from '../../../types/editions';
-import { Permissions } from '../../../types/permissions';
-import { ProductNameForUpgrade } from '../../../types/system';
-import { CurrentUser } from '../../../types/users';
-import { AppStateContext } from '../app-state/AppStateContext';
-import { CurrentUserContext } from '../current-user/CurrentUserContext';
-import { UpdateNotification } from '../update-notification/UpdateNotification';
-
-jest.mock('../../../api/system', () => ({
- getSystemUpgrades: jest.fn(),
-}));
-
-const ui = {
- closeDialogBtn: byRole('button', { name: 'cancel' }),
- dialog: byRole('dialog', { name: 'system.system_upgrade' }),
- dialogErrorMessage: byRole('dialog').byText('admin_notification.update.current_version_inactive'),
- dialogWarningMessage: byRole('dialog').byText('admin_notification.update.new_patch'),
- hideIntermediateBtn: byRole('button', { name: 'system.hide_intermediate_versions' }),
- intermediateRegion: byRole('region', { name: 'system.hide_intermediate_versions' }),
- latestHeader: byRole('heading', { name: /system.latest_version/ }),
- latestLTAHeader: byRole('heading', { name: /system.lta_version/ }),
- learnMoreLink: byRole('link', { name: /learn_more/ }),
- openDialogBtn: byRole('button', { name: 'learn_more' }),
- patchHeader: byRole('heading', { name: /system.latest_patch/ }),
- showIntermediateBtn: byRole('button', { name: 'system.show_intermediate_versions' }),
- updateMessage: byRole('alert'),
-};
-
-const SQCBUpgrade = { downloadUrl: '', product: ProductNameForUpgrade.SonarQubeCommunityBuild };
-const SQSUpgrade = { downloadUrl: '', product: ProductNameForUpgrade.SonarQubeServer };
-
-describe('when running SQS', () => {
- it('should not render update notification if user is not logged in', () => {
- renderUpdateNotification(undefined, { isLoggedIn: false });
- expect(getSystemUpgrades).not.toHaveBeenCalled();
- expect(ui.updateMessage.query()).not.toBeInTheDocument();
- });
-
- it('should not render update notification if user is not admin', () => {
- renderUpdateNotification(undefined, { permissions: { global: [] } });
- expect(getSystemUpgrades).not.toHaveBeenCalled();
- expect(ui.updateMessage.query()).not.toBeInTheDocument();
- });
-
- it('should not render update notification if no upgrades', () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
- renderUpdateNotification();
- expect(getSystemUpgrades).toHaveBeenCalled();
- expect(ui.updateMessage.query()).not.toBeInTheDocument();
- });
-
- it('should show error message if upgrades call failed and the version has reached eol', async () => {
- jest.mocked(getSystemUpgrades).mockReturnValue(Promise.reject(new Error('error')));
- renderUpdateNotification(undefined, undefined, {
- versionEOL: formatISO(subDays(new Date(), 1), { representation: 'date' }),
- });
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.CurrentVersionInactive}`,
- );
- expect(ui.openDialogBtn.query()).not.toBeInTheDocument();
- expect(ui.learnMoreLink.get()).toBeInTheDocument();
- });
-
- it('should not show the notification banner if there is no network connection and version has not reached the eol', () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [],
- });
- renderUpdateNotification(undefined, undefined, {
- versionEOL: formatISO(addDays(new Date(), 1), { representation: 'date' }),
- });
- expect(ui.updateMessage.query()).not.toBeInTheDocument();
- });
-
- it('should show the error banner if there is no network connection and version has reached the eol', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [],
- });
- renderUpdateNotification(undefined, undefined, {
- versionEOL: formatISO(subDays(new Date(), 1), { representation: 'date' }),
- });
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.CurrentVersionInactive}`,
- );
- expect(ui.openDialogBtn.query()).not.toBeInTheDocument();
- expect(ui.learnMoreLink.get()).toBeInTheDocument();
- });
-
- it('active / latest / patch', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [{ ...SQSUpgrade, version: '10.5.1' }],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
- const user = userEvent.setup();
- renderUpdateNotification();
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.NewPatch}`,
- );
- await user.click(ui.openDialogBtn.get());
- expect(ui.dialogWarningMessage.get()).toBeInTheDocument();
- expect(ui.dialog.get()).toHaveTextContent('10.5.1');
- expect(ui.patchHeader.get()).toBeInTheDocument();
- expect(ui.showIntermediateBtn.query()).not.toBeInTheDocument();
- });
-
- it('active / latest / several patches', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [
- { ...SQSUpgrade, version: '10.5.2', releaseDate: '2021-08-02' },
- { ...SQSUpgrade, version: '10.5.1', releaseDate: '2021-08-01' },
- ],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
- const user = userEvent.setup();
- renderUpdateNotification();
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.NewPatch}`,
- );
- await user.click(ui.openDialogBtn.get());
- expect(ui.dialogWarningMessage.get()).toBeInTheDocument();
- expect(ui.dialog.get()).toHaveTextContent('10.5.2');
- expect(ui.dialog.get()).not.toHaveTextContent('10.5.1');
- expect(ui.patchHeader.get()).toBeInTheDocument();
- expect(ui.showIntermediateBtn.get()).toBeInTheDocument();
- await user.click(ui.showIntermediateBtn.get());
- expect(ui.showIntermediateBtn.query()).not.toBeInTheDocument();
- expect(ui.hideIntermediateBtn.get()).toBeInTheDocument();
- expect(ui.intermediateRegion.get()).toHaveTextContent('10.5.1August 1, 2021');
- });
-
- it('active / latest / new minor', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [{ ...SQSUpgrade, version: '10.6.0' }],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
- const user = userEvent.setup();
- renderUpdateNotification();
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.NewVersion}`,
- );
- await user.click(ui.openDialogBtn.get());
- expect(ui.latestHeader.get()).toBeInTheDocument();
- expect(ui.showIntermediateBtn.query()).not.toBeInTheDocument();
- });
-
- it('active / latest / new minor + patch', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [
- { ...SQSUpgrade, version: '10.5.1', releaseDate: '2021-08-01' },
- { ...SQSUpgrade, version: '10.6.0', releaseDate: '2021-08-02' },
- ],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
- const user = userEvent.setup();
- renderUpdateNotification();
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.NewVersion}`,
- );
- await user.click(ui.openDialogBtn.get());
- expect(ui.dialogWarningMessage.query()).not.toBeInTheDocument();
- expect(ui.dialog.get()).toHaveTextContent('10.6.0');
- expect(ui.dialog.get()).not.toHaveTextContent('10.5.1');
- expect(ui.latestHeader.get()).toBeInTheDocument();
- expect(ui.patchHeader.query()).not.toBeInTheDocument();
- expect(ui.showIntermediateBtn.get()).toBeInTheDocument();
- await user.click(ui.showIntermediateBtn.get());
- expect(ui.intermediateRegion.get()).toHaveTextContent('10.5.1August 1, 2021');
- });
-
- it('no longer active / latest / new minor', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [
- { ...SQSUpgrade, version: '10.6.0', releaseDate: '2021-08-02' },
- { ...SQSUpgrade, version: '10.7.0', releaseDate: '2021-08-03' },
- ],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: false,
- });
- const user = userEvent.setup();
- renderUpdateNotification();
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.CurrentVersionInactive}`,
- );
- await user.click(ui.openDialogBtn.get());
- expect(ui.dialogErrorMessage.get()).toBeInTheDocument();
- expect(ui.dialog.get()).toHaveTextContent('10.7.0');
- expect(ui.dialog.get()).not.toHaveTextContent('10.6.0');
- expect(ui.latestHeader.get()).toBeInTheDocument();
- expect(ui.showIntermediateBtn.get()).toBeInTheDocument();
- await user.click(ui.showIntermediateBtn.get());
- expect(ui.intermediateRegion.get()).toHaveTextContent('10.6.0August 2, 2021');
- });
-
- it('no longer active / latest / new minor + patch', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [
- { ...SQSUpgrade, version: '10.5.1', releaseDate: '2021-08-01' },
- { ...SQSUpgrade, version: '10.6.0', releaseDate: '2021-08-02' },
- { ...SQSUpgrade, version: '10.7.0', releaseDate: '2021-08-03' },
- ],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: false,
- });
- const user = userEvent.setup();
- renderUpdateNotification();
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.CurrentVersionInactive}`,
- );
- await user.click(ui.openDialogBtn.get());
- expect(ui.dialogErrorMessage.get()).toBeInTheDocument();
- expect(ui.dialogWarningMessage.query()).not.toBeInTheDocument();
- expect(ui.dialog.get()).toHaveTextContent('10.7.0');
- expect(ui.dialog.get()).not.toHaveTextContent('10.6.0');
- expect(ui.dialog.get()).not.toHaveTextContent('10.5.1');
- expect(ui.latestHeader.get()).toBeInTheDocument();
- expect(ui.patchHeader.query()).not.toBeInTheDocument();
- expect(ui.showIntermediateBtn.get()).toBeInTheDocument();
- await user.click(ui.showIntermediateBtn.get());
- expect(ui.intermediateRegion.get()).toHaveTextContent('10.6.0August 2, 2021');
- expect(ui.intermediateRegion.get()).toHaveTextContent('10.5.1August 1, 2021');
- });
-
- it('active / lta / patch', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [{ ...SQSUpgrade, version: '9.9.1' }],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
- const user = userEvent.setup();
- renderUpdateNotification(undefined, undefined, { version: '9.9.0' });
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.NewPatch}`,
- );
- await user.click(ui.openDialogBtn.get());
- expect(ui.dialogWarningMessage.get()).toBeInTheDocument();
- expect(ui.dialog.get()).toHaveTextContent('9.9.1');
- expect(ui.latestLTAHeader.get()).toBeInTheDocument();
- // If the current version is an LTA version, we don't show Patch header, we show Latest LTA header
- expect(ui.patchHeader.query()).not.toBeInTheDocument();
- expect(ui.showIntermediateBtn.query()).not.toBeInTheDocument();
- });
-
- it('active / lta / new minor', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [{ ...SQSUpgrade, version: '10.0.0' }],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
- const user = userEvent.setup();
- renderUpdateNotification(undefined, undefined, { version: '9.9.0' });
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.NewVersion}`,
- );
- await user.click(ui.openDialogBtn.get());
- expect(ui.dialogWarningMessage.query()).not.toBeInTheDocument();
- expect(ui.dialog.get()).toHaveTextContent('10.0.0');
- expect(ui.latestHeader.get()).toBeInTheDocument();
- expect(ui.latestLTAHeader.query()).not.toBeInTheDocument();
- expect(ui.patchHeader.query()).not.toBeInTheDocument();
- expect(ui.showIntermediateBtn.query()).not.toBeInTheDocument();
- });
-
- it('active / lta / new minor + patch', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [
- { ...SQSUpgrade, version: '9.9.1' },
- { ...SQSUpgrade, version: '10.0.0' },
- ],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
- const user = userEvent.setup();
- renderUpdateNotification(undefined, undefined, { version: '9.9.0' });
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.NewPatch}`,
- );
- await user.click(ui.openDialogBtn.get());
- expect(ui.dialogWarningMessage.get()).toBeInTheDocument();
- expect(ui.dialog.get()).toHaveTextContent('10.0.0');
- expect(ui.dialog.get()).toHaveTextContent('9.9.1');
- expect(ui.latestHeader.get()).toBeInTheDocument();
- expect(ui.latestLTAHeader.get()).toBeInTheDocument();
- // If the current version is an LTA version, we don't show Patch header, we show Latest LTA header
- expect(ui.patchHeader.query()).not.toBeInTheDocument();
- expect(ui.showIntermediateBtn.query()).not.toBeInTheDocument();
- });
-
- it('active / prev lta / new lta + patch', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [
- { ...SQSUpgrade, version: '8.9.1' },
- { ...SQSUpgrade, version: '9.9.0' },
- ],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
- const user = userEvent.setup();
- renderUpdateNotification(undefined, undefined, { version: '8.9.0' });
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.NewPatch}`,
- );
- await user.click(ui.openDialogBtn.get());
- expect(ui.dialogWarningMessage.get()).toBeInTheDocument();
- expect(ui.dialog.get()).toHaveTextContent('8.9.1');
- expect(ui.dialog.get()).toHaveTextContent('9.9.0');
- expect(ui.latestHeader.query()).not.toBeInTheDocument();
- expect(ui.latestLTAHeader.get()).toBeInTheDocument();
- expect(ui.patchHeader.get()).toBeInTheDocument();
- expect(ui.showIntermediateBtn.query()).not.toBeInTheDocument();
- });
-
- it('active / prev lta / new lta + new minor + patch', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [
- { ...SQSUpgrade, version: '8.9.1' },
- { ...SQSUpgrade, version: '9.9.0' },
- { ...SQSUpgrade, version: '10.0.0' },
- ],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
- const user = userEvent.setup();
- renderUpdateNotification(undefined, undefined, { version: '8.9.0' });
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.NewPatch}`,
- );
- await user.click(ui.openDialogBtn.get());
- expect(ui.dialogWarningMessage.get()).toBeInTheDocument();
- expect(ui.dialog.get()).toHaveTextContent('8.9.1');
- expect(ui.dialog.get()).toHaveTextContent('9.9.0');
- expect(ui.dialog.get()).toHaveTextContent('10.0.0');
- expect(ui.latestHeader.get()).toBeInTheDocument();
- expect(ui.latestLTAHeader.get()).toBeInTheDocument();
- expect(ui.patchHeader.get()).toBeInTheDocument();
- expect(ui.showIntermediateBtn.query()).not.toBeInTheDocument();
- });
-
- it('active / no uogrades', () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
-
- renderUpdateNotification(undefined, undefined, { version: '8.9.0' });
-
- expect(screen.queryByText('admin_notification.update')).not.toBeInTheDocument();
- });
-
- it('no longer active / prev lta / new lta', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [{ ...SQSUpgrade, version: '9.9.0' }],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: false,
- });
- const user = userEvent.setup();
- renderUpdateNotification(undefined, undefined, { version: '8.9.0' });
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.CurrentVersionInactive}`,
- );
- await user.click(ui.openDialogBtn.get());
- expect(ui.dialogErrorMessage.get()).toBeInTheDocument();
- expect(ui.dialog.get()).toHaveTextContent('9.9.0');
- expect(ui.latestLTAHeader.get()).toBeInTheDocument();
- expect(ui.showIntermediateBtn.query()).not.toBeInTheDocument();
- });
-
- it('no longer active / prev lta / new lta + patch', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [
- { ...SQSUpgrade, version: '8.9.1' },
- { ...SQSUpgrade, version: '9.9.0' },
- ],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: false,
- });
- const user = userEvent.setup();
- renderUpdateNotification(undefined, undefined, { version: '8.9.0' });
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.CurrentVersionInactive}`,
- );
- await user.click(ui.openDialogBtn.get());
- expect(ui.dialogErrorMessage.get()).toBeInTheDocument();
- expect(ui.dialog.get()).toHaveTextContent('9.9.0');
- expect(ui.dialog.get()).not.toHaveTextContent('8.9.1');
- expect(ui.latestLTAHeader.get()).toBeInTheDocument();
- expect(ui.patchHeader.query()).not.toBeInTheDocument();
- expect(ui.showIntermediateBtn.query()).not.toBeInTheDocument();
- });
-
- it('no longer active / prev lta / new lta + patch + new minors', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [
- { ...SQSUpgrade, version: '8.9.1', releaseDate: '2021-08-01' },
- { ...SQSUpgrade, version: '9.9.0', releaseDate: '2021-08-02' },
- { ...SQSUpgrade, version: '9.9.1', releaseDate: '2021-08-03' },
- { ...SQSUpgrade, version: '10.0.0', releaseDate: '2021-08-04' },
- { ...SQSUpgrade, version: '10.1.0', releaseDate: '2021-08-05' },
- { ...SQSUpgrade, version: '10.1.1', releaseDate: '2021-08-06' },
- ],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: false,
- });
- const user = userEvent.setup();
- renderUpdateNotification(true, undefined, { version: '8.9.0' });
- expect(await ui.updateMessage.find()).toHaveTextContent(
- `admin_notification.update.${UpdateUseCase.CurrentVersionInactive}`,
- );
- await user.click(ui.openDialogBtn.get());
- expect(ui.dialogErrorMessage.get()).toBeInTheDocument();
- expect(ui.dialog.get()).toHaveTextContent('9.9.1');
- expect(ui.dialog.get()).not.toHaveTextContent('9.9.0');
- expect(ui.dialog.get()).toHaveTextContent('10.1.1');
- expect(ui.dialog.get()).not.toHaveTextContent('10.1.0');
- expect(ui.dialog.get()).not.toHaveTextContent('10.0.0');
- expect(ui.dialog.get()).not.toHaveTextContent('8.9.1');
- expect(ui.latestHeader.get()).toBeInTheDocument();
- expect(ui.latestLTAHeader.get()).toBeInTheDocument();
- expect(ui.patchHeader.query()).not.toBeInTheDocument();
- expect(ui.showIntermediateBtn.getAll()).toHaveLength(2);
- await user.click(ui.showIntermediateBtn.getAt(0));
- expect(ui.intermediateRegion.get()).toHaveTextContent('10.1.0August 5, 2021');
- expect(ui.intermediateRegion.get()).toHaveTextContent('10.0.0August 4, 2021');
- expect(ui.intermediateRegion.get()).not.toHaveTextContent('9.9.0');
- await user.click(ui.hideIntermediateBtn.get());
- await user.click(ui.showIntermediateBtn.getAt(1));
- expect(ui.intermediateRegion.get()).toHaveTextContent('9.9.0August 2, 2021');
- expect(ui.intermediateRegion.get()).not.toHaveTextContent('10.1.0');
- expect(ui.intermediateRegion.get()).not.toHaveTextContent('10.0.0');
- });
-});
-
-describe('when running SQCB', () => {
- it('should not render update notification if no upgrades', () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
-
- renderUpdateNotification(undefined, undefined, { edition: EditionKey.community });
-
- expect(getSystemUpgrades).toHaveBeenCalled();
-
- expect(ui.updateMessage.query()).not.toBeInTheDocument();
- });
-
- it('SQCB upgrade available, no SQS upgrade', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [{ ...SQCBUpgrade, version: '25.2' }],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
-
- renderUpdateNotification(undefined, undefined, { edition: EditionKey.community });
-
- expect(await ui.updateMessage.find()).toHaveTextContent(
- 'admin_notification.update.new_sqcb_version',
- );
-
- expect(
- screen.queryByText('admin_notification.update.new_sqs_version_when_running_sqcb.banner'),
- ).not.toBeInTheDocument();
- });
-
- it('non-patch SQS upgrade available, no SQCB upgrade', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [{ ...SQSUpgrade, version: '2025.2' }],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
-
- const user = userEvent.setup();
-
- renderUpdateNotification(undefined, undefined, { edition: EditionKey.community });
-
- expect(
- screen.queryByText('admin_notification.update.new_sqcb_version'),
- ).not.toBeInTheDocument();
-
- expect(await ui.updateMessage.find()).toHaveTextContent(
- 'admin_notification.update.new_sqs_version_when_running_sqcb.banner',
- );
-
- await user.click(ui.openDialogBtn.get());
-
- expect(
- await screen.findByText(
- 'admin_notification.update.new_sqs_version_when_running_sqcb.upgrade',
- ),
- ).toBeInTheDocument();
-
- await user.click(ui.closeDialogBtn.get());
-
- expect(
- screen.queryByText('admin_notification.update.new_sqs_version_when_running_sqcb.upgrade'),
- ).not.toBeInTheDocument();
- });
-
- it('only patch SQS upgrade available, no SQCB upgrade', () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [{ ...SQSUpgrade, version: '2025.2.3' }],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
-
- renderUpdateNotification(undefined, undefined, { edition: EditionKey.community });
-
- expect(
- screen.queryByText('admin_notification.update.new_sqcb_version'),
- ).not.toBeInTheDocument();
-
- expect(
- screen.queryByText('admin_notification.update.new_sqs_version_when_running_sqcb.banner'),
- ).not.toBeInTheDocument();
- });
-
- it('both SQCB and non-patch-SQS upgrades available', async () => {
- jest.mocked(getSystemUpgrades).mockResolvedValue({
- upgrades: [
- { ...SQCBUpgrade, version: '25.4' },
- { ...SQSUpgrade, version: '2025.4' },
- ],
- latestLTA: '9.9',
- updateCenterRefresh: '',
- installedVersionActive: true,
- });
-
- const user = userEvent.setup();
-
- renderUpdateNotification(true, undefined, { edition: EditionKey.community });
-
- expect(await ui.updateMessage.findAll()).toHaveLength(2);
-
- await user.click(ui.openDialogBtn.get());
-
- expect(
- await screen.findByText(
- 'admin_notification.update.new_sqs_version_when_running_sqcb.upgrade',
- ),
- ).toBeInTheDocument();
-
- await user.keyboard('{Escape}');
-
- expect(
- screen.queryByText('admin_notification.update.new_sqs_version_when_running_sqcb.upgrade'),
- ).not.toBeInTheDocument();
- });
-});
-
-function renderUpdateNotification(
- dissmissable = false,
- user?: Partial<CurrentUser>,
- appState: Partial<AppState> = {},
-) {
- return renderComponent(
- <CurrentUserContext.Provider
- value={{
- currentUser: mockCurrentUser({
- isLoggedIn: true,
- permissions: { global: [Permissions.Admin] },
- ...user,
- }),
- updateCurrentUserHomepage: () => {},
- updateDismissedNotices: () => {},
- }}
- >
- <AppStateContext.Provider
- value={mockAppState({
- edition: EditionKey.developer,
- version: '10.5.0',
- // versionEOL is a date in the past to be sure that it is not used when we have data from upgrades endpoint
- versionEOL: '2020-01-01',
- ...appState,
- })}
- >
- <UpdateNotification dismissable={dissmissable} />
- </AppStateContext.Provider>
- </CurrentUserContext.Provider>,
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/admin/StickyTable.tsx b/server/sonar-web/src/main/js/app/components/admin/StickyTable.tsx
deleted file mode 100644
index 69bb9af301d..00000000000
--- a/server/sonar-web/src/main/js/app/components/admin/StickyTable.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { LAYOUT_GLOBAL_NAV_HEIGHT, Table, themeColor } from '~design-system';
-
-export const LAYOUT_ADMIN_NAV_HEIGHT = 92;
-
-export const StickyTable = styled(Table)`
- & th {
- position: sticky;
- top: ${LAYOUT_ADMIN_NAV_HEIGHT + LAYOUT_GLOBAL_NAV_HEIGHT}px;
- background: ${themeColor('backgroundSecondary')};
- z-index: 1;
- }
-`;
diff --git a/server/sonar-web/src/main/js/app/components/admin/withAdminPagesOutletContext.tsx b/server/sonar-web/src/main/js/app/components/admin/withAdminPagesOutletContext.tsx
deleted file mode 100644
index 86b1d0e0336..00000000000
--- a/server/sonar-web/src/main/js/app/components/admin/withAdminPagesOutletContext.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { useOutletContext } from 'react-router-dom';
-import { AdminPagesContext } from '../../../types/admin';
-
-export default function withAdminPagesOutletContext(
- WrappedComponent: React.ComponentType<React.PropsWithChildren<AdminPagesContext>>,
-) {
- return function WithAdminPagesOutletContext() {
- const { adminPages } = useOutletContext<AdminPagesContext>();
-
- return <WrappedComponent adminPages={adminPages} />;
- };
-}
diff --git a/server/sonar-web/src/main/js/app/components/app-state/AppStateContext.tsx b/server/sonar-web/src/main/js/app/components/app-state/AppStateContext.tsx
deleted file mode 100644
index 1d88b1d220e..00000000000
--- a/server/sonar-web/src/main/js/app/components/app-state/AppStateContext.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { DOC_URL } from '../../../helpers/doc-links';
-import { AppState } from '../../../types/appstate';
-
-export const DEFAULT_APP_STATE = {
- authenticationError: false,
- authorizationError: false,
- edition: undefined,
- productionDatabase: true,
- qualifiers: [],
- settings: {},
- version: '',
- versionEOL: '',
- documentationUrl: DOC_URL,
-};
-export const AppStateContext = React.createContext<AppState>(DEFAULT_APP_STATE);
diff --git a/server/sonar-web/src/main/js/app/components/app-state/AppStateContextProvider.tsx b/server/sonar-web/src/main/js/app/components/app-state/AppStateContextProvider.tsx
deleted file mode 100644
index fb245c7d3c6..00000000000
--- a/server/sonar-web/src/main/js/app/components/app-state/AppStateContextProvider.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { AppState } from '../../../types/appstate';
-import { AppStateContext } from './AppStateContext';
-
-export interface AppStateContextProviderProps {
- appState: AppState;
-}
-
-export default function AppStateContextProvider({
- appState,
- children,
-}: React.PropsWithChildren<AppStateContextProviderProps>) {
- return <AppStateContext.Provider value={appState}>{children}</AppStateContext.Provider>;
-}
diff --git a/server/sonar-web/src/main/js/app/components/app-state/withAppStateContext.tsx b/server/sonar-web/src/main/js/app/components/app-state/withAppStateContext.tsx
deleted file mode 100644
index 5abc2557fe5..00000000000
--- a/server/sonar-web/src/main/js/app/components/app-state/withAppStateContext.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { getWrappedDisplayName } from '~sonar-aligned/components/hoc/utils';
-import { AppState } from '../../../types/appstate';
-import { AppStateContext } from './AppStateContext';
-
-export interface WithAppStateContextProps {
- appState: AppState;
-}
-
-export default function withAppStateContext<P>(
- WrappedComponent: React.ComponentType<React.PropsWithChildren<P & WithAppStateContextProps>>,
-) {
- return class WithAppStateContext extends React.PureComponent<
- Omit<P, keyof WithAppStateContextProps>
- > {
- static displayName = getWrappedDisplayName(WrappedComponent, 'withAppStateContext');
-
- render() {
- return (
- <AppStateContext.Consumer>
- {(appState) => <WrappedComponent appState={appState} {...(this.props as P)} />}
- </AppStateContext.Consumer>
- );
- }
- };
-}
-
-export function useAppState() {
- return React.useContext(AppStateContext);
-}
diff --git a/server/sonar-web/src/main/js/app/components/available-features/AvailableFeaturesContext.tsx b/server/sonar-web/src/main/js/app/components/available-features/AvailableFeaturesContext.tsx
deleted file mode 100644
index e8851950500..00000000000
--- a/server/sonar-web/src/main/js/app/components/available-features/AvailableFeaturesContext.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Feature } from '../../../types/features';
-
-export const DEFAULT_AVAILABLE_FEATURES = [];
-
-export const AvailableFeaturesContext = React.createContext<Feature[]>(DEFAULT_AVAILABLE_FEATURES);
diff --git a/server/sonar-web/src/main/js/app/components/available-features/withAvailableFeatures.tsx b/server/sonar-web/src/main/js/app/components/available-features/withAvailableFeatures.tsx
deleted file mode 100644
index d8dc006a188..00000000000
--- a/server/sonar-web/src/main/js/app/components/available-features/withAvailableFeatures.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { getWrappedDisplayName } from '~sonar-aligned/components/hoc/utils';
-import { Feature } from '../../../types/features';
-import { AvailableFeaturesContext } from './AvailableFeaturesContext';
-
-export interface WithAvailableFeaturesProps {
- hasFeature: (feature: Feature) => boolean;
-}
-
-export default function withAvailableFeatures<P>(
- WrappedComponent: React.ComponentType<React.PropsWithChildren<P & WithAvailableFeaturesProps>>,
-) {
- return class WithAvailableFeatures extends React.PureComponent<
- Omit<P, keyof WithAvailableFeaturesProps>
- > {
- static displayName = getWrappedDisplayName(WrappedComponent, 'withAvailableFeaturesContext');
-
- render() {
- return (
- <AvailableFeaturesContext.Consumer>
- {(availableFeatures) => (
- <WrappedComponent
- hasFeature={(feature) => availableFeatures.includes(feature)}
- {...(this.props as P)}
- />
- )}
- </AvailableFeaturesContext.Consumer>
- );
- }
- };
-}
-
-export function useAvailableFeatures() {
- const availableFeatures = React.useContext(AvailableFeaturesContext);
-
- return {
- hasFeature: (feature: Feature) => availableFeatures.includes(feature),
- };
-}
diff --git a/server/sonar-web/src/main/js/app/components/calculation-notification/CalculationChangeMessage.tsx b/server/sonar-web/src/main/js/app/components/calculation-notification/CalculationChangeMessage.tsx
deleted file mode 100644
index 8256becdc22..00000000000
--- a/server/sonar-web/src/main/js/app/components/calculation-notification/CalculationChangeMessage.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkHighlight } from '@sonarsource/echoes-react';
-import { FormattedMessage } from 'react-intl';
-import { useLocation } from '~sonar-aligned/components/hoc/withRouter';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import DocumentationLink from '../../../components/common/DocumentationLink';
-import { DismissableAlert } from '../../../components/ui/DismissableAlert';
-import { DocLink } from '../../../helpers/doc-links';
-import { useStandardExperienceModeQuery } from '../../../queries/mode';
-import { Dict } from '../../../types/types';
-
-const SHOW_MESSAGE_PATHS: Dict<ComponentQualifier> = {
- '/projects': ComponentQualifier.Project,
- '/portfolios': ComponentQualifier.Portfolio,
-};
-
-const ALERT_KEY = 'sonarqube.dismissed_calculation_change_alert';
-
-export default function CalculationChangeMessage() {
- const location = useLocation();
- const { data: isStandardMode } = useStandardExperienceModeQuery();
-
- if (isStandardMode || !Object.keys(SHOW_MESSAGE_PATHS).includes(location.pathname)) {
- return null;
- }
-
- return (
- <DismissableAlert variant="info" alertKey={ALERT_KEY + SHOW_MESSAGE_PATHS[location.pathname]}>
- <FormattedMessage
- id="notification.calculation_change.message"
- values={{
- link: (text) => (
- <DocumentationLink
- shouldOpenInNewTab
- className="sw-ml-1"
- highlight={LinkHighlight.Default}
- to={DocLink.MetricDefinitions}
- >
- {text}
- </DocumentationLink>
- ),
- }}
- />
- </DismissableAlert>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/componentContext/ComponentContext.ts b/server/sonar-web/src/main/js/app/components/componentContext/ComponentContext.ts
deleted file mode 100644
index 61bccd51adf..00000000000
--- a/server/sonar-web/src/main/js/app/components/componentContext/ComponentContext.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { noop } from 'lodash';
-import * as React from 'react';
-import { ComponentContextShape } from '../../../types/component';
-
-export const ComponentContext = React.createContext<ComponentContextShape>({
- onComponentChange: noop,
- fetchComponent: () => new Promise(noop),
-});
diff --git a/server/sonar-web/src/main/js/app/components/componentContext/withComponentContext.tsx b/server/sonar-web/src/main/js/app/components/componentContext/withComponentContext.tsx
deleted file mode 100644
index 2301608b7af..00000000000
--- a/server/sonar-web/src/main/js/app/components/componentContext/withComponentContext.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { getWrappedDisplayName } from '~sonar-aligned/components/hoc/utils';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { ComponentContextShape } from '../../../types/component';
-import { ComponentContext } from './ComponentContext';
-
-export default function withComponentContext<P extends Partial<ComponentContextShape>>(
- WrappedComponent: React.ComponentType<React.PropsWithChildren<P>>,
-) {
- return class WithComponentContext extends React.PureComponent<
- Omit<P, keyof ComponentContextShape>
- > {
- static displayName = getWrappedDisplayName(WrappedComponent, 'withComponentContext');
-
- render() {
- return (
- <ComponentContext.Consumer>
- {(componentContext) => <WrappedComponent {...componentContext} {...(this.props as P)} />}
- </ComponentContext.Consumer>
- );
- }
- };
-}
-
-export function useComponent() {
- return React.useContext(ComponentContext);
-}
-
-export function useTopLevelComponentKey() {
- const { component } = useComponent();
-
- const componentKey = React.useMemo(() => {
- if (!component) {
- return undefined;
- }
-
- let current = component.breadcrumbs.length - 1;
-
- while (
- current > 0 &&
- !(
- [
- ComponentQualifier.Project,
- ComponentQualifier.Portfolio,
- ComponentQualifier.Application,
- ] as string[]
- ).includes(component.breadcrumbs[current].qualifier)
- ) {
- current--;
- }
-
- return component.breadcrumbs[current].key;
- }, [component]);
-
- return componentKey;
-}
diff --git a/server/sonar-web/src/main/js/app/components/current-user/CurrentUserContext.ts b/server/sonar-web/src/main/js/app/components/current-user/CurrentUserContext.ts
deleted file mode 100644
index 74191488f24..00000000000
--- a/server/sonar-web/src/main/js/app/components/current-user/CurrentUserContext.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { noop } from 'lodash';
-import * as React from 'react';
-import { useContext } from 'react';
-import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication';
-import { CurrentUser, HomePage, LoggedInUser, NoticeType } from '../../../types/users';
-
-export interface CurrentUserContextInterface {
- currentUser: CurrentUser;
- updateCurrentUserHomepage: (homepage: HomePage) => void;
- updateDismissedNotices: (key: NoticeType, value: boolean) => void;
-}
-
-export const CurrentUserContext = React.createContext<CurrentUserContextInterface>({
- currentUser: {
- isLoggedIn: false,
- dismissedNotices: {},
- },
- updateCurrentUserHomepage: noop,
- updateDismissedNotices: noop,
-});
-
-export function useCurrentUser() {
- return useContext(CurrentUserContext);
-}
-
-export function useCurrentLoginUser() {
- const { currentUser } = useCurrentUser();
-
- if (!currentUser.isLoggedIn) {
- handleRequiredAuthentication();
- }
- return currentUser as LoggedInUser;
-}
diff --git a/server/sonar-web/src/main/js/app/components/current-user/CurrentUserContextProvider.tsx b/server/sonar-web/src/main/js/app/components/current-user/CurrentUserContextProvider.tsx
deleted file mode 100644
index 2cb559b224a..00000000000
--- a/server/sonar-web/src/main/js/app/components/current-user/CurrentUserContextProvider.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { CurrentUser, HomePage, NoticeType } from '../../../types/users';
-import { CurrentUserContext } from './CurrentUserContext';
-
-interface Props {
- currentUser?: CurrentUser;
-}
-
-interface State {
- currentUser: CurrentUser;
-}
-
-export default class CurrentUserContextProvider extends React.PureComponent<
- React.PropsWithChildren<Props>,
- State
-> {
- constructor(props: Props) {
- super(props);
- this.state = { currentUser: props.currentUser ?? { isLoggedIn: false, dismissedNotices: {} } };
- }
-
- updateCurrentUserHomepage = (homepage: HomePage) => {
- this.setState((prevState) => ({
- currentUser: { ...prevState.currentUser, homepage },
- }));
- };
-
- updateDismissedNotices = (key: NoticeType, value: boolean) => {
- this.setState((prevState) => ({
- currentUser: {
- ...prevState.currentUser,
- dismissedNotices: { ...prevState.currentUser.dismissedNotices, [key]: value },
- },
- }));
- };
-
- render() {
- return (
- <CurrentUserContext.Provider
- value={{
- currentUser: this.state.currentUser,
- updateCurrentUserHomepage: this.updateCurrentUserHomepage,
- updateDismissedNotices: this.updateDismissedNotices,
- }}
- >
- {this.props.children}
- </CurrentUserContext.Provider>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/app/components/current-user/withCurrentUserContext.tsx b/server/sonar-web/src/main/js/app/components/current-user/withCurrentUserContext.tsx
deleted file mode 100644
index e052e819639..00000000000
--- a/server/sonar-web/src/main/js/app/components/current-user/withCurrentUserContext.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { getWrappedDisplayName } from '~sonar-aligned/components/hoc/utils';
-import { CurrentUserContext, CurrentUserContextInterface } from './CurrentUserContext';
-
-export default function withCurrentUserContext<P>(
- WrappedComponent: React.ComponentType<
- React.PropsWithChildren<
- React.PropsWithChildren<P & Pick<CurrentUserContextInterface, 'currentUser'>>
- >
- >,
-) {
- return class WithCurrentUserContext extends React.PureComponent<
- Omit<P, 'currentUser' | 'updateCurrentUserHomepage' | 'updateDismissedNotices'>
- > {
- static displayName = getWrappedDisplayName(WrappedComponent, 'withCurrentUserContext');
-
- render() {
- return (
- <CurrentUserContext.Consumer>
- {(currentUserContext: CurrentUserContextInterface) => (
- <WrappedComponent {...currentUserContext} {...(this.props as P)} />
- )}
- </CurrentUserContext.Consumer>
- );
- }
- };
-}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/CreateApplicationForm.tsx b/server/sonar-web/src/main/js/app/components/extensions/CreateApplicationForm.tsx
deleted file mode 100644
index cc336ae3ea3..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/CreateApplicationForm.tsx
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import {
- ButtonSecondary,
- FormField,
- InputField,
- InputTextArea,
- Modal,
- RadioButton,
-} from '~design-system';
-import { ComponentQualifier, Visibility } from '~sonar-aligned/types/component';
-import { createApplication } from '../../../api/application';
-import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation';
-import { translate } from '../../../helpers/l10n';
-
-interface Props {
- onClose: () => void;
- onCreate: (application: { key: string; qualifier: ComponentQualifier }) => Promise<void>;
-}
-
-interface State {
- description: string;
- key: string;
- name: string;
- submitting: boolean;
- visibility: Visibility;
-}
-
-export default class CreateApplicationForm extends React.PureComponent<Props, State> {
- mounted = false;
-
- constructor(props: Props) {
- super(props);
- this.state = {
- description: '',
- key: '',
- name: '',
- visibility: Visibility.Public,
- submitting: false,
- };
- }
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- handleDescriptionChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
- this.setState({ description: event.currentTarget.value });
- };
-
- handleKeyChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- this.setState({ key: event.currentTarget.value });
- };
-
- handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- this.setState({ name: event.currentTarget.value });
- };
-
- handleVisibilityChange = (visibility: Visibility) => {
- this.setState({ visibility });
- };
-
- handleFormSubmit = (event: React.FormEvent) => {
- event.preventDefault();
-
- const { name, description, key, visibility } = this.state;
- this.setState({ submitting: true });
- return createApplication(name, description, key.length > 0 ? key : undefined, visibility)
- .then(({ application }) => {
- if (this.mounted) {
- this.setState({ submitting: false });
- this.props.onCreate({
- key: application.key,
- qualifier: ComponentQualifier.Application,
- });
- }
- })
- .catch(() => {
- this.setState({ submitting: false });
- });
- };
-
- renderForm = () => {
- const { name, description, key, visibility } = this.state;
-
- return (
- <form onSubmit={this.handleFormSubmit} id="create-application-form">
- <MandatoryFieldsExplanation className="modal-field" />
-
- <FormField
- htmlFor="view-edit-name"
- label={translate('name')}
- required
- requiredAriaLabel={translate('field_required')}
- >
- <InputField
- autoFocus
- id="view-edit-name"
- maxLength={100}
- name="name"
- onChange={this.handleNameChange}
- type="text"
- size="full"
- value={name}
- />
- </FormField>
- <FormField htmlFor="view-edit-description" label={translate('description')}>
- <InputTextArea
- id="view-edit-description"
- name="description"
- onChange={this.handleDescriptionChange}
- size="full"
- value={description}
- />
- </FormField>
- <FormField
- htmlFor="view-edit-key"
- label={translate('key')}
- description={translate('onboarding.create_application.key.description')}
- >
- <InputField
- autoComplete="off"
- id="view-edit-key"
- maxLength={256}
- name="key"
- onChange={this.handleKeyChange}
- type="text"
- size="full"
- value={key}
- />
- </FormField>
-
- <FormField label={translate('visibility')}>
- {[Visibility.Public, Visibility.Private].map((v) => (
- <RadioButton
- key={v}
- checked={visibility === v}
- value={v}
- onCheck={this.handleVisibilityChange}
- >
- {translate('visibility', v)}
- </RadioButton>
- ))}
- </FormField>
- </form>
- );
- };
-
- render() {
- const { submitting } = this.state;
- const header = translate('qualifiers.create.APP');
- const submitDisabled = !this.state.name.length;
-
- return (
- <Modal
- onClose={this.props.onClose}
- headerTitle={header}
- isScrollable
- loading={submitting}
- body={this.renderForm()}
- primaryButton={
- <ButtonSecondary
- disabled={submitting || submitDisabled}
- form="create-application-form"
- type="submit"
- >
- {translate('create')}
- </ButtonSecondary>
- }
- secondaryButtonLabel={translate('cancel')}
- />
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx b/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx
deleted file mode 100644
index c1da696ae96..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { withTheme } from '@emotion/react';
-import { QueryClient } from '@tanstack/react-query';
-import { isEqual } from 'lodash';
-import * as React from 'react';
-import { Helmet } from 'react-helmet-async';
-import { injectIntl, WrappedComponentProps } from 'react-intl';
-import { addGlobalErrorMessage, Theme } from '~design-system';
-import { withRouter } from '~sonar-aligned/components/hoc/withRouter';
-import { Location, Router } from '~sonar-aligned/types/router';
-import { getExtensionStart } from '../../../helpers/extensions';
-import { translate } from '../../../helpers/l10n';
-import { getCurrentL10nBundle } from '../../../helpers/l10nBundle';
-import { getBaseUrl } from '../../../helpers/system';
-import { withQueryClient } from '../../../queries/withQueryClientHoc';
-import { AppState } from '../../../types/appstate';
-import { ExtensionStartMethod } from '../../../types/extension';
-import { Dict, Extension as TypeExtension } from '../../../types/types';
-import { CurrentUser, HomePage } from '../../../types/users';
-import withAppStateContext from '../app-state/withAppStateContext';
-import withCurrentUserContext from '../current-user/withCurrentUserContext';
-
-export interface ExtensionProps extends WrappedComponentProps {
- appState: AppState;
- currentUser: CurrentUser;
- extension: TypeExtension;
- location: Location;
- options?: Dict<unknown>;
- queryClient: QueryClient;
- router: Router;
- theme: Theme;
- updateCurrentUserHomepage: (homepage: HomePage) => void;
-}
-
-interface State {
- extensionElement?: React.ReactElement<unknown>;
-}
-
-class Extension extends React.PureComponent<ExtensionProps, State> {
- container?: HTMLElement | null;
- state: State = {};
- stop?: Function;
-
- componentDidMount() {
- this.startExtension();
- }
-
- componentDidUpdate(prevProps: ExtensionProps) {
- if (prevProps.extension.key !== this.props.extension.key) {
- this.stopExtension();
- this.startExtension();
- } else if (!isEqual(prevProps.location, this.props.location)) {
- this.startExtension();
- }
- }
-
- componentWillUnmount() {
- this.stopExtension();
- }
-
- handleStart = (start: ExtensionStartMethod) => {
- const { theme, queryClient } = this.props;
-
- const result = start({
- appState: this.props.appState,
- baseUrl: getBaseUrl(),
- currentUser: this.props.currentUser,
- el: this.container,
- intl: this.props.intl,
- l10nBundle: getCurrentL10nBundle(),
- location: this.props.location,
- queryClient,
- router: this.props.router,
- theme,
- // See SONAR-16207 and core-extension-enterprise-server/src/main/js/portfolios/components/Header.tsx
- // for more information on why we're passing this as a prop to an extension.
- updateCurrentUserHomepage: this.props.updateCurrentUserHomepage,
- ...this.props.options,
- });
-
- if (result) {
- if (React.isValidElement(result)) {
- this.setState({ extensionElement: result });
- } else if (typeof result === 'function') {
- this.stop = result;
- }
- }
- };
-
- handleFailure = () => {
- addGlobalErrorMessage(translate('page_extension_failed'));
- };
-
- startExtension() {
- getExtensionStart(this.props.extension.key).then(this.handleStart, this.handleFailure);
- }
-
- stopExtension() {
- if (this.stop) {
- this.stop();
- this.stop = undefined;
- } else {
- this.setState({ extensionElement: undefined });
- }
- }
-
- render() {
- return (
- <div>
- <Helmet title={this.props.extension.name} />
-
- {this.state.extensionElement ? (
- this.state.extensionElement
- ) : (
- <div ref={(container) => (this.container = container)} />
- )}
- </div>
- );
- }
-}
-
-export default injectIntl(
- withRouter(withTheme(withAppStateContext(withCurrentUserContext(withQueryClient(Extension))))),
-);
diff --git a/server/sonar-web/src/main/js/app/components/extensions/GlobalAdminPageExtension.tsx b/server/sonar-web/src/main/js/app/components/extensions/GlobalAdminPageExtension.tsx
deleted file mode 100644
index 2e515670d2d..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/GlobalAdminPageExtension.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useOutletContext, useParams } from 'react-router-dom';
-import { AdminPagesContext } from '../../../types/admin';
-import NotFound from '../NotFound';
-import Extension from './Extension';
-
-export default function GlobalAdminPageExtension() {
- const { pluginKey, extensionKey } = useParams();
- const { adminPages } = useOutletContext<AdminPagesContext>();
-
- const extension = adminPages?.find((p) => p.key === `${pluginKey}/${extensionKey}`);
- return extension ? <Extension extension={extension} /> : <NotFound />;
-}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/GlobalPageExtension.tsx b/server/sonar-web/src/main/js/app/components/extensions/GlobalPageExtension.tsx
deleted file mode 100644
index ee5f63a37c9..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/GlobalPageExtension.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useParams } from 'react-router-dom';
-import { AppState } from '../../../types/appstate';
-import NotFound from '../NotFound';
-import withAppStateContext from '../app-state/withAppStateContext';
-import Extension from './Extension';
-
-export interface GlobalPageExtensionProps {
- appState: AppState;
- params?: {
- extensionKey: string;
- pluginKey: string;
- };
-}
-
-function GlobalPageExtension(props: GlobalPageExtensionProps) {
- const {
- appState: { globalPages },
- params,
- } = props;
- const { extensionKey, pluginKey } = useParams();
-
- const fullKey =
- params !== undefined
- ? `${params.pluginKey}/${params.extensionKey}`
- : `${pluginKey}/${extensionKey}`;
-
- const extension = globalPages?.find((p) => p.key === fullKey);
- return extension ? <Extension extension={extension} /> : <NotFound />;
-}
-
-export default withAppStateContext(GlobalPageExtension);
diff --git a/server/sonar-web/src/main/js/app/components/extensions/PortfolioPage.tsx b/server/sonar-web/src/main/js/app/components/extensions/PortfolioPage.tsx
deleted file mode 100644
index 1fec68bb9b9..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/PortfolioPage.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import ProjectPageExtension from './ProjectPageExtension';
-
-export default function PortfolioPage() {
- return <ProjectPageExtension params={{ pluginKey: 'governance', extensionKey: 'portfolio' }} />;
-}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/PortfoliosPage.tsx b/server/sonar-web/src/main/js/app/components/extensions/PortfoliosPage.tsx
deleted file mode 100644
index 0503ae98ab1..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/PortfoliosPage.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import GlobalPageExtension from './GlobalPageExtension';
-
-export default function PortfoliosPage() {
- return <GlobalPageExtension params={{ pluginKey: 'governance', extensionKey: 'portfolios' }} />;
-}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/ProjectAdminPageExtension.tsx b/server/sonar-web/src/main/js/app/components/extensions/ProjectAdminPageExtension.tsx
deleted file mode 100644
index f052ffba02c..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/ProjectAdminPageExtension.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { useParams } from 'react-router-dom';
-import { useRefreshBranches } from '../../../queries/branch';
-import NotFound from '../NotFound';
-import { ComponentContext } from '../componentContext/ComponentContext';
-import Extension from './Extension';
-
-export default function ProjectAdminPageExtension() {
- const { extensionKey, pluginKey } = useParams();
- const { component, onComponentChange } = React.useContext(ComponentContext);
-
- // We keep that for compatibility but ideally should advocate to use tanstack query
- const onBranchesChange = useRefreshBranches(component?.key);
-
- const extension = component?.configuration?.extensions?.find(
- (p) => p.key === `${pluginKey}/${extensionKey}`,
- );
-
- return extension ? (
- <Extension extension={extension} options={{ component, onComponentChange, onBranchesChange }} />
- ) : (
- <NotFound />
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/ProjectPageExtension.tsx b/server/sonar-web/src/main/js/app/components/extensions/ProjectPageExtension.tsx
deleted file mode 100644
index b290cf34b03..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/ProjectPageExtension.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { useParams } from 'react-router-dom';
-import { useCurrentBranchQuery } from '../../../queries/branch';
-import NotFound from '../NotFound';
-import { ComponentContext } from '../componentContext/ComponentContext';
-import Extension from './Extension';
-
-export interface ProjectPageExtensionProps {
- params?: {
- extensionKey: string;
- pluginKey: string;
- };
-}
-
-export default function ProjectPageExtension({ params }: ProjectPageExtensionProps) {
- const { extensionKey, pluginKey } = useParams();
- const { component } = React.useContext(ComponentContext);
- const { data: branchLike, isLoading } = useCurrentBranchQuery(component);
-
- if (component === undefined || isLoading) {
- return null;
- }
-
- const fullKey =
- params !== undefined
- ? `${params.pluginKey}/${params.extensionKey}`
- : `${pluginKey}/${extensionKey}`;
-
- const extension = component.extensions?.find((p) => p.key === fullKey);
- return extension ? (
- <Extension extension={extension} options={{ branchLike, component }} />
- ) : (
- <NotFound />
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/__tests__/Extension-test.tsx b/server/sonar-web/src/main/js/app/components/extensions/__tests__/Extension-test.tsx
deleted file mode 100644
index 1f5b09b60f7..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/__tests__/Extension-test.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen, waitFor } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { IntlShape } from 'react-intl';
-import { setImmediate } from 'timers';
-import { addGlobalErrorMessage, lightTheme } from '~design-system';
-import { getEnhancedWindow } from '../../../../helpers/browser';
-import { installExtensionsHandler } from '../../../../helpers/extensionsHandler';
-import {
- mockAppState,
- mockCurrentUser,
- mockLocation,
- mockRouter,
-} from '../../../../helpers/testMocks';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { ExtensionStartMethodParameter } from '../../../../types/extension';
-import Extension, { ExtensionProps } from '../Extension';
-
-jest.mock('~design-system', () => ({
- ...jest.requireActual('~design-system'),
- addGlobalErrorMessage: jest.fn(),
-}));
-
-beforeAll(() => {
- installExtensionsHandler();
-
- getEnhancedWindow().registerExtension(
- 'first-react-extension',
- ({ location, router }: ExtensionStartMethodParameter) => {
- const suffix = location.pathname === '/new' ? ' change' : '';
- const handleClick = () => {
- router.push('new');
- };
- return (
- <div>
- <button onClick={handleClick} type="button">
- Click first react{suffix}
- </button>
- </div>
- );
- },
- );
-
- getEnhancedWindow().registerExtension(
- 'not-react-extension',
- ({ el }: ExtensionStartMethodParameter) => {
- if (el) {
- el.innerHTML = '<button type="button">Click not react</button>';
- return () => {
- el.innerHTML = '';
- };
- }
- },
- );
-
- getEnhancedWindow().registerExtension('second-extension', () => {
- return (
- <div>
- <button type="button">Click second</button>
- </div>
- );
- });
-});
-
-it('should render React extensions correctly', async () => {
- const user = userEvent.setup();
- renderExtention();
-
- expect(await screen.findByRole('button', { name: 'Click first react' })).toBeInTheDocument();
-
- await user.click(screen.getByRole('button', { name: 'Click first react' }));
-
- expect(
- await screen.findByRole('button', { name: 'Click first react change' }),
- ).toBeInTheDocument();
-});
-
-it('should unmount an extension before starting a new one', async () => {
- const rerender = renderExtention();
- await screen.findByRole('button', { name: 'Click first react' });
-
- rerender({ extension: { key: 'not-react-extension', name: 'not-react-extension' } });
- expect(await screen.findByRole('button', { name: 'Click not react' })).toBeInTheDocument();
-
- rerender({ extension: { key: 'second-extension', name: 'second-extension' } });
- expect(await screen.findByRole('button', { name: 'Click second' })).toBeInTheDocument();
-});
-
-it('should warn when no extension found', async () => {
- renderExtention({ extension: { key: 'unknown', name: 'null' } });
-
- // JSDOM is not handling script loading so we need to simulate that.
- await waitFor(() => {
- // eslint-disable-next-line testing-library/no-node-access
- const script = document.querySelector('script');
- expect(script).toBeInTheDocument();
- script!.onload!(new Event(''));
- });
-
- await new Promise(setImmediate);
- expect(addGlobalErrorMessage).toHaveBeenCalled();
-});
-
-function renderExtention(props: Partial<ExtensionProps> = {}) {
- const originalProp = {
- theme: lightTheme,
- appState: mockAppState(),
- currentUser: mockCurrentUser(),
- extension: { key: 'first-react-extension', name: 'first-react-extension' },
- intl: {} as IntlShape,
- location: mockLocation(),
- router: mockRouter(),
- updateCurrentUserHomepage: jest.fn(),
- } as const;
- const { rerender } = renderComponent(<Extension {...originalProp} {...props} />);
-
- return (rerenderProp: Partial<ExtensionProps> = {}) => {
- rerender(<Extension {...originalProp} {...props} {...rerenderProp} />);
- };
-}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/__tests__/GlobalAdminPageExtension-test.tsx b/server/sonar-web/src/main/js/app/components/extensions/__tests__/GlobalAdminPageExtension-test.tsx
deleted file mode 100644
index 62bbb5f383c..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/__tests__/GlobalAdminPageExtension-test.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { Outlet, Route } from 'react-router-dom';
-import { renderAppRoutes } from '../../../../helpers/testReactTestingUtils';
-import { AdminPagesContext } from '../../../../types/admin';
-import { Extension } from '../../../../types/types';
-import GlobalAdminPageExtension from '../GlobalAdminPageExtension';
-
-jest.mock('../Extension', () => ({
- __esModule: true,
- default(props: { extension: { key: string; name: string } }) {
- return <h1>{props.extension.name}</h1>;
- },
-}));
-
-const extensions = [{ key: 'plugin123/ext42', name: 'extension 42' }];
-
-it('should find the extension from params', () => {
- renderGlobalAdminPageExtension('admin/extension/plugin123/ext42', extensions);
-
- expect(screen.getByText('extension 42')).toBeInTheDocument();
-});
-
-it('should notify if extension is not found', () => {
- renderGlobalAdminPageExtension('admin/extension/plugin123/wrong-extension', extensions);
-
- expect(screen.getByText('page_not_found')).toBeInTheDocument();
-});
-
-function renderGlobalAdminPageExtension(navigateTo: string, adminPages: Extension[] = []) {
- renderAppRoutes(
- `admin/extension/:pluginKey/:extensionKey`,
- () => (
- <Route path="admin" element={<Wrapper adminPages={adminPages} />}>
- <Route path="extension/:pluginKey/:extensionKey" element={<GlobalAdminPageExtension />} />
- </Route>
- ),
- {
- navigateTo,
- },
- );
-}
-
-function Wrapper(props: Readonly<AdminPagesContext>) {
- return <Outlet context={props} />;
-}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/__tests__/GlobalPageExtension-test.tsx b/server/sonar-web/src/main/js/app/components/extensions/__tests__/GlobalPageExtension-test.tsx
deleted file mode 100644
index 52eb9774ab7..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/__tests__/GlobalPageExtension-test.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { mockAppState } from '../../../../helpers/testMocks';
-import { renderApp } from '../../../../helpers/testReactTestingUtils';
-import { Extension } from '../../../../types/types';
-import GlobalPageExtension, { GlobalPageExtensionProps } from '../GlobalPageExtension';
-
-jest.mock('../Extension', () => ({
- __esModule: true,
- default(props: { extension: { key: string; name: string } }) {
- return <h1>{props.extension.name}</h1>;
- },
-}));
-
-const extensions = [{ key: 'plugin123/ext42', name: 'extension 42' }];
-
-it('should find the extension from params', () => {
- renderGlobalPageExtension('extension/plugin123/ext42', extensions);
-
- expect(screen.getByText('extension 42')).toBeInTheDocument();
-});
-
-it('should notify if extension is not found', () => {
- renderGlobalPageExtension('extension/plugin123/wrong-extension', extensions);
-
- expect(screen.getByText('page_not_found')).toBeInTheDocument();
-});
-
-it('should find the extension from props', () => {
- const params = { pluginKey: 'plugin123', extensionKey: 'ext42' };
-
- renderGlobalPageExtension('extension/whatever/overridden', extensions, params);
-
- expect(screen.getByText('extension 42')).toBeInTheDocument();
-});
-
-function renderGlobalPageExtension(
- navigateTo: string,
- globalPages: Extension[] = [],
- params?: GlobalPageExtensionProps['params'],
-) {
- renderApp(`extension/:pluginKey/:extensionKey`, <GlobalPageExtension params={params} />, {
- appState: mockAppState({ globalPages }),
- navigateTo,
- });
-}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/__tests__/ProjectAdminPageExtension-test.tsx b/server/sonar-web/src/main/js/app/components/extensions/__tests__/ProjectAdminPageExtension-test.tsx
deleted file mode 100644
index c94f760d7d1..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/__tests__/ProjectAdminPageExtension-test.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
-import { render, screen } from '@testing-library/react';
-import { HelmetProvider } from 'react-helmet-async';
-import { IntlProvider } from 'react-intl';
-import { MemoryRouter, Route, Routes } from 'react-router-dom';
-import { getExtensionStart } from '../../../../helpers/extensions';
-import { mockComponent } from '../../../../helpers/mocks/component';
-import { ComponentContextShape } from '../../../../types/component';
-import { Component } from '../../../../types/types';
-import { ComponentContext } from '../../componentContext/ComponentContext';
-import ProjectAdminPageExtension from '../ProjectAdminPageExtension';
-
-jest.mock('../../../../helpers/extensions', () => ({
- getExtensionStart: jest.fn().mockResolvedValue(jest.fn()),
-}));
-
-it('should render correctly when the extension is found', () => {
- renderProjectAdminPageExtension(
- mockComponent({
- configuration: { extensions: [{ key: 'pluginId/extensionId', name: 'name' }] },
- }),
- { pluginKey: 'pluginId', extensionKey: 'extensionId' },
- );
- expect(getExtensionStart).toHaveBeenCalledWith('pluginId/extensionId');
-});
-
-it('should render correctly when the extension is not found', () => {
- renderProjectAdminPageExtension(
- mockComponent({ extensions: [{ key: 'pluginId/extensionId', name: 'name' }] }),
- { pluginKey: 'not-found-plugin', extensionKey: 'not-found-extension' },
- );
- expect(screen.getByText('page_not_found')).toBeInTheDocument();
-});
-
-function renderProjectAdminPageExtension(
- component: Component,
- params: {
- extensionKey: string;
- pluginKey: string;
- },
-) {
- const { pluginKey, extensionKey } = params;
- const queryClient = new QueryClient();
- return render(
- <QueryClientProvider client={queryClient}>
- <HelmetProvider context={{}}>
- <IntlProvider defaultLocale="en" locale="en">
- <ComponentContext.Provider value={{ component } as ComponentContextShape}>
- <MemoryRouter initialEntries={[`/${pluginKey}/${extensionKey}`]}>
- <Routes>
- <Route path="/:pluginKey/:extensionKey" element={<ProjectAdminPageExtension />} />
- </Routes>
- </MemoryRouter>
- </ComponentContext.Provider>
- </IntlProvider>
- </HelmetProvider>
- </QueryClientProvider>,
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/__tests__/ProjectPageExtension-test.tsx b/server/sonar-web/src/main/js/app/components/extensions/__tests__/ProjectPageExtension-test.tsx
deleted file mode 100644
index bf2165c9532..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/__tests__/ProjectPageExtension-test.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
-import { render, screen, waitFor } from '@testing-library/react';
-import { HelmetProvider } from 'react-helmet-async';
-import { IntlProvider } from 'react-intl';
-import { MemoryRouter, Route, Routes } from 'react-router-dom';
-import BranchesServiceMock from '../../../../api/mocks/BranchesServiceMock';
-import { getExtensionStart } from '../../../../helpers/extensions';
-import { mockComponent } from '../../../../helpers/mocks/component';
-import { ComponentContextShape } from '../../../../types/component';
-import { Component } from '../../../../types/types';
-import { ComponentContext } from '../../componentContext/ComponentContext';
-import ProjectPageExtension, { ProjectPageExtensionProps } from '../ProjectPageExtension';
-
-jest.mock('../../../../helpers/extensions', () => ({
- getExtensionStart: jest.fn().mockResolvedValue(jest.fn()),
-}));
-
-const handler = new BranchesServiceMock();
-
-beforeEach(() => {
- handler.reset();
-});
-
-it('should not render when no component is passed', () => {
- renderProjectPageExtension();
- expect(screen.queryByText('page_not_found')).not.toBeInTheDocument();
- expect(getExtensionStart).not.toHaveBeenCalledWith('pluginId/extensionId');
-});
-
-it('should render correctly when the extension is found', async () => {
- renderProjectPageExtension(
- mockComponent({ extensions: [{ key: 'pluginId/extensionId', name: 'name' }] }),
- { params: { pluginKey: 'pluginId', extensionKey: 'extensionId' } },
- );
- await waitFor(() => expect(getExtensionStart).toHaveBeenCalledWith('pluginId/extensionId'));
-});
-
-it('should render correctly when the extension is not found', async () => {
- renderProjectPageExtension(
- mockComponent({ extensions: [{ key: 'pluginId/extensionId', name: 'name' }] }),
- { params: { pluginKey: 'not-found-plugin', extensionKey: 'not-found-extension' } },
- );
- expect(await screen.findByText('page_not_found')).toBeInTheDocument();
-});
-
-function renderProjectPageExtension(
- component?: Component,
- props?: Partial<ProjectPageExtensionProps>,
-) {
- const queryClient = new QueryClient();
- return render(
- <QueryClientProvider client={queryClient}>
- <HelmetProvider context={{}}>
- <IntlProvider defaultLocale="en" locale="en">
- <ComponentContext.Provider value={{ component } as ComponentContextShape}>
- <MemoryRouter initialEntries={[`/?id=${component?.key}`]}>
- <Routes>
- <Route
- path="*"
- element={
- <ProjectPageExtension
- params={{ extensionKey: 'extensionId', pluginKey: 'pluginId' }}
- {...props}
- />
- }
- />
- </Routes>
- </MemoryRouter>
- </ComponentContext.Provider>
- </IntlProvider>
- </HelmetProvider>
- </QueryClientProvider>,
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/__tests__/exposeLibraries-test.ts b/server/sonar-web/src/main/js/app/components/extensions/__tests__/exposeLibraries-test.ts
deleted file mode 100644
index e38b89f466e..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/__tests__/exposeLibraries-test.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import exposeLibraries from '../exposeLibraries';
-
-it('should register expected libraries to the window object', () => {
- exposeLibraries();
-
- const { SonarRequest, t, tp } = window as any;
-
- expect(SonarRequest).toBeDefined();
- expect(t).toBeDefined();
- expect(tp).toBeDefined();
-});
diff --git a/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts b/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts
deleted file mode 100644
index d831f918c36..00000000000
--- a/server/sonar-web/src/main/js/app/components/extensions/exposeLibraries.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { addGlobalSuccessMessage } from '~design-system';
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { getJSON } from '~sonar-aligned/helpers/request';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-import {
- get,
- getText,
- omitNil,
- parseError,
- post,
- postJSON,
- postJSONBody,
- request,
-} from '../../../helpers/request';
-
-const exposeLibraries = () => {
- const global = window as any;
-
- global.SonarRequest = {
- request,
- get,
- getJSON,
- getText,
- omitNil,
- parseError,
- post,
- postJSON,
- postJSONBody,
- throwGlobalError,
- addGlobalSuccessMessage,
- };
-
- global.t = translate;
- global.tp = translateWithParameters;
-};
-
-export default exposeLibraries;
diff --git a/server/sonar-web/src/main/js/app/components/global-search/GlobalSearch.tsx b/server/sonar-web/src/main/js/app/components/global-search/GlobalSearch.tsx
deleted file mode 100644
index 684ef20ec50..00000000000
--- a/server/sonar-web/src/main/js/app/components/global-search/GlobalSearch.tsx
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ButtonIcon, ButtonVariety, IconSearch, Text } from '@sonarsource/echoes-react';
-import { debounce, isEmpty, uniqBy } from 'lodash';
-import * as React from 'react';
-import { DropdownMenu, InputSearch, Popup, PopupZLevel } from '~design-system';
-import { withRouter } from '~sonar-aligned/components/hoc/withRouter';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { Router } from '~sonar-aligned/types/router';
-import { getSuggestions } from '../../../api/components';
-import FocusOutHandler from '../../../components/controls/FocusOutHandler';
-import OutsideClickHandler from '../../../components/controls/OutsideClickHandler';
-import { PopupPlacement } from '../../../components/ui/popups';
-import { isInput, isShortcut } from '../../../helpers/keyboardEventHelpers';
-import { KeyboardKeys } from '../../../helpers/keycodes';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { getKeyboardShortcutEnabled } from '../../../helpers/preferences';
-import { getComponentOverviewUrl } from '../../../helpers/urls';
-import { Dict } from '../../../types/types';
-import RecentHistory from '../RecentHistory';
-import GlobalSearchResult from './GlobalSearchResult';
-import GlobalSearchResults from './GlobalSearchResults';
-import { ComponentResult, More, Results, sortQualifiers } from './utils';
-
-interface Props {
- router: Router;
-}
-interface State {
- loading: boolean;
- loadingMore?: string;
- more: More;
- open: boolean;
- query: string;
- results: Results;
- selected?: string;
-}
-const MIN_SEARCH_QUERY_LENGTH = 2;
-
-export class GlobalSearch extends React.PureComponent<Props, State> {
- input?: HTMLInputElement | null;
- node?: HTMLElement | null;
- nodes: Dict<HTMLElement | undefined>;
- mounted = false;
-
- constructor(props: Props) {
- super(props);
- this.nodes = {};
- this.search = debounce(this.search, 250);
-
- this.state = {
- loading: false,
- more: {},
- open: false,
- query: '',
- results: {},
- };
- }
-
- componentDidMount() {
- this.mounted = true;
- document.addEventListener('keydown', this.handleSKeyDown);
- }
-
- componentDidUpdate(_prevProps: Props, prevState: State) {
- if (prevState.selected !== this.state.selected) {
- this.scrollToSelected();
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- document.removeEventListener('keydown', this.handleSKeyDown);
- }
-
- focusInput = () => {
- if (this.input) {
- this.input.focus();
- }
- };
-
- handleClickOutside = () => {
- this.closeSearch(false);
- };
-
- handleFocus = () => {
- if (!this.state.open) {
- // simulate click to close any other dropdowns
- document.documentElement.click();
- }
-
- this.openSearch();
- };
-
- openSearch = () => {
- if (!this.state.open && !this.state.query) {
- this.search('');
- }
-
- this.setState({ open: true });
- };
-
- closeSearch = (clear = true) => {
- if (this.input) {
- this.input.blur();
- }
-
- if (clear) {
- this.setState({
- more: {},
- open: false,
- query: '',
- results: {},
- selected: undefined,
- });
- } else {
- this.setState({ open: false });
- }
- };
-
- getPlainComponentsList = (results: Results, more: More) =>
- sortQualifiers(Object.keys(results)).reduce((components, qualifier) => {
- const next = [...components, ...(results[qualifier] ?? []).map((component) => component.key)];
- if (more[qualifier]) {
- next.push('qualifier###' + qualifier);
- }
-
- return next;
- }, []);
-
- stopLoading = () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- };
-
- search = (query: string) => {
- if (query.length === 0 || query.length >= MIN_SEARCH_QUERY_LENGTH) {
- this.setState({ loading: true });
- const recentlyBrowsed = RecentHistory.get().map((component) => component.key);
-
- getSuggestions(query, recentlyBrowsed).then((response) => {
- // compare `this.state.query` and `query` to handle two request done almost at the same time
- // in this case only the request that matches the current query should be taken
- if (this.mounted && this.state.query === query) {
- const results: Results = {};
- const more: More = {};
- this.nodes = {};
- response.results.forEach((group) => {
- results[group.q] = group.items.map((item) => ({ ...item, qualifier: group.q }));
- more[group.q] = group.more;
- });
- const list = this.getPlainComponentsList(results, more);
- this.setState({
- loading: false,
- more,
- results,
- selected: list.length > 0 ? list[0] : undefined,
- });
- }
- }, this.stopLoading);
- } else {
- this.setState({ loading: false });
- }
- };
-
- searchMore = (qualifier: string) => {
- const { query } = this.state;
-
- if (query.length === 1) {
- return;
- }
-
- this.setState({ loading: true, loadingMore: qualifier });
- const recentlyBrowsed = RecentHistory.get().map((component) => component.key);
-
- getSuggestions(query, recentlyBrowsed, qualifier).then((response) => {
- if (this.mounted) {
- const group = response.results.find((group) => group.q === qualifier);
- const moreResults = (group ? group.items : []).map((item) => ({ ...item, qualifier }));
-
- this.setState((state) => ({
- loading: false,
- loadingMore: undefined,
- more: { ...state.more, [qualifier]: 0 },
- results: {
- ...state.results,
- [qualifier]: uniqBy([...(state.results[qualifier] ?? []), ...moreResults], 'key'),
- },
- selected: moreResults.length > 0 ? moreResults[0].key : state.selected,
- }));
-
- this.focusInput();
- }
- }, this.stopLoading);
- };
-
- handleQueryChange = (query: string) => {
- this.setState({ query });
- this.search(query);
- };
-
- selectPrevious = () => {
- this.setState(({ more, results, selected }) => {
- if (selected) {
- const list = this.getPlainComponentsList(results, more);
- const index = list.indexOf(selected);
- return index > 0 ? { selected: list[index - 1] } : null;
- }
-
- return null;
- });
- };
-
- selectNext = () => {
- this.setState(({ more, results, selected }) => {
- if (selected) {
- const list = this.getPlainComponentsList(results, more);
- const index = list.indexOf(selected);
- return index >= 0 && index < list.length - 1 ? { selected: list[index + 1] } : null;
- }
-
- return null;
- });
- };
-
- openSelected = () => {
- const { results, selected } = this.state;
-
- if (!selected) {
- return;
- }
-
- if (selected.startsWith('qualifier###')) {
- this.searchMore(selected.substring('qualifier###'.length));
- } else {
- let qualifier = ComponentQualifier.Project;
-
- if ((results[ComponentQualifier.Portfolio] ?? []).find((r) => r.key === selected)) {
- qualifier = ComponentQualifier.Portfolio;
- } else if ((results[ComponentQualifier.SubPortfolio] ?? []).find((r) => r.key === selected)) {
- qualifier = ComponentQualifier.SubPortfolio;
- }
-
- this.props.router.push(getComponentOverviewUrl(selected, qualifier));
-
- this.closeSearch();
- }
- };
-
- scrollToSelected = () => {
- if (this.state.selected) {
- const node = this.nodes[this.state.selected];
-
- if (node && this.node) {
- node.scrollIntoView({
- block: 'center',
- behavior: 'smooth',
- });
- }
- }
- };
-
- handleSKeyDown = (event: KeyboardEvent) => {
- if (!getKeyboardShortcutEnabled() || isInput(event) || isShortcut(event)) {
- return true;
- }
-
- if (event.key === KeyboardKeys.KeyS) {
- event.preventDefault();
- this.focusInput();
- this.openSearch();
- }
- };
-
- handleKeyDown = (event: React.KeyboardEvent) => {
- if (!this.state.open) {
- return;
- }
-
- switch (event.key) {
- case KeyboardKeys.Enter:
- event.preventDefault();
- event.stopPropagation();
- this.openSelected();
- break;
- case KeyboardKeys.UpArrow:
- event.preventDefault();
- event.stopPropagation();
- this.selectPrevious();
- break;
- case KeyboardKeys.Escape:
- event.preventDefault();
- event.stopPropagation();
- this.closeSearch();
- break;
- case KeyboardKeys.DownArrow:
- event.preventDefault();
- event.stopPropagation();
- this.selectNext();
- break;
- }
- };
-
- handleSelect = (selected: string) => {
- this.setState({ selected });
- };
-
- innerRef = (component: string, node: HTMLElement | null) => {
- if (node) {
- this.nodes[component] = node;
- }
- };
-
- searchInputRef = (node: HTMLInputElement | null) => {
- this.input = node;
- };
-
- renderResult = (component: ComponentResult) => (
- <GlobalSearchResult
- component={component}
- innerRef={this.innerRef}
- key={component.key}
- onClose={this.closeSearch}
- onSelect={this.handleSelect}
- selected={this.state.selected === component.key}
- />
- );
-
- renderNoResults = () => (
- <div className="sw-px-3 sw-py-2">
- {translateWithParameters('no_results_for_x', this.state.query)}
- </div>
- );
-
- render() {
- const { open, query, results, more, loadingMore, selected, loading } = this.state;
-
- const list = this.getPlainComponentsList(results, more);
-
- const search = (
- <div className="sw-min-w-abs-200 sw-max-w-abs-350 sw-w-full">
- <Popup
- allowResizing
- overlay={
- open && (
- <DropdownMenu
- className="it__global-navbar-search-dropdown sw-overflow-y-auto sw-overflow-x-hidden"
- maxHeight="38rem"
- innerRef={(node: HTMLUListElement | null) => (this.node = node)}
- size="auto"
- aria-owns="global-search-input"
- >
- <GlobalSearchResults
- loading={loading}
- query={query}
- loadingMore={loadingMore}
- more={more}
- onMoreClick={this.searchMore}
- onSelect={this.handleSelect}
- renderNoResults={this.renderNoResults}
- renderResult={this.renderResult}
- results={results}
- selected={selected}
- />
- {list.length > 0 && (
- <li className="sw-px-3 sw-pt-1">
- <Text isSubdued>{translate('global_search.shortcut_hint')}</Text>
- </li>
- )}
- </DropdownMenu>
- )
- }
- placement={PopupPlacement.BottomLeft}
- zLevel={PopupZLevel.Global}
- >
- <InputSearch
- id="global-search-input"
- className="sw-w-full"
- autoFocus={open}
- innerRef={this.searchInputRef}
- loading={loading}
- minLength={MIN_SEARCH_QUERY_LENGTH}
- onChange={this.handleQueryChange}
- onFocus={this.handleFocus}
- onKeyDown={this.handleKeyDown}
- placeholder={translate('search.search_for_projects')}
- size="auto"
- value={query}
- searchInputAriaLabel={translate('search_verb')}
- />
- </Popup>
- </div>
- );
-
- return (
- <form role="search">
- {!open && isEmpty(query) ? (
- <ButtonIcon
- Icon={IconSearch}
- ariaLabel={translate('search_verb')}
- className="it__search-icon"
- onClick={this.handleFocus}
- variety={ButtonVariety.DefaultGhost}
- />
- ) : (
- <FocusOutHandler onFocusOut={this.handleClickOutside}>
- <OutsideClickHandler onClickOutside={this.handleClickOutside}>
- {search}
- </OutsideClickHandler>
- </FocusOutHandler>
- )}
- </form>
- );
- }
-}
-
-export default withRouter(GlobalSearch);
diff --git a/server/sonar-web/src/main/js/app/components/global-search/GlobalSearchResult.tsx b/server/sonar-web/src/main/js/app/components/global-search/GlobalSearchResult.tsx
deleted file mode 100644
index 8de9e756d0b..00000000000
--- a/server/sonar-web/src/main/js/app/components/global-search/GlobalSearchResult.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import * as React from 'react';
-import { ClockIcon, ItemLink, StarFillIcon, TextBold, TextMuted } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { getComponentOverviewUrl } from '../../../helpers/urls';
-import { ComponentResult } from './utils';
-
-interface Props {
- component: ComponentResult;
- innerRef: (componentKey: string, node: HTMLElement | null) => void;
- onClose: () => void;
- onSelect: (componentKey: string) => void;
- selected: boolean;
-}
-export default class GlobalSearchResult extends React.PureComponent<Props> {
- doSelect = () => {
- this.props.onSelect(this.props.component.key);
- };
-
- render() {
- const { component, selected } = this.props;
- const to = getComponentOverviewUrl(component.key, component.qualifier);
- return (
- <ItemLink
- className={classNames('sw-flex sw-flex-col sw-items-start sw-space-y-1', {
- active: selected,
- })}
- innerRef={(node: HTMLAnchorElement | null) => {
- this.props.innerRef(component.key, node);
- }}
- key={component.key}
- onClick={this.props.onClose}
- onPointerEnter={this.doSelect}
- to={to}
- >
- <div className="sw-flex sw-justify-between sw-items-center sw-w-full">
- <TextBold match={component.match} name={component.name} />
- <div className="sw-ml-2">
- {component.isFavorite && <StarFillIcon />}
- {!component.isFavorite && component.isRecentlyBrowsed && (
- <ClockIcon aria-label={translate('recently_browsed')} />
- )}
- </div>
- </div>
- <TextMuted text={component.key} />
- </ItemLink>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/app/components/global-search/GlobalSearchResults.tsx b/server/sonar-web/src/main/js/app/components/global-search/GlobalSearchResults.tsx
deleted file mode 100644
index 85d23c8a1d8..00000000000
--- a/server/sonar-web/src/main/js/app/components/global-search/GlobalSearchResults.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { useIntl } from 'react-intl';
-import { ItemDivider, ItemHeader } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import GlobalSearchShowMore from './GlobalSearchShowMore';
-import { ComponentResult, More, Results, sortQualifiers } from './utils';
-
-export interface Props {
- loading: boolean;
- loadingMore?: string;
- more: More;
- onMoreClick: (qualifier: string) => void;
- onSelect: (componentKey: string) => void;
- query: string;
- renderNoResults: () => React.ReactElement;
- renderResult: (component: ComponentResult) => React.ReactNode;
- results: Results;
- selected?: string;
-}
-
-export default function GlobalSearchResults(props: Props): React.ReactElement<Props> {
- const intl = useIntl();
- const qualifiers = Object.keys(props.results);
- const renderedComponents: React.ReactNode[] = [];
- const allowMore = props.query.length !== 1;
-
- sortQualifiers(qualifiers).forEach((qualifier) => {
- const components = props.results[qualifier];
-
- if (components?.length) {
- const more = props.more[qualifier];
-
- renderedComponents.push(
- <li key={`group-${qualifier}`}>
- <ul key={`header-${qualifier}`} aria-labelledby={translate('qualifiers', qualifier)}>
- <ItemHeader>
- <p id={translate('qualifiers', qualifier)}>{translate('qualifiers', qualifier)}</p>
- </ItemHeader>
- {components.map((component) => props.renderResult(component))}
- {more !== undefined && more > 0 && (
- <GlobalSearchShowMore
- allowMore={allowMore}
- key={`more-${qualifier}`}
- loadingMore={props.loadingMore}
- onMoreClick={props.onMoreClick}
- onSelect={props.onSelect}
- qualifier={qualifier}
- selected={props.selected === `qualifier###${qualifier}`}
- />
- )}
- <ItemDivider />
- </ul>
- </li>,
- );
- }
- });
-
- const resultCount = Object.values(props.results).reduce(
- (acc, components) => acc + (components?.length ?? 0),
- 0,
- );
-
- return (
- <>
- <output aria-busy={props.loading || Boolean(props.loadingMore)}>
- {renderedComponents.length === 0 && props.renderNoResults()}
- {renderedComponents.length > 0 && (
- <span className="sw-sr-only">
- {intl.formatMessage({ id: 'results_shown_x' }, { count: resultCount })}
- </span>
- )}
- </output>
- {renderedComponents.length > 0 && renderedComponents}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/global-search/GlobalSearchShowMore.tsx b/server/sonar-web/src/main/js/app/components/global-search/GlobalSearchShowMore.tsx
deleted file mode 100644
index af0e86c8514..00000000000
--- a/server/sonar-web/src/main/js/app/components/global-search/GlobalSearchShowMore.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Spinner } from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import * as React from 'react';
-import { ItemButton } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-
-interface Props {
- allowMore: boolean;
- loadingMore?: string;
- onMoreClick: (qualifier: string) => void;
- onSelect: (qualifier: string) => void;
- qualifier: string;
- selected: boolean;
-}
-
-export default class GlobalSearchShowMore extends React.PureComponent<Props> {
- handleMoreClick = (event: React.MouseEvent<HTMLButtonElement>, qualifier: string) => {
- event.preventDefault();
- event.stopPropagation();
- event.currentTarget.blur();
-
- if (qualifier !== '') {
- this.props.onMoreClick(qualifier);
- }
- };
-
- handleMouseEnter = (qualifier: string) => {
- if (qualifier !== '') {
- this.props.onSelect(`qualifier###${qualifier}`);
- }
- };
-
- render() {
- const { loadingMore, qualifier, selected, allowMore } = this.props;
-
- return (
- <ItemButton
- className={classNames({ active: selected })}
- disabled={!allowMore}
- onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
- this.handleMoreClick(e, qualifier);
- }}
- onPointerEnter={() => {
- this.handleMouseEnter(qualifier);
- }}
- >
- <Spinner isLoading={loadingMore === qualifier}>{translate('show_more')}</Spinner>
- </ItemButton>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/app/components/global-search/__tests__/GlobalSearch-it.tsx b/server/sonar-web/src/main/js/app/components/global-search/__tests__/GlobalSearch-it.tsx
deleted file mode 100644
index 37a2168210b..00000000000
--- a/server/sonar-web/src/main/js/app/components/global-search/__tests__/GlobalSearch-it.tsx
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { getSuggestions } from '../../../../api/components';
-import { mockRouter } from '../../../../helpers/testMocks';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import GlobalSearch, { GlobalSearch as GlobalSearchWithoutRouter } from '../GlobalSearch';
-
-jest.mock('../../../../api/components', () => ({
- getSuggestions: jest.fn().mockResolvedValue({
- results: [
- {
- q: 'TRK',
- more: 1,
- items: [
- {
- isFavorite: true,
- isRecentlyBrowsed: true,
- key: 'sonarqube',
- match: 'SonarQube',
- name: 'SonarQube',
- project: '',
- },
- {
- isFavorite: false,
- isRecentlyBrowsed: false,
- key: 'sonarcloud',
- match: 'Sonarcloud',
- name: 'Sonarcloud',
- project: '',
- },
- ],
- },
- ],
- }),
-}));
-
-const ui = {
- searchButton: byRole('button', { name: 'search_verb' }),
- searchInput: byRole('searchbox'),
- searchItemListWrapper: byRole('menu'),
- searchItem: byRole('menuitem'),
- showMoreButton: byRole('menuitem', { name: 'show_more' }),
- tooShortWarning: byText('select2.tooShort.2'),
- noResultTextABCD: byText('no_results_for_x.abcd'),
-};
-
-it('should show the input when user click on the search icon', async () => {
- const user = userEvent.setup();
- renderGlobalSearch();
-
- expect(ui.searchButton.get()).toBeInTheDocument();
- await user.click(ui.searchButton.get());
- expect(ui.searchInput.get()).toBeVisible();
- expect(ui.searchItemListWrapper.get()).toBeVisible();
-
- await user.click(document.body);
- expect(ui.searchInput.query()).not.toBeInTheDocument();
- expect(ui.searchItemListWrapper.query()).not.toBeInTheDocument();
-});
-
-it('selects the results', async () => {
- const user = userEvent.setup();
- renderGlobalSearch();
- await user.click(ui.searchButton.get());
-
- await user.click(ui.searchInput.get());
- await user.keyboard('son');
- expect(ui.searchItem.getAll()[1]).toHaveClass('active');
- expect(ui.searchItem.getAll()[1]).toHaveTextContent('SonarQubesonarqube');
-
- await user.keyboard('{arrowdown}');
- expect(ui.searchItem.getAll()[2]).toHaveClass('active');
- expect(ui.searchItem.getAll()[2]).toHaveTextContent('Sonarcloudsonarcloud');
-
- await user.keyboard('{arrowdown}');
- expect(ui.searchItem.getAll()[3]).toHaveClass('active');
- expect(ui.searchItem.getAll()[3]).toHaveTextContent('show_more');
-
- await user.keyboard('{arrowup}');
- expect(ui.searchItem.getAll()[2]).toHaveClass('active');
- expect(ui.searchItem.getAll()[2]).toHaveTextContent('Sonarcloudsonarcloud');
-
- await user.hover(ui.searchItem.getAll()[1]);
- expect(ui.searchItem.getAll()[1]).toHaveClass('active');
-
- await user.keyboard('{Escape}');
- expect(ui.searchInput.query()).not.toBeInTheDocument();
-});
-
-it('load more results', async () => {
- const user = userEvent.setup();
- renderGlobalSearch();
- await user.click(ui.searchButton.get());
- expect(getSuggestions).toHaveBeenCalledWith('', []);
-
- await user.click(ui.searchInput.get());
- await user.keyboard('foo');
- expect(getSuggestions).toHaveBeenLastCalledWith('foo', []);
-
- jest.mocked(getSuggestions).mockResolvedValueOnce({
- projects: [],
- results: [
- {
- items: [
- {
- isFavorite: false,
- isRecentlyBrowsed: false,
- key: 'bar',
- match: '<mark>Bar</mark>',
- name: 'Bar',
- project: 'bar',
- },
- ],
- more: 0,
- q: 'TRK',
- },
- ],
- });
-
- await user.click(ui.showMoreButton.get());
- expect(getSuggestions).toHaveBeenLastCalledWith('foo', [], 'TRK');
- expect(ui.searchItem.getAll()[3]).toHaveTextContent('Barbar');
-});
-
-it('shows warning about short input', async () => {
- const user = userEvent.setup();
- renderGlobalSearch();
- await user.click(ui.searchButton.get());
-
- await user.click(ui.searchInput.get());
- await user.keyboard('s');
- expect(ui.tooShortWarning.get()).toBeVisible();
-
- await user.keyboard('abc');
- expect(ui.tooShortWarning.query()).not.toBeInTheDocument();
-});
-
-it('should display no results message', async () => {
- const user = userEvent.setup();
- renderGlobalSearch();
- (getSuggestions as jest.Mock).mockResolvedValue({
- results: [
- {
- items: [],
- more: 0,
- q: 'TRK',
- },
- ],
- });
-
- await user.click(ui.searchButton.get());
-
- await user.click(ui.searchInput.get());
- await user.keyboard('abcd');
-
- expect(ui.noResultTextABCD.get()).toBeVisible();
-});
-
-it('should open selected', async () => {
- (getSuggestions as jest.Mock).mockResolvedValueOnce({
- results: [
- {
- items: [
- {
- isFavorite: true,
- isRecentlyBrowsed: true,
- key: 'sonarqube',
- match: 'SonarQube',
- name: 'SonarQube',
- project: '',
- },
- ],
- more: 0,
- q: 'TRK',
- },
- ],
- });
- const user = userEvent.setup();
- const router = mockRouter();
- renderComponent(<GlobalSearchWithoutRouter router={router} />);
- await user.click(ui.searchButton.get());
-
- await user.click(ui.searchInput.get());
- await user.keyboard('{arrowdown}');
- await user.keyboard('{enter}');
- expect(router.push).toHaveBeenCalledWith({
- pathname: '/dashboard',
- search: '?id=sonarqube',
- });
-});
-
-function renderGlobalSearch() {
- return renderComponent(<GlobalSearch />);
-}
diff --git a/server/sonar-web/src/main/js/app/components/global-search/utils.ts b/server/sonar-web/src/main/js/app/components/global-search/utils.ts
deleted file mode 100644
index 09df62cee9c..00000000000
--- a/server/sonar-web/src/main/js/app/components/global-search/utils.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { sortBy } from 'lodash';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-
-const ORDER = [
- ComponentQualifier.Portfolio,
- ComponentQualifier.SubPortfolio,
- ComponentQualifier.Application,
- ComponentQualifier.Project,
-];
-
-export function sortQualifiers(qualifiers: string[]) {
- return sortBy(qualifiers, (qualifier) => ORDER.indexOf(qualifier as ComponentQualifier));
-}
-
-export interface ComponentResult {
- isFavorite?: boolean;
- isRecentlyBrowsed?: boolean;
- key: string;
- match?: string;
- name: string;
- qualifier: string;
-}
-
-export interface Results {
- [qualifier: string]: ComponentResult[] | undefined;
-}
-
-export interface More {
- [qualifier: string]: number | undefined;
-}
diff --git a/server/sonar-web/src/main/js/app/components/indexation/IndexationContext.ts b/server/sonar-web/src/main/js/app/components/indexation/IndexationContext.ts
deleted file mode 100644
index e86ab2ea402..00000000000
--- a/server/sonar-web/src/main/js/app/components/indexation/IndexationContext.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { createContext } from 'react';
-import { IndexationContextInterface } from '../../../types/indexation';
-
-export const IndexationContext = createContext<IndexationContextInterface | null>(null);
diff --git a/server/sonar-web/src/main/js/app/components/indexation/IndexationContextProvider.tsx b/server/sonar-web/src/main/js/app/components/indexation/IndexationContextProvider.tsx
deleted file mode 100644
index 4160e67faa9..00000000000
--- a/server/sonar-web/src/main/js/app/components/indexation/IndexationContextProvider.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable react/no-unused-state */
-
-import * as React from 'react';
-import { AppState } from '../../../types/appstate';
-import { IndexationContextInterface, IndexationStatus } from '../../../types/indexation';
-import withAppStateContext from '../app-state/withAppStateContext';
-import { IndexationContext } from './IndexationContext';
-import IndexationNotificationHelper from './IndexationNotificationHelper';
-
-export interface IndexationContextProviderProps {
- appState: AppState;
-}
-
-export class IndexationContextProvider extends React.PureComponent<
- React.PropsWithChildren<IndexationContextProviderProps>,
- IndexationContextInterface
-> {
- mounted = false;
-
- componentDidMount() {
- this.mounted = true;
-
- if (this.props.appState.needIssueSync) {
- IndexationNotificationHelper.startPolling(this.handleNewStatus);
- } else {
- this.setState({
- status: { isCompleted: true, hasFailures: false },
- });
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
-
- IndexationNotificationHelper.stopPolling();
- }
-
- handleNewStatus = (newIndexationStatus: IndexationStatus) => {
- if (this.mounted) {
- this.setState({ status: newIndexationStatus });
- }
- };
-
- render() {
- return (
- <IndexationContext.Provider value={this.state}>
- {this.props.children}
- </IndexationContext.Provider>
- );
- }
-}
-
-export default withAppStateContext(IndexationContextProvider);
diff --git a/server/sonar-web/src/main/js/app/components/indexation/IndexationNotification.tsx b/server/sonar-web/src/main/js/app/components/indexation/IndexationNotification.tsx
deleted file mode 100644
index 00e1fb09675..00000000000
--- a/server/sonar-web/src/main/js/app/components/indexation/IndexationNotification.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { isBefore } from 'date-fns';
-import * as React from 'react';
-import withIndexationContext, {
- WithIndexationContextProps,
-} from '../../../components/hoc/withIndexationContext';
-import { hasGlobalPermission } from '../../../helpers/users';
-import { IndexationNotificationType } from '../../../types/indexation';
-import { Permissions } from '../../../types/permissions';
-import { CurrentUser, isLoggedIn } from '../../../types/users';
-import withAppStateContext, { WithAppStateContextProps } from '../app-state/withAppStateContext';
-import withCurrentUserContext from '../current-user/withCurrentUserContext';
-import IndexationNotificationHelper from './IndexationNotificationHelper';
-import IndexationNotificationRenderer from './IndexationNotificationRenderer';
-
-interface Props extends WithIndexationContextProps {
- currentUser: CurrentUser;
-}
-
-interface State {
- notificationType?: IndexationNotificationType;
- shouldDisplaySurveyLink: boolean;
-}
-
-type IndexationNotificationProps = Props & WithIndexationContextProps & WithAppStateContextProps;
-
-const SPRIG_SURVEY_LIMIT_DATE = new Date('2025-07-01T00:00:00+01:00');
-
-export class IndexationNotification extends React.PureComponent<
- IndexationNotificationProps,
- State
-> {
- state: State = {
- shouldDisplaySurveyLink: false,
- };
-
- isSystemAdmin = false;
-
- constructor(props: IndexationNotificationProps) {
- super(props);
-
- this.isSystemAdmin =
- isLoggedIn(this.props.currentUser) &&
- hasGlobalPermission(this.props.currentUser, Permissions.Admin);
- }
-
- componentDidMount() {
- this.refreshNotification();
- }
-
- componentDidUpdate(prevProps: Props) {
- if (prevProps.indexationContext.status !== this.props.indexationContext.status) {
- this.refreshNotification();
- }
- }
-
- dismissBanner = () => {
- this.setState({ notificationType: undefined });
- };
-
- refreshNotification() {
- const { isCompleted, hasFailures } = this.props.indexationContext.status;
-
- const currentSqsVersion = this.props.appState.version;
- this.setState({
- shouldDisplaySurveyLink:
- isBefore(new Date(), SPRIG_SURVEY_LIMIT_DATE) &&
- IndexationNotificationHelper.getLastIndexationSQSVersion() !== currentSqsVersion,
- });
-
- if (!isCompleted) {
- IndexationNotificationHelper.markCompletedNotificationAsToDisplay();
-
- this.setState({
- notificationType: hasFailures
- ? IndexationNotificationType.InProgressWithFailure
- : IndexationNotificationType.InProgress,
- });
-
- return;
- }
-
- IndexationNotificationHelper.saveLastIndexationSQSVersion(this.props.appState.version);
-
- if (hasFailures) {
- this.setState({ notificationType: IndexationNotificationType.CompletedWithFailure });
- return;
- }
-
- if (IndexationNotificationHelper.shouldDisplayCompletedNotification()) {
- this.setState({
- notificationType: IndexationNotificationType.Completed,
- });
-
- IndexationNotificationHelper.markCompletedNotificationAsDisplayed();
- return;
- }
-
- this.setState({ notificationType: undefined });
- }
-
- render() {
- const { notificationType, shouldDisplaySurveyLink } = this.state;
-
- const {
- indexationContext: {
- status: { completedCount, total },
- },
- } = this.props;
-
- return !this.isSystemAdmin ? null : (
- <IndexationNotificationRenderer
- completedCount={completedCount}
- onDismissBanner={this.dismissBanner}
- shouldDisplaySurveyLink={shouldDisplaySurveyLink}
- total={total}
- type={notificationType}
- />
- );
- }
-}
-
-export default withCurrentUserContext(
- withIndexationContext(withAppStateContext(IndexationNotification)),
-);
diff --git a/server/sonar-web/src/main/js/app/components/indexation/IndexationNotificationHelper.ts b/server/sonar-web/src/main/js/app/components/indexation/IndexationNotificationHelper.ts
deleted file mode 100644
index ffe785edb03..00000000000
--- a/server/sonar-web/src/main/js/app/components/indexation/IndexationNotificationHelper.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getIndexationStatus } from '../../../api/ce';
-import { get, remove, save } from '../../../helpers/storage';
-import { IndexationStatus } from '../../../types/indexation';
-
-const POLLING_INTERVAL_MS = 5000;
-const LS_INDEXATION_COMPLETED_NOTIFICATION_SHOULD_BE_DISPLAYED =
- 'display_indexation_completed_notification';
-const LS_LAST_INDEXATION_SQS_VERSION = 'last_indexation_sqs_version';
-
-export default class IndexationNotificationHelper {
- private static interval?: NodeJS.Timeout;
-
- static async startPolling(onNewStatus: (status: IndexationStatus) => void) {
- this.stopPolling();
-
- const status = await this.poll(onNewStatus);
-
- if (!status.isCompleted) {
- this.interval = setInterval(() => {
- this.poll(onNewStatus).catch(() => {
- /* noop */
- });
- }, POLLING_INTERVAL_MS);
- }
- }
-
- static stopPolling() {
- if (this.interval) {
- clearInterval(this.interval);
- }
- }
-
- static async poll(onNewStatus: (status: IndexationStatus) => void) {
- const status = await getIndexationStatus();
-
- onNewStatus(status);
-
- if (status.isCompleted) {
- this.stopPolling();
- }
-
- return status;
- }
-
- static markCompletedNotificationAsToDisplay() {
- save(LS_INDEXATION_COMPLETED_NOTIFICATION_SHOULD_BE_DISPLAYED, true.toString());
- }
-
- static markCompletedNotificationAsDisplayed() {
- remove(LS_INDEXATION_COMPLETED_NOTIFICATION_SHOULD_BE_DISPLAYED);
- }
-
- static shouldDisplayCompletedNotification() {
- return JSON.parse(
- get(LS_INDEXATION_COMPLETED_NOTIFICATION_SHOULD_BE_DISPLAYED) ?? false.toString(),
- );
- }
-
- static saveLastIndexationSQSVersion(version: string) {
- save(LS_LAST_INDEXATION_SQS_VERSION, version);
- }
-
- static getLastIndexationSQSVersion() {
- return get(LS_LAST_INDEXATION_SQS_VERSION);
- }
-}
diff --git a/server/sonar-web/src/main/js/app/components/indexation/IndexationNotificationRenderer.tsx b/server/sonar-web/src/main/js/app/components/indexation/IndexationNotificationRenderer.tsx
deleted file mode 100644
index 2bddeadc942..00000000000
--- a/server/sonar-web/src/main/js/app/components/indexation/IndexationNotificationRenderer.tsx
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable react/no-unused-prop-types */
-import styled from '@emotion/styled';
-import {
- IconCheckCircle,
- IconError,
- IconWarning,
- IconX,
- Link,
- LinkHighlight,
- Spinner,
-} from '@sonarsource/echoes-react';
-import { FormattedMessage, useIntl } from 'react-intl';
-import { InteractiveIconBase, ThemeColors, themeBorder, themeColor } from '~design-system';
-import { queryToSearchString } from '~sonar-aligned/helpers/urls';
-import DocumentationLink from '../../../components/common/DocumentationLink';
-import { DocLink } from '../../../helpers/doc-links';
-import { translate } from '../../../helpers/l10n';
-import { IndexationNotificationType } from '../../../types/indexation';
-import { TaskStatuses, TaskTypes } from '../../../types/tasks';
-
-interface IndexationNotificationRendererProps {
- completedCount?: number;
- onDismissBanner: () => void;
- shouldDisplaySurveyLink: boolean;
- total?: number;
- type?: IndexationNotificationType;
-}
-
-const NOTIFICATION_COLORS: {
- [key in IndexationNotificationType]: { background: ThemeColors; border: ThemeColors };
-} = {
- [IndexationNotificationType.InProgress]: {
- background: 'warningBackground',
- border: 'warningBorder',
- },
- [IndexationNotificationType.InProgressWithFailure]: {
- background: 'errorBackground',
- border: 'errorBorder',
- },
- [IndexationNotificationType.Completed]: {
- background: 'successBackground',
- border: 'successBorder',
- },
- [IndexationNotificationType.CompletedWithFailure]: {
- background: 'errorBackground',
- border: 'errorBorder',
- },
-};
-
-const SPRIG_SURVEY_LINK =
- 'https://a.sprig.com/U1h4UFpySUNwN2ZtfnNpZDowNWUyNmRkZC01MmUyLTQ4OGItOTA3ZC05M2VjYjQxZTYzN2Y=';
-
-export default function IndexationNotificationRenderer(
- props: Readonly<IndexationNotificationRendererProps>,
-) {
- const { type } = props;
-
- return (
- <div className={type === undefined ? 'sw-hidden' : ''}>
- <StyledBanner
- className="sw-typo-default sw-py-3 sw-px-4 sw-gap-4"
- type={type ?? IndexationNotificationType.Completed}
- aria-live="assertive"
- role="alert"
- >
- <IndexationStatusIcon type={type} />
- <IndexationBanner {...props} />
- </StyledBanner>
- </div>
- );
-}
-
-function IndexationStatusIcon(props: Readonly<{ type?: IndexationNotificationType }>) {
- const { type } = props;
-
- switch (type) {
- case IndexationNotificationType.Completed:
- return <IconCheckCircle color="echoes-color-icon-success" />;
- case IndexationNotificationType.CompletedWithFailure:
- case IndexationNotificationType.InProgressWithFailure:
- return <IconError color="echoes-color-icon-danger" />;
- case IndexationNotificationType.InProgress:
- return <IconWarning color="echoes-color-icon-warning" />;
- default:
- return null;
- }
-}
-
-function IndexationBanner(props: Readonly<IndexationNotificationRendererProps>) {
- const { completedCount, onDismissBanner, shouldDisplaySurveyLink, total, type } = props;
-
- switch (type) {
- case IndexationNotificationType.Completed:
- return (
- <CompletedBanner
- onDismissBanner={onDismissBanner}
- shouldDisplaySurveyLink={shouldDisplaySurveyLink}
- />
- );
- case IndexationNotificationType.CompletedWithFailure:
- return <CompletedWithFailureBanner shouldDisplaySurveyLink={shouldDisplaySurveyLink} />;
- case IndexationNotificationType.InProgress:
- return <InProgressBanner completedCount={completedCount as number} total={total as number} />;
- case IndexationNotificationType.InProgressWithFailure:
- return (
- <InProgressWithFailureBanner
- completedCount={completedCount as number}
- total={total as number}
- />
- );
- default:
- return null;
- }
-}
-
-function SurveyLink() {
- return (
- <span className="sw-ml-2">
- <FormattedMessage
- id="indexation.upgrade_survey_link"
- values={{
- link: (text) => (
- <Link highlight={LinkHighlight.Default} shouldOpenInNewTab to={SPRIG_SURVEY_LINK}>
- {text}
- </Link>
- ),
- }}
- />
- </span>
- );
-}
-
-function CompletedBanner(
- props: Readonly<{ onDismissBanner: () => void; shouldDisplaySurveyLink: boolean }>,
-) {
- const { onDismissBanner, shouldDisplaySurveyLink } = props;
-
- const intl = useIntl();
-
- return (
- <div className="sw-flex sw-flex-1 sw-items-center">
- <FormattedMessage id="indexation.completed" />
- {shouldDisplaySurveyLink && <SurveyLink />}
- <div className="sw-flex sw-flex-1 sw-justify-end">
- <BannerDismissIcon
- className="sw-ml-2 sw-px-1/2"
- Icon={IconX}
- aria-label={intl.formatMessage({ id: 'dismiss' })}
- onClick={onDismissBanner}
- size="small"
- />
- </div>
- </div>
- );
-}
-
-function CompletedWithFailureBanner(props: Readonly<{ shouldDisplaySurveyLink: boolean }>) {
- const { shouldDisplaySurveyLink } = props;
-
- const { formatMessage } = useIntl();
-
- return (
- <span>
- <FormattedMessage
- defaultMessage={translate('indexation.completed_with_error')}
- id="indexation.completed_with_error"
- values={{
- link: (
- <BackgroundTasksPageLink
- hasError
- text={formatMessage({ id: 'indexation.completed_with_error.link' })}
- />
- ),
- }}
- />
- {shouldDisplaySurveyLink && <SurveyLink />}
- </span>
- );
-}
-
-function InProgressBanner(props: Readonly<{ completedCount: number; total: number }>) {
- const { completedCount, total } = props;
-
- const { formatMessage } = useIntl();
-
- return (
- <>
- <span>
- <FormattedMessage id="indexation.in_progress" />{' '}
- <FormattedMessage
- id="indexation.features_partly_available"
- values={{
- link: <IndexationDocPageLink />,
- }}
- />
- </span>
-
- <span className="sw-flex sw-items-center">
- <Spinner className="sw-mr-1 -sw-mb-1/2" />
- <FormattedMessage
- id="indexation.progression"
- values={{
- count: completedCount,
- total,
- }}
- />
- </span>
-
- <span>
- <FormattedMessage
- id="indexation.admin_link"
- values={{
- link: (
- <BackgroundTasksPageLink
- hasError={false}
- text={formatMessage({ id: 'background_tasks.page' })}
- />
- ),
- }}
- />
- </span>
- </>
- );
-}
-
-function InProgressWithFailureBanner(props: Readonly<{ completedCount: number; total: number }>) {
- const { completedCount, total } = props;
-
- const { formatMessage } = useIntl();
-
- return (
- <>
- <span>
- <FormattedMessage id="indexation.in_progress" />{' '}
- <FormattedMessage
- id="indexation.features_partly_available"
- values={{
- link: <IndexationDocPageLink />,
- }}
- />
- </span>
-
- <span className="sw-flex sw-items-center">
- <Spinner className="sw-mr-1 -sw-mb-1/2" />
- <FormattedMessage
- tagName="span"
- id="indexation.progression_with_error"
- values={{
- count: completedCount,
- total,
- link: (
- <BackgroundTasksPageLink
- hasError
- text={formatMessage({ id: 'indexation.progression_with_error.link' })}
- />
- ),
- }}
- />
- </span>
- </>
- );
-}
-
-function BackgroundTasksPageLink(props: Readonly<{ hasError: boolean; text: string }>) {
- const { hasError, text } = props;
-
- return (
- <Link
- to={{
- pathname: '/admin/background_tasks',
- search: queryToSearchString({
- taskType: TaskTypes.IssueSync,
- status: hasError ? TaskStatuses.Failed : undefined,
- }),
- }}
- >
- {text}
- </Link>
- );
-}
-
-function IndexationDocPageLink() {
- return (
- <DocumentationLink className="sw-whitespace-nowrap" to={DocLink.InstanceAdminReindexation}>
- <FormattedMessage id="indexation.features_partly_available.link" />
- </DocumentationLink>
- );
-}
-
-const StyledBanner = styled.div<{ type: IndexationNotificationType }>`
- display: flex;
- align-items: center;
- box-sizing: border-box;
- width: 100%;
-
- background-color: ${({ type }) => themeColor(NOTIFICATION_COLORS[type].background)};
- border-bottom: ${({ type }) => themeBorder('default', NOTIFICATION_COLORS[type].border)};
-`;
-
-// There's currently no banner in Echoes so let's use the legacy design-system components for now
-const BannerDismissIcon = styled(InteractiveIconBase)`
- --background: ${themeColor('successBackground')};
- --backgroundHover: ${themeColor('successText', 0.1)};
- --color: ${themeColor('successText')};
- --colorHover: ${themeColor('successText')};
- --focus: ${themeColor('bannerIconFocus', 0.2)};
-`;
diff --git a/server/sonar-web/src/main/js/app/components/indexation/PageUnavailableDueToIndexation.tsx b/server/sonar-web/src/main/js/app/components/indexation/PageUnavailableDueToIndexation.tsx
deleted file mode 100644
index 7b06d3ddcd5..00000000000
--- a/server/sonar-web/src/main/js/app/components/indexation/PageUnavailableDueToIndexation.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { CenteredLayout, FlagMessage, Link } from '~design-system';
-import withIndexationContext, {
- WithIndexationContextProps,
-} from '../../../components/hoc/withIndexationContext';
-
-export class PageUnavailableDueToIndexation extends React.PureComponent<WithIndexationContextProps> {
- componentDidUpdate() {
- if (
- this.props.indexationContext.status.isCompleted &&
- !this.props.indexationContext.status.hasFailures
- ) {
- window.location.reload();
- }
- }
-
- render() {
- return (
- <CenteredLayout className="sw-flex sw-justify-around">
- <FlagMessage className="sw-mt-32" variant="info">
- <span className="sw-w-[290px]">
- <FormattedMessage id="indexation.page_unavailable.description" />
- <span className="sw-ml-1">
- <FormattedMessage
- id="indexation.page_unavailable.description.additional_information"
- values={{
- link: (
- <Link to="https://docs.sonarsource.com/sonarqube/latest/instance-administration/reindexing/">
- <FormattedMessage id="learn_more" />
- </Link>
- ),
- }}
- />
- </span>
- </span>
- </FlagMessage>
- </CenteredLayout>
- );
- }
-}
-
-export default withIndexationContext(PageUnavailableDueToIndexation);
diff --git a/server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationContextProvider-test.tsx b/server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationContextProvider-test.tsx
deleted file mode 100644
index 13b7b53b5ac..00000000000
--- a/server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationContextProvider-test.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { waitFor } from '@testing-library/react';
-import { useContext } from 'react';
-import { byText } from '~sonar-aligned/helpers/testSelector';
-import { mockAppState } from '../../../../helpers/testMocks';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { IndexationStatus } from '../../../../types/indexation';
-import { IndexationContext } from '../IndexationContext';
-import {
- IndexationContextProvider,
- IndexationContextProviderProps,
-} from '../IndexationContextProvider';
-import IndexationNotificationHelper from '../IndexationNotificationHelper';
-
-beforeEach(() => jest.clearAllMocks());
-
-jest.mock('../IndexationNotificationHelper');
-
-it('should render correctly, start polling if issue sync is needed and stop when unmounted', () => {
- const { unmount } = renderIndexationContextProvider();
- expect(IndexationNotificationHelper.startPolling).toHaveBeenCalled();
- unmount();
- expect(IndexationNotificationHelper.stopPolling).toHaveBeenCalled();
-});
-
-it('should not start polling if no issue sync is needed', () => {
- const appState = mockAppState({ needIssueSync: false });
- renderIndexationContextProvider({ appState });
- expect(IndexationNotificationHelper.startPolling).not.toHaveBeenCalled();
-});
-
-it('should update the state on new status', async () => {
- renderIndexationContextProvider();
-
- const triggerNewStatus = jest.mocked(IndexationNotificationHelper.startPolling).mock
- .calls[0][0] as (status: IndexationStatus) => void;
-
- const newStatus: IndexationStatus = {
- hasFailures: false,
- isCompleted: true,
- };
-
- expect(byText('null').get()).toBeInTheDocument();
-
- await waitFor(() => {
- triggerNewStatus(newStatus);
- });
- expect(byText('{"status":{"hasFailures":false,"isCompleted":true}}').get()).toBeInTheDocument();
-});
-
-function renderIndexationContextProvider(props?: IndexationContextProviderProps) {
- return renderComponent(
- <IndexationContextProvider appState={mockAppState({ needIssueSync: true, ...props?.appState })}>
- <TestComponent />
- </IndexationContextProvider>,
- );
-}
-
-function TestComponent() {
- const state = useContext(IndexationContext);
- return <div>{JSON.stringify(state)}</div>;
-}
diff --git a/server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationNotification-test.tsx b/server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationNotification-test.tsx
deleted file mode 100644
index ab005ef0d4a..00000000000
--- a/server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationNotification-test.tsx
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { mockAppState, mockCurrentUser, mockLoggedInUser } from '../../../../helpers/testMocks';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { Permissions } from '../../../../types/permissions';
-import { IndexationNotification } from '../IndexationNotification';
-import IndexationNotificationHelper from '../IndexationNotificationHelper';
-
-beforeEach(() => jest.clearAllMocks());
-
-jest.mock('../IndexationNotificationHelper');
-
-describe('Completed banner', () => {
- it('should be displayed and call helper when updated', () => {
- jest
- .mocked(IndexationNotificationHelper.shouldDisplayCompletedNotification)
- .mockReturnValueOnce(true);
-
- const { rerender } = renderIndexationNotification();
-
- rerender(
- <IndexationNotification
- appState={mockAppState()}
- currentUser={mockCurrentUser()}
- indexationContext={{
- status: { completedCount: 23, hasFailures: false, isCompleted: true, total: 42 },
- }}
- />,
- );
-
- expect(IndexationNotificationHelper.shouldDisplayCompletedNotification).toHaveBeenCalled();
- });
-
- it('should be displayed at startup', () => {
- jest
- .mocked(IndexationNotificationHelper.shouldDisplayCompletedNotification)
- .mockReturnValueOnce(true);
-
- renderIndexationNotification({
- indexationContext: {
- status: { hasFailures: false, isCompleted: true },
- },
- });
-
- expect(IndexationNotificationHelper.shouldDisplayCompletedNotification).toHaveBeenCalled();
- });
-
- it('should start progress > progress with failure > complete with failure', () => {
- const { rerender } = renderIndexationNotification({
- indexationContext: {
- status: { completedCount: 23, hasFailures: false, isCompleted: false, total: 42 },
- },
- });
-
- expect(byText('indexation.progression2342').get()).toBeInTheDocument();
-
- rerender(
- <IndexationNotification
- appState={mockAppState()}
- currentUser={mockLoggedInUser({ permissions: { global: [Permissions.Admin] } })}
- indexationContext={{
- status: { completedCount: 23, hasFailures: true, isCompleted: false, total: 42 },
- }}
- />,
- );
-
- expect(byText(/^indexation\.progression_with_error\.link/).get()).toBeInTheDocument();
-
- rerender(
- <IndexationNotification
- appState={mockAppState()}
- currentUser={mockLoggedInUser({ permissions: { global: [Permissions.Admin] } })}
- indexationContext={{
- status: { completedCount: 23, hasFailures: true, isCompleted: true, total: 42 },
- }}
- />,
- );
- expect(byText('indexation.completed_with_error').get()).toBeInTheDocument();
- });
-
- it('should start progress > success > disappear', () => {
- const { rerender } = renderIndexationNotification({
- indexationContext: {
- status: { completedCount: 23, hasFailures: false, isCompleted: false, total: 42 },
- },
- });
-
- expect(byText('indexation.progression2342').get()).toBeInTheDocument();
-
- rerender(
- <IndexationNotification
- appState={mockAppState()}
- currentUser={mockLoggedInUser({ permissions: { global: [Permissions.Admin] } })}
- indexationContext={{
- status: { completedCount: 23, hasFailures: false, isCompleted: true, total: 42 },
- }}
- />,
- );
- expect(IndexationNotificationHelper.shouldDisplayCompletedNotification).toHaveBeenCalled();
- });
-
- it('should show survey link when indexation follows an upgrade', () => {
- jest
- .mocked(IndexationNotificationHelper.shouldDisplayCompletedNotification)
- .mockReturnValueOnce(true);
- jest
- .mocked(IndexationNotificationHelper.getLastIndexationSQSVersion)
- .mockReturnValueOnce('11.0');
-
- const { rerender } = renderIndexationNotification({
- appState: mockAppState({ version: '12.0' }),
- indexationContext: {
- status: { completedCount: 42, hasFailures: false, isCompleted: true, total: 42 },
- },
- });
-
- expect(byText('indexation.upgrade_survey_link').get()).toBeInTheDocument();
-
- rerender(
- <IndexationNotification
- appState={mockAppState({ version: '12.0' })}
- currentUser={mockLoggedInUser({ permissions: { global: [Permissions.Admin] } })}
- indexationContext={{
- status: { completedCount: 23, hasFailures: true, isCompleted: true, total: 42 },
- }}
- />,
- );
-
- expect(byText('indexation.upgrade_survey_link').get()).toBeInTheDocument();
- });
-
- it('should not show survey link when indexation does not follow an upgrade', () => {
- jest
- .mocked(IndexationNotificationHelper.shouldDisplayCompletedNotification)
- .mockReturnValueOnce(true);
- jest
- .mocked(IndexationNotificationHelper.getLastIndexationSQSVersion)
- .mockReturnValueOnce('12.0');
-
- const { rerender } = renderIndexationNotification({
- appState: mockAppState({ version: '12.0' }),
- indexationContext: {
- status: { completedCount: 42, hasFailures: false, isCompleted: true, total: 42 },
- },
- });
-
- expect(byRole('indexation.upgrade_survey_link').query()).not.toBeInTheDocument();
-
- rerender(
- <IndexationNotification
- appState={mockAppState({ version: '12.0' })}
- currentUser={mockLoggedInUser({ permissions: { global: [Permissions.Admin] } })}
- indexationContext={{
- status: { completedCount: 23, hasFailures: true, isCompleted: true, total: 42 },
- }}
- />,
- );
-
- expect(byRole('indexation.upgrade_survey_link').query()).not.toBeInTheDocument();
- });
-
- it('should not see notification if not admin', () => {
- renderIndexationNotification({
- indexationContext: {
- status: { completedCount: 23, hasFailures: false, isCompleted: false, total: 42 },
- },
- currentUser: mockLoggedInUser(),
- });
-
- expect(byText('indexation.progression2342').query()).not.toBeInTheDocument();
- });
-});
-
-function renderIndexationNotification(props?: Partial<IndexationNotification['props']>) {
- return renderComponent(
- <IndexationNotification
- appState={mockAppState()}
- currentUser={mockLoggedInUser({ permissions: { global: [Permissions.Admin] } })}
- indexationContext={{
- status: { completedCount: 23, hasFailures: false, isCompleted: false, total: 42 },
- }}
- {...props}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationNotificationHelper-test.tsx b/server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationNotificationHelper-test.tsx
deleted file mode 100644
index ee35ded4da1..00000000000
--- a/server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationNotificationHelper-test.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { setImmediate } from 'timers';
-import { getIndexationStatus } from '../../../../api/ce';
-import { get, remove, save } from '../../../../helpers/storage';
-import { IndexationStatus } from '../../../../types/indexation';
-import IndexationNotificationHelper from '../IndexationNotificationHelper';
-
-beforeEach(() => {
- jest.clearAllMocks();
- jest.useFakeTimers();
-});
-
-afterEach(() => {
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
-});
-
-jest.mock('../../../../api/ce', () => ({
- getIndexationStatus: jest.fn().mockResolvedValue({}),
-}));
-
-jest.mock('../../../../helpers/storage', () => ({
- get: jest.fn(),
- remove: jest.fn(),
- save: jest.fn(),
-}));
-
-it('should properly start & stop polling for indexation status', async () => {
- const onNewStatus = jest.fn();
-
- const newStatus: IndexationStatus = {
- completedCount: 23,
- hasFailures: false,
- isCompleted: false,
- total: 42,
- };
-
- jest.mocked(getIndexationStatus).mockResolvedValueOnce(newStatus);
-
- IndexationNotificationHelper.startPolling(onNewStatus);
- expect(getIndexationStatus).toHaveBeenCalled();
-
- await new Promise(setImmediate);
- expect(onNewStatus).toHaveBeenCalledWith(newStatus);
-
- jest.runOnlyPendingTimers();
- expect(getIndexationStatus).toHaveBeenCalledTimes(2);
-
- jest.mocked(getIndexationStatus).mockClear();
-
- IndexationNotificationHelper.stopPolling();
- jest.runAllTimers();
-
- expect(getIndexationStatus).not.toHaveBeenCalled();
-});
-
-it('should properly handle the flag to show the completed banner', () => {
- IndexationNotificationHelper.markCompletedNotificationAsToDisplay();
-
- expect(save).toHaveBeenCalledWith(expect.any(String), 'true');
-
- jest.mocked(get).mockReturnValueOnce('true');
- let shouldDisplay = IndexationNotificationHelper.shouldDisplayCompletedNotification();
-
- expect(shouldDisplay).toBe(true);
- expect(get).toHaveBeenCalled();
-
- IndexationNotificationHelper.markCompletedNotificationAsDisplayed();
-
- expect(remove).toHaveBeenCalled();
-
- shouldDisplay = IndexationNotificationHelper.shouldDisplayCompletedNotification();
-
- expect(shouldDisplay).toBe(false);
-});
diff --git a/server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationNotificationRenderer-test.tsx b/server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationNotificationRenderer-test.tsx
deleted file mode 100644
index e57085f14b2..00000000000
--- a/server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationNotificationRenderer-test.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { IndexationNotificationType } from '../../../../types/indexation';
-import IndexationNotificationRenderer from '../IndexationNotificationRenderer';
-
-describe('Indexation notification renderer', () => {
- const ui = {
- inProgressText: byText(/indexation.in_progress\s*indexation.features_partly_available/),
- completedText: byText('indexation.completed'),
- completedWithFailures: byText('indexation.completed_with_error'),
- docLink: byRole('link', { name: /indexation.features_partly_available.link/ }),
- };
-
- it('should display "In progress" status', () => {
- renderIndexationNotificationRenderer(IndexationNotificationType.InProgress);
-
- expect(ui.inProgressText.get()).toBeInTheDocument();
- expect(ui.docLink.get()).toBeInTheDocument();
- });
-
- it('should display "In progress with failures" status', () => {
- renderIndexationNotificationRenderer(IndexationNotificationType.InProgressWithFailure);
-
- expect(ui.inProgressText.get()).toBeInTheDocument();
- expect(ui.docLink.get()).toBeInTheDocument();
- });
-
- it('should display "Completed" status', () => {
- renderIndexationNotificationRenderer(IndexationNotificationType.Completed);
-
- expect(ui.completedText.get()).toBeInTheDocument();
- });
-
- it('should display "Completed with failures" status', () => {
- renderIndexationNotificationRenderer(IndexationNotificationType.CompletedWithFailure);
-
- expect(ui.completedWithFailures.get()).toBeInTheDocument();
- });
-});
-
-function renderIndexationNotificationRenderer(status: IndexationNotificationType) {
- renderComponent(
- <IndexationNotificationRenderer
- completedCount={23}
- onDismissBanner={() => undefined}
- shouldDisplaySurveyLink={false}
- total={42}
- type={status}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/indexation/__tests__/PageUnavailableDueToIndexation-test.tsx b/server/sonar-web/src/main/js/app/components/indexation/__tests__/PageUnavailableDueToIndexation-test.tsx
deleted file mode 100644
index ecafb8f6ce9..00000000000
--- a/server/sonar-web/src/main/js/app/components/indexation/__tests__/PageUnavailableDueToIndexation-test.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { byRole } from '~sonar-aligned/helpers/testSelector';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { PageUnavailableDueToIndexation } from '../PageUnavailableDueToIndexation';
-
-it('should render correctly', () => {
- renderPageUnavailableToIndexation();
-
- expect(byRole('link', { name: 'learn_more' }).get()).toBeInTheDocument();
-});
-
-it('should not refresh the page once the indexation is complete if there were failures', () => {
- const reload = jest.fn();
-
- Object.defineProperty(window, 'location', {
- writable: true,
- value: { reload },
- });
-
- const { rerender } = renderPageUnavailableToIndexation();
-
- expect(reload).not.toHaveBeenCalled();
-
- rerender(
- <PageUnavailableDueToIndexation
- indexationContext={{
- status: { hasFailures: true, isCompleted: true },
- }}
- />,
- );
-
- expect(reload).not.toHaveBeenCalled();
-});
-
-it('should refresh the page once the indexation is complete if there were NO failures', () => {
- const reload = jest.fn();
-
- Object.defineProperty(window, 'location', {
- writable: true,
- value: { reload },
- });
-
- const { rerender } = renderPageUnavailableToIndexation();
-
- expect(reload).not.toHaveBeenCalled();
-
- rerender(
- <PageUnavailableDueToIndexation
- indexationContext={{
- status: { hasFailures: false, isCompleted: true },
- }}
- />,
- );
-
- expect(reload).toHaveBeenCalled();
-});
-
-function renderPageUnavailableToIndexation() {
- return renderComponent(
- <PageUnavailableDueToIndexation
- indexationContext={{
- status: { completedCount: 23, hasFailures: false, isCompleted: false, total: 42 },
- }}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/languages/LanguagesContext.ts b/server/sonar-web/src/main/js/app/components/languages/LanguagesContext.ts
deleted file mode 100644
index e54aceab103..00000000000
--- a/server/sonar-web/src/main/js/app/components/languages/LanguagesContext.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Languages } from '../../../types/languages';
-
-export const LanguagesContext = React.createContext<Languages>({});
diff --git a/server/sonar-web/src/main/js/app/components/languages/LanguagesContextProvider.tsx b/server/sonar-web/src/main/js/app/components/languages/LanguagesContextProvider.tsx
deleted file mode 100644
index c70f8b9929b..00000000000
--- a/server/sonar-web/src/main/js/app/components/languages/LanguagesContextProvider.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { keyBy } from 'lodash';
-import * as React from 'react';
-import { getLanguages } from '../../../api/languages';
-import { Languages } from '../../../types/languages';
-import { LanguagesContext } from './LanguagesContext';
-
-interface State {
- languages: Languages;
-}
-
-export default class LanguagesContextProvider extends React.PureComponent<
- React.PropsWithChildren,
- State
-> {
- mounted = false;
- state: State = {
- languages: {},
- };
-
- componentDidMount() {
- this.mounted = true;
-
- this.loadData();
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- loadData = async () => {
- const languageList = await getLanguages().catch(() => []);
- this.setState({ languages: keyBy(languageList, 'key') });
- };
-
- render() {
- return (
- <LanguagesContext.Provider value={this.state.languages}>
- {this.props.children}
- </LanguagesContext.Provider>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/app/components/languages/__tests__/LanguagesContextProvider-test.tsx b/server/sonar-web/src/main/js/app/components/languages/__tests__/LanguagesContextProvider-test.tsx
deleted file mode 100644
index ab00891d2b3..00000000000
--- a/server/sonar-web/src/main/js/app/components/languages/__tests__/LanguagesContextProvider-test.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { byRole } from '~sonar-aligned/helpers/testSelector';
-import { getLanguages } from '../../../../api/languages';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { Language } from '../../../../types/languages';
-import { LanguagesContext } from '../LanguagesContext';
-import LanguagesContextProvider from '../LanguagesContextProvider';
-
-jest.mock('../../../../api/languages', () => ({
- getLanguages: jest.fn().mockResolvedValue([]),
-}));
-
-it('should call language', async () => {
- const languages: Language[] = [
- { key: 'c', name: 'c' },
- { key: 'js', name: 'Javascript' },
- ];
- jest.mocked(getLanguages).mockResolvedValueOnce(languages);
- renderLanguagesContextProvider();
-
- expect(await byRole('listitem').findAll()).toHaveLength(2);
-});
-
-function renderLanguagesContextProvider() {
- return renderComponent(
- <LanguagesContextProvider>
- <Consumer />
- </LanguagesContextProvider>,
- );
-}
-
-function Consumer() {
- const languages = React.useContext(LanguagesContext);
- return (
- <ul>
- {Object.keys(languages).map((k) => (
- <li key={k}>{languages[k].name}</li>
- ))}
- </ul>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/languages/withLanguagesContext.tsx b/server/sonar-web/src/main/js/app/components/languages/withLanguagesContext.tsx
deleted file mode 100644
index 11572b648d7..00000000000
--- a/server/sonar-web/src/main/js/app/components/languages/withLanguagesContext.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { getWrappedDisplayName } from '~sonar-aligned/components/hoc/utils';
-import { Languages } from '../../../types/languages';
-import { LanguagesContext } from './LanguagesContext';
-
-export interface WithLanguagesContextProps {
- languages: Languages;
-}
-
-export default function withLanguagesContext<P>(
- WrappedComponent: React.ComponentType<React.PropsWithChildren<P & WithLanguagesContextProps>>,
-) {
- return class WithLanguagesContext extends React.PureComponent<
- Omit<P, keyof WithLanguagesContextProps>
- > {
- static displayName = getWrappedDisplayName(WrappedComponent, 'withLanguagesContext');
-
- render() {
- return (
- <LanguagesContext.Consumer>
- {(languages) => <WrappedComponent languages={languages} {...(this.props as P)} />}
- </LanguagesContext.Consumer>
- );
- }
- };
-}
diff --git a/server/sonar-web/src/main/js/app/components/metrics/MetricsContext.tsx b/server/sonar-web/src/main/js/app/components/metrics/MetricsContext.tsx
deleted file mode 100644
index 0e3d905282d..00000000000
--- a/server/sonar-web/src/main/js/app/components/metrics/MetricsContext.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Dict, Metric } from '../../../types/types';
-
-export const MetricsContext = React.createContext<Dict<Metric>>({});
diff --git a/server/sonar-web/src/main/js/app/components/metrics/MetricsContextProvider.tsx b/server/sonar-web/src/main/js/app/components/metrics/MetricsContextProvider.tsx
deleted file mode 100644
index 88223042e43..00000000000
--- a/server/sonar-web/src/main/js/app/components/metrics/MetricsContextProvider.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { keyBy } from 'lodash';
-import * as React from 'react';
-import { getAllMetrics } from '../../../api/metrics';
-import { Dict, Metric } from '../../../types/types';
-import { MetricsContext } from './MetricsContext';
-
-interface State {
- metrics: Dict<Metric>;
-}
-
-export default class MetricsContextProvider extends React.PureComponent<
- React.PropsWithChildren,
- State
-> {
- mounted = false;
- state: State = {
- metrics: {},
- };
-
- componentDidMount() {
- this.mounted = true;
- this.fetchMetrics();
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchMetrics = async () => {
- const metricList = await getAllMetrics();
- if (this.mounted) {
- this.setState({ metrics: keyBy(metricList, 'key') });
- }
- };
-
- render() {
- return (
- <MetricsContext.Provider value={this.state.metrics}>
- {this.props.children}
- </MetricsContext.Provider>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/app/components/metrics/RatingComponent.tsx b/server/sonar-web/src/main/js/app/components/metrics/RatingComponent.tsx
deleted file mode 100644
index e59a6c90bdb..00000000000
--- a/server/sonar-web/src/main/js/app/components/metrics/RatingComponent.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Spinner, Tooltip } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { MetricsRatingBadge, RatingEnum } from '~design-system';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import { getLeakValue } from '../../../components/measure/utils';
-import { SOFTWARE_QUALITY_RATING_METRICS_MAP } from '../../../helpers/constants';
-import { isDiffMetric } from '../../../helpers/measures';
-import { useMeasureQuery } from '../../../queries/measures';
-import { useStandardExperienceModeQuery } from '../../../queries/mode';
-import { BranchLike } from '../../../types/branch-like';
-
-type SizeType = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
-
-interface Props {
- branchLike?: BranchLike;
- className?: string;
- componentKey: string;
- forceMetric?: boolean;
- getLabel?: (rating: RatingEnum) => string;
- getTooltip?: (
- rating: RatingEnum,
- value: string | undefined,
- metricKey?: MetricKey,
- ) => React.ReactNode;
- ratingMetric: MetricKey;
- size?: SizeType;
-}
-
-type RatingMetricKeys =
- | MetricKey.reliability_rating
- | MetricKey.sqale_rating
- | MetricKey.security_rating
- | MetricKey.security_review_rating
- | MetricKey.releasability_rating;
-
-function isNewRatingMetric(metricKey: MetricKey) {
- return metricKey.includes('software_quality_');
-}
-
-const useGetMetricKeyForRating = (ratingMetric: RatingMetricKeys): MetricKey | null => {
- const { data: isStandardMode, isLoading } = useStandardExperienceModeQuery();
-
- const hasSoftwareQualityRating = !!SOFTWARE_QUALITY_RATING_METRICS_MAP[ratingMetric];
-
- if (isNewRatingMetric(ratingMetric)) {
- return ratingMetric;
- }
-
- if (isLoading) {
- return null;
- }
- return isStandardMode || !hasSoftwareQualityRating
- ? ratingMetric
- : SOFTWARE_QUALITY_RATING_METRICS_MAP[ratingMetric];
-};
-
-export default function RatingComponent(props: Readonly<Props>) {
- const {
- componentKey,
- ratingMetric,
- size,
- forceMetric,
- className,
- getLabel,
- branchLike,
- getTooltip,
- } = props;
-
- const metricKey = useGetMetricKeyForRating(ratingMetric as RatingMetricKeys);
- const { data: isStandardMode } = useStandardExperienceModeQuery();
- const { data: targetMeasure, isLoading: isLoadingTargetMeasure } = useMeasureQuery(
- { componentKey, metricKey: metricKey ?? '', branchLike },
- { enabled: !forceMetric && !!metricKey },
- );
-
- const { data: oldMeasure, isLoading: isLoadingOldMeasure } = useMeasureQuery(
- { componentKey, metricKey: ratingMetric, branchLike },
- {
- enabled:
- forceMetric ||
- (!isStandardMode && !isNewRatingMetric(ratingMetric) && targetMeasure === null),
- },
- );
-
- const isLoading = isLoadingTargetMeasure || isLoadingOldMeasure;
-
- const measure = forceMetric ? oldMeasure : (targetMeasure ?? oldMeasure);
-
- const value = isDiffMetric(metricKey ?? '') ? getLeakValue(measure) : measure?.value;
- const rating = formatMeasure(value, MetricType.Rating) as RatingEnum;
-
- const badge = (
- <MetricsRatingBadge
- label={getLabel ? getLabel(rating) : (value ?? '—')}
- rating={rating}
- size={size}
- className={className}
- />
- );
-
- return (
- <Spinner isLoading={isLoading}>
- {getTooltip ? (
- <>
- <Tooltip content={getTooltip(rating, value, measure?.metric as MetricKey)}>
- {badge}
- </Tooltip>
- {/* The badge is not interactive, so show the tooltip content for screen-readers only */}
- <span className="sw-sr-only">
- {getTooltip(rating, value, measure?.metric as MetricKey)}
- </span>
- </>
- ) : (
- badge
- )}
- </Spinner>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/metrics/__tests__/MetricsContextProvider-test.tsx b/server/sonar-web/src/main/js/app/components/metrics/__tests__/MetricsContextProvider-test.tsx
deleted file mode 100644
index d61d2b37ab4..00000000000
--- a/server/sonar-web/src/main/js/app/components/metrics/__tests__/MetricsContextProvider-test.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { byRole } from '~sonar-aligned/helpers/testSelector';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { getAllMetrics } from '../../../../api/metrics';
-import { mockMetric } from '../../../../helpers/testMocks';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { MetricsContext } from '../MetricsContext';
-import MetricsContextProvider from '../MetricsContextProvider';
-
-jest.mock('../../../../api/metrics', () => ({
- getAllMetrics: jest.fn().mockResolvedValue([]),
-}));
-
-it('should call metric', async () => {
- const metrics = [
- mockMetric({ key: MetricKey.alert_status, name: 'Alert Status' }),
- mockMetric({ key: MetricKey.code_smells, name: 'Code Smells' }),
- ];
- jest.mocked(getAllMetrics).mockResolvedValueOnce(metrics);
- renderMetricsContextProvider();
-
- expect(await byRole('listitem').findAll()).toHaveLength(2);
-});
-
-function renderMetricsContextProvider() {
- return renderComponent(
- <MetricsContextProvider>
- <Consumer />
- </MetricsContextProvider>,
- );
-}
-
-function Consumer() {
- const metrics = React.useContext(MetricsContext);
- return (
- <ul>
- {Object.keys(metrics).map((k) => (
- <li key={k}>{metrics[k].name}</li>
- ))}
- </ul>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/metrics/withMetricsContext.tsx b/server/sonar-web/src/main/js/app/components/metrics/withMetricsContext.tsx
deleted file mode 100644
index a0c303db260..00000000000
--- a/server/sonar-web/src/main/js/app/components/metrics/withMetricsContext.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { getWrappedDisplayName } from '~sonar-aligned/components/hoc/utils';
-import { Dict, Metric } from '../../../types/types';
-import { MetricsContext } from './MetricsContext';
-
-export interface WithMetricsContextProps {
- metrics: Dict<Metric>;
-}
-
-export default function withMetricsContext<P>(
- WrappedComponent: React.ComponentType<React.PropsWithChildren<P & WithMetricsContextProps>>,
-) {
- return class WithMetricsContext extends React.PureComponent<
- Omit<P, keyof WithMetricsContextProps>
- > {
- static displayName = getWrappedDisplayName(WrappedComponent, 'withMetricsContext');
-
- render() {
- return (
- <MetricsContext.Consumer>
- {(metrics) => <WrappedComponent metrics={metrics} {...(this.props as P)} />}
- </MetricsContext.Consumer>
- );
- }
- };
-}
-
-export function useMetrics() {
- return React.useContext(MetricsContext);
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/Breadcrumb.tsx b/server/sonar-web/src/main/js/app/components/nav/component/Breadcrumb.tsx
deleted file mode 100644
index 351d89f6fb1..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/Breadcrumb.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { LinkHighlight, LinkStandalone } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import Favorite from '../../../../components/controls/Favorite';
-import { getComponentOverviewUrl } from '../../../../helpers/urls';
-import { Component } from '../../../../types/types';
-import { CurrentUser, isLoggedIn } from '../../../../types/users';
-
-export interface BreadcrumbProps {
- component: Component;
- currentUser: CurrentUser;
-}
-
-export function Breadcrumb(props: Readonly<BreadcrumbProps>) {
- const { component, currentUser } = props;
-
- return (
- <div className="sw-text-sm sw-flex sw-justify-center">
- {component.breadcrumbs.map((breadcrumbElement, i) => {
- const isNotLast = i < component.breadcrumbs.length - 1;
- const isLast = !isNotLast;
-
- return (
- <div key={breadcrumbElement.key} className="sw-flex sw-items-center">
- {isLast && isLoggedIn(currentUser) && (
- <Favorite
- className="sw-mr-2"
- component={component.key}
- favorite={Boolean(component.isFavorite)}
- qualifier={component.qualifier}
- />
- )}
-
- <LinkStandalone
- highlight={LinkHighlight.Subdued}
- className="js-project-link"
- key={breadcrumbElement.name}
- shouldBlurAfterClick
- title={breadcrumbElement.name}
- to={getComponentOverviewUrl(breadcrumbElement.key, breadcrumbElement.qualifier)}
- >
- {breadcrumbElement.name}
- </LinkStandalone>
-
- {isNotLast && <SlashSeparator className="sw-mx-2" />}
- </div>
- );
- })}
- </div>
- );
-}
-
-export default React.memo(Breadcrumb);
-
-const SlashSeparator = styled.span`
- &:after {
- content: '/';
- color: rgba(68, 68, 68, 0.3);
- }
-`;
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx
deleted file mode 100644
index 67c27da7acd..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { TopBar } from '~design-system';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import NCDAutoUpdateMessage from '../../../../components/new-code-definition/NCDAutoUpdateMessage';
-import { ComponentMissingMqrMetricsMessage } from '../../../../components/shared/ComponentMissingMqrMetricsMessage';
-import { getBranchLikeDisplayName } from '../../../../helpers/branch-like';
-import { translate } from '../../../../helpers/l10n';
-import { isDefined } from '../../../../helpers/types';
-import { useCurrentBranchQuery } from '../../../../queries/branch';
-import { ProjectAlmBindingConfigurationErrors } from '../../../../types/alm-settings';
-import { Feature } from '../../../../types/features';
-import { Component } from '../../../../types/types';
-import RecentHistory from '../../RecentHistory';
-import withAvailableFeatures, {
- WithAvailableFeaturesProps,
-} from '../../available-features/withAvailableFeatures';
-import ComponentNavProjectBindingErrorNotif from './ComponentNavProjectBindingErrorNotif';
-import Header from './Header';
-import Menu from './Menu';
-
-export interface ComponentNavProps extends WithAvailableFeaturesProps {
- component: Component;
- isInProgress?: boolean;
- isPending?: boolean;
- projectBindingErrors?: ProjectAlmBindingConfigurationErrors;
-}
-
-function ComponentNav(props: Readonly<ComponentNavProps>) {
- const { component, hasFeature, isInProgress, isPending, projectBindingErrors } = props;
-
- const { data: branchLike } = useCurrentBranchQuery(component);
-
- React.useEffect(() => {
- const { breadcrumbs, key, name } = component;
- const { qualifier } = breadcrumbs[breadcrumbs.length - 1];
- if (
- [
- ComponentQualifier.Project,
- ComponentQualifier.Portfolio,
- ComponentQualifier.Application,
- ].includes(qualifier as ComponentQualifier)
- ) {
- RecentHistory.add(key, name, qualifier.toLowerCase());
- }
- }, [component, component.key]);
-
- const branchName =
- hasFeature(Feature.BranchSupport) || !isDefined(branchLike)
- ? undefined
- : getBranchLikeDisplayName(branchLike);
-
- return (
- <>
- <TopBar id="context-navigation" aria-label={translate('qualifier', component.qualifier)}>
- <div className="sw-min-h-10 sw-flex sw-justify-between">
- <Header component={component} />
- </div>
- <Menu component={component} isInProgress={isInProgress} isPending={isPending} />
- </TopBar>
- <NCDAutoUpdateMessage branchName={branchName} component={component} />
- <ComponentMissingMqrMetricsMessage component={component} />
- {projectBindingErrors !== undefined && (
- <ComponentNavProjectBindingErrorNotif component={component} />
- )}
- </>
- );
-}
-
-export default withAvailableFeatures(ComponentNav);
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavProjectBindingErrorNotif.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavProjectBindingErrorNotif.tsx
deleted file mode 100644
index 3d344003c62..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavProjectBindingErrorNotif.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { FormattedMessage } from 'react-intl';
-import { FlagWarningIcon, Link, themeBorder, themeColor } from '~design-system';
-import { PULL_REQUEST_DECORATION_BINDING_CATEGORY } from '../../../../apps/settings/constants';
-import { translate } from '../../../../helpers/l10n';
-import { getProjectSettingsUrl } from '../../../../helpers/urls';
-import { Component } from '../../../../types/types';
-
-export interface ComponentNavProjectBindingErrorNotifProps {
- component: Component;
-}
-
-export default function ComponentNavProjectBindingErrorNotif(
- props: Readonly<ComponentNavProjectBindingErrorNotifProps>,
-) {
- const { component } = props;
- let action;
-
- if (component.configuration?.showSettings) {
- action = (
- <Link to={getProjectSettingsUrl(component.key, PULL_REQUEST_DECORATION_BINDING_CATEGORY)}>
- {translate('component_navigation.pr_deco.action.check_project_settings')}
- </Link>
- );
- } else {
- action = translate('component_navigation.pr_deco.action.contact_project_admin');
- }
-
- return (
- <StyledBanner className="sw-typo-default sw-py-3 sw-px-4 sw-gap-4">
- <FlagWarningIcon />
- <FormattedMessage id="component_navigation.pr_deco.error_detected_X" values={{ action }} />
- </StyledBanner>
- );
-}
-
-const StyledBanner = styled.div`
- display: flex;
- align-items: center;
- box-sizing: border-box;
- width: 100%;
-
- background-color: ${themeColor('warningBackground')};
- border-top: ${themeBorder('default', 'warningBorder')};
- border-bottom: ${themeBorder('default', 'warningBorder')};
-`;
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/Header.tsx b/server/sonar-web/src/main/js/app/components/nav/component/Header.tsx
deleted file mode 100644
index f2e609e7688..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/Header.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Component } from '../../../../types/types';
-import { CurrentUser } from '../../../../types/users';
-import withCurrentUserContext from '../../current-user/withCurrentUserContext';
-import { Breadcrumb } from './Breadcrumb';
-import BranchLikeNavigation from './branch-like/BranchLikeNavigation';
-
-export interface HeaderProps {
- component: Component;
- currentUser: CurrentUser;
-}
-
-export function Header(props: HeaderProps) {
- const { component, currentUser } = props;
-
- return (
- <div className="sw-flex sw-flex-shrink sw-items-center">
- <Breadcrumb component={component} currentUser={currentUser} />
-
- <BranchLikeNavigation component={component} />
- </div>
- );
-}
-
-export default withCurrentUserContext(React.memo(Header));
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx b/server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx
deleted file mode 100644
index 2f8592dd109..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/Menu.tsx
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { DropdownMenu } from '@sonarsource/echoes-react';
-import { DisabledTabLink, NavBarTabLink, NavBarTabs } from '~design-system';
-import { useLocation } from '~sonar-aligned/components/hoc/withRouter';
-import { getBranchLikeQuery, isPullRequest } from '~sonar-aligned/helpers/branch-like';
-import { isPortfolioLike } from '~sonar-aligned/helpers/component';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { DEFAULT_ISSUES_QUERY } from '../../../../components/shared/utils';
-import { hasMessage, translate, translateWithParameters } from '../../../../helpers/l10n';
-import { getPortfolioUrl, getProjectQueryUrl } from '../../../../helpers/urls';
-import { useBranchesQuery, useCurrentBranchQuery } from '../../../../queries/branch';
-import { isApplication, isProject } from '../../../../types/component';
-import { Feature } from '../../../../types/features';
-import { Component, Dict, Extension } from '../../../../types/types';
-import withAvailableFeatures, {
- WithAvailableFeaturesProps,
-} from '../../available-features/withAvailableFeatures';
-
-const SETTINGS_URLS = [
- '/project/admin',
- '/project/baseline',
- '/project/branches',
- '/project/settings',
- '/project/quality_profiles',
- '/project/quality_gate',
- '/project/links',
- '/project_roles',
- '/project/history',
- 'background_tasks',
- '/project/key',
- '/project/deletion',
- '/project/webhooks',
-];
-
-interface Props extends WithAvailableFeaturesProps {
- component: Component;
- isInProgress?: boolean;
- isPending?: boolean;
-}
-
-type Query = BranchParameters & { id: string };
-
-export function Menu(props: Readonly<Props>) {
- const { component, isInProgress, isPending } = props;
- const { extensions = [], canBrowseAllChildProjects, qualifier, configuration = {} } = component;
-
- const { data: branchLikes = [] } = useBranchesQuery(component);
- const { data: branchLike } = useCurrentBranchQuery(component);
-
- const isApplicationChildInaccessble = isApplication(qualifier) && !canBrowseAllChildProjects;
-
- const location = useLocation();
-
- const hasAnalysis = () => {
- const hasBranches = branchLikes.length > 1;
- return hasBranches || isInProgress || isPending || component.analysisDate !== undefined;
- };
-
- const isGovernanceEnabled = extensions.some((extension) =>
- extension.key.startsWith('governance/'),
- );
-
- const getQuery = (): Query => {
- return { id: component.key, ...getBranchLikeQuery(branchLike) };
- };
-
- const renderLinkWhenInaccessibleChild = (label: string) => {
- return (
- <DisabledTabLink
- overlay={translateWithParameters(
- 'layout.all_project_must_be_accessible',
- translate('qualifier', qualifier),
- )}
- label={label}
- />
- );
- };
-
- const renderMenuLink = ({
- label,
- pathname,
- additionalQueryParams = {},
- }: {
- additionalQueryParams?: Dict<string>;
- label: string;
- pathname: string;
- }) => {
- const query = getQuery();
- if (isApplicationChildInaccessble) {
- return renderLinkWhenInaccessibleChild(label);
- }
- return hasAnalysis() ? (
- <NavBarTabLink
- to={{
- pathname,
- search: new URLSearchParams({ ...query, ...additionalQueryParams }).toString(),
- }}
- text={label}
- />
- ) : (
- <DisabledTabLink overlay={translate('layout.must_be_configured')} label={label} />
- );
- };
-
- const renderDashboardLink = () => {
- const { id, ...branchLike } = getQuery();
-
- if (isPortfolioLike(qualifier)) {
- return isGovernanceEnabled ? (
- <NavBarTabLink to={getPortfolioUrl(id)} text={translate('overview.page')} />
- ) : null;
- }
-
- const showingTutorial = location.pathname.includes('/tutorials');
-
- if (showingTutorial) {
- return (
- <DisabledTabLink
- overlay={translate('layout.must_be_configured')}
- label={translate('overview.page')}
- />
- );
- }
-
- if (isApplicationChildInaccessble) {
- return renderLinkWhenInaccessibleChild(translate('overview.page'));
- }
- return (
- <NavBarTabLink to={getProjectQueryUrl(id, branchLike)} text={translate('overview.page')} />
- );
- };
-
- const renderBreakdownLink = () => {
- return isPortfolioLike(qualifier) && isGovernanceEnabled
- ? renderMenuLink({
- label: translate('portfolio_breakdown.page'),
- pathname: '/code',
- })
- : null;
- };
-
- const renderCodeLink = () => {
- if (isPortfolioLike(qualifier)) {
- return null;
- }
-
- const label = isApplication(qualifier)
- ? translate('view_projects.page')
- : translate('code.page');
-
- return renderMenuLink({ label, pathname: '/code' });
- };
-
- const renderActivityLink = () => {
- if (isPullRequest(branchLike)) {
- return null;
- }
-
- return renderMenuLink({
- label: translate('project_activity.page'),
- pathname: '/project/activity',
- });
- };
-
- const renderIssuesLink = () => {
- return renderMenuLink({
- label: translate('issues.page'),
- pathname: '/project/issues',
- additionalQueryParams: DEFAULT_ISSUES_QUERY,
- });
- };
-
- const renderComponentMeasuresLink = () => {
- return renderMenuLink({
- label: translate('layout.measures'),
- pathname: '/component_measures',
- });
- };
-
- const renderSecurityHotspotsLink = () => {
- const isPortfolio = isPortfolioLike(qualifier);
- return (
- !isPortfolio &&
- renderMenuLink({
- label: translate('layout.security_hotspots'),
- pathname: '/security_hotspots',
- })
- );
- };
-
- const renderDependenciesLink = () => {
- const isEnabled = false; // SONAR-23577 Temporarily hide dependencies page
- const isPortfolio = isPortfolioLike(qualifier);
- return (
- isEnabled &&
- !isPortfolio &&
- renderMenuLink({
- label: translate('layout.dependencies'),
- pathname: '/dependencies',
- })
- );
- };
-
- const renderSecurityReports = () => {
- if (isPullRequest(branchLike)) {
- return null;
- }
-
- const hasSecurityReportsEnabled = extensions.some((extension) =>
- extension.key.startsWith('securityreport/'),
- );
-
- if (!hasSecurityReportsEnabled) {
- return null;
- }
-
- return renderMenuLink({
- label: translate('layout.security_reports'),
- pathname: '/project/extension/securityreport/securityreport',
- });
- };
-
- const renderAdministration = () => {
- const query = getQuery();
-
- if (!configuration.showSettings || isPullRequest(branchLike)) {
- return null;
- }
-
- const isSettingsActive = SETTINGS_URLS.some((url) => window.location.href.includes(url));
-
- const adminLinks = renderAdministrationLinks(
- query,
- isProject(qualifier),
- isApplication(qualifier),
- isPortfolioLike(qualifier),
- );
-
- if (!adminLinks.some((link) => link != null)) {
- return null;
- }
-
- return (
- <DropdownMenu.Root
- data-test="administration"
- id="component-navigation-admin"
- items={adminLinks}
- >
- <NavBarTabLink
- active={isSettingsActive}
- preventDefault // not really a link, we just use the same style to be consistent
- text={
- hasMessage('layout.settings', component.qualifier)
- ? translate('layout.settings', component.qualifier)
- : translate('layout.settings')
- }
- to={{}} // not really a link, we just use the same style to be consistent
- withChevron
- />
- </DropdownMenu.Root>
- );
- };
-
- const renderAdministrationLinks = (
- query: Query,
- isProject: boolean,
- isApplication: boolean,
- isPortfolio: boolean,
- ) => {
- return [
- renderSettingsLink(query, isApplication, isPortfolio),
- renderBranchesLink(query, isProject),
- renderBaselineLink(query, isApplication, isPortfolio),
- ...renderAdminExtensions(query, isApplication),
- renderImportExportLink(query, isProject),
- renderProfilesLink(query),
- renderQualityGateLink(query),
- renderLinksLink(query),
- renderPermissionsLink(query),
- renderBackgroundTasksLink(query),
- renderUpdateKeyLink(query),
- renderWebhooksLink(query, isProject),
- renderDeletionLink(query),
- ];
- };
-
- const renderProjectInformationButton = () => {
- const label = translate(isProject(qualifier) ? 'project' : 'application', 'info.title');
- const query = getQuery();
-
- if (isPullRequest(branchLike)) {
- return null;
- }
-
- if (isApplicationChildInaccessble) {
- return renderLinkWhenInaccessibleChild(label);
- }
-
- return (
- (isProject(qualifier) || isApplication(qualifier)) && (
- <NavBarTabLink
- to={{ pathname: '/project/information', search: new URLSearchParams(query).toString() }}
- text={label}
- />
- )
- );
- };
-
- const renderSettingsLink = (query: Query, isApplication: boolean, isPortfolio: boolean) => {
- if (!configuration.showSettings || isApplication || isPortfolio) {
- return null;
- }
- return (
- <DropdownMenu.ItemLink
- key="settings"
- to={{ pathname: '/project/settings', search: new URLSearchParams(query).toString() }}
- >
- {translate('project_settings.page')}
- </DropdownMenu.ItemLink>
- );
- };
-
- const renderBranchesLink = (query: Query, isProject: boolean) => {
- if (!props.hasFeature(Feature.BranchSupport) || !isProject || !configuration.showSettings) {
- return null;
- }
-
- return (
- <DropdownMenu.ItemLink
- key="branches"
- to={{ pathname: '/project/branches', search: new URLSearchParams(query).toString() }}
- >
- {translate('project_branch_pull_request.page')}
- </DropdownMenu.ItemLink>
- );
- };
-
- const renderBaselineLink = (query: Query, isApplication: boolean, isPortfolio: boolean) => {
- if (!configuration.showSettings || isApplication || isPortfolio) {
- return null;
- }
- return (
- <DropdownMenu.ItemLink
- key="baseline"
- to={{ pathname: '/project/baseline', search: new URLSearchParams(query).toString() }}
- >
- {translate('project_baseline.page')}
- </DropdownMenu.ItemLink>
- );
- };
-
- const renderImportExportLink = (query: Query, isProject: boolean) => {
- if (!isProject) {
- return null;
- }
- return (
- <DropdownMenu.ItemLink
- key="import-export"
- to={{
- pathname: '/project/import_export',
- search: new URLSearchParams(query).toString(),
- }}
- >
- {translate('project_dump.page')}
- </DropdownMenu.ItemLink>
- );
- };
-
- const renderProfilesLink = (query: Query) => {
- if (!configuration.showQualityProfiles) {
- return null;
- }
- return (
- <DropdownMenu.ItemLink
- key="profiles"
- to={{
- pathname: '/project/quality_profiles',
- search: new URLSearchParams(query).toString(),
- }}
- >
- {translate('project_quality_profiles.page')}
- </DropdownMenu.ItemLink>
- );
- };
-
- const renderQualityGateLink = (query: Query) => {
- if (!configuration.showQualityGates) {
- return null;
- }
- return (
- <DropdownMenu.ItemLink
- key="quality_gate"
- to={{ pathname: '/project/quality_gate', search: new URLSearchParams(query).toString() }}
- >
- {translate('project_quality_gate.page')}
- </DropdownMenu.ItemLink>
- );
- };
-
- const renderLinksLink = (query: Query) => {
- if (!configuration.showLinks) {
- return null;
- }
- return (
- <DropdownMenu.ItemLink
- key="links"
- to={{ pathname: '/project/links', search: new URLSearchParams(query).toString() }}
- >
- {translate('project_links.page')}
- </DropdownMenu.ItemLink>
- );
- };
-
- const renderPermissionsLink = (query: Query) => {
- if (!configuration.showPermissions) {
- return null;
- }
- return (
- <DropdownMenu.ItemLink
- key="permissions"
- to={{ pathname: '/project_roles', search: new URLSearchParams(query).toString() }}
- >
- {translate('permissions.page')}
- </DropdownMenu.ItemLink>
- );
- };
-
- const renderBackgroundTasksLink = (query: Query) => {
- if (!configuration.showBackgroundTasks) {
- return null;
- }
- return (
- <DropdownMenu.ItemLink
- key="background_tasks"
- to={{
- pathname: '/project/background_tasks',
- search: new URLSearchParams(query).toString(),
- }}
- >
- {translate('background_tasks.page')}
- </DropdownMenu.ItemLink>
- );
- };
-
- const renderUpdateKeyLink = (query: Query) => {
- if (!configuration.showUpdateKey) {
- return null;
- }
- return (
- <DropdownMenu.ItemLink
- key="update_key"
- to={{ pathname: '/project/key', search: new URLSearchParams(query).toString() }}
- >
- {translate('update_key.page')}
- </DropdownMenu.ItemLink>
- );
- };
-
- const renderWebhooksLink = (query: Query, isProject: boolean) => {
- if (!configuration.showSettings || !isProject) {
- return null;
- }
- return (
- <DropdownMenu.ItemLink
- key="webhooks"
- to={{ pathname: '/project/webhooks', search: new URLSearchParams(query).toString() }}
- >
- {translate('webhooks.page')}
- </DropdownMenu.ItemLink>
- );
- };
-
- const renderDeletionLink = (query: Query) => {
- if (!configuration.showSettings) {
- return null;
- }
-
- if (
- ![
- ComponentQualifier.Project,
- ComponentQualifier.Portfolio,
- ComponentQualifier.Application,
- ].includes(qualifier as ComponentQualifier)
- ) {
- return null;
- }
-
- return (
- <DropdownMenu.ItemLink
- key="project_delete"
- to={{ pathname: '/project/deletion', search: new URLSearchParams(query).toString() }}
- >
- {translate('deletion.page')}
- </DropdownMenu.ItemLink>
- );
- };
-
- const renderExtension = ({ key, name }: Extension, isAdmin: boolean, baseQuery: Query) => {
- const pathname = isAdmin ? `/project/admin/extension/${key}` : `/project/extension/${key}`;
- const query = { ...baseQuery, qualifier };
- return (
- <DropdownMenu.ItemLink
- key={key}
- to={{ pathname, search: new URLSearchParams(query).toString() }}
- >
- {name}
- </DropdownMenu.ItemLink>
- );
- };
-
- const renderAdminExtensions = (query: Query, isApplication: boolean) => {
- const extensions = component.configuration?.extensions ?? [];
- return extensions
- .filter((e) => !isApplication || e.key !== 'governance/console')
- .map((e) => renderExtension(e, true, query));
- };
-
- const renderExtensions = () => {
- const query = getQuery();
- const withoutSecurityExtension = extensions.filter(
- (extension) =>
- !extension.key.startsWith('securityreport/') && !extension.key.startsWith('governance/'),
- );
-
- if (withoutSecurityExtension.length === 0) {
- return null;
- }
-
- return (
- <DropdownMenu.Root
- data-test="extensions"
- id="component-navigation-more"
- items={withoutSecurityExtension.map((e) => renderExtension(e, false, query))}
- >
- <NavBarTabLink preventDefault text={translate('more')} withChevron to={{}} />
- </DropdownMenu.Root>
- );
- };
-
- return (
- <div className="sw-flex sw-justify-between sw-pt-4 it__navbar-tabs">
- <NavBarTabs>
- {renderDashboardLink()}
- {renderBreakdownLink()}
- {renderIssuesLink()}
- {renderSecurityHotspotsLink()}
- {renderDependenciesLink()}
- {renderSecurityReports()}
- {renderComponentMeasuresLink()}
- {renderCodeLink()}
- {renderActivityLink()}
- {renderExtensions()}
- </NavBarTabs>
- <NavBarTabs>
- {renderAdministration()}
- {renderProjectInformationButton()}
- </NavBarTabs>
- </div>
- );
-}
-
-export default withAvailableFeatures(Menu);
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx
deleted file mode 100644
index 067866c1ee7..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen, waitFor } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import AlmSettingsServiceMock from '../../../../../api/mocks/AlmSettingsServiceMock';
-import BranchesServiceMock from '../../../../../api/mocks/BranchesServiceMock';
-import { MeasuresServiceMock } from '../../../../../api/mocks/MeasuresServiceMock';
-import { ModeServiceMock } from '../../../../../api/mocks/ModeServiceMock';
-import { mockProjectAlmBindingConfigurationErrors } from '../../../../../helpers/mocks/alm-settings';
-import { mockComponent } from '../../../../../helpers/mocks/component';
-import { get } from '../../../../../helpers/storage';
-import { mockMeasure } from '../../../../../helpers/testMocks';
-import { renderApp } from '../../../../../helpers/testReactTestingUtils';
-import { byRole } from '../../../../../sonar-aligned/helpers/testSelector';
-import { MetricKey } from '../../../../../sonar-aligned/types/metrics';
-import { Mode } from '../../../../../types/mode';
-import ComponentNav, { ComponentNavProps } from '../ComponentNav';
-
-jest.mock('../../../../../helpers/storage', () => ({
- get: jest.fn(),
- remove: jest.fn(),
- save: jest.fn(),
-}));
-
-const branchesHandler = new BranchesServiceMock();
-const almHandler = new AlmSettingsServiceMock();
-const modeHandler = new ModeServiceMock();
-const measuresHandler = new MeasuresServiceMock();
-
-afterEach(() => {
- branchesHandler.reset();
- almHandler.reset();
- modeHandler.reset();
- measuresHandler.reset();
-});
-
-it('renders correctly when the project binding is incorrect', () => {
- renderComponentNav({
- projectBindingErrors: mockProjectAlmBindingConfigurationErrors(),
- });
- expect(
- screen.getByText('component_navigation.pr_deco.error_detected_X', { exact: false }),
- ).toBeInTheDocument();
-});
-
-it('correctly returns focus to the Project Information link when the drawer is closed', async () => {
- const user = userEvent.setup();
- renderComponentNav();
- await user.click(screen.getByRole('link', { name: 'project.info.title' }));
- expect(await screen.findByText('/project/information?id=my-project')).toBeInTheDocument();
-});
-
-describe('MQR mode calculation change message', () => {
- it('does not render the message in standard mode', async () => {
- modeHandler.setMode(Mode.Standard);
- renderComponentNav();
-
- await waitFor(() => {
- expect(screen.queryByText(/overview.missing_project_data/)).not.toBeInTheDocument();
- });
- });
-
- it.each([
- ['project', ComponentQualifier.Project],
- ['application', ComponentQualifier.Application],
- ['portfolio', ComponentQualifier.Portfolio],
- ])('does not render message when %s is not computed', async (_, qualifier) => {
- const component = mockComponent({
- qualifier,
- breadcrumbs: [{ key: 'foo', name: 'Foo', qualifier }],
- });
- measuresHandler.registerComponentMeasures({
- [component.key]: {},
- });
- renderComponentNav({ component });
-
- await waitFor(() => {
- expect(
- byRole('alert')
- .byText(new RegExp(`overview.missing_project_data${qualifier}`))
- .query(),
- ).not.toBeInTheDocument();
- });
- });
-
- it.each([
- ['project', ComponentQualifier.Project],
- ['application', ComponentQualifier.Application],
- ['portfolio', ComponentQualifier.Portfolio],
- ])('does not render message when %s mqr metrics computed', async (_, qualifier) => {
- const component = mockComponent({
- qualifier,
- breadcrumbs: [{ key: 'foo', name: 'Foo', qualifier }],
- });
- measuresHandler.registerComponentMeasures({
- [component.key]: {
- [MetricKey.security_rating]: mockMeasure({
- metric: MetricKey.security_rating,
- value: '1.0',
- }),
- [MetricKey.software_quality_security_rating]: mockMeasure({
- metric: MetricKey.software_quality_security_rating,
- value: '1.0',
- }),
- },
- });
- renderComponentNav({ component });
-
- await waitFor(() => {
- expect(
- byRole('alert')
- .byText(new RegExp(`overview.missing_project_data${qualifier}`))
- .query(),
- ).not.toBeInTheDocument();
- });
- });
-
- it.each([
- ['project', ComponentQualifier.Project],
- ['application', ComponentQualifier.Application],
- ['portfolio', ComponentQualifier.Portfolio],
- ])(
- 'does not render message when %s mqr metrics are not computed but it was already dismissed',
- async (_, qualifier) => {
- const component = mockComponent({
- qualifier,
- breadcrumbs: [{ key: 'foo', name: 'Foo', qualifier }],
- });
- jest.mocked(get).mockImplementation((key) => {
- const keys: Record<string, string> = {
- [`sonarqube.dismissed_calculation_change_alert.component_${component.key}`]: 'true',
- };
- return keys[key];
- });
- measuresHandler.registerComponentMeasures({
- [component.key]: {
- [MetricKey.security_rating]: mockMeasure({
- metric: MetricKey.security_rating,
- value: '1.0',
- }),
- },
- });
- renderComponentNav({ component });
-
- await waitFor(() => {
- expect(
- byRole('alert')
- .byText(new RegExp(`overview.missing_project_data${qualifier}`))
- .query(),
- ).not.toBeInTheDocument();
- });
- jest.mocked(get).mockRestore();
- },
- );
-
- it.each([
- ['project', ComponentQualifier.Project],
- ['application', ComponentQualifier.Application],
- ['portfolio', ComponentQualifier.Portfolio],
- ])('renders message when %s mqr metrics are not computed', async (_, qualifier) => {
- const component = mockComponent({
- qualifier,
- breadcrumbs: [{ key: 'foo', name: 'Foo', qualifier }],
- });
- measuresHandler.registerComponentMeasures({
- [component.key]: {
- [MetricKey.security_rating]: mockMeasure({
- metric: MetricKey.security_rating,
- value: '1.0',
- }),
- },
- });
- renderComponentNav({ component });
-
- expect(
- await byRole('alert')
- .byText(new RegExp(`overview.missing_project_data${qualifier}`))
- .find(),
- ).toBeInTheDocument();
-
- expect(
- byRole('link', { name: /overview.missing_project_data_link/ }).get(),
- ).toBeInTheDocument();
- });
-
- it('can dismiss message', async () => {
- const user = userEvent.setup();
-
- measuresHandler.registerComponentMeasures({
- 'my-project': {
- [MetricKey.security_rating]: mockMeasure({
- metric: MetricKey.security_rating,
- value: '1.0',
- }),
- },
- });
- renderComponentNav();
- expect(
- await byRole('alert')
- .byText(/overview.missing_project_dataTRK/)
- .find(),
- ).toBeInTheDocument();
-
- await user.click(byRole('button', { name: 'dismiss' }).get());
-
- expect(
- byRole('alert')
- .byText(/overview.missing_project_dataTRK/)
- .query(),
- ).not.toBeInTheDocument();
- });
-});
-
-function renderComponentNav(props: Partial<ComponentNavProps> = {}) {
- const component =
- props.component ??
- mockComponent({
- breadcrumbs: [{ key: 'foo', name: 'Foo', qualifier: ComponentQualifier.Project }],
- });
-
- measuresHandler.setComponents({ component, ancestors: [], children: [] });
-
- return renderApp(
- '/',
- <ComponentNav isInProgress={false} isPending={false} {...props} component={component} />,
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavProjectBindingErrorNotif-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavProjectBindingErrorNotif-test.tsx
deleted file mode 100644
index 6527484896a..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavProjectBindingErrorNotif-test.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { mockComponent } from '../../../../../helpers/mocks/component';
-import { renderComponent } from '../../../../../helpers/testReactTestingUtils';
-import ComponentNavProjectBindingErrorNotif, {
- ComponentNavProjectBindingErrorNotifProps,
-} from '../ComponentNavProjectBindingErrorNotif';
-
-it('should not show a link if use is not allowed', () => {
- renderComponentNavProjectBindingErrorNotif({
- component: mockComponent({ configuration: { showSettings: false } }),
- });
- expect(
- screen.queryByRole('link', {
- name: 'component_navigation.pr_deco.action.check_project_settings',
- }),
- ).not.toBeInTheDocument();
-});
-
-it('should show a link if use is allowed', () => {
- renderComponentNavProjectBindingErrorNotif({
- component: mockComponent({ configuration: { showSettings: true } }),
- });
- expect(
- screen.getByRole('link', {
- name: 'component_navigation.pr_deco.action.check_project_settings',
- }),
- ).toBeInTheDocument();
-});
-
-function renderComponentNavProjectBindingErrorNotif(
- props: Partial<ComponentNavProjectBindingErrorNotifProps> = {},
-) {
- return renderComponent(
- <ComponentNavProjectBindingErrorNotif component={mockComponent()} {...props} />,
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/Header-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/Header-test.tsx
deleted file mode 100644
index 7d7000073c4..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/Header-test.tsx
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import AlmSettingsServiceMock from '../../../../../api/mocks/AlmSettingsServiceMock';
-import BranchesServiceMock from '../../../../../api/mocks/BranchesServiceMock';
-import { mockMainBranch, mockPullRequest } from '../../../../../helpers/mocks/branch-like';
-import { mockComponent } from '../../../../../helpers/mocks/component';
-import { mockCurrentUser, mockLoggedInUser } from '../../../../../helpers/testMocks';
-import { renderApp } from '../../../../../helpers/testReactTestingUtils';
-import { AlmKeys } from '../../../../../types/alm-settings';
-import { Feature } from '../../../../../types/features';
-import { Header, HeaderProps } from '../Header';
-
-jest.mock('../../../../../api/favorites', () => ({
- addFavorite: jest.fn().mockResolvedValue({}),
- removeFavorite: jest.fn().mockResolvedValue({}),
-}));
-
-const handler = new BranchesServiceMock();
-const almHandler = new AlmSettingsServiceMock();
-
-beforeEach(() => {
- handler.reset();
- almHandler.reset();
-});
-
-it('should render correctly when there is only 1 branch', async () => {
- handler.emptyBranchesAndPullRequest();
- handler.addBranch(mockMainBranch({ status: { qualityGateStatus: 'OK' } }));
- renderHeader();
- expect(await screen.findByLabelText('help-tooltip')).toBeInTheDocument();
- expect(screen.getByText('project')).toBeInTheDocument();
- expect(
- await screen.findByRole('button', { name: 'master overview.quality_gate_x.metric.level.OK' }),
- ).toBeDisabled();
-});
-
-it('should render correctly when there are multiple branch', async () => {
- const user = userEvent.setup();
- renderHeader();
-
- expect(
- await screen.findByRole('button', { name: 'main overview.quality_gate_x.metric.level.OK' }),
- ).toBeEnabled();
-
- expect(screen.queryByLabelText('help-tooltip')).not.toBeInTheDocument();
-
- await user.click(
- screen.getByRole('button', { name: 'main overview.quality_gate_x.metric.level.OK' }),
- );
- expect(screen.getByText('branches.main_branch')).toBeInTheDocument();
- expect(
- screen.getByRole('menuitem', {
- name: '03 – TEST-193 dumb commit overview.quality_gate_x.metric.level.ERROR ERROR',
- }),
- ).toBeInTheDocument();
- expect(
- screen.getByRole('menuitem', {
- name: '01 – TEST-191 update master overview.quality_gate_x.metric.level.OK OK',
- }),
- ).toBeInTheDocument();
- expect(
- screen.getByRole('menuitem', {
- name: 'normal-branch overview.quality_gate_x.metric.level.ERROR ERROR',
- }),
- ).toBeInTheDocument();
-
- await user.click(
- screen.getByRole('menuitem', {
- name: 'normal-branch overview.quality_gate_x.metric.level.ERROR ERROR',
- }),
- );
- expect(screen.getByText('/dashboard?branch=normal-branch&id=header-project')).toBeInTheDocument();
-});
-
-it('should show manage branch and pull request button for admin', async () => {
- const user = userEvent.setup();
- renderHeader({
- currentUser: mockLoggedInUser(),
- component: mockComponent({
- key: 'header-project',
- configuration: { showSettings: true },
- breadcrumbs: [{ name: 'project', key: 'project', qualifier: ComponentQualifier.Project }],
- }),
- });
- await user.click(
- await screen.findByRole('button', { name: 'main overview.quality_gate_x.metric.level.OK' }),
- );
-
- expect(screen.getByRole('link', { name: 'branch_like_navigation.manage' })).toBeInTheDocument();
- expect(screen.getByRole('link', { name: 'branch_like_navigation.manage' })).toHaveAttribute(
- 'href',
- '/project/branches?id=header-project',
- );
-});
-
-it('should render favorite button if the user is logged in', async () => {
- const user = userEvent.setup();
- renderHeader({ currentUser: mockLoggedInUser() });
- expect(screen.getByRole('button', { name: 'favorite.action.TRK.add' })).toBeInTheDocument();
-
- await user.click(screen.getByRole('button', { name: 'favorite.action.TRK.add' }));
- expect(
- await screen.findByRole('button', { name: 'favorite.action.TRK.remove' }),
- ).toBeInTheDocument();
-
- await user.click(screen.getByRole('button', { name: 'favorite.action.TRK.remove' }));
- expect(screen.getByRole('button', { name: 'favorite.action.TRK.add' })).toBeInTheDocument();
-});
-
-it.each([['github'], ['gitlab'], ['bitbucket'], ['azure']])(
- 'should show correct %s links for a PR',
- async (alm: string) => {
- handler.emptyBranchesAndPullRequest();
- handler.addPullRequest(mockPullRequest({ url: alm }));
- renderHeader(
- {
- currentUser: mockLoggedInUser(),
- },
- undefined,
- 'pullRequest=1001&id=compa',
- );
- const image = await screen.findByAltText(alm);
- expect(image).toBeInTheDocument();
- expect(image).toHaveAttribute('src', `/images/alm/${alm}.svg`);
- },
-);
-
-it('should show the correct help tooltip for applications', async () => {
- handler.emptyBranchesAndPullRequest();
- handler.addBranch(mockMainBranch());
- renderHeader({
- currentUser: mockLoggedInUser(),
- component: mockComponent({
- key: 'header-project',
- configuration: { showSettings: true },
- breadcrumbs: [{ name: 'project', key: 'project', qualifier: ComponentQualifier.Application }],
- qualifier: 'APP',
- }),
- });
- expect(await screen.findByText('application.branches.help')).toBeInTheDocument();
- expect(screen.getByText('application.branches.link')).toBeInTheDocument();
-});
-
-it('should show the correct help tooltip when branch support is not enabled', async () => {
- handler.emptyBranchesAndPullRequest();
- handler.addBranch(mockMainBranch());
- almHandler.handleSetProjectBinding(AlmKeys.GitLab, {
- almSetting: 'key',
- project: 'header-project',
- repository: 'header-project',
- monorepo: true,
- });
- renderHeader(
- {
- currentUser: mockLoggedInUser(),
- },
- [],
- );
- expect(
- await screen.findByText('branch_like_navigation.no_branch_support.title.mr'),
- ).toBeInTheDocument();
- expect(
- screen.getByText('branch_like_navigation.no_branch_support.content_x.mr.alm.gitlab'),
- ).toBeInTheDocument();
-});
-
-function renderHeader(
- props?: Partial<HeaderProps>,
- featureList = [Feature.BranchSupport],
- params?: string,
-) {
- return renderApp(
- '/',
- <Header
- component={mockComponent({
- key: 'header-project',
- breadcrumbs: [{ name: 'project', key: 'project', qualifier: ComponentQualifier.Project }],
- })}
- currentUser={mockCurrentUser()}
- {...props}
- />,
- { featureList, navigateTo: params ? `/?id=header-project&${params}` : '/?id=header-project' },
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/Menu-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/Menu-test.tsx
deleted file mode 100644
index 3d5e6505de4..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/Menu-test.tsx
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen, waitFor } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import BranchesServiceMock from '../../../../../api/mocks/BranchesServiceMock';
-import { mockComponent } from '../../../../../helpers/mocks/component';
-import { renderComponent } from '../../../../../helpers/testReactTestingUtils';
-import { ComponentPropsType } from '../../../../../helpers/testUtils';
-import { Feature } from '../../../../../types/features';
-import { Menu } from '../Menu';
-
-const handler = new BranchesServiceMock();
-
-const BASE_COMPONENT = mockComponent({
- analysisDate: '2019-12-01',
- key: 'foo',
- name: 'foo',
-});
-
-beforeEach(() => handler.reset());
-
-it('should render correctly', async () => {
- const user = userEvent.setup();
- const component = {
- ...BASE_COMPONENT,
- configuration: {
- showSettings: true,
- extensions: [
- { key: 'foo', name: 'Foo' },
- { key: 'bar', name: 'Bar' },
- { key: 'securityreport/foo', name: 'Foo' },
- ],
- },
- extensions: [
- { key: 'component-foo', name: 'ComponentFoo' },
- { key: 'component-bar', name: 'ComponentBar' },
- { key: 'securityreport/foo', name: 'Security Report' },
- ],
- };
- renderMenu({ component });
-
- // Security Report is rendered on its own, as is not part of the dropdown menu.
- expect(screen.getByRole('link', { name: 'layout.security_reports' })).toBeInTheDocument();
-
- // Check the dropdown.
- const button = screen.getByRole('link', { name: 'more' });
- expect(button).toBeInTheDocument();
- await user.click(button);
- expect(screen.getByRole('menuitem', { name: 'ComponentFoo' })).toBeInTheDocument();
- expect(screen.getByRole('menuitem', { name: 'ComponentBar' })).toBeInTheDocument();
-});
-
-it('should render correctly when on a Portofolio', () => {
- const component = {
- ...BASE_COMPONENT,
- configuration: {
- showSettings: true,
- extensions: [
- { key: 'foo', name: 'Foo' },
- { key: 'bar', name: 'Bar' },
- ],
- },
- qualifier: ComponentQualifier.Portfolio,
- extensions: [
- { key: 'governance/foo', name: 'governance foo' },
- { key: 'governance/bar', name: 'governance bar' },
- ],
- };
- renderMenu({ component });
- expect(screen.getByRole('link', { name: 'overview.page' })).toBeInTheDocument();
- expect(screen.getByRole('link', { name: 'issues.page' })).toBeInTheDocument();
- expect(screen.getByRole('link', { name: 'layout.measures' })).toBeInTheDocument();
- expect(screen.getByRole('link', { name: 'portfolio_breakdown.page' })).toBeInTheDocument();
-});
-
-it('should render correctly when on a branch', async () => {
- renderMenu(
- {
- component: {
- ...BASE_COMPONENT,
- configuration: { showSettings: true },
- extensions: [{ key: 'component-foo', name: 'ComponentFoo' }],
- },
- },
- 'id=foo&branch=normal-branch',
- );
-
- expect(await screen.findByRole('link', { name: 'overview.page' })).toBeInTheDocument();
- expect(screen.getByRole('link', { name: 'issues.page' })).toBeInTheDocument();
- expect(screen.getByRole('link', { name: 'layout.measures' })).toBeInTheDocument();
- expect(screen.getByRole('link', { name: 'project.info.title' })).toBeInTheDocument();
-});
-
-it('should render correctly when on a pull request', async () => {
- renderMenu(
- {
- component: {
- ...BASE_COMPONENT,
- configuration: { showSettings: true },
- extensions: [{ key: 'component-foo', name: 'ComponentFoo' }],
- },
- },
- 'id=foo&pullRequest=01',
- );
-
- expect(await screen.findByRole('link', { name: 'overview.page' })).toBeInTheDocument();
- expect(screen.getByRole('link', { name: 'issues.page' })).toBeInTheDocument();
- expect(screen.getByRole('link', { name: 'layout.measures' })).toBeInTheDocument();
-
- await waitFor(() => {
- expect(
- screen.queryByRole('link', { name: `layout.settings.${ComponentQualifier.Project}` }),
- ).not.toBeInTheDocument();
- });
-
- expect(screen.queryByRole('button', { name: 'project.info.title' })).not.toBeInTheDocument();
-});
-
-it('should disable links if no analysis has been done', () => {
- renderMenu({
- component: {
- ...BASE_COMPONENT,
- analysisDate: undefined,
- },
- });
-
- expect(screen.queryByRole('link', { name: 'issues.page' })).toHaveAttribute(
- 'aria-disabled',
- 'true',
- );
- expect(screen.queryByRole('link', { name: 'layout.measures' })).toHaveAttribute(
- 'aria-disabled',
- 'true',
- );
- expect(screen.getByRole('link', { name: 'project.info.title' })).toBeInTheDocument();
-});
-
-it('should disable links if application has inaccessible projects', () => {
- renderMenu({
- component: {
- ...BASE_COMPONENT,
- qualifier: ComponentQualifier.Application,
- canBrowseAllChildProjects: false,
- },
- });
- expect(screen.queryByRole('link', { name: 'overview.page' })).toHaveAttribute(
- 'aria-disabled',
- 'true',
- );
- expect(screen.queryByRole('link', { name: 'issues.page' })).toHaveAttribute(
- 'aria-disabled',
- 'true',
- );
- expect(screen.queryByRole('link', { name: 'layout.measures' })).toHaveAttribute(
- 'aria-disabled',
- 'true',
- );
- expect(screen.queryByRole('button', { name: 'application.info.title' })).not.toBeInTheDocument();
-});
-
-function renderMenu(props: Partial<ComponentPropsType<typeof Menu>> = {}, params?: string) {
- return renderComponent(
- <Menu
- hasFeature={jest.fn().mockReturnValue(false)}
- component={BASE_COMPONENT}
- isInProgress={false}
- isPending={false}
- {...props}
- />,
- params ? `/?${params}` : '/',
- { featureList: [Feature.BranchSupport] },
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/utils-test.ts b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/utils-test.ts
deleted file mode 100644
index 9c670b03c8c..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/utils-test.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { mockBranch } from '../../../../../helpers/mocks/branch-like';
-import { mockComponent } from '../../../../../helpers/mocks/component';
-import { getCurrentPage } from '../utils';
-
-describe('getCurrentPage', () => {
- it('should return a portfolio page', () => {
- expect(
- getCurrentPage(
- mockComponent({ key: 'foo', qualifier: ComponentQualifier.Portfolio }),
- undefined,
- ),
- ).toEqual({
- type: 'PORTFOLIO',
- component: 'foo',
- });
- });
-
- it('should return a portfolio page for a subportfolio too', () => {
- expect(
- getCurrentPage(
- mockComponent({ key: 'foo', qualifier: ComponentQualifier.SubPortfolio }),
- undefined,
- ),
- ).toEqual({
- type: 'PORTFOLIO',
- component: 'foo',
- });
- });
-
- it('should return an application page', () => {
- expect(
- getCurrentPage(
- mockComponent({ key: 'foo', qualifier: ComponentQualifier.Application }),
- mockBranch({ name: 'develop' }),
- ),
- ).toEqual({ type: 'APPLICATION', component: 'foo', branch: 'develop' });
- });
-
- it('should return a project page', () => {
- expect(getCurrentPage(mockComponent(), mockBranch({ name: 'feature/foo' }))).toEqual({
- type: 'PROJECT',
- component: 'my-project',
- branch: 'feature/foo',
- });
- });
-});
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchHelpTooltip.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchHelpTooltip.tsx
deleted file mode 100644
index 062673766cf..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchHelpTooltip.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Link } from '@sonarsource/echoes-react';
-import { useIntl } from 'react-intl';
-import { HelperHintIcon } from '~design-system';
-import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
-import HelpTooltip from '~sonar-aligned/components/controls/HelpTooltip';
-import { DocLink } from '../../../../../helpers/doc-links';
-import { translate } from '../../../../../helpers/l10n';
-import { getApplicationAdminUrl } from '../../../../../helpers/urls';
-import { useProjectBindingQuery } from '../../../../../queries/devops-integration';
-import { AlmKeys } from '../../../../../types/alm-settings';
-import { Component } from '../../../../../types/types';
-
-interface Props {
- branchSupportEnabled: boolean;
- canAdminComponent?: boolean;
- component: Component;
- hasManyBranches: boolean;
- isApplication: boolean;
-}
-
-export default function BranchHelpTooltip({
- component,
- isApplication,
- hasManyBranches,
- canAdminComponent,
- branchSupportEnabled,
-}: Props) {
- const helpIcon = <HelperHintIcon aria-label="help-tooltip" />;
- const { data: projectBinding } = useProjectBindingQuery(component.key);
- const isGitLab = projectBinding != null && projectBinding.alm === AlmKeys.GitLab;
-
- const intl = useIntl();
-
- if (isApplication) {
- if (!hasManyBranches && canAdminComponent) {
- return (
- <HelpTooltip
- overlay={
- <>
- <p>{translate('application.branches.help')}</p>
- <hr className="sw-my-2" />
- <Link to={getApplicationAdminUrl(component.key)}>
- {translate('application.branches.link')}
- </Link>
- </>
- }
- >
- {helpIcon}
- </HelpTooltip>
- );
- }
- } else {
- if (!branchSupportEnabled) {
- return (
- <DocHelpTooltip
- content={
- projectBinding != null
- ? intl.formatMessage(
- {
- id: `branch_like_navigation.no_branch_support.content_x.${isGitLab ? 'mr' : 'pr'}`,
- },
- { alm: translate('alm', projectBinding.alm) },
- )
- : translate('branch_like_navigation.no_branch_support.content')
- }
- data-test="branches-support-disabled"
- links={[
- {
- href: 'https://www.sonarsource.com/plans-and-pricing/developer/',
- label: translate('learn_more'),
- doc: false,
- },
- ]}
- title={
- projectBinding != null
- ? translate('branch_like_navigation.no_branch_support.title', isGitLab ? 'mr' : 'pr')
- : translate('branch_like_navigation.no_branch_support.title')
- }
- >
- {helpIcon}
- </DocHelpTooltip>
- );
- }
-
- if (!hasManyBranches) {
- return (
- <DocHelpTooltip
- content={translate('branch_like_navigation.only_one_branch.content')}
- data-test="only-one-branch-like"
- links={[
- {
- href: DocLink.BranchAnalysis,
- label: translate('branch_like_navigation.only_one_branch.documentation'),
- },
- {
- href: DocLink.PullRequestAnalysis,
- label: translate('branch_like_navigation.only_one_branch.pr_analysis'),
- },
- {
- doc: false,
- href: `/tutorials?id=${component.key}`,
- inPlace: true,
- label: translate('branch_like_navigation.tutorial_for_ci'),
- },
- ]}
- title={translate('branch_like_navigation.only_one_branch.title')}
- >
- {helpIcon}
- </DocHelpTooltip>
- );
- }
- }
-
- return null;
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchLikeNavigation.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchLikeNavigation.tsx
deleted file mode 100644
index 0b5480e49fa..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchLikeNavigation.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { Button } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { Popup, PopupPlacement, PopupZLevel } from '~design-system';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import EscKeydownHandler from '../../../../../components/controls/EscKeydownHandler';
-import FocusOutHandler from '../../../../../components/controls/FocusOutHandler';
-import OutsideClickHandler from '../../../../../components/controls/OutsideClickHandler';
-import { useBranchesQuery, useCurrentBranchQuery } from '../../../../../queries/branch';
-import { Feature } from '../../../../../types/features';
-import { Component } from '../../../../../types/types';
-import withAvailableFeatures, {
- WithAvailableFeaturesProps,
-} from '../../../available-features/withAvailableFeatures';
-import BranchHelpTooltip from './BranchHelpTooltip';
-import CurrentBranchLike from './CurrentBranchLike';
-import Menu from './Menu';
-import PRLink from './PRLink';
-
-export interface BranchLikeNavigationProps extends WithAvailableFeaturesProps {
- component: Component;
-}
-
-export function BranchLikeNavigation(props: BranchLikeNavigationProps) {
- const {
- component,
- component: { configuration },
- } = props;
-
- const { data: branchLikes } = useBranchesQuery(component);
- const { data: currentBranchLike } = useCurrentBranchQuery(component);
-
- const [isMenuOpen, setIsMenuOpen] = React.useState(false);
-
- if (currentBranchLike === undefined) {
- return null;
- }
-
- const isApplication = component.qualifier === ComponentQualifier.Application;
-
- const branchSupportEnabled = props.hasFeature(Feature.BranchSupport);
- const canAdminComponent = configuration?.showSettings;
- const hasManyBranches = branchLikes.length >= 2;
- const isMenuEnabled = branchSupportEnabled && hasManyBranches;
-
- const currentBranchLikeElement = <CurrentBranchLike currentBranchLike={currentBranchLike} />;
-
- const handleOutsideClick = () => {
- setIsMenuOpen(false);
- };
-
- return (
- <>
- <SlashSeparator className=" sw-mx-2" />
- <div
- className="sw-flex sw-items-center it__branch-like-navigation-toggler-container"
- data-spotlight-id="cayc-promotion-4"
- >
- <Popup
- allowResizing
- overlay={
- isMenuOpen && (
- <FocusOutHandler onFocusOut={handleOutsideClick}>
- <EscKeydownHandler onKeydown={handleOutsideClick}>
- <OutsideClickHandler onClickOutside={handleOutsideClick}>
- <Menu
- branchLikes={branchLikes}
- canAdminComponent={canAdminComponent}
- component={component}
- currentBranchLike={currentBranchLike}
- onClose={() => {
- setIsMenuOpen(false);
- }}
- />
- </OutsideClickHandler>
- </EscKeydownHandler>
- </FocusOutHandler>
- )
- }
- placement={PopupPlacement.BottomLeft}
- zLevel={PopupZLevel.Global}
- >
- <Button
- className="sw-max-w-abs-800 sw-px-3"
- onClick={() => {
- setIsMenuOpen(!isMenuOpen);
- }}
- isDisabled={!isMenuEnabled}
- aria-expanded={isMenuOpen}
- aria-haspopup="menu"
- >
- {currentBranchLikeElement}
- </Button>
- </Popup>
-
- <div className="sw-ml-2">
- <BranchHelpTooltip
- component={component}
- isApplication={isApplication}
- hasManyBranches={hasManyBranches}
- canAdminComponent={canAdminComponent}
- branchSupportEnabled={branchSupportEnabled}
- />
- </div>
-
- <PRLink currentBranchLike={currentBranchLike} component={component} />
- </div>
- </>
- );
-}
-
-export default withAvailableFeatures(React.memo(BranchLikeNavigation));
-
-const SlashSeparator = styled.span`
- &:after {
- content: '/';
- color: rgba(68, 68, 68, 0.3);
- }
-`;
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLike.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLike.tsx
deleted file mode 100644
index bedbc684831..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLike.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { ChevronDownIcon, TextMuted } from '~design-system';
-import BranchLikeIcon from '../../../../../components/icon-mappers/BranchLikeIcon';
-import { getBranchLikeDisplayName } from '../../../../../helpers/branch-like';
-import { BranchLike, BranchStatusData } from '../../../../../types/branch-like';
-import QualityGateStatus from './QualityGateStatus';
-
-export interface CurrentBranchLikeProps extends Pick<BranchStatusData, 'status'> {
- currentBranchLike: BranchLike;
-}
-
-export function CurrentBranchLike(props: CurrentBranchLikeProps) {
- const { currentBranchLike } = props;
-
- const displayName = getBranchLikeDisplayName(currentBranchLike);
-
- return (
- <div className="sw-flex sw-items-center sw-truncate">
- <BranchLikeIcon branchLike={currentBranchLike} />
- <TextMuted text={displayName} className="sw-ml-3" />
- <QualityGateStatus branchLike={currentBranchLike} className="sw-ml-4" />
- <ChevronDownIcon className="sw-ml-1" />
- </div>
- );
-}
-
-export default React.memo(CurrentBranchLike);
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLikeMergeInformation.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLikeMergeInformation.tsx
deleted file mode 100644
index d738326b376..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLikeMergeInformation.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { translate, translateWithParameters } from '../../../../../helpers/l10n';
-import { PullRequest } from '../../../../../types/branch-like';
-
-export interface CurrentBranchLikeMergeInformationProps {
- pullRequest: PullRequest;
-}
-
-export function CurrentBranchLikeMergeInformation({
- pullRequest,
-}: Readonly<CurrentBranchLikeMergeInformationProps>) {
- return (
- <span
- className="sw-max-w-[400px] sw-text-ellipsis sw-whitespace-nowrap sw-overflow-hidden sw-flex-shrink sw-min-w-0"
- title={translateWithParameters(
- 'branch_like_navigation.for_merge_into_x_from_y.title',
- pullRequest.target,
- pullRequest.branch,
- )}
- >
- <FormattedMessage
- defaultMessage={translate('branch_like_navigation.for_merge_into_x_from_y')}
- id="branch_like_navigation.for_merge_into_x_from_y"
- values={{
- target: <strong>{pullRequest.target}</strong>,
- branch: <strong>{pullRequest.branch}</strong>,
- }}
- />
- </span>
- );
-}
-
-export default React.memo(CurrentBranchLikeMergeInformation);
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/Menu.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/Menu.tsx
deleted file mode 100644
index 1c608d237b7..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/Menu.tsx
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { DropdownMenu, InputSearch, ItemDivider, Link } from '~design-system';
-import { withRouter } from '~sonar-aligned/components/hoc/withRouter';
-import { isBranch, isPullRequest } from '~sonar-aligned/helpers/branch-like';
-import { queryToSearchString } from '~sonar-aligned/helpers/urls';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { Router } from '~sonar-aligned/types/router';
-import { getBrancheLikesAsTree, isSameBranchLike } from '../../../../../helpers/branch-like';
-import { KeyboardKeys } from '../../../../../helpers/keycodes';
-import { translate } from '../../../../../helpers/l10n';
-import { getBranchLikeUrl } from '../../../../../helpers/urls';
-import { BranchLike, BranchLikeTree } from '../../../../../types/branch-like';
-import { Component } from '../../../../../types/types';
-import MenuItemList from './MenuItemList';
-
-interface Props {
- branchLikes: BranchLike[];
- canAdminComponent?: boolean;
- component: Component;
- currentBranchLike: BranchLike;
- onClose: () => void;
- router: Router;
-}
-
-interface State {
- branchLikesToDisplay: BranchLike[];
- branchLikesToDisplayTree: BranchLikeTree;
- query: string;
- selectedBranchLike: BranchLike | undefined;
-}
-
-export class Menu extends React.PureComponent<Props, State> {
- constructor(props: Props) {
- super(props);
-
- let selectedBranchLike = undefined;
-
- if (props.branchLikes.some((b) => isSameBranchLike(b, props.currentBranchLike))) {
- selectedBranchLike = props.currentBranchLike;
- } else if (props.branchLikes.length > 0) {
- selectedBranchLike = props.branchLikes[0];
- }
-
- this.state = {
- query: '',
- selectedBranchLike,
- ...this.processBranchLikes(props.branchLikes),
- };
- }
-
- processBranchLikes = (branchLikes: BranchLike[]) => {
- const tree = getBrancheLikesAsTree(branchLikes);
- return {
- branchLikesToDisplay: [
- ...(tree.mainBranchTree
- ? [tree.mainBranchTree.branch, ...tree.mainBranchTree.pullRequests]
- : []),
- ...tree.branchTree.reduce((prev, t) => [...prev, t.branch, ...t.pullRequests], []),
- ...tree.parentlessPullRequests,
- ...tree.orphanPullRequests,
- ],
- branchLikesToDisplayTree: tree,
- };
- };
-
- openHighlightedBranchLike = () => {
- if (this.state.selectedBranchLike) {
- this.handleOnSelect(this.state.selectedBranchLike);
- }
- };
-
- highlightSiblingBranchlike = (indexDelta: number) => {
- const selectBranchLikeIndex = this.state.branchLikesToDisplay.findIndex((b) =>
- isSameBranchLike(b, this.state.selectedBranchLike),
- );
- const newIndex = selectBranchLikeIndex + indexDelta;
-
- if (
- selectBranchLikeIndex !== -1 &&
- newIndex >= 0 &&
- newIndex < this.state.branchLikesToDisplay.length
- ) {
- this.setState(({ branchLikesToDisplay }) => ({
- selectedBranchLike: branchLikesToDisplay[newIndex],
- }));
- }
- };
-
- handleKeyDown = (event: React.KeyboardEvent) => {
- switch (event.nativeEvent.key) {
- case KeyboardKeys.Enter:
- event.preventDefault();
- this.openHighlightedBranchLike();
- break;
- case KeyboardKeys.UpArrow:
- event.preventDefault();
- this.highlightSiblingBranchlike(-1);
- break;
- case KeyboardKeys.DownArrow:
- event.preventDefault();
- this.highlightSiblingBranchlike(+1);
- break;
- }
- };
-
- handleSearchChange = (query: string) => {
- const q = query.toLowerCase();
-
- const filterBranch = (branch: BranchLike) =>
- isBranch(branch) && branch.name.toLowerCase().includes(q);
- const filterPullRequest = (pr: BranchLike) =>
- isPullRequest(pr) && (pr.title.toLowerCase().includes(q) || pr.key.toLowerCase().includes(q));
-
- const filteredBranchLikes = this.props.branchLikes.filter(
- (bl) => filterBranch(bl) || filterPullRequest(bl),
- );
-
- this.setState({
- query: q,
- selectedBranchLike: filteredBranchLikes.length > 0 ? filteredBranchLikes[0] : undefined,
- ...this.processBranchLikes(filteredBranchLikes),
- });
- };
-
- handleOnSelect = (branchLike: BranchLike) => {
- this.setState({ selectedBranchLike: branchLike }, () => {
- this.props.onClose();
- this.props.router.push(getBranchLikeUrl(this.props.component.key, branchLike));
- });
- };
-
- render() {
- const { canAdminComponent, component, onClose } = this.props;
- const { branchLikesToDisplay, branchLikesToDisplayTree, query, selectedBranchLike } =
- this.state;
- const showManageLink = component.qualifier === ComponentQualifier.Project && canAdminComponent;
- const hasResults = branchLikesToDisplay.length > 0;
-
- return (
- <DropdownMenu
- className="sw-overflow-y-auto sw-overflow-x-hidden sw-min-w-abs-350 it__branch-like-navigation-menu"
- maxHeight="38rem"
- size="auto"
- >
- <InputSearch
- className="sw-mx-3 sw-my-2"
- autoFocus
- onChange={this.handleSearchChange}
- onKeyDown={this.handleKeyDown}
- placeholder={translate('branch_like_navigation.search_for_branch_like')}
- size="auto"
- value={query}
- searchInputAriaLabel={translate('search_verb')}
- />
- <MenuItemList
- search={query}
- branchLikeTree={branchLikesToDisplayTree}
- hasResults={hasResults}
- onSelect={this.handleOnSelect}
- selectedBranchLike={selectedBranchLike}
- />
- {showManageLink && (
- <>
- <ItemDivider />
- <li className="sw-px-3 sw-py-2">
- <Link
- onClick={() => {
- onClose();
- }}
- to={{
- pathname: '/project/branches',
- search: queryToSearchString({ id: component.key }),
- }}
- >
- {translate('branch_like_navigation.manage')}
- </Link>
- </li>
- </>
- )}
- </DropdownMenu>
- );
- }
-}
-
-export default withRouter(Menu);
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/MenuItem.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/MenuItem.tsx
deleted file mode 100644
index f8abb5e6441..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/MenuItem.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import * as React from 'react';
-import { Badge, ItemButton, TextBold, TextMuted } from '~design-system';
-import { isMainBranch } from '~sonar-aligned/helpers/branch-like';
-import BranchLikeIcon from '../../../../../components/icon-mappers/BranchLikeIcon';
-import { getBranchLikeDisplayName } from '../../../../../helpers/branch-like';
-import { translate } from '../../../../../helpers/l10n';
-import { BranchLike } from '../../../../../types/branch-like';
-import QualityGateStatus from './QualityGateStatus';
-
-export interface MenuItemProps {
- branchLike: BranchLike;
- indent: boolean;
- onSelect: (branchLike: BranchLike) => void;
- selected: boolean;
- setSelectedNode?: (node: HTMLLIElement) => void;
-}
-
-export function MenuItem(props: MenuItemProps) {
- const { branchLike, setSelectedNode, onSelect, selected, indent } = props;
- const displayName = getBranchLikeDisplayName(branchLike);
-
- return (
- <ItemButton
- className={classNames({ active: selected, 'sw-pl-6': indent })}
- innerRef={selected ? setSelectedNode : undefined}
- onClick={() => {
- onSelect(branchLike);
- }}
- >
- <div className="sw-flex sw-items-center sw-justify-between sw-truncate sw-flex-1">
- <div className="sw-flex sw-items-center">
- <BranchLikeIcon branchLike={branchLike} />
-
- {isMainBranch(branchLike) && (
- <>
- <TextBold name={displayName} className="sw-ml-4 sw-mr-2" />
- <Badge variant="default">{translate('branches.main_branch')}</Badge>
- </>
- )}
- {!isMainBranch(branchLike) && (
- <TextMuted text={displayName} className="sw-ml-3 sw-mr-2" />
- )}
- </div>
- <QualityGateStatus
- branchLike={branchLike}
- className="sw-flex sw-items-center sw-w-24"
- showStatusText
- />
- </div>
- </ItemButton>
- );
-}
-
-export default React.memo(MenuItem);
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/MenuItemList.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/MenuItemList.tsx
deleted file mode 100644
index 7315a367f50..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/MenuItemList.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { useIntl } from 'react-intl';
-import { HelperHintIcon, ItemDivider, ItemHeader } from '~design-system';
-import HelpTooltip from '~sonar-aligned/components/controls/HelpTooltip';
-import { getBranchLikeKey, isSameBranchLike } from '../../../../../helpers/branch-like';
-import { translate } from '../../../../../helpers/l10n';
-import { isDefined } from '../../../../../helpers/types';
-import { BranchLike, BranchLikeTree } from '../../../../../types/branch-like';
-import MenuItem from './MenuItem';
-
-export interface MenuItemListProps {
- branchLikeTree: BranchLikeTree;
- hasResults: boolean;
- onSelect: (branchLike: BranchLike) => void;
- search: string;
- selectedBranchLike: BranchLike | undefined;
-}
-
-export function MenuItemList(props: MenuItemListProps) {
- const intl = useIntl();
- let selectedNode: HTMLLIElement | null = null;
-
- React.useEffect(() => {
- if (selectedNode) {
- selectedNode.scrollIntoView({ block: 'center' });
- selectedNode.focus();
- }
- });
-
- const { branchLikeTree, hasResults, onSelect, selectedBranchLike, search } = props;
-
- const renderItem = (branchLike: BranchLike, indent = false) => (
- <MenuItem
- branchLike={branchLike}
- key={getBranchLikeKey(branchLike)}
- onSelect={onSelect}
- selected={isSameBranchLike(branchLike, selectedBranchLike)}
- setSelectedNode={(node) => (selectedNode = node)}
- indent={indent}
- />
- );
-
- const branches = [branchLikeTree.mainBranchTree, ...branchLikeTree.branchTree].filter(isDefined);
- const total =
- branches.length +
- branches.reduce((t, branchTree) => t + (branchTree?.pullRequests.length ?? 0), 0) +
- branchLikeTree.parentlessPullRequests.length +
- branchLikeTree.orphanPullRequests.length;
-
- return (
- <ul
- aria-label={`- ${translate('branch_like_navigation.list')}`}
- className="item-list sw-overflow-y-auto sw-overflow-x-hidden"
- >
- <output>
- {!hasResults && (
- <div className="sw-px-3 sw-py-2">
- <span>{intl.formatMessage({ id: 'no_results_for_x' }, { '0': search })}</span>
- </div>
- )}
- {hasResults && (
- <span className="sw-sr-only">
- {intl.formatMessage({ id: 'results_shown_x' }, { count: total })}
- </span>
- )}
- </output>
-
- {/* BRANCHES & PR */}
- {branches.map((tree, treeIndex) => (
- <React.Fragment key={getBranchLikeKey(tree.branch)}>
- {renderItem(tree.branch)}
- {tree.pullRequests.length > 0 && (
- <ul
- aria-label={` - ${intl.formatMessage({ id: 'branch_like_navigation.pull_requests_targeting' }, { branch: tree.branch.name })}`}
- >
- <ItemDivider aria-hidden />
- <ItemHeader aria-hidden>
- {translate('branch_like_navigation.pull_requests')}
- </ItemHeader>
- <ItemDivider aria-hidden />
- {tree.pullRequests.map((pr) => renderItem(pr, true))}
- {tree.pullRequests.length > 0 && treeIndex !== branches.length - 1 && <ItemDivider />}
- </ul>
- )}
- </React.Fragment>
- ))}
-
- {/* PARENTLESS PR (for display during search) */}
- {branchLikeTree.parentlessPullRequests.length > 0 && (
- <ul aria-label={` - ${translate('branch_like_navigation.pull_requests')}`}>
- <ItemDivider aria-hidden />
- <ItemHeader aria-hidden>{translate('branch_like_navigation.pull_requests')}</ItemHeader>
- <ItemDivider aria-hidden />
- {branchLikeTree.parentlessPullRequests.map((pr) => renderItem(pr))}
- </ul>
- )}
-
- {/* ORPHAN PR */}
- {branchLikeTree.orphanPullRequests.length > 0 && (
- <ul aria-label={` - ${translate('branch_like_navigation.orphan_pull_requests')}`}>
- <ItemDivider aria-hidden />
- <ItemHeader>
- {translate('branch_like_navigation.orphan_pull_requests')}
- <HelpTooltip
- className="sw-ml-1"
- overlay={translate('branch_like_navigation.orphan_pull_requests.tooltip')}
- >
- <HelperHintIcon />
- </HelpTooltip>
- </ItemHeader>
- <ItemDivider aria-hidden />
- {branchLikeTree.orphanPullRequests.map((pr) => renderItem(pr))}
- </ul>
- )}
- </ul>
- );
-}
-
-export default React.memo(MenuItemList);
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/PRLink.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/PRLink.tsx
deleted file mode 100644
index 1325cc7c632..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/PRLink.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkStandalone } from '@sonarsource/echoes-react';
-import { Image } from '~sonar-aligned/components/common/Image';
-import { isPullRequest } from '~sonar-aligned/helpers/branch-like';
-import { translate, translateWithParameters } from '../../../../../helpers/l10n';
-import { isDefined } from '../../../../../helpers/types';
-import { AlmKeys } from '../../../../../types/alm-settings';
-import { BranchLike } from '../../../../../types/branch-like';
-import { Component } from '../../../../../types/types';
-
-function getPRUrlAlmKey(url = '') {
- const lowerCaseUrl = url.toLowerCase();
-
- if (lowerCaseUrl.includes(AlmKeys.GitHub)) {
- return AlmKeys.GitHub;
- } else if (lowerCaseUrl.includes(AlmKeys.GitLab)) {
- return AlmKeys.GitLab;
- } else if (lowerCaseUrl.includes(AlmKeys.BitbucketServer)) {
- return AlmKeys.BitbucketServer;
- } else if (
- lowerCaseUrl.includes(AlmKeys.Azure) ||
- lowerCaseUrl.includes('microsoft') ||
- lowerCaseUrl.includes('visualstudio')
- ) {
- return AlmKeys.Azure;
- }
-
- return undefined;
-}
-
-export default function PRLink({
- currentBranchLike,
- component,
-}: Readonly<{
- component: Component;
- currentBranchLike: BranchLike;
-}>) {
- if (!isPullRequest(currentBranchLike)) {
- return null;
- }
-
- const almKey =
- component.alm?.key ||
- (isPullRequest(currentBranchLike) && getPRUrlAlmKey(currentBranchLike.url)) ||
- '';
-
- return (
- <>
- {isDefined(currentBranchLike.url) && (
- <LinkStandalone
- iconLeft={
- almKey !== '' && (
- <Image
- alt={almKey}
- height={16}
- src={`/images/alm/${almKey}.svg`}
- title={translateWithParameters('branches.see_the_pr_on_x', translate(almKey))}
- />
- )
- }
- key={currentBranchLike.key}
- to={currentBranchLike.url}
- >
- {almKey === '' && translate('branches.see_the_pr')}
- </LinkStandalone>
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/QualityGateStatus.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/QualityGateStatus.tsx
deleted file mode 100644
index ca8baf5c313..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/QualityGateStatus.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { QualityGateIndicator } from '~design-system';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import { BranchLike } from '../../../../../types/branch-like';
-
-interface Props {
- branchLike: BranchLike;
- className: string;
- showStatusText?: boolean;
-}
-
-export default function QualityGateStatus(props: Readonly<Props>) {
- const { className, showStatusText, branchLike } = props;
-
- // eslint-disable-next-line @typescript-eslint/prefer-optional-chain, @typescript-eslint/no-unnecessary-condition
- if (!branchLike.status?.qualityGateStatus) {
- return null;
- }
-
- const formatted = formatMeasure(branchLike.status?.qualityGateStatus, MetricType.Level);
- return (
- <div className={classNames(`it__level-${branchLike.status.qualityGateStatus}`, className)}>
- <QualityGateIndicator
- status={branchLike.status?.qualityGateStatus}
- className="sw-mr-2"
- size="sm"
- />
- {showStatusText && <span>{formatted}</span>}
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/utils.ts b/server/sonar-web/src/main/js/app/components/nav/component/utils.ts
deleted file mode 100644
index bbbd1e3890e..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/component/utils.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { isBranch } from '~sonar-aligned/helpers/branch-like';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { BranchLike } from '../../../../types/branch-like';
-import { Component } from '../../../../types/types';
-import { HomePage } from '../../../../types/users';
-
-export function getCurrentPage(component: Component, branchLike: BranchLike | undefined) {
- let currentPage: HomePage | undefined;
-
- const branch = isBranch(branchLike) && !branchLike.isMain ? branchLike.name : undefined;
-
- switch (component.qualifier) {
- case ComponentQualifier.Portfolio:
- case ComponentQualifier.SubPortfolio:
- currentPage = { type: 'PORTFOLIO', component: component.key };
- break;
- case ComponentQualifier.Application:
- currentPage = {
- type: 'APPLICATION',
- component: component.key,
- branch,
- };
- break;
- case ComponentQualifier.Project:
- // when home page is set to the default branch of a project, its name is returned as `undefined`
- currentPage = {
- type: 'PROJECT',
- component: component.key,
- branch,
- };
- break;
- }
-
- return currentPage;
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx
deleted file mode 100644
index 4bcbfd95288..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import EmbedDocsPopupHelper from '../../../../components/embed-docs-modal/EmbedDocsPopupHelper';
-import { CurrentUser } from '../../../../types/users';
-import withCurrentUserContext from '../../current-user/withCurrentUserContext';
-import GlobalSearch from '../../global-search/GlobalSearch';
-import GlobalNavMenu from './GlobalNavMenu';
-import { GlobalNavUser } from './GlobalNavUser';
-import MainSonarQubeBar from './MainSonarQubeBar';
-
-export interface GlobalNavProps {
- currentUser: CurrentUser;
- location: { pathname: string };
-}
-
-export function GlobalNav(props: GlobalNavProps) {
- const { currentUser, location } = props;
- return (
- <MainSonarQubeBar>
- <div className="sw-flex" id="global-navigation">
- <div className="it__global-navbar-menu sw-flex sw-justify-start sw-items-center sw-flex-1">
- <GlobalNavMenu currentUser={currentUser} location={location} />
- <div className="sw-px-8 sw-flex-1">
- <GlobalSearch />
- </div>
- </div>
-
- <div className="sw-flex sw-items-center sw-ml-2">
- <EmbedDocsPopupHelper />
- <div className="sw-ml-4">
- <GlobalNavUser />
- </div>
- </div>
- </div>
- </MainSonarQubeBar>
- );
-}
-
-export default withCurrentUserContext(GlobalNav);
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx
deleted file mode 100644
index 450be91202c..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import * as React from 'react';
-import { NavLink } from 'react-router-dom';
-import { MainMenu, MainMenuItem } from '~design-system';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { isMySet } from '../../../../apps/issues/utils';
-import Link from '../../../../components/common/Link';
-import { DEFAULT_ISSUES_QUERY } from '../../../../components/shared/utils';
-import { translate } from '../../../../helpers/l10n';
-import { getQualityGatesUrl } from '../../../../helpers/urls';
-import { AppState } from '../../../../types/appstate';
-import { CurrentUser } from '../../../../types/users';
-import withAppStateContext from '../../app-state/withAppStateContext';
-import GlobalNavMore from './GlobalNavMore';
-
-interface Props {
- appState: AppState;
- currentUser: CurrentUser;
- location: { pathname: string };
-}
-
-const ACTIVE_CLASS_NAME = 'active';
-
-class GlobalNavMenu extends React.PureComponent<Props> {
- renderProjects() {
- const active =
- this.props.location.pathname.startsWith('/projects') &&
- this.props.location.pathname !== '/projects/create';
-
- return (
- <MainMenuItem>
- <Link
- aria-current={active ? 'page' : undefined}
- className={classNames({ active })}
- to="/projects"
- >
- {translate('projects.page')}
- </Link>
- </MainMenuItem>
- );
- }
-
- renderPortfolios() {
- return (
- <MainMenuItem>
- <NavLink className={({ isActive }) => (isActive ? ACTIVE_CLASS_NAME : '')} to="/portfolios">
- {translate('portfolios.page')}
- </NavLink>
- </MainMenuItem>
- );
- }
-
- renderIssuesLink() {
- const search = (
- this.props.currentUser.isLoggedIn && isMySet()
- ? new URLSearchParams({ myIssues: 'true', ...DEFAULT_ISSUES_QUERY })
- : new URLSearchParams(DEFAULT_ISSUES_QUERY)
- ).toString();
-
- return (
- <MainMenuItem>
- <NavLink
- className={({ isActive }) => (isActive ? ACTIVE_CLASS_NAME : '')}
- to={{ pathname: '/issues', search }}
- >
- {translate('issues.page')}
- </NavLink>
- </MainMenuItem>
- );
- }
-
- renderRulesLink() {
- return (
- <MainMenuItem>
- <NavLink
- className={({ isActive }) => (isActive ? ACTIVE_CLASS_NAME : '')}
- to="/coding_rules"
- >
- {translate('coding_rules.page')}
- </NavLink>
- </MainMenuItem>
- );
- }
-
- renderProfilesLink() {
- return (
- <MainMenuItem>
- <NavLink className={({ isActive }) => (isActive ? ACTIVE_CLASS_NAME : '')} to="/profiles">
- {translate('quality_profiles.page')}
- </NavLink>
- </MainMenuItem>
- );
- }
-
- renderQualityGatesLink() {
- return (
- <MainMenuItem>
- <NavLink
- className={({ isActive }) => (isActive ? ACTIVE_CLASS_NAME : '')}
- to={getQualityGatesUrl()}
- >
- {translate('quality_gates.page')}
- </NavLink>
- </MainMenuItem>
- );
- }
-
- renderAdministrationLink() {
- if (!this.props.appState.canAdmin) {
- return null;
- }
-
- return (
- <MainMenuItem>
- <NavLink
- data-guiding-id="mode-tour-1"
- className={({ isActive }) => (isActive ? ACTIVE_CLASS_NAME : '')}
- to="/admin/settings"
- >
- {translate('layout.settings')}
- </NavLink>
- </MainMenuItem>
- );
- }
-
- render() {
- const governanceInstalled = this.props.appState.qualifiers.includes(
- ComponentQualifier.Portfolio,
- );
-
- return (
- <nav aria-label={translate('global')}>
- <MainMenu>
- {this.renderProjects()}
- {governanceInstalled && this.renderPortfolios()}
- {this.renderIssuesLink()}
- {this.renderRulesLink()}
- {this.renderProfilesLink()}
- {this.renderQualityGatesLink()}
- {this.renderAdministrationLink()}
- <GlobalNavMore />
- </MainMenu>
- </nav>
- );
- }
-}
-
-export default withAppStateContext(GlobalNavMenu);
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMore.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMore.tsx
deleted file mode 100644
index 094f55130f1..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMore.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { DropdownMenu, DropdownMenuAlign } from '@sonarsource/echoes-react';
-import { FormattedMessage } from 'react-intl';
-import { MainMenuItem } from '~design-system';
-import { AppState } from '../../../../types/appstate';
-import { Extension } from '../../../../types/types';
-import withAppStateContext from '../../app-state/withAppStateContext';
-
-const renderGlobalPageLink = ({ key, name }: Extension) => {
- return (
- <DropdownMenu.ItemLink key={key} to={`/extension/${key}`}>
- {name}
- </DropdownMenu.ItemLink>
- );
-};
-
-function GlobalNavMore({ appState: { globalPages = [] } }: Readonly<{ appState: AppState }>) {
- const withoutPortfolios = globalPages.filter((page) => page.key !== 'governance/portfolios');
-
- if (withoutPortfolios.length === 0) {
- return null;
- }
-
- return (
- <DropdownMenu.Root
- align={DropdownMenuAlign.Start}
- id="moreMenuDropdown"
- items={withoutPortfolios.map(renderGlobalPageLink)}
- >
- <MainMenuItem>
- <a aria-haspopup="menu" href="#" id="global-navigation-more" role="button">
- <FormattedMessage id="more" />
- </a>
- </MainMenuItem>
- </DropdownMenu.Root>
- );
-}
-
-export default withAppStateContext(GlobalNavMore);
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx
deleted file mode 100644
index b9498eb89f1..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, DropdownMenu, DropdownMenuAlign, Tooltip } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { Avatar, BareButton } from '~design-system';
-import { translate } from '../../../../helpers/l10n';
-import { getBaseUrl } from '../../../../helpers/system';
-import { GlobalSettingKeys } from '../../../../types/settings';
-import { isLoggedIn } from '../../../../types/users';
-import { AppStateContext } from '../../app-state/AppStateContext';
-import { CurrentUserContext } from '../../current-user/CurrentUserContext';
-import { GlobalNavUserMenu } from './GlobalNavUserMenu';
-
-export function GlobalNavUser() {
- const userContext = React.useContext(CurrentUserContext);
- const currentUser = userContext?.currentUser;
-
- const { settings } = React.useContext(AppStateContext);
-
- const handleLogin = React.useCallback(() => {
- const returnTo = encodeURIComponent(window.location.pathname + window.location.search);
- window.location.href = `${getBaseUrl()}/sessions/new?return_to=${returnTo}${
- window.location.hash
- }`;
- }, []);
-
- if (!currentUser || !isLoggedIn(currentUser)) {
- return (
- <div>
- <Button onClick={handleLogin}>{translate('layout.login')}</Button>
- </div>
- );
- }
-
- const enableGravatar = settings[GlobalSettingKeys.EnableGravatar] === 'true';
- const gravatarServerUrl = settings[GlobalSettingKeys.GravatarServerUrl] ?? '';
-
- return (
- <DropdownMenu.Root
- align={DropdownMenuAlign.End}
- header={{ helpText: currentUser.email ?? '', label: currentUser.name }}
- id="userAccountMenuDropdown"
- items={<GlobalNavUserMenu />}
- >
- <Tooltip content={translate('global_nav.account.tooltip')}>
- <BareButton aria-label={translate('global_nav.account.tooltip')}>
- <Avatar
- enableGravatar={enableGravatar}
- gravatarServerUrl={gravatarServerUrl}
- hash={currentUser.avatar}
- name={currentUser.name}
- />
- </BareButton>
- </Tooltip>
- </DropdownMenu.Root>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserMenu.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserMenu.tsx
deleted file mode 100644
index 39d6508e423..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserMenu.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { DropdownMenu } from '@sonarsource/echoes-react';
-import { translate } from '../../../../helpers/l10n';
-
-export function GlobalNavUserMenu() {
- return (
- <>
- <DropdownMenu.ItemLink isMatchingFullPath to="/account">
- {translate('my_account.page')}
- </DropdownMenu.ItemLink>
-
- <DropdownMenu.Separator />
-
- <DropdownMenu.ItemLink to="/sessions/logout">
- {translate('layout.logout')}
- </DropdownMenu.ItemLink>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/MainSonarQubeBar.tsx b/server/sonar-web/src/main/js/app/components/nav/global/MainSonarQubeBar.tsx
deleted file mode 100644
index 5a642219a17..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/global/MainSonarQubeBar.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LogoSize } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { MainAppBar } from '~design-system';
-import { Image } from '~sonar-aligned/components/common/Image';
-import { SonarQubeProductLogo } from '../../../../components/branding/SonarQubeProductLogo';
-import { translate } from '../../../../helpers/l10n';
-import { GlobalSettingKeys } from '../../../../types/settings';
-import { AppStateContext } from '../../app-state/AppStateContext';
-
-const DEFAULT_CUSTOM_LOGO_WIDTH_IN_PX = 100;
-
-function LogoWithAriaText() {
- const { settings } = React.useContext(AppStateContext);
- const customLogoUrl = settings[GlobalSettingKeys.LogoUrl];
- const customLogoWidth = settings[GlobalSettingKeys.LogoWidth] ?? DEFAULT_CUSTOM_LOGO_WIDTH_IN_PX;
-
- const title = customLogoUrl
- ? translate('layout.nav.home_logo_alt')
- : translate('layout.nav.home_sonarqube_logo_alt');
-
- return (
- <div aria-label={title} role="img">
- {customLogoUrl ? (
- <Image alt={title} src={customLogoUrl} width={customLogoWidth} />
- ) : (
- <SonarQubeProductLogo hasText size={LogoSize.Large} />
- )}
- </div>
- );
-}
-
-export default function MainSonarQubeBar({ children }: React.PropsWithChildren<object>) {
- return <MainAppBar Logo={LogoWithAriaText}>{children}</MainAppBar>;
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNav-test.tsx b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNav-test.tsx
deleted file mode 100644
index 400fd09a084..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNav-test.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { mockAppState, mockCurrentUser, mockLocation } from '../../../../../helpers/testMocks';
-import { renderApp } from '../../../../../helpers/testReactTestingUtils';
-import GlobalNav from '../GlobalNav';
-
-it('render global navigation correctly for anonymous user', () => {
- renderGlobalNav({ appState: mockAppState() });
- expect(screen.getByText('projects.page')).toBeInTheDocument();
- expect(screen.getByText('issues.page')).toBeInTheDocument();
- expect(screen.getByText('coding_rules.page')).toBeInTheDocument();
- expect(screen.getByText('quality_profiles.page')).toBeInTheDocument();
- expect(screen.getByText('quality_gates.page')).toBeInTheDocument();
- expect(screen.getByText('layout.login')).toBeInTheDocument();
-});
-
-it('render global navigation correctly for logged in user', () => {
- renderGlobalNav({ currentUser: mockCurrentUser({ isLoggedIn: true }) });
- expect(screen.getByText('projects.page')).toBeInTheDocument();
- expect(screen.queryByText('layout.login')).not.toBeInTheDocument();
-});
-
-it('render the logo correctly', () => {
- renderGlobalNav({
- appState: mockAppState({
- settings: {
- 'sonar.lf.logoUrl': 'http://sonarsource.com/test.svg',
- },
- }),
- });
- const image = screen.getByAltText('layout.nav.home_logo_alt');
- expect(image).toHaveAttribute('src', 'http://sonarsource.com/test.svg');
-});
-
-function renderGlobalNav({ appState = mockAppState(), currentUser = mockCurrentUser() }) {
- renderApp('/', <GlobalNav location={mockLocation()} />, {
- appState,
- currentUser,
- });
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavMenu-test.tsx b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavMenu-test.tsx
deleted file mode 100644
index d36f978a1d6..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavMenu-test.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { mockAppState, mockCurrentUser } from '../../../../../helpers/testMocks';
-import { renderApp } from '../../../../../helpers/testReactTestingUtils';
-import GlobalNavMenu from '../GlobalNavMenu';
-
-it('should work with extensions', () => {
- const appState = mockAppState({
- globalPages: [{ key: 'foo', name: 'Foo' }],
- qualifiers: ['TRK'],
- });
-
- const currentUser = mockCurrentUser({
- isLoggedIn: false,
- dismissedNotices: {},
- });
- renderGlobalNavMenu({ appState, currentUser });
- expect(screen.getByText('more')).toBeInTheDocument();
-});
-
-it('should show administration menu if the user has the rights', () => {
- const appState = mockAppState({
- canAdmin: true,
- globalPages: [],
- qualifiers: ['TRK'],
- });
- const currentUser = mockCurrentUser({
- isLoggedIn: false,
- dismissedNotices: {},
- });
-
- renderGlobalNavMenu({ appState, currentUser });
- expect(screen.getByText('layout.settings')).toBeInTheDocument();
-});
-
-function renderGlobalNavMenu({
- appState = mockAppState(),
- currentUser = mockCurrentUser(),
- location = { pathname: '' },
-}) {
- renderApp('/', <GlobalNavMenu currentUser={currentUser} location={location} />, {
- appState,
- });
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx
deleted file mode 100644
index e2eccbba5e1..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { mockCurrentUser, mockLoggedInUser } from '../../../../../helpers/testMocks';
-import { renderApp } from '../../../../../helpers/testReactTestingUtils';
-import { CurrentUser } from '../../../../../types/users';
-import { GlobalNavUser } from '../GlobalNavUser';
-
-it('should render the right interface for anonymous user', () => {
- renderGlobalNavUser({ currentUser: mockCurrentUser() });
- expect(screen.getByText('layout.login')).toBeInTheDocument();
-});
-
-it('should render the right interface for logged in user', async () => {
- const user = userEvent.setup();
- renderGlobalNavUser();
- await user.click(screen.getByRole('button'));
-
- expect(screen.getAllByRole('menuitem')).toHaveLength(2);
-});
-
-function renderGlobalNavUser(overrides: { currentUser?: CurrentUser } = {}) {
- return renderApp('/', <GlobalNavUser />, { currentUser: mockLoggedInUser(), ...overrides });
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/settings/PendingPluginsActionNotif.tsx b/server/sonar-web/src/main/js/app/components/nav/settings/PendingPluginsActionNotif.tsx
deleted file mode 100644
index fd5ed23cc89..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/settings/PendingPluginsActionNotif.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, ButtonGroup } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { FlagMessage } from '~design-system';
-import { cancelPendingPlugins } from '../../../../api/plugins';
-import InstanceMessage from '../../../../components/common/InstanceMessage';
-import RestartButton from '../../../../components/common/RestartButton';
-import { translate } from '../../../../helpers/l10n';
-import { PendingPluginResult } from '../../../../types/plugins';
-import { SysStatus } from '../../../../types/types';
-
-interface Props {
- fetchSystemStatus: () => void;
- pending: PendingPluginResult;
- refreshPending: () => void;
- systemStatus: SysStatus;
-}
-
-export default class PendingPluginsActionNotif extends React.PureComponent<Props> {
- handleRevert = () => {
- cancelPendingPlugins().then(this.props.refreshPending, () => {});
- };
-
- render() {
- const { installing, updating, removing } = this.props.pending;
- const hasPendingActions = installing.length || updating.length || removing.length;
- if (!hasPendingActions) {
- return null;
- }
-
- return (
- <FlagMessage className="sw-w-full" variant="info">
- <div className="sw-flex sw-items-center">
- <span className="sw-mr-1">
- <InstanceMessage message={translate('marketplace.instance_needs_to_be_restarted_to')} />
- </span>
- {[
- { length: installing.length, msg: 'marketplace.install_x_plugins' },
- { length: updating.length, msg: 'marketplace.update_x_plugins' },
- { length: removing.length, msg: 'marketplace.uninstall_x_plugins' },
- ]
- .filter(({ length }) => length > 0)
- .map(({ length, msg }, idx) => (
- <span key={msg}>
- {idx > 0 && '; '}
- <FormattedMessage
- defaultMessage={translate(msg)}
- id={msg}
- values={{ nb: <strong>{length}</strong> }}
- />
- </span>
- ))}
- <ButtonGroup className="sw-ml-2">
- <RestartButton
- fetchSystemStatus={this.props.fetchSystemStatus}
- systemStatus={this.props.systemStatus}
- />
- <Button onClick={this.handleRevert}>{translate('marketplace.revert')}</Button>
- </ButtonGroup>
- </div>
- </FlagMessage>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.tsx b/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.tsx
deleted file mode 100644
index 83f76c732b9..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.tsx
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { DropdownMenu, DropdownMenuAlign } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { Location } from 'react-router-dom';
-import { LightLabel, NavBarTabLink, NavBarTabs, TopBar } from '~design-system';
-import withLocation from '../../../../components/hoc/withLocation';
-import { translate } from '../../../../helpers/l10n';
-import { getBaseUrl } from '../../../../helpers/system';
-import { AdminPageExtension } from '../../../../types/extension';
-import { PendingPluginResult } from '../../../../types/plugins';
-import { Extension, SysStatus } from '../../../../types/types';
-import PendingPluginsActionNotif from './PendingPluginsActionNotif';
-import SystemRestartNotif from './SystemRestartNotif';
-
-interface Props {
- extensions: Extension[];
- fetchPendingPlugins: () => void;
- fetchSystemStatus: () => void;
- location: Location;
- pendingPlugins: PendingPluginResult;
- systemStatus: SysStatus;
-}
-
-export class SettingsNav extends React.PureComponent<Props> {
- static defaultProps = {
- extensions: [],
- };
-
- isSomethingActive = (urls: string[]) => {
- const path = this.props.location.pathname;
- return urls.some((url: string) => path.indexOf(getBaseUrl() + url) === 0);
- };
-
- isSecurityActive() {
- const urls = [
- '/admin/users',
- '/admin/groups',
- '/admin/permissions',
- '/admin/permission_templates',
- ];
- return this.isSomethingActive(urls);
- }
-
- isProjectsActive() {
- const urls = ['/admin/projects_management', '/admin/background_tasks'];
- return this.isSomethingActive(urls);
- }
-
- isSystemActive() {
- const urls = ['/admin/system'];
- return this.isSomethingActive(urls);
- }
-
- isMarketplace() {
- const urls = ['/admin/marketplace'];
- return this.isSomethingActive(urls);
- }
-
- isAudit() {
- const urls = ['/admin/audit'];
- return this.isSomethingActive(urls);
- }
-
- renderExtension = ({ key, name }: Extension) => {
- return (
- <DropdownMenu.ItemLink isMatchingFullPath key={key} to={`/admin/extension/${key}`}>
- {name}
- </DropdownMenu.ItemLink>
- );
- };
-
- renderConfigurationTab() {
- const extensionsWithoutSupport = this.props.extensions.filter(
- (extension) => extension.key !== 'license/support',
- );
-
- return (
- <DropdownMenu.Root
- align={DropdownMenuAlign.Start}
- id="settings-navigation-configuration-dropdown"
- items={
- <>
- <DropdownMenu.ItemLink isMatchingFullPath to="/admin/settings">
- {translate('settings.page')}
- </DropdownMenu.ItemLink>
-
- <DropdownMenu.ItemLink isMatchingFullPath to="/admin/settings/encryption">
- {translate('property.category.security.encryption')}
- </DropdownMenu.ItemLink>
-
- <DropdownMenu.ItemLink isMatchingFullPath to="/admin/webhooks">
- {translate('webhooks.page')}
- </DropdownMenu.ItemLink>
-
- {extensionsWithoutSupport.map(this.renderExtension)}
- </>
- }
- >
- <NavBarTabLink
- aria-haspopup="menu"
- active={
- !this.isSecurityActive() &&
- !this.isProjectsActive() &&
- !this.isSystemActive() &&
- !this.isSomethingActive(['/admin/extension/license/support']) &&
- !this.isMarketplace() &&
- !this.isAudit()
- }
- id="settings-navigation-configuration"
- text={translate('sidebar.project_settings')}
- to={{}}
- withChevron
- />
- </DropdownMenu.Root>
- );
- }
-
- renderProjectsTab() {
- return (
- <DropdownMenu.Root
- id="settings-navigation-projects-dropdown"
- items={
- <>
- <DropdownMenu.ItemLink isMatchingFullPath to="/admin/projects_management">
- {translate('management')}
- </DropdownMenu.ItemLink>
-
- <DropdownMenu.ItemLink isMatchingFullPath to="/admin/background_tasks">
- {translate('background_tasks.page')}
- </DropdownMenu.ItemLink>
- </>
- }
- >
- <NavBarTabLink
- aria-haspopup="menu"
- active={this.isProjectsActive()}
- to={{}}
- text={translate('sidebar.projects')}
- withChevron
- />
- </DropdownMenu.Root>
- );
- }
-
- renderSecurityTab() {
- return (
- <DropdownMenu.Root
- id="settings-navigation-security-dropdown"
- items={
- <>
- <DropdownMenu.ItemLink isMatchingFullPath to="/admin/users">
- {translate('users.page')}
- </DropdownMenu.ItemLink>
-
- <DropdownMenu.ItemLink isMatchingFullPath to="/admin/groups">
- {translate('user_groups.page')}
- </DropdownMenu.ItemLink>
-
- <DropdownMenu.ItemLink isMatchingFullPath to="/admin/permissions">
- {translate('global_permissions.page')}
- </DropdownMenu.ItemLink>
-
- <DropdownMenu.ItemLink isMatchingFullPath to="/admin/permission_templates">
- {translate('permission_templates')}
- </DropdownMenu.ItemLink>
- </>
- }
- >
- <NavBarTabLink
- aria-haspopup="menu"
- active={this.isSecurityActive()}
- to={{}}
- text={translate('sidebar.security')}
- withChevron
- />
- </DropdownMenu.Root>
- );
- }
-
- render() {
- const { extensions, pendingPlugins } = this.props;
- const hasSupportExtension = extensions.find((extension) => extension.key === 'license/support');
-
- const hasGovernanceExtension = extensions.find(
- (e) => e.key === AdminPageExtension.GovernanceConsole,
- );
-
- const totalPendingPlugins =
- pendingPlugins.installing.length +
- pendingPlugins.removing.length +
- pendingPlugins.updating.length;
-
- let notifComponent;
-
- if (this.props.systemStatus === 'RESTARTING') {
- notifComponent = <SystemRestartNotif />;
- } else if (totalPendingPlugins > 0) {
- notifComponent = (
- <PendingPluginsActionNotif
- fetchSystemStatus={this.props.fetchSystemStatus}
- pending={pendingPlugins}
- refreshPending={this.props.fetchPendingPlugins}
- systemStatus={this.props.systemStatus}
- />
- );
- }
-
- return (
- <>
- <TopBar id="context-navigation" aria-label={translate('settings')}>
- <LightLabel as="h1">{translate('layout.settings')}</LightLabel>
-
- <NavBarTabs className="it__navbar-tabs sw-mt-4">
- {this.renderConfigurationTab()}
- {this.renderSecurityTab()}
- {this.renderProjectsTab()}
-
- <NavBarTabLink end to="/admin/system" text={translate('sidebar.system')} />
-
- <NavBarTabLink end to="/admin/marketplace" text={translate('marketplace.page')} />
-
- {hasGovernanceExtension && (
- <NavBarTabLink end to="/admin/audit" text={translate('audit_logs.page')} />
- )}
-
- {hasSupportExtension && (
- <NavBarTabLink
- end
- to="/admin/extension/license/support"
- text={translate('support')}
- />
- )}
- </NavBarTabs>
- </TopBar>
-
- {notifComponent}
- </>
- );
- }
-}
-
-export default withLocation(SettingsNav);
diff --git a/server/sonar-web/src/main/js/app/components/nav/settings/SystemRestartNotif.tsx b/server/sonar-web/src/main/js/app/components/nav/settings/SystemRestartNotif.tsx
deleted file mode 100644
index e8dad0f4817..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/settings/SystemRestartNotif.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { FlagMessage, Link } from '~design-system';
-import { translate } from '../../../../helpers/l10n';
-import { getInstance } from '../../../../helpers/system';
-
-export default function SystemRestartNotif() {
- return (
- <FlagMessage variant="info" className="sw-w-full">
- <span>
- <FormattedMessage
- defaultMessage={translate('system.instance_restarting')}
- id="system.instance_restarting"
- values={{
- instance: getInstance(),
- link: <Link to="/admin/background_tasks">{translate('background_tasks.page')}</Link>,
- }}
- />
- </span>
- </FlagMessage>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.tsx b/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.tsx
deleted file mode 100644
index 8bf0ca1a0f9..00000000000
--- a/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { Button, Theme, ThemeProvider } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { ButtonPrimary, themeBorder, themeColor } from '~design-system';
-import { dismissNotice } from '../../../api/users';
-import { SonarQubeIDEPromotionIllustration } from '../../../components/branding/SonarQubeIDEPromotionIllustration';
-import { translate } from '../../../helpers/l10n';
-import { NoticeType, isLoggedIn } from '../../../types/users';
-import { CurrentUserContextInterface } from '../current-user/CurrentUserContext';
-import withCurrentUserContext from '../current-user/withCurrentUserContext';
-
-export function PromotionNotification(props: CurrentUserContextInterface) {
- const { currentUser, updateDismissedNotices } = props;
-
- const onClick = React.useCallback(() => {
- return dismissNotice(NoticeType.SONARLINT_AD)
- .then(() => {
- updateDismissedNotices(NoticeType.SONARLINT_AD, true);
- })
- .catch(() => {
- /* noop */
- });
- }, [updateDismissedNotices]);
-
- if (!isLoggedIn(currentUser) || currentUser.dismissedNotices[NoticeType.SONARLINT_AD]) {
- return null;
- }
-
- return (
- <PromotionNotificationWrapper className="it__promotion_notification sw-z-global-popup sw-rounded-1 sw-flex sw-items-center sw-px-4">
- <ThemeProvider theme={Theme.dark}>
- <div className="sw-mr-2">
- <SonarQubeIDEPromotionIllustration />
- </div>
- </ThemeProvider>
- <PromotionNotificationContent className="sw-flex-1 sw-px-2 sw-py-4">
- <span className="sw-typo-semibold">{translate('promotion.sonarlint.title')}</span>
- <p className="sw-mt-2">{translate('promotion.sonarlint.content')}</p>
- </PromotionNotificationContent>
- <div className="sw-ml-2 sw-pl-2 sw-flex sw-flex-col sw-items-stretch">
- <ButtonPrimary
- className="sw-mb-4"
- to="https://www.sonarsource.com/products/sonarlint/?referrer=sonarqube-welcome"
- onClick={onClick}
- >
- {translate('learn_more')}
- </ButtonPrimary>
- <Button className="sw-justify-center" onClick={onClick}>
- {translate('dismiss')}
- </Button>
- </div>
- </PromotionNotificationWrapper>
- );
-}
-
-export default withCurrentUserContext(PromotionNotification);
-
-const PromotionNotificationWrapper = styled.div`
- position: fixed;
- right: 10px;
- bottom: 10px;
- max-width: 600px;
- box-shadow: 1px 1px 5px 0px black;
-
- background: ${themeColor('promotionNotificationBackground')};
- color: ${themeColor('promotionNotification')};
-`;
-
-const PromotionNotificationContent = styled.div`
- border-right: ${themeBorder('default', 'promotionNotificationSeparator')};
-`;
diff --git a/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/PromotionNotification-test.tsx b/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/PromotionNotification-test.tsx
deleted file mode 100644
index 66ec203c920..00000000000
--- a/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/PromotionNotification-test.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { dismissNotice } from '../../../../api/users';
-import { mockCurrentUser, mockLoggedInUser } from '../../../../helpers/testMocks';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { CurrentUser, NoticeType } from '../../../../types/users';
-import PromotionNotification from '../PromotionNotification';
-
-jest.mock('../../../../api/users', () => ({
- dismissNotice: jest.fn().mockResolvedValue(undefined),
-}));
-
-it('should not render when anonymous', () => {
- renderPromotionNotification(mockCurrentUser({ isLoggedIn: false }));
-
- expect(byText('promotion.sonarlint.title').query()).not.toBeInTheDocument();
-});
-
-it('should not render if previously dismissed', () => {
- renderPromotionNotification(
- mockLoggedInUser({ dismissedNotices: { [NoticeType.SONARLINT_AD]: true } }),
- );
-
- expect(byText('promotion.sonarlint.title').query()).not.toBeInTheDocument();
-});
-
-it('should be dismissable', async () => {
- const user = userEvent.setup();
-
- renderPromotionNotification();
-
- expect(byText('promotion.sonarlint.title').get()).toBeInTheDocument();
- const dismissButton = byRole('button', { name: 'dismiss' }).get();
-
- expect(dismissButton).toBeInTheDocument();
- await user.click(dismissButton);
-
- expect(dismissNotice).toHaveBeenCalledWith(NoticeType.SONARLINT_AD);
-});
-
-function renderPromotionNotification(currentUser: CurrentUser = mockLoggedInUser()) {
- return renderComponent(<PromotionNotification />, '', {
- currentUser,
- });
-}
diff --git a/server/sonar-web/src/main/js/app/components/update-notification/SQCBUpdateBanners.tsx b/server/sonar-web/src/main/js/app/components/update-notification/SQCBUpdateBanners.tsx
deleted file mode 100644
index db9b26758ee..00000000000
--- a/server/sonar-web/src/main/js/app/components/update-notification/SQCBUpdateBanners.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkStandalone } from '@sonarsource/echoes-react';
-import { isEmpty } from 'lodash';
-import { FormattedMessage } from 'react-intl';
-import { Banner } from '~design-system';
-import { getSystemUpgrades } from '../../../api/system';
-import { DismissableAlert } from '../../../components/ui/DismissableAlert';
-import { SystemUpgradeButton } from '../../../components/upgrade/SystemUpgradeButton';
-import { UpdateUseCase } from '../../../components/upgrade/utils';
-import { translate } from '../../../helpers/l10n';
-import { ProductNameForUpgrade } from '../../../types/system';
-import { useAppState } from '../app-state/withAppStateContext';
-import { analyzeUpgrades, isVersionAPatchUpdate, parseVersion } from './helpers';
-
-interface Props {
- data?: Awaited<ReturnType<typeof getSystemUpgrades>>;
- dismissable?: boolean;
-}
-
-export function SQCBUpdateBanners({ data, dismissable }: Readonly<Props>) {
- const appState = useAppState();
-
- const parsedVersion = parseVersion(appState.version);
- const { upgrades = [], latestLTA } = data ?? {};
-
- const SQSUpgrades = upgrades.filter(
- (upgrade) =>
- upgrade.product === ProductNameForUpgrade.SonarQubeServer &&
- !isVersionAPatchUpdate(upgrade.version),
- );
-
- const SQCBUpgrades = upgrades.filter(
- (upgrade) => upgrade.product === ProductNameForUpgrade.SonarQubeCommunityBuild,
- );
-
- const banners = [];
-
- if (!isEmpty(SQCBUpgrades)) {
- const contents = (
- <FormattedMessage
- id="admin_notification.update.new_sqcb_version"
- values={{
- link: (
- <LinkStandalone
- className="sw-ml-1"
- to="https://www.sonarsource.com/open-source-editions/sonarqube-community-edition/"
- >
- {translate('admin_notification.update.latest')}
- </LinkStandalone>
- ),
- }}
- />
- );
-
- const { latest } = analyzeUpgrades({
- parsedVersion,
- upgrades: SQCBUpgrades,
- });
-
- const dismissKey = latest?.version ?? appState.version;
-
- banners.push(
- dismissable ? (
- <DismissableAlert alertKey={dismissKey} key="SQCB" variant="info">
- {contents}
- </DismissableAlert>
- ) : (
- <Banner key="SQCB" variant="info">
- {contents}
- </Banner>
- ),
- );
- }
-
- if (!isEmpty(SQSUpgrades)) {
- const { latest } = analyzeUpgrades({
- parsedVersion,
- upgrades: SQSUpgrades,
- });
-
- const contents = (
- <>
- {translate('admin_notification.update.new_sqs_version_when_running_sqcb.banner')}{' '}
- {translate('admin_notification.update.new_sqs_version_when_running_sqcb.upgrade')}.
- <SystemUpgradeButton
- systemUpgrades={[latest]}
- updateUseCase={UpdateUseCase.NewVersion}
- latestLTA={latestLTA}
- />
- </>
- );
-
- const dismissKey = latest?.version ?? appState.version;
-
- banners.push(
- dismissable ? (
- <DismissableAlert alertKey={dismissKey} key="SQS" variant="info">
- {contents}
- </DismissableAlert>
- ) : (
- <Banner key="SQS" variant="info">
- {contents}
- </Banner>
- ),
- );
- }
-
- return banners;
-}
diff --git a/server/sonar-web/src/main/js/app/components/update-notification/SQSUpdateBanner.tsx b/server/sonar-web/src/main/js/app/components/update-notification/SQSUpdateBanner.tsx
deleted file mode 100644
index f85348642c3..00000000000
--- a/server/sonar-web/src/main/js/app/components/update-notification/SQSUpdateBanner.tsx
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { isEmpty } from 'lodash';
-import { Banner } from '~design-system';
-import { getSystemUpgrades } from '../../../api/system';
-import { DismissableAlert } from '../../../components/ui/DismissableAlert';
-import { SystemUpgradeButton } from '../../../components/upgrade/SystemUpgradeButton';
-import { UpdateUseCase } from '../../../components/upgrade/utils';
-import { translate } from '../../../helpers/l10n';
-import { isCurrentVersionEOLActive } from '../../../helpers/system';
-import { ProductNameForUpgrade } from '../../../types/system';
-import { useAppState } from '../app-state/withAppStateContext';
-import { analyzeUpgrades, BANNER_VARIANT, isCurrentVersionLTA, parseVersion } from './helpers';
-
-interface Props {
- data?: Awaited<ReturnType<typeof getSystemUpgrades>>;
- dismissable?: boolean;
-}
-
-export function SQSUpdateBanner({ data, dismissable }: Readonly<Props>) {
- const appState = useAppState();
-
- // below: undefined already tested upstream in UpdateNotification, ?? [] is just to make TS happy
- const parsedVersion = parseVersion(appState.version) ?? [];
- const { upgrades = [], installedVersionActive, latestLTA } = data ?? {};
-
- const SQSUpgrades = upgrades.filter(
- (upgrade) => upgrade.product === ProductNameForUpgrade.SonarQubeServer,
- );
-
- const active = installedVersionActive ?? isCurrentVersionEOLActive(appState.versionEOL);
-
- if (active && isEmpty(SQSUpgrades)) {
- return null;
- }
-
- const { isMinorUpdate, isPatchUpdate, latest } = analyzeUpgrades({
- parsedVersion,
- upgrades: SQSUpgrades,
- });
-
- let useCase = UpdateUseCase.NewVersion;
-
- if (!active) {
- useCase = UpdateUseCase.CurrentVersionInactive;
- } else if (
- isPatchUpdate &&
- // if the latest update is a patch and either we're running latest LTA, or there's no minor update
- ((latestLTA !== undefined && isCurrentVersionLTA(parsedVersion, latestLTA)) || !isMinorUpdate)
- ) {
- useCase = UpdateUseCase.NewPatch;
- }
-
- const dismissKey = useCase + (latest?.version ?? appState.version);
-
- const contents = (
- <>
- {translate('admin_notification.update', useCase)}
-
- <SystemUpgradeButton
- systemUpgrades={SQSUpgrades}
- updateUseCase={useCase}
- latestLTA={latestLTA}
- />
- </>
- );
-
- return dismissable ? (
- <DismissableAlert
- alertKey={dismissKey}
- variant={BANNER_VARIANT[useCase]}
- className={`it__promote-update-notification it__upgrade-prompt-${useCase}`}
- >
- {contents}
- </DismissableAlert>
- ) : (
- <Banner variant={BANNER_VARIANT[useCase]} className={`it__upgrade-prompt-${useCase}`}>
- {contents}
- </Banner>
- );
-}
diff --git a/server/sonar-web/src/main/js/app/components/update-notification/UpdateNotification.tsx b/server/sonar-web/src/main/js/app/components/update-notification/UpdateNotification.tsx
deleted file mode 100644
index 0d13adce1be..00000000000
--- a/server/sonar-web/src/main/js/app/components/update-notification/UpdateNotification.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { isEmpty } from 'lodash';
-import { hasGlobalPermission } from '../../../helpers/users';
-import { useSystemUpgrades } from '../../../queries/system';
-import { EditionKey } from '../../../types/editions';
-import { Permissions } from '../../../types/permissions';
-import { isLoggedIn } from '../../../types/users';
-import { useAppState } from '../app-state/withAppStateContext';
-import { useCurrentUser } from '../current-user/CurrentUserContext';
-import { parseVersion } from './helpers';
-import { SQCBUpdateBanners } from './SQCBUpdateBanners';
-import { SQSUpdateBanner } from './SQSUpdateBanner';
-
-interface Props {
- dismissable?: boolean;
-}
-
-export function UpdateNotification({ dismissable }: Readonly<Props>) {
- const appState = useAppState();
- const { currentUser } = useCurrentUser();
-
- const canUserSeeNotification =
- isLoggedIn(currentUser) && hasGlobalPermission(currentUser, Permissions.Admin);
-
- const parsedVersion = parseVersion(appState.version);
-
- const { data, isLoading } = useSystemUpgrades({
- enabled: canUserSeeNotification && parsedVersion !== undefined,
- });
-
- if (!canUserSeeNotification || parsedVersion === undefined || isLoading) {
- return null;
- }
-
- const isCommunityBuildRunning = appState.edition === EditionKey.community;
-
- if (isCommunityBuildRunning && !isEmpty(data?.upgrades)) {
- // We're running SQCB, show SQCB update banner & SQS update banner if applicable
-
- return <SQCBUpdateBanners data={data} dismissable={dismissable} />;
- }
-
- // We're running SQS (or old SQ), only show SQS update banner if applicable
-
- return <SQSUpdateBanner data={data} dismissable={dismissable} />;
-}
diff --git a/server/sonar-web/src/main/js/app/components/update-notification/helpers.ts b/server/sonar-web/src/main/js/app/components/update-notification/helpers.ts
deleted file mode 100644
index 5092aa7bda9..00000000000
--- a/server/sonar-web/src/main/js/app/components/update-notification/helpers.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { groupBy, isEmpty, mapValues } from 'lodash';
-import { Variant } from '~design-system';
-import { UpdateUseCase, sortUpgrades } from '../../../components/upgrade/utils';
-import { SystemUpgrade } from '../../../types/system';
-import { Dict } from '../../../types/types';
-
-type GroupedSystemUpdate = {
- [x: string]: Record<string, SystemUpgrade[]>;
-};
-
-export const analyzeUpgrades = ({
- parsedVersion = [],
- upgrades,
-}: {
- parsedVersion: number[] | undefined;
- upgrades: SystemUpgrade[];
-}) => {
- const systemUpgrades = mapValues(
- groupBy(upgrades, (upgrade: SystemUpgrade) => {
- const [major] = upgrade.version.split('.');
- return major;
- }),
- (upgrades) =>
- groupBy(upgrades, (upgrade: SystemUpgrade) => {
- const [, minor] = upgrade.version.split('.');
- return minor;
- }),
- );
-
- const latest = [...upgrades].sort(
- (upgrade1, upgrade2) =>
- new Date(upgrade2.releaseDate ?? '').getTime() -
- new Date(upgrade1.releaseDate ?? '').getTime(),
- )[0];
-
- return {
- isMinorUpdate: isMinorUpdate(parsedVersion, systemUpgrades),
- isPatchUpdate: isLatestUpdatedAPatchUpdate(parsedVersion, systemUpgrades),
- latest,
- };
-};
-
-export const isCurrentVersionLTA = (parsedVersion: number[], latestLTS: string) => {
- const [currentMajor, currentMinor] = parsedVersion;
- const [ltsMajor, ltsMinor] = latestLTS.split('.').map(Number);
- return currentMajor === ltsMajor && currentMinor === ltsMinor;
-};
-
-export const isMinorUpdate = (parsedVersion: number[], systemUpgrades: GroupedSystemUpdate) => {
- const [currentMajor, currentMinor] = parsedVersion;
- const allMinor = systemUpgrades[currentMajor] ?? {};
-
- return Object.keys(allMinor)
- .map(Number)
- .some((minor) => minor > currentMinor);
-};
-
-export const isLatestUpdatedAPatchUpdate = (
- parsedVersion: number[],
- systemUpgrades: GroupedSystemUpdate,
-) => {
- const [currentMajor, currentMinor, currentPatch] = parsedVersion;
- const allMinor = systemUpgrades[currentMajor];
- const allPatch = sortUpgrades(allMinor?.[currentMinor] ?? []);
-
- if (!isEmpty(allPatch)) {
- const [, , latestPatch] = allPatch[0].version.split('.').map(Number);
- const effectiveCurrentPatch = isNaN(currentPatch) ? 0 : currentPatch;
- const effectiveLatestPatch = isNaN(latestPatch) ? 0 : latestPatch;
-
- return effectiveCurrentPatch < effectiveLatestPatch;
- }
-
- return false;
-};
-
-export const parseVersion = (version: string) => {
- const VERSION_PARSER = /^(\d+)\.(\d+)(\.(\d+))?/;
- const regExpParsedVersion = VERSION_PARSER.exec(version);
-
- return regExpParsedVersion
- ?.slice(1)
- .map(Number)
- .map((n) => (isNaN(n) ? 0 : n));
-};
-
-export const isVersionAPatchUpdate = (version: string) =>
- ((parseVersion(version) ?? [])[2] ?? 0) !== 0;
-
-export const BANNER_VARIANT: Dict<Variant> = {
- [UpdateUseCase.NewVersion]: 'info',
- [UpdateUseCase.CurrentVersionInactive]: 'error',
- [UpdateUseCase.NewPatch]: 'warning',
-};
diff --git a/server/sonar-web/src/main/js/app/index.ts b/server/sonar-web/src/main/js/app/index.ts
deleted file mode 100644
index e1b81ebe273..00000000000
--- a/server/sonar-web/src/main/js/app/index.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import axios from 'axios';
-import 'react-day-picker/dist/style.css';
-import { addGlobalErrorMessage } from '~design-system';
-import { getAvailableFeatures } from '../api/features';
-import { getGlobalNavigation } from '../api/navigation';
-import { getCurrentUser } from '../api/users';
-import { installExtensionsHandler, installWebAnalyticsHandler } from '../helpers/extensionsHandler';
-import { loadL10nBundle } from '../helpers/l10nBundle';
-import { axiosToCatch, parseErrorResponse } from '../helpers/request';
-import { getBaseUrl, getSystemStatus, initAppVariables } from '../helpers/system';
-import './styles/sonar.ts';
-
-installWebAnalyticsHandler();
-installExtensionsHandler();
-initAppVariables();
-initApplication();
-
-async function initApplication() {
- axiosToCatch.interceptors.response.use((response) => response.data);
- axiosToCatch.defaults.baseURL = getBaseUrl();
- axiosToCatch.defaults.headers.patch['Content-Type'] = 'application/merge-patch+json';
- axios.defaults.headers.patch['Content-Type'] = 'application/merge-patch+json';
- axios.defaults.baseURL = getBaseUrl();
-
- axios.interceptors.response.use(
- (response) => response.data,
- (error) => {
- const { response } = error;
- addGlobalErrorMessage(parseErrorResponse(response));
-
- return Promise.reject(response);
- },
- );
-
- const appState = isMainApp()
- ? await getGlobalNavigation().catch((error) => {
- // eslint-disable-next-line no-console
- console.error(error);
- return undefined;
- })
- : undefined;
-
- const [l10nBundle, currentUser, availableFeatures] = await Promise.all([
- loadL10nBundle(appState),
- isMainApp() ? getCurrentUser() : undefined,
- isMainApp() ? getAvailableFeatures() : undefined,
- ]).catch((error) => {
- // eslint-disable-next-line no-console
- console.error('Application failed to start', error);
- throw error;
- });
-
- const startReactApp = await import('./utils/startReactApp').then((i) => i.default);
- startReactApp(l10nBundle, currentUser, appState, availableFeatures);
-}
-
-function isMainApp() {
- const { pathname } = window.location;
-
- return (
- getSystemStatus() === 'UP' &&
- !pathname.startsWith(`${getBaseUrl()}/sessions`) &&
- !pathname.startsWith(`${getBaseUrl()}/maintenance`) &&
- !pathname.startsWith(`${getBaseUrl()}/setup`) &&
- !pathname.startsWith(`${getBaseUrl()}/formatting/help`)
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/projects/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/projects/__tests__/utils-test.ts
deleted file mode 100644
index 8e2f3486dd7..00000000000
--- a/server/sonar-web/src/main/js/apps/projects/__tests__/utils-test.ts
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { searchProjects } from '../../../api/components';
-import { ONE_SECOND } from '../../../helpers/constants';
-import { mockComponent } from '../../../helpers/mocks/component';
-import { Component } from '../../../types/types';
-import * as utils from '../utils';
-
-jest.mock('../../../api/components', () => ({
- searchProjects: jest
- .fn()
- .mockResolvedValue({ components: [], facets: [], paging: { total: 10 } }),
- getScannableProjects: jest.fn().mockResolvedValue({ projects: [] }),
-}));
-
-describe('localizeSorting', () => {
- it('localizes default sorting', () => {
- expect(utils.localizeSorting()).toBe('projects.sort.name');
- });
-
- it('localizes custom sorting', () => {
- expect(utils.localizeSorting('size')).toBe('projects.sort.size');
- });
-});
-
-describe('parseSorting', () => {
- it('parses ascending', () => {
- expect(utils.parseSorting('size')).toEqual({ sortDesc: false, sortValue: 'size' });
- });
-
- it('parses descending', () => {
- expect(utils.parseSorting('-size')).toEqual({ sortDesc: true, sortValue: 'size' });
- });
-});
-
-describe('formatDuration', () => {
- const ONE_MINUTE = 60 * ONE_SECOND;
- const ONE_HOUR = 60 * ONE_MINUTE;
- const ONE_DAY = 24 * ONE_HOUR;
- const ONE_MONTH = 30 * ONE_DAY;
- const ONE_YEAR = 12 * ONE_MONTH;
-
- it('render years and months only', () => {
- expect(utils.formatDuration(ONE_YEAR * 4 + ONE_MONTH * 2 + ONE_DAY * 10)).toEqual(
- 'duration.years.4 duration.months.2 ',
- );
- });
-
- it('render years only', () => {
- expect(utils.formatDuration(ONE_YEAR * 4 + ONE_DAY * 10)).toEqual('duration.years.4 ');
- });
-
- it('render hours and minutes', () => {
- expect(utils.formatDuration(ONE_HOUR * 4 + ONE_MINUTE * 10)).toEqual(
- 'duration.hours.4 duration.minutes.10 ',
- );
- });
-
- it('render days only', () => {
- expect(utils.formatDuration(ONE_DAY * 4 + ONE_MINUTE * 10)).toEqual('duration.days.4 ');
- });
-
- it('render less than a minute', () => {
- expect(utils.formatDuration(ONE_SECOND)).toEqual('duration.seconds');
- });
-});
-
-describe('fetchProjects', () => {
- it('correctly converts the passed arguments to the desired query format', async () => {
- await utils.fetchProjects({ isFavorite: true, query: {}, isStandardMode: true });
-
- expect(searchProjects).toHaveBeenCalledWith({
- f: 'analysisDate,leakPeriodDate',
- facets: utils.LEGACY_FACETS.join(),
- filter: 'isFavorite',
- p: undefined,
- ps: 50,
- });
-
- await utils.fetchProjects({
- isFavorite: false,
- pageIndex: 3,
- query: {
- view: 'leak',
- new_reliability: 6,
- incorrect_property: 'should not appear in post data',
- search: 'foo',
- },
- isStandardMode: true,
- });
-
- expect(searchProjects).toHaveBeenCalledWith({
- f: 'analysisDate,leakPeriodDate',
- facets: utils.LEGACY_LEAK_FACETS.join(),
- filter: 'new_reliability_rating = 6 and query = "foo"',
- p: 3,
- ps: 50,
- });
- });
-
- it('correctly converts the passed arguments to the desired query format for non legacy', async () => {
- await utils.fetchProjects({ isFavorite: true, query: {}, isStandardMode: false });
-
- expect(searchProjects).toHaveBeenCalledWith({
- f: 'analysisDate,leakPeriodDate',
- facets: utils.FACETS.join(),
- filter: 'isFavorite',
- p: undefined,
- ps: 50,
- });
-
- await utils.fetchProjects({
- isFavorite: false,
- pageIndex: 3,
- query: {
- view: 'leak',
- new_reliability: 6,
- incorrect_property: 'should not appear in post data',
- search: 'foo',
- },
- isStandardMode: false,
- });
-
- expect(searchProjects).toHaveBeenCalledWith({
- f: 'analysisDate,leakPeriodDate',
- facets: utils.LEAK_FACETS.join(),
- filter: 'new_software_quality_reliability_rating = 6 and query = "foo"',
- p: 3,
- ps: 50,
- });
- });
-
- it('correctly treats result data', async () => {
- const components = [mockComponent({ key: 'foo' }), mockComponent({ key: 'bar' })];
-
- (searchProjects as jest.Mock).mockResolvedValue({
- components,
- facets: [
- { property: 'new_coverage', values: [{ val: 'NO_DATA', count: 0 }] },
- {
- property: 'languages',
- values: [
- { val: 'css', count: 10 },
- { val: 'js', count: 2 },
- ],
- },
- ],
- paging: { total: 2 },
- });
-
- await utils.fetchProjects({ isFavorite: true, query: {}, isStandardMode: true }).then((r) => {
- expect(r).toEqual({
- facets: {
- new_coverage: { NO_DATA: 0 },
- languages: { css: 10, js: 2 },
- },
- projects: components.map(
- (
- component: Component & {
- isScannable: boolean;
- measures: { languages?: string; new_coverage?: string };
- },
- ) => {
- component.isScannable = false;
- return component;
- },
- ),
-
- total: 2,
- });
- });
- });
-});
-
-describe('defineMetrics', () => {
- it('returns the correct list of metrics', () => {
- expect(utils.defineMetrics({ view: 'leak' })).toBe(utils.LEAK_METRICS);
- expect(utils.defineMetrics({ view: 'overall' })).toBe(utils.METRICS);
- expect(utils.defineMetrics({})).toBe(utils.METRICS);
- });
-});
-
-describe('convertToSorting', () => {
- it('handles asc and desc sort', () => {
- expect(utils.convertToSorting({ sort: '-size' }, true)).toStrictEqual({
- asc: false,
- s: 'ncloc',
- });
- expect(utils.convertToSorting({}, true)).toStrictEqual({ s: undefined });
- expect(utils.convertToSorting({ sort: 'search' }, true)).toStrictEqual({ s: 'query' });
- });
-
- it('handles sort for legacy and non legacy queries', () => {
- expect(utils.convertToSorting({ sort: '-reliability' }, true)).toStrictEqual({
- asc: false,
- s: 'reliability_rating',
- });
- expect(utils.convertToSorting({ sort: '-reliability' }, false)).toStrictEqual({
- asc: false,
- s: 'software_quality_reliability_rating',
- });
- });
-});
diff --git a/server/sonar-web/src/main/js/apps/projects/query.ts b/server/sonar-web/src/main/js/apps/projects/query.ts
deleted file mode 100644
index 64e36dfdfb8..00000000000
--- a/server/sonar-web/src/main/js/apps/projects/query.ts
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { RawQuery } from '~sonar-aligned/types/router';
-import { propertyToMetricMap, propertyToMetricMapLegacy } from './utils';
-
-type Level = 'ERROR' | 'WARN' | 'OK';
-
-export interface Query {
- [x: string]: string | number | string[] | undefined;
- coverage?: number;
- duplications?: number;
- gate?: Level;
- languages?: string[];
- maintainability?: number;
- new_coverage?: number;
- new_duplications?: number;
- new_lines?: number;
- new_maintainability?: number;
- new_reliability?: number;
- new_security?: number;
- new_security_review_rating?: number;
- qualifier?: ComponentQualifier;
- reliability?: number;
- search?: string;
- security?: number;
- security_review_rating?: number;
- size?: number;
- sort?: string;
- tags?: string[];
- view?: string;
-}
-
-export function parseUrlQuery(urlQuery: RawQuery): Query {
- return {
- gate: getAsLevel(urlQuery['gate']),
- reliability: getAsNumericRating(urlQuery['reliability']),
- new_reliability: getAsNumericRating(urlQuery['new_reliability']),
- security: getAsNumericRating(urlQuery['security']),
- new_security: getAsNumericRating(urlQuery['new_security']),
- security_review: getAsNumericRating(urlQuery['security_review']),
- new_security_review: getAsNumericRating(urlQuery['new_security_review']),
- maintainability: getAsNumericRating(urlQuery['maintainability']),
- new_maintainability: getAsNumericRating(urlQuery['new_maintainability']),
- coverage: getAsNumericRating(urlQuery[MetricKey.coverage]),
- new_coverage: getAsNumericRating(urlQuery[MetricKey.new_coverage]),
- duplications: getAsNumericRating(urlQuery['duplications']),
- new_duplications: getAsNumericRating(urlQuery['new_duplications']),
- size: getAsNumericRating(urlQuery['size']),
- new_lines: getAsNumericRating(urlQuery[MetricKey.new_lines]),
- languages: getAsStringArray(urlQuery['languages']),
- tags: getAsStringArray(urlQuery['tags']),
- qualifier: getAsQualifier(urlQuery['qualifier']),
- search: getAsString(urlQuery['search']),
- sort: getAsString(urlQuery['sort']),
- view: getView(urlQuery['view']),
- };
-}
-
-export function convertToFilter(
- query: Query,
- isFavorite: boolean,
- isStandardMode: boolean,
-): string {
- const conditions: string[] = [];
-
- if (isFavorite) {
- conditions.push('isFavorite');
- }
-
- if (query['gate'] != null) {
- conditions.push(`${mapPropertyToMetric('gate', isStandardMode)}=${query['gate']}`);
- }
-
- [MetricKey.coverage, MetricKey.new_coverage].forEach((property) =>
- pushMetricToArray(query, property, conditions, convertCoverage, isStandardMode),
- );
-
- ['duplications', 'new_duplications'].forEach((property) =>
- pushMetricToArray(query, property, conditions, convertDuplications, isStandardMode),
- );
-
- ['size', 'new_lines'].forEach((property) =>
- pushMetricToArray(query, property, conditions, convertSize, isStandardMode),
- );
-
- [
- 'reliability',
- 'security',
- 'security_review',
- 'maintainability',
- 'new_reliability',
- 'new_security',
- 'new_security_review',
- 'new_maintainability',
- ].forEach((property) =>
- pushMetricToArray(query, property, conditions, convertIssuesRating, isStandardMode),
- );
-
- ['languages', 'tags', 'qualifier'].forEach((property) =>
- pushMetricToArray(query, property, conditions, convertArrayMetric, isStandardMode),
- );
-
- if (query['search'] != null) {
- conditions.push(`${mapPropertyToMetric('search', isStandardMode)} = "${query['search']}"`);
- }
-
- return conditions.join(' and ');
-}
-
-const viewParems = ['sort', 'view'];
-
-export function hasFilterParams(query: Query) {
- return Object.keys(query)
- .filter((key) => !viewParems.includes(key))
- .some((key) => query[key] !== undefined);
-}
-
-export function hasViewParams(query: Query) {
- return Object.keys(query)
- .filter((key) => viewParems.includes(key))
- .some((key) => query[key] !== undefined);
-}
-
-function getAsNumericRating(value: any): number | undefined {
- if (value === '' || value == null || isNaN(value)) {
- return undefined;
- }
- const num = Number(value);
- return num > 0 && num < 7 ? num : undefined;
-}
-
-function getAsLevel(value: any): Level | undefined {
- if (value === 'ERROR' || value === 'WARN' || value === 'OK') {
- return value;
- }
- return undefined;
-}
-
-function getAsString(value: any): string | undefined {
- if (typeof value !== 'string' || value === '') {
- return undefined;
- }
- return value;
-}
-
-function getAsStringArray(value: any): string[] | undefined {
- if (typeof value !== 'string' || value === '') {
- return undefined;
- }
- return value.split(',');
-}
-
-function getAsQualifier(value: string | undefined): ComponentQualifier | undefined {
- return value ? (value as ComponentQualifier) : undefined;
-}
-
-function getView(value: any): string | undefined {
- return typeof value !== 'string' || value === 'overall' ? undefined : value;
-}
-
-function convertIssuesRating(metric: string, rating: number): string {
- if (rating > 1 && rating < 5) {
- return `${metric} >= ${rating}`;
- }
-
- return `${metric} = ${rating}`;
-}
-
-function convertCoverage(metric: string, coverage: number): string {
- switch (coverage) {
- case 1:
- return metric + ' >= 80';
- case 2:
- return metric + ' < 80';
- case 3:
- return metric + ' < 70';
- case 4:
- return metric + ' < 50';
- case 5:
- return metric + ' < 30';
- case 6:
- return metric + '= NO_DATA';
- default:
- return '';
- }
-}
-
-function convertDuplications(metric: string, duplications: number): string {
- switch (duplications) {
- case 1:
- return metric + ' < 3';
- case 2:
- return metric + ' >= 3';
- case 3:
- return metric + ' >= 5';
- case 4:
- return metric + ' >= 10';
- case 5:
- return metric + ' >= 20';
- case 6:
- return metric + '= NO_DATA';
- default:
- return '';
- }
-}
-
-function convertSize(metric: string, size: number): string {
- switch (size) {
- case 1:
- return metric + ' < 1000';
- case 2:
- return metric + ' >= 1000';
- case 3:
- return metric + ' >= 10000';
- case 4:
- return metric + ' >= 100000';
- case 5:
- return metric + ' >= 500000';
- default:
- return '';
- }
-}
-
-function mapPropertyToMetric(property?: string, isStandardMode = false): string | undefined {
- if (property === undefined) {
- return;
- }
- return (isStandardMode ? propertyToMetricMapLegacy : propertyToMetricMap)[property];
-}
-
-function pushMetricToArray(
- query: Query,
- property: string,
- conditionsArray: string[],
- convertFunction: (metric: string, value: Query[string]) => string,
- isStandardMode: boolean,
-): void {
- const metric = mapPropertyToMetric(property, isStandardMode);
- if (query[property] !== undefined && metric !== undefined) {
- conditionsArray.push(convertFunction(metric, query[property]));
- }
-}
-
-function convertArrayMetric(metric: string, items: string | string[]): string {
- if (!Array.isArray(items) || items.length < 2) {
- return metric + ' = ' + items;
- }
- return `${metric} IN (${items.join(', ')})`;
-}
diff --git a/server/sonar-web/src/main/js/apps/projects/types.ts b/server/sonar-web/src/main/js/apps/projects/types.ts
deleted file mode 100644
index 691e452b1d3..00000000000
--- a/server/sonar-web/src/main/js/apps/projects/types.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentQualifier, Visibility } from '~sonar-aligned/types/component';
-import { AiCodeAssuranceStatus } from '../../api/ai-code-assurance';
-import { Dict } from '../../types/types';
-
-export interface Project {
- aiCodeAssurance?: AiCodeAssuranceStatus;
- analysisDate?: string;
- isFavorite?: boolean;
- isScannable: boolean;
- key: string;
- leakPeriodDate?: string;
- measures: Dict<string>;
- name: string;
- projects?: number;
- qualifier: ComponentQualifier;
- tags: string[];
- visibility: Visibility;
-}
-
-export interface Facet {
- [value: string]: number;
-}
-
-export interface Facets {
- [property: string]: Facet;
-}
diff --git a/server/sonar-web/src/main/js/apps/projects/utils.ts b/server/sonar-web/src/main/js/apps/projects/utils.ts
deleted file mode 100644
index 89fa2260e10..00000000000
--- a/server/sonar-web/src/main/js/apps/projects/utils.ts
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { invert } from 'lodash';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { Facet, getScannableProjects, searchProjects } from '../../api/components';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { RequestData } from '../../helpers/request';
-import { Dict } from '../../types/types';
-import { Query, convertToFilter } from './query';
-
-interface SortingOption {
- class?: string;
- value: string;
-}
-
-export const PROJECTS_DEFAULT_FILTER = 'sonarqube.projects.default';
-export const PROJECTS_FAVORITE = 'favorite';
-export const PROJECTS_ALL = 'all';
-
-export const SORTING_METRICS: SortingOption[] = [
- { value: 'name' },
- { value: 'analysis_date' },
- { value: 'creation_date' },
- { value: 'reliability' },
- { value: 'security' },
- { value: 'security_review' },
- { value: 'maintainability' },
- { value: 'coverage' },
- { value: 'duplications' },
- { value: 'size' },
-];
-
-export const SORTING_LEAK_METRICS: SortingOption[] = [
- { value: 'name' },
- { value: 'analysis_date' },
- { value: 'creation_date' },
- { value: 'new_reliability', class: 'projects-leak-sorting-option' },
- { value: 'new_security', class: 'projects-leak-sorting-option' },
- { value: 'new_security_review', class: 'projects-leak-sorting-option' },
- { value: 'new_maintainability', class: 'projects-leak-sorting-option' },
- { value: 'new_coverage', class: 'projects-leak-sorting-option' },
- { value: 'new_duplications', class: 'projects-leak-sorting-option' },
- { value: 'new_lines', class: 'projects-leak-sorting-option' },
-];
-
-export const SORTING_SWITCH: Dict<string> = {
- analysis_date: 'analysis_date',
- name: 'name',
- reliability: 'new_reliability',
- security: 'new_security',
- security_review: 'new_security_review',
- maintainability: 'new_maintainability',
- coverage: 'new_coverage',
- duplications: 'new_duplications',
- size: 'new_lines',
- new_reliability: 'reliability',
- new_security: 'security',
- new_security_review: 'security_review',
- new_maintainability: 'maintainability',
- new_coverage: 'coverage',
- new_duplications: 'duplications',
- new_lines: 'size',
-};
-
-export const VIEWS = [
- { value: 'overall', label: 'overall' },
- { value: 'leak', label: 'new_code' },
-];
-
-const PAGE_SIZE = 50;
-
-export const METRICS = [
- MetricKey.alert_status,
- MetricKey.software_quality_reliability_issues,
- MetricKey.bugs,
- MetricKey.reliability_rating,
- MetricKey.software_quality_reliability_rating,
- MetricKey.software_quality_security_issues,
- MetricKey.vulnerabilities,
- MetricKey.security_rating,
- MetricKey.software_quality_security_rating,
- MetricKey.software_quality_maintainability_issues,
- MetricKey.code_smells,
- MetricKey.sqale_rating,
- MetricKey.software_quality_maintainability_rating,
- MetricKey.security_hotspots_reviewed,
- MetricKey.security_review_rating,
- MetricKey.duplicated_lines_density,
- MetricKey.coverage,
- MetricKey.ncloc,
- MetricKey.ncloc_language_distribution,
- MetricKey.projects,
-];
-
-export const LEAK_METRICS = [
- MetricKey.alert_status,
- MetricKey.new_violations,
- MetricKey.new_security_hotspots_reviewed,
- MetricKey.new_security_review_rating,
- MetricKey.new_coverage,
- MetricKey.new_duplicated_lines_density,
- MetricKey.new_lines,
- MetricKey.projects,
-];
-
-export const LEGACY_FACETS = [
- MetricKey.reliability_rating,
- MetricKey.security_rating,
- MetricKey.security_review_rating,
- MetricKey.sqale_rating,
- MetricKey.coverage,
- MetricKey.duplicated_lines_density,
- MetricKey.ncloc,
- MetricKey.alert_status,
- 'languages',
- 'tags',
- 'qualifier',
-];
-
-export const FACETS = [
- MetricKey.software_quality_reliability_rating,
- MetricKey.software_quality_security_rating,
- MetricKey.software_quality_maintainability_rating,
- MetricKey.security_review_rating,
- MetricKey.coverage,
- MetricKey.duplicated_lines_density,
- MetricKey.ncloc,
- MetricKey.alert_status,
- 'languages',
- 'tags',
- 'qualifier',
-];
-
-export const LEGACY_LEAK_FACETS = [
- MetricKey.new_reliability_rating,
- MetricKey.new_security_rating,
- MetricKey.new_security_review_rating,
- MetricKey.new_maintainability_rating,
- MetricKey.new_coverage,
- MetricKey.new_duplicated_lines_density,
- MetricKey.new_lines,
- MetricKey.alert_status,
- 'languages',
- 'tags',
- 'qualifier',
-];
-
-export const LEAK_FACETS = [
- MetricKey.new_software_quality_reliability_rating,
- MetricKey.new_software_quality_security_rating,
- MetricKey.new_software_quality_maintainability_rating,
- MetricKey.new_security_review_rating,
- MetricKey.new_coverage,
- MetricKey.new_duplicated_lines_density,
- MetricKey.new_lines,
- MetricKey.alert_status,
- 'languages',
- 'tags',
- 'qualifier',
-];
-
-const REVERSED_FACETS = ['coverage', 'new_coverage'];
-let scannableProjectsCached: { key: string; name: string }[] | null = null;
-
-export function localizeSorting(sort?: string): string {
- return translate('projects.sort', sort ?? 'name');
-}
-
-export function parseSorting(sort: string): { sortDesc: boolean; sortValue: string } {
- const desc = sort.startsWith('-');
-
- return { sortValue: desc ? sort.substring(1) : sort, sortDesc: desc };
-}
-
-export async function fetchScannableProjects() {
- if (scannableProjectsCached) {
- return Promise.resolve({ scannableProjects: scannableProjectsCached });
- }
-
- const response = await getScannableProjects().then(({ projects }) => {
- scannableProjectsCached = projects;
- return projects;
- });
-
- return { scannableProjects: response };
-}
-
-export function fetchProjects({
- isFavorite,
- query,
- pageIndex = 1,
- isStandardMode,
-}: {
- isFavorite: boolean;
- isStandardMode: boolean;
- pageIndex?: number;
- query: Query;
-}) {
- const ps = PAGE_SIZE;
-
- const data = convertToQueryData(query, isFavorite, isStandardMode, {
- p: pageIndex > 1 ? pageIndex : undefined,
- ps,
- facets: defineFacets(query, isStandardMode).join(),
- f: 'analysisDate,leakPeriodDate',
- });
-
- return searchProjects(data)
- .then((response) => Promise.all([Promise.resolve(response), fetchScannableProjects()]))
- .then(([{ components, facets, paging }, { scannableProjects }]) => {
- return {
- facets: getFacetsMap(facets, isStandardMode),
- projects: components.map((component) => ({
- ...component,
- isScannable: scannableProjects.find((p) => p.key === component.key) !== undefined,
- })),
- total: paging.total,
- };
- });
-}
-
-export function defineMetrics(query: Query): string[] {
- if (query.view === 'leak') {
- return LEAK_METRICS;
- }
-
- return METRICS;
-}
-
-export function defineFacets(query: Query, isStandardMode: boolean): string[] {
- if (query.view === 'leak') {
- return isStandardMode ? LEGACY_LEAK_FACETS : LEAK_FACETS;
- }
-
- return isStandardMode ? LEGACY_FACETS : FACETS;
-}
-
-export function convertToQueryData(
- query: Query,
- isFavorite: boolean,
- isStandardMode: boolean,
- defaultData = {},
-) {
- const data: RequestData = { ...defaultData };
- const filter = convertToFilter(query, isFavorite, isStandardMode);
- const sort = convertToSorting(query, isStandardMode);
-
- if (filter) {
- data.filter = filter;
- }
-
- if (sort.s) {
- data.s = sort.s;
- }
-
- if (sort.asc !== undefined) {
- data.asc = sort.asc;
- }
-
- return data;
-}
-
-function mapFacetValues(values: Array<{ count: number; val: string }>) {
- const map: Dict<number> = {};
-
- values.forEach((value) => {
- map[value.val] = value.count;
- });
-
- return map;
-}
-
-export const propertyToMetricMapLegacy: Dict<string | undefined> = {
- analysis_date: 'analysisDate',
- reliability: 'reliability_rating',
- new_reliability: 'new_reliability_rating',
- security: 'security_rating',
- new_security: 'new_security_rating',
- security_review: 'security_review_rating',
- new_security_review: 'new_security_review_rating',
- maintainability: 'sqale_rating',
- new_maintainability: 'new_maintainability_rating',
- coverage: 'coverage',
- new_coverage: 'new_coverage',
- duplications: 'duplicated_lines_density',
- new_duplications: 'new_duplicated_lines_density',
- size: 'ncloc',
- new_lines: 'new_lines',
- gate: 'alert_status',
- languages: 'languages',
- tags: 'tags',
- search: 'query',
- qualifier: 'qualifier',
- creation_date: 'creationDate',
-};
-
-export const propertyToMetricMap: Dict<string | undefined> = {
- ...propertyToMetricMapLegacy,
- reliability: 'software_quality_reliability_rating',
- new_reliability: 'new_software_quality_reliability_rating',
- security: 'software_quality_security_rating',
- new_security: 'new_software_quality_security_rating',
- maintainability: 'software_quality_maintainability_rating',
- new_maintainability: 'new_software_quality_maintainability_rating',
-};
-
-export function getFacetsMap(facets: Facet[], isStandardMode: boolean) {
- const map: Dict<Dict<number>> = {};
-
- facets.forEach((facet) => {
- const property = invert(isStandardMode ? propertyToMetricMapLegacy : propertyToMetricMap)[
- facet.property
- ];
- const { values } = facet;
-
- if (REVERSED_FACETS.includes(property)) {
- values.reverse();
- }
-
- map[property] = mapFacetValues(values);
- });
-
- return map;
-}
-
-export function convertToSorting(
- { sort }: Query,
- isStandardMode: boolean,
-): { asc?: boolean; s?: string } {
- if (sort?.startsWith('-')) {
- return {
- s: (isStandardMode ? propertyToMetricMapLegacy : propertyToMetricMap)[sort.substring(1)],
- asc: false,
- };
- }
-
- return { s: (isStandardMode ? propertyToMetricMapLegacy : propertyToMetricMap)[sort ?? ''] };
-}
-
-const ONE_MINUTE = 60000;
-const ONE_HOUR = 60 * ONE_MINUTE;
-const ONE_DAY = 24 * ONE_HOUR;
-const ONE_MONTH = 30 * ONE_DAY;
-const ONE_YEAR = 12 * ONE_MONTH;
-
-function format(periods: Array<{ label: string; value: number }>) {
- let result = '';
- let count = 0;
- let lastId = -1;
-
- for (let i = 0; i < periods.length && count < 2; i++) {
- if (periods[i].value > 0) {
- count++;
-
- if (lastId < 0 || lastId + 1 === i) {
- lastId = i;
- result += translateWithParameters(periods[i].label, periods[i].value) + ' ';
- }
- }
- }
-
- return result;
-}
-
-export function formatDuration(ms: number) {
- if (ms < ONE_MINUTE) {
- return translate('duration.seconds');
- }
-
- const years = Math.floor(ms / ONE_YEAR);
- ms -= years * ONE_YEAR;
-
- const months = Math.floor(ms / ONE_MONTH);
- ms -= months * ONE_MONTH;
-
- const days = Math.floor(ms / ONE_DAY);
- ms -= days * ONE_DAY;
-
- const hours = Math.floor(ms / ONE_HOUR);
- ms -= hours * ONE_HOUR;
-
- const minutes = Math.floor(ms / ONE_MINUTE);
-
- return format([
- { value: years, label: 'duration.years' },
- { value: months, label: 'duration.months' },
- { value: days, label: 'duration.days' },
- { value: hours, label: 'duration.hours' },
- { value: minutes, label: 'duration.minutes' },
- ]);
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/quality-gates/__tests__/utils-test.ts
deleted file mode 100644
index 149ee5da7e8..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-gates/__tests__/utils-test.ts
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { mockCondition, mockMetric } from '../../../helpers/testMocks';
-import { Condition } from '../../../types/types';
-import { getLocalizedMetricNameNoDiffMetric, groupAndSortByPriorityConditions } from '../utils';
-
-const METRICS = {
- existing_metric: mockMetric(),
- [MetricKey.new_maintainability_rating]: mockMetric({ name: 'New Maintainability Rating' }),
- [MetricKey.sqale_rating]: mockMetric({
- name: 'Maintainability Rating',
- }),
- [MetricKey.coverage]: mockMetric({ name: 'Coverage' }),
- [MetricKey.bugs]: mockMetric({ name: 'Bugs' }),
- [MetricKey.new_coverage]: mockMetric({ name: 'New Code Coverage' }),
- [MetricKey.new_reliability_rating]: mockMetric({ name: 'New Reliability Rating' }),
- [MetricKey.new_bugs]: mockMetric({ name: 'New Bugs' }),
- [MetricKey.code_smells]: mockMetric({ name: 'Code Smells' }),
- [MetricKey.duplicated_lines_density]: mockMetric({ name: 'Duplicated lines (%)' }),
- [MetricKey.security_review_rating]: mockMetric({ name: 'Security Review Rating' }),
- [MetricKey.software_quality_reliability_rating]: mockMetric({ name: 'Reliability Rating' }),
- [MetricKey.software_quality_security_rating]: mockMetric({ name: 'Security Rating' }),
-};
-
-describe('getLocalizedMetricNameNoDiffMetric', () => {
- it('should return the correct corresponding metric', () => {
- expect(getLocalizedMetricNameNoDiffMetric(mockMetric(), {})).toBe(MetricKey.coverage);
- expect(
- getLocalizedMetricNameNoDiffMetric(mockMetric({ key: MetricKey.new_bugs }), METRICS),
- ).toBe('Bugs');
- expect(
- getLocalizedMetricNameNoDiffMetric(
- mockMetric({ key: 'new_custom_metric', name: 'Custom Metric on New Code' }),
- METRICS,
- ),
- ).toBe('Custom Metric on New Code');
- expect(
- getLocalizedMetricNameNoDiffMetric(
- mockMetric({ key: MetricKey.new_maintainability_rating }),
- METRICS,
- ),
- ).toBe('Maintainability Rating');
- });
-});
-
-describe('groupAndSortByPriorityConditions', () => {
- const conditions = [
- mockCondition(),
- mockCondition({ metric: MetricKey.new_duplicated_lines_density, isCaycCondition: true }),
- mockCondition({ metric: MetricKey.bugs }),
- mockCondition({ metric: MetricKey.new_coverage, isCaycCondition: true }),
- mockCondition({ metric: MetricKey.new_reliability_rating }),
- mockCondition({ metric: MetricKey.code_smells }),
- mockCondition({ metric: MetricKey.duplicated_lines_density }),
- mockCondition({ metric: MetricKey.new_violations, isCaycCondition: true }),
- mockCondition({ metric: MetricKey.new_bugs }),
- mockCondition({ metric: MetricKey.new_security_hotspots_reviewed, isCaycCondition: true }),
- ];
- const expectedConditionsOrderNewCode = [MetricKey.new_bugs, MetricKey.new_reliability_rating];
- const expectConditionsOrderOverallCode = [
- MetricKey.bugs,
- MetricKey.code_smells,
- MetricKey.coverage,
- MetricKey.duplicated_lines_density,
- ];
- const expectedConditionsOrderCayc = [
- MetricKey.new_violations,
- MetricKey.new_security_hotspots_reviewed,
- MetricKey.new_coverage,
- MetricKey.new_duplicated_lines_density,
- ];
- const expectedConditionsOrderAIOverall = [
- MetricKey.software_quality_security_rating,
- MetricKey.security_hotspots_reviewed,
- MetricKey.software_quality_reliability_rating,
- ];
-
- it('should return grouped conditions by overall/new code and sort them by CaYC order', () => {
- const result = groupAndSortByPriorityConditions(conditions, METRICS, true);
- const conditionsMap = ({ metric }: Condition) => metric;
-
- expect(result.newCodeConditions.map(conditionsMap)).toEqual(expectedConditionsOrderNewCode);
- expect(result.overallCodeConditions.map(conditionsMap)).toEqual(
- expectConditionsOrderOverallCode,
- );
- expect(result.builtInNewCodeConditions.map(conditionsMap)).toEqual(expectedConditionsOrderCayc);
- });
-
- it('should return grouped conditions by overall/new code and sort them for builtIn Ai QG', () => {
- const aiConditions = [
- ...conditions,
- mockCondition({ metric: MetricKey.security_hotspots_reviewed }),
- mockCondition({ metric: MetricKey.software_quality_reliability_rating }),
- mockCondition({ metric: MetricKey.software_quality_security_rating }),
- ];
- const result = groupAndSortByPriorityConditions(aiConditions, METRICS, true, true);
- const conditionsMap = ({ metric }: Condition) => metric;
-
- expect(result.builtInOverallConditions.map(conditionsMap)).toEqual(
- expectedConditionsOrderAIOverall,
- );
- expect(result.builtInNewCodeConditions.map(conditionsMap)).toEqual(expectedConditionsOrderCayc);
- });
-
- it('should return grouped conditions and add CaYC conditions to new code if QG is not compliant', () => {
- const result = groupAndSortByPriorityConditions(conditions, METRICS, false);
- const conditionsMap = ({ metric }: Condition) => metric;
-
- expect(result.newCodeConditions.map(conditionsMap)).toEqual([
- MetricKey.new_violations,
- MetricKey.new_security_hotspots_reviewed,
- MetricKey.new_coverage,
- MetricKey.new_duplicated_lines_density,
- MetricKey.new_bugs,
- MetricKey.new_reliability_rating,
- ]);
- expect(result.overallCodeConditions.map(conditionsMap)).toEqual(
- expectConditionsOrderOverallCode,
- );
- expect(result.builtInNewCodeConditions.map(conditionsMap)).toEqual([]);
- });
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/utils.ts b/server/sonar-web/src/main/js/apps/quality-gates/utils.ts
deleted file mode 100644
index 044ce62921d..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-gates/utils.ts
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { sortBy } from 'lodash';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { SOFTWARE_QUALITY_RATING_METRICS_MAP } from '../../helpers/constants';
-import { getLocalizedMetricName } from '../../helpers/l10n';
-import { isDiffMetric } from '../../helpers/measures';
-import { CaycStatus, Condition, Dict, Group, Metric, QualityGate } from '../../types/types';
-import { UserBase } from '../../types/users';
-
-interface GroupedByMetricConditions {
- builtInNewCodeConditions: Condition[];
- builtInOverallConditions: Condition[];
- newCodeConditions: Condition[];
- overallCodeConditions: Condition[];
-}
-
-type CommonCaycMetricKeys =
- | MetricKey.new_security_hotspots_reviewed
- | MetricKey.new_coverage
- | MetricKey.new_duplicated_lines_density;
-
-type OptimizedCaycMetricKeys = MetricKey.new_violations | CommonCaycMetricKeys;
-
-type UnoptimizedCaycMetricKeys =
- | MetricKey.new_reliability_rating
- | MetricKey.new_security_rating
- | MetricKey.new_maintainability_rating
- | CommonCaycMetricKeys;
-
-type AllCaycMetricKeys = OptimizedCaycMetricKeys | UnoptimizedCaycMetricKeys;
-
-type UserOrGroup = UserBase | Group;
-export type QGPermissionOption = UserOrGroup & { label: string; value: string };
-
-const COMMON_CONDITIONS: Record<
- CommonCaycMetricKeys,
- Condition & { shouldRenderOperator?: boolean }
-> = {
- [MetricKey.new_security_hotspots_reviewed]: {
- id: MetricKey.new_security_hotspots_reviewed,
- metric: MetricKey.new_security_hotspots_reviewed,
- op: 'LT',
- error: '100',
- isCaycCondition: true,
- },
- [MetricKey.new_coverage]: {
- id: MetricKey.new_coverage,
- metric: MetricKey.new_coverage,
- op: 'LT',
- error: '80',
- isCaycCondition: true,
- shouldRenderOperator: true,
- },
- [MetricKey.new_duplicated_lines_density]: {
- id: MetricKey.new_duplicated_lines_density,
- metric: MetricKey.new_duplicated_lines_density,
- op: 'GT',
- error: '3',
- isCaycCondition: true,
- shouldRenderOperator: true,
- },
-};
-
-export const OPTIMIZED_CAYC_CONDITIONS: Record<
- OptimizedCaycMetricKeys,
- Condition & { shouldRenderOperator?: boolean }
-> = {
- [MetricKey.new_violations]: {
- id: MetricKey.new_violations,
- metric: MetricKey.new_violations,
- op: 'GT',
- error: '0',
- isCaycCondition: true,
- },
- ...COMMON_CONDITIONS,
-};
-
-const UNOPTIMIZED_CAYC_CONDITIONS: Record<
- UnoptimizedCaycMetricKeys,
- Condition & { shouldRenderOperator?: boolean }
-> = {
- [MetricKey.new_reliability_rating]: {
- id: MetricKey.new_reliability_rating,
- metric: MetricKey.new_reliability_rating,
- op: 'GT',
- error: '1',
- isCaycCondition: true,
- },
- [MetricKey.new_security_rating]: {
- id: MetricKey.new_security_rating,
- metric: MetricKey.new_security_rating,
- op: 'GT',
- error: '1',
- isCaycCondition: true,
- },
- [MetricKey.new_maintainability_rating]: {
- id: MetricKey.new_maintainability_rating,
- metric: MetricKey.new_maintainability_rating,
- op: 'GT',
- error: '1',
- isCaycCondition: true,
- },
- ...COMMON_CONDITIONS,
-};
-
-const ALL_CAYC_CONDITIONS: Record<
- AllCaycMetricKeys,
- Condition & { shouldRenderOperator?: boolean }
-> = {
- ...OPTIMIZED_CAYC_CONDITIONS,
- ...UNOPTIMIZED_CAYC_CONDITIONS,
-};
-
-export const CAYC_CONDITION_ORDER_PRIORITIES: Dict<number> = {
- [MetricKey.new_violations]: 1,
- [MetricKey.new_security_hotspots_reviewed]: 2,
- [MetricKey.new_coverage]: 3,
- [MetricKey.new_duplicated_lines_density]: 4,
-};
-
-export const AI_SUPPORTED_CONDITION_ORDER_PRIORITIES: Dict<number> = {
- [MetricKey.software_quality_security_rating]: 1,
- [MetricKey.security_rating]: 1,
- [MetricKey.security_hotspots_reviewed]: 2,
- [MetricKey.software_quality_reliability_rating]: 3,
- [MetricKey.reliability_rating]: 3,
-};
-
-const CAYC_CONDITIONS_WITHOUT_FIXED_VALUE: AllCaycMetricKeys[] = [
- MetricKey.new_duplicated_lines_density,
- MetricKey.new_coverage,
-];
-const CAYC_CONDITIONS_WITH_FIXED_VALUE: AllCaycMetricKeys[] = [
- MetricKey.new_security_hotspots_reviewed,
- MetricKey.new_violations,
- MetricKey.new_reliability_rating,
- MetricKey.new_security_rating,
- MetricKey.new_maintainability_rating,
-];
-const NON_EDITABLE_CONDITIONS: MetricKey[] = [MetricKey.prioritized_rule_issues];
-
-export const STANDARD_CONDITIONS_MAP: Partial<Record<MetricKey, MetricKey>> = {
- [MetricKey.new_blocker_violations]: MetricKey.new_software_quality_blocker_issues,
- [MetricKey.new_critical_violations]: MetricKey.new_software_quality_high_issues,
- [MetricKey.new_major_violations]: MetricKey.new_software_quality_medium_issues,
- [MetricKey.new_minor_violations]: MetricKey.new_software_quality_low_issues,
- [MetricKey.new_info_violations]: MetricKey.new_software_quality_info_issues,
- [MetricKey.blocker_violations]: MetricKey.software_quality_blocker_issues,
- [MetricKey.critical_violations]: MetricKey.software_quality_high_issues,
- [MetricKey.major_violations]: MetricKey.software_quality_medium_issues,
- [MetricKey.minor_violations]: MetricKey.software_quality_low_issues,
- [MetricKey.info_violations]: MetricKey.software_quality_info_issues,
- [MetricKey.new_vulnerabilities]: MetricKey.new_software_quality_security_issues,
- [MetricKey.new_bugs]: MetricKey.new_software_quality_reliability_issues,
- [MetricKey.new_code_smells]: MetricKey.new_software_quality_maintainability_issues,
- [MetricKey.vulnerabilities]: MetricKey.software_quality_security_issues,
- [MetricKey.bugs]: MetricKey.software_quality_reliability_issues,
- [MetricKey.code_smells]: MetricKey.software_quality_maintainability_issues,
- ...SOFTWARE_QUALITY_RATING_METRICS_MAP,
-};
-
-export const MQR_CONDITIONS_MAP: Partial<Record<MetricKey, MetricKey | null>> = {
- ...Object.fromEntries(
- Object.entries(STANDARD_CONDITIONS_MAP).map(([key, value]) => [value, key]),
- ),
- [MetricKey.high_impact_accepted_issues]: null,
-};
-
-export function isConditionWithFixedValue(condition: Condition) {
- return CAYC_CONDITIONS_WITH_FIXED_VALUE.includes(condition.metric as OptimizedCaycMetricKeys);
-}
-
-export function isNonEditableMetric(metricKey: MetricKey) {
- return NON_EDITABLE_CONDITIONS.includes(metricKey);
-}
-
-export function getCaycConditionMetadata(condition: Condition) {
- const foundCondition = OPTIMIZED_CAYC_CONDITIONS[condition.metric as OptimizedCaycMetricKeys];
- return {
- shouldRenderOperator: foundCondition?.shouldRenderOperator,
- };
-}
-
-export function isQualityGateOptimized(qualityGate: QualityGate) {
- return (
- !qualityGate.isBuiltIn &&
- qualityGate.caycStatus !== CaycStatus.NonCompliant &&
- Object.values(OPTIMIZED_CAYC_CONDITIONS).every((condition) => {
- const foundCondition = qualityGate.conditions?.find((c) => c.metric === condition.metric);
- return (
- foundCondition &&
- !isWeakCondition(condition.metric as OptimizedCaycMetricKeys, foundCondition)
- );
- })
- );
-}
-
-function isWeakCondition(key: AllCaycMetricKeys, selectedCondition: Condition) {
- return (
- !CAYC_CONDITIONS_WITHOUT_FIXED_VALUE.includes(key) &&
- ALL_CAYC_CONDITIONS[key]?.error !== selectedCondition.error
- );
-}
-
-export function getWeakMissingAndNonCaycConditions(conditions: Condition[]) {
- const result: {
- missingConditions: Condition[];
- weakConditions: Condition[];
- } = {
- weakConditions: [],
- missingConditions: [],
- };
- Object.keys(OPTIMIZED_CAYC_CONDITIONS).forEach((key: OptimizedCaycMetricKeys) => {
- const selectedCondition = conditions.find((condition) => condition.metric === key);
- if (!selectedCondition) {
- result.missingConditions.push(OPTIMIZED_CAYC_CONDITIONS[key]);
- } else if (isWeakCondition(key, selectedCondition)) {
- result.weakConditions.push(selectedCondition);
- }
- });
- return result;
-}
-
-function groupConditionsByMetric(
- conditions: Condition[],
- isBuiltInQG = false,
- isAiSupportedQG = false,
-): GroupedByMetricConditions {
- return conditions.reduce(
- (result, condition) => {
- const isNewCode = isDiffMetric(condition.metric);
- if (condition.isCaycCondition && isBuiltInQG) {
- result.builtInNewCodeConditions.push(condition);
- } else if (
- isBuiltInQG &&
- isAiSupportedQG &&
- Object.keys(AI_SUPPORTED_CONDITION_ORDER_PRIORITIES).includes(condition.metric)
- ) {
- result.builtInOverallConditions.push(condition);
- } else if (isNewCode) {
- result.newCodeConditions.push(condition);
- } else {
- result.overallCodeConditions.push(condition);
- }
-
- return result;
- },
- {
- overallCodeConditions: [] as Condition[],
- newCodeConditions: [] as Condition[],
- builtInOverallConditions: [] as Condition[],
- builtInNewCodeConditions: [] as Condition[],
- },
- );
-}
-
-export function groupAndSortByPriorityConditions(
- conditions: Condition[],
- metrics: Dict<Metric>,
- isBuiltInQG = false,
- isAiCodeSupportedQG = false,
-): GroupedByMetricConditions {
- const groupedConditions = groupConditionsByMetric(conditions, isBuiltInQG, isAiCodeSupportedQG);
-
- const sortFns = [
- (condition: Condition) => CAYC_CONDITION_ORDER_PRIORITIES[condition.metric],
- (condition: Condition) => metrics[condition.metric]?.name,
- ];
-
- groupedConditions.newCodeConditions = sortBy(groupedConditions.newCodeConditions, sortFns);
- groupedConditions.overallCodeConditions = sortBy(
- groupedConditions.overallCodeConditions,
- sortFns,
- );
- groupedConditions.builtInNewCodeConditions = sortBy(
- groupedConditions.builtInNewCodeConditions,
- sortFns,
- );
- groupedConditions.builtInOverallConditions = sortBy(
- groupedConditions.builtInOverallConditions,
- (condition: Condition) => AI_SUPPORTED_CONDITION_ORDER_PRIORITIES[condition.metric],
- );
-
- return groupedConditions;
-}
-
-export function getCorrectCaycCondition(condition: Condition) {
- const conditionMetric = condition.metric as OptimizedCaycMetricKeys;
- if (CAYC_CONDITIONS_WITHOUT_FIXED_VALUE.includes(conditionMetric)) {
- return condition;
- }
- return OPTIMIZED_CAYC_CONDITIONS[conditionMetric];
-}
-
-export function getPossibleOperators(metric: Metric) {
- if (metric.direction === 1) {
- return 'LT';
- } else if (metric.direction === -1) {
- return 'GT';
- }
- return ['LT', 'GT'];
-}
-
-function metricKeyExists(key: string, metrics: Dict<Metric>) {
- return metrics[key] !== undefined;
-}
-
-function getNoDiffMetric(metric: Metric, metrics: Dict<Metric>) {
- const regularMetricKey = metric.key.replace(/^new_/, '');
- if (isDiffMetric(metric.key) && metricKeyExists(regularMetricKey, metrics)) {
- return metrics[regularMetricKey];
- } else if (metric.key === MetricKey.new_maintainability_rating) {
- return metrics[MetricKey.sqale_rating] || metric;
- }
- return metric;
-}
-
-export function getLocalizedMetricNameNoDiffMetric(metric: Metric, metrics: Dict<Metric>) {
- return getLocalizedMetricName(getNoDiffMetric(metric, metrics));
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfileApp-it.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfileApp-it.tsx
deleted file mode 100644
index 6a9c917a550..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfileApp-it.tsx
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen, waitFor } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { ModeServiceMock } from '../../../api/mocks/ModeServiceMock';
-import QualityProfilesServiceMock from '../../../api/mocks/QualityProfilesServiceMock';
-import { renderAppRoutes } from '../../../helpers/testReactTestingUtils';
-import { Mode } from '../../../types/mode';
-import routes from '../routes';
-
-jest.mock('../../../api/quality-profiles');
-jest.mock('../../../api/rules');
-
-beforeEach(() => {
- serviceMock.reset();
- modeHandler.reset();
-});
-
-const serviceMock = new QualityProfilesServiceMock();
-const modeHandler = new ModeServiceMock();
-const ui = {
- loading: byRole('status', { name: 'loading' }),
- permissionSection: byRole('region', { name: 'permissions.page' }),
- projectSection: byRole('region', { name: 'projects' }),
- rulesSection: byRole('region', { name: 'rules' }),
- rulesSectionHeader: byRole('heading', { name: 'quality_profile.rules.breakdown' }),
- exportersSection: byRole('region', { name: 'quality_profiles.exporters' }),
- inheritanceSection: byRole('region', { name: 'quality_profiles.profile_inheritance' }),
- grantPermissionButton: byRole('button', {
- name: 'quality_profiles.grant_permissions_to_more_users',
- }),
- dialog: byRole('dialog'),
- selectField: byRole('combobox'),
- selectUserOrGroup: byRole('combobox', { name: 'quality_profiles.search_description' }),
- twitterCheckbox: byRole('checkbox', { name: 'Twitter Twitter' }),
- benflixCheckbox: byRole('checkbox', { name: 'Benflix Benflix' }),
- addButton: byRole('button', { name: 'add_verb' }),
- removeButton: byRole('button', { name: 'remove' }),
- closeButton: byRole('button', { name: 'close' }),
- changeProjectsButton: byRole('button', { name: 'quality_profiles.change_projects' }),
- changeButton: byRole('button', { name: 'change_verb' }),
- withoutFilterButton: byRole('radio', { name: 'quality_gates.projects.without' }),
- changeParentButton: byRole('button', { name: 'quality_profiles.change_parent' }),
- qualityProfileActions: byRole('button', {
- name: /quality_profiles.actions/,
- }),
- qualityProfilesHeader: byRole('heading', { name: 'quality_profiles.page' }),
- deleteQualityProfileButton: byRole('menuitem', { name: 'delete' }),
- activateMoreLink: byRole('link', { name: 'quality_profiles.activate_more' }),
- activateMoreButton: byRole('button', { name: 'quality_profiles.activate_more' }),
- activateMoreRulesLink: byRole('menuitem', { name: 'quality_profiles.activate_more_rules' }),
- backUpLink: byRole('menuitem', { name: 'backup_verb open_in_new_tab' }),
- compareLink: byRole('menuitem', { name: 'compare' }),
- extendButton: byRole('menuitem', { name: 'extend' }),
- copyButton: byRole('menuitem', { name: 'copy' }),
- renameButton: byRole('menuitem', { name: 'rename' }),
- setAsDefaultButton: byRole('menuitem', { name: 'set_as_default' }),
- newNameInput: byRole('textbox', { name: /quality_profiles.new_name/ }),
- qualityProfilePageLink: byRole('link', { name: 'quality_profiles.back_to_list' }),
- rulesConsistencyRow: byRole('row', { name: /rule.clean_code_attribute_category.CONSISTENT/ }),
- rulesSecurityRow: byRole('row', { name: /rule.clean_code_attribute_category.SECURITY/ }),
- rulesMissingSonarWayWarning: byText('quality_profiles.sonarway_missing_rules_description'),
- rulesMissingSonarWayLink: byRole('link', {
- name: /quality_profiles.sonarway_see_x_missing_rules/,
- }),
- rulesDeprecatedWarning: byText('quality_profiles.deprecated_rules_description'),
- rulesDeprecatedLink: byRole('link', { name: '8' }),
-
- waitForDataLoaded: async () => {
- await waitFor(() => {
- expect(ui.loading.query()).not.toBeInTheDocument();
- });
- },
-
- checkRuleRow: (name: string, active: number, inactive: number) => {
- expect(
- byRole('row', { name: new RegExp(`${name}.+${active}.+${inactive}`) }).get(),
- ).toBeInTheDocument();
- },
-};
-
-describe('Admin or user with permission', () => {
- beforeEach(() => {
- serviceMock.setAdmin();
- });
-
- describe('Permissions', () => {
- it('should be able to grant permission to a user and remove it', async () => {
- const user = userEvent.setup();
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(await ui.permissionSection.find()).toBeInTheDocument();
-
- // Add user
- await user.click(ui.grantPermissionButton.get());
- expect(ui.dialog.get()).toBeInTheDocument();
-
- await user.click(ui.selectUserOrGroup.get());
- await user.click(byRole('option', { name: /^Buzz/ }).get());
-
- await user.click(ui.addButton.get());
- expect(ui.permissionSection.byText('Buzz').get()).toBeInTheDocument();
-
- // Remove User
- await user.click(
- ui.permissionSection
- .byRole('button', { name: 'quality_profiles.permissions.remove.user_x.Buzz' })
- .get(),
- );
- expect(ui.dialog.get()).toBeInTheDocument();
- await user.click(ui.removeButton.get());
- expect(ui.permissionSection.byText('buzz').query()).not.toBeInTheDocument();
- });
-
- it('should be able to grant permission to a group and remove it', async () => {
- const user = userEvent.setup();
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(await ui.permissionSection.find()).toBeInTheDocument();
-
- // Add Group
- await user.click(ui.grantPermissionButton.get());
- expect(ui.dialog.get()).toBeInTheDocument();
-
- await user.click(ui.selectUserOrGroup.get());
- await user.click(byRole('option', { name: /^ACDC/ }).get());
-
- await user.click(ui.addButton.get());
- expect(ui.permissionSection.byText('ACDC').get()).toBeInTheDocument();
-
- // Remove group
- await user.click(
- ui.permissionSection
- .byRole('button', { name: 'quality_profiles.permissions.remove.group_x.ACDC' })
- .get(),
- );
- expect(ui.dialog.get()).toBeInTheDocument();
- await user.click(ui.removeButton.get());
- expect(ui.permissionSection.byText('ACDC').query()).not.toBeInTheDocument();
- });
-
- it('should not be able to grant permission if the profile is built-in', async () => {
- renderQualityProfile('sonar');
- await ui.waitForDataLoaded();
- expect(await screen.findByRole('heading', { name: /\bSonar way\b/ })).toBeInTheDocument();
- expect(ui.permissionSection.query()).not.toBeInTheDocument();
- });
- });
-
- describe('Projects', () => {
- it('should be able to add a project to Quality Profile with active rules', async () => {
- const user = userEvent.setup();
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(await ui.projectSection.find()).toBeInTheDocument();
-
- expect(ui.projectSection.byText('Twitter').query()).not.toBeInTheDocument();
- await user.click(ui.changeProjectsButton.get());
- expect(ui.dialog.get()).toBeInTheDocument();
-
- await user.click(ui.withoutFilterButton.get());
- await user.click(ui.twitterCheckbox.get());
- await user.click(ui.closeButton.get());
- expect(ui.projectSection.byText('Twitter').get()).toBeInTheDocument();
- });
-
- it('should be able to remove a project from a Quality Profile with active rules', async () => {
- const user = userEvent.setup();
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(await ui.projectSection.find()).toBeInTheDocument();
-
- expect(ui.projectSection.byText('Benflix').get()).toBeInTheDocument();
- await user.click(ui.changeProjectsButton.get());
- expect(ui.dialog.get()).toBeInTheDocument();
-
- await user.click(ui.benflixCheckbox.get());
- await user.click(ui.closeButton.get());
- expect(ui.projectSection.byText('Benflix').query()).not.toBeInTheDocument();
- });
-
- it('should not be able to change project for Quality Profile with no active rules', async () => {
- renderQualityProfile('no-rule-qp');
- await ui.waitForDataLoaded();
-
- expect(await ui.projectSection.find()).toBeInTheDocument();
-
- expect(ui.changeProjectsButton.get()).toHaveAttribute('disabled');
- });
-
- it('should not be able to change projects for default profiles', async () => {
- renderQualityProfile('sonar');
- await ui.waitForDataLoaded();
-
- expect(await ui.projectSection.find()).toBeInTheDocument();
-
- expect(
- ui.projectSection.byText('quality_profiles.projects_for_default').get(),
- ).toBeInTheDocument();
- });
- });
-
- describe('Rules', () => {
- it('should be able to activate more rules', async () => {
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(await ui.rulesSection.find()).toBeInTheDocument();
-
- expect(await ui.activateMoreLink.find()).toBeInTheDocument();
- expect(ui.activateMoreLink.get()).toHaveAttribute(
- 'href',
- '/coding_rules?qprofile=old-php-qp&activation=false',
- );
- });
-
- it("shouldn't be able to activate more rules for built in Quality Profile", async () => {
- renderQualityProfile('sonar');
- await ui.waitForDataLoaded();
- expect(await ui.rulesSection.find()).toBeInTheDocument();
- expect(await ui.activateMoreButton.find()).toBeInTheDocument();
- expect(ui.activateMoreButton.get()).toBeDisabled();
- });
- });
-
- describe('Inheritance', () => {
- it("should be able to change a quality profile's parents", async () => {
- const user = userEvent.setup();
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(await ui.inheritanceSection.find()).toBeInTheDocument();
-
- // Parents
- expect(ui.inheritanceSection.byText('PHP Sonar way 1').get()).toBeInTheDocument();
- expect(ui.inheritanceSection.byText('PHP Sonar way 2').query()).not.toBeInTheDocument();
- // Children
- expect(ui.inheritanceSection.byText('PHP way').get()).toBeInTheDocument();
-
- await user.click(ui.changeParentButton.get());
- expect(await ui.dialog.find()).toBeInTheDocument();
- expect(ui.changeButton.get()).toBeDisabled();
-
- await user.click(ui.selectField.get());
- await user.click(byRole('option', { name: 'PHP Sonar way 2' }).get());
-
- await user.click(ui.changeButton.get());
- expect(ui.dialog.query()).not.toBeInTheDocument();
-
- await ui.waitForDataLoaded();
-
- // Parents
- expect(ui.inheritanceSection.byText('PHP Sonar way 2').get()).toBeInTheDocument();
- expect(ui.inheritanceSection.byText('PHP Sonar way 1').query()).not.toBeInTheDocument();
- // Children
- expect(ui.inheritanceSection.byText('PHP way').get()).toBeInTheDocument();
- });
-
- it("should not be able to change a Built-in quality profile's parents", async () => {
- renderQualityProfile('php-sonar-way-1');
- await ui.waitForDataLoaded();
-
- expect(await ui.inheritanceSection.find()).toBeInTheDocument();
- expect(ui.changeParentButton.query()).not.toBeInTheDocument();
- });
- });
-
- describe('Actions', () => {
- it('should be able to activate more rules', async () => {
- const user = userEvent.setup();
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- await user.click(await ui.qualityProfileActions.find());
- expect(ui.activateMoreRulesLink.get()).toBeInTheDocument();
- expect(ui.activateMoreRulesLink.get()).toHaveAttribute(
- 'href',
- '/coding_rules?qprofile=old-php-qp&activation=false',
- );
- });
-
- it('should be able to extend a quality profile', async () => {
- const user = userEvent.setup();
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(
- await screen.findByRole('heading', { name: 'Good old PHP quality profile' }),
- ).toBeInTheDocument();
-
- await user.click(ui.qualityProfileActions.get());
- await user.click(ui.extendButton.get());
-
- expect(ui.dialog.get()).toBeInTheDocument();
- expect(ui.dialog.byRole('button', { name: 'extend' }).get()).toBeDisabled();
-
- await user.clear(ui.newNameInput.get());
- await user.type(ui.newNameInput.get(), 'Bad new PHP quality profile');
- await user.click(ui.dialog.byRole('button', { name: 'extend' }).get());
-
- expect(ui.dialog.query()).not.toBeInTheDocument();
-
- await ui.waitForDataLoaded();
-
- expect(screen.getAllByText('Bad new PHP quality profile')).toHaveLength(2);
- expect(screen.getByText('Good old PHP quality profile')).toBeInTheDocument();
- });
-
- it('should be able to copy a quality profile', async () => {
- const user = userEvent.setup();
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- await user.click(await ui.qualityProfileActions.find());
- await user.click(ui.copyButton.get());
-
- expect(ui.dialog.get()).toBeInTheDocument();
- expect(ui.dialog.byRole('button', { name: 'copy' }).get()).toBeDisabled();
-
- await user.clear(ui.newNameInput.get());
- await user.type(ui.newNameInput.get(), 'Good old PHP quality profile copy');
- await user.click(ui.dialog.byRole('button', { name: 'copy' }).get());
-
- expect(ui.dialog.query()).not.toBeInTheDocument();
-
- await ui.waitForDataLoaded();
- expect(await screen.findAllByText('Good old PHP quality profile copy')).toHaveLength(2);
- });
-
- it('should be able to rename a quality profile', async () => {
- const user = userEvent.setup();
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- await user.click(await ui.qualityProfileActions.find());
- await user.click(ui.renameButton.get());
-
- expect(ui.dialog.get()).toBeInTheDocument();
- expect(ui.dialog.byRole('button', { name: 'rename' }).get()).toBeDisabled();
-
- await user.clear(ui.newNameInput.get());
- await user.type(ui.newNameInput.get(), 'Fossil PHP quality profile');
- await user.click(ui.dialog.byRole('button', { name: 'rename' }).get());
-
- expect(ui.dialog.query()).not.toBeInTheDocument();
-
- await ui.waitForDataLoaded();
- expect(screen.getAllByText('Fossil PHP quality profile')).toHaveLength(2);
- });
-
- it('should be able to set a quality profile as default', async () => {
- const user = userEvent.setup();
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- await user.click(await ui.qualityProfileActions.find());
- await user.click(ui.setAsDefaultButton.get());
-
- expect(screen.getAllByText('default')).toHaveLength(2);
- });
-
- it('should NOT be able to set a quality profile as default if it has no active rules', async () => {
- const user = userEvent.setup();
- renderQualityProfile('no-rule-qp');
- await ui.waitForDataLoaded();
-
- await user.click(await ui.qualityProfileActions.find());
- expect(ui.setAsDefaultButton.get()).toHaveAttribute('aria-disabled', 'true');
- });
-
- it('should be able to delete a Quality Profile and its children', async () => {
- const user = userEvent.setup();
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- await user.click(await ui.qualityProfileActions.find());
- await user.click(ui.deleteQualityProfileButton.get());
-
- expect(ui.dialog.get()).toBeInTheDocument();
- expect(
- ui.dialog
- .byText(/quality_profiles.are_you_sure_want_delete_profile_x_and_descendants/)
- .get(),
- ).toBeInTheDocument();
- await user.click(ui.dialog.byRole('button', { name: 'delete' }).get());
-
- expect(await ui.qualityProfilesHeader.find()).toBeInTheDocument();
- // children
- expect(screen.queryByText('PHP way')).not.toBeInTheDocument();
- expect(screen.queryByText('Good old PHP quality profile')).not.toBeInTheDocument();
- });
- });
-});
-
-describe('Users with no permission', () => {
- it('should not be able to activate more rules', async () => {
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(await ui.rulesSection.find()).toBeInTheDocument();
- expect(ui.activateMoreLink.query()).not.toBeInTheDocument();
- });
-
- it('should not be able to grant permission to a user', async () => {
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(ui.permissionSection.query()).not.toBeInTheDocument();
- });
-
- it("should not be able to change a quality profile's parents", async () => {
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(await ui.inheritanceSection.find()).toBeInTheDocument();
- expect(ui.inheritanceSection.byText('PHP Sonar way 1').get()).toBeInTheDocument();
- expect(ui.inheritanceSection.byText('PHP way').get()).toBeInTheDocument();
-
- expect(ui.changeParentButton.query()).not.toBeInTheDocument();
- });
-
- it('should not be able to change projects for Quality Profile', async () => {
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(await ui.projectSection.find()).toBeInTheDocument();
- expect(ui.changeProjectsButton.query()).not.toBeInTheDocument();
- });
-});
-
-describe('Every Users', () => {
- it('should be able to see active/inactive rules for a Quality Profile', async () => {
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(await ui.rulesSectionHeader.find()).toBeInTheDocument();
-
- ui.checkRuleRow('rule.clean_code_attribute_category.INTENTIONAL', 23, 4);
- ui.checkRuleRow('rule.clean_code_attribute_category.CONSISTENT', 2, 18);
- ui.checkRuleRow('rule.clean_code_attribute_category.ADAPTABLE', 1, 11);
- ui.checkRuleRow('rule.clean_code_attribute_category.RESPONSIBLE', 0, 0);
- ui.checkRuleRow('software_quality.MAINTAINABILITY', 9, 44);
- ui.checkRuleRow('software_quality.RELIABILITY', 16, 1);
- ui.checkRuleRow('software_quality.SECURITY', 0, 14);
- });
-
- it('should be able to see active/inactive rules for a Quality Profile in Legacy mode', async () => {
- modeHandler.setMode(Mode.Standard);
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(await ui.rulesSectionHeader.find()).toBeInTheDocument();
-
- ui.checkRuleRow('issue.type.BUG.plural', 60, 0);
- ui.checkRuleRow('issue.type.VULNERABILITY.plural', 40, 0);
- ui.checkRuleRow('issue.type.CODE_SMELL.plural', 250, 0);
- ui.checkRuleRow('issue.type.SECURITY_HOTSPOT.plural', 50, 0);
- });
-
- it('should be able to see a warning when some rules are missing compare to Sonar way', async () => {
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(await ui.rulesMissingSonarWayWarning.findAll()).toHaveLength(2);
- expect(ui.rulesMissingSonarWayLink.get()).toBeInTheDocument();
- expect(ui.rulesMissingSonarWayLink.get()).toHaveAttribute(
- 'href',
- '/coding_rules?qprofile=old-php-qp&activation=false&languages=php',
- );
- });
-
- it('should be able to see a warning when some rules are deprecated', async () => {
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(await ui.rulesDeprecatedWarning.findAll()).toHaveLength(1);
- expect(ui.rulesDeprecatedLink.get()).toBeInTheDocument();
- expect(ui.rulesDeprecatedLink.get()).toHaveAttribute(
- 'href',
- '/coding_rules?qprofile=old-php-qp&activation=true&statuses=DEPRECATED',
- );
- });
-
- it('should be able to see exporters links when there are exporters for the language', async () => {
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- expect(await ui.exportersSection.find()).toBeInTheDocument();
- expect(ui.exportersSection.byText('SonarLint for Visual Studio').get()).toBeInTheDocument();
- expect(ui.exportersSection.byText('SonarLint for Eclipse').get()).toBeInTheDocument();
- });
-
- it('should be informed when the quality profile has not been found', async () => {
- renderQualityProfile('i-dont-exist');
- await ui.waitForDataLoaded();
-
- expect(
- await screen.findByRole('heading', { name: 'quality_profiles.not_found' }),
- ).toBeInTheDocument();
- expect(ui.qualityProfilePageLink.get()).toBeInTheDocument();
- });
-
- it('should be able to backup quality profile', async () => {
- const user = userEvent.setup();
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- await user.click(await ui.qualityProfileActions.find());
- expect(ui.backUpLink.get()).toHaveAttribute(
- 'href',
- '/api/qualityprofiles/backup?language=php&qualityProfile=Good%20old%20PHP%20quality%20profile',
- );
- expect(ui.backUpLink.get()).toHaveAttribute('download', 'old-php-qp.xml');
- });
-
- it('should not be able to backup a built-in quality profile', async () => {
- const user = userEvent.setup();
- renderQualityProfile('sonar');
- await ui.waitForDataLoaded();
-
- await user.click(await ui.qualityProfileActions.find());
- expect(ui.backUpLink.query()).not.toBeInTheDocument();
- });
-
- it('should be able to compare quality profile', async () => {
- const user = userEvent.setup();
- renderQualityProfile();
- await ui.waitForDataLoaded();
-
- await user.click(await ui.qualityProfileActions.find());
-
- expect(ui.compareLink.get()).toBeInTheDocument();
- expect(ui.compareLink.get()).toHaveAttribute(
- 'href',
- '/profiles/compare?language=php&name=Good+old+PHP+quality+profile',
- );
- });
-});
-
-function renderQualityProfile(key = 'old-php-qp') {
- renderAppRoutes(`profiles/show?key=${key}`, routes, {});
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx
deleted file mode 100644
index 661a256dd1b..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { byLabelText, byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { ModeServiceMock } from '../../../api/mocks/ModeServiceMock';
-import QualityProfilesServiceMock from '../../../api/mocks/QualityProfilesServiceMock';
-import SettingsServiceMock from '../../../api/mocks/SettingsServiceMock';
-import { mockCompareResult, mockPaging, mockRule } from '../../../helpers/testMocks';
-import { renderAppRoutes } from '../../../helpers/testReactTestingUtils';
-import routes from '../routes';
-
-jest.mock('../../../api/quality-profiles');
-jest.mock('../../../api/rules');
-
-const serviceMock = new QualityProfilesServiceMock();
-const modeHandler = new ModeServiceMock();
-const settingsHandler = new SettingsServiceMock();
-
-beforeEach(() => {
- serviceMock.reset();
- modeHandler.reset();
- settingsHandler.reset();
-});
-
-const ui = {
- cQualityProfileName: 'c quality profile',
- newCQualityProfileName: 'New c quality profile',
- newCQualityProfileNameFromCreateButton: 'New c quality profile from create',
- listProfileActions: (name: string, language: string) =>
- byRole('button', {
- name: `quality_profiles.actions.${name}.${language}`,
- }),
- profileActions: (name: string, language: string) =>
- byRole('menuitem', {
- name: `quality_profiles.actions.${name}.${language}`,
- }),
- modalExtendButton: byRole('button', {
- name: 'extend',
- }),
- qualityProfileActions: byRole('button', {
- name: /quality_profiles.actions/,
- }),
- extendButton: byRole('menuitem', {
- name: 'extend',
- }),
- modalCopyButton: byRole('button', {
- name: 'copy',
- }),
- copyButton: byRole('menuitem', {
- name: 'copy',
- }),
- createButton: byRole('button', { name: 'create' }),
- restoreButton: byRole('button', { name: 'restore' }),
- compareButton: byRole('menuitem', { name: 'compare' }),
- cancelButton: byRole('button', { name: 'cancel' }),
- compareDropdown: byRole('combobox', { name: 'quality_profiles.compare_with' }),
- changelogLink: byRole('link', { name: 'changelog' }),
- popup: byRole('dialog'),
- confirmationModal: byRole('alertdialog'),
- restoreProfileDialog: byRole('dialog', { name: 'quality_profiles.restore_profile' }),
- copyRadio: byRole('radio', {
- name: 'quality_profiles.creation_from_copy quality_profiles.creation_from_copy_description_1 quality_profiles.creation_from_copy_description_2',
- }),
- extendRadio: byRole('radio', {
- name: 'quality_profiles.creation_from_extend quality_profiles.creation_from_extend_description_1 quality_profiles.creation_from_extend_description_2',
- }),
- blankRadio: byRole('radio', {
- name: 'quality_profiles.creation_from_blank quality_profiles.creation_from_blank_description',
- }),
- activeRuleButton: (profileName: string) =>
- byRole('button', {
- name: `quality_profiles.comparison.activate_rule.${profileName}`,
- }),
- deactivateRuleButton: (profileName: string) =>
- byRole('button', {
- name: `quality_profiles.comparison.deactivate_rule.${profileName}`,
- }),
- deactivateConfirmButton: byRole('button', { name: 'yes' }),
- activateConfirmButton: byRole('button', { name: 'coding_rules.activate' }),
- namePropupInput: byRole('textbox', { name: 'quality_profiles.new_name required' }),
- filterByLang: byRole('combobox', { name: 'quality_profiles.select_lang' }),
- listLinkCQualityProfile: byRole('link', { name: 'c quality profile' }),
- headingNewCQualityProfile: byRole('heading', { name: 'New c quality profile' }),
- headingNewCQualityProfileFromCreateButton: byRole('heading', {
- name: 'New c quality profile from create',
- }),
- listLinkJavaQualityProfile: byRole('link', { name: 'java quality profile' }),
- returnToList: byRole('link', { name: 'quality_profiles.page' }),
- languageSelect: byRole('combobox', { name: 'language' }),
- profileExtendSelect: byLabelText('quality_profiles.creation.choose_parent_quality_profile'),
- profileCopySelect: byLabelText('quality_profiles.creation.choose_copy_quality_profile'),
- nameCreatePopupInput: byRole('textbox', { name: 'name required' }),
- importerA: byText('Importer A'),
- importerB: byText('Importer B'),
- summaryAdditionalRules: (count: number) => byText(`quality_profile.summary_additional.${count}`),
- summaryFewerRules: (count: number) => byText(`quality_profile.summary_fewer.${count}`),
- comparisonDiffTableHeading: (rulesQuantity: number, profileName: string) =>
- byRole('columnheader', {
- name: `quality_profiles.x_rules_only_in.${rulesQuantity}.${profileName}`,
- }),
- comparisonModifiedTableHeading: (rulesQuantity: number) =>
- byRole('table', {
- name: `quality_profiles.x_rules_have_different_configuration.${rulesQuantity}`,
- }),
- deprecatedRulesRegion: byRole('region', { name: 'quality_profiles.deprecated_rules' }),
- stagnantProfilesRegion: byRole('region', { name: 'quality_profiles.stagnant_profiles' }),
- recentlyAddedRulesRegion: byRole('region', { name: 'quality_profiles.latest_new_rules' }),
- newRuleLink: byRole('link', { name: 'Recently Added Rule' }),
- seeAllNewRulesLink: byRole('link', { name: 'quality_profiles.latest_new_rules.see_all_x.20' }),
-};
-
-it('should list Quality Profiles and filter by language', async () => {
- const user = userEvent.setup();
- serviceMock.setAdmin();
- renderQualityProfiles();
- expect(await ui.listLinkCQualityProfile.find()).toBeInTheDocument();
- expect(ui.listLinkJavaQualityProfile.get()).toBeInTheDocument();
-
- await user.click(ui.filterByLang.get());
- await user.click(byRole('option', { name: 'C' }).get());
-
- expect(ui.listLinkJavaQualityProfile.query()).not.toBeInTheDocument();
-
- // Creation form should have language pre-selected
- await user.click(await ui.createButton.find());
-
- expect(ui.languageSelect.get()).toHaveValue('C');
-});
-
-describe('Evolution', () => {
- it('should list deprecated rules', async () => {
- serviceMock.setAdmin();
- renderQualityProfiles();
-
- expect(await ui.deprecatedRulesRegion.find()).toBeInTheDocument();
- expect(
- ui.deprecatedRulesRegion.byRole('link', { name: 'Good old PHP quality profile' }).get(),
- ).toBeInTheDocument();
- expect(
- ui.deprecatedRulesRegion.byRole('link', { name: 'java quality profile #2' }).get(),
- ).toBeInTheDocument();
- });
-
- it('should list stagnant profiles', async () => {
- serviceMock.setAdmin();
- renderQualityProfiles();
-
- expect(await ui.stagnantProfilesRegion.find()).toBeInTheDocument();
- expect(
- ui.stagnantProfilesRegion.byRole('link', { name: 'Good old PHP quality profile' }).get(),
- ).toBeInTheDocument();
- });
-
- it('should list recently added rules', async () => {
- serviceMock.setAdmin();
- serviceMock.setRulesSearchResponse({
- rules: [mockRule({ name: 'Recently Added Rule' })],
- paging: mockPaging({
- total: 20,
- }),
- });
- renderQualityProfiles();
-
- expect(await ui.recentlyAddedRulesRegion.find()).toBeInTheDocument();
- expect(ui.newRuleLink.get()).toBeInTheDocument();
- expect(ui.seeAllNewRulesLink.get()).toBeInTheDocument();
- });
-});
-
-describe('Create', () => {
- it('should be able to extend an existing Quality Profile', async () => {
- const user = userEvent.setup();
- serviceMock.setAdmin();
- renderQualityProfiles();
-
- await user.click(await ui.listProfileActions('c quality profile', 'C').find());
- await user.click(ui.extendButton.get());
- await user.clear(ui.namePropupInput.get());
- await user.type(ui.namePropupInput.get(), ui.newCQualityProfileName);
- await user.keyboard('{Enter}');
-
- expect(await ui.headingNewCQualityProfile.find()).toBeInTheDocument();
-
- await user.click(ui.returnToList.get());
- await user.click(ui.createButton.get());
- await user.click(ui.extendRadio.get());
-
- await user.click(ui.languageSelect.get());
- await user.click(byRole('option', { name: 'C' }).get());
-
- await user.click(ui.profileExtendSelect.get());
- await user.click(byRole('option', { name: ui.newCQualityProfileName }).get());
-
- await user.type(ui.nameCreatePopupInput.get(), ui.newCQualityProfileNameFromCreateButton);
- await user.click(ui.createButton.get(ui.popup.get()));
-
- expect(await ui.headingNewCQualityProfileFromCreateButton.find()).toBeInTheDocument();
- });
-
- it('should be able to copy an existing Quality Profile', async () => {
- const user = userEvent.setup();
- serviceMock.setAdmin();
- renderQualityProfiles();
-
- await user.click(await ui.listProfileActions('c quality profile', 'C').find());
- await user.click(ui.copyButton.get());
- await user.clear(ui.namePropupInput.get());
- await user.type(ui.namePropupInput.get(), ui.newCQualityProfileName);
- await user.click(ui.modalCopyButton.get(ui.popup.get()));
-
- expect(await ui.headingNewCQualityProfile.find()).toBeInTheDocument();
-
- await user.click(ui.returnToList.get());
- await user.click(ui.createButton.get());
- await user.click(ui.copyRadio.get());
-
- await user.click(ui.languageSelect.get());
- await user.click(byRole('option', { name: 'C' }).get());
-
- await user.click(ui.profileCopySelect.get());
- await user.click(byRole('option', { name: ui.newCQualityProfileName }).get());
-
- await user.type(ui.nameCreatePopupInput.get(), ui.newCQualityProfileNameFromCreateButton);
- await user.click(ui.createButton.get(ui.popup.get()));
-
- expect(await ui.headingNewCQualityProfileFromCreateButton.find()).toBeInTheDocument();
- });
-
- it('should be able to create blank Quality Profile', async () => {
- const user = userEvent.setup();
- serviceMock.setAdmin();
- renderQualityProfiles();
-
- await user.click(await ui.createButton.find());
- await user.click(ui.blankRadio.get());
-
- await user.click(ui.languageSelect.get());
- await user.click(byRole('option', { name: 'C' }).get());
-
- await user.type(ui.nameCreatePopupInput.get(), ui.newCQualityProfileName);
- await user.click(ui.createButton.get(ui.popup.get()));
-
- expect(await ui.headingNewCQualityProfile.find()).toBeInTheDocument();
- });
-
- it('should render importers', async () => {
- const user = userEvent.setup();
- serviceMock.setAdmin();
- renderQualityProfiles();
-
- await user.click(await ui.createButton.find());
- await user.click(ui.blankRadio.get());
-
- await user.click(ui.languageSelect.get());
- await user.click(byRole('option', { name: 'C' }).get());
-
- expect(ui.importerA.get()).toBeInTheDocument();
- expect(ui.importerB.get()).toBeInTheDocument();
-
- await user.click(ui.copyRadio.get());
- expect(ui.importerA.query()).not.toBeInTheDocument();
- expect(ui.importerB.query()).not.toBeInTheDocument();
-
- await user.click(ui.extendRadio.get());
- expect(ui.importerA.query()).not.toBeInTheDocument();
- expect(ui.importerB.query()).not.toBeInTheDocument();
- });
-});
-
-it('should be able to restore a quality profile', async () => {
- const user = userEvent.setup();
- serviceMock.setAdmin();
- renderQualityProfiles();
-
- await user.click(await ui.restoreButton.find());
- expect(await ui.restoreProfileDialog.find()).toBeInTheDocument();
-
- const profileXMLBackup = new File(['c-sonarsource-06756'], 'c-sonarsource-06756', {
- type: 'application/xml',
- });
- const input = screen.getByLabelText<HTMLInputElement>(/backup/);
- // Very hacky way to upload the file in the test
- input.removeAttribute('required');
-
- await userEvent.upload(input, profileXMLBackup);
- expect(input.files?.item(0)).toStrictEqual(profileXMLBackup);
-
- await user.click(ui.restoreProfileDialog.byRole('button', { name: 'restore' }).get());
-
- expect(await screen.findByText(/quality_profiles.restore_profile.success/)).toBeInTheDocument();
-});
-
-it('should be able to compare profiles', async () => {
- // From the list page
- const user = userEvent.setup();
- serviceMock.setAdmin();
- renderQualityProfiles();
-
- // For language with 1 profle we should not see compare action
- await user.click(await ui.listProfileActions('c quality profile', 'C').find());
- expect(ui.compareButton.query()).not.toBeInTheDocument();
-
- await user.click(ui.listProfileActions('java quality profile', 'Java').get());
- expect(ui.compareButton.get()).toBeInTheDocument();
- await user.click(ui.compareButton.get());
- expect(ui.compareDropdown.get()).toBeInTheDocument();
- expect(ui.profileActions('java quality profile', 'Java').query()).not.toBeInTheDocument();
- expect(ui.changelogLink.query()).not.toBeInTheDocument();
-
- await user.click(ui.compareDropdown.get());
- await user.click(byRole('option', { name: 'java quality profile #2' }).get());
-
- expect(await ui.comparisonDiffTableHeading(1, 'java quality profile').find()).toBeInTheDocument();
- expect(ui.comparisonDiffTableHeading(1, 'java quality profile #2').get()).toBeInTheDocument();
- expect(ui.comparisonModifiedTableHeading(1).get()).toBeInTheDocument();
-
- expect(
- ui.comparisonModifiedTableHeading(1).byLabelText('severity_impact.BLOCKER').get(),
- ).toBeInTheDocument();
- expect(
- ui.comparisonModifiedTableHeading(1).byLabelText('severity_impact.LOW').get(),
- ).toBeInTheDocument();
-
- // java quality profile is not editable
- expect(ui.activeRuleButton('java quality profile').query()).not.toBeInTheDocument();
- expect(ui.deactivateRuleButton('java quality profile').query()).not.toBeInTheDocument();
-});
-
-it('should be able to compare profiles without impacts', async () => {
- // From the list page
- const user = userEvent.setup();
- serviceMock.comparisonResult = mockCompareResult({
- modified: [
- {
- impacts: [],
- key: 'java:S1698',
- name: '== and != should not be used when equals is overridden',
- left: {
- params: {},
- severity: 'MINOR',
- },
- right: {
- params: {},
- severity: 'CRITICAL',
- },
- },
- ],
- });
- serviceMock.setAdmin();
- renderQualityProfiles();
-
- await user.click(await ui.listProfileActions('java quality profile', 'Java').find());
- expect(ui.compareButton.get()).toBeInTheDocument();
- await user.click(ui.compareButton.get());
- await user.click(ui.compareDropdown.get());
- await user.click(byRole('option', { name: 'java quality profile #2' }).get());
-
- expect(await ui.comparisonModifiedTableHeading(1).find()).toBeInTheDocument();
-
- expect(
- ui
- .comparisonModifiedTableHeading(1)
- .byLabelText(/severity_impact/)
- .query(),
- ).not.toBeInTheDocument();
-});
-
-it('should be able to activate or deactivate rules in comparison page', async () => {
- // From the list page
- const user = userEvent.setup();
- serviceMock.setAdmin();
- renderQualityProfiles();
-
- await user.click(await ui.listProfileActions('java quality profile #2', 'Java').find());
- await user.click(ui.compareButton.get());
-
- await user.click(ui.compareDropdown.get());
- await user.click(byRole('option', { name: 'java quality profile' }).get());
-
- expect(await ui.summaryFewerRules(1).find()).toBeInTheDocument();
- expect(ui.summaryAdditionalRules(1).get()).toBeInTheDocument();
-
- // Activate
- await user.click(ui.activeRuleButton('java quality profile #2').get());
- expect(ui.popup.get()).toBeInTheDocument();
-
- await user.click(ui.activateConfirmButton.get());
- expect(ui.summaryFewerRules(1).query()).not.toBeInTheDocument();
-
- // Deactivate
- await user.click(await ui.deactivateRuleButton('java quality profile #2').find());
- expect(ui.confirmationModal.get()).toBeInTheDocument();
- await user.click(ui.deactivateConfirmButton.get());
- expect(ui.summaryAdditionalRules(1).query()).not.toBeInTheDocument();
-});
-
-function renderQualityProfiles() {
- renderAppRoutes('profiles', routes, {
- languages: {
- js: { key: 'js', name: 'JavaScript' },
- java: { key: 'java', name: 'Java' },
- c: { key: 'c', name: 'C' },
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/__snapshots__/utils-test.ts.snap b/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/__snapshots__/utils-test.ts.snap
deleted file mode 100644
index 05becce21d1..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/__snapshots__/utils-test.ts.snap
+++ /dev/null
@@ -1,143 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`#sortProfiles should sort by name 1`] = `
-[
- {
- "childrenCount": 0,
- "depth": 1,
- "key": "profile1",
- "name": "profile1",
- "parentKey": undefined,
- },
- {
- "childrenCount": 0,
- "depth": 1,
- "key": "profile2",
- "name": "profile2",
- "parentKey": undefined,
- },
- {
- "childrenCount": 0,
- "depth": 1,
- "key": "profile3",
- "name": "profile3",
- "parentKey": undefined,
- },
-]
-`;
-
-exports[`#sortProfiles should sort single branch 1`] = `
-[
- {
- "childrenCount": 1,
- "depth": 1,
- "key": "profile1",
- "name": "profile1",
- "parentKey": undefined,
- },
- {
- "childrenCount": 1,
- "depth": 2,
- "key": "profile3",
- "name": "profile3",
- "parentKey": "profile1",
- },
- {
- "childrenCount": 0,
- "depth": 3,
- "key": "profile2",
- "name": "profile2",
- "parentKey": "profile3",
- },
-]
-`;
-
-exports[`#sortProfiles should sort when no parents 1`] = `
-[
- {
- "childrenCount": 0,
- "depth": 1,
- "key": "profile1",
- "name": "profile1",
- "parentKey": undefined,
- },
- {
- "childrenCount": 0,
- "depth": 1,
- "key": "profile2",
- "name": "profile2",
- "parentKey": undefined,
- },
- {
- "childrenCount": 0,
- "depth": 1,
- "key": "profile3",
- "name": "profile3",
- "parentKey": undefined,
- },
-]
-`;
-
-exports[`#sortProfiles should sort with children 1`] = `
-[
- {
- "childrenCount": 2,
- "depth": 1,
- "key": "parent",
- "name": "parent",
- "parentKey": undefined,
- },
- {
- "childrenCount": 0,
- "depth": 2,
- "key": "child1",
- "name": "child1",
- "parentKey": "parent",
- },
- {
- "childrenCount": 0,
- "depth": 2,
- "key": "child2",
- "name": "child2",
- "parentKey": "parent",
- },
-]
-`;
-
-exports[`#sortProfiles sorts partial set of inherited profiles 1`] = `
-[
- {
- "childrenCount": 0,
- "depth": 1,
- "key": "foo",
- "name": "foo",
- "parentKey": "bar",
- },
-]
-`;
-
-exports[`#sortProfiles sorts partial set of inherited profiles 2`] = `
-[
- {
- "childrenCount": 0,
- "depth": 1,
- "key": "profile1",
- "name": "profile1",
- "parentKey": "x",
- },
- {
- "childrenCount": 1,
- "depth": 1,
- "key": "profile2",
- "name": "profile2",
- "parentKey": undefined,
- },
- {
- "childrenCount": 0,
- "depth": 2,
- "key": "profile3",
- "name": "profile3",
- "parentKey": "profile2",
- },
-]
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/utils-test.ts
deleted file mode 100644
index 952eef8430e..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/utils-test.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Profile } from '../types';
-import { sortProfiles } from '../utils';
-
-function createProfile(key: string, parentKey?: string) {
- return { name: key, key, parentKey } as Profile;
-}
-
-describe('#sortProfiles', () => {
- it('should sort when no parents', () => {
- const profile1 = createProfile('profile1');
- const profile2 = createProfile('profile2');
- const profile3 = createProfile('profile3');
- expect(sortProfiles([profile1, profile2, profile3])).toMatchSnapshot();
- });
-
- it('should sort by name', () => {
- const profile1 = createProfile('profile1');
- const profile2 = createProfile('profile2');
- const profile3 = createProfile('profile3');
- expect(sortProfiles([profile3, profile1, profile2])).toMatchSnapshot();
- });
-
- it('should sort with children', () => {
- const child1 = createProfile('child1', 'parent');
- const child2 = createProfile('child2', 'parent');
- const parent = createProfile('parent');
- expect(sortProfiles([child1, child2, parent])).toMatchSnapshot();
- });
-
- it('should sort single branch', () => {
- const profile1 = createProfile('profile1');
- const profile2 = createProfile('profile2', 'profile3');
- const profile3 = createProfile('profile3', 'profile1');
- expect(sortProfiles([profile3, profile2, profile1])).toMatchSnapshot();
- });
-
- it('sorts partial set of inherited profiles', () => {
- const foo = createProfile('foo', 'bar');
- expect(sortProfiles([foo])).toMatchSnapshot();
-
- const profile1 = createProfile('profile1', 'x');
- const profile2 = createProfile('profile2');
- const profile3 = createProfile('profile3', 'profile2');
- expect(sortProfiles([profile1, profile2, profile3])).toMatchSnapshot();
- });
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/constants.ts b/server/sonar-web/src/main/js/apps/quality-profiles/constants.ts
deleted file mode 100644
index be44ea80494..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/constants.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export const PROFILE_PATH = '/profiles';
-export const PROFILE_COMPARE_PATH = `${PROFILE_PATH}/compare`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/qualityProfilesContext.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/qualityProfilesContext.tsx
deleted file mode 100644
index 758056fc31b..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/qualityProfilesContext.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React from 'react';
-import { useOutletContext } from 'react-router-dom';
-import { getWrappedDisplayName } from '~sonar-aligned/components/hoc/utils';
-import { Actions } from '../../api/quality-profiles';
-import { Language } from '../../types/languages';
-import { Exporter, Profile } from './types';
-
-export interface QualityProfilesContextProps {
- actions: Actions;
- exporters: Exporter[];
- languages: Language[];
- profile?: Profile;
- profiles: Profile[];
- updateProfiles: () => Promise<void>;
-}
-
-export function withQualityProfilesContext<P extends Partial<QualityProfilesContextProps>>(
- WrappedComponent: React.ComponentType<React.PropsWithChildren<P>>,
-): React.ComponentType<React.PropsWithChildren<Omit<P, keyof QualityProfilesContextProps>>> {
- function ComponentWithQualityProfilesProps(props: P) {
- const context = useOutletContext<QualityProfilesContextProps>();
- return <WrappedComponent {...props} {...context} />;
- }
-
- (ComponentWithQualityProfilesProps as React.FC<React.PropsWithChildren<P>>).displayName =
- getWrappedDisplayName(WrappedComponent, 'withQualityProfilesContext');
-
- return ComponentWithQualityProfilesProps;
-}
-
-export function useQualityProfilesContext() {
- return useOutletContext<QualityProfilesContextProps>();
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/types.ts b/server/sonar-web/src/main/js/apps/quality-profiles/types.ts
deleted file mode 100644
index 2fbc2391f0e..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/types.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Profile as BaseProfile } from '../../api/quality-profiles';
-import {
- CleanCodeAttribute,
- CleanCodeAttributeCategory,
- SoftwareImpactSeverity,
- SoftwareQuality,
-} from '../../types/clean-code-taxonomy';
-import { IssueSeverity } from '../../types/issues';
-import { Dict } from '../../types/types';
-
-export interface Profile extends BaseProfile {
- childrenCount: number;
- depth: number;
-}
-
-export interface Exporter {
- key: string;
- languages: string[];
- name: string;
-}
-
-export interface ProfileChangelogEventImpactChange {
- newSeverity?: SoftwareImpactSeverity;
- newSoftwareQuality?: SoftwareQuality;
- oldSeverity?: SoftwareImpactSeverity;
- oldSoftwareQuality?: SoftwareQuality;
-}
-
-export interface ProfileChangelogEvent {
- action: string;
- authorName?: string;
- cleanCodeAttributeCategory?: CleanCodeAttributeCategory;
- date: string;
- // impacts should be always set in the wild. But Next currently has a specific database state for which this field is undefined. May be possible to make this field required in the future.
- impacts?: {
- severity: SoftwareImpactSeverity;
- softwareQuality: SoftwareQuality;
- }[];
- params?: {
- impactChanges?: ProfileChangelogEventImpactChange[];
- newCleanCodeAttribute?: CleanCodeAttribute;
- newCleanCodeAttributeCategory?: CleanCodeAttributeCategory;
- oldCleanCodeAttribute?: CleanCodeAttribute;
- oldCleanCodeAttributeCategory?: CleanCodeAttributeCategory;
- severity?: IssueSeverity;
- } & Dict<string | ProfileChangelogEventImpactChange[] | null>;
- ruleKey: string;
- ruleName: string;
- sonarQubeVersion: string;
-}
-
-export enum ProfileActionModals {
- Copy = 'COPY',
- Extend = 'EXTEND',
- Rename = 'RENAME',
- Delete = 'DELETE',
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/utils.ts b/server/sonar-web/src/main/js/apps/quality-profiles/utils.ts
deleted file mode 100644
index 22c7fcba322..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/utils.ts
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { differenceInYears } from 'date-fns';
-import { sortBy } from 'lodash';
-import { queryToSearchString } from '~sonar-aligned/helpers/urls';
-import { Profile as BaseProfile } from '../../api/quality-profiles';
-import { isValidDate, parseDate } from '../../helpers/dates';
-import { PROFILE_COMPARE_PATH, PROFILE_PATH } from './constants';
-import { Profile } from './types';
-
-export function sortProfiles(profiles: BaseProfile[]): Profile[] {
- const result: Profile[] = [];
- const sorted = sortBy(profiles, 'name');
-
- function retrieveChildren(parent: BaseProfile | null) {
- return sorted.filter(
- (p) =>
- (parent == null && p.parentKey == null) || (parent != null && p.parentKey === parent.key),
- );
- }
-
- function putProfile(profile: BaseProfile | null = null, depth: number = 1) {
- const children = retrieveChildren(profile);
-
- if (profile != null) {
- result.push({ ...profile, childrenCount: children.length, depth });
- }
-
- children.forEach((child) => putProfile(child, depth + 1));
- }
-
- sorted
- .filter(
- (profile) =>
- profile.parentKey == null || sorted.find((p) => p.key === profile.parentKey) == null,
- )
- .forEach((profile) => putProfile(profile));
-
- return result;
-}
-
-export function isStagnant(profile: Profile): boolean {
- if (profile.rulesUpdatedAt) {
- const updateDate = parseDate(profile.rulesUpdatedAt);
- if (isValidDate(updateDate)) {
- return differenceInYears(new Date(), updateDate) >= 1;
- }
- }
- return false;
-}
-
-export const getProfilesForLanguagePath = (language: string) => ({
- pathname: PROFILE_PATH,
- search: queryToSearchString({ language }),
-});
-
-export const getProfilePath = (name: string, language: string) => ({
- pathname: `${PROFILE_PATH}/show`,
- search: queryToSearchString({ name, language }),
-});
-
-export const getProfileComparePath = (name: string, language: string, withKey?: string) => {
- const query = { language, name };
- if (withKey) {
- Object.assign(query, { withKey });
- }
- return {
- pathname: PROFILE_COMPARE_PATH,
- search: queryToSearchString(query),
- };
-};
-
-export const getProfileChangelogPath = (
- name: string,
- language: string,
- filter?: { since?: string; to?: string },
-) => {
- const query = { language, name };
- if (filter) {
- if (filter.since) {
- Object.assign(query, { since: filter.since });
- }
- if (filter.to) {
- Object.assign(query, { to: filter.to });
- }
- }
- return {
- pathname: `${PROFILE_PATH}/changelog`,
- search: queryToSearchString(query),
- };
-};
-
-export const isProfileComparePath = (pathname: string): boolean => {
- return pathname === PROFILE_COMPARE_PATH;
-};
diff --git a/server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts
deleted file mode 100644
index 6e53ac929b9..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { hasMessage } from '../../../helpers/l10n';
-import { mockComponent } from '../../../helpers/mocks/component';
-import { mockDefinition, mockSettingValue } from '../../../helpers/mocks/settings';
-import {
- ExtendedSettingDefinition,
- Setting,
- SettingFieldDefinition,
- SettingType,
-} from '../../../types/settings';
-import {
- buildSettingLink,
- getDefaultValue,
- getEmptyValue,
- getPropertyName,
- getSettingValue,
-} from '../utils';
-
-jest.mock('../../../helpers/l10n', () => ({
- ...jest.requireActual('../../../helpers/l10n'),
- hasMessage: jest.fn(),
-}));
-
-jest.mock('../../../helpers/l10nBundle', () => {
- const bundle = jest.requireActual('../../../helpers/l10nBundle');
- return {
- ...bundle,
- getIntl: () => ({ formatMessage: jest.fn(({ id }) => `${id}`) }),
- };
-});
-
-const fields = [
- { key: 'foo', type: 'STRING' } as SettingFieldDefinition,
- { key: 'bar', type: 'SINGLE_SELECT_LIST' } as SettingFieldDefinition,
-];
-
-const settingDefinition: ExtendedSettingDefinition = {
- category: 'test',
- fields: [],
- key: 'test',
- options: [],
- subCategory: 'subtest',
-};
-
-describe('getPropertyName', () => {
- it('should return correct value for existing translation', () => {
- jest.mocked(hasMessage).mockImplementation(() => true);
- expect(getPropertyName(mockDefinition())).toBe('property.foo.name');
- });
-
- it('should return a name when translation doesn`t exist', () => {
- jest.mocked(hasMessage).mockImplementation(() => false);
- expect(getPropertyName(mockDefinition({ name: 'nicename', key: 'keey' }))).toBe('nicename');
- });
- it('should return a key when translation and name dont exist', () => {
- expect(getPropertyName(mockDefinition({ key: 'keey' }))).toBe('keey');
- });
-});
-
-describe('#getEmptyValue()', () => {
- it('should work for property sets', () => {
- const setting: ExtendedSettingDefinition = {
- ...settingDefinition,
- type: SettingType.PROPERTY_SET,
- fields,
- };
- expect(getEmptyValue(setting)).toEqual([{ foo: '', bar: null }]);
- });
-
- it('should work for multi values string', () => {
- const setting: ExtendedSettingDefinition = {
- ...settingDefinition,
- type: SettingType.STRING,
- multiValues: true,
- };
- expect(getEmptyValue(setting)).toEqual(['']);
- });
-
- it('should work for multi values boolean', () => {
- const setting: ExtendedSettingDefinition = {
- ...settingDefinition,
- type: SettingType.BOOLEAN,
- multiValues: true,
- };
- expect(getEmptyValue(setting)).toEqual([null]);
- });
-});
-
-describe('#getSettingValue()', () => {
- it('should work for property sets', () => {
- const setting: ExtendedSettingDefinition = {
- ...settingDefinition,
- type: SettingType.PROPERTY_SET,
- fields,
- };
- const settingValue = mockSettingValue({ fieldValues: [{ foo: '' }] });
- expect(getSettingValue(setting, settingValue)).toEqual([{ foo: '' }]);
- });
-
- it('should work for category definitions', () => {
- const setting: ExtendedSettingDefinition = {
- ...settingDefinition,
- type: SettingType.FORMATTED_TEXT,
- fields,
- multiValues: true,
- };
- const settingValue = mockSettingValue({ values: ['*text*', 'text'] });
- expect(getSettingValue(setting, settingValue)).toEqual(['*text*', 'text']);
- });
-
- it('should work for formatted text', () => {
- const setting: ExtendedSettingDefinition = {
- ...settingDefinition,
- type: SettingType.FORMATTED_TEXT,
- fields,
- };
- const settingValue = mockSettingValue({ values: ['*text*', 'text'] });
- expect(getSettingValue(setting, settingValue)).toEqual('*text*');
- });
-
- it('should work for formatted text when values is undefined', () => {
- const setting: ExtendedSettingDefinition = {
- ...settingDefinition,
- type: SettingType.FORMATTED_TEXT,
- fields,
- };
- const settingValue = mockSettingValue({ values: undefined });
- expect(getSettingValue(setting, settingValue)).toBeUndefined();
- });
-});
-
-describe('#getDefaultValue()', () => {
- it.each([
- ['true', 'settings.boolean.true'],
- ['false', 'settings.boolean.false'],
- ])(
- 'should work for boolean field when passing "%s"',
- (parentValue?: string, expected?: string) => {
- const setting: Setting = {
- hasValue: true,
- definition: { key: 'test', options: [], type: SettingType.BOOLEAN },
- parentValue,
- key: 'test',
- };
- expect(getDefaultValue(setting)).toEqual(expected);
- },
- );
-});
-
-describe('buildSettingLink', () => {
- it.each([
- [
- mockDefinition({ key: 'anykey' }),
- undefined,
- { hash: '#anykey', pathname: '/admin/settings', search: '?category=foo+category' },
- ],
- [
- mockDefinition({ key: 'sonar.auth.gitlab.name' }),
- undefined,
- {
- hash: '#sonar.auth.gitlab.name',
- pathname: '/admin/settings',
- search: '?category=foo+category&tab=gitlab',
- },
- ],
- [
- mockDefinition({ key: 'sonar.auth.github.token' }),
- undefined,
- {
- hash: '#sonar.auth.github.token',
- pathname: '/admin/settings',
- search: '?category=foo+category&tab=github',
- },
- ],
- [
- mockDefinition({ key: 'sonar.auth.bitbucket.token' }),
- undefined,
- {
- hash: '#sonar.auth.bitbucket.token',
- pathname: '/admin/settings',
- search: '?category=foo+category&tab=bitbucket',
- },
- ],
- [
- mockDefinition({ key: 'sonar.almintegration.azure' }),
- undefined,
- {
- hash: '#sonar.almintegration.azure',
- pathname: '/admin/settings',
- search: '?category=foo+category&alm=azure',
- },
- ],
- [
- mockDefinition({ key: 'defKey' }),
- mockComponent({ key: 'componentKey' }),
- {
- hash: '#defKey',
- pathname: '/project/settings',
- search: '?id=componentKey&category=foo+category',
- },
- ],
- ])('should work as expected', (definition, component, expectedUrl) => {
- expect(buildSettingLink(definition, component)).toEqual(expectedUrl);
- });
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/constants.ts b/server/sonar-web/src/main/js/apps/settings/constants.ts
deleted file mode 100644
index d21ab6b25f2..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/constants.ts
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { AlmKeys } from '../../types/alm-settings';
-import { ExtendedSettingDefinition } from '../../types/settings';
-import { Dict } from '../../types/types';
-
-export const ALM_INTEGRATION_CATEGORY = 'almintegration';
-export const AI_CODE_FIX_CATEGORY = 'ai_codefix';
-export const AUTHENTICATION_CATEGORY = 'authentication';
-export const ANALYSIS_SCOPE_CATEGORY = 'exclusions';
-export const LANGUAGES_CATEGORY = 'languages';
-export const NEW_CODE_PERIOD_CATEGORY = 'new_code_period';
-export const PULL_REQUEST_DECORATION_BINDING_CATEGORY = 'pull_request_decoration_binding';
-export const EMAIL_NOTIFICATION_CATEGORY = 'email_notification';
-export const MODE_CATEGORY = 'mode';
-
-export const CATEGORY_OVERRIDES: Dict<string> = {
- abap: LANGUAGES_CATEGORY,
- ansible: LANGUAGES_CATEGORY,
- apex: LANGUAGES_CATEGORY,
- azureresourcemanager: LANGUAGES_CATEGORY,
- 'c / c++ / objective-c': LANGUAGES_CATEGORY,
- 'c#': LANGUAGES_CATEGORY,
- cloudformation: LANGUAGES_CATEGORY,
- cobol: LANGUAGES_CATEGORY,
- css: LANGUAGES_CATEGORY,
- dart: LANGUAGES_CATEGORY,
- docker: LANGUAGES_CATEGORY,
- flex: LANGUAGES_CATEGORY,
- go: LANGUAGES_CATEGORY,
- html: LANGUAGES_CATEGORY,
- java: LANGUAGES_CATEGORY,
- javascript: LANGUAGES_CATEGORY,
- 'javascript / typescript': LANGUAGES_CATEGORY,
- jcl: LANGUAGES_CATEGORY,
- json: LANGUAGES_CATEGORY,
- kotlin: LANGUAGES_CATEGORY,
- kubernetes: LANGUAGES_CATEGORY,
- php: LANGUAGES_CATEGORY,
- 'pl/i': LANGUAGES_CATEGORY,
- 'pl/sql': LANGUAGES_CATEGORY,
- python: LANGUAGES_CATEGORY,
- rpg: LANGUAGES_CATEGORY,
- ruby: LANGUAGES_CATEGORY,
- secrets: LANGUAGES_CATEGORY,
- scala: LANGUAGES_CATEGORY,
- swift: LANGUAGES_CATEGORY,
- 't-sql': LANGUAGES_CATEGORY,
- terraform: LANGUAGES_CATEGORY,
- typescript: LANGUAGES_CATEGORY,
- 'vb.net': LANGUAGES_CATEGORY,
- 'visual basic': LANGUAGES_CATEGORY,
- xml: LANGUAGES_CATEGORY,
- yaml: LANGUAGES_CATEGORY,
-};
-
-export const SUB_CATEGORY_EXCLUSIONS: Record<string, string[]> = {
- general: ['email'],
-};
-
-// As per Bitbucket Cloud's documentation, Workspace ID's can only contain lowercase letters,
-// numbers, dashes, and underscores.
-export const BITBUCKET_CLOUD_WORKSPACE_ID_FORMAT = /^[a-z0-9\-_]+$/;
-
-export const ADDITIONAL_PROJECT_SETTING_DEFINITIONS: ExtendedSettingDefinition[] = [
- {
- name: 'DevOps Platform Integration',
- description: `
- Display your Quality Gate status directly in your DevOps Platform.
- Each DevOps Platform instance must be configured globally first, and given a unique name. Pick the instance your project is hosted on.
- `,
- category: 'pull_request_decoration_binding',
- key: ``,
- fields: [],
- options: [],
- subCategory: '',
- },
-];
-
-export const ADDITIONAL_SETTING_DEFINITIONS: ExtendedSettingDefinition[] = [
- {
- name: 'Default New Code behavior',
- description: `
- The New Code definition is used to compare measures and track new issues.
- This setting is the default for all projects. A specific New Code definition can be configured at project level.
- `,
- category: 'new_code_period',
- key: `sonar.new_code_period`,
- fields: [],
- options: [],
- subCategory: '',
- },
- {
- name: 'Azure DevOps integration',
- description: `azure devops integration configuration
- Configuration name
- Give your configuration a clear and succinct name.
- This name will be used at project level to identify the correct configured Azure instance for a project.
- Azure DevOps URL
- For Azure DevOps Server, provide the full collection URL:
- https://ado.your-company.com/your_collection
-
- For Azure DevOps Services, provide the full organization URL:
- https://dev.azure.com/your_organization
- Personal Access Token
- SonarQube needs a Personal Access Token to report the Quality Gate status on Pull Requests in Azure DevOps.
- To create this token, we recommend using a dedicated Azure DevOps account with administration permissions.
- The token itself needs Code > Read & Write permission.
- `,
- category: 'almintegration',
- key: `sonar.almintegration.${AlmKeys.Azure}`,
- fields: [],
- options: [],
- subCategory: '',
- },
- {
- name: 'Bitbucket integration',
- description: `bitbucket server cloud integration configuration
- Configuration name
- Give your configuration a clear and succinct name.
- This name will be used at project level to identify the correct configured Bitbucket instance for a project.
- Bitbucket Server URL
- Example: https://bitbucket-server.your-company.com
- Personal Access Token
- SonarQube needs a Personal Access Token to report the Quality Gate status on Pull Requests in Bitbucket Server.
- To create this token, we recommend using a dedicated Bitbucket Server account with administration permissions.
- The token itself needs Read permission.
- Workspace ID
- The workspace ID is part of your bitbucket cloud URL https://bitbucket.org/{workspace}/{repository}
- SonarQube needs you to create an OAuth consumer in your Bitbucket Cloud workspace settings
- to report the Quality Gate status on Pull Requests.
- It needs to be a private consumer with Pull Requests: Read permission.
- An OAuth callback URL is required by Bitbucket Cloud but not used by SonarQube so any URL works.
- OAuth Key
- Bitbucket automatically creates an OAuth key when you create your OAuth consumer.
- You can find it in your Bitbucket Cloud workspace settings under OAuth consumers.
- OAuth Secret
- Bitbucket automatically creates an OAuth secret when you create your OAuth consumer.
- You can find it in your Bitbucket Cloud workspace settings under OAuth consumers.
- `,
- category: 'almintegration',
- key: `sonar.almintegration.${AlmKeys.BitbucketServer}`,
- fields: [],
- options: [],
- subCategory: '',
- },
- {
- name: 'GitHub integration',
- description: `github integration configuration
- Configuration name
- Give your configuration a clear and succinct name.
- This name will be used at project level to identify the correct configured GitHub App for a project.
- GitHub API URL
- Example for Github Enterprise:
- https://github.company.com/api/v3
- If using GitHub.com:
- https://api.github.com/
- You need to install a GitHub App with specific settings and permissions to enable
- Pull Request Decoration on your Organization or Repository.
- GitHub App ID
- The App ID is found on your GitHub App's page on GitHub at Settings > Developer Settings > GitHub Apps
- Client ID
- The Client ID is found on your GitHub App's page.
- Client Secret
- The Client secret is found on your GitHub App's page.
- Private Key
- Your GitHub App's private key. You can generate a .pem file from your GitHub App's page under Private keys.
- Copy and paste the whole contents of the file here.
- `,
- category: 'almintegration',
- key: `sonar.almintegration.${AlmKeys.GitHub}`,
- fields: [],
- options: [],
- subCategory: '',
- },
- {
- name: 'Gitlab integration',
- description: `gitlab integration configuration
- Configuration name
- Give your configuration a clear and succinct name.
- This name will be used at project level to identify the correct configured GitLab instance for a project.
- GitLab API URL
- Provide the GitLab API URL. For example:
- https://gitlab.com/api/v4
- Personal Access Token
- SonarQube needs a Personal Access Token to report the Quality Gate status on Merge Requests in GitLab.
- To create this token,
- we recommend using a dedicated GitLab account with Reporter permission to all target projects.
- The token itself needs the api scope.
- `,
- category: 'almintegration',
- key: `sonar.almintegration.${AlmKeys.GitLab}`,
- fields: [],
- options: [],
- subCategory: '',
- },
-];
diff --git a/server/sonar-web/src/main/js/apps/settings/utils.ts b/server/sonar-web/src/main/js/apps/settings/utils.ts
deleted file mode 100644
index b46e9572eee..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/utils.ts
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { sortBy } from 'lodash';
-import { Path } from 'react-router-dom';
-import { InputSizeKeys } from '~design-system';
-import { hasMessage, translate } from '../../helpers/l10n';
-import { isDefined } from '../../helpers/types';
-import { getGlobalSettingsUrl, getProjectSettingsUrl } from '../../helpers/urls';
-import { AlmKeys } from '../../types/alm-settings';
-import {
- DefinitionV2,
- ExtendedSettingDefinition,
- Setting,
- SettingDefinition,
- SettingType,
- SettingValue,
- SettingWithCategory,
-} from '../../types/settings';
-import { Component, Dict } from '../../types/types';
-
-export const DEFAULT_CATEGORY = 'general';
-
-export type DefaultSpecializedInputProps = DefaultInputProps & {
- autoComplete?: string;
- className?: string;
- index?: number;
- isDefault: boolean;
- name: string;
- type?: string;
-};
-
-export interface DefaultInputProps {
- ariaDescribedBy?: string;
- autoFocus?: boolean;
- hasValueChanged?: boolean;
- id?: string;
- isEditing?: boolean;
- isInvalid?: boolean;
- onCancel?: () => void;
- onChange: (value: any) => void;
- onEditing?: () => void;
- onSave?: () => void;
- setting: Setting;
- size?: InputSizeKeys;
- value: any;
-}
-
-export function getPropertyName(definition: SettingDefinition | DefinitionV2) {
- const key = `property.${definition.key}.name`;
-
- if (hasMessage(key)) {
- return translate(key);
- }
-
- return definition.name ?? definition.key;
-}
-
-export function getPropertyDescription(definition: SettingDefinition | DefinitionV2) {
- const key = `property.${definition.key}.description`;
- return hasMessage(key) ? translate(key) : definition.description;
-}
-
-export function getCategoryName(category: string) {
- const key = `property.category.${category}`;
- return hasMessage(key) ? translate(key) : category;
-}
-
-export function getSubCategoryName(category: string, subCategory: string) {
- const key = `property.category.${category}.${subCategory}`;
- return hasMessage(key) ? translate(key) : getCategoryName(subCategory);
-}
-
-export function getSubCategoryDescription(category: string, subCategory: string) {
- const key = `property.category.${category}.${subCategory}.description`;
- return hasMessage(key) ? translate(key) : null;
-}
-
-export function getUniqueName(definition: SettingDefinition, index?: string) {
- const indexSuffix = index ? `[${index}]` : '';
- return `settings[${definition.key}]${indexSuffix}`;
-}
-
-export function getSettingValue(definition: SettingDefinition, settingValue?: SettingValue) {
- const { fieldValues, value, values } = settingValue || {};
- if (definition.type === SettingType.PROPERTY_SET) {
- return fieldValues;
- } else if (isCategoryDefinition(definition) && definition.multiValues) {
- return values;
- } else if (definition.type === SettingType.FORMATTED_TEXT) {
- return values ? values[0] : undefined;
- }
-
- return value;
-}
-
-export function combineDefinitionAndSettingValue(
- definition: ExtendedSettingDefinition,
- value?: SettingValue | null,
-): SettingWithCategory {
- const hasValue = isDefined(value) && value.inherited !== true;
-
- return {
- key: definition.key,
- hasValue,
- ...value,
- definition,
- };
-}
-
-export function getDefaultCategory(categories: string[]) {
- if (categories.includes(DEFAULT_CATEGORY)) {
- return DEFAULT_CATEGORY;
- }
-
- const sortedCategories = sortBy(categories, (category) =>
- getCategoryName(category).toLowerCase(),
- );
-
- return sortedCategories[0];
-}
-
-export function isEmptyValue(definition: SettingDefinition, value: any) {
- if (value == null) {
- return true;
- } else if (definition.type === 'BOOLEAN') {
- return false;
- }
-
- return value.length === 0;
-}
-
-export function isURLKind(definition: SettingDefinition) {
- return [
- 'sonar.core.serverBaseURL',
- 'sonar.auth.github.apiUrl',
- 'sonar.auth.github.webUrl',
- 'sonar.auth.gitlab.url',
- 'sonar.lf.gravatarServerUrl',
- 'sonar.lf.logoUrl',
- 'sonar.auth.saml.loginUrl',
- ].includes(definition.key);
-}
-
-export function isSecuredDefinition(item: SettingDefinition | DefinitionV2): boolean {
- return 'secured' in item ? item.secured : item.key.endsWith('.secured');
-}
-
-export function isCategoryDefinition(item: SettingDefinition): item is ExtendedSettingDefinition {
- return Boolean((item as any).fields);
-}
-
-export function getEmptyValue(item: SettingDefinition | ExtendedSettingDefinition): any {
- if (isCategoryDefinition(item)) {
- if (item.type === SettingType.PROPERTY_SET) {
- const value: Dict<string> = {};
- item.fields.forEach((field) => (value[field.key] = getEmptyValue(field)));
- return [value];
- }
-
- if (item.multiValues) {
- return [getEmptyValue({ ...item, multiValues: false })];
- }
- }
-
- if (item.type === 'BOOLEAN' || item.type === 'SINGLE_SELECT_LIST') {
- return null;
- }
-
- return '';
-}
-
-export function isDefaultOrInherited(setting?: Pick<SettingValue, 'inherited'>) {
- return Boolean(setting?.inherited);
-}
-
-export function getDefaultValue(setting: Setting) {
- const { definition, parentFieldValues, parentValue, parentValues } = setting;
-
- if (definition.type === 'PASSWORD') {
- return translate('settings.default.password');
- }
-
- if (definition.type === 'BOOLEAN' && Boolean(parentValue)) {
- const isTrue = parentValue === 'true';
- return isTrue ? translate('settings.boolean.true') : translate('settings.boolean.false');
- }
-
- if (
- isCategoryDefinition(definition) &&
- definition.multiValues &&
- parentValues &&
- parentValues.length > 0
- ) {
- return parentValues.join(', ');
- }
-
- if (
- definition.type === SettingType.PROPERTY_SET &&
- parentFieldValues &&
- parentFieldValues.length > 0
- ) {
- return translate('settings.default.complex_value');
- }
-
- if (parentValue == null) {
- return isCategoryDefinition(definition) && definition.defaultValue
- ? definition.defaultValue
- : translate('settings.default.no_value');
- }
-
- return parentValue;
-}
-
-export function isRealSettingKey(key: string) {
- return ![
- 'sonar.new_code_period',
- `sonar.almintegration.${AlmKeys.Azure}`,
- `sonar.almintegration.${AlmKeys.BitbucketServer}`,
- `sonar.almintegration.${AlmKeys.GitHub}`,
- `sonar.almintegration.${AlmKeys.GitLab}`,
- ].includes(key);
-}
-
-export function buildSettingLink(
- definition: ExtendedSettingDefinition,
- component?: Component,
-): Partial<Path> {
- const { category, key } = definition;
-
- if (component !== undefined) {
- return {
- ...getProjectSettingsUrl(component.key, category),
- hash: `#${escape(key)}`,
- };
- }
-
- const query: Dict<string> = {};
-
- if (key.startsWith('sonar.auth.gitlab')) {
- query.tab = 'gitlab';
- } else if (key.startsWith('sonar.auth.github')) {
- query.tab = 'github';
- } else if (key.startsWith('sonar.auth.bitbucket')) {
- query.tab = 'bitbucket';
- } else if (key.startsWith('sonar.almintegration')) {
- query.alm = key.split('.').pop() || '';
- }
-
- return {
- ...getGlobalSettingsUrl(category, query),
- hash: `#${escape(key)}`,
- };
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewer.tsx b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewer.tsx
deleted file mode 100644
index 340931d6fa0..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewer.tsx
+++ /dev/null
@@ -1,639 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { intersection } from 'lodash';
-import * as React from 'react';
-import { FlagMessage } from '~design-system';
-import { getBranchLikeQuery } from '~sonar-aligned/helpers/branch-like';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import {
- getComponentData,
- getComponentForSourceViewer,
- getDuplications,
- getSources,
-} from '../../api/components';
-import { ComponentContext } from '../../app/components/componentContext/ComponentContext';
-import { isSameBranchLike } from '../../helpers/branch-like';
-import { translate } from '../../helpers/l10n';
-import { HttpStatus } from '../../helpers/request';
-import { BranchLike } from '../../types/branch-like';
-import {
- Dict,
- DuplicatedFile,
- Duplication,
- FlowLocation,
- Issue,
- LinearIssueLocation,
- Measure,
- SourceLine,
- SourceViewerFile,
-} from '../../types/types';
-import { WorkspaceContext } from '../workspace/context';
-import SourceViewerCode from './SourceViewerCode';
-import { SourceViewerContext } from './SourceViewerContext';
-import SourceViewerHeader from './SourceViewerHeader';
-import DuplicationPopup from './components/DuplicationPopup';
-import {
- filterDuplicationBlocksByLine,
- getDuplicationBlocksForIndex,
- isDuplicationBlockInRemovedComponent,
-} from './helpers/duplications';
-import getCoverageStatus from './helpers/getCoverageStatus';
-import {
- duplicationsByLine,
- issuesByLine,
- locationsByLine,
- symbolsByLine,
-} from './helpers/indexing';
-import { LINES_TO_LOAD } from './helpers/lines';
-import loadIssues from './helpers/loadIssues';
-import './styles.css';
-
-export interface Props {
- aroundLine?: number;
- branchLike: BranchLike | undefined;
- component: string;
- componentMeasures?: Measure[];
- displayAllIssues?: boolean;
- displayLocationMarkers?: boolean;
- hideHeader?: boolean;
- hidePinOption?: boolean;
- highlightedLine?: number;
- highlightedLocationMessage?: { index: number; text: string | undefined };
- // `undefined` elements mean they are located in a different file,
- // but kept to maintain the location indexes
- highlightedLocations?: (FlowLocation | undefined)[];
- metricKey?: string;
- needIssueSync?: boolean;
- onIssueSelect?: (issueKey: string) => void;
- onIssueUnselect?: () => void;
- onLoaded?: (component: SourceViewerFile, sources: SourceLine[], issues: Issue[]) => void;
- onLocationSelect?: (index: number) => void;
- selectedIssue?: string;
- showMeasures?: boolean;
-}
-
-interface State {
- component?: SourceViewerFile;
- duplicatedFiles?: Dict<DuplicatedFile>;
- duplications?: Duplication[];
- duplicationsByLine: { [line: number]: number[] };
- hasSourcesAfter: boolean;
- highlightedSymbols: string[];
- issueLocationsByLine: { [line: number]: LinearIssueLocation[] };
- issuePopup?: { issue: string; name: string };
- issues?: Issue[];
- issuesByLine: { [line: number]: Issue[] };
- loading: boolean;
- loadingSourcesAfter: boolean;
- loadingSourcesBefore: boolean;
- notAccessible: boolean;
- notExist: boolean;
- openIssuesByLine: { [line: number]: boolean };
- selectedIssue?: string;
- sourceRemoved: boolean;
- sources?: SourceLine[];
- symbolsByLine: { [line: number]: string[] };
-}
-
-export class SourceViewerClass extends React.PureComponent<Props, State> {
- mounted = false;
-
- static defaultProps = {
- displayAllIssues: false,
- displayIssueLocationsCount: true,
- displayIssueLocationsLink: true,
- displayLocationMarkers: true,
- };
-
- constructor(props: Props) {
- super(props);
-
- this.state = {
- duplicationsByLine: {},
- hasSourcesAfter: false,
- highlightedSymbols: [],
- issuesByLine: {},
- issueLocationsByLine: {},
- loading: true,
- loadingSourcesAfter: false,
- loadingSourcesBefore: false,
- notAccessible: false,
- notExist: false,
- openIssuesByLine: {},
- selectedIssue: props.selectedIssue,
- sourceRemoved: false,
- symbolsByLine: {},
- };
- }
-
- componentDidMount() {
- this.mounted = true;
- this.fetchComponent();
- }
-
- async componentDidUpdate(prevProps: Props) {
- if (
- this.props.onIssueSelect !== undefined &&
- this.props.selectedIssue !== prevProps.selectedIssue
- ) {
- this.setState({ selectedIssue: this.props.selectedIssue });
- }
-
- if (
- prevProps.component !== this.props.component ||
- !isSameBranchLike(prevProps.branchLike, this.props.branchLike)
- ) {
- this.fetchComponent();
- } else if (
- this.props.aroundLine !== undefined &&
- prevProps.aroundLine !== this.props.aroundLine &&
- this.isLineOutsideOfRange(this.props.aroundLine)
- ) {
- const sources = await this.fetchSources().catch(() => []);
-
- if (this.mounted) {
- const finalSources = sources.slice(0, LINES_TO_LOAD);
-
- this.setState(
- {
- sources: sources.slice(0, LINES_TO_LOAD),
- hasSourcesAfter: sources.length > LINES_TO_LOAD,
- },
- () => {
- if (this.props.onLoaded && this.state.component && this.state.issues) {
- this.props.onLoaded(this.state.component, finalSources, this.state.issues);
- }
- },
- );
- }
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- loadComponent(component: string, branchLike?: BranchLike) {
- return Promise.all([
- getComponentForSourceViewer({ component, ...getBranchLikeQuery(branchLike) }),
- getComponentData({ component, ...getBranchLikeQuery(branchLike) }),
- ]).then(([sourceViewerComponent, { component }]) => ({
- ...sourceViewerComponent,
- leakPeriodDate: component.leakPeriodDate,
- }));
- }
-
- loadSources(
- key: string,
- from: number | undefined,
- to: number | undefined,
- branchLike: BranchLike | undefined,
- ) {
- return getSources({ key, from, to, ...getBranchLikeQuery(branchLike) });
- }
-
- computeCoverageStatus(lines: SourceLine[]) {
- return lines.map((line) => ({ ...line, coverageStatus: getCoverageStatus(line) }));
- }
-
- isLineOutsideOfRange(lineNumber: number) {
- const { sources } = this.state;
-
- if (sources && sources.length > 0) {
- const firstLine = sources[0];
- const lastList = sources[sources.length - 1];
- return lineNumber < firstLine.line || lineNumber > lastList.line;
- }
-
- return true;
- }
-
- fetchComponent() {
- this.setState({ loading: true });
-
- const loadIssuesCallback = (component: SourceViewerFile, sources: SourceLine[]) => {
- loadIssues(this.props.component, this.props.branchLike, this.props.needIssueSync).then(
- (issues) => {
- if (this.mounted) {
- const finalSources = sources.slice(0, LINES_TO_LOAD);
-
- this.setState(
- {
- component,
- duplicatedFiles: undefined,
- duplications: undefined,
- duplicationsByLine: {},
- hasSourcesAfter: sources.length > LINES_TO_LOAD,
- highlightedSymbols: [],
- issueLocationsByLine: locationsByLine(issues),
- issuePopup: undefined,
- issues,
- issuesByLine: issuesByLine(issues),
- loading: false,
- notAccessible: false,
- notExist: false,
- openIssuesByLine: {},
- sourceRemoved: false,
- sources: this.computeCoverageStatus(finalSources),
- symbolsByLine: symbolsByLine(sources.slice(0, LINES_TO_LOAD)),
- },
- () => {
- if (this.props.onLoaded) {
- this.props.onLoaded(component, finalSources, issues);
- }
- },
- );
- }
- },
- () => {
- /* no op */
- },
- );
- };
-
- const onFailLoadComponent = (response: Response) => {
- if (this.mounted) {
- if (response.status === HttpStatus.Forbidden) {
- this.setState({ loading: false, notAccessible: true });
- } else if (response.status === HttpStatus.NotFound) {
- this.setState({ loading: false, notExist: true });
- }
- }
- };
-
- const onFailLoadSources = (response: Response, component: SourceViewerFile) => {
- if (this.mounted) {
- if (response.status === HttpStatus.Forbidden) {
- this.setState({ component, loading: false, notAccessible: true });
- } else if (response.status === HttpStatus.NotFound) {
- this.setState({ component, loading: false, sourceRemoved: true });
- }
- }
- };
-
- const onResolve = (component: SourceViewerFile) => {
- const sourcesRequest =
- component.q === ComponentQualifier.File || component.q === ComponentQualifier.TestFile
- ? this.fetchSources()
- : Promise.resolve([]);
-
- sourcesRequest.then(
- (sources) => loadIssuesCallback(component, sources),
- (response) => onFailLoadSources(response, component),
- );
- };
-
- this.loadComponent(this.props.component, this.props.branchLike).then(
- onResolve,
- onFailLoadComponent,
- );
- }
-
- fetchSources = (): Promise<SourceLine[]> => {
- return new Promise((resolve, reject) => {
- const onFailLoadSources = (response: Response) => {
- if (this.mounted) {
- if ([HttpStatus.Forbidden, HttpStatus.NotFound].includes(response.status)) {
- reject(response);
- } else {
- resolve([]);
- }
- }
- };
-
- const from = this.props.aroundLine
- ? Math.max(1, this.props.aroundLine - LINES_TO_LOAD / 2 + 1)
- : 1;
-
- let to = this.props.aroundLine
- ? this.props.aroundLine + LINES_TO_LOAD / 2 + 1
- : LINES_TO_LOAD + 1;
-
- // make sure we try to download `LINES` lines
- if (from === 1 && to < LINES_TO_LOAD) {
- to = LINES_TO_LOAD;
- }
-
- // request one additional line to define `hasSourcesAfter`
- to++;
-
- this.loadSources(this.props.component, from, to, this.props.branchLike).then((sources) => {
- resolve(sources);
- }, onFailLoadSources);
- });
- };
-
- loadSourcesBefore = () => {
- if (!this.state.sources) {
- return;
- }
-
- const firstSourceLine = this.state.sources[0];
-
- this.setState({ loadingSourcesBefore: true });
-
- const from = Math.max(1, firstSourceLine.line - LINES_TO_LOAD);
-
- this.loadSources(
- this.props.component,
- from,
- firstSourceLine.line - 1,
- this.props.branchLike,
- ).then(
- (sources) => {
- if (this.mounted) {
- this.setState((prevState) => {
- return {
- loadingSourcesBefore: false,
- sources: [...this.computeCoverageStatus(sources), ...(prevState.sources || [])],
- symbolsByLine: { ...prevState.symbolsByLine, ...symbolsByLine(sources) },
- };
- });
- }
- },
- () => {
- /* no op */
- },
- );
- };
-
- loadSourcesAfter = () => {
- if (!this.state.sources) {
- return;
- }
-
- const lastSourceLine = this.state.sources[this.state.sources.length - 1];
-
- this.setState({ loadingSourcesAfter: true });
-
- const fromLine = lastSourceLine.line + 1;
- const toLine = lastSourceLine.line + LINES_TO_LOAD + 1;
-
- this.loadSources(this.props.component, fromLine, toLine, this.props.branchLike).then(
- (sources) => {
- if (this.mounted) {
- const hasSourcesAfter = LINES_TO_LOAD < sources.length;
-
- if (hasSourcesAfter) {
- sources.pop();
- }
-
- this.setState((prevState) => {
- return {
- hasSourcesAfter,
- loadingSourcesAfter: false,
- sources: [...(prevState.sources || []), ...this.computeCoverageStatus(sources)],
- symbolsByLine: {
- ...prevState.symbolsByLine,
- ...symbolsByLine(sources),
- },
- };
- });
- }
- },
- () => {
- /* no op */
- },
- );
- };
-
- loadDuplications = () => {
- getDuplications({
- key: this.props.component,
- ...getBranchLikeQuery(this.props.branchLike),
- }).then(
- (r) => {
- if (this.mounted) {
- this.setState({
- duplications: r.duplications,
- duplicationsByLine: duplicationsByLine(r.duplications),
- duplicatedFiles: r.files,
- });
- }
- },
- () => {
- /* no op */
- },
- );
- };
-
- handleIssuePopupToggle = (issue: string, popupName: string, open?: boolean) => {
- this.setState((state: State) => {
- const samePopup =
- state.issuePopup && state.issuePopup.name === popupName && state.issuePopup.issue === issue;
-
- if (open !== false && !samePopup) {
- return { issuePopup: { issue, name: popupName } };
- } else if (open !== true && samePopup) {
- return { issuePopup: undefined };
- }
-
- return null;
- });
- };
-
- handleSymbolClick = (symbols: string[]) => {
- this.setState((state) => {
- const shouldDisable = intersection(state.highlightedSymbols, symbols).length > 0;
- const highlightedSymbols = shouldDisable ? [] : symbols;
-
- return { highlightedSymbols };
- });
- };
-
- handleIssueSelect = (issue: string) => {
- if (this.props.onIssueSelect) {
- this.props.onIssueSelect(issue);
- } else {
- this.setState({ selectedIssue: issue });
- }
- };
-
- handleIssueUnselect = () => {
- if (this.props.onIssueUnselect) {
- this.props.onIssueUnselect();
- } else {
- this.setState({ selectedIssue: undefined });
- }
- };
-
- handleOpenIssues = (line: SourceLine) => {
- this.setState((state) => ({
- openIssuesByLine: { ...state.openIssuesByLine, [line.line]: true },
- }));
- };
-
- handleCloseIssues = (line: SourceLine) => {
- this.setState((state) => ({
- openIssuesByLine: { ...state.openIssuesByLine, [line.line]: false },
- }));
- };
-
- handleIssueChange = (issue: Issue) => {
- this.setState(({ issues = [] }) => {
- const newIssues = issues.map((candidate) =>
- candidate.key === issue.key ? issue : candidate,
- );
-
- return { issues: newIssues, issuesByLine: issuesByLine(newIssues) };
- });
- };
-
- renderDuplicationPopup = (index: number, line: number) => {
- const { component, duplicatedFiles, duplications } = this.state;
-
- if (!component || !duplicatedFiles) {
- return null;
- }
-
- const blocks = getDuplicationBlocksForIndex(duplications, index);
-
- return (
- <WorkspaceContext.Consumer>
- {({ openComponent }) => (
- <DuplicationPopup
- blocks={filterDuplicationBlocksByLine(blocks, line)}
- branchLike={this.props.branchLike}
- duplicatedFiles={duplicatedFiles}
- duplicationHeader={translate('component_viewer.transition.duplication')}
- inRemovedComponent={isDuplicationBlockInRemovedComponent(blocks)}
- openComponent={openComponent}
- sourceViewerFile={component}
- />
- )}
- </WorkspaceContext.Consumer>
- );
- };
-
- renderCode(sources: SourceLine[]) {
- const hasSourcesBefore = sources.length > 0 && sources[0].line > 1;
-
- return (
- <SourceViewerCode
- branchLike={this.props.branchLike}
- displayAllIssues={this.props.displayAllIssues}
- displayLocationMarkers={this.props.displayLocationMarkers}
- duplications={this.state.duplications}
- duplicationsByLine={this.state.duplicationsByLine}
- hasSourcesAfter={this.state.hasSourcesAfter}
- hasSourcesBefore={hasSourcesBefore}
- highlightedLine={this.props.highlightedLine}
- highlightedLocationMessage={this.props.highlightedLocationMessage}
- highlightedLocations={this.props.highlightedLocations}
- highlightedSymbols={this.state.highlightedSymbols}
- issueLocationsByLine={this.state.issueLocationsByLine}
- issuePopup={this.state.issuePopup}
- issues={this.state.issues}
- issuesByLine={this.state.issuesByLine}
- loadDuplications={this.loadDuplications}
- loadingSourcesAfter={this.state.loadingSourcesAfter}
- loadingSourcesBefore={this.state.loadingSourcesBefore}
- loadSourcesAfter={this.loadSourcesAfter}
- loadSourcesBefore={this.loadSourcesBefore}
- metricKey={this.props.metricKey}
- onIssueChange={this.handleIssueChange}
- onIssuePopupToggle={this.handleIssuePopupToggle}
- onIssuesClose={this.handleCloseIssues}
- onIssueSelect={this.handleIssueSelect}
- onIssuesOpen={this.handleOpenIssues}
- onIssueUnselect={this.handleIssueUnselect}
- onLocationSelect={this.props.onLocationSelect}
- onSymbolClick={this.handleSymbolClick}
- openIssuesByLine={this.state.openIssuesByLine}
- renderDuplicationPopup={this.renderDuplicationPopup}
- selectedIssue={this.state.selectedIssue}
- sources={sources}
- symbolsByLine={this.state.symbolsByLine}
- />
- );
- }
-
- renderHeader(sourceViewerFile: SourceViewerFile) {
- return (
- <WorkspaceContext.Consumer>
- {({ openComponent }) => (
- <SourceViewerHeader
- branchLike={this.props.branchLike}
- componentMeasures={this.props.componentMeasures}
- hidePinOption={this.props.hidePinOption}
- openComponent={openComponent}
- showMeasures={this.props.showMeasures}
- sourceViewerFile={sourceViewerFile}
- />
- )}
- </WorkspaceContext.Consumer>
- );
- }
-
- render() {
- const { component, loading, sources, notAccessible, sourceRemoved } = this.state;
- const { hideHeader } = this.props;
-
- if (loading) {
- return null;
- }
-
- if (this.state.notExist) {
- return (
- <FlagMessage className="sw-mt-2" variant="warning">
- {translate('component_viewer.no_component')}
- </FlagMessage>
- );
- }
-
- if (notAccessible) {
- return (
- <FlagMessage className="sw-mt-2" variant="warning">
- {translate('code_viewer.no_source_code_displayed_due_to_security')}
- </FlagMessage>
- );
- }
-
- if (!component) {
- return null;
- }
-
- return (
- <SourceViewerContext.Provider value={{ branchLike: this.props.branchLike, file: component }}>
- <div className="source-viewer">
- {!hideHeader && this.renderHeader(component)}
-
- {sourceRemoved && (
- <FlagMessage className="sw-mt-4 sw-ml-4" variant="warning">
- {translate('code_viewer.no_source_code_displayed_due_to_source_removed')}
- </FlagMessage>
- )}
-
- {!sourceRemoved && sources !== undefined && this.renderCode(sources)}
- </div>
- </SourceViewerContext.Provider>
- );
- }
-}
-
-export default function SourceViewer(props: Props) {
- return (
- // we can't use withComponentContext as it would override the "component" prop
- <ComponentContext.Consumer>
- {({ component }) => <SourceViewerClass needIssueSync={component?.needIssueSync} {...props} />}
- </ComponentContext.Consumer>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx
deleted file mode 100644
index 2f6b811e1c6..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerCode.tsx
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { LightLabel, SonarCodeColorizer, Spinner } from '~design-system';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { decorateWithUnderlineFlags } from '../../helpers/code-viewer';
-import { translate } from '../../helpers/l10n';
-import { BranchLike } from '../../types/branch-like';
-import {
- Duplication,
- FlowLocation,
- Issue,
- LineMap,
- LinearIssueLocation,
- SourceLine,
-} from '../../types/types';
-import Line from './components/Line';
-import LineIssuesList from './components/LineIssuesList';
-import { getSecondaryIssueLocationsForLine } from './helpers/issueLocations';
-import { optimizeHighlightedSymbols, optimizeLocationMessage } from './helpers/lines';
-
-const EMPTY_ARRAY: unknown[] = [];
-
-const ZERO_LINE = {
- code: '',
- duplicated: false,
- isNew: false,
- line: 0,
-};
-
-interface State {
- decoratedLinesMap: LineMap;
- hoveredLine?: SourceLine;
-}
-
-interface Props {
- branchLike: BranchLike | undefined;
- displayAllIssues?: boolean;
- displayLocationMarkers?: boolean;
- duplications: Duplication[] | undefined;
- duplicationsByLine: { [line: number]: number[] };
- hasSourcesAfter: boolean;
- hasSourcesBefore: boolean;
- highlightedLine: number | undefined;
- highlightedLocationMessage: { index: number; text: string | undefined } | undefined;
- // `undefined` elements mean they are located in a different file,
- // but kept to maintain the location indexes
- highlightedLocations: (FlowLocation | undefined)[] | undefined;
- highlightedSymbols: string[];
- issueLocationsByLine: { [line: number]: LinearIssueLocation[] };
- issuePopup: { issue: string; name: string } | undefined;
- issues: Issue[] | undefined;
- issuesByLine: { [line: number]: Issue[] };
- loadDuplications: (line: SourceLine) => void;
- loadSourcesAfter: () => void;
- loadSourcesBefore: () => void;
- loadingSourcesAfter: boolean;
- loadingSourcesBefore: boolean;
- metricKey?: string;
- onIssueChange: (issue: Issue) => void;
- onIssuePopupToggle: (issue: string, popupName: string, open?: boolean) => void;
- onIssueSelect: (issueKey: string) => void;
- onIssueUnselect: () => void;
- onIssuesClose: (line: SourceLine) => void;
- onIssuesOpen: (line: SourceLine) => void;
- onLocationSelect: ((index: number) => void) | undefined;
- onSymbolClick: (symbols: string[]) => void;
- openIssuesByLine: { [line: number]: boolean };
- renderDuplicationPopup: (index: number, line: number) => React.ReactNode;
- selectedIssue: string | undefined;
- sources: SourceLine[];
- symbolsByLine: { [line: number]: string[] };
-}
-
-export default class SourceViewerCode extends React.PureComponent<Props, State> {
- firstUncoveredLineFound = false;
-
- constructor(props: Props) {
- super(props);
-
- this.state = {
- decoratedLinesMap: this.getDecoratedLinesMap(props.sources),
- hoveredLine: undefined,
- };
- }
-
- componentDidUpdate(prevProps: Props) {
- if (this.props.metricKey !== prevProps.metricKey) {
- this.firstUncoveredLineFound = false;
- }
-
- if (this.props.sources !== prevProps.sources) {
- this.setState({
- decoratedLinesMap: this.getDecoratedLinesMap(this.props.sources),
- });
- }
- }
-
- getDecoratedLinesMap = (sources: SourceLine[]) =>
- sources.reduce((map: LineMap, line: SourceLine) => {
- map[line.line] = decorateWithUnderlineFlags(line, map);
-
- return map;
- }, {});
-
- getDuplicationsForLine = (line: SourceLine): number[] => {
- return this.props.duplicationsByLine[line.line] || EMPTY_ARRAY;
- };
-
- getIssuesForLine = (line: SourceLine): Issue[] => {
- return this.props.issuesByLine[line.line] || EMPTY_ARRAY;
- };
-
- getIssueLocationsForLine = (line: SourceLine): LinearIssueLocation[] => {
- return this.props.issueLocationsByLine[line.line] || EMPTY_ARRAY;
- };
-
- onLineMouseEnter = (hoveredLineNumber: number) =>
- this.setState(({ decoratedLinesMap }) => ({
- hoveredLine: decoratedLinesMap[hoveredLineNumber],
- }));
-
- onLineMouseLeave = (leftLineNumber: number) =>
- this.setState(({ hoveredLine }) => ({
- hoveredLine: hoveredLine?.line === leftLineNumber ? undefined : hoveredLine,
- }));
-
- renderLine = ({
- displayCoverage,
- displayDuplications,
- displayIssues,
- index,
- line,
- }: {
- displayCoverage: boolean;
- displayDuplications: boolean;
- displayIssues: boolean;
- index: number;
- line: SourceLine;
- }) => {
- const { hoveredLine } = this.state;
-
- const {
- branchLike,
- displayAllIssues,
- displayLocationMarkers,
- duplications,
- highlightedLine,
- highlightedLocationMessage,
- highlightedLocations,
- highlightedSymbols,
- issueLocationsByLine,
- issuePopup,
- metricKey,
- openIssuesByLine,
- selectedIssue,
- sources,
- symbolsByLine,
- } = this.props;
-
- const secondaryIssueLocations = getSecondaryIssueLocationsForLine(line, highlightedLocations);
-
- const duplicationsCount = duplications?.length ?? 0;
-
- const issuesForLine = this.getIssuesForLine(line);
-
- const firstLineNumber = sources?.length ? sources[0].line : 0;
-
- let scrollToUncoveredLine = false;
-
- if (
- !this.firstUncoveredLineFound &&
- displayCoverage &&
- line.coverageStatus &&
- ['uncovered', 'partially-covered'].includes(line.coverageStatus)
- ) {
- scrollToUncoveredLine =
- (metricKey === MetricKey.new_uncovered_lines && line.isNew) ||
- metricKey === MetricKey.uncovered_lines;
-
- this.firstUncoveredLineFound = scrollToUncoveredLine;
- }
-
- const displayCoverageUnderline = !!(
- hoveredLine?.coverageBlock && hoveredLine.coverageBlock === line.coverageBlock
- );
-
- return (
- <Line
- displayAllIssues={displayAllIssues}
- displayCoverage={displayCoverage}
- displayCoverageUnderline={displayCoverageUnderline}
- displayDuplications={displayDuplications}
- displayIssues={displayIssues}
- displayLocationMarkers={displayLocationMarkers}
- displayNewCodeUnderline={hoveredLine?.newCodeBlock === line.line}
- displaySCM={sources.length > 0}
- duplications={this.getDuplicationsForLine(line)}
- duplicationsCount={duplicationsCount}
- firstLineNumber={firstLineNumber}
- highlighted={line.line === highlightedLine}
- highlightedLocationMessage={optimizeLocationMessage(
- highlightedLocationMessage,
- secondaryIssueLocations,
- )}
- highlightedSymbols={optimizeHighlightedSymbols(
- symbolsByLine[line.line],
- highlightedSymbols,
- )}
- issueLocations={this.getIssueLocationsForLine(line)}
- issues={issuesForLine}
- key={line.line || line.code}
- line={line}
- loadDuplications={this.props.loadDuplications}
- onIssuesClose={this.props.onIssuesClose}
- onIssueSelect={this.props.onIssueSelect}
- onIssuesOpen={this.props.onIssuesOpen}
- onIssueUnselect={this.props.onIssueUnselect}
- onLineMouseEnter={this.onLineMouseEnter}
- onLineMouseLeave={this.onLineMouseLeave}
- onLocationSelect={this.props.onLocationSelect}
- onSymbolClick={this.props.onSymbolClick}
- openIssues={openIssuesByLine[line.line] || false}
- previousLine={index > 0 ? sources[index - 1] : undefined}
- renderDuplicationPopup={this.props.renderDuplicationPopup}
- scrollToUncoveredLine={scrollToUncoveredLine}
- secondaryIssueLocations={secondaryIssueLocations}
- >
- <LineIssuesList
- branchLike={branchLike}
- displayAllIssues={displayAllIssues}
- displayWhyIsThisAnIssue
- issueLocationsByLine={issueLocationsByLine}
- issuePopup={issuePopup}
- issuesForLine={issuesForLine}
- line={line}
- onIssueChange={this.props.onIssueChange}
- onIssueClick={this.props.onIssueSelect}
- onIssuePopupToggle={this.props.onIssuePopupToggle}
- openIssuesByLine={openIssuesByLine}
- selectedIssue={selectedIssue}
- />
- </Line>
- );
- };
-
- render() {
- const { decoratedLinesMap } = this.state;
-
- const {
- hasSourcesAfter,
- hasSourcesBefore,
- issues = [],
- loadingSourcesAfter,
- loadingSourcesBefore,
- sources,
- } = this.props;
-
- const displayCoverage = sources.some((s) => s.coverageStatus != null);
- const displayDuplications = sources.some((s) => !!s.duplicated);
- const displayIssues = issues.length > 0;
-
- const hasFileIssues = displayIssues && issues.some((issue) => !issue.textRange);
-
- return (
- <SonarCodeColorizer>
- <div className="it__source-viewer-code">
- {hasSourcesBefore && (
- <div className="sw-flex sw-justify-center sw-p-6">
- {loadingSourcesBefore ? (
- <div className="sw-flex sw-items-center">
- <Spinner loading />
- <LightLabel className="sw-ml-2">
- {translate('source_viewer.loading_more_code')}
- </LightLabel>
- </div>
- ) : (
- <Button onClick={this.props.loadSourcesBefore}>
- {translate('source_viewer.load_more_code')}
- </Button>
- )}
- </div>
- )}
-
- <table className="source-table">
- <tbody>
- {hasFileIssues &&
- this.renderLine({
- displayCoverage,
- displayDuplications,
- displayIssues,
- index: -1,
- line: ZERO_LINE,
- })}
- {sources.map((line, index) =>
- this.renderLine({
- displayCoverage,
- displayDuplications,
- displayIssues,
- index,
- line: decoratedLinesMap[line.line] || line,
- }),
- )}
- </tbody>
- </table>
-
- {hasSourcesAfter && (
- <div className="sw-flex sw-justify-center sw-p-6">
- {loadingSourcesAfter ? (
- <div className="sw-flex sw-items-center">
- <Spinner loading />
- <LightLabel className="sw-ml-2">
- {translate('source_viewer.loading_more_code')}
- </LightLabel>
- </div>
- ) : (
- <Button onClick={this.props.loadSourcesAfter}>
- {translate('source_viewer.load_more_code')}
- </Button>
- )}
- </div>
- )}
- </div>
- </SonarCodeColorizer>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerContext.tsx b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerContext.tsx
deleted file mode 100644
index febd1acd17c..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerContext.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { BranchLike } from '../../types/branch-like';
-import { SourceViewerFile } from '../../types/types';
-
-interface SourceViewerContextShape {
- branchLike?: BranchLike;
- file: SourceViewerFile;
-}
-
-export const SourceViewerContext = React.createContext<SourceViewerContextShape>({
- branchLike: {} as BranchLike,
- file: {} as SourceViewerFile,
-});
-
-export function useSourceViewerContext() {
- return React.useContext(SourceViewerContext);
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.tsx b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.tsx
deleted file mode 100644
index a6214f5e3cd..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.tsx
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { LinkStandalone } from '@sonarsource/echoes-react';
-import { useIntl } from 'react-intl';
-import {
- ClipboardIconButton,
- DrilldownLink,
- Dropdown,
- InteractiveIcon,
- ItemButton,
- ItemLink,
- MenuIcon,
- Note,
- PopupPlacement,
- PopupZLevel,
- ProjectIcon,
- QualifierIcon,
- themeBorder,
- themeColor,
-} from '~design-system';
-import { getBranchLikeQuery } from '~sonar-aligned/helpers/branch-like';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import {
- getComponentIssuesUrl,
- getComponentSecurityHotspotsUrl,
-} from '~sonar-aligned/helpers/urls';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import { SOFTWARE_QUALITIES } from '../../helpers/constants';
-import {
- ISSUETYPE_METRIC_KEYS_MAP,
- SOFTWARE_QUALITIES_METRIC_KEYS_MAP,
- getIssueTypeBySoftwareQuality,
-} from '../../helpers/issues';
-import { areCCTMeasuresComputed as areCCTMeasuresComputedFn } from '../../helpers/measures';
-import { collapsedDirFromPath, fileFromPath } from '../../helpers/path';
-import { omitNil } from '../../helpers/request';
-import { getBaseUrl } from '../../helpers/system';
-import { isDefined } from '../../helpers/types';
-import { getBranchLikeUrl, getCodeUrl } from '../../helpers/urls';
-import { useStandardExperienceModeQuery } from '../../queries/mode';
-import type { BranchLike } from '../../types/branch-like';
-import { IssueType } from '../../types/issues';
-import type { Measure, SourceViewerFile } from '../../types/types';
-import { DEFAULT_ISSUES_QUERY } from '../shared/utils';
-import type { WorkspaceContextShape } from '../workspace/context';
-
-interface Props {
- branchLike: BranchLike | undefined;
- componentMeasures?: Measure[];
- hidePinOption?: boolean;
- openComponent: WorkspaceContextShape['openComponent'];
- showMeasures?: boolean;
- sourceViewerFile: SourceViewerFile;
-}
-
-export default function SourceViewerHeader(props: Readonly<Props>) {
- const intl = useIntl();
- const { data: isStandardMode = false } = useStandardExperienceModeQuery();
-
- const { showMeasures, branchLike, hidePinOption, openComponent, componentMeasures } = props;
- const { key, measures, path, project, projectName, q } = props.sourceViewerFile;
- const unitTestsOrLines = q === ComponentQualifier.TestFile ? MetricKey.tests : MetricKey.lines;
-
- const query = new URLSearchParams(omitNil({ key, ...getBranchLikeQuery(branchLike) })).toString();
-
- const rawSourcesLink = `${getBaseUrl()}/api/sources/raw?${query}`;
-
- const renderIssueMeasures = () => {
- const areCCTMeasuresComputed = !isStandardMode && areCCTMeasuresComputedFn(componentMeasures);
-
- return (
- componentMeasures &&
- componentMeasures.length > 0 && (
- <>
- <StyledVerticalSeparator className="sw-h-8 sw-mx-6" />
-
- <div className="sw-flex sw-gap-6">
- {SOFTWARE_QUALITIES.map((quality) => {
- const { deprecatedMetric, metric } = SOFTWARE_QUALITIES_METRIC_KEYS_MAP[quality];
- const measure = componentMeasures.find(
- (m) => m.metric === (areCCTMeasuresComputed ? metric : deprecatedMetric),
- );
- const measureValue = measure?.value ?? 0;
-
- const linkUrl = getComponentIssuesUrl(project, {
- ...getBranchLikeQuery(branchLike),
- files: path,
- ...DEFAULT_ISSUES_QUERY,
- ...(areCCTMeasuresComputed
- ? { impactSoftwareQualities: quality }
- : { types: getIssueTypeBySoftwareQuality(quality) }),
- });
-
- const qualityTitle = intl.formatMessage({
- id: `metric.${isStandardMode ? deprecatedMetric : metric}.short_name`,
- });
-
- return (
- <div className="sw-flex sw-flex-col sw-gap-1" key={quality}>
- <Note className="it__source-viewer-header-measure-label">{qualityTitle}</Note>
-
- <span>
- <StyledDrilldownLink
- className="sw-typo-lg"
- aria-label={intl.formatMessage(
- { id: 'source_viewer.issue_link_x' },
- {
- count: formatMeasure(measureValue, MetricType.Integer),
- quality: qualityTitle,
- },
- )}
- to={linkUrl}
- >
- {formatMeasure(measureValue, MetricType.Integer)}
- </StyledDrilldownLink>
- </span>
- </div>
- );
- })}
-
- <div className="sw-flex sw-flex-col sw-gap-1" key={IssueType.SecurityHotspot}>
- <Note className="it__source-viewer-header-measure-label">
- {intl.formatMessage({ id: `issue.type.${IssueType.SecurityHotspot}` })}
- </Note>
-
- <span>
- <StyledDrilldownLink
- className="sw-typo-lg"
- to={getComponentSecurityHotspotsUrl(project, branchLike, {
- files: path,
- ...DEFAULT_ISSUES_QUERY,
- types: IssueType.SecurityHotspot,
- })}
- >
- {formatMeasure(
- componentMeasures.find(
- (m) =>
- m.metric === ISSUETYPE_METRIC_KEYS_MAP[IssueType.SecurityHotspot].metric,
- )?.value ?? 0,
- MetricType.Integer,
- )}
- </StyledDrilldownLink>
- </span>
- </div>
- </div>
- </>
- )
- );
- };
-
- return (
- <StyledHeaderContainer
- className={
- 'it__source-viewer-header sw-typo-default sw-flex sw-items-center sw-px-4 sw-py-3 ' +
- 'sw-relative'
- }
- >
- <div className="sw-flex sw-flex-1 sw-flex-col sw-gap-1 sw-mr-5 sw-my-1">
- <div className="sw-flex sw-gap-1 sw-items-center">
- <LinkStandalone
- iconLeft={<ProjectIcon className="sw-mr-2" />}
- to={getBranchLikeUrl(project, branchLike)}
- >
- {projectName}
- </LinkStandalone>
- </div>
-
- <div className="sw-flex sw-gap-2 sw-items-center">
- <QualifierIcon qualifier={q} />
-
- {collapsedDirFromPath(path)}
-
- {fileFromPath(path)}
-
- <span>
- <ClipboardIconButton
- aria-label={intl.formatMessage({ id: 'component_viewer.copy_path_to_clipboard' })}
- copyValue={path}
- />
- </span>
- </div>
- </div>
-
- {showMeasures && (
- <div className="sw-flex sw-gap-6 sw-items-center">
- {isDefined(measures[unitTestsOrLines]) && (
- <div className="sw-flex sw-flex-col sw-gap-1">
- <Note className="it__source-viewer-header-measure-label">
- {intl.formatMessage({ id: `metric.${unitTestsOrLines}.name` })}
- </Note>
-
- <span>{formatMeasure(measures[unitTestsOrLines], MetricType.ShortInteger)}</span>
- </div>
- )}
-
- {isDefined(measures.coverage) && (
- <div className="sw-flex sw-flex-col sw-gap-1">
- <Note className="it__source-viewer-header-measure-label">
- {intl.formatMessage({ id: 'metric.coverage.name' })}
- </Note>
-
- <span>{formatMeasure(measures.coverage, MetricType.Percent)}</span>
- </div>
- )}
-
- {isDefined(measures.duplicationDensity) && (
- <div className="sw-flex sw-flex-col sw-gap-1">
- <Note className="it__source-viewer-header-measure-label">
- {intl.formatMessage({ id: 'duplications' })}
- </Note>
-
- <span>{formatMeasure(measures.duplicationDensity, MetricType.Percent)}</span>
- </div>
- )}
-
- {renderIssueMeasures()}
- </div>
- )}
-
- <Dropdown
- id="source-viewer-header-actions"
- overlay={
- <>
- <ItemLink isExternal to={getCodeUrl(project, branchLike, key)}>
- {intl.formatMessage({ id: 'component_viewer.new_window' })}
- </ItemLink>
-
- {!hidePinOption && (
- <ItemButton
- className="it__js-workspace"
- onClick={() => {
- openComponent({ branchLike, key });
- }}
- >
- {intl.formatMessage({ id: 'component_viewer.open_in_workspace' })}
- </ItemButton>
- )}
-
- <ItemLink isExternal to={rawSourcesLink}>
- {intl.formatMessage({ id: 'component_viewer.show_raw_source' })}
- </ItemLink>
- </>
- }
- placement={PopupPlacement.BottomRight}
- zLevel={PopupZLevel.Global}
- >
- <InteractiveIcon
- aria-label={intl.formatMessage({ id: 'component_viewer.action_menu' })}
- className="it__js-actions sw-flex-0 sw-ml-4 sw-px-3 sw-py-2"
- Icon={MenuIcon}
- />
- </Dropdown>
- </StyledHeaderContainer>
- );
-}
-
-const StyledDrilldownLink = styled(DrilldownLink)`
- color: ${themeColor('linkDefault')};
-
- &:visited {
- color: ${themeColor('linkDefault')};
- }
-
- &:active,
- &:focus,
- &:hover {
- color: ${themeColor('linkActive')};
- }
-`;
-
-const StyledHeaderContainer = styled.div`
- background-color: ${themeColor('backgroundSecondary')};
- border-bottom: ${themeBorder('default', 'codeLineBorder')};
-`;
-
-const StyledVerticalSeparator = styled.div`
- border-right: ${themeBorder('default', 'codeLineBorder')};
-`;
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerPreview.tsx b/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerPreview.tsx
deleted file mode 100644
index 02955f3871d..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/SourceViewerPreview.tsx
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ICell, INotebookContent, isCode, isMarkdown } from '@jupyterlab/nbformat';
-import { Spinner } from '@sonarsource/echoes-react';
-import {
- Card,
- FlagMessage,
- hljsIssueIndicatorPlugin,
- hljsUnderlinePlugin,
- UnderlineRangePosition,
-} from '~design-system';
-
-import React, { forwardRef, useEffect, useMemo, useRef, useState } from 'react';
-import { createPortal } from 'react-dom';
-import { To } from 'react-router-dom';
-import { useLocation, useRouter } from '~sonar-aligned/components/hoc/withRouter';
-import {
- JupyterCodeCell,
- JupyterMarkdownCell,
-} from '~sonar-aligned/components/SourceViewer/JupyterNotebookViewer';
-import { getBranchLikeQuery } from '~sonar-aligned/helpers/branch-like';
-import { getOffsetsForIssue } from '~sonar-aligned/helpers/json-issue-mapper';
-import { getComponentIssuesUrl } from '~sonar-aligned/helpers/urls';
-import { ComponentContext } from '../../app/components/componentContext/ComponentContext';
-import { parseQuery, serializeQuery } from '../../apps/issues/utils';
-import { translate } from '../../helpers/l10n';
-import { getIssuesUrl } from '../../helpers/urls';
-import { useRawSourceQuery } from '../../queries/sources';
-import { BranchLike } from '../../types/branch-like';
-import { Component, Issue } from '../../types/types';
-import LineIssuesIndicator from './components/LineIssuesIndicator';
-import loadIssues from './helpers/loadIssues';
-
-export interface Props {
- branchLike: BranchLike | undefined;
- component: string;
-}
-
-type IssuesByCell = { [key: number]: IssuesByLine };
-type IssueByLine = {
- end: UnderlineRangePosition;
- issue: Issue;
- start: UnderlineRangePosition;
-};
-type IssuesByLine = {
- [line: number]: IssueByLine[];
-};
-type IssueKeysByLine = { [line: number]: string[] };
-type IssueIndicatorsProps = {
- branchLike: BranchLike;
- component: Component;
- issuesByCell: IssuesByCell;
- jupyterRef: React.RefObject<HTMLDivElement>;
-};
-type IssueMapper = {
- issueUrl: To;
- key: string;
- lineIndex: number;
- onlyIssues: Issue[];
-};
-
-export default function SourceViewerPreview(props: Readonly<Props>) {
- const { component, branchLike } = props;
- const [issues, setIssues] = useState<Issue[]>([]);
- const [issuesByCell, setIssuesByCell] = useState<IssuesByCell>({});
- const jupyterNotebookRef = useRef<HTMLDivElement>(null);
-
- const { data, isLoading } = useRawSourceQuery({
- key: component,
- ...getBranchLikeQuery(branchLike),
- });
- const { component: componentContext } = React.useContext(ComponentContext);
-
- const jupyterNotebook = useMemo(() => {
- if (typeof data !== 'string') {
- return null;
- }
- try {
- return JSON.parse(data) as INotebookContent;
- } catch (error) {
- return null;
- }
- }, [data]);
-
- useEffect(() => {
- const fetchData = async () => {
- const issues = await loadIssues(component, branchLike);
- setIssues(issues);
- };
-
- fetchData();
- }, [component, branchLike]);
-
- useEffect(() => {
- processIssuesByCell(issues, data, setIssuesByCell);
- }, [issues, data]);
-
- if (isLoading) {
- return <Spinner isLoading={isLoading} />;
- }
-
- if (typeof data !== 'string') {
- return (
- <FlagMessage className="sw-mt-2" variant="warning">
- {translate('component_viewer.no_component')}
- </FlagMessage>
- );
- }
-
- if (!jupyterNotebook?.cells) {
- return (
- <FlagMessage className="sw-mt-2" variant="warning">
- {translate('source_viewer.jupyter.preview.error')}
- </FlagMessage>
- );
- }
-
- return (
- <Card>
- <JupyterNotebookSourceViewer
- cells={jupyterNotebook.cells}
- issuesByCell={issuesByCell}
- ref={jupyterNotebookRef}
- />
- {issues && componentContext && branchLike && (
- <IssueIndicators
- issuesByCell={issuesByCell}
- component={componentContext}
- branchLike={branchLike}
- jupyterRef={jupyterNotebookRef}
- />
- )}
- </Card>
- );
-}
-
-type JupyterNotebookProps = {
- cells: ICell[];
- issuesByCell: IssuesByCell;
-};
-
-function mapIssuesToIssueKeys(issuesByLine: IssuesByLine): IssueKeysByLine {
- return Object.entries(issuesByLine).reduce((acc, [line, issues]) => {
- acc[Number(line)] = issues.map(({ issue }) => issue.key);
- return acc;
- }, {} as IssueKeysByLine);
-}
-
-const JupyterNotebookSourceViewer = forwardRef<HTMLDivElement, JupyterNotebookProps>(
- ({ cells, issuesByCell }, ref) => {
- const buildCellsBlocks = useMemo(() => {
- return cells.map((cell: ICell, index: number) => {
- let sourceLines = Array.isArray(cell.source) ? cell.source : [cell.source];
- const issuesByLine = issuesByCell[index];
- if (!issuesByLine) {
- return {
- cell,
- sourceLines,
- };
- }
- const issues = mapIssuesToIssueKeys(issuesByLine);
- const flatIssues = Object.entries(issuesByLine).flatMap(([, issues]) => issues);
-
- sourceLines = hljsUnderlinePlugin.tokenize(sourceLines, flatIssues);
- sourceLines = hljsIssueIndicatorPlugin.addIssuesToLines(sourceLines, issues);
-
- return {
- cell,
- sourceLines,
- };
- });
- }, [cells, issuesByCell]);
-
- return (
- <div ref={ref}>
- {buildCellsBlocks.map((element, index) => {
- const { cell, sourceLines } = element;
- if (isCode(cell)) {
- return (
- <JupyterCodeCell
- source={sourceLines}
- outputs={cell.outputs}
- key={`${cell.cell_type}-${index}`}
- />
- );
- } else if (isMarkdown(cell)) {
- return <JupyterMarkdownCell cell={cell} key={`${cell.cell_type}-${index}`} />;
- }
- return null;
- })}
- </div>
- );
- },
-);
-
-JupyterNotebookSourceViewer.displayName = 'JupyterNotebookSourceViewer';
-
-function IssueIndicators({
- issuesByCell,
- component,
- branchLike,
- jupyterRef,
-}: Readonly<IssueIndicatorsProps>) {
- const location = useLocation();
- const query = parseQuery(location.query);
- const onlyIssuesMap = (issues: IssueByLine[]) => issues.map(({ issue }) => issue);
- const mappedIssues = useMemo(() => {
- return Object.entries(issuesByCell).flatMap(([, issuesByLine]) =>
- Object.entries(issuesByLine).map(([, issues]) => {
- const firstIssue = issues[0].issue;
- const onlyIssues = onlyIssuesMap(issues);
- const urlQuery = {
- ...getBranchLikeQuery(branchLike),
- ...serializeQuery(query),
- open: firstIssue.key,
- };
- const issueUrl = component?.key
- ? getComponentIssuesUrl(component?.key, urlQuery)
- : getIssuesUrl(urlQuery);
- return { key: firstIssue.key, issueUrl, onlyIssues, lineIndex: issues[0].start.line };
- }),
- );
- // we only need to recompute this with new issues
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [issuesByCell]);
-
- return mappedIssues.map((mappedIssues) => (
- <PortalLineIssuesIndicator
- key={mappedIssues.key}
- issueMapper={mappedIssues}
- jupyterRef={jupyterRef}
- />
- ));
-}
-
-/*
-Creates a react portal bound to an element id `issue-key-${key}` that represents the first issue
-present on a virtual line of code. The element id is generated from executing the
-HljsIssueIndicatorPlugin.addIssuesToLines function on the source code of a Jupyter notebook cell.
-*/
-function PortalLineIssuesIndicator(props: {
- issueMapper: IssueMapper;
- jupyterRef: React.RefObject<HTMLDivElement>;
-}) {
- const { jupyterRef, issueMapper } = props;
- const router = useRouter();
-
- // We use this state to force-re-render the component when the jupyterRef changes
- // eslint-disable-next-line react/hook-use-state
- const [, setMutationCount] = useState(0);
-
- useEffect(() => {
- if (!jupyterRef.current) {
- return;
- }
- setMutationCount((count) => count + 1);
- }, [jupyterRef]);
-
- const { key, lineIndex, onlyIssues, issueUrl } = issueMapper;
- const element = document.getElementById(`issue-key-${key}`);
-
- if (!element) {
- return null;
- }
-
- return createPortal(
- <LineIssuesIndicator
- issues={onlyIssues}
- onClick={() => router.navigate(issueUrl)}
- line={{ line: Number(lineIndex) }}
- as="span"
- />,
- element,
- );
-}
-
-/**
- * Processes issues and maps them to their corresponding cells and lines in a Jupyter notebook.
- * This function updates the state with a new mapping of issues by cell.
- *
- * @param {Array} issues - The list of issues to process.
- * @param {string} data - The JSON data representing the notebook.
- * @param {Function} setIssuesByCell - Function to update the state with the new issues mapping.
- */
-function processIssuesByCell(
- issues: Issue[],
- data: string | null | undefined,
- setIssuesByCell: Function,
-) {
- const newIssuesByCell: IssuesByCell = {};
-
- issues.forEach((issue) => {
- if (typeof data !== 'string') {
- return;
- }
-
- const { startOffset, endOffset } = getOffsetsForIssue(issue, data);
-
- // failed to parse the issue offsets, skip the issue
- if (!startOffset || !endOffset) {
- return;
- }
-
- const { cell } = startOffset;
-
- if (!newIssuesByCell[cell]) {
- newIssuesByCell[cell] = {};
- }
-
- if (!newIssuesByCell[cell][startOffset.line]) {
- newIssuesByCell[cell][startOffset.line] = [{ issue, start: startOffset, end: endOffset }];
- }
-
- const existingIssues = newIssuesByCell[cell][startOffset.line];
- const issueExists = existingIssues.some(
- ({ issue: existingIssue }) => existingIssue.key === issue.key,
- );
-
- if (!issueExists) {
- newIssuesByCell[cell][startOffset.line].push({ issue, start: startOffset, end: endOffset });
- }
- });
-
- setIssuesByCell(newIssuesByCell);
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewer-it.tsx b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewer-it.tsx
deleted file mode 100644
index c599bf9089e..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewer-it.tsx
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen, within } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { byLabelText } from '~sonar-aligned/helpers/testSelector';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import ComponentsServiceMock from '../../../api/mocks/ComponentsServiceMock';
-import IssuesServiceMock from '../../../api/mocks/IssuesServiceMock';
-import { ModeServiceMock } from '../../../api/mocks/ModeServiceMock';
-import UsersServiceMock from '../../../api/mocks/UsersServiceMock';
-import { CCT_SOFTWARE_QUALITY_METRICS } from '../../../helpers/constants';
-import { isDiffMetric } from '../../../helpers/measures';
-import { HttpStatus } from '../../../helpers/request';
-import { mockIssue, mockLoggedInUser, mockMeasure } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { Mode } from '../../../types/mode';
-import { RestUserDetailed } from '../../../types/users';
-import SourceViewer, { Props } from '../SourceViewer';
-import loadIssues from '../helpers/loadIssues';
-
-jest.mock('../../../api/components');
-jest.mock('../../../api/issues');
-// The following 2 mocks are needed, because IssuesServiceMock mocks more than it should.
-// This should be removed once IssuesServiceMock is cleaned up.
-jest.mock('../../../api/rules');
-
-jest.mock('../helpers/loadIssues', () => ({
- __esModule: true,
- default: jest.fn().mockResolvedValue([]),
-}));
-
-jest.mock('../helpers/lines', () => {
- const lines = jest.requireActual('../helpers/lines');
- return {
- ...lines,
- LINES_TO_LOAD: 20,
- };
-});
-
-const componentsHandler = new ComponentsServiceMock();
-const issuesHandler = new IssuesServiceMock();
-const usersHandler = new UsersServiceMock();
-const modeHandler = new ModeServiceMock();
-const message = 'First Issue';
-
-beforeEach(() => {
- issuesHandler.reset();
- componentsHandler.reset();
- usersHandler.reset();
- modeHandler.reset();
- usersHandler.users = [mockLoggedInUser() as unknown as RestUserDetailed];
-});
-
-it('should show a permalink on line number', async () => {
- const user = userEvent.setup();
- renderSourceViewer();
- let row = await screen.findByRole('row', { name: /\/\*$/ });
- expect(row).toBeInTheDocument();
- const rowScreen = within(row);
-
- await user.click(
- rowScreen.getByRole('button', {
- name: 'source_viewer.line_X.1',
- }),
- );
-
- expect(
- rowScreen.getByRole('menuitem', { name: 'source_viewer.copy_permalink' }),
- ).toBeInTheDocument();
-
- await user.keyboard('[Escape]');
-
- expect(
- rowScreen.queryByRole('menuitem', { name: 'source_viewer.copy_permalink' }),
- ).not.toBeInTheDocument();
-
- row = await screen.findByRole('row', { name: / \* 6$/ });
- expect(row).toBeInTheDocument();
- const lowerRowScreen = within(row);
-
- await user.click(
- lowerRowScreen.getByRole('button', {
- name: 'source_viewer.line_X.6',
- }),
- );
-
- expect(
- lowerRowScreen.getByRole('menuitem', {
- name: 'source_viewer.copy_permalink',
- }),
- ).toBeInTheDocument();
-});
-
-it('should show issue on empty file', async () => {
- jest.mocked(loadIssues).mockResolvedValueOnce([
- mockIssue(false, {
- key: 'first-issue',
- message,
- line: undefined,
- textRange: undefined,
- }),
- ]);
-
- renderSourceViewer({
- component: componentsHandler.getEmptyFileKey(),
- });
-
- expect(await screen.findByRole('table')).toBeInTheDocument();
- expect(await screen.findByRole('row', { name: 'First Issue' })).toBeInTheDocument();
-});
-
-it('should be able to interact with issue action', async () => {
- jest.mocked(loadIssues).mockResolvedValueOnce([
- mockIssue(false, {
- actions: ['set_tags', 'comment', 'assign'],
- key: 'issue1',
- message,
- line: 1,
- textRange: { startLine: 1, endLine: 1, startOffset: 0, endOffset: 1 },
- }),
- ]);
-
- const user = userEvent.setup();
- renderSourceViewer();
-
- // Assign issue to a different user
- await user.click(
- await screen.findByRole('combobox', { name: 'issue.assign.unassigned_click_to_assign' }),
- );
- await user.click(screen.getByLabelText('search.search_for_users'));
- await user.keyboard('luke');
- expect(screen.getByText('Skywalker')).toBeInTheDocument();
-});
-
-it('should load line when looking around unloaded line', async () => {
- const rerender = renderSourceViewer({
- aroundLine: 50,
- component: componentsHandler.getHugeFileKey(),
- });
-
- expect(await screen.findByRole('row', { name: /Line 50$/ })).toBeInTheDocument();
- rerender({ aroundLine: 100, component: componentsHandler.getHugeFileKey() });
-
- expect(await screen.findByRole('row', { name: /Line 100$/ })).toBeInTheDocument();
-});
-
-it('should show SCM information', async () => {
- const user = userEvent.setup();
- renderSourceViewer();
- let row = await screen.findByRole('row', { name: /\/\*$/ });
- expect(row).toBeInTheDocument();
- const firstRowScreen = within(row);
-
- expect(
- firstRowScreen.getByRole('cell', { name: 'stas.vilchik@sonarsource.com' }),
- ).toBeInTheDocument();
-
- await user.click(
- firstRowScreen.getByRole('button', {
- name: 'source_viewer.author_X.stas.vilchik@sonarsource.com, source_viewer.click_for_scm_info.1',
- }),
- );
-
- // After using miui component the tooltip is appearing outside of the row
- expect(await screen.findAllByText('author')).toHaveLength(4);
- expect(screen.getAllByText('source_viewer.tooltip.scm.commited_on')).toHaveLength(3);
- expect(screen.getAllByText('source_viewer.tooltip.scm.revision')).toHaveLength(7);
-
- row = screen.getByRole('row', { name: /\* SonarQube$/ });
- expect(row).toBeInTheDocument();
- const secondRowScreen = within(row);
-
- expect(
- secondRowScreen.queryByRole('cell', { name: 'stas.vilchik@sonarsource.com' }),
- ).not.toBeInTheDocument();
-
- // SCM with no date
- row = await screen.findByRole('row', { name: /\* mailto:info AT sonarsource DOT com$/ });
- expect(row).toBeInTheDocument();
- const fourthRowScreen = within(row);
-
- await user.click(
- fourthRowScreen.getByRole('button', {
- name: 'source_viewer.author_X.stas.vilchik@sonarsource.com, source_viewer.click_for_scm_info.4',
- }),
- );
-
- // SCM with no date no author
- row = await screen.findByRole('row', { name: /\* 5$/ });
- expect(row).toBeInTheDocument();
- const fithRowScreen = within(row);
- expect(fithRowScreen.getByText('…')).toBeInTheDocument();
-
- await user.click(
- fithRowScreen.getByRole('button', {
- name: 'source_viewer.click_for_scm_info.5',
- }),
- );
-
- // No SCM Popup
- row = await screen.findByRole('row', {
- name: /\* This program is free software; you can redistribute it and\/or$/,
- });
-
- expect(row).toBeInTheDocument();
- expect(within(row).queryByRole('button')).not.toBeInTheDocument();
-});
-
-it.each([
- [Mode.MQR, ''],
- [Mode.Standard, '.legacy'],
-])('should show issue indicator in %s', async (mode, translationKey) => {
- modeHandler.setMode(mode);
- jest.mocked(loadIssues).mockResolvedValueOnce([
- mockIssue(false, {
- key: 'first-issue',
- message,
- line: 1,
- textRange: { startLine: 1, endLine: 1, startOffset: 0, endOffset: 1 },
- }),
- mockIssue(false, {
- key: 'second-issue',
- message: 'Second Issue',
- line: 1,
- textRange: { startLine: 1, endLine: 1, startOffset: 1, endOffset: 2 },
- }),
- ]);
-
- const user = userEvent.setup();
- const onIssueSelect = jest.fn();
-
- renderSourceViewer({
- onIssueSelect,
- displayAllIssues: false,
- });
-
- const row = await screen.findByRole('row', { name: /.*\/ \*$/ });
- const issueRow = within(row);
- expect(issueRow.getByText('2')).toBeInTheDocument();
-
- const issueIndicator = await issueRow.findByRole('button', {
- name: `source_viewer.issues_on_line.multiple_issues_same_category${translationKey}.true.2.issue.type.bug.plural.issue.clean_code_attribute_category.responsible`,
- });
- await user.click(issueIndicator);
-
- expect(await screen.findByRole('tooltip')).toBeInTheDocument();
-});
-
-it('should show coverage information', async () => {
- renderSourceViewer();
-
- const coverdLine = within(
- await screen.findByRole('row', { name: /\* mailto:info AT sonarsource DOT com$/ }),
- );
-
- expect(
- coverdLine.getByLabelText('source_viewer.tooltip.covered.conditions.1'),
- ).toBeInTheDocument();
-
- const partialyCoveredWithConditionLine = within(
- await screen.findByRole('row', { name: / \* 5$/ }),
- );
-
- expect(
- partialyCoveredWithConditionLine.getByLabelText(
- 'source_viewer.tooltip.partially-covered.conditions.1.2',
- ),
- ).toBeInTheDocument();
-
- const partialyCoveredLine = within(await screen.findByRole('row', { name: /\/\*$/ }));
-
- expect(
- partialyCoveredLine.getByLabelText('source_viewer.tooltip.partially-covered'),
- ).toBeInTheDocument();
-
- const uncoveredLine = within(await screen.findByRole('row', { name: / \* 6$/ }));
- expect(uncoveredLine.getByLabelText('source_viewer.tooltip.uncovered')).toBeInTheDocument();
-
- const uncoveredWithConditionLine = within(
- await screen.findByRole('row', { name: / \* SonarQube$/ }),
- );
-
- expect(
- uncoveredWithConditionLine.getByLabelText('source_viewer.tooltip.uncovered.conditions.1'),
- ).toBeInTheDocument();
-
- const coveredWithNoCondition = within(await screen.findByRole('row', { name: /\* Copyright$/ }));
-
- expect(
- coveredWithNoCondition.getByLabelText('source_viewer.tooltip.covered'),
- ).toBeInTheDocument();
-});
-
-it('should show duplication block', async () => {
- const user = userEvent.setup();
- renderSourceViewer();
- const duplicateLine = within(await screen.findByRole('row', { name: /\* 7$/ }));
-
- expect(
- duplicateLine.getByLabelText('source_viewer.tooltip.duplicated_block'),
- ).toBeInTheDocument();
-
- await user.click(
- duplicateLine.getByRole('button', { name: 'source_viewer.tooltip.duplicated_block' }),
- );
-
- expect(screen.getByRole('tooltip')).toBeVisible();
-
- await user.click(document.body);
-
- expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
-});
-
-it('should highlight symbol', async () => {
- const user = userEvent.setup();
- renderSourceViewer({ component: 'foo:testSymb.tsx' });
- const symbols = await screen.findAllByText('symbole');
- await user.click(symbols[0]);
-
- // For now just check the class. Maybe find a better accessible way of showing higlighted symbols
- symbols.forEach((element) => {
- expect(element).toHaveClass('highlighted');
- });
-});
-
-it('should show software quality measures in header', async () => {
- renderSourceViewer({ componentMeasures: generateMeasures(), showMeasures: true });
-
- expect(
- await byLabelText(
- 'source_viewer.issue_link_x.3.metric.software_quality_security_issues.short_name',
- ).find(),
- ).toBeInTheDocument();
- expect(
- await byLabelText(
- 'source_viewer.issue_link_x.3.metric.software_quality_reliability_issues.short_name',
- ).find(),
- ).toBeInTheDocument();
- expect(
- await byLabelText(
- 'source_viewer.issue_link_x.3.metric.software_quality_maintainability_issues.short_name',
- ).find(),
- ).toBeInTheDocument();
-});
-
-it('should show old issue measures in header', async () => {
- renderSourceViewer({
- componentMeasures: generateMeasures().filter(
- (m) => !CCT_SOFTWARE_QUALITY_METRICS.includes(m.metric as MetricKey),
- ),
- showMeasures: true,
- });
-
- expect(
- await byLabelText(
- 'source_viewer.issue_link_x.1.metric.software_quality_security_issues.short_name',
- ).find(),
- ).toBeInTheDocument();
- expect(
- await byLabelText(
- 'source_viewer.issue_link_x.1.metric.software_quality_reliability_issues.short_name',
- ).find(),
- ).toBeInTheDocument();
- expect(
- await byLabelText(
- 'source_viewer.issue_link_x.1.metric.software_quality_maintainability_issues.short_name',
- ).find(),
- ).toBeInTheDocument();
-});
-
-it('should show correct message when component is not asscessible', async () => {
- componentsHandler.setFailLoadingComponentStatus(HttpStatus.Forbidden);
- renderSourceViewer();
-
- expect(
- await screen.findByText('code_viewer.no_source_code_displayed_due_to_security'),
- ).toBeInTheDocument();
-});
-
-it('should show correct message when component does not exist', async () => {
- componentsHandler.setFailLoadingComponentStatus(HttpStatus.NotFound);
- renderSourceViewer();
- expect(await screen.findByText('component_viewer.no_component')).toBeInTheDocument();
-});
-
-function generateMeasures(qualitiesValue = '3.0', overallValue = '1.0', newValue = '2.0') {
- return [
- ...[
- MetricKey.software_quality_security_issues,
- MetricKey.software_quality_reliability_issues,
- MetricKey.software_quality_maintainability_issues,
- ].map((metric) => mockMeasure({ metric, value: qualitiesValue, period: undefined })),
- ...[
- MetricKey.ncloc,
- MetricKey.new_lines,
- MetricKey.bugs,
- MetricKey.vulnerabilities,
- MetricKey.code_smells,
- MetricKey.security_hotspots,
- MetricKey.coverage,
- MetricKey.new_coverage,
- ].map((metric) =>
- isDiffMetric(metric)
- ? mockMeasure({ metric, period: { index: 1, value: newValue } })
- : mockMeasure({ metric, value: overallValue, period: undefined }),
- ),
- ];
-}
-
-function renderSourceViewer(override?: Partial<Props>) {
- const { rerender } = renderComponent(
- <SourceViewer
- aroundLine={1}
- branchLike={undefined}
- component={componentsHandler.getNonEmptyFileKey()}
- displayAllIssues
- displayLocationMarkers
- onIssueSelect={jest.fn()}
- onLoaded={jest.fn()}
- onLocationSelect={jest.fn()}
- {...override}
- />,
- );
-
- return function (reoverride?: Partial<Props>) {
- rerender(
- <SourceViewer
- aroundLine={1}
- branchLike={undefined}
- component={componentsHandler.getNonEmptyFileKey()}
- displayAllIssues
- displayLocationMarkers
- onIssueSelect={jest.fn()}
- onLoaded={jest.fn()}
- onLocationSelect={jest.fn()}
- {...override}
- {...reoverride}
- />,
- );
- };
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/DuplicationPopup.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/DuplicationPopup.tsx
deleted file mode 100644
index 0f0c43fc4b2..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/components/DuplicationPopup.tsx
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { groupBy, sortBy } from 'lodash';
-import React, { Fragment, PureComponent } from 'react';
-import {
- DiscreetLink,
- DuplicationHighlight,
- FlagMessage,
- StandoutLink as Link,
- QualifierIcon,
-} from '~design-system';
-import { isPullRequest } from '~sonar-aligned/helpers/branch-like';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { translate } from '../../../helpers/l10n';
-import { collapsedDirFromPath, fileFromPath } from '../../../helpers/path';
-import { getProjectUrl } from '../../../helpers/urls';
-import { BranchLike } from '../../../types/branch-like';
-import { Dict, DuplicatedFile, DuplicationBlock, SourceViewerFile } from '../../../types/types';
-import { WorkspaceContextShape } from '../../workspace/context';
-
-interface Props {
- blocks: DuplicationBlock[];
- branchLike: BranchLike | undefined;
- duplicatedFiles?: Dict<DuplicatedFile>;
- duplicationHeader: string;
- inRemovedComponent: boolean;
- openComponent: WorkspaceContextShape['openComponent'];
- sourceViewerFile: SourceViewerFile;
-}
-
-export default class DuplicationPopup extends PureComponent<Props> {
- shouldLink() {
- const { branchLike } = this.props;
- return !isPullRequest(branchLike);
- }
-
- isDifferentComponent = (a: { project: string }, b: { project: string }) => {
- return Boolean(a && b && a.project !== b.project);
- };
-
- handleFileClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
- const { key, line } = event.currentTarget.dataset;
- if (this.shouldLink() && key) {
- this.props.openComponent({
- branchLike: this.props.branchLike,
- key,
- line: line ? Number(line) : undefined,
- });
- }
- };
-
- renderDuplication(file: DuplicatedFile, children: React.ReactNode, line?: number) {
- return this.shouldLink() ? (
- <DiscreetLink
- data-key={file.key}
- data-line={line}
- onClick={this.handleFileClick}
- title={file.name}
- to={{}}
- >
- {children}
- </DiscreetLink>
- ) : (
- children
- );
- }
-
- render() {
- const {
- duplicatedFiles = {},
- sourceViewerFile,
- duplicationHeader,
- inRemovedComponent,
- } = this.props;
-
- const groupedBlocks = groupBy(this.props.blocks, '_ref');
- let duplications = Object.keys(groupedBlocks).map((fileRef) => {
- return {
- blocks: groupedBlocks[fileRef],
- file: duplicatedFiles[fileRef],
- };
- });
-
- // first duplications in the same file
- // then duplications in the same project
- // then duplications in other projects
- duplications = sortBy(
- duplications,
- (d) => d.file.projectName !== sourceViewerFile.projectName,
- (d) => d.file.key !== sourceViewerFile.key,
- );
-
- return (
- <div className="sw-w-abs-400">
- {inRemovedComponent && (
- <FlagMessage variant="warning">
- {translate('duplications.dups_found_on_deleted_resource')}
- </FlagMessage>
- )}
- {duplications.length > 0 && (
- <>
- <DuplicationHighlight>{duplicationHeader}</DuplicationHighlight>
- {duplications.map((duplication) => (
- <div className="sw-my-2" key={duplication.file.key}>
- <div className="sw-flex sw-flex-wrap sw-typo-default">
- {this.isDifferentComponent(duplication.file, this.props.sourceViewerFile) && (
- <div className="sw-mr-4">
- <QualifierIcon className="sw-mr-1" qualifier={ComponentQualifier.Project} />
- <Link
- to={getProjectUrl(duplication.file.project)}
- title={duplication.file.projectName}
- >
- {duplication.file.projectName}
- </Link>
- </div>
- )}
-
- {duplication.file.key !== this.props.sourceViewerFile.key && (
- <div className="sw-mr-2">
- {this.renderDuplication(
- duplication.file,
- <span
- title={
- (collapsedDirFromPath(duplication.file.name) ?? '') +
- (fileFromPath(duplication.file.name) ?? '')
- }
- >
- <span>{collapsedDirFromPath(duplication.file.name)}</span>
- <span>{fileFromPath(duplication.file.name)}</span>
- </span>,
- )}
- </div>
- )}
-
- <div>
- {'Lines: '}
- {duplication.blocks.map((block, index) => (
- <Fragment key={index}>
- {this.renderDuplication(
- duplication.file,
- <>
- {block.from}
- {' – '}
- {block.from + block.size - 1}
- </>,
- block.from,
- )}
- {index < duplication.blocks.length - 1 && ', '}
- </Fragment>
- ))}
- </div>
- </div>
- </div>
- ))}
- </>
- )}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/Line.css b/server/sonar-web/src/main/js/components/SourceViewer/components/Line.css
deleted file mode 100644
index b5822602448..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/components/Line.css
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-.source-viewer pre {
- line-height: 18px;
- font-family: Consolas, 'Ubuntu Mono', 'Liberation Mono', Menlo, Courier, monospace;
- font-size: 12px;
-}
-
-.source-line-code-issue {
- display: inline-block;
- background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAGCAYAAAAPDoR2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1M0M2Rjk4M0M3QUYxMUUzODkzRUREMUM5OTNDMjY4QSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1M0M2Rjk4NEM3QUYxMUUzODkzRUREMUM5OTNDMjY4QSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjUzQzZGOTgxQzdBRjExRTM4OTNFREQxQzk5M0MyNjhBIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjUzQzZGOTgyQzdBRjExRTM4OTNFREQxQzk5M0MyNjhBIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+bcqJtQAAAEhJREFUeNpi+G+swwDGDAwgbAWlwZiJAQFCgfgwEIfDRaC67ID4NRDnQ2kQnwFZwgFqnANMAQOUYY9sF0wBiCGH5CBkrAgQYACuWi4sSGW8yAAAAABJRU5ErkJggg==);
- background-repeat: repeat-x;
- background-size: 4px;
- background-position: bottom;
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx
deleted file mode 100644
index 374907bc7f4..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { times } from 'lodash';
-import * as React from 'react';
-import { LineCoverage, LineMeta, LineNumber, LineWrapper } from '~design-system';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { getCodeUrl, getPathUrlAsString } from '../../../helpers/urls';
-import { Issue, LinearIssueLocation, SourceLine } from '../../../types/types';
-import { useSourceViewerContext } from '../SourceViewerContext';
-import './Line.css';
-import { LineCode } from './LineCode';
-import LineDuplicationBlock from './LineDuplicationBlock';
-import LineIssuesIndicator from './LineIssuesIndicator';
-import LineOptionsPopup from './LineOptionsPopup';
-import LineSCM from './LineSCM';
-
-export interface LineProps {
- children?: React.ReactNode;
- displayAllIssues?: boolean;
- displayCoverage: boolean;
- displayCoverageUnderline: boolean;
- displayDuplications: boolean;
- displayIssues: boolean;
- displayLineNumberOptions?: boolean;
- displayLocationMarkers?: boolean;
- displayNewCodeUnderline: boolean;
- displaySCM?: boolean;
- duplications: number[];
- duplicationsCount: number;
- firstLineNumber: number;
- hideLocationIndex?: boolean;
- highlighted: boolean;
- highlightedLocationMessage: { index: number; text: string | undefined } | undefined;
- highlightedSymbols: string[] | undefined;
- issueLocations: LinearIssueLocation[];
- issues: Issue[];
- line: SourceLine;
- loadDuplications: (line: SourceLine) => void;
- onIssueSelect: (issueKey: string) => void;
- onIssueUnselect: () => void;
- onIssuesClose: (line: SourceLine) => void;
- onIssuesOpen: (line: SourceLine) => void;
- onLineMouseEnter: (line: number) => void;
- onLineMouseLeave: (line: number) => void;
- onLocationSelect: ((x: number) => void) | undefined;
- onSymbolClick: (symbols: string[]) => void;
- openIssues: boolean;
- previousLine: SourceLine | undefined;
- renderDuplicationPopup: (index: number, line: number) => React.ReactNode;
- scrollToUncoveredLine?: boolean;
- secondaryIssueLocations: LinearIssueLocation[];
-}
-
-export default function Line(props: LineProps) {
- const {
- children,
- displayAllIssues,
- displayCoverage,
- displayDuplications,
- displayLineNumberOptions = true,
- displayLocationMarkers,
- highlightedLocationMessage,
- displayNewCodeUnderline,
- displayIssues,
- displaySCM = true,
- duplications,
- duplicationsCount,
- firstLineNumber,
- highlighted,
- highlightedSymbols,
- issueLocations,
- issues,
- line,
- openIssues,
- previousLine,
- scrollToUncoveredLine,
- secondaryIssueLocations,
- displayCoverageUnderline,
- hideLocationIndex,
- onLineMouseEnter,
- onLineMouseLeave,
- } = props;
-
- const handleIssuesIndicatorClick = () => {
- if (props.openIssues) {
- props.onIssuesClose(props.line);
- props.onIssueUnselect();
- } else {
- props.onIssuesOpen(props.line);
-
- const { issues } = props;
- if (issues.length > 0) {
- props.onIssueSelect(issues[0].key);
- }
- }
- };
-
- const blocksLoaded = duplicationsCount > 0;
-
- const handleLineMouseEnter = React.useCallback(
- () => onLineMouseEnter(line.line),
- [line.line, onLineMouseEnter],
- );
-
- const handleLineMouseLeave = React.useCallback(
- () => onLineMouseLeave(line.line),
- [line.line, onLineMouseLeave],
- );
-
- const { branchLike, file } = useSourceViewerContext();
- const permalink = getPathUrlAsString(
- getCodeUrl(file.project, branchLike, file.key, line.line),
- false,
- );
-
- const getStatusTooltip = (line: SourceLine) => {
- switch (line.coverageStatus) {
- case 'uncovered':
- return line.conditions
- ? translateWithParameters('source_viewer.tooltip.uncovered.conditions', line.conditions)
- : translate('source_viewer.tooltip.uncovered');
- case 'covered':
- return line.conditions
- ? translateWithParameters('source_viewer.tooltip.covered.conditions', line.conditions)
- : translate('source_viewer.tooltip.covered');
- case 'partially-covered':
- return line.conditions
- ? translateWithParameters(
- 'source_viewer.tooltip.partially-covered.conditions',
- line.coveredConditions ?? 0,
- line.conditions,
- )
- : translate('source_viewer.tooltip.partially-covered');
- default:
- return undefined;
- }
- };
-
- const status = getStatusTooltip(line);
-
- return (
- <LineWrapper
- data-line-number={line.line}
- displayCoverage={displayCoverage}
- displaySCM={displaySCM}
- duplicationsCount={!duplicationsCount && displayDuplications ? 1 : duplicationsCount}
- highlighted={highlighted}
- onMouseEnter={handleLineMouseEnter}
- onMouseLeave={handleLineMouseLeave}
- className={classNames('it__source-line', { 'it__source-line-filtered': line.isNew })}
- >
- <LineNumber
- displayOptions={displayLineNumberOptions}
- firstLineNumber={firstLineNumber}
- lineNumber={line.line}
- ariaLabel={translateWithParameters('source_viewer.line_X', line.line)}
- popup={<LineOptionsPopup line={line} permalink={permalink} />}
- />
-
- {displaySCM && <LineSCM line={line} previousLine={previousLine} />}
-
- {displayIssues && !displayAllIssues ? (
- <LineIssuesIndicator
- issues={issues}
- issuesOpen={openIssues}
- line={line}
- onClick={handleIssuesIndicatorClick}
- />
- ) : (
- <LineMeta data-line-number={line.line} />
- )}
-
- {displayDuplications && (
- <LineDuplicationBlock
- blocksLoaded={blocksLoaded}
- duplicated={!blocksLoaded ? Boolean(line.duplicated) : duplications.includes(0)}
- index={0}
- key={0}
- line={line}
- onClick={props.loadDuplications}
- renderDuplicationPopup={props.renderDuplicationPopup}
- />
- )}
-
- {blocksLoaded &&
- times(duplicationsCount - 1, (index) => {
- return (
- <LineDuplicationBlock
- blocksLoaded={blocksLoaded}
- duplicated={duplications.includes(index + 1)}
- index={index + 1}
- key={index + 1}
- line={line}
- renderDuplicationPopup={props.renderDuplicationPopup}
- />
- );
- })}
-
- {displayCoverage && (
- <LineCoverage
- lineNumber={line.line}
- scrollToUncoveredLine={scrollToUncoveredLine}
- status={status}
- coverageStatus={line.coverageStatus}
- />
- )}
-
- <LineCode
- displayCoverageUnderline={displayCoverage && displayCoverageUnderline}
- displayLocationMarkers={displayLocationMarkers}
- displayNewCodeUnderlineLabel={displayNewCodeUnderline}
- hideLocationIndex={hideLocationIndex}
- highlightedLocationMessage={highlightedLocationMessage}
- highlightedSymbols={highlightedSymbols}
- issueLocations={issueLocations}
- line={line}
- onLocationSelect={props.onLocationSelect}
- onSymbolClick={props.onSymbolClick}
- previousLine={previousLine}
- secondaryIssueLocations={secondaryIssueLocations}
- >
- {children}
- </LineCode>
- </LineWrapper>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/LineCode.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/LineCode.tsx
deleted file mode 100644
index d3296b3eb74..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/components/LineCode.tsx
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React, { PureComponent, ReactNode, RefObject, createRef } from 'react';
-import {
- CoveredUnderline,
- CoveredUnderlineLabel,
- LineCodeLayer,
- LineCodeLayers,
- LineCodePreFormatted,
- LineMarker,
- LineToken,
- NewCodeUnderline,
- NewCodeUnderlineLabel,
- UncoveredUnderline,
- UncoveredUnderlineLabel,
- UnderlineLabels,
-} from '~design-system';
-import { IssueSourceViewerScrollContext } from '../../../apps/issues/components/IssueSourceViewerScrollContext';
-import { translate } from '../../../helpers/l10n';
-import { LinearIssueLocation, SourceLine } from '../../../types/types';
-import { Token, getHighlightedTokens } from '../helpers/highlight';
-
-interface Props {
- displayCoverageUnderline?: boolean;
- displayLocationMarkers?: boolean;
- displayNewCodeUnderlineLabel?: boolean;
- hideLocationIndex?: boolean;
- highlightedLocationMessage: { index: number; text: string | undefined } | undefined;
- highlightedSymbols: string[] | undefined;
- issueLocations: LinearIssueLocation[];
- line: SourceLine;
- onLocationSelect: ((index: number) => void) | undefined;
- onSymbolClick: (symbols: string[]) => void;
- previousLine?: SourceLine;
- secondaryIssueLocations: LinearIssueLocation[];
-}
-
-export class LineCode extends PureComponent<React.PropsWithChildren<Props>> {
- symbols?: NodeListOf<HTMLElement>;
- findingNode?: RefObject<HTMLDivElement>;
-
- constructor(props: Props) {
- super(props);
- this.findingNode = createRef<HTMLDivElement>();
- }
-
- nodeNodeRef = (el: HTMLElement | null) => {
- if (el) {
- this.attachEvents(el);
- } else {
- this.detachEvents();
- }
- };
-
- attachEvents(codeNode: HTMLElement) {
- this.symbols = codeNode.querySelectorAll('.sym');
- if (this.symbols) {
- for (let i = 0; i < this.symbols.length; i++) {
- const symbol = this.symbols[i];
- symbol.addEventListener('click', this.handleSymbolClick);
- }
- }
- }
-
- detachEvents() {
- if (this.symbols) {
- for (let i = 0; i < this.symbols.length; i++) {
- const symbol = this.symbols[i];
- symbol.addEventListener('click', this.handleSymbolClick);
- }
- }
- }
-
- handleSymbolClick = (event: MouseEvent) => {
- event.preventDefault();
- const keys = (event.currentTarget as HTMLElement).className.match(/sym-\d+/g);
- if (keys && keys.length > 0) {
- this.props.onSymbolClick(keys);
- }
- };
-
- addLineMarker = (marker: number, index: number, leadingMarker: boolean, markerIndex: number) => {
- const { highlightedLocationMessage, secondaryIssueLocations, hideLocationIndex } = this.props;
- const selected =
- highlightedLocationMessage !== undefined && highlightedLocationMessage.index === marker;
- const loc = secondaryIssueLocations.find((loc) => loc.index === marker);
- const message = loc?.text;
- const isLeading = leadingMarker && markerIndex === 0;
- return (
- <IssueSourceViewerScrollContext.Consumer key={`${marker}-${index}`}>
- {(ctx) => (
- <LineMarker
- hideLocationIndex={hideLocationIndex}
- index={marker}
- leading={isLeading}
- message={message}
- onLocationSelect={this.props.onLocationSelect}
- ref={selected ? ctx?.registerSelectedSecondaryLocationRef : undefined}
- selected={selected}
- />
- )}
- </IssueSourceViewerScrollContext.Consumer>
- );
- };
-
- addLineToken = (token: Token, shouldPlacePointer: boolean, index: number) => {
- return (
- <LineToken
- className={token.className}
- hasMarker={token.markers.length > 0}
- issueFindingRef={shouldPlacePointer ? this.findingNode : undefined}
- key={`${token.text}-${index}`}
- {...token.modifiers}
- >
- {token.text}
- </LineToken>
- );
- };
-
- renderTokens = (tokens: Token[]) => {
- const renderedTokens: ReactNode[] = [];
-
- // track if the first marker is displayed before the source code
- // set `false` for the first token in a row
- let leadingMarker = false;
-
- // track if a pointer is placed on the token
- let numberOfPlacedPointers = 0;
-
- tokens.forEach((token, index) => {
- if (this.props.displayLocationMarkers && token.markers.length > 0) {
- token.markers.forEach((marker, markerIndex) => {
- renderedTokens.push(this.addLineMarker(marker, index, leadingMarker, markerIndex));
- });
- }
-
- if (token.modifiers.isUnderlined && token.text.trim().length > 1) {
- numberOfPlacedPointers++;
- }
- renderedTokens.push(this.addLineToken(token, numberOfPlacedPointers === 1, index));
-
- if (numberOfPlacedPointers === 1) {
- numberOfPlacedPointers++;
- }
-
- // keep leadingMarker truthy if previous token has only whitespaces
- leadingMarker = (index === 0 ? true : leadingMarker) && !token.text.trim().length;
- });
-
- return renderedTokens;
- };
-
- render() {
- const {
- displayCoverageUnderline,
- displayNewCodeUnderlineLabel,
- children,
- highlightedLocationMessage,
- highlightedSymbols,
- issueLocations,
- line,
- previousLine,
- secondaryIssueLocations,
- } = this.props;
-
- const displayCoverageUnderlineLabel =
- displayCoverageUnderline && line.coverageBlock === line.line;
- const previousLineHasUnderline =
- previousLine?.isNew ||
- (previousLine?.coverageStatus && previousLine.coverageBlock === line.coverageBlock);
-
- return (
- <LineCodeLayers className="it__source-line-code" data-line-number={line.line}>
- {(displayCoverageUnderlineLabel || displayNewCodeUnderlineLabel) && (
- <UnderlineLabels aria-hidden transparentBackground={previousLineHasUnderline}>
- {displayCoverageUnderlineLabel && line.coverageStatus === 'covered' && (
- <CoveredUnderlineLabel>
- {translate('source_viewer.coverage.covered')}
- </CoveredUnderlineLabel>
- )}
- {displayCoverageUnderlineLabel &&
- (line.coverageStatus === 'uncovered' ||
- line.coverageStatus === 'partially-covered') && (
- <UncoveredUnderlineLabel>
- {translate('source_viewer.coverage', line.coverageStatus)}
- </UncoveredUnderlineLabel>
- )}
- {displayNewCodeUnderlineLabel && (
- <NewCodeUnderlineLabel>{translate('source_viewer.new_code')}</NewCodeUnderlineLabel>
- )}
- </UnderlineLabels>
- )}
- {line.isNew && <NewCodeUnderline aria-hidden data-testid="new-code-underline" />}
- {displayCoverageUnderline && line.coverageStatus === 'covered' && (
- <CoveredUnderline aria-hidden data-testid="covered-underline" />
- )}
- {displayCoverageUnderline &&
- (line.coverageStatus === 'uncovered' || line.coverageStatus === 'partially-covered') && (
- <UncoveredUnderline aria-hidden data-testid="uncovered-underline" />
- )}
-
- <LineCodeLayer className="sw-px-3">
- <LineCodePreFormatted ref={this.nodeNodeRef}>
- {this.renderTokens(
- getHighlightedTokens({
- code: line.code,
- highlightedLocationMessage,
- highlightedSymbols,
- issueLocations,
- secondaryIssueLocations,
- }),
- )}
- </LineCodePreFormatted>
- <div ref={this.findingNode}>{children}</div>
- </LineCodeLayer>
- </LineCodeLayers>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/LineDuplicationBlock.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/LineDuplicationBlock.tsx
deleted file mode 100644
index 4fdd9827f80..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/components/LineDuplicationBlock.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { DuplicationBlock, LineMeta, OutsideClickHandler, PopupPlacement } from '~design-system';
-import Tooltip from '../../../components/controls/Tooltip';
-import { translate } from '../../../helpers/l10n';
-import { SourceLine } from '../../../types/types';
-
-export interface LineDuplicationBlockProps {
- blocksLoaded: boolean;
- duplicated: boolean;
- index: number;
- line: SourceLine;
- onClick?: (line: SourceLine) => void;
- renderDuplicationPopup: (index: number, line: number) => React.ReactNode;
-}
-
-export function LineDuplicationBlock(props: LineDuplicationBlockProps) {
- const { blocksLoaded, duplicated, index, line, onClick } = props;
- const [popupOpen, setPopupOpen] = React.useState(false);
-
- const tooltip = popupOpen ? undefined : translate('source_viewer.tooltip.duplicated_block');
-
- const handleClick = React.useCallback(() => {
- setPopupOpen(!popupOpen);
- if (!blocksLoaded && line.duplicated && onClick) {
- onClick(line);
- }
- }, [blocksLoaded, line, onClick, popupOpen]);
-
- const handleClose = React.useCallback(() => setPopupOpen(false), []);
-
- return duplicated ? (
- <Tooltip content={tooltip} side={PopupPlacement.Right}>
- <LineMeta
- className="it__source-line-duplicated"
- data-index={index}
- data-line-number={line.line}
- >
- <OutsideClickHandler onClickOutside={handleClose}>
- <Tooltip
- side={PopupPlacement.Right}
- isOpen={popupOpen}
- isInteractive
- content={popupOpen ? props.renderDuplicationPopup(index, line.line) : undefined}
- classNameInner="sw-max-w-abs-400"
- >
- <DuplicationBlock
- aria-label={translate('source_viewer.tooltip.duplicated_block')}
- aria-expanded={popupOpen}
- aria-haspopup="dialog"
- onClick={handleClick}
- role="button"
- tabIndex={0}
- />
- </Tooltip>
- </OutsideClickHandler>
- </LineMeta>
- </Tooltip>
- ) : (
- <LineMeta data-index={index} data-line-number={line.line} />
- );
-}
-
-export default React.memo(LineDuplicationBlock);
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesIndicator.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesIndicator.tsx
deleted file mode 100644
index 3a86577a0d4..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesIndicator.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { uniq } from 'lodash';
-import * as React from 'react';
-import { useIntl } from 'react-intl';
-import { IssueIndicatorButton, LineIssuesIndicatorIcon, LineMeta } from '~design-system';
-import Tooltip from '../../../components/controls/Tooltip';
-import { useStandardExperienceModeQuery } from '../../../queries/mode';
-import { Issue, SourceLine } from '../../../types/types';
-
-const MOUSE_LEAVE_DELAY = 0.25;
-
-export interface LineIssuesIndicatorProps {
- as?: React.ElementType;
- issues: Issue[];
- issuesOpen?: boolean;
- line: SourceLine;
- onClick: () => void;
-}
-
-export function LineIssuesIndicator(props: LineIssuesIndicatorProps) {
- const { issues, issuesOpen, line, as = 'td' } = props;
- const hasIssues = issues.length > 0;
- const intl = useIntl();
- const { data: isStandardMode } = useStandardExperienceModeQuery();
-
- if (!hasIssues) {
- return <LineMeta />;
- }
-
- const issueAttributeCategories = uniq(issues.map((issue) => issue.cleanCodeAttributeCategory));
- const issueTypes = uniq(issues.map((issue) => issue.type));
- let tooltipContent;
-
- if (isStandardMode ? issueTypes.length > 1 : issueAttributeCategories.length > 1) {
- tooltipContent = intl.formatMessage(
- { id: 'source_viewer.issues_on_line.multiple_issues' },
- { show: !issuesOpen },
- );
- } else {
- tooltipContent = intl.formatMessage(
- {
- id: `source_viewer.issues_on_line.multiple_issues_same_category${isStandardMode ? '.legacy' : ''}`,
- },
- {
- show: !issuesOpen,
- count: issues.length,
- issueType: intl
- .formatMessage({
- id: `issue.type.${issueTypes[0]}${issues.length > 1 ? '.plural' : ''}`,
- })
- .toLowerCase(),
- category: intl
- .formatMessage({
- id: `issue.clean_code_attribute_category.${issueAttributeCategories[0]}`,
- })
- .toLowerCase(),
- },
- );
- }
-
- return (
- <LineMeta className="it__source-line-with-issues" data-line-number={line.line} as={as}>
- <Tooltip mouseLeaveDelay={MOUSE_LEAVE_DELAY} content={tooltipContent}>
- <IssueIndicatorButton
- aria-label={tooltipContent}
- aria-expanded={issuesOpen}
- onClick={props.onClick}
- >
- <LineIssuesIndicatorIcon issuesCount={issues.length} />
- </IssueIndicatorButton>
- </Tooltip>
- </LineMeta>
- );
-}
-
-export default React.memo(LineIssuesIndicator);
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesList.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesList.tsx
deleted file mode 100644
index 5f0946a234e..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesList.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { BranchLike } from '../../../types/branch-like';
-import { LinearIssueLocation, SourceLine, Issue as TypeIssue } from '../../../types/types';
-import Issue from '../../issue/Issue';
-
-export interface LineIssuesListProps {
- branchLike: BranchLike | undefined;
- displayAllIssues?: boolean;
- displayWhyIsThisAnIssue: boolean;
- issueLocationsByLine: { [line: number]: LinearIssueLocation[] };
- issuePopup: { issue: string; name: string } | undefined;
- issuesForLine: TypeIssue[];
- line: SourceLine;
- onIssueChange: (issue: TypeIssue) => void;
- onIssueClick: (issueKey: string) => void;
- onIssuePopupToggle: (issue: string, popupName: string, open?: boolean) => void;
- openIssuesByLine: { [line: number]: boolean };
- selectedIssue: string | undefined;
-}
-
-export default function LineIssuesList(props: LineIssuesListProps) {
- const {
- line,
- displayWhyIsThisAnIssue,
- displayAllIssues,
- openIssuesByLine,
- selectedIssue,
- issuesForLine,
- issueLocationsByLine,
- issuePopup,
- } = props;
-
- const showIssues = openIssuesByLine[line.line] || displayAllIssues;
- const issueLocations = issueLocationsByLine[line.line] || [];
- let displayedIssue: TypeIssue[] = [];
- if (showIssues && issuesForLine.length > 0) {
- displayedIssue = issuesForLine;
- } else if (selectedIssue && !showIssues && issueLocations.length) {
- displayedIssue = issuesForLine.filter((i) => i.key === selectedIssue);
- }
-
- if (displayedIssue.length === 0) {
- return null;
- }
- return (
- <ul className="sw-my-4 sw-max-w-[980px]">
- {displayedIssue.map((issue) => (
- <Issue
- branchLike={props.branchLike}
- displayWhyIsThisAnIssue={displayWhyIsThisAnIssue}
- issue={issue}
- key={issue.key}
- onChange={props.onIssueChange}
- onSelect={props.onIssueClick}
- onPopupToggle={props.onIssuePopupToggle}
- openPopup={issuePopup && issuePopup.issue === issue.key ? issuePopup.name : undefined}
- selected={props.selectedIssue === issue.key}
- />
- ))}
- </ul>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/LineOptionsPopup.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/LineOptionsPopup.tsx
deleted file mode 100644
index 7e2b15ca127..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/components/LineOptionsPopup.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { memo } from 'react';
-import { DropdownMenu, ItemCopy } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { SourceLine } from '../../../types/types';
-import { getLineCodeAsPlainText } from '../helpers/lines';
-
-interface Props {
- line: SourceLine;
- permalink: string;
-}
-
-export function LineOptionsPopup({ line, permalink }: Props) {
- const lineCodeAsPlainText = getLineCodeAsPlainText(line.code);
- return (
- <DropdownMenu>
- <ItemCopy
- copyValue={permalink}
- tooltipOverlay={translate('source_viewer.copied_to_clipboard')}
- >
- {translate('source_viewer.copy_permalink')}
- </ItemCopy>
-
- {lineCodeAsPlainText && (
- <ItemCopy
- copyValue={lineCodeAsPlainText}
- tooltipOverlay={translate('source_viewer.copied_to_clipboard')}
- >
- {translate('source_viewer.copy_line')}
- </ItemCopy>
- )}
- </DropdownMenu>
- );
-}
-
-export default memo(LineOptionsPopup);
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/LineSCM.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/LineSCM.tsx
deleted file mode 100644
index 7c3772e5967..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/components/LineSCM.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { memo, useCallback, useState } from 'react';
-import {
- LineMeta,
- LineSCMStyled,
- LineSCMStyledDiv,
- OutsideClickHandler,
- PopupPlacement,
-} from '~design-system';
-import { translateWithParameters } from '../../../helpers/l10n';
-import { SourceLine } from '../../../types/types';
-import Tooltip from '../../controls/Tooltip';
-import SCMPopup from './SCMPopup';
-
-interface Props {
- line: SourceLine;
- previousLine: SourceLine | undefined;
-}
-
-function LineSCM({ line, previousLine }: Props) {
- const [isOpen, setIsOpen] = useState(false);
-
- const handleToggle = useCallback(() => {
- setIsOpen(!isOpen);
- }, [isOpen]);
- const handleClose = useCallback(() => {
- setIsOpen(false);
- }, []);
-
- const isFileIssue = !line.line;
- if (isFileIssue) {
- return (
- <LineMeta>
- <LineSCMStyledDiv>{line.scmAuthor ?? ' '}</LineSCMStyledDiv>
- </LineMeta>
- );
- }
-
- let ariaLabel = translateWithParameters('source_viewer.click_for_scm_info', line.line);
- if (line.scmAuthor) {
- ariaLabel = `${translateWithParameters(
- 'source_viewer.author_X',
- line.scmAuthor,
- )}, ${ariaLabel}`;
- }
-
- return (
- <LineMeta data-line-number={line.line}>
- <OutsideClickHandler onClickOutside={handleClose}>
- <Tooltip
- content={<SCMPopup line={line} />}
- side={PopupPlacement.Right}
- isOpen={isOpen}
- isInteractive
- classNameInner="sw-max-w-abs-600"
- >
- <LineSCMStyled aria-label={ariaLabel} onClick={handleToggle} role="button">
- {isSCMChanged(line, previousLine) ? (line.scmAuthor ?? '…') : ' '}
- </LineSCMStyled>
- </Tooltip>
- </OutsideClickHandler>
- </LineMeta>
- );
-}
-
-function isSCMChanged(s: SourceLine, p: SourceLine | undefined) {
- let changed = true;
- if (p != null && s.scmRevision != null && p.scmRevision != null) {
- changed = s.scmRevision !== p.scmRevision || s.scmDate !== p.scmDate;
- }
- return changed;
-}
-
-export default memo(LineSCM);
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/SCMPopup.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/SCMPopup.tsx
deleted file mode 100644
index a4caf1a3316..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/components/SCMPopup.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { memo } from 'react';
-import { SCMHighlight } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { SourceLine } from '../../../types/types';
-import DateFormatter from '../../intl/DateFormatter';
-
-interface Props {
- line: SourceLine;
-}
-
-export function SCMPopup({ line }: Props) {
- const hasAuthor = line.scmAuthor !== undefined && line.scmAuthor !== '';
- const hasDate = line.scmDate !== undefined;
- return (
- <div className="sw-select-text sw-text-left">
- {hasAuthor && (
- <div className="sw-flex sw-items-center">
- <SCMHighlight>{translate('author')}</SCMHighlight>
- <div className="sw-whitespace-nowrap sw-mr-2">{line.scmAuthor}</div>
- </div>
- )}
- {hasDate && (
- <div className="sw-flex sw-items-center">
- <SCMHighlight>{translate('source_viewer.tooltip.scm.commited_on')}</SCMHighlight>
- <div className="sw-whitespace-nowrap sw-mr-2">
- <DateFormatter date={line.scmDate!} />
- </div>
- </div>
- )}
- {line.scmRevision && (
- <div className="sw-flex sw-items-center">
- <SCMHighlight>{translate('source_viewer.tooltip.scm.revision')}</SCMHighlight>
- <div className="sw-whitespace-nowrap sw-mr-2">{line.scmRevision}</div>
- </div>
- )}
- </div>
- );
-}
-
-export default memo(SCMPopup);
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/__snapshots__/loadIssues-test.ts.snap b/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/__snapshots__/loadIssues-test.ts.snap
deleted file mode 100644
index 8c10c4dbf60..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/__snapshots__/loadIssues-test.ts.snap
+++ /dev/null
@@ -1,136 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`loadIssues should load issues with listIssues if re-indexing 1`] = `
-[
- {
- "actions": [
- "set_tags",
- "comment",
- "assign",
- ],
- "assignee": "luke",
- "author": "luke@sonarsource.com",
- "cleanCodeAttribute": "RESPECTFUL",
- "cleanCodeAttributeCategory": "RESPONSIBLE",
- "comments": [],
- "component": "foo.java",
- "componentEnabled": true,
- "componentKey": "foo.java",
- "componentLongName": "Foo.java",
- "componentName": "foo.java",
- "componentPath": "/foo.java",
- "componentQualifier": "FIL",
- "creationDate": "2016-08-15T15:25:38+0200",
- "flows": [],
- "flowsWithType": [],
- "impacts": [
- {
- "severity": "MEDIUM",
- "softwareQuality": "MAINTAINABILITY",
- },
- ],
- "issueStatus": "OPEN",
- "key": "AWaqVGl3tut9VbnJvk6M",
- "line": 62,
- "message": "Make sure this file handling is safe here.",
- "prioritizedRule": false,
- "project": "org.sonarsource.java:java",
- "projectEnabled": true,
- "projectKey": "org.sonarsource.java:java",
- "projectLongName": "SonarJava",
- "projectName": "SonarJava",
- "projectQualifier": "TRK",
- "rule": "squid:S4797",
- "scope": "MAIN",
- "secondaryLocations": [],
- "severity": "MAJOR",
- "status": "OPEN",
- "tags": [
- "cert",
- "cwe",
- "owasp-a1",
- "owasp-a3",
- ],
- "textRange": {
- "endLine": 62,
- "endOffset": 96,
- "startLine": 62,
- "startOffset": 93,
- },
- "transitions": [],
- "type": "SECURITY_HOTSPOT",
- },
-]
-`;
-
-exports[`loadIssues should load issues with searchIssues if not re-indexing 1`] = `
-[
- {
- "actions": [
- "set_tags",
- "comment",
- "assign",
- ],
- "assignee": "luke",
- "assigneeActive": true,
- "assigneeAvatar": "lukavatar",
- "assigneeLogin": "luke",
- "assigneeName": "Luke",
- "author": "luke@sonarsource.com",
- "cleanCodeAttribute": "RESPECTFUL",
- "cleanCodeAttributeCategory": "RESPONSIBLE",
- "comments": [],
- "component": "foo.java",
- "componentEnabled": true,
- "componentKey": "foo.java",
- "componentLongName": "Foo.java",
- "componentName": "foo.java",
- "componentPath": "/foo.java",
- "componentQualifier": "FIL",
- "creationDate": "2016-08-15T15:25:38+0200",
- "flows": [],
- "flowsWithType": [],
- "impacts": [
- {
- "severity": "MEDIUM",
- "softwareQuality": "MAINTAINABILITY",
- },
- ],
- "issueStatus": "OPEN",
- "key": "AWaqVGl3tut9VbnJvk6M",
- "line": 62,
- "message": "Make sure this file handling is safe here.",
- "prioritizedRule": false,
- "project": "org.sonarsource.java:java",
- "projectEnabled": true,
- "projectKey": "org.sonarsource.java:java",
- "projectLongName": "SonarJava",
- "projectName": "SonarJava",
- "projectQualifier": "TRK",
- "rule": "squid:S4797",
- "ruleKey": "squid:S4797",
- "ruleLang": "java",
- "ruleLangName": "Java",
- "ruleName": "Handling files is security-sensitive",
- "ruleStatus": "READY",
- "scope": "MAIN",
- "secondaryLocations": [],
- "severity": "MAJOR",
- "status": "OPEN",
- "tags": [
- "cert",
- "cwe",
- "owasp-a1",
- "owasp-a3",
- ],
- "textRange": {
- "endLine": 62,
- "endOffset": 96,
- "startLine": 62,
- "startOffset": 93,
- },
- "transitions": [],
- "type": "SECURITY_HOTSPOT",
- },
-]
-`;
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/duplications-test.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/duplications-test.ts
deleted file mode 100644
index 40d2548262d..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/duplications-test.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- getDuplicationBlocksForIndex,
- isDuplicationBlockInRemovedComponent,
-} from '../duplications';
-
-describe('getDuplicationBlocksForIndex', () => {
- it('should return duplications blocks', () => {
- const blocks = [{ _ref: '0', from: 2, size: 2 }];
- expect(getDuplicationBlocksForIndex([{ blocks }], 0)).toBe(blocks);
- expect(getDuplicationBlocksForIndex([{ blocks }], 5)).toEqual([]);
- expect(getDuplicationBlocksForIndex(undefined, 5)).toEqual([]);
- });
-});
-
-describe('isDuplicationBlockInRemovedComponent', () => {
- it('should', () => {
- expect(
- isDuplicationBlockInRemovedComponent([
- { _ref: '0', from: 2, size: 2 },
- { _ref: '0', from: 3, size: 1 },
- ]),
- ).toBe(false);
- expect(
- isDuplicationBlockInRemovedComponent([
- { _ref: undefined, from: 2, size: 2 },
- { _ref: '0', from: 3, size: 1 },
- ]),
- ).toBe(true);
- });
-});
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/highlight-test.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/highlight-test.ts
deleted file mode 100644
index 96bebd42de1..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/highlight-test.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { highlightSymbol } from '../highlight';
-
-describe('highlightSymbol', () => {
- it('should not highlight symbols with similar beginning', () => {
- // test all positions of sym-X in the string: beginning, middle and ending
- const tokens = [
- { className: 'sym-18 b', markers: [], text: 'foo', modifiers: {} },
- { className: 'a sym-18', markers: [], text: 'foo', modifiers: {} },
- { className: 'a sym-18 b', markers: [], text: 'foo', modifiers: {} },
- { className: 'sym-1 d', markers: [], text: 'bar', modifiers: {} },
- { className: 'c sym-1', markers: [], text: 'bar', modifiers: {} },
- { className: 'c sym-1 d', markers: [], text: 'bar', modifiers: {} },
- ];
- expect(highlightSymbol(tokens, 'sym-1')).toEqual([
- { className: 'sym-18 b', markers: [], text: 'foo', modifiers: {} },
- { className: 'a sym-18', markers: [], text: 'foo', modifiers: {} },
- { className: 'a sym-18 b', markers: [], text: 'foo', modifiers: {} },
- { className: 'sym-1 d highlighted', markers: [], text: 'bar', modifiers: {} },
- { className: 'c sym-1 highlighted', markers: [], text: 'bar', modifiers: {} },
- { className: 'c sym-1 d highlighted', markers: [], text: 'bar', modifiers: {} },
- ]);
- });
-
- it('should highlight symbols marked twice', () => {
- const tokens = [
- { className: 'sym sym-1 sym sym-2', markers: [], text: 'foo', modifiers: {} },
- { className: 'sym sym-1', markers: [], text: 'bar', modifiers: {} },
- { className: 'sym sym-2', markers: [], text: 'qux', modifiers: {} },
- ];
- expect(highlightSymbol(tokens, 'sym-1')).toEqual([
- { className: 'sym sym-1 sym sym-2 highlighted', markers: [], text: 'foo', modifiers: {} },
- { className: 'sym sym-1 highlighted', markers: [], text: 'bar', modifiers: {} },
- { className: 'sym sym-2', markers: [], text: 'qux', modifiers: {} },
- ]);
- });
-});
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/indexing-test.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/indexing-test.ts
deleted file mode 100644
index 4e204533f62..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/indexing-test.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { mockIssue } from '../../../../helpers/testMocks';
-import { issuesByComponentAndLine, symbolsByLine } from '../indexing';
-
-describe('issuesByComponentAndLine', () => {
- it('should map issues by lines and components', () => {
- const issues = [
- mockIssue(true, { component: 'foo.js' }),
- mockIssue(false, {
- component: 'foo.js',
- textRange: { startLine: 5, endLine: 5, startOffset: 0, endOffset: 0 },
- }),
- mockIssue(false, { component: 'bar.js' }),
- mockIssue(),
- mockIssue(),
- ];
- const result = issuesByComponentAndLine(issues);
- expect(Object.keys(result['foo.js'])).toHaveLength(2);
- expect(Object.keys(result['foo.js'])).toEqual(['5', '26']);
- expect(result['foo.js'][5]).toHaveLength(1);
-
- expect(Object.keys(result['bar.js'])).toHaveLength(1);
-
- expect(Object.keys(result['main.js'])).toHaveLength(1);
- expect(result['main.js'][26]).toHaveLength(2);
- });
-});
-
-describe('symbolsByLine', () => {
- it('should highlight symbols marked twice', () => {
- const lines = [
- { line: 1, code: '<span class="sym-54 sym"><span class="sym-56 sym">foo</span></span>' },
- { line: 2, code: '<span class="sym-56 sym">bar</span>' },
- { line: 3, code: '<span class="k">qux</span>' },
- ];
- expect(symbolsByLine(lines)).toEqual({
- 1: ['sym-54', 'sym-56'],
- 2: ['sym-56'],
- 3: [],
- });
- });
-});
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/issueLocations-test.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/issueLocations-test.ts
deleted file mode 100644
index b171ebf96dc..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/issueLocations-test.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { mockSourceLine } from '../../../../helpers/mocks/sources';
-import { mockFlowLocation } from '../../../../helpers/testMocks';
-import { getLinearLocations, getSecondaryIssueLocationsForLine } from '../issueLocations';
-
-describe('getSecondaryIssueLocationsForLine', () => {
- it('should return secondary locations for a line', () => {
- const sourceLine = mockSourceLine({ line: 2 });
- expect(getSecondaryIssueLocationsForLine(sourceLine, undefined)).toEqual([]);
- expect(getSecondaryIssueLocationsForLine(sourceLine, [mockFlowLocation()])).toEqual([
- { from: 0, index: undefined, line: 2, startLine: 1, text: undefined, to: 2 },
- ]);
- });
-});
-
-describe('getLinearLocations', () => {
- it('should return a linear location', () => {
- expect(getLinearLocations({ startLine: 6, startOffset: 3, endLine: 8, endOffset: 56 })).toEqual(
- [
- { from: 3, line: 6, to: 999999 },
- { from: 0, line: 7, to: 999999 },
- { from: 0, line: 8, to: 56 },
- ],
- );
- expect(getLinearLocations({ startLine: 6, startOffset: 0, endLine: 6, endOffset: 42 })).toEqual(
- [{ from: 0, line: 6, to: 42 }],
- );
- });
-});
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/loadIssues-test.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/loadIssues-test.ts
deleted file mode 100644
index 4c0a50416b3..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/loadIssues-test.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { mockMainBranch } from '../../../../helpers/mocks/branch-like';
-import { mockRawIssue } from '../../../../helpers/testMocks';
-import { IssueStatus, IssueType } from '../../../../types/issues';
-import loadIssues from '../loadIssues';
-
-const mockListResolvedValue = {
- components: [
- {
- enabled: true,
- key: 'org.sonarsource.java:java',
- longName: 'SonarJava',
- name: 'SonarJava',
- qualifier: ComponentQualifier.Project,
- },
- {
- enabled: true,
- key: 'foo.java',
- longName: 'Foo.java',
- name: 'foo.java',
- path: '/foo.java',
- qualifier: ComponentQualifier.File,
- },
- ],
- issues: [
- mockRawIssue(false, {
- actions: ['set_tags', 'comment', 'assign'],
- assignee: 'luke',
- author: 'luke@sonarsource.com',
- comments: [],
- component: 'foo.java',
- creationDate: '2016-08-15T15:25:38+0200',
- flows: [],
- key: 'AWaqVGl3tut9VbnJvk6M',
- line: 62,
- message: 'Make sure this file handling is safe here.',
- project: 'org.sonarsource.java:java',
- rule: 'squid:S4797',
- status: 'OPEN',
- issueStatus: IssueStatus.Open,
- tags: ['cert', 'cwe', 'owasp-a1', 'owasp-a3'],
- textRange: { startLine: 62, endLine: 62, startOffset: 93, endOffset: 96 },
- transitions: [],
- type: IssueType.SecurityHotspot,
- }),
- ],
- paging: { pageIndex: 1, pageSize: 500, total: 1 },
-};
-
-const mockSearchResolvedValue = {
- ...mockListResolvedValue,
- debtTotal: 15,
- effortTotal: 15,
- facets: [],
- languages: [{ key: 'java', name: 'Java' }],
- rules: [
- {
- key: 'squid:S4797',
- lang: 'java',
- langName: 'Java',
- name: 'Handling files is security-sensitive',
- status: 'READY',
- },
- ],
- users: [{ active: true, avatar: 'lukavatar', login: 'luke', name: 'Luke' }],
-};
-
-jest.mock('../../../../api/issues', () => ({
- listIssues: jest.fn().mockImplementation(() => Promise.resolve(mockListResolvedValue)),
- searchIssues: jest.fn().mockImplementation(() => Promise.resolve(mockSearchResolvedValue)),
-}));
-
-describe('loadIssues', () => {
- it('should load issues with searchIssues if not re-indexing', async () => {
- const result = await loadIssues('foo.java', mockMainBranch());
-
- expect(result).toMatchSnapshot();
- });
-
- it('should load issues with listIssues if re-indexing', async () => {
- const result = await loadIssues('foo.java', mockMainBranch(), true);
- expect(result).toMatchSnapshot();
- });
-});
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/duplications.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/duplications.ts
deleted file mode 100644
index 2c1ba5acbbe..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/duplications.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Duplication, DuplicationBlock } from '../../../types/types';
-
-// TODO Test this function, but I don't get the logic behind it
-export function filterDuplicationBlocksByLine(blocks: DuplicationBlock[], line: number) {
- /* eslint-disable no-underscore-dangle */
- let foundOne = false;
- return blocks.filter((b) => {
- const outOfBounds = b.from > line || b.from + b.size < line;
- const currentFile = b._ref === '1';
- const shouldDisplayForCurrentFile = outOfBounds || foundOne;
- const shouldDisplay = !currentFile || shouldDisplayForCurrentFile;
- const isOk = b._ref !== undefined && shouldDisplay;
- if (b._ref === '1' && !outOfBounds) {
- foundOne = true;
- }
- return isOk;
- });
- /* eslint-enable no-underscore-dangle */
-}
-
-export function getDuplicationBlocksForIndex(
- duplications: Duplication[] | undefined,
- index: number,
-) {
- return (duplications && duplications[index] && duplications[index].blocks) || [];
-}
-
-export function isDuplicationBlockInRemovedComponent(blocks: DuplicationBlock[]) {
- return blocks.some((b) => b._ref === undefined); // eslint-disable-line no-underscore-dangle
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/getCoverageStatus.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/getCoverageStatus.ts
deleted file mode 100644
index 225dc376371..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/getCoverageStatus.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { SourceLine, SourceLineCoverageStatus } from '../../../types/types';
-
-export default function getCoverageStatus(s: SourceLine): SourceLineCoverageStatus | undefined {
- let status: SourceLineCoverageStatus | undefined;
- if (s.lineHits != null && s.lineHits > 0) {
- status = 'partially-covered';
- }
- if (s.lineHits != null && s.lineHits > 0 && s.conditions === s.coveredConditions) {
- status = 'covered';
- }
- if (s.lineHits === 0 || s.coveredConditions === 0) {
- status = 'uncovered';
- }
- return status;
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/highlight.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/highlight.ts
deleted file mode 100644
index 9237b0a12e2..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/highlight.ts
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { uniq } from 'lodash';
-import { LinearIssueLocation } from '../../../types/types';
-
-export interface TokenModifiers {
- isHighlighted?: boolean;
- isLocation?: boolean;
- isSelected?: boolean;
- isUnderlined?: boolean;
-}
-
-export interface Token {
- className: string;
- markers: number[];
- modifiers: TokenModifiers;
- text: string;
-}
-
-const ISSUE_LOCATION_CLASS = 'source-line-code-issue';
-
-export function splitByTokens(code: NodeListOf<ChildNode>, rootClassName = ''): Token[] {
- let tokens: Token[] = [];
- Array.prototype.forEach.call(code, (node: Element) => {
- if (node.nodeType === 1) {
- // ELEMENT NODE
- const fullClassName = rootClassName ? rootClassName + ' ' + node.className : node.className;
- const innerTokens = splitByTokens(node.childNodes, fullClassName);
- tokens = tokens.concat(innerTokens);
- }
- if (node.nodeType === 3 && node.nodeValue) {
- // TEXT NODE
- tokens.push({ className: rootClassName, markers: [], text: node.nodeValue, modifiers: {} });
- }
- });
- return tokens;
-}
-
-export function highlightSymbol(tokens: Token[], symbol: string): Token[] {
- const symbolRegExp = new RegExp(`\\b${symbol}\\b`);
- return tokens.map((token) =>
- symbolRegExp.test(token.className)
- ? { ...token, className: `${token.className} highlighted` }
- : token,
- );
-}
-
-/**
- * Intersect two ranges
- * @param s1 Start position of the first range
- * @param e1 End position of the first range
- * @param s2 Start position of the second range
- * @param e2 End position of the second range
- */
-function intersect(s1: number, e1: number, s2: number, e2: number) {
- return { from: Math.max(s1, s2), to: Math.min(e1, e2) };
-}
-
-/**
- * Get the substring of a string
- * @param str A string
- * @param from "From" offset
- * @param to "To" offset
- * @param acc Global offset to eliminate
- */
-function part(str: string, from: number, to: number, acc: number): string {
- // we do not want negative number as the first argument of `substr`
- return from >= acc ? str.substr(from - acc, to - from) : str.substr(0, to - from);
-}
-
-/**
- * Highlight issue locations in the list of tokens
- */
-export function highlightIssueLocations(
- tokens: Token[],
- issueLocations: LinearIssueLocation[],
- modifier: keyof TokenModifiers,
- rootClassName: string = ISSUE_LOCATION_CLASS,
-): Token[] {
- issueLocations.forEach((location) => {
- const nextTokens: Token[] = [];
- let acc = 0;
- let markerAdded = location.line !== location.startLine;
- tokens.forEach((token) => {
- const x = intersect(acc, acc + token.text.length, location.from, location.to);
- const p1 = part(token.text, acc, x.from, acc);
- const p2 = part(token.text, x.from, x.to, acc);
- const p3 = part(token.text, x.to, acc + token.text.length, acc);
- if (p1.length) {
- nextTokens.push({ ...token, text: p1 });
- }
- if (p2.length) {
- const newClassName =
- token.className.indexOf(rootClassName) === -1
- ? `${token.className} ${rootClassName}`
- : token.className;
- nextTokens.push({
- className: newClassName,
- modifiers: {
- ...token.modifiers,
- [modifier]: true,
- },
- markers:
- !markerAdded && location.index != null
- ? uniq([...token.markers, location.index])
- : token.markers,
- text: p2,
- });
- markerAdded = true;
- }
- if (p3.length) {
- nextTokens.push({ ...token, text: p3 });
- }
- acc += token.text.length;
- });
- tokens = nextTokens.slice();
- });
- return tokens;
-}
-
-export const getHighlightedTokens = (params: {
- code: string | undefined;
- highlightedLocationMessage: { index: number; text: string | undefined } | undefined;
- highlightedSymbols: string[] | undefined;
- issueLocations: LinearIssueLocation[];
- secondaryIssueLocations: LinearIssueLocation[];
-}) => {
- const {
- code,
- highlightedLocationMessage,
- highlightedSymbols,
- issueLocations,
- secondaryIssueLocations,
- } = params;
-
- const container = document.createElement('div');
- container.innerHTML = code ?? '';
- let tokens = splitByTokens(container.childNodes);
-
- if (highlightedSymbols) {
- highlightedSymbols.forEach((symbol) => {
- tokens = highlightSymbol(tokens, symbol);
- });
- }
-
- if (issueLocations.length > 0) {
- tokens = highlightIssueLocations(tokens, issueLocations, 'isUnderlined', 'isUnderlined');
- }
-
- if (secondaryIssueLocations) {
- tokens = highlightIssueLocations(
- tokens,
- secondaryIssueLocations,
- 'isLocation',
- 'issue-location',
- );
-
- if (highlightedLocationMessage) {
- const location = secondaryIssueLocations.find(
- (location) => location.index === highlightedLocationMessage.index,
- );
- if (location) {
- tokens = highlightIssueLocations(tokens, [location], 'isSelected', 'selected');
- }
- }
- }
-
- return tokens;
-};
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/indexing.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/indexing.ts
deleted file mode 100644
index 45a98398646..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/indexing.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { flatten } from 'lodash';
-import { Duplication, Issue, LinearIssueLocation, SourceLine } from '../../../types/types';
-import { splitByTokens } from './highlight';
-import { getLinearLocations } from './issueLocations';
-
-export function issuesByLine(issues: Issue[]) {
- const index: { [line: number]: Issue[] } = {};
- issues.forEach((issue) => {
- const line = issue.textRange ? issue.textRange.endLine : 0;
- if (!(line in index)) {
- index[line] = [];
- }
- index[line].push(issue);
- });
- return index;
-}
-
-export function issuesByComponentAndLine(issues: Issue[] = []): {
- [component: string]: { [line: number]: Issue[] };
-} {
- return issues.reduce((mapping: { [component: string]: { [line: number]: Issue[] } }, issue) => {
- mapping[issue.component] = mapping[issue.component] || {};
- const line = issue.textRange ? issue.textRange.endLine : 0;
- mapping[issue.component][line] = mapping[issue.component][line] || [];
- mapping[issue.component][line].push(issue);
- return mapping;
- }, {});
-}
-
-export function locationsByLine(issues: Pick<Issue, 'textRange'>[]) {
- const index: { [line: number]: LinearIssueLocation[] } = {};
- issues.forEach((issue) => {
- getLinearLocations(issue.textRange).forEach((location) => {
- if (!(location.line in index)) {
- index[location.line] = [];
- }
- index[location.line].push(location);
- });
- });
- return index;
-}
-
-export function duplicationsByLine(duplications: Duplication[] | undefined) {
- if (duplications == null) {
- return {};
- }
-
- const duplicationsByLine: { [line: number]: number[] } = {};
-
- duplications.forEach(({ blocks }, duplicationIndex) => {
- blocks.forEach((block) => {
- // eslint-disable-next-line no-underscore-dangle
- if (block._ref === '1') {
- for (let line = block.from; line < block.from + block.size; line++) {
- if (!(line in duplicationsByLine)) {
- duplicationsByLine[line] = [];
- }
- duplicationsByLine[line].push(duplicationIndex);
- }
- }
- });
- });
-
- return duplicationsByLine;
-}
-
-export function symbolsByLine(sources: SourceLine[]) {
- const index: { [line: number]: string[] } = {};
- sources.forEach((line) => {
- const container = document.createElement('div');
- container.innerHTML = line.code || '';
- const tokens = splitByTokens(container.childNodes);
- const symbols = flatten(
- tokens.map((token) => {
- const keys = token.className.match(/sym-\d+/g);
- return keys != null ? keys : [];
- }),
- );
- index[line.line] = symbols.filter((key) => key);
- });
- return index;
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/issueLocations.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/issueLocations.ts
deleted file mode 100644
index 983bede74c1..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/issueLocations.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FlowLocation, LinearIssueLocation, SourceLine, TextRange } from '../../../types/types';
-
-export function getLinearLocations(textRange: TextRange | undefined): LinearIssueLocation[] {
- if (!textRange) {
- return [];
- }
- const locations = [];
-
- // go through all lines of the `textRange`
- for (let line = textRange.startLine; line <= textRange.endLine; line++) {
- // TODO fix 999999
- const from = line === textRange.startLine ? textRange.startOffset : 0;
- const to = line === textRange.endLine ? textRange.endOffset : 999999;
- locations.push({ line, from, to });
- }
- return locations;
-}
-
-export function getSecondaryIssueLocationsForLine(
- line: SourceLine,
- highlightedLocations: (FlowLocation | undefined)[] | undefined,
-): LinearIssueLocation[] {
- if (!highlightedLocations) {
- return [];
- }
- return highlightedLocations.reduce((locations, location) => {
- const linearLocations: LinearIssueLocation[] = location
- ? getLinearLocations(location.textRange)
- .filter((l) => l.line === line.line)
- .map((l) => ({
- ...l,
- startLine: location.textRange.startLine,
- index: location.index,
- text: location.msg,
- textFormatting: location.msgFormattings,
- }))
- : [];
- return [...locations, ...linearLocations];
- }, []);
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/lines.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/lines.ts
deleted file mode 100644
index 9c4a6b3108f..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/lines.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { intersection } from 'lodash';
-import { LinearIssueLocation } from '../../../types/types';
-
-export const LINES_TO_LOAD = 1000;
-
-export function optimizeHighlightedSymbols(
- symbolsForLine: string[] = [],
- highlightedSymbols: string[] = [],
-): string[] | undefined {
- const symbols = intersection(symbolsForLine, highlightedSymbols);
-
- return symbols.length ? symbols : undefined;
-}
-
-export function optimizeLocationMessage(
- highlightedLocationMessage: { index: number; text: string | undefined } | undefined,
- optimizedSecondaryIssueLocations: LinearIssueLocation[],
-) {
- return highlightedLocationMessage != null &&
- optimizedSecondaryIssueLocations.some(
- (location) => location.index === highlightedLocationMessage.index,
- )
- ? highlightedLocationMessage
- : undefined;
-}
-
-/**
- * Parse lineCode HTML and return text nodes content only
- */
-export const getLineCodeAsPlainText = (lineCode?: string) => {
- if (!lineCode) {
- return '';
- }
- const domParser = new DOMParser();
- const domDoc = domParser.parseFromString(lineCode, 'text/html');
- const bodyElements = domDoc.getElementsByTagName('body');
- return bodyElements.length && bodyElements[0].textContent ? bodyElements[0].textContent : '';
-};
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/helpers/loadIssues.ts b/server/sonar-web/src/main/js/components/SourceViewer/helpers/loadIssues.ts
deleted file mode 100644
index d925b42ec04..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/helpers/loadIssues.ts
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getBranchLikeQuery } from '~sonar-aligned/helpers/branch-like';
-import { RawQuery } from '~sonar-aligned/types/router';
-import { listIssues, searchIssues } from '../../../api/issues';
-import { parseIssueFromResponse } from '../../../helpers/issues';
-import { BranchLike } from '../../../types/branch-like';
-import { Issue } from '../../../types/types';
-import { DEFAULT_ISSUES_QUERY } from '../../shared/utils';
-
-// maximum possible value
-const PAGE_SIZE = 500;
-// Maximum issues return 20*500 for the API.
-const PAGE_MAX = 20;
-
-function buildListQuery(component: string, branchLike: BranchLike | undefined) {
- return {
- component,
- ...DEFAULT_ISSUES_QUERY,
- ...getBranchLikeQuery(branchLike),
- };
-}
-
-function buildSearchQuery(component: string, branchLike: BranchLike | undefined) {
- return {
- ...DEFAULT_ISSUES_QUERY,
- additionalFields: '_all',
- components: component,
- s: 'FILE_LINE',
- ...getBranchLikeQuery(branchLike),
- };
-}
-
-function loadListPage(query: RawQuery, page: number, pageSize = PAGE_SIZE): Promise<Issue[]> {
- return listIssues({
- ...query,
- p: page,
- ps: pageSize,
- }).then((r) => r.issues.map((issue) => parseIssueFromResponse(issue, r.components)));
-}
-
-function loadSearchPage(query: RawQuery, page: number, pageSize = PAGE_SIZE): Promise<Issue[]> {
- return searchIssues({
- ...query,
- p: page,
- ps: pageSize,
- }).then((r) =>
- r.issues.map((issue) => parseIssueFromResponse(issue, r.components, r.users, r.rules)),
- );
-}
-
-async function loadPageAndNext(
- query: RawQuery,
- needIssueSync = false,
- page = 1,
- pageSize = PAGE_SIZE,
-): Promise<Issue[]> {
- const issues = needIssueSync
- ? await loadListPage(query, page)
- : await loadSearchPage(query, page);
-
- if (issues.length === 0) {
- return [];
- }
-
- if (issues.length < pageSize || page >= PAGE_MAX) {
- return issues;
- }
-
- const nextIssues = await loadPageAndNext(query, needIssueSync, page + 1, pageSize);
-
- return [...issues, ...nextIssues];
-}
-
-export default function loadIssues(
- component: string,
- branchLike: BranchLike | undefined,
- needIssueSync = false,
-): Promise<Issue[]> {
- const query = needIssueSync
- ? buildListQuery(component, branchLike)
- : buildSearchQuery(component, branchLike);
-
- return loadPageAndNext(query, needIssueSync);
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/styles.css b/server/sonar-web/src/main/js/components/SourceViewer/styles.css
deleted file mode 100644
index 0779f8fda2e..00000000000
--- a/server/sonar-web/src/main/js/components/SourceViewer/styles.css
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-.source-viewer {
- width: 100%;
- min-height: 200px;
- border: 1px solid #cdcdcd;
- box-sizing: border-box;
- background-color: #fff;
-}
-
-.source-table {
- width: 100%;
- border: none;
- border-collapse: collapse;
-}
-
-.source-viewer-code {
- overflow-x: auto;
-}
-
-.source-viewer-more-code {
- padding: 40px 0;
- border-bottom: 1px solid #e6e6e6;
- background-color: #f3f3f3;
- text-align: center;
-}
-
-.source-table + .source-viewer-more-code {
- border-bottom: none;
- border-top: 1px solid #e6e6e6;
-}
-
-.issue-location.highlighted {
- border-color: #e1e1f2;
- background-color: #e1e1f2;
-}
-
-.issue-location.selected {
- border-color: #f4b1b0;
- background-color: #f4b1b0;
-}
-
-.measures-viewer {
- display: flex;
- margin: 0 calc(-1 * 8px);
-}
-
-.measures-viewer + .measures-viewer {
- margin-top: 8px;
-}
-
-.measures-viewer-header {
- font-size: 12px;
-}
-
-.measures-viewer-secondary .measures-viewer-card {
- background-color: #f3f3f3;
-}
-
-.measures-viewer-section {
- flex: 1;
-}
-
-.measures-viewer-section-limited {
- max-width: 25%;
-}
-
-.measures-viewer-card {
- margin: calc(2 * 8px) 8px;
- padding: 8px;
- border: 1px solid #e6e6e6;
- background-color: #fff;
-}
-
-.measures + .measures {
- margin-top: calc(2 * 8px);
- padding-top: calc(2 * 8px);
- border-top: 1px solid #e6e6e6;
-}
-
-.measures-chart {
- display: inline-block;
- vertical-align: middle;
- width: calc(8px * 10);
- margin-right: calc(8px * 3);
- text-align: center;
-}
-
-.measure {
- line-height: 1.34;
-}
-
-.measure-one-line {
- display: flex;
- justify-content: space-between;
-}
-
-.measure-one-line .measure-name {
- display: inline;
-}
-
-.measure-name {
- display: block;
- font-size: 13px;
-}
-
-.measure-value {
- color: #236a97;
- font-size: 16px;
- font-weight: 400;
-}
-
-.measure-big {
- display: inline-block;
- vertical-align: middle;
-}
-
-.measure-big .measure-name {
- margin-top: calc(8px / 2);
- margin-bottom: 8px;
- font-size: 16px;
-}
-
-.measure-big .measure-value,
-.measure-big .rating {
- font-size: 24px;
-}
-
-.measure-big + .measure-big {
- margin-left: calc(8px * 3);
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/AddGraphMetric.tsx b/server/sonar-web/src/main/js/components/activity-graph/AddGraphMetric.tsx
deleted file mode 100644
index f7c43ec35fa..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/AddGraphMetric.tsx
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, IconChevronDown } from '@sonarsource/echoes-react';
-import { sortBy } from 'lodash';
-import * as React from 'react';
-import { Dropdown } from '~design-system';
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import { MQR_CONDITIONS_MAP, STANDARD_CONDITIONS_MAP } from '../../apps/quality-gates/utils';
-import { HIDDEN_METRICS } from '../../helpers/constants';
-import { getLocalizedMetricName, translate } from '../../helpers/l10n';
-import { isDiffMetric } from '../../helpers/measures';
-import { useStandardExperienceModeQuery } from '../../queries/mode';
-import { Metric } from '../../types/types';
-import AddGraphMetricPopup from './AddGraphMetricPopup';
-
-interface Props {
- metrics: Metric[];
- metricsTypeFilter?: string[];
- onAddMetric: (metric: string) => void;
- onRemoveMetric: (metric: string) => void;
- selectedMetrics: string[];
-}
-
-export default function AddGraphMetric(props: Readonly<Props>) {
- const [metrics, setMetrics] = React.useState<string[]>([]);
- const [query, setQuery] = React.useState<string>('');
- const [selectedMetrics, setSelectedMetrics] = React.useState<string[]>([]);
-
- const { data: isStandardMode } = useStandardExperienceModeQuery();
-
- const filterSelected = (query: string, selectedElements: string[]) => {
- return selectedElements.filter((element) =>
- getLocalizedMetricNameFromKey(element).toLowerCase().includes(query.toLowerCase()),
- );
- };
-
- const filterMetricsElements = () => {
- const { metricsTypeFilter, metrics, selectedMetrics } = props;
-
- return metrics
- .filter((metric) => {
- if (metric.hidden) {
- return false;
- }
- if (isDiffMetric(metric.key)) {
- return false;
- }
- if ([MetricType.Data, MetricType.Distribution].includes(metric.type as MetricType)) {
- return false;
- }
- if (HIDDEN_METRICS.includes(metric.key as MetricKey)) {
- return false;
- }
- if (
- isStandardMode
- ? MQR_CONDITIONS_MAP[metric.key as MetricKey]
- : STANDARD_CONDITIONS_MAP[metric.key as MetricKey]
- ) {
- return false;
- }
- if (
- selectedMetrics.includes(metric.key) ||
- !getLocalizedMetricName(metric).toLowerCase().includes(query.toLowerCase())
- ) {
- return false;
- }
- if (metricsTypeFilter && metricsTypeFilter.length > 0) {
- return metricsTypeFilter.includes(metric.type);
- }
- return true;
- })
- .map((metric) => metric.key);
- };
-
- const getSelectedMetricsElements = (metrics: Metric[], selectedMetrics: string[]) => {
- return metrics
- .filter(
- (metric) =>
- selectedMetrics.includes(metric.key) &&
- (isStandardMode || !STANDARD_CONDITIONS_MAP[metric.key as MetricKey]),
- )
- .map((metric) => metric.key);
- };
-
- const getLocalizedMetricNameFromKey = (key: string) => {
- const metric = props.metrics.find((m) => m.key === key);
- return metric === undefined ? key : getLocalizedMetricName(metric);
- };
-
- const onSearch = (query: string) => {
- setQuery(query);
- return Promise.resolve();
- };
-
- const onSelect = (metric: string) => {
- props.onAddMetric(metric);
- setSelectedMetrics(sortBy([...selectedMetrics, metric]));
- setMetrics(filterMetricsElements());
- };
-
- const onUnselect = (metric: string) => {
- props.onRemoveMetric(metric);
- setSelectedMetrics(selectedMetrics.filter((selected) => selected !== metric));
- setMetrics(sortBy(metrics, metric));
- };
-
- const filteredMetrics = filterMetricsElements();
- const selectedElements = getSelectedMetricsElements(props.metrics, props.selectedMetrics);
-
- return (
- <Dropdown
- allowResizing
- size="large"
- closeOnClick={false}
- id="activity-graph-custom-metric-selector"
- overlay={
- <AddGraphMetricPopup
- elements={filteredMetrics}
- filterSelected={filterSelected}
- metricsTypeFilter={props.metricsTypeFilter}
- onSearch={onSearch}
- onSelect={onSelect}
- onUnselect={onUnselect}
- selectedElements={selectedElements}
- />
- }
- >
- <Button suffix={<IconChevronDown />}>
- <span className="sw-typo-default sw-flex">
- {translate('project_activity.graphs.custom.add')}
- </span>
- </Button>
- </Dropdown>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/AddGraphMetricPopup.tsx b/server/sonar-web/src/main/js/components/activity-graph/AddGraphMetricPopup.tsx
deleted file mode 100644
index 5cd379f1e2e..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/AddGraphMetricPopup.tsx
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ReactNode } from 'react';
-import { FormattedMessage, useIntl } from 'react-intl';
-import { Badge, FlagMessage, MultiSelectMenu } from '~design-system';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { DEPRECATED_ACTIVITY_METRICS } from '../../helpers/constants';
-import { getLocalizedMetricName, translate, translateWithParameters } from '../../helpers/l10n';
-import { getDeprecatedTranslationKeyForTooltip } from './utils';
-
-export interface AddGraphMetricPopupProps {
- elements: string[];
- filterSelected: (query: string, selectedElements: string[]) => string[];
- metricsTypeFilter?: string[];
- onSearch: (query: string) => Promise<void>;
- onSelect: (item: string) => void;
- onUnselect: (item: string) => void;
- popupPosition?: any;
- selectedElements: string[];
-}
-
-export default function AddGraphMetricPopup({
- elements,
- metricsTypeFilter,
- ...props
-}: Readonly<AddGraphMetricPopupProps>) {
- const intl = useIntl();
- let footerNode: ReactNode = '';
-
- if (props.selectedElements.length >= 6) {
- footerNode = (
- <FlagMessage className="sw-m-2" variant="info">
- {translate('project_activity.graphs.custom.add_metric_info')}
- </FlagMessage>
- );
- } else if (metricsTypeFilter && metricsTypeFilter.length > 0) {
- footerNode = (
- <FlagMessage className="sw-m-2" variant="info">
- {translateWithParameters(
- 'project_activity.graphs.custom.type_x_message',
- metricsTypeFilter
- .map((type: string) => translate('metric.type', type))
- .sort((a, b) => a.localeCompare(b))
- .join(', '),
- )}
- </FlagMessage>
- );
- }
-
- const renderAriaLabel = (key: MetricKey) => {
- const metricName = getLocalizedMetricName({ key });
- const isDeprecated = DEPRECATED_ACTIVITY_METRICS.includes(key);
-
- return isDeprecated
- ? `${metricName} (${intl.formatMessage({ id: 'deprecated' })})`
- : metricName;
- };
-
- const renderLabel = (key: MetricKey) => {
- const metricName = getLocalizedMetricName({ key });
- const isDeprecated = DEPRECATED_ACTIVITY_METRICS.includes(key);
-
- return (
- <>
- {metricName}
- {isDeprecated && (
- <Badge className="sw-ml-1">{intl.formatMessage({ id: 'deprecated' })}</Badge>
- )}
- </>
- );
- };
-
- const renderTooltip = (key: MetricKey) => {
- const isDeprecated = DEPRECATED_ACTIVITY_METRICS.includes(key);
- if (isDeprecated) {
- return <FormattedMessage id={getDeprecatedTranslationKeyForTooltip(key)} tagName="div" />;
- }
-
- return null;
- };
- return (
- <MultiSelectMenu
- createElementLabel=""
- searchInputAriaLabel={translate('project_activity.graphs.custom.select_metric')}
- allowNewElements={false}
- allowSelection={props.selectedElements.length < 6}
- elements={elements}
- filterSelected={props.filterSelected}
- footerNode={footerNode}
- noResultsLabel={translateWithParameters('no_results')}
- onSearch={props.onSearch}
- onSelect={(item: string) => elements.includes(item) && props.onSelect(item)}
- onUnselect={props.onUnselect}
- placeholder={translate('search.search_for_metrics')}
- renderAriaLabel={renderAriaLabel}
- renderTooltip={renderTooltip}
- renderLabel={renderLabel}
- selectedElements={props.selectedElements}
- listSize={0}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/ChartLegend.tsx b/server/sonar-web/src/main/js/components/activity-graph/ChartLegend.tsx
deleted file mode 100644
index 75b9d5b2f93..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/ChartLegend.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import classNames from 'classnames';
-import { Theme, themeColor } from '~design-system';
-import { LINE_CHART_DASHES } from './utils';
-
-interface Props {
- className?: string;
- index: number;
-}
-
-export function ChartLegend({ index, className }: Readonly<Props>) {
- const theme = useTheme() as Theme;
-
- return (
- <svg
- className={className}
- clipRule="evenodd"
- fillRule="evenodd"
- height={16}
- strokeMiterlimit={1.41421}
- viewBox="0 0 16 16"
- width={16}
- xmlSpace="preserve"
- xmlnsXlink="http://www.w3.org/1999/xlink"
- >
- <path
- className={classNames('line-chart-path', `line-chart-path-${index}`)}
- d="M0 8 L 16 8"
- style={{
- stroke: themeColor(`graphLineColor.${index}` as Parameters<typeof themeColor>[0])({
- theme,
- }),
- strokeDasharray: LINE_CHART_DASHES[index],
- }}
- />
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/DataTableModal.tsx b/server/sonar-web/src/main/js/components/activity-graph/DataTableModal.tsx
deleted file mode 100644
index f4bd358181b..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/DataTableModal.tsx
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { filter, slice, sortBy } from 'lodash';
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { FlagMessage, Modal } from '~design-system';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { ParsedAnalysis, Serie } from '../../types/project-activity';
-import DateFormatter from '../intl/DateFormatter';
-import TimeFormatter from '../intl/TimeFormatter';
-import EventInner from './EventInner';
-import { getAnalysisEventsForDate } from './utils';
-
-export interface DataTableModalProps {
- analyses: ParsedAnalysis[];
- graphEndDate?: Date;
- graphStartDate?: Date;
- onClose: () => void;
- series: Serie[];
-}
-
-type DataTableEntry = { date: Date } & { [x: string]: string | undefined };
-
-export const MAX_DATA_TABLE_ROWS = 100;
-
-export default function DataTableModal(props: DataTableModalProps) {
- const { analyses, series, graphEndDate, graphStartDate } = props;
-
- if (series.length === 0) {
- return renderModal(
- props,
- <FlagMessage variant="warning">
- {translate('project_activity.graphs.data_table.no_data_warning')}
- </FlagMessage>,
- );
- }
-
- const tableData = series.reduce(
- (acc, serie) => {
- const data = filter(
- serie.data,
- // Make sure we respect the date filtering. On the graph, this is done by dynamically
- // "zooming" on the series. Here, we actually have to "cut off" part of the serie's
- // data points.
- ({ x }) => {
- if (graphEndDate && x > graphEndDate) {
- return false;
- }
- if (graphStartDate && x < graphStartDate) {
- return false;
- }
- return true;
- },
- );
-
- data.forEach(({ x, y }) => {
- const key = x.getTime();
- if (acc[key] === undefined) {
- acc[key] = { date: x } as DataTableEntry;
- }
-
- if (y !== undefined && !(typeof y === 'number' && isNaN(y))) {
- acc[key][serie.name] = formatMeasure(y, serie.type);
- }
- });
-
- return acc;
- },
- {} as { [x: number]: DataTableEntry },
- );
-
- const metrics = series.map(({ name }) => name);
- const rows = slice(
- sortBy(Object.values(tableData), ({ date }) => -date),
- 0,
- MAX_DATA_TABLE_ROWS,
- ).map(({ date, ...values }) => (
- <tr key={date.getTime()}>
- <td className="sw-whitespace-nowrap">
- <DateFormatter long date={date} />
- <div className="sw-text-xs">
- <TimeFormatter date={date} />
- </div>
- </td>
- {metrics.map((metric) => (
- <td key={metric} className="sw-whitespace-nowrap sw-w-20">
- {values[metric] ?? '-'}
- </td>
- ))}
- <td>
- <ul>
- {getAnalysisEventsForDate(analyses, date).map((event) => (
- <li className="sw-mb-1" key={event.key}>
- <EventInner event={event} readonly />
- </li>
- ))}
- </ul>
- </td>
- </tr>
- ));
-
- const rowCount = rows.length;
-
- if (rowCount === 0) {
- const start = graphStartDate && <DateFormatter long date={graphStartDate} />;
- const end = graphEndDate && <DateFormatter long date={graphEndDate} />;
- let suffix = '';
- if (start && end) {
- suffix = '_x_y';
- } else if (start) {
- suffix = '_x';
- } else if (end) {
- suffix = '_y';
- }
- return renderModal(
- props,
- <FlagMessage variant="warning">
- <FormattedMessage
- defaultMessage={translate(
- `project_activity.graphs.data_table.no_data_warning_check_dates${suffix}`,
- )}
- id={`project_activity.graphs.data_table.no_data_warning_check_dates${suffix}`}
- values={{ start, end }}
- />
- </FlagMessage>,
- );
- }
-
- return renderModal(
- props,
- <>
- {rowCount === MAX_DATA_TABLE_ROWS && (
- <FlagMessage variant="warning">
- {translateWithParameters(
- 'project_activity.graphs.data_table.max_lines_warning',
- MAX_DATA_TABLE_ROWS,
- )}
- </FlagMessage>
- )}
- <StyledTable className="sw-mt-2">
- <thead>
- <tr>
- <th>{translate('date')}</th>
- {series.map((serie) => (
- <th key={serie.name} className="sw-whitespace-nowrap sw-w-20">
- {serie.translatedName}
- </th>
- ))}
- <th>{translate('events')}</th>
- </tr>
- </thead>
- <tbody>{rows}</tbody>
- </StyledTable>
- </>,
- );
-}
-
-function renderModal(props: DataTableModalProps, children: React.ReactNode) {
- const heading = translate('project_activity.graphs.data_table.title');
- return (
- <Modal
- headerTitle={heading}
- isLarge
- onClose={props.onClose}
- body={children}
- primaryButton={null}
- secondaryButtonLabel={translate('close')}
- />
- );
-}
-
-const StyledTable = styled.table`
- width: 100%;
- & > thead > tr > th {
- position: relative;
- vertical-align: top;
- line-height: 18px;
- padding: 8px 10px;
- border-bottom: 1px solid #e6e6e6;
- font-weight: 600;
- }
-
- & > thead > tr > th > .small {
- display: block;
- line-height: 1.4;
- font-weight: 400;
- }
-
- & > tfoot > tr > td {
- font-size: 93%;
- color: #656565;
- padding: 5px;
- }
-
- & > tbody > tr > td {
- position: relative;
- padding: 8px 10px;
- line-height: 16px;
- }
-
- & > tbody > tr > td.text-middle {
- vertical-align: middle;
- }
-`;
diff --git a/server/sonar-web/src/main/js/components/activity-graph/DefinitionChangeEventInner.tsx b/server/sonar-web/src/main/js/components/activity-graph/DefinitionChangeEventInner.tsx
deleted file mode 100644
index 6b1ae083052..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/DefinitionChangeEventInner.tsx
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { BareButton, BranchIcon, ChevronDownIcon, Note, StandoutLink } from '~design-system';
-import { isMainBranch } from '~sonar-aligned/helpers/branch-like';
-import { translate } from '../../helpers/l10n';
-import { getProjectUrl } from '../../helpers/urls';
-import { BranchLike } from '../../types/branch-like';
-import {
- AnalysisEvent,
- ApplicationAnalysisEventCategory,
- DefinitionChangeType,
-} from '../../types/project-activity';
-import ClickEventBoundary from '../controls/ClickEventBoundary';
-
-export type DefinitionChangeEvent = AnalysisEvent &
- Required<Pick<AnalysisEvent, 'definitionChange'>>;
-
-export function isDefinitionChangeEvent(event: AnalysisEvent): event is DefinitionChangeEvent {
- return (
- event.category === ApplicationAnalysisEventCategory.DefinitionChange &&
- event.definitionChange !== undefined
- );
-}
-
-interface Props {
- branchLike: BranchLike | undefined;
- event: DefinitionChangeEvent;
- readonly?: boolean;
-}
-
-interface State {
- expanded: boolean;
-}
-
-export class DefinitionChangeEventInner extends React.PureComponent<Props, State> {
- state: State = { expanded: false };
-
- toggleProjectsList = () => {
- this.setState((state) => ({ expanded: !state.expanded }));
- };
-
- renderProjectLink = (project: { key: string; name: string }, branch: string | undefined) => (
- <ClickEventBoundary>
- <StandoutLink
- className="sw-truncate sw-mr-1"
- title={project.name}
- to={getProjectUrl(project.key, branch)}
- >
- {project.name}
- </StandoutLink>
- </ClickEventBoundary>
- );
-
- renderBranch = (branch = translate('branches.main_branch')) => (
- <span className="sw-flex sw-items-center sw-mr-1" title={branch}>
- <BranchIcon className="sw-ml-1" />
- {branch}
- </span>
- );
-
- renderProjectChange(project: {
- branch?: string;
- changeType: DefinitionChangeType;
- key: string;
- name: string;
- newBranch?: string;
- oldBranch?: string;
- }) {
- const mainBranch = !this.props.branchLike || isMainBranch(this.props.branchLike);
-
- switch (project.changeType) {
- case DefinitionChangeType.Added: {
- const message = mainBranch
- ? 'event.definition_change.added'
- : 'event.definition_change.branch_added';
- return (
- <FormattedMessage
- defaultMessage={translate(message)}
- id={message}
- values={{
- project: this.renderProjectLink(project, project.branch),
- branch: this.renderBranch(project.branch),
- }}
- />
- );
- }
-
- case DefinitionChangeType.Removed: {
- const message = mainBranch
- ? 'event.definition_change.removed'
- : 'event.definition_change.branch_removed';
- return (
- <FormattedMessage
- defaultMessage={translate(message)}
- id={message}
- values={{
- project: this.renderProjectLink(project, project.branch),
- branch: this.renderBranch(project.branch),
- }}
- />
- );
- }
-
- case DefinitionChangeType.BranchChanged:
- return (
- <FormattedMessage
- defaultMessage={translate('event.definition_change.branch_replaced')}
- id="event.definition_change.branch_replaced"
- values={{
- project: this.renderProjectLink(project, project.newBranch),
- oldBranch: this.renderBranch(project.oldBranch),
- newBranch: this.renderBranch(project.newBranch),
- }}
- />
- );
- }
- }
-
- render() {
- const { event, readonly } = this.props;
- const { expanded } = this.state;
- return (
- <div className="sw-w-full sw-typo-default sw-py-1/2">
- <div className="sw-flex sw-justify-between">
- <Note className="sw-mr-1 sw-typo-semibold">
- {translate('event.category', event.category)}
- </Note>
-
- {!readonly && (
- <ClickEventBoundary>
- <BareButton
- className="sw-flex sw-items-center sw-ml-2"
- onClick={this.toggleProjectsList}
- >
- {expanded ? translate('hide') : translate('more')}
- <ChevronDownIcon transform={expanded ? 'rotate(180)' : undefined} />
- </BareButton>
- </ClickEventBoundary>
- )}
- </div>
-
- {expanded && (
- <ul className="sw-mt-2">
- {event.definitionChange.projects.map((project) => (
- <li className="sw-flex sw-items-center sw-flex-wrap sw-p-1 sw-mb-1" key={project.key}>
- {this.renderProjectChange(project)}
- </li>
- ))}
- </ul>
- )}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/EventInner.tsx b/server/sonar-web/src/main/js/components/activity-graph/EventInner.tsx
deleted file mode 100644
index 6fa0899a2a4..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/EventInner.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Tooltip } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { Note } from '~design-system';
-import { ComponentContext } from '../../app/components/componentContext/ComponentContext';
-import { translate } from '../../helpers/l10n';
-import { useCurrentBranchQuery } from '../../queries/branch';
-import { StaleTime } from '../../queries/common';
-import { AnalysisEvent, ProjectAnalysisEventCategory } from '../../types/project-activity';
-import { DefinitionChangeEventInner, isDefinitionChangeEvent } from './DefinitionChangeEventInner';
-import { RichQualityGateEventInner, isRichQualityGateEvent } from './RichQualityGateEventInner';
-import {
- RichQualityProfileEventInner,
- isRichQualityProfileEvent,
-} from './RichQualityProfileEventInner';
-import { SqUpgradeActivityEventMessage } from './SqUpgradeActivityEventMessage';
-
-export interface EventInnerProps {
- event: AnalysisEvent;
- readonly?: boolean;
-}
-
-export default function EventInner({ event, readonly }: EventInnerProps) {
- const { component } = React.useContext(ComponentContext);
- const { data: branchLike } = useCurrentBranchQuery(component, StaleTime.LONG);
- if (isRichQualityGateEvent(event)) {
- return <RichQualityGateEventInner event={event} readonly={readonly} />;
- } else if (isDefinitionChangeEvent(event)) {
- return <DefinitionChangeEventInner branchLike={branchLike} event={event} readonly={readonly} />;
- } else if (isRichQualityProfileEvent(event)) {
- return (
- <div>
- <Note className="sw-mr-1 sw-typo-semibold">
- {translate('event.category', event.category)}
- </Note>
- <Note>
- <RichQualityProfileEventInner event={event} />
- </Note>
- </div>
- );
- } else if (event.category === ProjectAnalysisEventCategory.SqUpgrade) {
- return <SqUpgradeActivityEventMessage event={event} />;
- }
-
- const tooltipContent =
- event.category && event.category === 'QUALITY_GATE' && event.description
- ? `${translate('event.failed_conditions')} ${event.description}`
- : event.description;
-
- return (
- <Tooltip content={tooltipContent}>
- <div className="sw-min-w-0 sw-flex-1 sw-py-1/2">
- <div className="sw-flex sw-items-start">
- <span>
- <Note className="sw-mr-1 sw-typo-semibold">
- {translate('event.category', event.category)}
- {event.category === 'VERSION' && ':'}
- </Note>
- <Note className="sw-typo-default" title={event.description}>
- {event.name}
- </Note>
- </span>
- </div>
- </div>
- </Tooltip>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphHistory.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphHistory.tsx
deleted file mode 100644
index d287575cefc..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphHistory.tsx
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import * as React from 'react';
-import { useIntl } from 'react-intl';
-import { AutoSizer } from 'react-virtualized/dist/commonjs/AutoSizer';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { AdvancedTimeline } from '../../components/charts/AdvancedTimeline';
-import { KeyboardKeys } from '../../helpers/keycodes';
-import { getShortType } from '../../helpers/measures';
-import { MeasureHistory, ParsedAnalysis, Serie } from '../../types/project-activity';
-import DataTableModal from './DataTableModal';
-import GraphsLegendCustom from './GraphsLegendCustom';
-import GraphsLegendStatic from './GraphsLegendStatic';
-import { GraphsTooltips } from './GraphsTooltips';
-import { getAnalysisEventsForDate } from './utils';
-
-interface Props {
- analyses: ParsedAnalysis[];
- canShowDataAsTable?: boolean;
- graph: string;
- graphDescription: string;
- graphEndDate?: Date;
- graphStartDate?: Date;
- isCustom?: boolean;
- leakPeriodDate?: Date;
- measuresHistory: MeasureHistory[];
- metricsType: string;
- removeCustomMetric?: (metric: string) => void;
- selectedDate?: Date;
- series: Serie[];
- showAreas: boolean;
- updateGraphZoom?: (from?: Date, to?: Date) => void;
- updateSelectedDate?: (selectedDate?: Date) => void;
- updateTooltip: (selectedDate?: Date) => void;
-}
-
-export default function GraphHistory(props: Readonly<Props>) {
- const {
- analyses,
- canShowDataAsTable = true,
- graph,
- graphEndDate,
- graphStartDate,
- isCustom,
- leakPeriodDate,
- measuresHistory,
- metricsType,
- selectedDate,
- series,
- showAreas,
- graphDescription,
- } = props;
- const intl = useIntl();
- const [tooltipIdx, setTooltipIdx] = React.useState<number | undefined>(undefined);
- const [tooltipXPos, setTooltipXPos] = React.useState<number | undefined>(undefined);
- const [tableIsVisible, setTableIsVisible] = React.useState(false);
-
- const formatValue = (tick: string | number) => {
- return formatMeasure(tick, getShortType(metricsType));
- };
-
- const formatTooltipValue = (tick: string | number) => {
- return formatMeasure(tick, metricsType);
- };
-
- const updateTooltip = (selectedDate?: Date, tooltipXPos?: number, tooltipIdx?: number) => {
- props.updateTooltip(selectedDate);
- setTooltipIdx(tooltipIdx);
- setTooltipXPos(tooltipXPos);
- };
-
- const events = getAnalysisEventsForDate(analyses, selectedDate);
-
- return (
- <>
- <StyledGraphContainer
- tabIndex={canShowDataAsTable ? 0 : -1}
- aria-label={`${intl.formatMessage(
- { id: 'project_activity.graphs.graph_shown_x' },
- { '0': isCustom ? series.map((s) => s.translatedName).join(',') : graph },
- )} ${intl.formatMessage({ id: 'project_activity.graphs.open_in_table' })}`}
- onKeyUp={(event) => {
- if (event.key === KeyboardKeys.Enter) {
- setTableIsVisible(true);
- }
- }}
- className="sw-flex sw-flex-col sw-justify-center sw-items-stretch sw-grow sw-py-2"
- >
- {isCustom && props.removeCustomMetric ? (
- <GraphsLegendCustom
- leakPeriodDate={leakPeriodDate}
- removeMetric={props.removeCustomMetric}
- series={series}
- />
- ) : (
- <GraphsLegendStatic leakPeriodDate={leakPeriodDate} series={series} />
- )}
-
- <div className="sw-flex-1">
- <AutoSizer>
- {({ height, width }) => (
- <div>
- <AdvancedTimeline
- endDate={graphEndDate}
- formatYTick={formatValue}
- height={height}
- leakPeriodDate={leakPeriodDate}
- splitPointDate={measuresHistory.find((m) => m.splitPointDate)?.splitPointDate}
- metricType={metricsType}
- selectedDate={selectedDate}
- series={series}
- showAreas={showAreas}
- startDate={graphStartDate}
- graphDescription={graphDescription}
- updateSelectedDate={props.updateSelectedDate}
- updateTooltip={updateTooltip}
- updateZoom={props.updateGraphZoom}
- width={width}
- />
-
- {selectedDate !== undefined &&
- tooltipIdx !== undefined &&
- tooltipXPos !== undefined && (
- <GraphsTooltips
- events={events}
- formatValue={formatTooltipValue}
- graph={graph}
- graphWidth={width}
- measuresHistory={measuresHistory}
- selectedDate={selectedDate}
- series={series}
- tooltipIdx={tooltipIdx}
- tooltipPos={tooltipXPos}
- />
- )}
- </div>
- )}
- </AutoSizer>
- </div>
- </StyledGraphContainer>
- {tableIsVisible && (
- <DataTableModal
- analyses={analyses}
- graphEndDate={graphEndDate}
- graphStartDate={graphStartDate}
- series={series}
- onClose={() => setTableIsVisible(false)}
- />
- )}
- </>
- );
-}
-
-const StyledGraphContainer = styled.section`
- height: 300px;
-`;
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsHeader.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsHeader.tsx
deleted file mode 100644
index 35d1150b9cd..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphsHeader.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ButtonGroup, InputSize, Select } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { translate } from '../../helpers/l10n';
-import { GraphType } from '../../types/project-activity';
-import { Metric } from '../../types/types';
-import AddGraphMetric from './AddGraphMetric';
-import { getGraphTypes, isCustomGraph } from './utils';
-
-interface Props {
- className?: string;
- graph: GraphType;
- metrics: Metric[];
- metricsTypeFilter?: string[];
- onAddCustomMetric?: (metric: string) => void;
- onRemoveCustomMetric?: (metric: string) => void;
- onUpdateGraph: (graphType: string) => void;
- selectedMetrics?: string[];
-}
-
-export default function GraphsHeader(props: Readonly<Props>) {
- const {
- className,
- graph,
- metrics,
- metricsTypeFilter,
- onUpdateGraph,
- selectedMetrics = [],
- } = props;
-
- const handleGraphChange = React.useCallback(
- (value: GraphType) => {
- if (value !== graph) {
- onUpdateGraph(value);
- }
- },
- [graph, onUpdateGraph],
- );
-
- const noCustomGraph =
- props.onAddCustomMetric === undefined || props.onRemoveCustomMetric === undefined;
-
- return (
- <div className={className}>
- <ButtonGroup>
- <label htmlFor="graph-type" className="sw-typo-semibold">
- {translate('project_activity.graphs.choose_type')}
- </label>
- <Select
- id="graph-type"
- hasDropdownAutoWidth
- onChange={handleGraphChange}
- isNotClearable
- value={graph}
- size={InputSize.Small}
- data={getGraphTypes(noCustomGraph).map((type) => ({
- value: type,
- label: translate('project_activity.graphs', type),
- }))}
- />
-
- {isCustomGraph(graph) &&
- props.onAddCustomMetric !== undefined &&
- props.onRemoveCustomMetric !== undefined && (
- <AddGraphMetric
- onAddMetric={props.onAddCustomMetric}
- metrics={metrics}
- metricsTypeFilter={metricsTypeFilter}
- onRemoveMetric={props.onRemoveCustomMetric}
- selectedMetrics={selectedMetrics}
- />
- )}
- </ButtonGroup>
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsHistory.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsHistory.tsx
deleted file mode 100644
index e7a09e7d41e..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphsHistory.tsx
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Spinner, Text } from '@sonarsource/echoes-react';
-import { isEqual, uniqBy } from 'lodash';
-import * as React from 'react';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { GraphType, MeasureHistory, ParsedAnalysis, Serie } from '../../types/project-activity';
-import GraphHistory from './GraphHistory';
-import { getSeriesMetricType, hasHistoryData, isCustomGraph } from './utils';
-
-interface Props {
- analyses: ParsedAnalysis[];
- ariaLabel?: string;
- canShowDataAsTable?: boolean;
- graph: GraphType;
- graphEndDate?: Date;
- graphStartDate?: Date;
- graphs: Serie[][];
- leakPeriodDate?: Date;
- loading: boolean;
- measuresHistory: MeasureHistory[];
- removeCustomMetric?: (metric: string) => void;
- selectedDate?: Date;
- series: Serie[];
- updateGraphZoom?: (from?: Date, to?: Date) => void;
- updateSelectedDate?: (selectedDate?: Date) => void;
-}
-
-interface State {
- selectedDate?: Date;
-}
-
-export default class GraphsHistory extends React.PureComponent<Props, State> {
- constructor(props: Props) {
- super(props);
- this.state = {
- selectedDate: props.selectedDate,
- };
- }
-
- componentDidUpdate(prevProps: Props) {
- if (!isEqual(prevProps.selectedDate, this.props.selectedDate)) {
- this.setState({ selectedDate: this.props.selectedDate });
- }
- }
-
- updateTooltip = (selectedDate?: Date) => {
- this.setState({ selectedDate });
- };
-
- render() {
- const { analyses, graph, loading, series, ariaLabel, canShowDataAsTable } = this.props;
- const isCustom = isCustomGraph(graph);
- const showAreas = [GraphType.coverage, GraphType.duplications].includes(graph);
-
- return (
- <div className="sw-flex sw-justify-center sw-flex-col sw-items-stretch sw-text-center sw-grow">
- <output aria-busy={loading}>
- <Spinner isLoading={loading}>
- {!hasHistoryData(series) && (
- <Text isSubdued className="sw-max-w-full">
- {translate(
- isCustom
- ? 'project_activity.graphs.custom.no_history'
- : 'component_measures.no_history',
- )}
- </Text>
- )}
- </Spinner>
- </output>
-
- {hasHistoryData(series) && !loading && (
- <>
- {this.props.graphs.map((graphSeries, idx) => {
- return (
- <GraphHistory
- analyses={analyses}
- canShowDataAsTable={canShowDataAsTable}
- graph={graph}
- graphEndDate={this.props.graphEndDate}
- graphStartDate={this.props.graphStartDate}
- isCustom={isCustom}
- key={idx}
- leakPeriodDate={this.props.leakPeriodDate}
- measuresHistory={this.props.measuresHistory}
- metricsType={getSeriesMetricType(graphSeries)}
- removeCustomMetric={this.props.removeCustomMetric}
- selectedDate={this.state.selectedDate}
- series={graphSeries}
- graphDescription={
- ariaLabel ??
- translateWithParameters(
- 'project_activity.graphs.explanation_x',
- uniqBy(graphSeries, 'name')
- .map(({ translatedName }) => translatedName)
- .join(', '),
- )
- }
- showAreas={showAreas}
- updateGraphZoom={this.props.updateGraphZoom}
- updateSelectedDate={this.props.updateSelectedDate}
- updateTooltip={this.updateTooltip}
- />
- );
- })}
- </>
- )}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendCustom.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendCustom.tsx
deleted file mode 100644
index 0bd125dc767..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendCustom.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { NewCodeLegend } from '~design-system';
-import Tooltip from '../../components/controls/Tooltip';
-import { translate } from '../../helpers/l10n';
-import { Serie } from '../../types/project-activity';
-import { GraphsLegendItem } from './GraphsLegendItem';
-import { hasDataValues } from './utils';
-
-export interface GraphsLegendCustomProps {
- leakPeriodDate?: Date;
- removeMetric: (metric: string) => void;
- series: Serie[];
-}
-
-export default function GraphsLegendCustom(props: GraphsLegendCustomProps) {
- const { leakPeriodDate, series, removeMetric } = props;
-
- return (
- <ul className="activity-graph-legends sw-flex sw-justify-center sw-items-center sw-pb-4">
- {series.map((serie, idx) => {
- const hasData = hasDataValues(serie);
-
- const legendItem = (
- <GraphsLegendItem
- index={idx}
- metric={serie.name}
- name={serie.translatedName}
- removeMetric={removeMetric}
- showWarning={!hasData}
- />
- );
-
- if (!hasData) {
- return (
- <Tooltip
- key={serie.name}
- content={translate('project_activity.graphs.custom.metric_no_history')}
- >
- <li
- className="sw-mx-2"
- aria-label={translate('project_activity.graphs.custom.metric_no_history')}
- >
- {legendItem}
- </li>
- </Tooltip>
- );
- }
-
- return (
- <li className="sw-ml-3" key={serie.name}>
- {legendItem}
- </li>
- );
- })}
- {leakPeriodDate && (
- <li key={translate('hotspot.filters.period.since_leak_period')}>
- <NewCodeLegend
- className="sw-ml-3 sw-mr-4"
- text={translate('hotspot.filters.period.since_leak_period')}
- />
- </li>
- )}
- </ul>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendItem.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendItem.tsx
deleted file mode 100644
index d9ae9ae663b..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendItem.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { ButtonIcon, ButtonSize, IconWarning, IconX } from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import { themeBorder } from '~design-system';
-import { translateWithParameters } from '../../helpers/l10n';
-import { ChartLegend } from './ChartLegend';
-
-interface Props {
- className?: string;
- index: number;
- metric: string;
- name: string;
- removeMetric?: (metric: string) => void;
- showWarning?: boolean;
-}
-
-export function GraphsLegendItem({
- className,
- index,
- metric,
- name,
- removeMetric,
- showWarning,
-}: Readonly<Props>) {
- const isActionable = removeMetric !== undefined;
-
- return (
- <StyledLegendItem
- className={classNames('sw-px-2 sw-py-1 sw-rounded-2', className)}
- isActionable={isActionable}
- >
- {showWarning ? (
- <IconWarning color="echoes-color-icon-warning" className="sw-mr-2" />
- ) : (
- <ChartLegend className="sw-mr-2" index={index} />
- )}
- <span className="sw-typo-default" style={{ color: 'var(--echoes-color-text-subdued)' }}>
- {name}
- </span>
- {isActionable && (
- <ButtonIcon
- size={ButtonSize.Medium}
- Icon={IconX}
- ariaLabel={translateWithParameters('project_activity.graphs.custom.remove_metric', name)}
- className="sw-ml-2 sw-border-0"
- onClick={() => removeMetric(metric)}
- />
- )}
- </StyledLegendItem>
- );
-}
-
-interface GraphPillsProps {
- isActionable: boolean;
-}
-
-const StyledLegendItem = styled.div<GraphPillsProps>`
- display: flex;
- align-items: center;
- border: ${(props) =>
- props.isActionable ? themeBorder('default', 'buttonSecondaryBorder') : 'none'};
-`;
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendStatic.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendStatic.tsx
deleted file mode 100644
index 00f64d7328b..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendStatic.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { NewCodeLegend } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { Serie } from '../../types/project-activity';
-import { GraphsLegendItem } from './GraphsLegendItem';
-
-export interface GraphsLegendStaticProps {
- leakPeriodDate?: Date;
- series: Array<Pick<Serie, 'name' | 'translatedName'>>;
-}
-
-export default function GraphsLegendStatic({
- series,
- leakPeriodDate,
-}: Readonly<GraphsLegendStaticProps>) {
- return (
- <ul className="activity-graph-legends sw-flex sw-justify-center sw-items-center sw-pb-4">
- {series.map((serie, idx) => (
- <li key={serie.name}>
- <GraphsLegendItem
- className="sw-mx-2"
- index={idx}
- metric={serie.name}
- name={serie.translatedName}
- />
- </li>
- ))}
- {leakPeriodDate && (
- <li key={translate('hotspot.filters.period.since_leak_period')}>
- <NewCodeLegend
- className="sw-mr-2"
- text={translate('hotspot.filters.period.since_leak_period')}
- />
- </li>
- )}
- </ul>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltips.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltips.tsx
deleted file mode 100644
index 8331a1138dd..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltips.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Table, TableSeparator, ThemeProp, themeColor, withTheme } from '~design-system';
-import { Popup, PopupPlacement } from '../../components/ui/popups';
-import { isDefined } from '../../helpers/types';
-import { AnalysisEvent, GraphType, MeasureHistory, Serie } from '../../types/project-activity';
-import DateTimeFormatter from '../intl/DateTimeFormatter';
-import GraphsTooltipsContent from './GraphsTooltipsContent';
-import GraphsTooltipsContentCoverage from './GraphsTooltipsContentCoverage';
-import GraphsTooltipsContentDuplication from './GraphsTooltipsContentDuplication';
-import GraphsTooltipsContentEvents from './GraphsTooltipsContentEvents';
-
-interface PropsWithoutTheme {
- events: AnalysisEvent[];
- formatValue: (tick: number | string) => string;
- graph: string;
- graphWidth: number;
- measuresHistory: MeasureHistory[];
- selectedDate: Date;
- series: Serie[];
- tooltipIdx: number;
- tooltipPos: number;
-}
-
-export type Props = PropsWithoutTheme & ThemeProp;
-
-const TOOLTIP_WIDTH = 280;
-const TOOLTIP_LEFT_MARGIN = 60;
-const TOOLTIP_LEFT_FLIP_THRESHOLD = 50;
-
-const COLUMNS = 3;
-
-export class GraphsTooltipsClass extends React.PureComponent<Props> {
- renderContent() {
- const { tooltipIdx, series } = this.props;
-
- return series.map((serie, idx) => {
- const point = serie.data[tooltipIdx];
-
- if (!point || (!point.y && point.y !== 0)) {
- return null;
- }
-
- return (
- <GraphsTooltipsContent
- index={idx}
- key={serie.name}
- name={serie.name}
- translatedName={serie.translatedName}
- value={this.props.formatValue(point.y)}
- />
- );
- });
- }
-
- render() {
- const {
- events,
- measuresHistory,
- tooltipIdx,
- tooltipPos,
- graph,
- graphWidth,
- selectedDate,
- theme,
- } = this.props;
-
- const top = 30;
- let left = tooltipPos + TOOLTIP_LEFT_MARGIN;
- let placement = PopupPlacement.RightTop;
-
- if (left > graphWidth - TOOLTIP_WIDTH - TOOLTIP_LEFT_FLIP_THRESHOLD) {
- left -= TOOLTIP_WIDTH;
- placement = PopupPlacement.LeftTop;
- }
-
- const tooltipContent = this.renderContent().filter(isDefined);
- const addSeparator = tooltipContent.length > 0;
-
- return (
- <Popup
- className="sw-pointer-events-none"
- noArrow
- placement={placement}
- style={{ top, left, width: TOOLTIP_WIDTH }}
- >
- <div className="sw-p-2">
- <div
- className="sw-typo-lg-semibold sw-whitespace-nowrap"
- style={{ color: themeColor('selectionCardHeader')({ theme }) }}
- >
- <DateTimeFormatter date={selectedDate} />
- </div>
- <Table
- columnCount={COLUMNS}
- noHeaderTopBorder
- style={{ color: 'var(--echoes-color-text-subdued)' }}
- >
- {addSeparator && <TableSeparator />}
- {events?.length > 0 && (
- <GraphsTooltipsContentEvents addSeparator={addSeparator} events={events} />
- )}
- {tooltipContent}
- {graph === GraphType.coverage && (
- <GraphsTooltipsContentCoverage
- addSeparator={addSeparator}
- measuresHistory={measuresHistory}
- tooltipIdx={tooltipIdx}
- />
- )}
- {graph === GraphType.duplications && (
- <GraphsTooltipsContentDuplication
- addSeparator={addSeparator}
- measuresHistory={measuresHistory}
- tooltipIdx={tooltipIdx}
- />
- )}
- </Table>
- </div>
- </Popup>
- );
- }
-}
-
-export const GraphsTooltips = withTheme<PropsWithoutTheme>(GraphsTooltipsClass);
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContent.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContent.tsx
deleted file mode 100644
index c8bbc38cd96..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContent.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ChartLegend } from './ChartLegend';
-
-interface Props {
- index: number;
- name: string;
- translatedName: string;
- value: string;
-}
-
-export default function GraphsTooltipsContent({ name, index, translatedName, value }: Props) {
- return (
- <tr className="sw-h-8" key={name}>
- <td className="thin">
- <ChartLegend className="sw-mr-2" index={index} />
- </td>
- <td className="sw-font-bold sw-text-right sw-pr-2 thin">{value}</td>
- <td>{translatedName}</td>
- </tr>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentCoverage.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentCoverage.tsx
deleted file mode 100644
index 297f596e995..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentCoverage.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { TableSeparator } from '~design-system';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import { translate } from '../../helpers/l10n';
-import { MeasureHistory } from '../../types/project-activity';
-
-export interface GraphsTooltipsContentCoverageProps {
- addSeparator: boolean;
- measuresHistory: MeasureHistory[];
- tooltipIdx: number;
-}
-
-export default function GraphsTooltipsContentCoverage(props: GraphsTooltipsContentCoverageProps) {
- const { addSeparator, measuresHistory, tooltipIdx } = props;
- const uncovered = measuresHistory.find((measure) => measure.metric === MetricKey.uncovered_lines);
- const coverage = measuresHistory.find((measure) => measure.metric === MetricKey.coverage);
- if (!uncovered?.history[tooltipIdx] || !coverage?.history[tooltipIdx]) {
- return null;
- }
- const uncoveredValue = uncovered.history[tooltipIdx].value;
- const coverageValue = coverage.history[tooltipIdx].value;
- return (
- <>
- {addSeparator && <TableSeparator />}
- {uncoveredValue && (
- <tr className="sw-h-8">
- <td className="sw-font-bold sw-text-right sw-pr-2 thin" colSpan={2}>
- {formatMeasure(uncoveredValue, MetricType.ShortInteger)}
- </td>
- <td>{translate('metric.uncovered_lines.name')}</td>
- </tr>
- )}
- {coverageValue && (
- <tr className="sw-h-8">
- <td className="sw-font-bold sw-text-right sw-pr-2 thin" colSpan={2}>
- {formatMeasure(coverageValue, MetricType.Percent)}
- </td>
- <td>{translate('metric.coverage.name')}</td>
- </tr>
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentDuplication.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentDuplication.tsx
deleted file mode 100644
index c7ef5149a33..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentDuplication.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { TableSeparator } from '~design-system';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import { translate } from '../../helpers/l10n';
-import { MeasureHistory } from '../../types/project-activity';
-
-export interface GraphsTooltipsContentDuplicationProps {
- addSeparator: boolean;
- measuresHistory: MeasureHistory[];
- tooltipIdx: number;
-}
-
-export default function GraphsTooltipsContentDuplication(
- props: Readonly<GraphsTooltipsContentDuplicationProps>,
-) {
- const { addSeparator, measuresHistory, tooltipIdx } = props;
- const duplicationDensity = measuresHistory.find(
- (measure) => measure.metric === MetricKey.duplicated_lines_density,
- );
- if (!duplicationDensity?.history[tooltipIdx]) {
- return null;
- }
- const duplicationDensityValue = duplicationDensity.history[tooltipIdx].value;
- if (!duplicationDensityValue) {
- return null;
- }
- return (
- <>
- {addSeparator && <TableSeparator />}
- <tr className="sw-h-8">
- <td className="sw-font-bold sw-text-right sw-pr-2 thin" colSpan={2}>
- {formatMeasure(duplicationDensityValue, MetricType.Percent)}
- </td>
- <td>{translate('metric.duplicated_lines_density.name')}</td>
- </tr>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentEvents.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentEvents.tsx
deleted file mode 100644
index 1c7b6deb38b..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentEvents.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { TableSeparator } from '~design-system';
-import { AnalysisEvent } from '../../types/project-activity';
-import EventInner from './EventInner';
-
-interface Props {
- addSeparator: boolean;
- events: AnalysisEvent[];
-}
-
-export default function GraphsTooltipsContentEvents({ addSeparator, events }: Props) {
- return (
- <>
- <tr className="sw-h-8">
- <td colSpan={3}>
- {events.map((event) => (
- <div key={event.key}>
- <EventInner event={event} readonly />
- </div>
- ))}
- </td>
- </tr>
- {addSeparator && <TableSeparator />}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsZoom.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsZoom.tsx
deleted file mode 100644
index 776f8b12830..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphsZoom.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { AutoSizer } from 'react-virtualized/dist/commonjs/AutoSizer';
-import { ZoomTimeLine } from '../../components/charts/ZoomTimeLine';
-import { Serie } from '../../types/project-activity';
-import { hasHistoryData } from './utils';
-
-interface GraphsZoomProps {
- graphEndDate?: Date;
- graphStartDate?: Date;
- leakPeriodDate?: Date;
- loading: boolean;
- metricsType: string;
- onUpdateGraphZoom: (from?: Date, to?: Date) => void;
- series: Serie[];
- showAreas?: boolean;
-}
-
-const ZOOM_TIMELINE_PADDING_TOP = 0;
-const ZOOM_TIMELINE_PADDING_RIGHT = 10;
-const ZOOM_TIMELINE_PADDING_BOTTOM = 18;
-const ZOOM_TIMELINE_PADDING_LEFT = 60;
-const ZOOM_TIMELINE_HEIGHT = 64;
-
-export default function GraphsZoom(props: GraphsZoomProps) {
- const { loading, series, graphEndDate, leakPeriodDate, metricsType, showAreas, graphStartDate } =
- props;
-
- if (loading || !hasHistoryData(series)) {
- return null;
- }
-
- return (
- // We hide this for screen readers; they should use date inputs instead.
- <div className="activity-graph-zoom" aria-hidden>
- <AutoSizer disableHeight>
- {({ width }) => (
- <ZoomTimeLine
- endDate={graphEndDate}
- height={ZOOM_TIMELINE_HEIGHT}
- leakPeriodDate={leakPeriodDate}
- metricType={metricsType}
- padding={[
- ZOOM_TIMELINE_PADDING_TOP,
- ZOOM_TIMELINE_PADDING_RIGHT,
- ZOOM_TIMELINE_PADDING_BOTTOM,
- ZOOM_TIMELINE_PADDING_LEFT,
- ]}
- series={series}
- showAreas={showAreas}
- startDate={graphStartDate}
- updateZoom={props.onUpdateGraphZoom}
- width={width}
- />
- )}
- </AutoSizer>
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/RichQualityGateEventInner.tsx b/server/sonar-web/src/main/js/components/activity-graph/RichQualityGateEventInner.tsx
deleted file mode 100644
index b59da884261..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/RichQualityGateEventInner.tsx
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import {
- BareButton,
- ChevronDownIcon,
- Note,
- QualityGateIndicator,
- StandoutLink,
-} from '~design-system';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { getProjectUrl } from '../../helpers/urls';
-import { AnalysisEvent } from '../../types/project-activity';
-import ClickEventBoundary from '../controls/ClickEventBoundary';
-
-export type RichQualityGateEvent = AnalysisEvent & Required<Pick<AnalysisEvent, 'qualityGate'>>;
-
-export function isRichQualityGateEvent(event: AnalysisEvent): event is RichQualityGateEvent {
- return event.category === 'QUALITY_GATE' && event.qualityGate !== undefined;
-}
-
-interface Props {
- event: RichQualityGateEvent;
- readonly?: boolean;
-}
-
-interface State {
- expanded: boolean;
-}
-
-export class RichQualityGateEventInner extends React.PureComponent<Props, State> {
- state: State = { expanded: false };
-
- toggleProjectsList = () => {
- this.setState((state) => ({ expanded: !state.expanded }));
- };
-
- render() {
- const { event, readonly } = this.props;
- const { expanded } = this.state;
- return (
- <div className="sw-w-full sw-typo-default sw-py-1/2">
- <div className="sw-flex sw-justify-between">
- <div className="sw-flex sw-items-center">
- <Note className="sw-mr-1 sw-typo-semibold">
- {translate('event.category', event.category)}
- </Note>
-
- <div className="sw-ml-2 sw-flex sw-items-center">
- {event.qualityGate.stillFailing ? (
- <FormattedMessage
- defaultMessage={translate('event.quality_gate.still_x')}
- id="event.quality_gate.still_x"
- values={{
- status: <QualityGateIndicator status={event.qualityGate.status} size="sm" />,
- }}
- />
- ) : (
- <QualityGateIndicator status={event.qualityGate.status} size="sm" />
- )}
-
- <span className="sw-ml-1">
- {translate(`event.quality_gate.${event.qualityGate.status}`)}
- </span>
- </div>
- </div>
-
- {!readonly && event.qualityGate.failing.length > 0 && (
- <ClickEventBoundary>
- <BareButton
- className="sw-flex sw-items-center sw-ml-2"
- onClick={this.toggleProjectsList}
- >
- {expanded ? translate('hide') : translate('more')}
- <ChevronDownIcon transform={expanded ? 'rotate(180)' : undefined} />
- </BareButton>
- </ClickEventBoundary>
- )}
- </div>
-
- {expanded && (
- <ul className="sw-mt-2">
- {event.qualityGate.failing.map((project) => (
- <li className="sw-flex sw-justify-between sw-p-1" key={project.key}>
- <div className="sw-truncate">
- <ClickEventBoundary>
- <StandoutLink
- title={project.name}
- to={getProjectUrl(project.key, project.branch)}
- >
- <span aria-label={translateWithParameters('project_x', project.name)}>
- {project.name}
- </span>
- </StandoutLink>
- </ClickEventBoundary>
- </div>
- <div className="sw-flex sw-items-center sw-ml-2">
- <QualityGateIndicator status={event.qualityGate.status} size="sm" />
- <span className="sw-ml-2">
- {translate(`event.quality_gate.${event.qualityGate.status}`)}
- </span>
- </div>
- </li>
- ))}
- </ul>
- )}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/RichQualityProfileEventInner.tsx b/server/sonar-web/src/main/js/components/activity-graph/RichQualityProfileEventInner.tsx
deleted file mode 100644
index 6db8bf4ea0a..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/RichQualityProfileEventInner.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Link } from '@sonarsource/echoes-react';
-import { useIntl } from 'react-intl';
-import { getProfileChangelogPath } from '../../apps/quality-profiles/utils';
-import { AnalysisEvent, ProjectAnalysisEventCategory } from '../../types/project-activity';
-
-type RichQualityGateEvent = AnalysisEvent &
- Required<Pick<AnalysisEvent, 'description' | 'qualityProfile'>>;
-
-interface RichQualityProfileEventInnerProps {
- event: RichQualityGateEvent;
-}
-
-export function isRichQualityProfileEvent(event: AnalysisEvent): event is RichQualityGateEvent {
- return (
- event.category === ProjectAnalysisEventCategory.QualityProfile &&
- event.description !== undefined &&
- event.qualityProfile !== undefined
- );
-}
-
-export function RichQualityProfileEventInner({
- event,
-}: Readonly<RichQualityProfileEventInnerProps>) {
- const {
- description,
- name,
- qualityProfile: { languageKey, name: qualityProfileName },
- } = event;
-
- const intl = useIntl();
-
- const truncatedName = name.split(description)[0];
-
- const contextForAria = intl.formatMessage(
- { id: 'quality_profiles.page_title_changelog_x' },
- { 0: qualityProfileName },
- );
-
- return (
- <span aria-label={name}>
- {truncatedName}
-
- <Link
- aria-label={`${contextForAria}: ${description}`}
- to={getProfileChangelogPath(qualityProfileName, languageKey)}
- // Needed to make this link work from the Activity tab
- // Because of a click handler on a parent component that is also trigerring a redirection
- onClick={(event) => event.stopPropagation()}
- >
- {description}
- </Link>
- </span>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/SqUpgradeActivityEventMessage.tsx b/server/sonar-web/src/main/js/components/activity-graph/SqUpgradeActivityEventMessage.tsx
deleted file mode 100644
index cc59fbb0728..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/SqUpgradeActivityEventMessage.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { FlagMessage } from '~design-system';
-import { AnalysisEvent } from '../../types/project-activity';
-
-interface SqUpgradeActivityEventMessageProps {
- event: AnalysisEvent;
-}
-
-export function SqUpgradeActivityEventMessage({
- event,
-}: Readonly<SqUpgradeActivityEventMessageProps>) {
- return (
- <FlagMessage className="sw-my-1" id={event.key} variant="info">
- <FormattedMessage
- id="event.sqUpgrade"
- values={{
- sqVersion: event.name,
- }}
- />
- </FlagMessage>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/ActivityGraph-it.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/ActivityGraph-it.tsx
deleted file mode 100644
index 82ae2ed50d3..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/ActivityGraph-it.tsx
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { times } from 'lodash';
-import * as React from 'react';
-import {
- byLabelText,
- byPlaceholderText,
- byRole,
- byText,
-} from '~sonar-aligned/helpers/testSelector';
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import { modeHandler } from '../../../apps/issues/test-utils';
-import { CCT_SOFTWARE_QUALITY_METRICS } from '../../../helpers/constants';
-import { parseDate } from '../../../helpers/dates';
-import { mockHistoryItem, mockMeasureHistory } from '../../../helpers/mocks/project-activity';
-import { mockMetric } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { ComponentPropsType } from '../../../helpers/testUtils';
-import { Mode } from '../../../types/mode';
-import { GraphType, MeasureHistory } from '../../../types/project-activity';
-import { Metric } from '../../../types/types';
-import GraphsHeader from '../GraphsHeader';
-import GraphsHistory from '../GraphsHistory';
-import { generateSeries, getDisplayedHistoryMetrics, splitSeriesInGraphs } from '../utils';
-
-const MAX_GRAPHS = 2;
-const MAX_SERIES_PER_GRAPH = 3;
-const HISTORY_COUNT = 10;
-const START_DATE = '2016-01-01T00:00:00+0200';
-
-describe('rendering', () => {
- it('should render correctly when loading', async () => {
- renderActivityGraph({ loading: true });
- expect(await screen.findByText('loading')).toBeInTheDocument();
- });
-
- it.each([
- [Mode.MQR, MetricKey.software_quality_maintainability_issues],
- [Mode.Standard, MetricKey.code_smells],
- ])('should show the correct legend items in %s mode', async (mode, metric) => {
- modeHandler.setMode(mode);
- const { ui, user } = getPageObject();
- renderActivityGraph();
-
- // Static legend items, which aren't interactive.
- expect(ui.legendRemoveMetricBtn(MetricKey.violations).query()).not.toBeInTheDocument();
- expect(ui.getLegendItem(MetricKey.violations)).toBeInTheDocument();
-
- // Switch to custom graph.
- await ui.changeGraphType(GraphType.custom);
- await ui.openAddMetrics();
- await ui.clickOnMetric(metric);
- await ui.clickOnMetric(MetricKey.test_failures);
- await user.keyboard('{Escape}');
-
- // These legend items are interactive (interaction tested below).
- expect(ui.legendRemoveMetricBtn(metric).get()).toBeInTheDocument();
- expect(ui.legendRemoveMetricBtn(MetricKey.test_failures).get()).toBeInTheDocument();
-
- // Shows warning for metrics with no data.
- const li = ui.getLegendItem(MetricKey.test_failures);
- // eslint-disable-next-line jest/no-conditional-in-test
- if (li) {
- li.focus();
- }
- expect(ui.noDataWarningTooltip.get()).toBeInTheDocument();
- });
-});
-
-describe('data table modal', () => {
- it('shows the same data in a table', async () => {
- const { ui } = getPageObject();
- renderActivityGraph();
-
- await ui.openDataTable();
- expect(ui.dataTable.get()).toBeInTheDocument();
- expect(ui.dataTableColHeaders.getAll()).toHaveLength(3);
- expect(ui.dataTableRows.getAll()).toHaveLength(HISTORY_COUNT + 1);
-
- // Change graph type and dates, check table updates correctly.
- await ui.closeDataTable();
- await ui.changeGraphType(GraphType.coverage);
-
- await ui.openDataTable(true);
- expect(ui.dataTable.get()).toBeInTheDocument();
- expect(ui.dataTableColHeaders.getAll()).toHaveLength(4);
- expect(ui.dataTableRows.getAll()).toHaveLength(HISTORY_COUNT + 1);
- });
-
- it('shows the same data in a table when filtered by date', async () => {
- const { ui } = getPageObject();
- renderActivityGraph({
- graphStartDate: parseDate('2017-01-01'),
- graphEndDate: parseDate('2019-01-01'),
- });
-
- await ui.openDataTable();
- expect(ui.dataTable.get()).toBeInTheDocument();
- expect(ui.dataTableColHeaders.getAll()).toHaveLength(3);
- expect(ui.dataTableRows.getAll()).toHaveLength(2);
- });
-});
-
-it.each([
- [
- Mode.MQR,
- MetricKey.software_quality_reliability_issues,
- MetricKey.software_quality_maintainability_issues,
- MetricKey.software_quality_security_issues,
- ],
- [Mode.Standard, MetricKey.bugs, MetricKey.code_smells, MetricKey.vulnerabilities],
-])(
- 'should correctly handle adding/removing custom metrics in $s mode',
- async (mode, bugs, codeSmells, vulnerabilities) => {
- modeHandler.setMode(mode);
- const { ui } = getPageObject();
- renderActivityGraph();
-
- // Change graph type to "Custom".
- await ui.changeGraphType(GraphType.custom);
-
- // Open the "Add metrics" dropdown button; select some metrics.
- await ui.openAddMetrics();
-
- // We should not see DATA type or New Code metrics.
- expect(ui.metricCheckbox(`new_${bugs}`).query()).not.toBeInTheDocument();
- expect(ui.burnedBudgetCheckbox.query()).not.toBeInTheDocument();
-
- // Select 3 Int types.
- await ui.clickOnMetric(bugs);
- await ui.clickOnMetric(codeSmells);
- await ui.clickOnMetric(MetricKey.accepted_issues);
- // Select 1 Percent type.
- await ui.clickOnMetric(MetricKey.coverage);
-
- // We should see 2 graphs, correctly labelled.
- expect(ui.graphs.getAll()).toHaveLength(2);
-
- // We cannot select anymore Int types. It should hide options, and show an alert.
- expect(ui.metricCheckbox(vulnerabilities).query()).not.toBeInTheDocument();
- expect(ui.hiddenOptionsAlert.get()).toBeInTheDocument();
-
- // Select 2 more Percent types.
- await ui.clickOnMetric(MetricKey.duplicated_lines_density);
- await ui.clickOnMetric(MetricKey.test_success_density);
-
- // We cannot select anymore options. It should disable all remaining options, and
- // show a different alert.
- expect(ui.maxOptionsAlert.get()).toBeInTheDocument();
- expect(ui.metricCheckbox(vulnerabilities).get()).toBeDisabled();
-
- // Disable a few options.
- await ui.clickOnMetric(bugs);
- await ui.clickOnMetric(codeSmells);
- await ui.clickOnMetric(MetricKey.coverage);
-
- // Search for option and select it
- await ui.searchForMetric('condition');
- expect(ui.metricCheckbox(MetricKey.branch_coverage).query()).not.toBeInTheDocument();
- await ui.clickOnMetric(MetricKey.conditions_to_cover);
-
- // Disable percentage metrics by clicking on the legend items.
- await ui.removeMetric(MetricKey.duplicated_lines_density);
- await ui.removeMetric(MetricKey.test_success_density);
-
- // We should see 1 graph
- expect(ui.graphs.getAll()).toHaveLength(1);
-
- // Disable final number metrics
- await ui.removeMetric(MetricKey.accepted_issues);
- await ui.removeMetric(MetricKey.conditions_to_cover);
-
- // Should show message that there's no data to be rendered.
- expect(ui.noDataText.get()).toBeInTheDocument();
- },
-);
-
-function getPageObject() {
- const user = userEvent.setup();
- const ui = {
- // Graph types.
- graphTypeSelect: byLabelText('project_activity.graphs.choose_type'),
-
- // Add/remove metrics.
- addMetricBtn: byRole('button', { name: 'project_activity.graphs.custom.add' }),
- maintainabilityIssuesCheckbox: byRole('checkbox', {
- name: MetricKey.software_quality_maintainability_issues,
- }),
- newBugsCheckbox: byRole('checkbox', { name: MetricKey.new_bugs }),
- burnedBudgetCheckbox: byRole('checkbox', { name: MetricKey.burned_budget }),
- hiddenOptionsAlert: byText('project_activity.graphs.custom.type_x_message', {
- exact: false,
- }),
- maxOptionsAlert: byText('project_activity.graphs.custom.add_metric_info'),
- filterMetrics: byPlaceholderText('search.search_for_metrics'),
- metricCheckbox: (name: string) => byRole('checkbox', { name }),
- legendRemoveMetricBtn: (key: string) =>
- byRole('button', { name: `project_activity.graphs.custom.remove_metric.${key}` }),
- getLegendItem: (name: string) => {
- // This is due to a limitation in testing library, where we cannot get a listitem
- // role element by name.
- return screen.getAllByRole('listitem').find((item) => item.textContent === name);
- },
- noDataWarningTooltip: byLabelText('project_activity.graphs.custom.metric_no_history'),
-
- // Graphs.
- graphs: byLabelText('project_activity.graphs.explanation_x', { exact: false }),
- noDataText: byText('project_activity.graphs.custom.no_history'),
-
- // Data in table.
- openInTableRegion: byRole('region', { name: /project_activity.graphs.open_in_table/ }),
- closeDataTableBtn: byRole('button', { name: 'close' }),
- dataTable: byRole('table'),
- dataTableRows: byRole('row'),
- dataTableColHeaders: byRole('columnheader'),
- noDataTableText: byText('project_activity.graphs.data_table.no_data_warning_check_dates_x', {
- exact: false,
- }),
- };
-
- return {
- user,
- ui: {
- ...ui,
- async changeGraphType(type: GraphType) {
- await user.click(ui.graphTypeSelect.get());
- const optionForType = await screen.findByText(`project_activity.graphs.${type}`);
- await user.click(optionForType);
- },
- async openAddMetrics() {
- await user.click(ui.addMetricBtn.get());
- },
- async searchForMetric(text: string) {
- await user.type(ui.filterMetrics.get(), text);
- },
- async clickOnMetric(name: MetricKey) {
- await user.click(ui.metricCheckbox(name).get());
- },
- async removeMetric(metric: MetricKey) {
- await user.click(ui.legendRemoveMetricBtn(metric).get());
- },
- async openDataTable(tabFromGraphSelection = false) {
- // tab to graph selection and close popup
- if (!tabFromGraphSelection) {
- await user.tab();
- await user.keyboard('{escape}');
- }
- // tab to graph region and open data table
- await user.tab();
- await user.keyboard('{enter}');
- },
- async closeDataTable() {
- await user.click(ui.closeDataTableBtn.get());
- },
- },
- };
-}
-
-function renderActivityGraph(
- graphsHistoryProps: Partial<GraphsHistory['props']> = {},
- graphsHeaderProps: Partial<ComponentPropsType<typeof GraphsHeader>> = {},
-) {
- function ActivityGraph() {
- const [selectedMetrics, setSelectedMetrics] = React.useState<string[]>([]);
- const [graph, setGraph] = React.useState(graphsHistoryProps.graph || GraphType.issues);
-
- const measuresHistory: MeasureHistory[] = [];
- const metrics: Metric[] = [];
- [
- MetricKey.accepted_issues,
- MetricKey.violations,
- MetricKey.bugs,
- MetricKey.code_smells,
- MetricKey.vulnerabilities,
- MetricKey.software_quality_maintainability_issues,
- MetricKey.software_quality_reliability_issues,
- MetricKey.software_quality_security_issues,
- MetricKey.blocker_violations,
- MetricKey.lines_to_cover,
- MetricKey.uncovered_lines,
- MetricKey.coverage,
- MetricKey.duplicated_lines_density,
- MetricKey.test_success_density,
- MetricKey.branch_coverage,
- MetricKey.conditions_to_cover,
- ].forEach((metric) => {
- const history = times(HISTORY_COUNT - 2, (i) => {
- const date = parseDate(START_DATE);
- date.setDate(date.getDate() + i);
- return mockHistoryItem({ date, value: i.toString() });
- });
- history.push(
- mockHistoryItem({
- date: parseDate('2018-10-27T12:21:15+0200'),
- value: CCT_SOFTWARE_QUALITY_METRICS.includes(metric)
- ? JSON.stringify({ total: 2286 })
- : '2286',
- }),
- mockHistoryItem({ date: parseDate('2020-10-27T16:33:50+0200') }),
- );
- measuresHistory.push(mockMeasureHistory({ metric, history }));
- metrics.push(
- mockMetric({
- key: metric,
- type:
- metric.includes('_density') || metric === MetricKey.coverage
- ? MetricType.Percent
- : MetricType.Integer,
- }),
- );
- });
-
- // The following should be filtered out, and not be suggested as options.
- metrics.push(
- mockMetric({ key: MetricKey.new_bugs, type: MetricType.Integer }),
- mockMetric({ key: MetricKey.burned_budget, type: MetricType.Data }),
- );
-
- // The following will not be filtered out, but has no values.
- metrics.push(mockMetric({ key: MetricKey.test_failures, type: MetricType.Integer }));
- measuresHistory.push(
- mockMeasureHistory({
- metric: MetricKey.test_failures,
- history: times(HISTORY_COUNT, (i) => {
- const date = parseDate(START_DATE);
- date.setDate(date.getDate() + i);
- return mockHistoryItem({ date, value: undefined });
- }),
- }),
- );
-
- const series = generateSeries(
- measuresHistory,
- graph,
- metrics,
- getDisplayedHistoryMetrics(graph, selectedMetrics),
- );
- const graphs = splitSeriesInGraphs(series, MAX_GRAPHS, MAX_SERIES_PER_GRAPH);
- const metricsTypeFilter =
- graphs.length < MAX_GRAPHS
- ? undefined
- : graphs
- .filter((graph) => graph.length < MAX_SERIES_PER_GRAPH)
- .map((graph) => graph[0].type);
-
- const addCustomMetric = (metricKey: string) => {
- setSelectedMetrics([...selectedMetrics, metricKey]);
- };
-
- const removeCustomMetric = (metricKey: string) => {
- setSelectedMetrics(selectedMetrics.filter((m) => m !== metricKey));
- };
-
- const updateGraph = (graphType: string) => {
- setGraph(graphType as GraphType);
- };
-
- return (
- <>
- <GraphsHeader
- onAddCustomMetric={addCustomMetric}
- graph={graph}
- metrics={metrics}
- metricsTypeFilter={metricsTypeFilter}
- onRemoveCustomMetric={removeCustomMetric}
- selectedMetrics={selectedMetrics}
- onUpdateGraph={updateGraph}
- {...graphsHeaderProps}
- />
- <GraphsHistory
- analyses={[]}
- graph={graph}
- graphs={graphs}
- loading={false}
- measuresHistory={[]}
- removeCustomMetric={removeCustomMetric}
- series={series}
- {...graphsHistoryProps}
- />
- </>
- );
- }
-
- return renderComponent(<ActivityGraph />);
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/DataTableModal-it.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/DataTableModal-it.tsx
deleted file mode 100644
index 5bd2c16c450..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/DataTableModal-it.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { times } from 'lodash';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { parseDate } from '../../../helpers/dates';
-import {
- mockAnalysisEvent,
- mockHistoryItem,
- mockMeasureHistory,
- mockParsedAnalysis,
-} from '../../../helpers/mocks/project-activity';
-import { mockMetric } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import {
- GraphType,
- MeasureHistory,
- ProjectAnalysisEventCategory,
-} from '../../../types/project-activity';
-import { Metric } from '../../../types/types';
-import DataTableModal, { DataTableModalProps, MAX_DATA_TABLE_ROWS } from '../DataTableModal';
-import { generateSeries, getDisplayedHistoryMetrics } from '../utils';
-
-it('should render correctly if there are no series', () => {
- renderDataTableModal({ series: [] });
- expect(
- screen.getByText('project_activity.graphs.data_table.no_data_warning'),
- ).toBeInTheDocument();
-});
-
-it('should render correctly if there are events', () => {
- renderDataTableModal({
- analyses: [
- mockParsedAnalysis({
- date: parseDate('2016-01-01T00:00:00+0200'),
- events: [
- mockAnalysisEvent({ key: '1', category: ProjectAnalysisEventCategory.QualityGate }),
- ],
- }),
- ],
- });
- expect(screen.getByText('event.category.QUALITY_GATE', { exact: false })).toBeInTheDocument();
-});
-
-it('should render correctly if there is too much data', () => {
- renderDataTableModal({ series: mockSeries(MAX_DATA_TABLE_ROWS + 1) });
- expect(
- screen.getByText(`project_activity.graphs.data_table.max_lines_warning.${MAX_DATA_TABLE_ROWS}`),
- ).toBeInTheDocument();
-});
-
-it('should render correctly if there is no data and we have a start date', () => {
- renderDataTableModal({ graphStartDate: parseDate('3022-01-01') });
- expect(
- screen.getByText('project_activity.graphs.data_table.no_data_warning_check_dates_x', {
- exact: false,
- }),
- ).toBeInTheDocument();
-});
-
-it('should render correctly if there is no data and we have an end date', () => {
- renderDataTableModal({ graphEndDate: parseDate('2015-01-01') });
- expect(
- screen.getByText('project_activity.graphs.data_table.no_data_warning_check_dates_y', {
- exact: false,
- }),
- ).toBeInTheDocument();
-});
-
-it('should render correctly if there is no data and we have a date range', () => {
- renderDataTableModal({
- graphEndDate: parseDate('2015-01-01'),
- graphStartDate: parseDate('2014-01-01'),
- });
- expect(
- screen.getByText('project_activity.graphs.data_table.no_data_warning_check_dates_x_y', {
- exact: false,
- }),
- ).toBeInTheDocument();
-});
-
-function renderDataTableModal(props: Partial<DataTableModalProps> = {}) {
- return renderComponent(
- <DataTableModal analyses={[]} series={mockSeries()} onClose={jest.fn()} {...props} />,
- );
-}
-
-function mockSeries(n = 10) {
- const measuresHistory: MeasureHistory[] = [];
- const metrics: Metric[] = [];
- [MetricKey.violations].forEach((metric) => {
- const history = times(n, (i) => {
- const date = parseDate('2016-01-01T00:00:00+0200');
- date.setDate(date.getDate() + 365 * i);
- return mockHistoryItem({ date, value: i.toString() });
- });
- measuresHistory.push(mockMeasureHistory({ metric, history }));
- metrics.push(
- mockMetric({
- key: metric,
- name: metric,
- type: 'INT',
- }),
- );
- });
-
- return generateSeries(
- measuresHistory,
- GraphType.issues,
- metrics,
- getDisplayedHistoryMetrics(GraphType.issues, [
- MetricKey.bugs,
- MetricKey.code_smells,
- MetricKey.vulnerabilities,
- ]),
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/EventInner-it.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/EventInner-it.tsx
deleted file mode 100644
index 70d1cbe408b..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/EventInner-it.tsx
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { Route } from 'react-router-dom';
-import { isMainBranch } from '~sonar-aligned/helpers/branch-like';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import BranchesServiceMock from '../../../api/mocks/BranchesServiceMock';
-import { mockBranch, mockMainBranch } from '../../../helpers/mocks/branch-like';
-import { mockAnalysisEvent } from '../../../helpers/mocks/project-activity';
-import { renderAppWithComponentContext } from '../../../helpers/testReactTestingUtils';
-import { Branch, BranchLike } from '../../../types/branch-like';
-import {
- ApplicationAnalysisEventCategory,
- DefinitionChangeType,
- ProjectAnalysisEventCategory,
-} from '../../../types/project-activity';
-import EventInner, { EventInnerProps } from '../EventInner';
-
-const ui = {
- showMoreBtn: byRole('button', { name: 'more' }),
- showLessBtn: byRole('button', { name: 'hide' }),
- projectLink: (name: string) => byRole('link', { name }),
-
- definitionChangeLabel: byText('event.category.DEFINITION_CHANGE', { exact: false }),
- projectAddedTxt: (branch: BranchLike) =>
- isMainBranch(branch)
- ? byText(/event\.definition_change\.added/)
- : byText(/event\.definition_change\.branch_added/),
- projectRemovedTxt: (branch: BranchLike) =>
- isMainBranch(branch)
- ? byText('event.definition_change.removed')
- : byText('event.definition_change.branch_removed'),
- branchReplacedTxt: byText('event.definition_change.branch_replaced'),
-
- qualityGateLabel: byText('event.category.QUALITY_GATE', { exact: false }),
- stillFailingTxt: byText('event.quality_gate.still_x'),
-
- versionLabel: byText('event.category.VERSION', { exact: false }),
-
- sqUpgradeLabel: (sqVersion: string) => byText(`event.sqUpgrade${sqVersion}`),
-};
-
-const handler = new BranchesServiceMock();
-
-beforeEach(() => {
- handler.reset();
-});
-
-describe('DEFINITION_CHANGE events', () => {
- it.each([mockMainBranch(), mockBranch()])(
- 'should render correctly for "ADDED" events',
- async (branchLike: Branch) => {
- handler.addBranch(branchLike);
- const user = userEvent.setup();
- renderEventInner(
- {
- event: mockAnalysisEvent({
- category: ApplicationAnalysisEventCategory.DefinitionChange,
- definitionChange: {
- projects: [
- {
- changeType: DefinitionChangeType.Added,
- key: 'foo',
- name: 'Foo',
- branch: 'master-foo',
- },
- ],
- },
- }),
- },
- `branch=${branchLike.name}&id=my-project`,
- );
-
- expect(await ui.definitionChangeLabel.find()).toBeInTheDocument();
-
- await user.click(ui.showMoreBtn.get());
-
- expect(await ui.projectAddedTxt(branchLike).find()).toBeInTheDocument();
- expect(ui.projectLink('Foo').get()).toBeInTheDocument();
- expect(screen.getByText('master-foo')).toBeInTheDocument();
- },
- );
-
- it.each([mockMainBranch(), mockBranch()])(
- 'should render correctly for "REMOVED" events',
- async (branchLike: Branch) => {
- const user = userEvent.setup();
- handler.addBranch(branchLike);
- renderEventInner(
- {
- event: mockAnalysisEvent({
- category: ApplicationAnalysisEventCategory.DefinitionChange,
- definitionChange: {
- projects: [
- {
- changeType: DefinitionChangeType.Removed,
- key: 'bar',
- name: 'Bar',
- branch: 'master-bar',
- },
- ],
- },
- }),
- },
- `branch=${branchLike.name}&id=my-project`,
- );
-
- expect(ui.definitionChangeLabel.get()).toBeInTheDocument();
-
- await user.click(ui.showMoreBtn.get());
-
- expect(await ui.projectRemovedTxt(branchLike).find()).toBeInTheDocument();
- expect(ui.projectLink('Bar').get()).toBeInTheDocument();
- expect(screen.getByText('master-bar')).toBeInTheDocument();
- },
- );
-
- it('should render correctly for "BRANCH_CHANGED" events', async () => {
- const user = userEvent.setup();
- renderEventInner({
- event: mockAnalysisEvent({
- category: ApplicationAnalysisEventCategory.DefinitionChange,
- definitionChange: {
- projects: [
- {
- changeType: DefinitionChangeType.BranchChanged,
- key: 'baz',
- name: 'Baz',
- oldBranch: 'old-branch',
- newBranch: 'new-branch',
- },
- ],
- },
- }),
- });
-
- expect(ui.definitionChangeLabel.get()).toBeInTheDocument();
-
- await user.click(ui.showMoreBtn.get());
-
- expect(ui.branchReplacedTxt.get()).toBeInTheDocument();
- expect(ui.projectLink('Baz').get()).toBeInTheDocument();
- expect(screen.getByText('old-branch')).toBeInTheDocument();
- expect(screen.getByText('new-branch')).toBeInTheDocument();
- });
-});
-
-describe('QUALITY_GATE events', () => {
- it('should render correctly for simple "QUALITY_GATE" events', () => {
- renderEventInner({
- event: mockAnalysisEvent({
- category: ProjectAnalysisEventCategory.QualityGate,
- qualityGate: { status: 'ERROR', stillFailing: false, failing: [] },
- }),
- });
-
- expect(ui.qualityGateLabel.get()).toBeInTheDocument();
- });
-
- it('should render correctly for "still failing" "QUALITY_GATE" events', () => {
- renderEventInner({
- event: mockAnalysisEvent({
- category: ProjectAnalysisEventCategory.QualityGate,
- qualityGate: { status: 'ERROR', stillFailing: true, failing: [] },
- }),
- });
-
- expect(ui.qualityGateLabel.get()).toBeInTheDocument();
- expect(ui.stillFailingTxt.get()).toBeInTheDocument();
- });
-
- it('should render correctly for application "QUALITY_GATE" events', async () => {
- const user = userEvent.setup();
- renderEventInner({
- event: mockAnalysisEvent({
- category: ProjectAnalysisEventCategory.QualityGate,
- qualityGate: {
- status: 'ERROR',
- stillFailing: true,
- failing: [
- {
- key: 'foo',
- name: 'Foo',
- branch: 'master',
- },
- {
- key: 'bar',
- name: 'Bar',
- branch: 'feature/bar',
- },
- ],
- },
- }),
- });
-
- expect(ui.qualityGateLabel.get()).toBeInTheDocument();
-
- await user.click(ui.showMoreBtn.get());
- expect(ui.projectLink('Foo').get()).toBeInTheDocument();
- expect(ui.projectLink('Bar').get()).toBeInTheDocument();
-
- await user.click(ui.showLessBtn.get());
- expect(ui.projectLink('Foo').query()).not.toBeInTheDocument();
- expect(ui.projectLink('Bar').query()).not.toBeInTheDocument();
- });
-});
-
-describe('VERSION events', () => {
- it('should render correctly', () => {
- renderEventInner({
- event: mockAnalysisEvent({
- category: ProjectAnalysisEventCategory.Version,
- name: '1.0',
- }),
- });
-
- expect(ui.versionLabel.get()).toBeInTheDocument();
- expect(screen.getByText('1.0')).toBeInTheDocument();
- });
-});
-
-describe('SQ_UPGRADE events', () => {
- it('should render correctly', () => {
- renderEventInner({
- event: mockAnalysisEvent({
- category: ProjectAnalysisEventCategory.SqUpgrade,
- name: '10.0',
- }),
- });
-
- expect(ui.sqUpgradeLabel('10.0').get()).toBeInTheDocument();
- });
-});
-
-function renderEventInner(props: Partial<EventInnerProps> = {}, params?: string) {
- return renderAppWithComponentContext(
- '/',
- () => <Route path="*" element={<EventInner event={mockAnalysisEvent()} {...props} />} />,
- { navigateTo: params ? `/?id=my-project&${params}` : '/?id=my-project' },
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltips-it.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltips-it.tsx
deleted file mode 100644
index 4ef99df5911..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltips-it.tsx
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { parseDate } from '../../../helpers/dates';
-import {
- mockAnalysisEvent,
- mockHistoryItem,
- mockMeasureHistory,
-} from '../../../helpers/mocks/project-activity';
-import { mockMetric } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { GraphType, MeasureHistory } from '../../../types/project-activity';
-import { Metric } from '../../../types/types';
-import { GraphsTooltips, Props } from '../GraphsTooltips';
-import { generateSeries, getDisplayedHistoryMetrics } from '../utils';
-
-it.each([
- [GraphType.issues, [[MetricKey.violations, 1]]],
- [
- GraphType.coverage,
- [
- ['metric.coverage.name', '75.0%'],
- ['metric.uncovered_lines.name', 8],
- ],
- ],
- [GraphType.duplications, [['metric.duplicated_lines_density.name', '3.0%']]],
- [GraphType.custom, [[MetricKey.bugs, 1]]],
-])(
- 'renders correctly for graph of type %s',
- (graph, metrics: Array<[string, number, string] | [string, number]>) => {
- renderGraphsTooltips({ graph });
-
- // Render events.
- expect(screen.getByText('event.category.QUALITY_GATE', { exact: false })).toBeInTheDocument();
-
- // Measures table.
- metrics.forEach(([key, n, rating]) => {
- expect(
- screen.getByRole('row', {
- // eslint-disable-next-line jest/no-conditional-in-test
- name: rating ? `${n} ${key} ${rating}` : `${n} ${key}`,
- }),
- ).toBeInTheDocument();
- });
- },
-);
-
-function renderGraphsTooltips(props: Partial<Props> = {}) {
- const graph = (props.graph as GraphType) || GraphType.coverage;
- const measuresHistory: MeasureHistory[] = [];
- const date = props.selectedDate || parseDate('2016-01-01T00:00:00+0200');
- const metrics: Metric[] = [];
-
- (
- [
- [MetricKey.violations, '1'],
- [MetricKey.bugs, '1'],
- [MetricKey.lines_to_cover, '10'],
- [MetricKey.uncovered_lines, '8'],
- [MetricKey.coverage, '75'],
- [MetricKey.duplicated_lines_density, '3'],
- ] as Array<[MetricKey, string]>
- ).forEach(([metric, value]) => {
- measuresHistory.push(
- mockMeasureHistory({
- metric,
- history: [mockHistoryItem({ date, value })],
- }),
- );
-
- metrics.push(
- mockMetric({
- key: metric,
- type: metric.includes('_density') || metric === MetricKey.coverage ? 'PERCENT' : 'INT',
- }),
- );
- });
-
- const series = generateSeries(
- measuresHistory,
- graph,
- metrics,
- getDisplayedHistoryMetrics(graph, graph === GraphType.custom ? [MetricKey.bugs] : []),
- );
-
- return renderComponent(
- <GraphsTooltips
- events={[mockAnalysisEvent({ key: '1' })]}
- graph={graph}
- graphWidth={100}
- measuresHistory={measuresHistory}
- selectedDate={date}
- series={series}
- tooltipIdx={0}
- tooltipPos={0}
- formatValue={(n: number | string) => String(n)}
- {...props}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/utils-test.ts.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/utils-test.ts.snap
deleted file mode 100644
index 0c670cffbc5..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/utils-test.ts.snap
+++ /dev/null
@@ -1,80 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`generateCoveredLinesMetric should correctly generate covered lines metric: empty data 1`] = `
-{
- "data": [],
- "name": "covered_lines",
- "translatedName": "project_activity.custom_metric.covered_lines",
- "type": "INT",
-}
-`;
-
-exports[`generateCoveredLinesMetric should correctly generate covered lines metric: with data 1`] = `
-{
- "data": [
- {
- "x": 2017-04-27T08:21:32.000Z,
- "y": 88,
- },
- {
- "x": 2017-04-30T23:06:24.000Z,
- "y": 50,
- },
- ],
- "name": "covered_lines",
- "translatedName": "project_activity.custom_metric.covered_lines",
- "type": "INT",
-}
-`;
-
-exports[`generateSeries should correctly generate the series 1`] = `
-[
- {
- "data": [
- {
- "x": 2017-04-27T08:21:32.000Z,
- "y": 88,
- },
- {
- "x": 2017-04-30T23:06:24.000Z,
- "y": 50,
- },
- ],
- "name": "covered_lines",
- "translatedName": "project_activity.custom_metric.covered_lines",
- "type": "INT",
- },
- {
- "data": [
- {
- "x": 2017-04-27T08:21:32.000Z,
- "y": 100,
- },
- {
- "x": 2017-04-30T23:06:24.000Z,
- "y": 100,
- },
- ],
- "name": "lines_to_cover",
- "translatedName": "lines_to_cover",
- "type": "PERCENT",
- },
-]
-`;
-
-exports[`getGraphTypes should correctly return the graph types 1`] = `
-[
- "issues",
- "coverage",
- "duplications",
- "custom",
-]
-`;
-
-exports[`getGraphTypes should correctly return the graph types 2`] = `
-[
- "issues",
- "coverage",
- "duplications",
-]
-`;
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/utils-test.ts b/server/sonar-web/src/main/js/components/activity-graph/__tests__/utils-test.ts
deleted file mode 100644
index 446434ec143..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/utils-test.ts
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import * as dates from '../../../helpers/dates';
-import { mockMeasureHistory, mockSerie } from '../../../helpers/mocks/project-activity';
-import { get, save } from '../../../helpers/storage';
-import { mockMetric } from '../../../helpers/testMocks';
-import { GraphType } from '../../../types/project-activity';
-import * as utils from '../utils';
-
-jest.mock('date-fns', () => {
- const actual = jest.requireActual('date-fns');
- return {
- ...actual,
- startOfDay: jest.fn((date) => {
- const startDay = new Date(date);
- startDay.setUTCHours(0, 0, 0, 0);
- return startDay;
- }),
- };
-});
-
-jest.mock('../../../helpers/storage', () => ({
- save: jest.fn(),
- get: jest.fn(),
-}));
-
-const HISTORY = [
- mockMeasureHistory({
- metric: MetricKey.lines_to_cover,
- history: [
- { date: dates.parseDate('2017-04-27T08:21:32.000Z'), value: '100' },
- { date: dates.parseDate('2017-04-30T23:06:24.000Z'), value: '100' },
- ],
- }),
- mockMeasureHistory({
- metric: MetricKey.uncovered_lines,
- history: [
- { date: dates.parseDate('2017-04-27T08:21:32.000Z'), value: '12' },
- { date: dates.parseDate('2017-04-30T23:06:24.000Z'), value: '50' },
- ],
- }),
-];
-
-const METRICS = [
- mockMetric({ key: MetricKey.uncovered_lines, type: MetricType.Integer }),
- mockMetric({ key: MetricKey.lines_to_cover, type: MetricType.Percent }),
-];
-
-const SERIE = mockSerie({
- type: MetricType.Percent,
-});
-
-describe('generateCoveredLinesMetric', () => {
- it('should correctly generate covered lines metric', () => {
- expect(utils.generateCoveredLinesMetric(HISTORY[1], HISTORY)).toMatchSnapshot('with data');
- expect(utils.generateCoveredLinesMetric(HISTORY[1], [])).toMatchSnapshot('empty data');
- });
-});
-
-describe('generateSeries', () => {
- it('should correctly generate the series', () => {
- expect(
- utils.generateSeries(HISTORY, GraphType.coverage, METRICS, [
- MetricKey.uncovered_lines,
- MetricKey.lines_to_cover,
- ]),
- ).toMatchSnapshot();
- });
- it('should correctly handle non-existent data', () => {
- expect(utils.generateSeries(HISTORY, GraphType.coverage, METRICS, [])).toEqual([]);
- });
-});
-
-describe('getDisplayedHistoryMetrics', () => {
- const customMetrics = ['foo', 'bar'];
- it('should return only displayed metrics on the graph', () => {
- expect(utils.getDisplayedHistoryMetrics(utils.DEFAULT_GRAPH, [])).toEqual([
- MetricKey.violations,
- ]);
- expect(utils.getDisplayedHistoryMetrics(GraphType.coverage, customMetrics)).toEqual([
- MetricKey.lines_to_cover,
- MetricKey.uncovered_lines,
- ]);
- });
- it('should return all custom metrics for the custom graph', () => {
- expect(utils.getDisplayedHistoryMetrics(GraphType.custom, customMetrics)).toEqual(
- customMetrics,
- );
- });
- it('should return Legacy graphs', () => {
- expect(utils.getDisplayedHistoryMetrics(GraphType.issues, [], true)).toEqual([
- MetricKey.bugs,
- MetricKey.code_smells,
- MetricKey.vulnerabilities,
- ]);
- });
-});
-
-describe('getHistoryMetrics', () => {
- const customMetrics = ['foo', 'bar'];
- it('should return all metrics', () => {
- expect(utils.getHistoryMetrics(utils.DEFAULT_GRAPH, [])).toEqual([
- MetricKey.violations,
- MetricKey.reliability_rating,
- MetricKey.security_rating,
- MetricKey.sqale_rating,
- ]);
- expect(utils.getHistoryMetrics(GraphType.coverage, customMetrics)).toEqual([
- MetricKey.lines_to_cover,
- MetricKey.uncovered_lines,
- GraphType.coverage,
- ]);
- expect(utils.getHistoryMetrics(GraphType.custom, customMetrics)).toEqual(customMetrics);
- });
- it('should return legacy metrics', () => {
- expect(utils.getHistoryMetrics(utils.DEFAULT_GRAPH, [], true)).toEqual([
- MetricKey.bugs,
- MetricKey.code_smells,
- MetricKey.vulnerabilities,
- MetricKey.reliability_rating,
- MetricKey.security_rating,
- MetricKey.sqale_rating,
- ]);
- });
-});
-
-describe('hasHistoryData', () => {
- it('should correctly detect if there is history data', () => {
- expect(utils.hasHistoryData([mockSerie()])).toBe(true);
- expect(
- utils.hasHistoryData([
- mockSerie({
- data: [],
- }),
- mockSerie({
- name: 'bar',
- translatedName: 'bar',
- }),
- ]),
- ).toBe(true);
- expect(
- utils.hasHistoryData([
- mockSerie({
- name: 'bar',
- translatedName: 'bar',
- data: [{ x: dates.parseDate('2017-04-27T08:21:32.000Z'), y: 2 }],
- }),
- ]),
- ).toBe(false);
- });
-});
-
-describe('getGraphTypes', () => {
- it('should correctly return the graph types', () => {
- expect(utils.getGraphTypes()).toMatchSnapshot();
- expect(utils.getGraphTypes(true)).toMatchSnapshot();
- });
-});
-
-describe('hasDataValues', () => {
- it('should check for data value', () => {
- expect(utils.hasDataValues(SERIE)).toBe(true);
- expect(utils.hasDataValues({ ...SERIE, data: [] })).toBe(false);
- });
-});
-
-describe('getSeriesMetricType', () => {
- it('should return the correct type', () => {
- expect(utils.getSeriesMetricType([SERIE])).toBe(MetricType.Percent);
- expect(utils.getSeriesMetricType([])).toBe(MetricType.Integer);
- });
-});
-
-describe('hasHistoryDataValue', () => {
- it('should return the correct type', () => {
- expect(utils.hasHistoryDataValue([SERIE])).toBe(true);
- expect(utils.hasHistoryDataValue([])).toBe(false);
- });
-});
-
-describe('saveActivityGraph', () => {
- it('should correctly store data for standard graph types', () => {
- utils.saveActivityGraph('foo', 'bar', GraphType.issues);
- expect(save).toHaveBeenCalledWith('foo', GraphType.issues, 'bar');
- });
-
- it.each([[[]], [[MetricKey.bugs, MetricKey.alert_status]]])(
- 'should correctly store data for custom graph types',
- (metrics) => {
- utils.saveActivityGraph('foo', 'bar', GraphType.custom, metrics);
- expect(save).toHaveBeenCalledWith('foo', GraphType.custom, 'bar');
- // eslint-disable-next-line jest/no-conditional-in-test
- expect(save).toHaveBeenCalledWith('foo.custom', metrics.join(','), 'bar');
- },
- );
-});
-
-describe('getActivityGraph', () => {
- it('should correctly retrieve data for standard graph types', () => {
- jest.mocked(get).mockImplementation((key) => {
- // eslint-disable-next-line jest/no-conditional-in-test
- if (key.includes('.custom')) {
- return null;
- }
- return GraphType.coverage;
- });
-
- expect(utils.getActivityGraph('foo', 'bar')).toEqual({
- graph: GraphType.coverage,
- customGraphs: [],
- });
- });
-
- it.each([null, 'bugs,code_smells'])(
- 'should correctly retrieve data for custom graph types',
- (data) => {
- jest.mocked(get).mockImplementation((key) => {
- // eslint-disable-next-line jest/no-conditional-in-test
- if (key.includes('.custom')) {
- return data;
- }
- return GraphType.custom;
- });
-
- expect(utils.getActivityGraph('foo', 'bar')).toEqual({
- graph: GraphType.custom,
- // eslint-disable-next-line jest/no-conditional-in-test
- customGraphs: data ? [MetricKey.bugs, MetricKey.code_smells] : [],
- });
- },
- );
-
- it('should correctly retrieve data for unknown graphs', () => {
- jest.mocked(get).mockReturnValue(null);
-
- expect(utils.getActivityGraph('foo', 'bar')).toEqual({
- graph: GraphType.issues,
- customGraphs: [],
- });
- });
-});
diff --git a/server/sonar-web/src/main/js/components/activity-graph/utils.ts b/server/sonar-web/src/main/js/components/activity-graph/utils.ts
deleted file mode 100644
index 06ef722bd9e..00000000000
--- a/server/sonar-web/src/main/js/components/activity-graph/utils.ts
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { chunk, flatMap, groupBy, sortBy } from 'lodash';
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import {
- CCT_SOFTWARE_QUALITY_METRICS,
- OLD_TO_NEW_TAXONOMY_METRICS_MAP,
-} from '../../helpers/constants';
-import { getLocalizedMetricName, translate } from '../../helpers/l10n';
-import { localizeMetric } from '../../helpers/measures';
-import { get, save } from '../../helpers/storage';
-import { GraphType, MeasureHistory, ParsedAnalysis, Serie } from '../../types/project-activity';
-import { Dict, Metric } from '../../types/types';
-
-export const DEFAULT_GRAPH = GraphType.issues;
-
-const GRAPHS_METRICS_DISPLAYED: Dict<string[]> = {
- [GraphType.issues]: [MetricKey.violations],
- [GraphType.coverage]: [MetricKey.lines_to_cover, MetricKey.uncovered_lines],
- [GraphType.duplications]: [MetricKey.ncloc, MetricKey.duplicated_lines],
-};
-
-const LEGACY_GRAPHS_METRICS_DISPLAYED: Dict<string[]> = {
- ...GRAPHS_METRICS_DISPLAYED,
- [GraphType.issues]: [MetricKey.bugs, MetricKey.code_smells, MetricKey.vulnerabilities],
-};
-
-const GRAPHS_METRICS: Dict<string[]> = {
- [GraphType.issues]: GRAPHS_METRICS_DISPLAYED[GraphType.issues].concat([
- MetricKey.reliability_rating,
- MetricKey.security_rating,
- MetricKey.sqale_rating,
- ]),
- [GraphType.coverage]: [...GRAPHS_METRICS_DISPLAYED[GraphType.coverage], MetricKey.coverage],
- [GraphType.duplications]: [
- ...GRAPHS_METRICS_DISPLAYED[GraphType.duplications],
- MetricKey.duplicated_lines_density,
- ],
-};
-
-const LEGACY_GRAPHS_METRICS: Dict<string[]> = {
- ...GRAPHS_METRICS,
- [GraphType.issues]: LEGACY_GRAPHS_METRICS_DISPLAYED[GraphType.issues].concat([
- MetricKey.reliability_rating,
- MetricKey.security_rating,
- MetricKey.sqale_rating,
- ]),
-};
-
-export const LINE_CHART_DASHES = [0, 3, 7];
-
-export function isCustomGraph(graph: GraphType) {
- return graph === GraphType.custom;
-}
-
-export function getGraphTypes(ignoreCustom = false) {
- const graphs = [GraphType.issues, GraphType.coverage, GraphType.duplications];
-
- return ignoreCustom ? graphs : [...graphs, GraphType.custom];
-}
-
-export function hasDataValues(serie: Serie) {
- return serie.data.some((point) => Boolean(point.y || point.y === 0));
-}
-
-export function hasHistoryData(series: Serie[]) {
- return series.some((serie) => serie.data && serie.data.length > 1);
-}
-
-export function getSeriesMetricType(series: Serie[]) {
- return series.length > 0 ? series[0].type : MetricType.Integer;
-}
-
-export function getDisplayedHistoryMetrics(
- graph: GraphType,
- customMetrics: string[],
- isStandardMode = false,
-) {
- if (isCustomGraph(graph)) {
- return customMetrics;
- }
-
- return isStandardMode ? LEGACY_GRAPHS_METRICS_DISPLAYED[graph] : GRAPHS_METRICS_DISPLAYED[graph];
-}
-
-export function getHistoryMetrics(
- graph: GraphType,
- customMetrics: string[],
- isStandardMode = false,
-) {
- if (isCustomGraph(graph)) {
- return customMetrics;
- }
- return isStandardMode ? LEGACY_GRAPHS_METRICS[graph] : GRAPHS_METRICS[graph];
-}
-
-export function hasHistoryDataValue(series: Serie[]) {
- return series.some((serie) => serie.data && serie.data.length > 1 && hasDataValues(serie));
-}
-
-export function splitSeriesInGraphs(series: Serie[], maxGraph: number, maxSeries: number) {
- return flatMap(
- groupBy(series, (serie) => serie.type),
- (type) => chunk(type, maxSeries),
- ).slice(0, maxGraph);
-}
-
-export function generateCoveredLinesMetric(
- uncoveredLines: MeasureHistory,
- measuresHistory: MeasureHistory[],
-): Serie {
- const linesToCover = measuresHistory.find(
- (measure) => measure.metric === MetricKey.lines_to_cover,
- );
-
- return {
- data: linesToCover
- ? uncoveredLines.history.map((analysis, idx) => ({
- x: analysis.date,
- y: Number(linesToCover.history[idx].value) - Number(analysis.value),
- }))
- : [],
- name: 'covered_lines',
- translatedName: translate('project_activity.custom_metric.covered_lines'),
- type: MetricType.Integer,
- };
-}
-
-export function generateSeries(
- measuresHistory: MeasureHistory[],
- graph: GraphType,
- metrics: Metric[],
- displayedMetrics: string[],
-): Serie[] {
- if (displayedMetrics.length <= 0 || measuresHistory === undefined) {
- return [];
- }
-
- return sortBy(
- measuresHistory
- .filter((measure) => displayedMetrics.indexOf(measure.metric) >= 0)
- .map((measure) => {
- if (measure.metric === MetricKey.uncovered_lines && !isCustomGraph(graph)) {
- return generateCoveredLinesMetric(measure, measuresHistory);
- }
- const metric = findMetric(measure.metric, metrics);
- const isSoftwareQualityMetric = CCT_SOFTWARE_QUALITY_METRICS.includes(
- metric?.key as MetricKey,
- );
- return {
- data: measure.history.map((analysis) => {
- const { value } = analysis;
-
- return {
- x: analysis.date,
- y: metric?.type === MetricType.Level ? value : Number(value),
- };
- }),
- name: measure.metric,
- translatedName: metric ? getLocalizedMetricName(metric) : localizeMetric(measure.metric),
- type: !metric || isSoftwareQualityMetric ? MetricType.Integer : metric.type,
- };
- }),
- (serie) =>
- displayedMetrics.indexOf(
- serie.name === 'covered_lines' ? MetricKey.uncovered_lines : serie.name,
- ),
- );
-}
-
-export function saveActivityGraph(
- namespace: string,
- project: string,
- graph: GraphType,
- metrics?: string[],
-) {
- save(namespace, graph, project);
-
- if (isCustomGraph(graph) && metrics) {
- save(`${namespace}.custom`, metrics.join(','), project);
- }
-}
-
-export function getActivityGraph(
- namespace: string,
- project: string,
-): { customGraphs: string[]; graph: GraphType } {
- const customGraphs = get(`${namespace}.custom`, project);
-
- return {
- graph: (get(namespace, project) as GraphType) || DEFAULT_GRAPH,
- customGraphs: customGraphs ? customGraphs.split(',') : [],
- };
-}
-
-export function getAnalysisEventsForDate(analyses: ParsedAnalysis[], date?: Date) {
- if (date) {
- const analysis = analyses.find((a) => a.date.valueOf() === date.valueOf());
- if (analysis) {
- return analysis.events;
- }
- }
-
- return [];
-}
-
-export function getDeprecatedTranslationKeyForTooltip(metric: MetricKey) {
- const quality = OLD_TO_NEW_TAXONOMY_METRICS_MAP[metric];
-
- let deprecatedKey = 'severity';
- if (quality) {
- deprecatedKey = 'quality';
- } else if (metric === MetricKey.confirmed_issues) {
- deprecatedKey = 'confirmed';
- }
-
- return `project_activity.custom_metric.deprecated.${deprecatedKey}`;
-}
-
-function findMetric(key: string, metrics: Metric[]) {
- return metrics.find((metric) => metric.key === key);
-}
diff --git a/server/sonar-web/src/main/js/components/branding/SonarQubeConnectionIllustration.tsx b/server/sonar-web/src/main/js/components/branding/SonarQubeConnectionIllustration.tsx
deleted file mode 100644
index 11c7b8308be..00000000000
--- a/server/sonar-web/src/main/js/components/branding/SonarQubeConnectionIllustration.tsx
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useAppState } from '../../app/components/app-state/withAppStateContext';
-import { EditionKey } from '../../types/editions';
-
-interface Props {
- className?: string;
- connected: boolean;
-}
-
-/**
- * This component switches between the Community and Server product versions' logo,
- * and between the connected and requested versions of the illustration
- */
-export function SonarQubeConnectionIllustration(props: Props) {
- const { edition } = useAppState();
-
- return edition === EditionKey.community ? (
- <CommunityIllustration {...props} />
- ) : (
- <ServerIllustration {...props} />
- );
-}
-
-function CommunityIllustration({ connected, ...imageProps }: Props) {
- return connected ? (
- <svg
- aria-hidden
- width="179"
- height="98"
- viewBox="0 0 179 98"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- {...imageProps}
- >
- <path
- fillRule="evenodd"
- clipRule="evenodd"
- d="M72.005 26h-50.01c-8.836 0-16 7.163-16 16v40c0 8.837 7.164 16 16 16h135c8.837 0 16-7.163 16-16V42c0-8.837-7.163-16-16-16h-57.4l-2 2h59.4c7.732 0 14 6.268 14 14v40c0 7.732-6.268 14-14 14h-135c-7.732 0-14-6.268-14-14V42c0-7.732 6.268-14 14-14h52.01l-2-2Z"
- fill="var(--echoes-color-icon-success)"
- />
- <path
- d="M66.545 64.34c0 1.08-1.23 1.71-2.1 1.08-.96-.72-1.56-1.86-2.04-2.76-.66-1.26-1.14-2.01-1.74-2.01-.6 0-1.05.75-1.74 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.74-2.01-.63 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.71-2.01-.6 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.48-.87-.84-1.53-1.2-1.83-.3-.24-.51-.57-.51-.96v-.21c0-1.08 1.23-1.71 2.1-1.08.96.72 1.56 1.86 2.04 2.76.66 1.26 1.11 2.01 1.71 2.01.6 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.74-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.48.87.84 1.53 1.23 1.83.3.24.51.57.51.96v.21h-.03ZM46.355 83.18c-4.95 0-9.66-1.71-13.47-4.83-.6-.51-.66-1.44-.12-2.01.51-.54 1.32-.57 1.86-.12 3.42 2.85 7.71 4.32 12.21 4.2 4.5-.12 8.7-1.83 11.97-4.83.54-.48 1.35-.48 1.86 0 .57.54.57 1.47 0 2.01-3.75 3.48-8.61 5.43-13.77 5.58h-.57.03ZM32.045 48.41c-.57-.54-.57-1.47 0-2.01 3.87-3.57 8.79-5.43 13.77-5.55 4.98-.12 9.96 1.47 14.04 4.83.6.51.66 1.44.12 2.01-.51.51-1.32.57-1.86.12-3.51-2.88-7.8-4.29-12.09-4.2-4.29.09-8.67 1.71-12.09 4.83-.54.48-1.35.48-1.86 0l-.03-.03Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M90.316 63.612h5.232v1.632h-5.232V70.5h-1.632v-5.256h-5.232v-1.632h5.232v-5.256h1.632v5.256Z"
- fill="var(--echoes-color-text-subdued)"
- />
- <path
- d="M155.444 63.552A1.55 1.55 0 0 1 153.892 62c0-11.524-9.373-20.897-20.897-20.897a1.55 1.55 0 0 1-1.551-1.551A1.55 1.55 0 0 1 132.995 38c13.231 0 24 10.769 24 24a1.55 1.55 0 0 1-1.551 1.552ZM132.995 86c-13.231 0-24-10.769-24-24a1.55 1.55 0 0 1 1.552-1.552A1.55 1.55 0 0 1 112.099 62c0 11.524 9.372 20.897 20.896 20.897a1.55 1.55 0 0 1 1.552 1.551A1.55 1.55 0 0 1 132.995 86Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M147.582 63.552A1.55 1.55 0 0 1 146.03 62c0-7.19-5.845-13.035-13.035-13.035a1.55 1.55 0 0 1-1.551-1.551 1.55 1.55 0 0 1 1.551-1.552c8.897 0 16.138 7.241 16.138 16.138a1.55 1.55 0 0 1-1.551 1.552ZM132.995 78.138c-8.896 0-16.138-7.242-16.138-16.138a1.55 1.55 0 0 1 1.552-1.552A1.55 1.55 0 0 1 119.961 62c0 7.19 5.845 13.034 13.034 13.034a1.55 1.55 0 0 1 1.552 1.552 1.55 1.55 0 0 1-1.552 1.552ZM133.016 70.286a8.254 8.254 0 0 1-5.855-2.42c-3.228-3.228-3.228-8.483 0-11.721a8.232 8.232 0 0 1 5.855-2.431 8.19 8.19 0 0 1 5.855 2.43c.61.611.61 1.594 0 2.194-.61.61-1.593.61-2.193 0a5.133 5.133 0 0 0-3.662-1.52c-1.386 0-2.69.537-3.662 1.52a5.189 5.189 0 0 0 0 7.324 5.188 5.188 0 0 0 7.324 0c.61-.61 1.593-.61 2.193 0 .6.61.61 1.593 0 2.193a8.254 8.254 0 0 1-5.855 2.42v.011Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M110.658 4.837a2.861 2.861 0 0 1 0 4.044L87.804 31.736a2.861 2.861 0 0 1-4.044 0L72.332 20.308a2.861 2.861 0 0 1 0-4.044 2.861 2.861 0 0 1 4.044 0l9.41 9.401 20.837-20.828a2.86 2.86 0 0 1 4.044 0h-.009Z"
- fill="var(--echoes-color-icon-success)"
- />
- </svg>
- ) : (
- <svg
- aria-hidden
- width="179"
- height="98"
- viewBox="0 0 179 98"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- {...imageProps}
- >
- <path
- d="M35.076 27H80.745L64.703 97H16C7.716 97 1 90.284 1 82V42c0-8.284 6.716-15 15-15h19.076Z"
- stroke="var(--echoes-color-border-weak)"
- strokeWidth="2"
- />
- <path
- d="M56.55 64.34c0 1.08-1.23 1.71-2.1 1.08-.96-.72-1.56-1.86-2.04-2.76-.66-1.26-1.14-2.01-1.74-2.01-.6 0-1.05.75-1.74 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.74-2.01-.63 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.71-2.01-.6 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.48-.87-.84-1.53-1.2-1.83-.3-.24-.51-.57-.51-.96v-.21c0-1.08 1.23-1.71 2.1-1.08.96.72 1.56 1.86 2.04 2.76.66 1.26 1.11 2.01 1.71 2.01.6 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.74-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.48.87.84 1.53 1.23 1.83.3.24.51.57.51.96v.21h-.03ZM36.36 83.18c-4.95 0-9.66-1.71-13.47-4.83-.6-.51-.66-1.44-.12-2.01.51-.54 1.32-.57 1.86-.12 3.42 2.85 7.71 4.32 12.21 4.2 4.5-.12 8.7-1.83 11.97-4.83.54-.48 1.35-.48 1.86 0 .57.54.57 1.47 0 2.01-3.75 3.48-8.61 5.43-13.77 5.58h-.57.03ZM22.05 48.41c-.57-.54-.57-1.47 0-2.01 3.87-3.57 8.79-5.43 13.77-5.55 4.98-.12 9.96 1.47 14.04 4.83.6.51.66 1.44.12 2.01-.51.51-1.32.57-1.86.12-3.51-2.88-7.8-4.29-12.09-4.2-4.29.09-8.67 1.71-12.09 4.83-.54.48-1.35.48-1.86 0l-.03-.03Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M90.32 63.612h5.233v1.632H90.32V70.5h-1.632v-5.256h-5.232v-1.632h5.232v-5.256h1.632v5.256Z"
- fill="var(--echoes-color-text-subdued)"
- />
- <path
- d="M143.924 97H98.255l16.042-70H163c8.284 0 15 6.716 15 15v40c0 8.284-6.716 15-15 15h-19.076Z"
- stroke="var(--echoes-color-border-weak)"
- strokeWidth="2"
- />
- <path
- d="M165.448 62.552A1.55 1.55 0 0 1 163.897 61c0-11.524-9.373-20.897-20.897-20.897a1.55 1.55 0 0 1-1.552-1.551A1.55 1.55 0 0 1 143 37c13.231 0 24 10.769 24 24a1.55 1.55 0 0 1-1.552 1.552ZM143 85c-13.231 0-24-10.769-24-24a1.55 1.55 0 0 1 1.552-1.552A1.55 1.55 0 0 1 122.103 61c0 11.524 9.373 20.897 20.897 20.897a1.55 1.55 0 0 1 1.552 1.551A1.55 1.55 0 0 1 143 85Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M157.586 62.552A1.55 1.55 0 0 1 156.034 61c0-7.19-5.844-13.035-13.034-13.035a1.55 1.55 0 0 1-1.552-1.551A1.55 1.55 0 0 1 143 44.862c8.897 0 16.138 7.241 16.138 16.138a1.55 1.55 0 0 1-1.552 1.552ZM143 77.138c-8.897 0-16.138-7.242-16.138-16.138a1.55 1.55 0 0 1 1.552-1.552A1.55 1.55 0 0 1 129.966 61c0 7.19 5.844 13.034 13.034 13.034a1.55 1.55 0 0 1 1.552 1.552A1.55 1.55 0 0 1 143 77.138ZM143.021 69.286a8.252 8.252 0 0 1-5.855-2.42c-3.228-3.228-3.228-8.483 0-11.721a8.232 8.232 0 0 1 5.855-2.431c2.213 0 4.293.858 5.855 2.43.61.611.61 1.594 0 2.194-.61.61-1.593.61-2.193 0a5.133 5.133 0 0 0-3.662-1.52c-1.387 0-2.69.537-3.662 1.52a5.187 5.187 0 0 0 0 7.324 5.188 5.188 0 0 0 7.324 0c.61-.61 1.593-.61 2.193 0 .6.61.61 1.593 0 2.193a8.256 8.256 0 0 1-5.855 2.42v.011Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- </svg>
- );
-}
-
-function ServerIllustration({ connected, ...imageProps }: Props) {
- return connected ? (
- <svg
- aria-hidden
- width="179"
- height="98"
- viewBox="0 0 179 98"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- {...imageProps}
- >
- <path
- fillRule="evenodd"
- clipRule="evenodd"
- d="M72.005 26h-50.01c-8.836 0-16 7.163-16 16v40c0 8.837 7.164 16 16 16h135c8.837 0 16-7.163 16-16V42c0-8.837-7.163-16-16-16h-57.4l-2 2h59.4c7.732 0 14 6.268 14 14v40c0 7.732-6.268 14-14 14h-135c-7.732 0-14-6.268-14-14V42c0-7.732 6.268-14 14-14h52.01l-2-2Z"
- fill="var(--echoes-color-icon-success)"
- />
- <path
- d="M66.545 64.34c0 1.08-1.23 1.71-2.1 1.08-.96-.72-1.56-1.86-2.04-2.76-.66-1.26-1.14-2.01-1.74-2.01-.6 0-1.05.75-1.74 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.74-2.01-.63 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.71-2.01-.6 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.48-.87-.84-1.53-1.2-1.83-.3-.24-.51-.57-.51-.96v-.21c0-1.08 1.23-1.71 2.1-1.08.96.72 1.56 1.86 2.04 2.76.66 1.26 1.11 2.01 1.71 2.01.6 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.74-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.48.87.84 1.53 1.23 1.83.3.24.51.57.51.96v.21h-.03ZM46.355 83.18c-4.95 0-9.66-1.71-13.47-4.83-.6-.51-.66-1.44-.12-2.01.51-.54 1.32-.57 1.86-.12 3.42 2.85 7.71 4.32 12.21 4.2 4.5-.12 8.7-1.83 11.97-4.83.54-.48 1.35-.48 1.86 0 .57.54.57 1.47 0 2.01-3.75 3.48-8.61 5.43-13.77 5.58h-.57.03ZM32.045 48.41c-.57-.54-.57-1.47 0-2.01 3.87-3.57 8.79-5.43 13.77-5.55 4.98-.12 9.96 1.47 14.04 4.83.6.51.66 1.44.12 2.01-.51.51-1.32.57-1.86.12-3.51-2.88-7.8-4.29-12.09-4.2-4.29.09-8.67 1.71-12.09 4.83-.54.48-1.35.48-1.86 0l-.03-.03Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M90.316 63.612h5.232v1.632h-5.232V70.5h-1.632v-5.256h-5.232v-1.632h5.232v-5.256h1.632v5.256Z"
- fill="var(--echoes-color-text-subdued)"
- />
- <g clipPath="url(#sqciok)" fill="var(--echoes-logos-colors-brand)">
- <path d="M155.268 63.54a1.54 1.54 0 0 1-1.539-1.54c0-11.433-9.301-20.733-20.734-20.733a1.54 1.54 0 0 1 0-3.079c13.131 0 23.814 10.682 23.814 23.812 0 .85-.69 1.54-1.54 1.54h-.001ZM132.994 85.812c-13.129 0-23.811-10.681-23.811-23.812a1.54 1.54 0 0 1 3.079 0c0 11.433 9.3 20.733 20.732 20.733a1.54 1.54 0 1 1 0 3.079ZM139.677 63.54c-.85 0-1.54-.69-1.54-1.54a5.147 5.147 0 0 0-5.142-5.141 1.54 1.54 0 0 1 0-3.079c4.534 0 8.222 3.688 8.222 8.22 0 .851-.69 1.54-1.539 1.54h-.001ZM132.994 70.222c-4.532 0-8.221-3.688-8.221-8.222a1.54 1.54 0 0 1 3.079 0 5.147 5.147 0 0 0 5.141 5.142 1.54 1.54 0 1 1 0 3.079h.001Z" />
- <path d="M147.472 63.54a1.54 1.54 0 0 1-1.539-1.54c0-7.133-5.804-12.937-12.939-12.937a1.54 1.54 0 0 1 0-3.078c8.833 0 16.018 7.185 16.018 16.016 0 .85-.69 1.54-1.54 1.54v-.002ZM132.994 78.017c-8.831 0-16.016-7.185-16.016-16.017a1.54 1.54 0 0 1 3.079 0c0 7.134 5.804 12.938 12.936 12.938a1.54 1.54 0 1 1 0 3.08h.001Z" />
- </g>
- <path
- d="M110.658 4.837a2.861 2.861 0 0 1 0 4.044L87.804 31.736a2.861 2.861 0 0 1-4.044 0L72.332 20.308a2.861 2.861 0 0 1 0-4.044 2.861 2.861 0 0 1 4.044 0l9.41 9.401 20.837-20.828a2.86 2.86 0 0 1 4.044 0h-.009Z"
- fill="var(--echoes-color-icon-success)"
- />
- <defs>
- <clipPath id="sqciok">
- <path fill="#fff" transform="translate(108.995 38)" d="M0 0h48v48H0z" />
- </clipPath>
- </defs>
- </svg>
- ) : (
- <svg
- aria-hidden
- width="179"
- height="98"
- viewBox="0 0 179 98"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- {...imageProps}
- >
- <path
- d="M35.076 27H80.745L64.703 97H16C7.716 97 1 90.284 1 82V42c0-8.284 6.716-15 15-15h19.076Z"
- stroke="var(--echoes-color-border-weak)"
- strokeWidth="2"
- />
- <path
- d="M56.55 64.34c0 1.08-1.23 1.71-2.1 1.08-.96-.72-1.56-1.86-2.04-2.76-.66-1.26-1.14-2.01-1.74-2.01-.6 0-1.05.75-1.74 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.74-2.01-.63 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.71-2.01-.6 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.48-.87-.84-1.53-1.2-1.83-.3-.24-.51-.57-.51-.96v-.21c0-1.08 1.23-1.71 2.1-1.08.96.72 1.56 1.86 2.04 2.76.66 1.26 1.11 2.01 1.71 2.01.6 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.74-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.48.87.84 1.53 1.23 1.83.3.24.51.57.51.96v.21h-.03ZM36.36 83.18c-4.95 0-9.66-1.71-13.47-4.83-.6-.51-.66-1.44-.12-2.01.51-.54 1.32-.57 1.86-.12 3.42 2.85 7.71 4.32 12.21 4.2 4.5-.12 8.7-1.83 11.97-4.83.54-.48 1.35-.48 1.86 0 .57.54.57 1.47 0 2.01-3.75 3.48-8.61 5.43-13.77 5.58h-.57.03ZM22.05 48.41c-.57-.54-.57-1.47 0-2.01 3.87-3.57 8.79-5.43 13.77-5.55 4.98-.12 9.96 1.47 14.04 4.83.6.51.66 1.44.12 2.01-.51.51-1.32.57-1.86.12-3.51-2.88-7.8-4.29-12.09-4.2-4.29.09-8.67 1.71-12.09 4.83-.54.48-1.35.48-1.86 0l-.03-.03Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M90.32 63.612h5.233v1.632H90.32V70.5h-1.632v-5.256h-5.232v-1.632h5.232v-5.256h1.632v5.256Z"
- fill="var(--echoes-color-text-subdued)"
- />
- <path
- d="M143.924 97H98.255l16.042-70H163c8.284 0 15 6.716 15 15v40c0 8.284-6.716 15-15 15h-19.076Z"
- stroke="var(--echoes-color-border-weak)"
- strokeWidth="2"
- />
- <g clipPath="url(#sqcireq)" fill="var(--echoes-logos-colors-brand)">
- <path d="M165.273 63.54a1.54 1.54 0 0 1-1.539-1.54c0-11.433-9.301-20.733-20.734-20.733a1.54 1.54 0 0 1 0-3.079c13.131 0 23.813 10.682 23.813 23.812 0 .85-.69 1.54-1.539 1.54h-.001ZM142.999 85.812c-13.13 0-23.811-10.681-23.811-23.812a1.54 1.54 0 1 1 3.078 0c0 11.433 9.3 20.733 20.733 20.733a1.54 1.54 0 0 1 0 3.079ZM149.682 63.54a1.54 1.54 0 0 1-1.54-1.54A5.147 5.147 0 0 0 143 56.859a1.54 1.54 0 0 1 0-3.079c4.534 0 8.222 3.688 8.222 8.22 0 .851-.69 1.54-1.54 1.54ZM142.999 70.222c-4.533 0-8.221-3.688-8.221-8.222a1.54 1.54 0 0 1 3.079 0 5.147 5.147 0 0 0 5.141 5.142 1.54 1.54 0 0 1 0 3.079h.001Z" />
- <path d="M157.477 63.54c-.85 0-1.54-.69-1.54-1.54 0-7.133-5.804-12.937-12.938-12.937a1.54 1.54 0 0 1 0-3.078c8.832 0 16.017 7.185 16.017 16.016 0 .85-.69 1.54-1.539 1.54v-.002ZM142.999 78.017c-8.831 0-16.016-7.185-16.016-16.017a1.54 1.54 0 0 1 3.079 0c0 7.134 5.804 12.938 12.936 12.938a1.54 1.54 0 0 1 0 3.08h.001Z" />
- </g>
- <defs>
- <clipPath id="sqcireq">
- <path fill="#fff" transform="translate(119 38)" d="M0 0h48v48H0z" />
- </clipPath>
- </defs>
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/branding/SonarQubeIDEPromotionIllustration.tsx b/server/sonar-web/src/main/js/components/branding/SonarQubeIDEPromotionIllustration.tsx
deleted file mode 100644
index 3e4ea0bc9db..00000000000
--- a/server/sonar-web/src/main/js/components/branding/SonarQubeIDEPromotionIllustration.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useAppState } from '../../app/components/app-state/withAppStateContext';
-import { EditionKey } from '../../types/editions';
-
-interface Props {
- className?: string;
-}
-/**
- * This component switches between the Community and Server product versions' logo
- */
-export function SonarQubeIDEPromotionIllustration({ className }: Props) {
- const { edition } = useAppState();
-
- return edition === EditionKey.community ? (
- <svg
- aria-hidden
- height="120"
- viewBox="0 0 82 173"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- className={className}
- >
- <path
- d="M46.924 71H1.255L17.297 1H66c8.284 0 15 6.716 15 15v40c0 8.284-6.716 15-15 15H46.924Z"
- stroke="var(--echoes-color-border-weak)"
- strokeWidth="2"
- />
- <path
- d="M68.448 36.552A1.55 1.55 0 0 1 66.897 35c0-11.524-9.373-20.897-20.897-20.897a1.55 1.55 0 0 1-1.552-1.551A1.55 1.55 0 0 1 46 11c13.231 0 24 10.769 24 24a1.55 1.55 0 0 1-1.552 1.552ZM46 59c-13.231 0-24-10.769-24-24a1.55 1.55 0 0 1 1.552-1.552A1.55 1.55 0 0 1 25.103 35c0 11.524 9.373 20.897 20.897 20.897a1.55 1.55 0 0 1 1.552 1.551A1.55 1.55 0 0 1 46 59Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M60.586 36.552A1.55 1.55 0 0 1 59.035 35c0-7.19-5.845-13.035-13.035-13.035a1.55 1.55 0 0 1-1.552-1.551A1.55 1.55 0 0 1 46 18.862c8.897 0 16.138 7.241 16.138 16.138a1.55 1.55 0 0 1-1.552 1.552ZM46 51.138c-8.897 0-16.138-7.241-16.138-16.138a1.55 1.55 0 0 1 1.552-1.552A1.55 1.55 0 0 1 32.965 35c0 7.19 5.845 13.035 13.035 13.035a1.55 1.55 0 0 1 1.552 1.551A1.55 1.55 0 0 1 46 51.138ZM46.02 43.286a8.255 8.255 0 0 1-5.855-2.42c-3.227-3.228-3.227-8.483 0-11.721a8.233 8.233 0 0 1 5.856-2.431 8.19 8.19 0 0 1 5.855 2.43c.61.611.61 1.594 0 2.194-.61.61-1.593.61-2.193 0a5.133 5.133 0 0 0-3.662-1.52c-1.386 0-2.69.537-3.662 1.52a5.189 5.189 0 0 0 0 7.324 5.189 5.189 0 0 0 7.324 0c.61-.61 1.593-.61 2.193 0 .6.61.61 1.593 0 2.193a8.255 8.255 0 0 1-5.855 2.42v.011Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M41.82 88.112h5.233v1.632H41.82V95h-1.632v-5.256h-5.232v-1.632h5.232v-5.256h1.632v5.256Z"
- fill="var(--echoes-color-text-subdued)"
- />
- <path
- d="M35.076 102H80.745l-16.042 70H16c-8.284 0-15-6.716-15-15v-40c0-8.284 6.716-15 15-15h19.076Z"
- stroke="var(--echoes-color-border-weak)"
- strokeWidth="2"
- />
- <path
- d="M56.55 139.34c0 1.08-1.23 1.71-2.1 1.08-.96-.72-1.56-1.86-2.04-2.76-.66-1.26-1.14-2.01-1.74-2.01-.6 0-1.05.75-1.74 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.74-2.01-.63 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.71-2.01-.6 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.48-.87-.84-1.53-1.2-1.83-.3-.24-.51-.57-.51-.96v-.21c0-1.08 1.23-1.71 2.1-1.08.96.72 1.56 1.86 2.04 2.76.66 1.26 1.11 2.01 1.71 2.01.6 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.74-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.48.87.84 1.53 1.23 1.83.3.24.51.57.51.96v.21h-.03ZM36.36 158.18c-4.95 0-9.66-1.71-13.47-4.83-.6-.51-.66-1.44-.12-2.01.51-.54 1.32-.57 1.86-.12 3.42 2.85 7.71 4.32 12.21 4.2 4.5-.12 8.7-1.83 11.97-4.83.54-.48 1.35-.48 1.86 0 .57.54.57 1.47 0 2.01-3.75 3.48-8.61 5.43-13.77 5.58h-.57.03ZM22.05 123.41c-.57-.54-.57-1.47 0-2.01 3.87-3.57 8.79-5.43 13.77-5.55 4.98-.12 9.96 1.47 14.04 4.83.6.51.66 1.44.12 2.01-.51.51-1.32.57-1.86.12-3.51-2.88-7.8-4.29-12.09-4.2-4.29.09-8.67 1.71-12.09 4.83-.54.48-1.35.48-1.86 0l-.03-.03Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- </svg>
- ) : (
- <svg
- aria-hidden
- height="120"
- viewBox="0 0 82 173"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- className={className}
- >
- <path
- d="M46.924 71H1.255L17.297 1H66c8.284 0 15 6.716 15 15v40c0 8.284-6.716 15-15 15H46.924Z"
- stroke="var(--echoes-color-border-weak)"
- strokeWidth="2"
- />
- <g clipPath="url(#sqidepi)" fill="var(--echoes-logos-colors-brand)">
- <path d="M68.273 37.54c-.85 0-1.54-.69-1.54-1.54 0-11.433-9.3-20.733-20.733-20.733a1.54 1.54 0 0 1 0-3.079c13.13 0 23.813 10.682 23.813 23.812 0 .85-.69 1.54-1.539 1.54ZM46 59.812C32.87 59.812 22.186 49.13 22.186 36a1.54 1.54 0 0 1 3.08 0c0 11.433 9.3 20.733 20.732 20.733a1.54 1.54 0 0 1 0 3.079ZM52.682 37.54c-.85 0-1.54-.69-1.54-1.54A5.147 5.147 0 0 0 46 30.859a1.54 1.54 0 0 1 0-3.079c4.534 0 8.222 3.688 8.222 8.22 0 .851-.69 1.54-1.54 1.54ZM46 44.222c-4.534 0-8.222-3.688-8.222-8.222a1.54 1.54 0 0 1 3.079 0 5.147 5.147 0 0 0 5.141 5.142 1.54 1.54 0 0 1 0 3.079H46Z" />
- <path d="M60.477 37.54c-.85 0-1.54-.69-1.54-1.54 0-7.133-5.804-12.937-12.938-12.937a1.54 1.54 0 0 1 0-3.078c8.832 0 16.017 7.185 16.017 16.016 0 .85-.69 1.54-1.54 1.54v-.002ZM46 52.017c-8.832 0-16.017-7.185-16.017-16.017a1.54 1.54 0 0 1 3.079 0c0 7.134 5.804 12.938 12.936 12.938a1.54 1.54 0 0 1 0 3.08H46Z" />
- </g>
- <path
- d="M41.82 88.112h5.233v1.632H41.82V95h-1.632v-5.256h-5.232v-1.632h5.232v-5.256h1.632v5.256Z"
- fill="var(--echoes-color-text-subdued)"
- />
- <path
- d="M35.076 102H80.745l-16.042 70H16c-8.284 0-15-6.716-15-15v-40c0-8.284 6.716-15 15-15h19.076Z"
- stroke="var(--echoes-color-border-weak)"
- strokeWidth="2"
- />
- <path
- d="M56.55 139.34c0 1.08-1.23 1.71-2.1 1.08-.96-.72-1.56-1.86-2.04-2.76-.66-1.26-1.14-2.01-1.74-2.01-.6 0-1.05.75-1.74 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.74-2.01-.63 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.71-2.01-.6 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.48-.87-.84-1.53-1.2-1.83-.3-.24-.51-.57-.51-.96v-.21c0-1.08 1.23-1.71 2.1-1.08.96.72 1.56 1.86 2.04 2.76.66 1.26 1.11 2.01 1.71 2.01.6 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.74-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.48.87.84 1.53 1.23 1.83.3.24.51.57.51.96v.21h-.03ZM36.36 158.18c-4.95 0-9.66-1.71-13.47-4.83-.6-.51-.66-1.44-.12-2.01.51-.54 1.32-.57 1.86-.12 3.42 2.85 7.71 4.32 12.21 4.2 4.5-.12 8.7-1.83 11.97-4.83.54-.48 1.35-.48 1.86 0 .57.54.57 1.47 0 2.01-3.75 3.48-8.61 5.43-13.77 5.58h-.57.03ZM22.05 123.41c-.57-.54-.57-1.47 0-2.01 3.87-3.57 8.79-5.43 13.77-5.55 4.98-.12 9.96 1.47 14.04 4.83.6.51.66 1.44.12 2.01-.51.51-1.32.57-1.86.12-3.51-2.88-7.8-4.29-12.09-4.2-4.29.09-8.67 1.71-12.09 4.83-.54.48-1.35.48-1.86 0l-.03-.03Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <defs>
- <clipPath id="sqidepi">
- <path fill="#fff" transform="translate(22 12)" d="M0 0h48v48H0z" />
- </clipPath>
- </defs>
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/branding/SonarQubeProductLogo.tsx b/server/sonar-web/src/main/js/components/branding/SonarQubeProductLogo.tsx
deleted file mode 100644
index a9db4c2aa96..00000000000
--- a/server/sonar-web/src/main/js/components/branding/SonarQubeProductLogo.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LogoSonarQubeCommunity, LogoSonarQubeServer } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { useAppState } from '../../app/components/app-state/withAppStateContext';
-import { EditionKey } from '../../types/editions';
-
-type Props = React.ComponentProps<typeof LogoSonarQubeServer>;
-
-/**
- * This component switches between the Community and Server product versions' logo
- */
-export function SonarQubeProductLogo(props: Props) {
- const { edition } = useAppState();
-
- const OfficialLogo =
- edition === EditionKey.community ? LogoSonarQubeCommunity : LogoSonarQubeServer;
-
- return <OfficialLogo {...props} />;
-}
diff --git a/server/sonar-web/src/main/js/components/branding/__tests__/SonarQubeConnectionIllustration-test.tsx b/server/sonar-web/src/main/js/components/branding/__tests__/SonarQubeConnectionIllustration-test.tsx
deleted file mode 100644
index b95f33683f1..00000000000
--- a/server/sonar-web/src/main/js/components/branding/__tests__/SonarQubeConnectionIllustration-test.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { mockAppState } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { EditionKey } from '../../../types/editions';
-import { SonarQubeConnectionIllustration } from '../SonarQubeConnectionIllustration';
-
-it.each([
- [EditionKey.community, true],
- [EditionKey.community, false],
- [EditionKey.enterprise, true],
- [EditionKey.enterprise, false],
-])('should render %s edition (variant connected %s) correctly', (edition, connected) => {
- const { container } = renderComponent(
- <SonarQubeConnectionIllustration connected={connected} />,
- '',
- { appState: mockAppState({ edition }) },
- );
-
- expect(container).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/components/branding/__tests__/__snapshots__/SonarQubeConnectionIllustration-test.tsx.snap b/server/sonar-web/src/main/js/components/branding/__tests__/__snapshots__/SonarQubeConnectionIllustration-test.tsx.snap
deleted file mode 100644
index 400a3b1350d..00000000000
--- a/server/sonar-web/src/main/js/components/branding/__tests__/__snapshots__/SonarQubeConnectionIllustration-test.tsx.snap
+++ /dev/null
@@ -1,189 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render community edition (variant connected false) correctly 1`] = `
-<div>
- <svg
- aria-hidden="true"
- fill="none"
- height="98"
- viewBox="0 0 179 98"
- width="179"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- d="M35.076 27H80.745L64.703 97H16C7.716 97 1 90.284 1 82V42c0-8.284 6.716-15 15-15h19.076Z"
- stroke="var(--echoes-color-border-weak)"
- stroke-width="2"
- />
- <path
- d="M56.55 64.34c0 1.08-1.23 1.71-2.1 1.08-.96-.72-1.56-1.86-2.04-2.76-.66-1.26-1.14-2.01-1.74-2.01-.6 0-1.05.75-1.74 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.74-2.01-.63 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.71-2.01-.6 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.48-.87-.84-1.53-1.2-1.83-.3-.24-.51-.57-.51-.96v-.21c0-1.08 1.23-1.71 2.1-1.08.96.72 1.56 1.86 2.04 2.76.66 1.26 1.11 2.01 1.71 2.01.6 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.74-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.48.87.84 1.53 1.23 1.83.3.24.51.57.51.96v.21h-.03ZM36.36 83.18c-4.95 0-9.66-1.71-13.47-4.83-.6-.51-.66-1.44-.12-2.01.51-.54 1.32-.57 1.86-.12 3.42 2.85 7.71 4.32 12.21 4.2 4.5-.12 8.7-1.83 11.97-4.83.54-.48 1.35-.48 1.86 0 .57.54.57 1.47 0 2.01-3.75 3.48-8.61 5.43-13.77 5.58h-.57.03ZM22.05 48.41c-.57-.54-.57-1.47 0-2.01 3.87-3.57 8.79-5.43 13.77-5.55 4.98-.12 9.96 1.47 14.04 4.83.6.51.66 1.44.12 2.01-.51.51-1.32.57-1.86.12-3.51-2.88-7.8-4.29-12.09-4.2-4.29.09-8.67 1.71-12.09 4.83-.54.48-1.35.48-1.86 0l-.03-.03Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M90.32 63.612h5.233v1.632H90.32V70.5h-1.632v-5.256h-5.232v-1.632h5.232v-5.256h1.632v5.256Z"
- fill="var(--echoes-color-text-subdued)"
- />
- <path
- d="M143.924 97H98.255l16.042-70H163c8.284 0 15 6.716 15 15v40c0 8.284-6.716 15-15 15h-19.076Z"
- stroke="var(--echoes-color-border-weak)"
- stroke-width="2"
- />
- <path
- d="M165.448 62.552A1.55 1.55 0 0 1 163.897 61c0-11.524-9.373-20.897-20.897-20.897a1.55 1.55 0 0 1-1.552-1.551A1.55 1.55 0 0 1 143 37c13.231 0 24 10.769 24 24a1.55 1.55 0 0 1-1.552 1.552ZM143 85c-13.231 0-24-10.769-24-24a1.55 1.55 0 0 1 1.552-1.552A1.55 1.55 0 0 1 122.103 61c0 11.524 9.373 20.897 20.897 20.897a1.55 1.55 0 0 1 1.552 1.551A1.55 1.55 0 0 1 143 85Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M157.586 62.552A1.55 1.55 0 0 1 156.034 61c0-7.19-5.844-13.035-13.034-13.035a1.55 1.55 0 0 1-1.552-1.551A1.55 1.55 0 0 1 143 44.862c8.897 0 16.138 7.241 16.138 16.138a1.55 1.55 0 0 1-1.552 1.552ZM143 77.138c-8.897 0-16.138-7.242-16.138-16.138a1.55 1.55 0 0 1 1.552-1.552A1.55 1.55 0 0 1 129.966 61c0 7.19 5.844 13.034 13.034 13.034a1.55 1.55 0 0 1 1.552 1.552A1.55 1.55 0 0 1 143 77.138ZM143.021 69.286a8.252 8.252 0 0 1-5.855-2.42c-3.228-3.228-3.228-8.483 0-11.721a8.232 8.232 0 0 1 5.855-2.431c2.213 0 4.293.858 5.855 2.43.61.611.61 1.594 0 2.194-.61.61-1.593.61-2.193 0a5.133 5.133 0 0 0-3.662-1.52c-1.387 0-2.69.537-3.662 1.52a5.187 5.187 0 0 0 0 7.324 5.188 5.188 0 0 0 7.324 0c.61-.61 1.593-.61 2.193 0 .6.61.61 1.593 0 2.193a8.256 8.256 0 0 1-5.855 2.42v.011Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- </svg>
-</div>
-`;
-
-exports[`should render community edition (variant connected true) correctly 1`] = `
-<div>
- <svg
- aria-hidden="true"
- fill="none"
- height="98"
- viewBox="0 0 179 98"
- width="179"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- clip-rule="evenodd"
- d="M72.005 26h-50.01c-8.836 0-16 7.163-16 16v40c0 8.837 7.164 16 16 16h135c8.837 0 16-7.163 16-16V42c0-8.837-7.163-16-16-16h-57.4l-2 2h59.4c7.732 0 14 6.268 14 14v40c0 7.732-6.268 14-14 14h-135c-7.732 0-14-6.268-14-14V42c0-7.732 6.268-14 14-14h52.01l-2-2Z"
- fill="var(--echoes-color-icon-success)"
- fill-rule="evenodd"
- />
- <path
- d="M66.545 64.34c0 1.08-1.23 1.71-2.1 1.08-.96-.72-1.56-1.86-2.04-2.76-.66-1.26-1.14-2.01-1.74-2.01-.6 0-1.05.75-1.74 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.74-2.01-.63 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.71-2.01-.6 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.48-.87-.84-1.53-1.2-1.83-.3-.24-.51-.57-.51-.96v-.21c0-1.08 1.23-1.71 2.1-1.08.96.72 1.56 1.86 2.04 2.76.66 1.26 1.11 2.01 1.71 2.01.6 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.74-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.48.87.84 1.53 1.23 1.83.3.24.51.57.51.96v.21h-.03ZM46.355 83.18c-4.95 0-9.66-1.71-13.47-4.83-.6-.51-.66-1.44-.12-2.01.51-.54 1.32-.57 1.86-.12 3.42 2.85 7.71 4.32 12.21 4.2 4.5-.12 8.7-1.83 11.97-4.83.54-.48 1.35-.48 1.86 0 .57.54.57 1.47 0 2.01-3.75 3.48-8.61 5.43-13.77 5.58h-.57.03ZM32.045 48.41c-.57-.54-.57-1.47 0-2.01 3.87-3.57 8.79-5.43 13.77-5.55 4.98-.12 9.96 1.47 14.04 4.83.6.51.66 1.44.12 2.01-.51.51-1.32.57-1.86.12-3.51-2.88-7.8-4.29-12.09-4.2-4.29.09-8.67 1.71-12.09 4.83-.54.48-1.35.48-1.86 0l-.03-.03Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M90.316 63.612h5.232v1.632h-5.232V70.5h-1.632v-5.256h-5.232v-1.632h5.232v-5.256h1.632v5.256Z"
- fill="var(--echoes-color-text-subdued)"
- />
- <path
- d="M155.444 63.552A1.55 1.55 0 0 1 153.892 62c0-11.524-9.373-20.897-20.897-20.897a1.55 1.55 0 0 1-1.551-1.551A1.55 1.55 0 0 1 132.995 38c13.231 0 24 10.769 24 24a1.55 1.55 0 0 1-1.551 1.552ZM132.995 86c-13.231 0-24-10.769-24-24a1.55 1.55 0 0 1 1.552-1.552A1.55 1.55 0 0 1 112.099 62c0 11.524 9.372 20.897 20.896 20.897a1.55 1.55 0 0 1 1.552 1.551A1.55 1.55 0 0 1 132.995 86Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M147.582 63.552A1.55 1.55 0 0 1 146.03 62c0-7.19-5.845-13.035-13.035-13.035a1.55 1.55 0 0 1-1.551-1.551 1.55 1.55 0 0 1 1.551-1.552c8.897 0 16.138 7.241 16.138 16.138a1.55 1.55 0 0 1-1.551 1.552ZM132.995 78.138c-8.896 0-16.138-7.242-16.138-16.138a1.55 1.55 0 0 1 1.552-1.552A1.55 1.55 0 0 1 119.961 62c0 7.19 5.845 13.034 13.034 13.034a1.55 1.55 0 0 1 1.552 1.552 1.55 1.55 0 0 1-1.552 1.552ZM133.016 70.286a8.254 8.254 0 0 1-5.855-2.42c-3.228-3.228-3.228-8.483 0-11.721a8.232 8.232 0 0 1 5.855-2.431 8.19 8.19 0 0 1 5.855 2.43c.61.611.61 1.594 0 2.194-.61.61-1.593.61-2.193 0a5.133 5.133 0 0 0-3.662-1.52c-1.386 0-2.69.537-3.662 1.52a5.189 5.189 0 0 0 0 7.324 5.188 5.188 0 0 0 7.324 0c.61-.61 1.593-.61 2.193 0 .6.61.61 1.593 0 2.193a8.254 8.254 0 0 1-5.855 2.42v.011Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M110.658 4.837a2.861 2.861 0 0 1 0 4.044L87.804 31.736a2.861 2.861 0 0 1-4.044 0L72.332 20.308a2.861 2.861 0 0 1 0-4.044 2.861 2.861 0 0 1 4.044 0l9.41 9.401 20.837-20.828a2.86 2.86 0 0 1 4.044 0h-.009Z"
- fill="var(--echoes-color-icon-success)"
- />
- </svg>
-</div>
-`;
-
-exports[`should render enterprise edition (variant connected false) correctly 1`] = `
-<div>
- <svg
- aria-hidden="true"
- fill="none"
- height="98"
- viewBox="0 0 179 98"
- width="179"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- d="M35.076 27H80.745L64.703 97H16C7.716 97 1 90.284 1 82V42c0-8.284 6.716-15 15-15h19.076Z"
- stroke="var(--echoes-color-border-weak)"
- stroke-width="2"
- />
- <path
- d="M56.55 64.34c0 1.08-1.23 1.71-2.1 1.08-.96-.72-1.56-1.86-2.04-2.76-.66-1.26-1.14-2.01-1.74-2.01-.6 0-1.05.75-1.74 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.74-2.01-.63 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.71-2.01-.6 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.48-.87-.84-1.53-1.2-1.83-.3-.24-.51-.57-.51-.96v-.21c0-1.08 1.23-1.71 2.1-1.08.96.72 1.56 1.86 2.04 2.76.66 1.26 1.11 2.01 1.71 2.01.6 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.74-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.48.87.84 1.53 1.23 1.83.3.24.51.57.51.96v.21h-.03ZM36.36 83.18c-4.95 0-9.66-1.71-13.47-4.83-.6-.51-.66-1.44-.12-2.01.51-.54 1.32-.57 1.86-.12 3.42 2.85 7.71 4.32 12.21 4.2 4.5-.12 8.7-1.83 11.97-4.83.54-.48 1.35-.48 1.86 0 .57.54.57 1.47 0 2.01-3.75 3.48-8.61 5.43-13.77 5.58h-.57.03ZM22.05 48.41c-.57-.54-.57-1.47 0-2.01 3.87-3.57 8.79-5.43 13.77-5.55 4.98-.12 9.96 1.47 14.04 4.83.6.51.66 1.44.12 2.01-.51.51-1.32.57-1.86.12-3.51-2.88-7.8-4.29-12.09-4.2-4.29.09-8.67 1.71-12.09 4.83-.54.48-1.35.48-1.86 0l-.03-.03Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M90.32 63.612h5.233v1.632H90.32V70.5h-1.632v-5.256h-5.232v-1.632h5.232v-5.256h1.632v5.256Z"
- fill="var(--echoes-color-text-subdued)"
- />
- <path
- d="M143.924 97H98.255l16.042-70H163c8.284 0 15 6.716 15 15v40c0 8.284-6.716 15-15 15h-19.076Z"
- stroke="var(--echoes-color-border-weak)"
- stroke-width="2"
- />
- <g
- clip-path="url(#sqcireq)"
- fill="var(--echoes-logos-colors-brand)"
- >
- <path
- d="M165.273 63.54a1.54 1.54 0 0 1-1.539-1.54c0-11.433-9.301-20.733-20.734-20.733a1.54 1.54 0 0 1 0-3.079c13.131 0 23.813 10.682 23.813 23.812 0 .85-.69 1.54-1.539 1.54h-.001ZM142.999 85.812c-13.13 0-23.811-10.681-23.811-23.812a1.54 1.54 0 1 1 3.078 0c0 11.433 9.3 20.733 20.733 20.733a1.54 1.54 0 0 1 0 3.079ZM149.682 63.54a1.54 1.54 0 0 1-1.54-1.54A5.147 5.147 0 0 0 143 56.859a1.54 1.54 0 0 1 0-3.079c4.534 0 8.222 3.688 8.222 8.22 0 .851-.69 1.54-1.54 1.54ZM142.999 70.222c-4.533 0-8.221-3.688-8.221-8.222a1.54 1.54 0 0 1 3.079 0 5.147 5.147 0 0 0 5.141 5.142 1.54 1.54 0 0 1 0 3.079h.001Z"
- />
- <path
- d="M157.477 63.54c-.85 0-1.54-.69-1.54-1.54 0-7.133-5.804-12.937-12.938-12.937a1.54 1.54 0 0 1 0-3.078c8.832 0 16.017 7.185 16.017 16.016 0 .85-.69 1.54-1.539 1.54v-.002ZM142.999 78.017c-8.831 0-16.016-7.185-16.016-16.017a1.54 1.54 0 0 1 3.079 0c0 7.134 5.804 12.938 12.936 12.938a1.54 1.54 0 0 1 0 3.08h.001Z"
- />
- </g>
- <defs>
- <clippath
- id="sqcireq"
- >
- <path
- d="M0 0h48v48H0z"
- fill="#fff"
- transform="translate(119 38)"
- />
- </clippath>
- </defs>
- </svg>
-</div>
-`;
-
-exports[`should render enterprise edition (variant connected true) correctly 1`] = `
-<div>
- <svg
- aria-hidden="true"
- fill="none"
- height="98"
- viewBox="0 0 179 98"
- width="179"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- clip-rule="evenodd"
- d="M72.005 26h-50.01c-8.836 0-16 7.163-16 16v40c0 8.837 7.164 16 16 16h135c8.837 0 16-7.163 16-16V42c0-8.837-7.163-16-16-16h-57.4l-2 2h59.4c7.732 0 14 6.268 14 14v40c0 7.732-6.268 14-14 14h-135c-7.732 0-14-6.268-14-14V42c0-7.732 6.268-14 14-14h52.01l-2-2Z"
- fill="var(--echoes-color-icon-success)"
- fill-rule="evenodd"
- />
- <path
- d="M66.545 64.34c0 1.08-1.23 1.71-2.1 1.08-.96-.72-1.56-1.86-2.04-2.76-.66-1.26-1.14-2.01-1.74-2.01-.6 0-1.05.75-1.74 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.74-2.01-.63 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.66-1.26-1.11-2.01-1.71-2.01-.6 0-1.05.75-1.71 2.01-.78 1.47-1.86 3.48-4.14 3.48-2.28 0-3.36-2.01-4.14-3.48-.48-.87-.84-1.53-1.2-1.83-.3-.24-.51-.57-.51-.96v-.21c0-1.08 1.23-1.71 2.1-1.08.96.72 1.56 1.86 2.04 2.76.66 1.26 1.11 2.01 1.71 2.01.6 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.71-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.66 1.26 1.11 2.01 1.74 2.01.63 0 1.05-.75 1.74-2.01.78-1.47 1.86-3.48 4.14-3.48 2.28 0 3.36 2.01 4.14 3.48.48.87.84 1.53 1.23 1.83.3.24.51.57.51.96v.21h-.03ZM46.355 83.18c-4.95 0-9.66-1.71-13.47-4.83-.6-.51-.66-1.44-.12-2.01.51-.54 1.32-.57 1.86-.12 3.42 2.85 7.71 4.32 12.21 4.2 4.5-.12 8.7-1.83 11.97-4.83.54-.48 1.35-.48 1.86 0 .57.54.57 1.47 0 2.01-3.75 3.48-8.61 5.43-13.77 5.58h-.57.03ZM32.045 48.41c-.57-.54-.57-1.47 0-2.01 3.87-3.57 8.79-5.43 13.77-5.55 4.98-.12 9.96 1.47 14.04 4.83.6.51.66 1.44.12 2.01-.51.51-1.32.57-1.86.12-3.51-2.88-7.8-4.29-12.09-4.2-4.29.09-8.67 1.71-12.09 4.83-.54.48-1.35.48-1.86 0l-.03-.03Z"
- fill="var(--echoes-logos-colors-brand)"
- />
- <path
- d="M90.316 63.612h5.232v1.632h-5.232V70.5h-1.632v-5.256h-5.232v-1.632h5.232v-5.256h1.632v5.256Z"
- fill="var(--echoes-color-text-subdued)"
- />
- <g
- clip-path="url(#sqciok)"
- fill="var(--echoes-logos-colors-brand)"
- >
- <path
- d="M155.268 63.54a1.54 1.54 0 0 1-1.539-1.54c0-11.433-9.301-20.733-20.734-20.733a1.54 1.54 0 0 1 0-3.079c13.131 0 23.814 10.682 23.814 23.812 0 .85-.69 1.54-1.54 1.54h-.001ZM132.994 85.812c-13.129 0-23.811-10.681-23.811-23.812a1.54 1.54 0 0 1 3.079 0c0 11.433 9.3 20.733 20.732 20.733a1.54 1.54 0 1 1 0 3.079ZM139.677 63.54c-.85 0-1.54-.69-1.54-1.54a5.147 5.147 0 0 0-5.142-5.141 1.54 1.54 0 0 1 0-3.079c4.534 0 8.222 3.688 8.222 8.22 0 .851-.69 1.54-1.539 1.54h-.001ZM132.994 70.222c-4.532 0-8.221-3.688-8.221-8.222a1.54 1.54 0 0 1 3.079 0 5.147 5.147 0 0 0 5.141 5.142 1.54 1.54 0 1 1 0 3.079h.001Z"
- />
- <path
- d="M147.472 63.54a1.54 1.54 0 0 1-1.539-1.54c0-7.133-5.804-12.937-12.939-12.937a1.54 1.54 0 0 1 0-3.078c8.833 0 16.018 7.185 16.018 16.016 0 .85-.69 1.54-1.54 1.54v-.002ZM132.994 78.017c-8.831 0-16.016-7.185-16.016-16.017a1.54 1.54 0 0 1 3.079 0c0 7.134 5.804 12.938 12.936 12.938a1.54 1.54 0 1 1 0 3.08h.001Z"
- />
- </g>
- <path
- d="M110.658 4.837a2.861 2.861 0 0 1 0 4.044L87.804 31.736a2.861 2.861 0 0 1-4.044 0L72.332 20.308a2.861 2.861 0 0 1 0-4.044 2.861 2.861 0 0 1 4.044 0l9.41 9.401 20.837-20.828a2.86 2.86 0 0 1 4.044 0h-.009Z"
- fill="var(--echoes-color-icon-success)"
- />
- <defs>
- <clippath
- id="sqciok"
- >
- <path
- d="M0 0h48v48H0z"
- fill="#fff"
- transform="translate(108.995 38)"
- />
- </clippath>
- </defs>
- </svg>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.css b/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.css
deleted file mode 100644
index fc7e781c032..00000000000
--- a/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.css
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-.line-tooltip {
- fill: none;
- stroke: #656565;
- stroke-width: 1px;
- shape-rendering: crispEdges;
-}
-
-.chart-mouse-events-overlay {
- fill: none;
- stroke: none;
- pointer-events: all;
-}
-
-.chart-zoomed .line-chart-path {
- clip-path: url(#chart-clip);
-}
-
-.chart-zoomed .leak-chart-rect {
- clip-path: url(#chart-clip);
-}
-
-.line-chart-event {
- fill: #fff;
- stroke: #4b9fd5;
- stroke-width: 2px;
-}
-
-.line-chart-event.VERSION {
- stroke: #4b9fd5;
-}
-
-.line-chart-event.QUALITY_GATE {
- stroke: #00aa00;
-}
-
-.line-chart-event.QUALITY_PROFILE {
- stroke: #ed7d20;
-}
-
-.line-chart-event.OTHER {
- stroke: #9139d4;
-}
-
-.new-code-legend {
- fill: #656565;
- font-size: 12px;
-}
diff --git a/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.tsx b/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.tsx
deleted file mode 100644
index 47c400227f1..00000000000
--- a/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.tsx
+++ /dev/null
@@ -1,683 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { bisector, extent, max } from 'd3-array';
-import {
- NumberValue,
- ScaleLinear,
- ScalePoint,
- ScaleTime,
- scaleLinear,
- scalePoint,
- scaleTime,
-} from 'd3-scale';
-import { area, curveBasis, line as d3Line } from 'd3-shape';
-import { flatten, isEqual, sortBy, throttle, uniq } from 'lodash';
-import * as React from 'react';
-import { CSSColor, ThemeProp, themeColor, withTheme } from '~design-system';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import { isDefined } from '../../helpers/types';
-import { Chart } from '../../types/types';
-import { LINE_CHART_DASHES } from '../activity-graph/utils';
-import './AdvancedTimeline.css';
-import './LineChart.css';
-import SplitLine from './SplitLine';
-import SplitLinePopover from './SplitLinePopover';
-
-export interface PropsWithoutTheme {
- basisCurve?: boolean;
- disableZoom?: boolean;
- endDate?: Date;
- formatYTick?: (tick: number | string) => string;
- graphDescription?: string;
- height: number;
- hideGrid?: boolean;
- hideXAxis?: boolean;
- leakPeriodDate?: Date;
- // used to avoid same y ticks labels
- maxYTicksCount?: number;
- metricType: string;
- padding?: number[];
- selectedDate?: Date;
- series: Chart.Serie[];
- showAreas?: boolean;
- splitPointDate?: Date;
- startDate?: Date;
- updateSelectedDate?: (selectedDate?: Date) => void;
- updateTooltip?: (selectedDate?: Date, tooltipXPos?: number, tooltipIdx?: number) => void;
- updateZoom?: (start?: Date, endDate?: Date) => void;
- width: number;
- zoomSpeed?: number;
-}
-
-export type Props = PropsWithoutTheme & ThemeProp;
-
-type PropsWithDefaults = Props & typeof AdvancedTimelineClass.defaultProps;
-
-type XScale = ScaleTime<number, number>;
-type YScale = ScaleLinear<number, number> | ScalePoint<number | string>;
-type YPoint = (number | string) & NumberValue;
-
-const X_LABEL_OFFSET = 15;
-
-interface State {
- maxXRange: number[];
- mouseOver?: boolean;
- selectedDate?: Date;
- selectedDateIdx?: number;
- selectedDateXPos?: number;
- xScale: XScale;
- yScale: YScale;
-}
-
-export class AdvancedTimelineClass extends React.PureComponent<Props, State> {
- static defaultProps = {
- padding: [26, 10, 50, 50],
- };
-
- constructor(props: PropsWithDefaults) {
- super(props);
-
- const scales = this.getScales(props);
- const selectedDatePos = this.getSelectedDatePos(scales.xScale, props.selectedDate);
- this.state = { ...scales, ...selectedDatePos };
- this.updateTooltipPos = throttle(this.updateTooltipPos, 40);
- this.handleZoomUpdate = throttle(this.handleZoomUpdate, 40);
- }
-
- componentDidUpdate(prevProps: PropsWithDefaults) {
- let scales;
- let selectedDatePos;
-
- if (
- this.props.metricType !== prevProps.metricType ||
- this.props.startDate !== prevProps.startDate ||
- this.props.endDate !== prevProps.endDate ||
- this.props.width !== prevProps.width ||
- this.props.padding !== prevProps.padding ||
- this.props.height !== prevProps.height ||
- this.props.series !== prevProps.series
- ) {
- scales = this.getScales(this.props as PropsWithDefaults);
- this.setState({ ...scales });
-
- if (this.state.selectedDate != null) {
- selectedDatePos = this.getSelectedDatePos(scales.xScale, this.state.selectedDate);
- }
- }
-
- if (!isEqual(this.props.selectedDate, prevProps.selectedDate)) {
- const xScale = scales ? scales.xScale : this.state.xScale;
-
- selectedDatePos = this.getSelectedDatePos(xScale, this.props.selectedDate);
- }
-
- if (selectedDatePos) {
- this.setState({ ...selectedDatePos });
-
- if (this.props.updateTooltip) {
- this.props.updateTooltip(
- selectedDatePos.selectedDate,
- selectedDatePos.selectedDateXPos,
- selectedDatePos.selectedDateIdx,
- );
- }
- }
- }
-
- getRatingScale = (availableHeight: number) => {
- return scalePoint<number>().domain([5, 4, 3, 2, 1]).range([availableHeight, 0]);
- };
-
- getLevelScale = (availableHeight: number) => {
- return scalePoint().domain(['ERROR', 'WARN', 'OK']).range([availableHeight, 0]);
- };
-
- getYScale = (
- props: PropsWithDefaults,
- availableHeight: number,
- flatData: Chart.Point[],
- ): YScale => {
- if (props.metricType === MetricType.Rating) {
- return this.getRatingScale(availableHeight);
- } else if (props.metricType === MetricType.Level) {
- return this.getLevelScale(availableHeight);
- }
-
- return scaleLinear()
- .range([availableHeight, 0])
- .domain([0, max(flatData, (d) => Number(d.y || 0)) || 1])
- .nice();
- };
-
- isYScaleLinear(yScale: YScale): yScale is ScaleLinear<number, number> {
- return 'ticks' in yScale;
- }
-
- getXScale = (
- { startDate, endDate }: PropsWithDefaults,
- availableWidth: number,
- flatData: Chart.Point[],
- ) => {
- const dateRange = extent(flatData, (d) => d.x) as [Date, Date];
- const start = startDate && startDate > dateRange[0] ? startDate : dateRange[0];
- const end = endDate && endDate < dateRange[1] ? endDate : dateRange[1];
-
- const xScale: ScaleTime<number, number> = scaleTime()
- .domain(sortBy([start, end]))
- .range([0, availableWidth])
- .clamp(false);
-
- return {
- xScale,
- maxXRange: dateRange.map(xScale),
- };
- };
-
- getScales = (props: PropsWithDefaults) => {
- const availableWidth = props.width - props.padding[1] - props.padding[3];
- const availableHeight = props.height - props.padding[0] - props.padding[2];
- const flatData = flatten(props.series.map((serie) => serie.data));
-
- return {
- ...this.getXScale(props, availableWidth, flatData),
- yScale: this.getYScale(props, availableHeight, flatData),
- };
- };
-
- getSelectedDatePos = (xScale: XScale, selectedDate?: Date) => {
- const firstSerie = this.props.series[0];
-
- if (selectedDate && firstSerie) {
- const idx = firstSerie.data.findIndex((p) => p.x.valueOf() === selectedDate.valueOf());
- const xRange = sortBy(xScale.range());
- const xPos = xScale(selectedDate);
- if (idx >= 0 && xPos >= xRange[0] && xPos <= xRange[1]) {
- return {
- selectedDate,
- selectedDateXPos: xScale(selectedDate),
- selectedDateIdx: idx,
- };
- }
- }
-
- return { selectedDate: undefined, selectedDateXPos: undefined, selectedDateIdx: undefined };
- };
-
- handleWheel = (event: React.WheelEvent<SVGElement>) => {
- const { zoomSpeed = 1 } = this.props;
- const { maxXRange, xScale } = this.state;
-
- const parentBbox = event.currentTarget.getBoundingClientRect();
- const mouseXPos = (event.pageX - parentBbox.left) / parentBbox.width;
- const xRange = xScale.range();
-
- const speed = (event.deltaMode as number | undefined)
- ? (25 / event.deltaMode) * zoomSpeed
- : zoomSpeed;
-
- const leftPos = xRange[0] - Math.round(speed * event.deltaY * mouseXPos);
- const rightPos = xRange[1] + Math.round(speed * event.deltaY * (1 - mouseXPos));
- const startDate = leftPos > maxXRange[0] ? xScale.invert(leftPos) : undefined;
- const endDate = rightPos < maxXRange[1] ? xScale.invert(rightPos) : undefined;
- this.handleZoomUpdate(startDate, endDate);
- };
-
- handleZoomUpdate = (startDate?: Date, endDate?: Date) => {
- if (this.props.updateZoom) {
- this.props.updateZoom(startDate, endDate);
- }
- };
-
- handleMouseMove = (event: React.MouseEvent<SVGElement>) => {
- const parentBbox = event.currentTarget.getBoundingClientRect();
- this.updateTooltipPos(event.pageX - parentBbox.left);
- };
-
- handleMouseEnter = () => {
- this.setState({ mouseOver: true });
- };
-
- handleMouseOut = () => {
- const { updateTooltip } = this.props;
-
- if (updateTooltip) {
- this.setState({
- mouseOver: false,
- selectedDate: undefined,
- selectedDateXPos: undefined,
- selectedDateIdx: undefined,
- });
-
- updateTooltip(undefined, undefined, undefined);
- }
- };
-
- handleClick = () => {
- const { updateSelectedDate } = this.props;
-
- if (updateSelectedDate) {
- updateSelectedDate(this.state.selectedDate || undefined);
- }
- };
-
- updateTooltipPos = (xPos: number) => {
- this.setState((state) => {
- const firstSerie = this.props.series[0];
-
- if (state.mouseOver && firstSerie) {
- const { updateTooltip } = this.props;
- const date = state.xScale.invert(xPos);
- const bisectX = bisector<Chart.Point, Date>((d) => d.x).right;
- let idx = bisectX(firstSerie.data, date);
-
- if (idx >= 0) {
- const previousPoint = firstSerie.data[idx - 1];
- const nextPoint = firstSerie.data[idx];
-
- if (
- !nextPoint ||
- (previousPoint &&
- date.valueOf() - previousPoint.x.valueOf() <= nextPoint.x.valueOf() - date.valueOf())
- ) {
- idx--;
- }
-
- const selectedDate = firstSerie.data[idx].x;
- const xPos = state.xScale(selectedDate);
-
- if (updateTooltip) {
- updateTooltip(selectedDate, xPos, idx);
- }
-
- return { selectedDate, selectedDateXPos: xPos, selectedDateIdx: idx };
- }
- }
-
- return null;
- });
- };
-
- renderHorizontalGrid = () => {
- const { formatYTick, maxYTicksCount = 4 } = this.props;
- const { xScale, yScale } = this.state;
- const hasTicks = this.isYScaleLinear(yScale);
-
- let ticks: Array<string | number> = hasTicks ? yScale.ticks(maxYTicksCount) : yScale.domain();
-
- if (!ticks.length) {
- ticks.push(yScale.domain()[1]);
- }
-
- // if there are duplicated ticks, that means 4 ticks are too much for this data
- // so let's just use the domain values (min and max)
- if (formatYTick) {
- const formattedTicks = ticks.map((tick) => formatYTick(tick));
- if (ticks.length > uniq(formattedTicks).length) {
- ticks = yScale.domain();
- }
- }
-
- return (
- <g>
- {ticks.map((tick) => {
- const y = yScale(tick as YPoint);
-
- return (
- <g key={tick}>
- {formatYTick != null && (
- <text
- className="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- textAnchor="end"
- x={xScale.range()[0]}
- y={y}
- >
- {formatYTick(tick)}
- </text>
- )}
- <line
- className="line-chart-grid"
- x1={xScale.range()[0]}
- x2={xScale.range()[1]}
- y1={y}
- y2={y}
- />
- </g>
- );
- })}
- </g>
- );
- };
-
- renderXAxisTicks = () => {
- const { xScale, yScale } = this.state;
- const format = xScale.tickFormat(7);
- const ticks = xScale.ticks(7);
- const y = yScale.range()[0];
-
- return (
- <g transform="translate(0, 20)">
- {ticks.slice(0, -1).map((tick, index) => {
- const x = xScale(tick);
-
- return (
- <text
- className="line-chart-tick sw-typo-default"
- // eslint-disable-next-line react/no-array-index-key
- key={index}
- textAnchor="end"
- transform={`rotate(-35, ${x + X_LABEL_OFFSET}, ${y})`}
- x={x + X_LABEL_OFFSET}
- y={y}
- >
- {format(tick)}
- </text>
- );
- })}
- </g>
- );
- };
-
- renderLeak = () => {
- const { leakPeriodDate, theme } = this.props;
-
- if (!leakPeriodDate) {
- return null;
- }
-
- const { xScale, yScale } = this.state;
- const yRange = yScale.range();
- const xRange = xScale.range();
-
- // truncate leak to start of chart to prevent weird visual artifacts when too far left
- // (occurs when leak starts a long time before first analysis)
- const leakStart = Math.max(xScale(leakPeriodDate), xRange[0]);
-
- const leakWidth = xRange[xRange.length - 1] - leakStart;
-
- if (leakWidth < 1) {
- return null;
- }
-
- return (
- <rect
- className="leak-chart-rect"
- fill={themeColor('newCodeLegend')({ theme })}
- height={yRange[0] - yRange[yRange.length - 1]}
- width={leakWidth}
- x={leakStart}
- y={yRange[yRange.length - 1]}
- />
- );
- };
-
- renderLines = () => {
- const { series, theme } = this.props;
- const { xScale, yScale } = this.state;
-
- const lineGenerator = d3Line<Chart.Point>()
- .defined((d) => Boolean(d.y || d.y === 0))
- .x((d) => xScale(d.x))
- .y((d) => yScale(d.y as YPoint) as number);
-
- if (this.props.basisCurve) {
- lineGenerator.curve(curveBasis);
- }
-
- return (
- <g>
- {series.map((serie, idx) => (
- <path
- className={classNames('line-chart-path', `line-chart-path-${idx}`)}
- d={lineGenerator(serie.data) ?? undefined}
- key={serie.name}
- stroke={themeColor(`graphLineColor.${idx}` as Parameters<typeof themeColor>[0])({
- theme,
- })}
- strokeDasharray={LINE_CHART_DASHES[idx]}
- />
- ))}
- </g>
- );
- };
-
- renderDots = () => {
- const { series, theme } = this.props;
- const { xScale, yScale } = this.state;
-
- return (
- <g>
- {series
- .map((serie, serieIdx) =>
- serie.data
- .map((point, idx) => {
- const pointNotDefined = !point.y && point.y !== 0;
-
- const hasPointBefore =
- serie.data[idx - 1] && (serie.data[idx - 1].y || serie.data[idx - 1].y === 0);
-
- const hasPointAfter =
- serie.data[idx + 1] && (serie.data[idx + 1].y || serie.data[idx + 1].y === 0);
-
- if (pointNotDefined || hasPointBefore || hasPointAfter) {
- return undefined;
- }
-
- return (
- <circle
- cx={xScale(point.x)}
- cy={yScale(point.y as YPoint)}
- fill={themeColor(
- `graphLineColor.${serieIdx}` as Parameters<typeof themeColor>[0],
- )({
- theme,
- })}
- key={`${serie.name}${point.x}${point.y}`}
- r="2"
- stroke="white"
- strokeWidth={1}
- />
- );
- })
- .filter(isDefined),
- )
- .filter((dots) => dots.length > 0)}
- </g>
- );
- };
-
- renderAreas = () => {
- const { series, basisCurve } = this.props;
- const { xScale, yScale } = this.state;
-
- const areaGenerator = area<Chart.Point>()
- .defined((d) => Boolean(d.y || d.y === 0))
- .x((d) => xScale(d.x))
- .y1((d) => yScale(d.y as YPoint) as number)
- .y0(yScale(0) as number);
-
- if (basisCurve) {
- areaGenerator.curve(curveBasis);
- }
-
- return (
- <g>
- {series.map((serie, idx) => (
- <StyledArea d={areaGenerator(serie.data) ?? undefined} index={idx} key={serie.name} />
- ))}
- </g>
- );
- };
-
- renderSelectedDate = () => {
- const { series, theme } = this.props;
- const { selectedDateIdx, selectedDateXPos, yScale } = this.state;
- const firstSerie = series[0];
-
- if (selectedDateIdx == null || selectedDateXPos == null || !firstSerie) {
- return null;
- }
-
- return (
- <g>
- <line
- className="line-tooltip"
- x1={selectedDateXPos}
- x2={selectedDateXPos}
- y1={yScale.range()[0]}
- y2={yScale.range()[1]}
- />
- {series.map((serie, idx) => {
- const point = serie.data[selectedDateIdx];
-
- if (!point || (!point.y && point.y !== 0)) {
- return null;
- }
-
- return (
- <circle
- cx={selectedDateXPos}
- cy={yScale(point.y as YPoint)}
- fill={themeColor(`graphLineColor.${idx}` as Parameters<typeof themeColor>[0])({
- theme,
- })}
- key={serie.name}
- r="4"
- stroke="white"
- strokeWidth={1}
- />
- );
- })}
- </g>
- );
- };
-
- renderClipPath = () => {
- const { yScale, xScale } = this.state;
-
- return (
- <defs>
- <clipPath id="chart-clip">
- <rect
- height={yScale.range()[0] + 10}
- transform="translate(0,-5)"
- width={xScale.range()[1]}
- />
- </clipPath>
- </defs>
- );
- };
-
- renderMouseEventsOverlay = (zoomEnabled: boolean) => {
- const { yScale, xScale } = this.state;
-
- const mouseEvents: Partial<React.SVGProps<SVGRectElement>> = {};
-
- if (zoomEnabled) {
- mouseEvents.onWheel = this.handleWheel;
- }
-
- if (this.props.updateTooltip) {
- mouseEvents.onMouseEnter = this.handleMouseEnter;
- mouseEvents.onMouseMove = this.handleMouseMove;
- mouseEvents.onMouseOut = this.handleMouseOut;
- }
-
- if (this.props.updateSelectedDate) {
- mouseEvents.onClick = this.handleClick;
- }
-
- return (
- <rect
- className="chart-mouse-events-overlay"
- height={yScale.range()[0]}
- width={xScale.range()[1]}
- {...mouseEvents}
- />
- );
- };
-
- render() {
- const {
- width,
- height,
- padding,
- disableZoom,
- startDate,
- endDate,
- leakPeriodDate,
- hideGrid,
- hideXAxis,
- showAreas,
- graphDescription,
- splitPointDate,
- } = this.props as PropsWithDefaults;
- const { xScale, yScale } = this.state;
-
- if (!width || !height) {
- return <div />;
- }
-
- const zoomEnabled = !disableZoom && this.props.updateZoom != null;
- const isZoomed = Boolean(startDate ?? endDate);
-
- return (
- <div className="sw-relative">
- <svg
- aria-label={graphDescription}
- className={classNames('line-chart', { 'chart-zoomed': isZoomed })}
- height={height}
- width={width}
- >
- {zoomEnabled && this.renderClipPath()}
- <g transform={`translate(${padding[3]}, ${padding[0]})`}>
- {leakPeriodDate != null && this.renderLeak()}
- {!hideGrid && this.renderHorizontalGrid()}
- {!hideXAxis && this.renderXAxisTicks()}
- {showAreas && this.renderAreas()}
- {this.renderLines()}
- {this.renderDots()}
- {this.renderSelectedDate()}
- {this.renderMouseEventsOverlay(zoomEnabled)}
- <SplitLine splitPointDate={splitPointDate} xScale={xScale} yScale={yScale} />
- </g>
- </svg>
- <SplitLinePopover
- paddingLeft={padding[3]}
- splitPointDate={splitPointDate}
- xScale={xScale}
- />
- </div>
- );
- }
-}
-
-const AREA_OPACITY = 0.15;
-
-const StyledArea = styled.path<{ index: number }>`
- clip-path: url(#chart-clip);
- fill: ${({ index }) => themeColor(`graphLineColor.${index}` as CSSColor, AREA_OPACITY)};
-`;
-
-export const AdvancedTimeline = withTheme<PropsWithoutTheme>(AdvancedTimelineClass);
diff --git a/server/sonar-web/src/main/js/components/charts/ColorBoxLegend.tsx b/server/sonar-web/src/main/js/components/charts/ColorBoxLegend.tsx
deleted file mode 100644
index e58453cb7ca..00000000000
--- a/server/sonar-web/src/main/js/components/charts/ColorBoxLegend.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { ScaleLinear, ScaleOrdinal } from 'd3-scale';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-
-interface Props {
- colorNA?: string;
- colorScale:
- | ScaleOrdinal<string, string> // used for LEVEL type
- | ScaleLinear<string, string | number>; // used for RATING or PERCENT type
- metricType: string;
-}
-
-export default function ColorBoxLegend({ colorScale, colorNA, metricType }: Props) {
- const colorDomain: Array<number | string> = colorScale.domain();
- const colorRange = colorScale.range();
- return (
- <div className="sw-flex sw-justify-center sw-gap-6">
- {colorDomain.map((value, idx) => (
- <div key={value}>
- <LegendRect style={{ borderColor: colorRange[idx] }}>
- <span style={{ backgroundColor: colorRange[idx] }} />
- </LegendRect>
- {formatMeasure(value, metricType)}
- </div>
- ))}
- {colorNA && (
- <div>
- <LegendRect style={{ borderColor: colorNA }}>
- <span style={{ backgroundColor: colorNA }} />
- </LegendRect>
- N/A
- </div>
- )}
- </div>
- );
-}
-
-const LegendRect = styled.span`
- display: inline-block;
- margin-top: 1px;
- margin-right: 4px;
- border: 1px solid;
-
- & span {
- display: block;
- width: 8px;
- height: 8px;
- }
-`;
diff --git a/server/sonar-web/src/main/js/components/charts/ColorGradientLegend.tsx b/server/sonar-web/src/main/js/components/charts/ColorGradientLegend.tsx
deleted file mode 100644
index 0d79a2e980a..00000000000
--- a/server/sonar-web/src/main/js/components/charts/ColorGradientLegend.tsx
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { ScaleLinear, ScaleOrdinal } from 'd3-scale';
-import * as React from 'react';
-import { CSSColor, themeColor } from '~design-system';
-
-interface Props {
- className?: string;
- colorScale:
- | ScaleOrdinal<string, string> // used for LEVEL type
- | ScaleLinear<string, string | number>;
- height: number;
- // used for RATING or PERCENT type
- naColors?: [CSSColor, CSSColor];
- padding?: [number, number, number, number];
- showColorNA?: boolean;
- width: number;
-}
-
-const NA_SPACING = 4;
-const NA_GRADIENT_LINE_INCREMENTS = [0, 8, 16, 24];
-
-export default function ColorGradientLegend({
- className,
- colorScale,
- padding = [12, 24, 0, 0],
- height,
- showColorNA = false,
- naColors = ['rgb(36,36,36)', 'rgb(120,120,120)'],
- width,
-}: Props) {
- const colorRange: Array<string | number> = colorScale.range();
- const colorDomain: Array<string | number> = colorScale.domain();
- const lastColorIdx = colorRange.length - 1;
- const lastDomainIdx = colorDomain.length - 1;
- const widthNoPadding = width - padding[1];
- const rectHeight = height - padding[0];
- return (
- <svg className={className} height={height} width={width}>
- <defs>
- <linearGradient id="gradient-legend">
- {colorRange.map((color, idx) => (
- // eslint-disable-next-line react/no-array-index-key
- <stop key={idx} offset={idx / lastColorIdx} stopColor={String(color)} />
- ))}
- </linearGradient>
-
- <pattern
- id="stripes"
- width="30"
- height="30"
- patternTransform="rotate(45 0 0)"
- patternUnits="userSpaceOnUse"
- >
- {NA_GRADIENT_LINE_INCREMENTS.map((i) => (
- <React.Fragment key={i}>
- <line
- x1={i}
- y1="0"
- x2={i}
- y2="30"
- style={{ stroke: naColors[0], strokeWidth: NA_SPACING }}
- />
- <line
- x1={i + NA_SPACING}
- y1="0"
- x2={i + NA_SPACING}
- y2="30"
- style={{ stroke: naColors[1], strokeWidth: NA_SPACING }}
- />
- </React.Fragment>
- ))}
- </pattern>
- </defs>
- <g transform={`translate(${padding[3]}, ${padding[0]})`}>
- <rect fill="url(#gradient-legend)" height={rectHeight} width={widthNoPadding} x={0} y={0} />
- {colorDomain.map((d, idx) => (
- <GradientLegendText
- dy="-2px"
- // eslint-disable-next-line react/no-array-index-key
- key={idx}
- x={widthNoPadding * (idx / lastDomainIdx)}
- y={0}
- >
- {d}
- </GradientLegendText>
- ))}
- </g>
- {showColorNA && (
- <g transform={`translate(${widthNoPadding}, ${padding[0]})`}>
- <rect
- fill="url(#stripes)"
- height={rectHeight}
- width={padding[1] - NA_SPACING}
- x={NA_SPACING}
- y={0}
- />
- <GradientLegendTextBase dy="-2px" x={NA_SPACING + (padding[1] - NA_SPACING) / 2} y={0}>
- N/A
- </GradientLegendTextBase>
- </g>
- )}
- </svg>
- );
-}
-
-const GradientLegendTextBase = styled.text`
- text-anchor: middle;
- fill: ${themeColor('pageContent')};
- font-size: 10px;
-`;
-
-const GradientLegendText = styled(GradientLegendTextBase)`
- &:first-of-type {
- text-anchor: start;
- }
-
- &:last-of-type {
- text-anchor: end;
- }
-`;
diff --git a/server/sonar-web/src/main/js/components/charts/DonutChart.tsx b/server/sonar-web/src/main/js/components/charts/DonutChart.tsx
deleted file mode 100644
index ee7885fa876..00000000000
--- a/server/sonar-web/src/main/js/components/charts/DonutChart.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { arc as d3Arc, pie as d3Pie, PieArcDatum } from 'd3-shape';
-
-export interface DataPoint {
- fill: string;
- value: number;
-}
-
-export interface DonutChartProps {
- data: DataPoint[];
- height: number;
- padAngle?: number;
- padding?: [number, number, number, number];
- thickness: number;
- width: number;
-}
-
-export default function DonutChart(props: DonutChartProps) {
- const { height, padding = [0, 0, 0, 0], width, padAngle, data, thickness } = props;
-
- const availableWidth = width - padding[1] - padding[3];
- const availableHeight = height - padding[0] - padding[2];
-
- const size = Math.min(availableWidth, availableHeight);
- const radius = Math.floor(size / 2);
-
- const pie = d3Pie<any, DataPoint>()
- .sort(null)
- .value((d) => d.value);
-
- if (padAngle !== undefined) {
- pie.padAngle(padAngle);
- }
-
- const sectors = pie(data).map((d, i) => {
- return (
- <Sector
- data={d}
- fill={data[i].fill}
- // eslint-disable-next-line react/no-array-index-key
- key={i}
- radius={radius}
- thickness={thickness}
- />
- );
- });
-
- return (
- <svg className="donut-chart" height={height} width={width}>
- <g transform={`translate(${padding[3]}, ${padding[0]})`}>
- <g transform={`translate(${radius}, ${radius})`}>{sectors}</g>
- </g>
- </svg>
- );
-}
-
-interface SectorProps {
- data: PieArcDatum<DataPoint>;
- fill: string;
- radius: number;
- thickness: number;
-}
-
-function Sector(props: SectorProps) {
- const arc = d3Arc<any, PieArcDatum<DataPoint>>()
- .outerRadius(props.radius)
- .innerRadius(props.radius - props.thickness);
- const d = arc(props.data) as string;
- return <path d={d} style={{ fill: props.fill }} />;
-}
diff --git a/server/sonar-web/src/main/js/components/charts/LanguageDistribution.tsx b/server/sonar-web/src/main/js/components/charts/LanguageDistribution.tsx
deleted file mode 100644
index cac224094f8..00000000000
--- a/server/sonar-web/src/main/js/components/charts/LanguageDistribution.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { sortBy } from 'lodash';
-import { Histogram } from '~design-system';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import withLanguagesContext from '../../app/components/languages/withLanguagesContext';
-import { translate } from '../../helpers/l10n';
-import { Languages } from '../../types/languages';
-
-export interface LanguageDistributionProps {
- distribution: string;
- languages: Languages;
-}
-
-const NUMBER_FORMAT_THRESHOLD = 1000;
-
-export function LanguageDistribution(props: LanguageDistributionProps) {
- const { distribution, languages } = props;
- let parsedDistribution = distribution.split(';').map((point) => {
- const tokens = point.split('=');
- return { language: tokens[0], lines: parseInt(tokens[1], 10) };
- });
-
- parsedDistribution = sortBy(parsedDistribution, (d) => -d.lines);
-
- const data = parsedDistribution.map((d) => d.lines);
- const yTicks = parsedDistribution
- .map((d) => getLanguageName(languages, d.language))
- .map(cutLanguageName);
- const yTooltips = parsedDistribution.map((d) =>
- d.lines > NUMBER_FORMAT_THRESHOLD ? formatMeasure(d.lines, MetricType.Integer) : '',
- );
- const yValues = parsedDistribution.map((d) => formatMeasure(d.lines, MetricType.ShortInteger));
-
- return (
- <Histogram
- bars={data}
- height={parsedDistribution.length * 25}
- leftAlignTicks
- padding={[0, 60, 0, 80]}
- width={260}
- yTicks={yTicks}
- yTooltips={yTooltips}
- yValues={yValues}
- />
- );
-}
-
-function getLanguageName(languages: Languages, langKey: string) {
- if (langKey === '<null>') {
- return translate('unknown');
- }
- const lang = languages[langKey];
- return lang ? lang.name : langKey;
-}
-
-function cutLanguageName(name: string) {
- return name.length > 10 ? `${name.substr(0, 7)}...` : name;
-}
-
-export default withLanguagesContext(LanguageDistribution);
diff --git a/server/sonar-web/src/main/js/components/charts/LineChart.css b/server/sonar-web/src/main/js/components/charts/LineChart.css
deleted file mode 100644
index c7b40167d56..00000000000
--- a/server/sonar-web/src/main/js/components/charts/LineChart.css
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-.line-chart-path {
- fill: none;
- stroke-width: 2px;
-}
-
-.line-chart-point {
- fill: #fff;
- stroke: #4b9fd5;
- stroke-width: 2px;
-}
-
-.line-chart-tick {
- fill: #656565;
-}
-
-.line-chart-tick-x {
- text-anchor: end;
-}
-
-.line-chart-tick-x-right {
- text-anchor: start;
-}
-
-.line-chart-grid {
- shape-rendering: crispedges;
- stroke: #eee;
-}
diff --git a/server/sonar-web/src/main/js/components/charts/SplitLine.tsx b/server/sonar-web/src/main/js/components/charts/SplitLine.tsx
deleted file mode 100644
index 0338936a50b..00000000000
--- a/server/sonar-web/src/main/js/components/charts/SplitLine.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ScaleLinear, ScalePoint, ScaleTime } from 'd3-scale';
-import { shouldShowSplitLine } from '../../helpers/activity-graph';
-
-interface Props {
- splitPointDate?: Date;
- xScale: ScaleTime<number, number>;
- yScale: ScaleLinear<number, number> | ScalePoint<number | string>;
-}
-
-export default function SplitLine({ splitPointDate, xScale, yScale }: Readonly<Props>) {
- const showSplitLine = shouldShowSplitLine(splitPointDate, xScale);
-
- if (!showSplitLine) {
- return null;
- }
-
- return (
- <line
- className="line-tooltip"
- strokeDasharray="2"
- x1={xScale(splitPointDate)}
- x2={xScale(splitPointDate)}
- y1={yScale.range()[0]}
- y2={yScale.range()[1] - 10}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/charts/SplitLinePopover.tsx b/server/sonar-web/src/main/js/components/charts/SplitLinePopover.tsx
deleted file mode 100644
index 54c2f05ae0d..00000000000
--- a/server/sonar-web/src/main/js/components/charts/SplitLinePopover.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ButtonIcon, IconInfo, Popover } from '@sonarsource/echoes-react';
-import { ScaleTime } from 'd3-scale';
-import * as React from 'react';
-import { shouldShowSplitLine } from '../../helpers/activity-graph';
-import { DocLink } from '../../helpers/doc-links';
-import { translate } from '../../helpers/l10n';
-import DocumentationLink from '../common/DocumentationLink';
-
-interface Props {
- paddingLeft: number;
- splitPointDate?: Date;
- xScale: ScaleTime<number, number>;
-}
-
-export default function SplitLinePopover({ paddingLeft, splitPointDate, xScale }: Readonly<Props>) {
- const [popoverOpen, setPopoverOpen] = React.useState(false);
- const showSplitLine = shouldShowSplitLine(splitPointDate, xScale);
-
- if (!showSplitLine) {
- return null;
- }
-
- return (
- <Popover
- isOpen={popoverOpen}
- title={translate('project_activity.graphs.rating_split.title')}
- description={translate('project_activity.graphs.rating_split.description')}
- footer={
- <DocumentationLink standalone to={DocLink.MetricDefinitions}>
- {translate('learn_more')}
- </DocumentationLink>
- }
- >
- <ButtonIcon
- isIconFilled
- style={{ left: `${Math.round(xScale(splitPointDate)) + paddingLeft}px` }}
- className="sw-border-none sw-absolute sw-bg-transparent sw--top-3 sw--translate-x-2/4"
- ariaLabel={translate('project_activity.graphs.rating_split.info_icon')}
- Icon={IconInfo}
- onClick={() => setPopoverOpen(!popoverOpen)}
- />
- </Popover>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/charts/ZoomTimeLine.tsx b/server/sonar-web/src/main/js/components/charts/ZoomTimeLine.tsx
deleted file mode 100644
index de6e16507b8..00000000000
--- a/server/sonar-web/src/main/js/components/charts/ZoomTimeLine.tsx
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { extent, max } from 'd3-array';
-import { ScaleTime, scaleLinear, scalePoint, scaleTime } from 'd3-scale';
-import { area, curveBasis, line as d3Line } from 'd3-shape';
-import { flatten, sortBy, throttle } from 'lodash';
-import * as React from 'react';
-import Draggable, { DraggableBounds, DraggableCore, DraggableData } from 'react-draggable';
-import { CSSColor, DraggableIcon, themeColor } from '~design-system';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import { Chart } from '../../types/types';
-import { LINE_CHART_DASHES } from '../activity-graph/utils';
-
-export interface Props {
- basisCurve?: boolean;
- endDate?: Date;
- height: number;
- leakPeriodDate?: Date;
- metricType: string;
- padding?: number[];
- series: Chart.Serie[];
- showAreas?: boolean;
- startDate?: Date;
- updateZoom: (start?: Date, endDate?: Date) => void;
- width: number;
-}
-
-const DEFAULT_PADDING = [0, 0, 18, 0];
-
-interface State {
- newZoomStart?: number;
- overlayLeftPos?: number;
-}
-
-type XScale = ScaleTime<number, number>;
-
-export class ZoomTimeLine extends React.PureComponent<Props, State> {
- constructor(props: Props) {
- super(props);
-
- this.state = {};
- this.handleZoomUpdate = throttle(this.handleZoomUpdate, 40);
- }
-
- getRatingScale = (availableHeight: number) => {
- return scalePoint<number>().domain([5, 4, 3, 2, 1]).range([availableHeight, 0]);
- };
-
- getLevelScale = (availableHeight: number) => {
- return scalePoint().domain(['ERROR', 'WARN', 'OK']).range([availableHeight, 0]);
- };
-
- getYScale = (availableHeight: number, flatData: Chart.Point[]) => {
- if (this.props.metricType === MetricType.Rating) {
- return this.getRatingScale(availableHeight);
- } else if (this.props.metricType === MetricType.Level) {
- return this.getLevelScale(availableHeight);
- }
-
- return scaleLinear()
- .range([availableHeight, 0])
- .domain([0, max(flatData, (d) => Number(d.y || 0)) as number])
- .nice();
- };
-
- getXScale = (availableWidth: number, flatData: Chart.Point[]): XScale => {
- return scaleTime()
- .domain(extent(flatData, (d) => d.x) as [Date, Date])
- .range([0, availableWidth])
- .clamp(true);
- };
-
- getScales = () => {
- const { padding = DEFAULT_PADDING } = this.props;
-
- const availableWidth = this.props.width - padding[1] - padding[3];
- const availableHeight = this.props.height - padding[0] - padding[2];
- const flatData = flatten(this.props.series.map((serie) => serie.data));
-
- return {
- xScale: this.getXScale(availableWidth, flatData),
- yScale: this.getYScale(availableHeight, flatData),
- };
- };
-
- handleDoubleClick = (xScale: XScale, xDim: number[]) => () => {
- this.handleZoomUpdate(xScale, xDim);
- };
-
- handleSelectionDrag =
- (xScale: XScale, width: number, xDim: number[], checkDelta = false) =>
- (_: MouseEvent, data: DraggableData) => {
- if (!checkDelta || data.deltaX) {
- const x = Math.max(xDim[0], Math.min(data.x, xDim[1] - width));
- this.handleZoomUpdate(xScale, [x, width + x]);
- }
- };
-
- handleSelectionHandleDrag =
- (xScale: XScale, fixedX: number, xDim: number[], handleDirection: string, checkDelta = false) =>
- (_: MouseEvent, data: DraggableData) => {
- if (!checkDelta || data.deltaX) {
- const x = Math.max(xDim[0], Math.min(data.x, xDim[1]));
- this.handleZoomUpdate(xScale, handleDirection === 'right' ? [fixedX, x] : [x, fixedX]);
- }
- };
-
- handleNewZoomDragStart = (xDim: number[]) => (_: MouseEvent, data: DraggableData) => {
- const overlayLeftPos = data.node.getBoundingClientRect().left;
-
- this.setState({
- overlayLeftPos,
- newZoomStart: Math.round(Math.max(xDim[0], Math.min(data.x - overlayLeftPos, xDim[1]))),
- });
- };
-
- handleNewZoomDrag = (xScale: XScale, xDim: number[]) => (_: MouseEvent, data: DraggableData) => {
- const { newZoomStart, overlayLeftPos } = this.state;
-
- if (newZoomStart != null && overlayLeftPos != null && data.deltaX) {
- this.handleZoomUpdate(
- xScale,
- sortBy([newZoomStart, Math.max(xDim[0], Math.min(data.x - overlayLeftPos, xDim[1]))]),
- );
- }
- };
-
- handleNewZoomDragEnd =
- (xScale: XScale, xDim: number[]) => (_: MouseEvent, data: DraggableData) => {
- const { newZoomStart, overlayLeftPos } = this.state;
-
- if (newZoomStart !== undefined && overlayLeftPos !== undefined) {
- const x = Math.round(Math.max(xDim[0], Math.min(data.x - overlayLeftPos, xDim[1])));
- this.handleZoomUpdate(xScale, newZoomStart === x ? xDim : sortBy([newZoomStart, x]));
- this.setState({ newZoomStart: undefined, overlayLeftPos: undefined });
- }
- };
-
- handleZoomUpdate = (xScale: XScale, xArray: number[]) => {
- const xRange = xScale.range();
-
- const startDate =
- xArray[0] > xRange[0] && xArray[0] < xRange[xRange.length - 1]
- ? xScale.invert(xArray[0])
- : undefined;
-
- const endDate =
- xArray[1] > xRange[0] && xArray[1] < xRange[xRange.length - 1]
- ? xScale.invert(xArray[1])
- : undefined;
-
- this.props.updateZoom(startDate, endDate);
- };
-
- renderBaseLine = (xScale: XScale, yScale: { range: () => number[] }) => {
- return (
- <StyledBaseLine
- x1={xScale.range()[0]}
- x2={xScale.range()[1]}
- y1={yScale.range()[0]}
- y2={yScale.range()[0]}
- />
- );
- };
-
- renderNewCode = (xScale: XScale, yScale: { range: () => number[] }) => {
- const { leakPeriodDate } = this.props;
-
- if (!leakPeriodDate) {
- return null;
- }
-
- const yRange = yScale.range();
-
- return (
- <StyledNewCodeLegend
- height={yRange[0] - yRange[yRange.length - 1]}
- width={xScale.range()[1] - xScale(leakPeriodDate)}
- x={xScale(leakPeriodDate)}
- y={yRange[yRange.length - 1]}
- />
- );
- };
-
- renderLines = (xScale: XScale, yScale: (y: string | number | undefined) => number) => {
- const { series } = this.props;
-
- const lineGenerator = d3Line<Chart.Point>()
- .defined((d) => Boolean(d.y || d.y === 0))
- .x((d) => xScale(d.x))
- .y((d) => yScale(d.y));
-
- if (this.props.basisCurve) {
- lineGenerator.curve(curveBasis);
- }
-
- return (
- <g>
- {series.map((serie, idx) => (
- <StyledPath index={idx} d={lineGenerator(serie.data) ?? undefined} key={serie.name} />
- ))}
- </g>
- );
- };
-
- renderAreas = (xScale: XScale, yScale: (y: string | number | undefined) => number) => {
- const areaGenerator = area<Chart.Point>()
- .defined((d) => Boolean(d.y || d.y === 0))
- .x((d) => xScale(d.x))
- .y1((d) => yScale(d.y))
- .y0(yScale(0));
-
- if (this.props.basisCurve) {
- areaGenerator.curve(curveBasis);
- }
-
- return (
- <g>
- {this.props.series.map((serie, idx) => (
- <StyledArea index={idx} d={areaGenerator(serie.data) ?? undefined} key={serie.name} />
- ))}
- </g>
- );
- };
-
- renderZoomHandle = (options: {
- direction: string;
- fixedPos: number;
- xDim: number[];
- xPos: number;
- xScale: XScale;
- yDim: number[];
- }) => (
- <Draggable
- axis="x"
- bounds={{ left: options.xDim[0], right: options.xDim[1] } as DraggableBounds}
- onDrag={this.handleSelectionHandleDrag(
- options.xScale,
- options.fixedPos,
- options.xDim,
- options.direction,
- true,
- )}
- onStop={this.handleSelectionHandleDrag(
- options.xScale,
- options.fixedPos,
- options.xDim,
- options.direction,
- )}
- position={{ x: options.xPos, y: 0 }}
- >
- <g>
- <ZoomHighlightHandle
- height={options.yDim[0] - options.yDim[1] + 1}
- width={2}
- x={options.direction === 'right' ? 0 : -2}
- y={options.yDim[1]}
- />
- <DraggableIcon
- fill="var(--echoes-color-icon-subdued)"
- x={options.direction === 'right' ? -7 : -9}
- y={16}
- />
- </g>
- </Draggable>
- );
-
- renderZoom = (xScale: XScale, yScale: { range: () => number[] }) => {
- const xRange = xScale.range();
- const yRange = yScale.range();
- const xDim = [xRange[0], xRange[xRange.length - 1]];
- const yDim = [yRange[0], yRange[yRange.length - 1]];
- const startX = Math.round(this.props.startDate ? xScale(this.props.startDate) : xDim[0]);
- const endX = Math.round(this.props.endDate ? xScale(this.props.endDate) : xDim[1]);
- const xArray = sortBy([startX, endX]);
- const zoomBoxWidth = xArray[1] - xArray[0];
-
- const showZoomArea =
- this.state.newZoomStart == null ||
- this.state.newZoomStart === startX ||
- this.state.newZoomStart === endX;
-
- return (
- <g>
- <DraggableCore
- onDrag={this.handleNewZoomDrag(xScale, xDim)}
- onStart={this.handleNewZoomDragStart(xDim)}
- onStop={this.handleNewZoomDragEnd(xScale, xDim)}
- >
- <ZoomOverlay
- height={yDim[0] - yDim[1]}
- width={xDim[1] - xDim[0]}
- x={xDim[0]}
- y={yDim[1]}
- />
- </DraggableCore>
- {showZoomArea && (
- <Draggable
- axis="x"
- bounds={{ left: xDim[0], right: Math.floor(xDim[1] - zoomBoxWidth) } as DraggableBounds}
- onDrag={this.handleSelectionDrag(xScale, zoomBoxWidth, xDim, true)}
- onStop={this.handleSelectionDrag(xScale, zoomBoxWidth, xDim)}
- position={{ x: xArray[0], y: 0 }}
- >
- <ZoomHighlight
- height={yDim[0] - yDim[1] + 1}
- onDoubleClick={this.handleDoubleClick(xScale, xDim)}
- width={zoomBoxWidth}
- x={0}
- y={yDim[1]}
- />
- </Draggable>
- )}
- {showZoomArea &&
- this.renderZoomHandle({
- xScale,
- xPos: startX,
- fixedPos: endX,
- xDim,
- yDim,
- direction: 'left',
- })}
- {showZoomArea &&
- this.renderZoomHandle({
- xScale,
- xPos: endX,
- fixedPos: startX,
- xDim,
- yDim,
- direction: 'right',
- })}
- </g>
- );
- };
-
- render() {
- const { padding = DEFAULT_PADDING, height, width } = this.props;
-
- if (width === 0 || height === 0) {
- return <div />;
- }
-
- const { xScale, yScale } = this.getScales();
-
- return (
- <svg height={this.props.height} width={this.props.width}>
- <g transform={`translate(${padding[3]}, ${padding[0] + 2})`}>
- {this.renderNewCode(xScale, yScale as Parameters<typeof this.renderNewCode>[1])}
- {this.renderBaseLine(xScale, yScale as Parameters<typeof this.renderBaseLine>[1])}
- {this.props.showAreas &&
- this.renderAreas(xScale, yScale as Parameters<typeof this.renderAreas>[1])}
- {this.renderLines(xScale, yScale as Parameters<typeof this.renderLines>[1])}
- {this.renderZoom(xScale, yScale as Parameters<typeof this.renderZoom>[1])}
- </g>
- </svg>
- );
- }
-}
-
-const ZoomHighlight = styled.rect`
- cursor: move;
- fill: ${themeColor('graphZoomBackgroundColor')};
- stroke: ${themeColor('graphZoomBorderColor')};
- fill-opacity: 0.2;
- shape-rendering: crispEdges;
-`;
-
-const ZoomHighlightHandle = styled.rect`
- cursor: ew-resize;
- fill-opacity: 1;
- fill: var(--echoes-color-icon-subdued);
- stroke: none;
-`;
-
-const ZoomOverlay = styled.rect`
- cursor: crosshair;
- pointer-events: all;
- fill: none;
- stroke: none;
-`;
-
-const AREA_OPACITY = 0.15;
-
-const StyledArea = styled.path<{ index: number }>`
- clip-path: url(#chart-clip);
- fill: ${({ index }) => themeColor(`graphLineColor.${index}` as CSSColor, AREA_OPACITY)};
- stroke-width: 0;
-`;
-
-const StyledPath = styled.path<{ index: number }>`
- clip-path: url(#chart-clip);
- fill: none;
- stroke: ${({ index }) => themeColor(`graphLineColor.${index}` as CSSColor)};
- stroke-dasharray: ${({ index }) => LINE_CHART_DASHES[index]};
- stroke-width: 2px;
-`;
-
-const StyledNewCodeLegend = styled.rect`
- fill: ${themeColor('newCodeLegend')};
-`;
-
-const StyledBaseLine = styled('line')`
- shape-rendering: crispedges;
- stroke: ${themeColor('graphGridColor')};
-`;
diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/AdvancedTimeline-test.tsx b/server/sonar-web/src/main/js/components/charts/__tests__/AdvancedTimeline-test.tsx
deleted file mode 100644
index ac7d3846ed9..00000000000
--- a/server/sonar-web/src/main/js/components/charts/__tests__/AdvancedTimeline-test.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { TooltipProvider } from '@sonarsource/echoes-react';
-import { render } from '@testing-library/react';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import { AdvancedTimeline, PropsWithoutTheme } from '../AdvancedTimeline';
-
-// Replace scaleTime with scaleUtc to avoid timezone-dependent snapshots
-jest.mock('d3-scale', () => {
- const d3scale = jest.requireActual('d3-scale');
- return {
- ...d3scale,
- scaleTime: d3scale.scaleUtc,
- };
-});
-
-jest.mock('lodash', () => {
- const lodash = jest.requireActual('lodash');
-
- return { ...lodash, throttle: (f: unknown) => f };
-});
-
-it('should render correctly', () => {
- const checkSnapShot = (props: Partial<PropsWithoutTheme> = {}, snapshotName = 'default') => {
- const renderedComponent = renderComponent(props);
-
- // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
- const svg = renderedComponent.container.querySelector("[class='line-chart']");
-
- expect(svg).toMatchSnapshot(snapshotName);
- };
-
- checkSnapShot();
- checkSnapShot({ disableZoom: false, updateZoom: () => {} }, 'Zoom enabled');
- checkSnapShot({ formatYTick: (t) => `Nicer tick ${t}` }, 'format y tick');
- checkSnapShot({ width: undefined }, 'no width');
- checkSnapShot({ height: undefined }, 'no height');
- checkSnapShot({ showAreas: undefined }, 'no areas');
- checkSnapShot({ selectedDate: new Date('2019-10-01') }, 'selected date');
- checkSnapShot({ metricType: MetricType.Rating }, 'rating metric');
- checkSnapShot({ metricType: MetricType.Level }, 'level metric');
- checkSnapShot({ zoomSpeed: 2 }, 'zoomSpeed');
- checkSnapShot({ leakPeriodDate: new Date('2019-10-02T00:00:00.000Z') }, 'leakPeriodDate');
- checkSnapShot({ basisCurve: true }, 'basisCurve');
- checkSnapShot(
- { splitPointDate: new Date('2019-10-02T00:00:00.000Z') },
- 'split point, but not Rating',
- );
-});
-
-function renderComponent(props?: Partial<PropsWithoutTheme>) {
- return render(
- <TooltipProvider>
- <AdvancedTimeline
- height={100}
- maxYTicksCount={10}
- metricType="TEST_METRIC"
- series={[
- {
- name: 'test-1',
- type: 'test-type-1',
- translatedName: '',
- data: [
- {
- x: new Date('2019-10-01T00:00:00.000Z'),
- y: 1,
- },
- {
- x: new Date('2019-10-02T00:00:00.000Z'),
- y: 2,
- },
- ],
- },
- {
- name: 'test-2',
- type: 'test-type-2',
- translatedName: '',
- data: [
- {
- x: new Date('2019-10-03T00:00:00.000Z'),
- y: 3,
- },
- ],
- },
- ]}
- width={100}
- zoomSpeed={1}
- {...props}
- />
- </TooltipProvider>,
- );
-}
diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/LanguageDistribution-test.tsx b/server/sonar-web/src/main/js/components/charts/__tests__/LanguageDistribution-test.tsx
deleted file mode 100644
index fa54bc774db..00000000000
--- a/server/sonar-web/src/main/js/components/charts/__tests__/LanguageDistribution-test.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import LanguageDistribution, { LanguageDistributionProps } from '../LanguageDistribution';
-
-it('should render correctly', () => {
- const { container } = renderLanguageDistribution();
- expect(container).toMatchSnapshot();
-});
-
-function renderLanguageDistribution(props: Partial<LanguageDistributionProps> = {}) {
- return renderComponent(
- <LanguageDistribution
- distribution="java=1734;js=845;cpp=73;<null>=15"
- languages={{ java: { key: 'java', name: 'Java' }, js: { key: 'js', name: 'JavaScript' } }}
- {...props}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/AdvancedTimeline-test.tsx.snap b/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/AdvancedTimeline-test.tsx.snap
deleted file mode 100644
index b9c083f888e..00000000000
--- a/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/AdvancedTimeline-test.tsx.snap
+++ /dev/null
@@ -1,2904 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: Zoom enabled 1`] = `
-<svg
- class="line-chart"
- height="100"
- width="100"
->
- <defs>
- <clippath
- id="chart-clip"
- >
- <rect
- height="34"
- transform="translate(0,-5)"
- width="40"
- />
- </clippath>
- </defs>
- <g
- transform="translate(50, 26)"
- >
- <g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="24"
- y2="24"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="22.4"
- y2="22.4"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="20.8"
- y2="20.8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="19.200000000000003"
- y2="19.200000000000003"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="17.6"
- y2="17.6"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="16"
- y2="16"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="14.400000000000002"
- y2="14.400000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="12.800000000000002"
- y2="12.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="11.2"
- y2="11.2"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="9.600000000000001"
- y2="9.600000000000001"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="8"
- y2="8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="6.399999999999999"
- y2="6.399999999999999"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="4.800000000000002"
- y2="4.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="3.1999999999999993"
- y2="3.1999999999999993"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="1.6000000000000023"
- y2="1.6000000000000023"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="0"
- y2="0"
- />
- </g>
- </g>
- <g
- transform="translate(0, 20)"
- >
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 15, 24)"
- x="15"
- y="24"
- >
- October
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 20, 24)"
- x="20"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 25, 24)"
- x="25"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 30, 24)"
- x="30"
- y="24"
- >
- 06 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 35, 24)"
- x="35"
- y="24"
- >
- Wed 02
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 40, 24)"
- x="40"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 45, 24)"
- x="45"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 50, 24)"
- x="50"
- y="24"
- >
- 06 PM
- </text>
- </g>
- <g>
- <path
- class="line-chart-path line-chart-path-0"
- d="M0,16L20,8"
- stroke="rgb(85,170,223)"
- stroke-dasharray="0"
- />
- <path
- class="line-chart-path line-chart-path-1"
- d="M40,0Z"
- stroke="rgb(58,127,173)"
- stroke-dasharray="3"
- />
- </g>
- <g>
- <circle
- cx="40"
- cy="0"
- fill="rgb(58,127,173)"
- r="2"
- stroke="white"
- stroke-width="1"
- />
- </g>
- <rect
- class="chart-mouse-events-overlay"
- height="24"
- width="40"
- />
- </g>
-</svg>
-`;
-
-exports[`should render correctly: basisCurve 1`] = `
-<svg
- class="line-chart"
- height="100"
- width="100"
->
- <g
- transform="translate(50, 26)"
- >
- <g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="24"
- y2="24"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="22.4"
- y2="22.4"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="20.8"
- y2="20.8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="19.200000000000003"
- y2="19.200000000000003"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="17.6"
- y2="17.6"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="16"
- y2="16"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="14.400000000000002"
- y2="14.400000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="12.800000000000002"
- y2="12.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="11.2"
- y2="11.2"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="9.600000000000001"
- y2="9.600000000000001"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="8"
- y2="8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="6.399999999999999"
- y2="6.399999999999999"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="4.800000000000002"
- y2="4.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="3.1999999999999993"
- y2="3.1999999999999993"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="1.6000000000000023"
- y2="1.6000000000000023"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="0"
- y2="0"
- />
- </g>
- </g>
- <g
- transform="translate(0, 20)"
- >
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 15, 24)"
- x="15"
- y="24"
- >
- October
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 20, 24)"
- x="20"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 25, 24)"
- x="25"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 30, 24)"
- x="30"
- y="24"
- >
- 06 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 35, 24)"
- x="35"
- y="24"
- >
- Wed 02
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 40, 24)"
- x="40"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 45, 24)"
- x="45"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 50, 24)"
- x="50"
- y="24"
- >
- 06 PM
- </text>
- </g>
- <g>
- <path
- class="line-chart-path line-chart-path-0"
- d="M0,16L20,8"
- stroke="rgb(85,170,223)"
- stroke-dasharray="0"
- />
- <path
- class="line-chart-path line-chart-path-1"
- d="M40,0Z"
- stroke="rgb(58,127,173)"
- stroke-dasharray="3"
- />
- </g>
- <g>
- <circle
- cx="40"
- cy="0"
- fill="rgb(58,127,173)"
- r="2"
- stroke="white"
- stroke-width="1"
- />
- </g>
- <rect
- class="chart-mouse-events-overlay"
- height="24"
- width="40"
- />
- </g>
-</svg>
-`;
-
-exports[`should render correctly: default 1`] = `
-<svg
- class="line-chart"
- height="100"
- width="100"
->
- <g
- transform="translate(50, 26)"
- >
- <g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="24"
- y2="24"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="22.4"
- y2="22.4"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="20.8"
- y2="20.8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="19.200000000000003"
- y2="19.200000000000003"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="17.6"
- y2="17.6"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="16"
- y2="16"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="14.400000000000002"
- y2="14.400000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="12.800000000000002"
- y2="12.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="11.2"
- y2="11.2"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="9.600000000000001"
- y2="9.600000000000001"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="8"
- y2="8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="6.399999999999999"
- y2="6.399999999999999"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="4.800000000000002"
- y2="4.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="3.1999999999999993"
- y2="3.1999999999999993"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="1.6000000000000023"
- y2="1.6000000000000023"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="0"
- y2="0"
- />
- </g>
- </g>
- <g
- transform="translate(0, 20)"
- >
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 15, 24)"
- x="15"
- y="24"
- >
- October
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 20, 24)"
- x="20"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 25, 24)"
- x="25"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 30, 24)"
- x="30"
- y="24"
- >
- 06 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 35, 24)"
- x="35"
- y="24"
- >
- Wed 02
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 40, 24)"
- x="40"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 45, 24)"
- x="45"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 50, 24)"
- x="50"
- y="24"
- >
- 06 PM
- </text>
- </g>
- <g>
- <path
- class="line-chart-path line-chart-path-0"
- d="M0,16L20,8"
- stroke="rgb(85,170,223)"
- stroke-dasharray="0"
- />
- <path
- class="line-chart-path line-chart-path-1"
- d="M40,0Z"
- stroke="rgb(58,127,173)"
- stroke-dasharray="3"
- />
- </g>
- <g>
- <circle
- cx="40"
- cy="0"
- fill="rgb(58,127,173)"
- r="2"
- stroke="white"
- stroke-width="1"
- />
- </g>
- <rect
- class="chart-mouse-events-overlay"
- height="24"
- width="40"
- />
- </g>
-</svg>
-`;
-
-exports[`should render correctly: format y tick 1`] = `
-<svg
- class="line-chart"
- height="100"
- width="100"
->
- <g
- transform="translate(50, 26)"
- >
- <g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="24"
- >
- Nicer tick 0
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="24"
- y2="24"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="22.4"
- >
- Nicer tick 0.2
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="22.4"
- y2="22.4"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="20.8"
- >
- Nicer tick 0.4
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="20.8"
- y2="20.8"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="19.200000000000003"
- >
- Nicer tick 0.6
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="19.200000000000003"
- y2="19.200000000000003"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="17.6"
- >
- Nicer tick 0.8
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="17.6"
- y2="17.6"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="16"
- >
- Nicer tick 1
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="16"
- y2="16"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="14.400000000000002"
- >
- Nicer tick 1.2
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="14.400000000000002"
- y2="14.400000000000002"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="12.800000000000002"
- >
- Nicer tick 1.4
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="12.800000000000002"
- y2="12.800000000000002"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="11.2"
- >
- Nicer tick 1.6
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="11.2"
- y2="11.2"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="9.600000000000001"
- >
- Nicer tick 1.8
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="9.600000000000001"
- y2="9.600000000000001"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="8"
- >
- Nicer tick 2
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="8"
- y2="8"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="6.399999999999999"
- >
- Nicer tick 2.2
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="6.399999999999999"
- y2="6.399999999999999"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="4.800000000000002"
- >
- Nicer tick 2.4
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="4.800000000000002"
- y2="4.800000000000002"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="3.1999999999999993"
- >
- Nicer tick 2.6
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="3.1999999999999993"
- y2="3.1999999999999993"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="1.6000000000000023"
- >
- Nicer tick 2.8
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="1.6000000000000023"
- y2="1.6000000000000023"
- />
- </g>
- <g>
- <text
- class="line-chart-tick line-chart-tick-x sw-typo-default"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="0"
- >
- Nicer tick 3
- </text>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="0"
- y2="0"
- />
- </g>
- </g>
- <g
- transform="translate(0, 20)"
- >
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 15, 24)"
- x="15"
- y="24"
- >
- October
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 20, 24)"
- x="20"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 25, 24)"
- x="25"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 30, 24)"
- x="30"
- y="24"
- >
- 06 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 35, 24)"
- x="35"
- y="24"
- >
- Wed 02
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 40, 24)"
- x="40"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 45, 24)"
- x="45"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 50, 24)"
- x="50"
- y="24"
- >
- 06 PM
- </text>
- </g>
- <g>
- <path
- class="line-chart-path line-chart-path-0"
- d="M0,16L20,8"
- stroke="rgb(85,170,223)"
- stroke-dasharray="0"
- />
- <path
- class="line-chart-path line-chart-path-1"
- d="M40,0Z"
- stroke="rgb(58,127,173)"
- stroke-dasharray="3"
- />
- </g>
- <g>
- <circle
- cx="40"
- cy="0"
- fill="rgb(58,127,173)"
- r="2"
- stroke="white"
- stroke-width="1"
- />
- </g>
- <rect
- class="chart-mouse-events-overlay"
- height="24"
- width="40"
- />
- </g>
-</svg>
-`;
-
-exports[`should render correctly: leakPeriodDate 1`] = `
-<svg
- class="line-chart"
- height="100"
- width="100"
->
- <g
- transform="translate(50, 26)"
- >
- <rect
- class="leak-chart-rect"
- fill="rgba(159,169,237,0.15)"
- height="24"
- width="20"
- x="20"
- y="0"
- />
- <g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="24"
- y2="24"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="22.4"
- y2="22.4"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="20.8"
- y2="20.8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="19.200000000000003"
- y2="19.200000000000003"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="17.6"
- y2="17.6"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="16"
- y2="16"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="14.400000000000002"
- y2="14.400000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="12.800000000000002"
- y2="12.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="11.2"
- y2="11.2"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="9.600000000000001"
- y2="9.600000000000001"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="8"
- y2="8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="6.399999999999999"
- y2="6.399999999999999"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="4.800000000000002"
- y2="4.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="3.1999999999999993"
- y2="3.1999999999999993"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="1.6000000000000023"
- y2="1.6000000000000023"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="0"
- y2="0"
- />
- </g>
- </g>
- <g
- transform="translate(0, 20)"
- >
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 15, 24)"
- x="15"
- y="24"
- >
- October
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 20, 24)"
- x="20"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 25, 24)"
- x="25"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 30, 24)"
- x="30"
- y="24"
- >
- 06 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 35, 24)"
- x="35"
- y="24"
- >
- Wed 02
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 40, 24)"
- x="40"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 45, 24)"
- x="45"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 50, 24)"
- x="50"
- y="24"
- >
- 06 PM
- </text>
- </g>
- <g>
- <path
- class="line-chart-path line-chart-path-0"
- d="M0,16L20,8"
- stroke="rgb(85,170,223)"
- stroke-dasharray="0"
- />
- <path
- class="line-chart-path line-chart-path-1"
- d="M40,0Z"
- stroke="rgb(58,127,173)"
- stroke-dasharray="3"
- />
- </g>
- <g>
- <circle
- cx="40"
- cy="0"
- fill="rgb(58,127,173)"
- r="2"
- stroke="white"
- stroke-width="1"
- />
- </g>
- <rect
- class="chart-mouse-events-overlay"
- height="24"
- width="40"
- />
- </g>
-</svg>
-`;
-
-exports[`should render correctly: level metric 1`] = `
-<svg
- class="line-chart"
- height="100"
- width="100"
->
- <g
- transform="translate(50, 26)"
- >
- <g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="24"
- y2="24"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="12"
- y2="12"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="0"
- y2="0"
- />
- </g>
- </g>
- <g
- transform="translate(0, 20)"
- >
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 15, 24)"
- x="15"
- y="24"
- >
- October
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 20, 24)"
- x="20"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 25, 24)"
- x="25"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 30, 24)"
- x="30"
- y="24"
- >
- 06 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 35, 24)"
- x="35"
- y="24"
- >
- Wed 02
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 40, 24)"
- x="40"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 45, 24)"
- x="45"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 50, 24)"
- x="50"
- y="24"
- >
- 06 PM
- </text>
- </g>
- <g>
- <path
- class="line-chart-path line-chart-path-0"
- d="M0,NaNL20,NaN"
- stroke="rgb(85,170,223)"
- stroke-dasharray="0"
- />
- <path
- class="line-chart-path line-chart-path-1"
- d="M40,NaNZ"
- stroke="rgb(58,127,173)"
- stroke-dasharray="3"
- />
- </g>
- <g>
- <circle
- cx="40"
- fill="rgb(58,127,173)"
- r="2"
- stroke="white"
- stroke-width="1"
- />
- </g>
- <rect
- class="chart-mouse-events-overlay"
- height="24"
- width="40"
- />
- </g>
-</svg>
-`;
-
-exports[`should render correctly: no areas 1`] = `
-<svg
- class="line-chart"
- height="100"
- width="100"
->
- <g
- transform="translate(50, 26)"
- >
- <g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="24"
- y2="24"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="22.4"
- y2="22.4"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="20.8"
- y2="20.8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="19.200000000000003"
- y2="19.200000000000003"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="17.6"
- y2="17.6"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="16"
- y2="16"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="14.400000000000002"
- y2="14.400000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="12.800000000000002"
- y2="12.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="11.2"
- y2="11.2"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="9.600000000000001"
- y2="9.600000000000001"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="8"
- y2="8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="6.399999999999999"
- y2="6.399999999999999"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="4.800000000000002"
- y2="4.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="3.1999999999999993"
- y2="3.1999999999999993"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="1.6000000000000023"
- y2="1.6000000000000023"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="0"
- y2="0"
- />
- </g>
- </g>
- <g
- transform="translate(0, 20)"
- >
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 15, 24)"
- x="15"
- y="24"
- >
- October
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 20, 24)"
- x="20"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 25, 24)"
- x="25"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 30, 24)"
- x="30"
- y="24"
- >
- 06 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 35, 24)"
- x="35"
- y="24"
- >
- Wed 02
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 40, 24)"
- x="40"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 45, 24)"
- x="45"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 50, 24)"
- x="50"
- y="24"
- >
- 06 PM
- </text>
- </g>
- <g>
- <path
- class="line-chart-path line-chart-path-0"
- d="M0,16L20,8"
- stroke="rgb(85,170,223)"
- stroke-dasharray="0"
- />
- <path
- class="line-chart-path line-chart-path-1"
- d="M40,0Z"
- stroke="rgb(58,127,173)"
- stroke-dasharray="3"
- />
- </g>
- <g>
- <circle
- cx="40"
- cy="0"
- fill="rgb(58,127,173)"
- r="2"
- stroke="white"
- stroke-width="1"
- />
- </g>
- <rect
- class="chart-mouse-events-overlay"
- height="24"
- width="40"
- />
- </g>
-</svg>
-`;
-
-exports[`should render correctly: no height 1`] = `null`;
-
-exports[`should render correctly: no width 1`] = `null`;
-
-exports[`should render correctly: rating metric 1`] = `
-<svg
- class="line-chart"
- height="100"
- width="100"
->
- <g
- transform="translate(50, 26)"
- >
- <g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="24"
- y2="24"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="18"
- y2="18"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="12"
- y2="12"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="6"
- y2="6"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="0"
- y2="0"
- />
- </g>
- </g>
- <g
- transform="translate(0, 20)"
- >
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 15, 24)"
- x="15"
- y="24"
- >
- October
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 20, 24)"
- x="20"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 25, 24)"
- x="25"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 30, 24)"
- x="30"
- y="24"
- >
- 06 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 35, 24)"
- x="35"
- y="24"
- >
- Wed 02
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 40, 24)"
- x="40"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 45, 24)"
- x="45"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 50, 24)"
- x="50"
- y="24"
- >
- 06 PM
- </text>
- </g>
- <g>
- <path
- class="line-chart-path line-chart-path-0"
- d="M0,0L20,6"
- stroke="rgb(85,170,223)"
- stroke-dasharray="0"
- />
- <path
- class="line-chart-path line-chart-path-1"
- d="M40,12Z"
- stroke="rgb(58,127,173)"
- stroke-dasharray="3"
- />
- </g>
- <g>
- <circle
- cx="40"
- cy="12"
- fill="rgb(58,127,173)"
- r="2"
- stroke="white"
- stroke-width="1"
- />
- </g>
- <rect
- class="chart-mouse-events-overlay"
- height="24"
- width="40"
- />
- </g>
-</svg>
-`;
-
-exports[`should render correctly: selected date 1`] = `
-<svg
- class="line-chart"
- height="100"
- width="100"
->
- <g
- transform="translate(50, 26)"
- >
- <g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="24"
- y2="24"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="22.4"
- y2="22.4"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="20.8"
- y2="20.8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="19.200000000000003"
- y2="19.200000000000003"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="17.6"
- y2="17.6"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="16"
- y2="16"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="14.400000000000002"
- y2="14.400000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="12.800000000000002"
- y2="12.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="11.2"
- y2="11.2"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="9.600000000000001"
- y2="9.600000000000001"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="8"
- y2="8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="6.399999999999999"
- y2="6.399999999999999"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="4.800000000000002"
- y2="4.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="3.1999999999999993"
- y2="3.1999999999999993"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="1.6000000000000023"
- y2="1.6000000000000023"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="0"
- y2="0"
- />
- </g>
- </g>
- <g
- transform="translate(0, 20)"
- >
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 15, 24)"
- x="15"
- y="24"
- >
- October
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 20, 24)"
- x="20"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 25, 24)"
- x="25"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 30, 24)"
- x="30"
- y="24"
- >
- 06 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 35, 24)"
- x="35"
- y="24"
- >
- Wed 02
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 40, 24)"
- x="40"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 45, 24)"
- x="45"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 50, 24)"
- x="50"
- y="24"
- >
- 06 PM
- </text>
- </g>
- <g>
- <path
- class="line-chart-path line-chart-path-0"
- d="M0,16L20,8"
- stroke="rgb(85,170,223)"
- stroke-dasharray="0"
- />
- <path
- class="line-chart-path line-chart-path-1"
- d="M40,0Z"
- stroke="rgb(58,127,173)"
- stroke-dasharray="3"
- />
- </g>
- <g>
- <circle
- cx="40"
- cy="0"
- fill="rgb(58,127,173)"
- r="2"
- stroke="white"
- stroke-width="1"
- />
- </g>
- <g>
- <line
- class="line-tooltip"
- x1="0"
- x2="0"
- y1="24"
- y2="0"
- />
- <circle
- cx="0"
- cy="16"
- fill="rgb(85,170,223)"
- r="4"
- stroke="white"
- stroke-width="1"
- />
- <circle
- cx="0"
- cy="0"
- fill="rgb(58,127,173)"
- r="4"
- stroke="white"
- stroke-width="1"
- />
- </g>
- <rect
- class="chart-mouse-events-overlay"
- height="24"
- width="40"
- />
- </g>
-</svg>
-`;
-
-exports[`should render correctly: split point, but not Rating 1`] = `
-<svg
- class="line-chart"
- height="100"
- width="100"
->
- <g
- transform="translate(50, 26)"
- >
- <g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="24"
- y2="24"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="22.4"
- y2="22.4"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="20.8"
- y2="20.8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="19.200000000000003"
- y2="19.200000000000003"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="17.6"
- y2="17.6"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="16"
- y2="16"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="14.400000000000002"
- y2="14.400000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="12.800000000000002"
- y2="12.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="11.2"
- y2="11.2"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="9.600000000000001"
- y2="9.600000000000001"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="8"
- y2="8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="6.399999999999999"
- y2="6.399999999999999"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="4.800000000000002"
- y2="4.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="3.1999999999999993"
- y2="3.1999999999999993"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="1.6000000000000023"
- y2="1.6000000000000023"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="0"
- y2="0"
- />
- </g>
- </g>
- <g
- transform="translate(0, 20)"
- >
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 15, 24)"
- x="15"
- y="24"
- >
- October
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 20, 24)"
- x="20"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 25, 24)"
- x="25"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 30, 24)"
- x="30"
- y="24"
- >
- 06 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 35, 24)"
- x="35"
- y="24"
- >
- Wed 02
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 40, 24)"
- x="40"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 45, 24)"
- x="45"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 50, 24)"
- x="50"
- y="24"
- >
- 06 PM
- </text>
- </g>
- <g>
- <path
- class="line-chart-path line-chart-path-0"
- d="M0,16L20,8"
- stroke="rgb(85,170,223)"
- stroke-dasharray="0"
- />
- <path
- class="line-chart-path line-chart-path-1"
- d="M40,0Z"
- stroke="rgb(58,127,173)"
- stroke-dasharray="3"
- />
- </g>
- <g>
- <circle
- cx="40"
- cy="0"
- fill="rgb(58,127,173)"
- r="2"
- stroke="white"
- stroke-width="1"
- />
- </g>
- <rect
- class="chart-mouse-events-overlay"
- height="24"
- width="40"
- />
- <line
- class="line-tooltip"
- stroke-dasharray="2"
- x1="20"
- x2="20"
- y1="24"
- y2="-10"
- />
- </g>
-</svg>
-`;
-
-exports[`should render correctly: zoomSpeed 1`] = `
-<svg
- class="line-chart"
- height="100"
- width="100"
->
- <g
- transform="translate(50, 26)"
- >
- <g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="24"
- y2="24"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="22.4"
- y2="22.4"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="20.8"
- y2="20.8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="19.200000000000003"
- y2="19.200000000000003"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="17.6"
- y2="17.6"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="16"
- y2="16"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="14.400000000000002"
- y2="14.400000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="12.800000000000002"
- y2="12.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="11.2"
- y2="11.2"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="9.600000000000001"
- y2="9.600000000000001"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="8"
- y2="8"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="6.399999999999999"
- y2="6.399999999999999"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="4.800000000000002"
- y2="4.800000000000002"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="3.1999999999999993"
- y2="3.1999999999999993"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="1.6000000000000023"
- y2="1.6000000000000023"
- />
- </g>
- <g>
- <line
- class="line-chart-grid"
- x1="0"
- x2="40"
- y1="0"
- y2="0"
- />
- </g>
- </g>
- <g
- transform="translate(0, 20)"
- >
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 15, 24)"
- x="15"
- y="24"
- >
- October
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 20, 24)"
- x="20"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 25, 24)"
- x="25"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 30, 24)"
- x="30"
- y="24"
- >
- 06 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 35, 24)"
- x="35"
- y="24"
- >
- Wed 02
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 40, 24)"
- x="40"
- y="24"
- >
- 06 AM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 45, 24)"
- x="45"
- y="24"
- >
- 12 PM
- </text>
- <text
- class="line-chart-tick sw-typo-default"
- text-anchor="end"
- transform="rotate(-35, 50, 24)"
- x="50"
- y="24"
- >
- 06 PM
- </text>
- </g>
- <g>
- <path
- class="line-chart-path line-chart-path-0"
- d="M0,16L20,8"
- stroke="rgb(85,170,223)"
- stroke-dasharray="0"
- />
- <path
- class="line-chart-path line-chart-path-1"
- d="M40,0Z"
- stroke="rgb(58,127,173)"
- stroke-dasharray="3"
- />
- </g>
- <g>
- <circle
- cx="40"
- cy="0"
- fill="rgb(58,127,173)"
- r="2"
- stroke="white"
- stroke-width="1"
- />
- </g>
- <rect
- class="chart-mouse-events-overlay"
- height="24"
- width="40"
- />
- </g>
-</svg>
-`;
diff --git a/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/LanguageDistribution-test.tsx.snap b/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/LanguageDistribution-test.tsx.snap
deleted file mode 100644
index 1d2f304b0cf..00000000000
--- a/server/sonar-web/src/main/js/components/charts/__tests__/__snapshots__/LanguageDistribution-test.tsx.snap
+++ /dev/null
@@ -1,147 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-.emotion-0 {
- fill: rgb(93,108,208);
-}
-
-.emotion-2 {
- font: var(--echoes-typography-text-default-regular);
- fill: var(--echoes-color-text-subdued);
-}
-
-.e4r8l5e2 .emotion-2 {
- fill: rgb(255,255,255);
-}
-
-<div>
- <svg
- height="100"
- width="260"
- >
- <g
- transform="translate(0, 0)"
- >
- <g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="121"
- x="80"
- y="13"
- />
- <text
- aria-describedby="tooltip-1"
- class="emotion-2 emotion-3"
- dx="1em"
- dy="0.3em"
- text-anchor="start"
- x="200"
- y="18"
- >
- 1.7short_number_suffix.k
- </text>
- <text
- class="emotion-2 emotion-3"
- dx="0"
- dy="0.3em"
- text-anchor="start"
- x="0"
- y="18"
- >
- Java
- </text>
- </g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="59"
- x="80"
- y="38"
- />
- <text
- class="emotion-2 emotion-3"
- dx="1em"
- dy="0.3em"
- text-anchor="start"
- x="138.47750865051904"
- y="43"
- >
- 845
- </text>
- <text
- class="emotion-2 emotion-3"
- dx="0"
- dy="0.3em"
- text-anchor="start"
- x="0"
- y="43"
- >
- JavaScript
- </text>
- </g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="6"
- x="80"
- y="63"
- />
- <text
- class="emotion-2 emotion-3"
- dx="1em"
- dy="0.3em"
- text-anchor="start"
- x="85.05190311418686"
- y="68"
- >
- 73
- </text>
- <text
- class="emotion-2 emotion-3"
- dx="0"
- dy="0.3em"
- text-anchor="start"
- x="0"
- y="68"
- >
- cpp
- </text>
- </g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="2"
- x="80"
- y="88"
- />
- <text
- class="emotion-2 emotion-3"
- dx="1em"
- dy="0.3em"
- text-anchor="start"
- x="81.03806228373702"
- y="93"
- >
- 15
- </text>
- <text
- class="emotion-2 emotion-3"
- dx="0"
- dy="0.3em"
- text-anchor="start"
- x="0"
- y="93"
- >
- unknown
- </text>
- </g>
- </g>
- </g>
- </svg>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/components/common/ActivityLink.tsx b/server/sonar-web/src/main/js/components/common/ActivityLink.tsx
deleted file mode 100644
index cdcf2fce7bf..00000000000
--- a/server/sonar-web/src/main/js/components/common/ActivityLink.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { StandoutLink } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { getActivityUrl, getMeasureHistoryUrl } from '../../helpers/urls';
-import { BranchLike } from '../../types/branch-like';
-import { GraphType } from '../../types/project-activity';
-import { isCustomGraph } from '../activity-graph/utils';
-
-export interface ActivityLinkProps {
- branchLike?: BranchLike;
- component: string;
- graph?: GraphType;
- label?: string;
- metric?: string;
-}
-
-export default function ActivityLink(props: ActivityLinkProps) {
- const { branchLike, component, graph, label, metric } = props;
- return (
- <StandoutLink
- className="sw-typo-semibold"
- to={
- metric !== undefined && graph !== undefined && isCustomGraph(graph)
- ? getMeasureHistoryUrl(component, metric, branchLike)
- : getActivityUrl(component, branchLike, graph)
- }
- >
- {label || translate('portfolio.activity_link')}
- </StandoutLink>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/common/DisableableSelectOption.tsx b/server/sonar-web/src/main/js/components/common/DisableableSelectOption.tsx
deleted file mode 100644
index a467bf0f5af..00000000000
--- a/server/sonar-web/src/main/js/components/common/DisableableSelectOption.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import Tooltip from '../../components/controls/Tooltip';
-
-export interface DisableableSelectOptionProps {
- className?: string;
- disableTooltipOverlay: () => React.ReactNode;
- disabledReason?: string;
- option: { isDisabled?: boolean; label?: string; value?: string | number | boolean };
-}
-
-export default function DisableableSelectOption(props: DisableableSelectOptionProps) {
- const { option, disableTooltipOverlay, disabledReason, className = '' } = props;
- const label = option.label || option.value;
- return option.isDisabled ? (
- <Tooltip content={disableTooltipOverlay()} side="left">
- <span className={className}>
- {label}
- {disabledReason !== undefined && <em className="small sw-ml-1">({disabledReason})</em>}
- </span>
- </Tooltip>
- ) : (
- <span className={className}>{label}</span>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/common/DocumentationLink.tsx b/server/sonar-web/src/main/js/components/common/DocumentationLink.tsx
deleted file mode 100644
index b95aeeb4688..00000000000
--- a/server/sonar-web/src/main/js/components/common/DocumentationLink.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Link, LinkProps, LinkStandalone } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { DocLink } from '../../helpers/doc-links';
-import { useDocUrl } from '../../helpers/docs';
-
-type Props = Omit<LinkProps, 'to'> & {
- innerRef?: React.Ref<HTMLAnchorElement>;
- standalone?: boolean;
- to: DocLink;
-};
-
-export default function DocumentationLink({ to, innerRef, standalone = false, ...props }: Props) {
- const toStatic = useDocUrl(to);
-
- return standalone ? (
- <LinkStandalone ref={innerRef} to={toStatic} {...props} />
- ) : (
- <Link ref={innerRef} to={toStatic} {...props} />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/common/EmailInput.tsx b/server/sonar-web/src/main/js/components/common/EmailInput.tsx
deleted file mode 100644
index 3e42a8fc393..00000000000
--- a/server/sonar-web/src/main/js/components/common/EmailInput.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { IconCheckCircle, IconError, Text } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import isEmail from 'validator/lib/isEmail';
-import { InputField } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import FocusOutHandler from '../controls/FocusOutHandler';
-
-export interface Props {
- id: string;
- isDisabled?: boolean;
- isMandotory?: boolean;
- onChange: (email: { isValid: boolean; value: string }) => void;
- value: string;
-}
-
-export type EmailChangeHandlerParams = { isValid: boolean; value: string };
-
-export default function EmailIput(props: Readonly<Props>) {
- const { id, value, onChange, isDisabled, isMandotory = false } = props;
-
- const [isEmailValid, setIsEmailValid] = React.useState<boolean>();
-
- React.useEffect(() => {
- if (!isMandotory) {
- onChange({ value, isValid: true });
- }
- }, []);
-
- return (
- <FocusOutHandler onFocusOut={() => value !== '' && setIsEmailValid(isEmail(value))}>
- <div className="sw-flex sw-items-center">
- <InputField
- id={id}
- isInvalid={isEmailValid === false}
- isValid={isEmailValid === true}
- size="full"
- onChange={({ currentTarget }) => {
- const isValid = isMandotory
- ? isEmail(currentTarget.value)
- : currentTarget.value === '' || isEmail(currentTarget.value);
- onChange({ value: currentTarget.value, isValid });
- if (!isMandotory && currentTarget.value === '') {
- setIsEmailValid(undefined);
- } else if (isValid) {
- setIsEmailValid(true);
- }
- }}
- value={value}
- disabled={isDisabled === true}
- />
- {isEmailValid === false && (
- <IconError className="sw-ml-2" color="echoes-color-icon-danger" />
- )}
- {isEmailValid === true && (
- <IconCheckCircle color="echoes-color-icon-success" className="sw-ml-2" />
- )}
- </div>
- {isEmailValid === false && (
- <Text className="sw-mt-2" colorOverride="echoes-color-text-danger">
- {translate('users.email.invalid')}
- </Text>
- )}
- </FocusOutHandler>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/common/EmptySearch.tsx b/server/sonar-web/src/main/js/components/common/EmptySearch.tsx
deleted file mode 100644
index 2837dc86af4..00000000000
--- a/server/sonar-web/src/main/js/components/common/EmptySearch.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Text, TextSize } from '@sonarsource/echoes-react';
-import { FishVisual } from '~design-system';
-import { translate } from '../../helpers/l10n';
-
-export default function EmptySearch() {
- return (
- <div className="sw-flex sw-flex-col sw-items-center sw-py-8">
- <FishVisual />
- <Text isHighlighted size={TextSize.Large} className="sw-mt-6">
- {translate('no_results_search')}
- </Text>
- <p className="sw-typo-default sw-mt-2">{translate('no_results_search.2')}</p>
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/common/FormattingTips.tsx b/server/sonar-web/src/main/js/components/common/FormattingTips.tsx
deleted file mode 100644
index 780df38d9e7..00000000000
--- a/server/sonar-web/src/main/js/components/common/FormattingTips.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React from 'react';
-import { Link, Note } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { getBaseUrl } from '../../helpers/system';
-import { getFormattingHelpUrl } from '../../helpers/urls';
-
-export interface FormattingTipsProps {
- className?: string;
-}
-
-export default function FormattingTips({ className }: FormattingTipsProps) {
- const handleClick = React.useCallback((evt: React.MouseEvent<HTMLAnchorElement>) => {
- evt.preventDefault();
- window.open(
- `${getBaseUrl()}${getFormattingHelpUrl()}`,
- 'Formatting',
- 'height=300,width=600,scrollbars=1,resizable=1',
- );
- }, []);
-
- return (
- <Note className={className}>
- <Link className="sw-mr-1" onClick={handleClick} to={getFormattingHelpUrl()}>
- {translate('formatting.helplink')}
- </Link>
- {':'}
- <span className="sw-ml-2">*{translate('bold')}*</span>
- <span className="sw-ml-2">
- ``
- {translate('code')}
- ``
- </span>
- <span className="sw-ml-2">* {translate('bulleted_point')}</span>
- </Note>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/common/FormattingTipsWithLink.tsx b/server/sonar-web/src/main/js/components/common/FormattingTipsWithLink.tsx
deleted file mode 100644
index b8df1d4382d..00000000000
--- a/server/sonar-web/src/main/js/components/common/FormattingTipsWithLink.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkStandalone } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { CodeSnippet } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { getFormattingHelpUrl } from '../../helpers/urls';
-
-interface Props {
- className?: string;
-}
-
-export default class FormattingTipsWithLink extends React.PureComponent<Props> {
- handleClick(evt: React.SyntheticEvent<HTMLAnchorElement>) {
- evt.preventDefault();
-
- window.open(
- getFormattingHelpUrl(),
- 'Formatting',
- 'height=300,width=600,scrollbars=1,resizable=1',
- );
- }
-
- render() {
- return (
- <div className={this.props.className}>
- <LinkStandalone onClick={this.handleClick} to="#">
- {translate('formatting.helplink')}
- </LinkStandalone>
-
- <p className="sw-mt-2">
- <FormattedMessage
- id="formatting.example.link"
- values={{
- example: (
- <>
- <br />
-
- <CodeSnippet
- isOneLine
- noCopy
- snippet={translate('formatting.example.link.example')}
- />
- </>
- ),
- }}
- />
- </p>
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/common/InstanceMessage.tsx b/server/sonar-web/src/main/js/components/common/InstanceMessage.tsx
deleted file mode 100644
index 3b38f17fc3e..00000000000
--- a/server/sonar-web/src/main/js/components/common/InstanceMessage.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { getInstance } from '../../helpers/system';
-
-interface Props {
- children?: (transformedMessage: string) => React.ReactChild;
- message: string;
-}
-
-export default function InstanceMessage({ children, message }: Props): any {
- const transformedMessage = message.replace(/\{instance\}/gim, getInstance());
-
- if (children) {
- return children(transformedMessage);
- }
-
- return transformedMessage;
-}
diff --git a/server/sonar-web/src/main/js/components/common/Link.tsx b/server/sonar-web/src/main/js/components/common/Link.tsx
deleted file mode 100644
index 5182788dfe7..00000000000
--- a/server/sonar-web/src/main/js/components/common/Link.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as Echoes from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { Link as ReactRouterDomLink, LinkProps as ReactRouterDomLinkProps } from 'react-router-dom';
-import { isWebUri } from 'valid-url';
-import { OpenNewTabIcon } from '~design-system';
-import { translate } from '../../helpers/l10n';
-
-type OriginalLinkProps = ReactRouterDomLinkProps & React.RefAttributes<HTMLAnchorElement>;
-
-/** @deprecated Use {@link Echoes.LinkProps | LinkProps} from Echoes instead.
- *
- * Some of the props have changed or been renamed:
- * - `blurAfterClick` is now `shouldBlurAfterClick`
- * - ~`disabled`~ doesn't exist anymore, a disabled link is just a regular text
- * - `forceExternal` is now `isExternal`
- * - `icon` is now `iconLeft` and can only be used with LinkStandalone
- * - `preventDefault` is now `shouldPreventDefault`
- * - `showExternalIcon` is now `hasExternalIcon`
- * - `stopPropagation` is now `shouldStopPropagation`
- */
-export interface LinkProps extends OriginalLinkProps {
- size?: number;
-}
-
-function Link({ children, size, ...props }: LinkProps, ref: React.ForwardedRef<HTMLAnchorElement>) {
- if (typeof props.to === 'string' && isWebUri(props.to)) {
- // The new React Router DOM's <Link> component no longer supports external links.
- // We have to use the <a> element instead.
- const { to, ...anchorProps } = props;
- return (
- <a
- ref={ref}
- href={to}
- rel={anchorProps.target === '_blank' ? 'noopener noreferrer' : undefined}
- {...anchorProps}
- >
- {anchorProps.target === '_blank' && (
- <OpenNewTabIcon aria-label={translate('opens_in_new_window')} className="sw-mr-1" />
- )}
- {children}
- </a>
- );
- }
-
- return (
- <ReactRouterDomLink
- ref={ref}
- rel={props.target === '_blank' ? 'noopener noreferrer' : undefined}
- {...props}
- >
- {children}
- </ReactRouterDomLink>
- );
-}
-
-/** @deprecated Use either {@link Echoes.Link | Link} or {@link Echoes.LinkStandalone | LinkStandalone} from Echoes instead.
- */
-export default React.forwardRef(Link);
diff --git a/server/sonar-web/src/main/js/components/common/LocationMessage.tsx b/server/sonar-web/src/main/js/components/common/LocationMessage.tsx
deleted file mode 100644
index bf10859e575..00000000000
--- a/server/sonar-web/src/main/js/components/common/LocationMessage.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-
-interface Props {
- children?: React.ReactNode;
-}
-
-export default function LocationMessage(props: Props) {
- return <div className="location-message">{props.children}</div>;
-}
diff --git a/server/sonar-web/src/main/js/components/common/MetaLink.tsx b/server/sonar-web/src/main/js/components/common/MetaLink.tsx
deleted file mode 100644
index 537b5b805e7..00000000000
--- a/server/sonar-web/src/main/js/components/common/MetaLink.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkStandalone } from '@sonarsource/echoes-react';
-import React, { useState } from 'react';
-import { CloseIcon, InputField, InteractiveIcon } from '~design-system';
-import isValidUri from '../../app/utils/isValidUri';
-import { translate } from '../../helpers/l10n';
-import { getLinkName } from '../../helpers/projectLinks';
-import { ProjectLink } from '../../types/types';
-
-interface Props {
- link: ProjectLink;
-}
-
-export default function MetaLink({ link }: Readonly<Props>) {
- const [expanded, setExpanded] = useState(false);
-
- const handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- setExpanded((expanded) => !expanded);
- };
-
- const handleCollapse = () => {
- setExpanded(false);
- };
-
- const handleSelect = (event: React.MouseEvent<HTMLInputElement>) => {
- event.currentTarget.select();
- };
-
- const linkTitle = getLinkName(link);
- const isValid = isValidUri(link.url);
- return (
- <li>
- <LinkStandalone
- onClick={isValid ? undefined : handleClick}
- shouldPreventDefault={!isValid}
- to={link.url}
- >
- {linkTitle}
- </LinkStandalone>
-
- {expanded && (
- <div className="sw-mt-1 sw-flex sw-items-center">
- <InputField onClick={handleSelect} readOnly type="text" value={link.url} size="large" />
- <InteractiveIcon
- Icon={CloseIcon}
- aria-label={translate('hide')}
- className="sw-ml-1"
- onClick={handleCollapse}
- />
- </div>
- )}
- </li>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/common/ModeBanner.tsx b/server/sonar-web/src/main/js/components/common/ModeBanner.tsx
deleted file mode 100644
index ec7143278f5..00000000000
--- a/server/sonar-web/src/main/js/components/common/ModeBanner.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import {
- ButtonIcon,
- ButtonSize,
- ButtonVariety,
- IconX,
- Link,
- LinkHighlight,
-} from '@sonarsource/echoes-react';
-import { useIntl } from 'react-intl';
-import tw from 'twin.macro';
-import { dismissNotice } from '../../api/users';
-import { useCurrentUser } from '../../app/components/current-user/CurrentUserContext';
-import { Banner } from '../../design-system';
-import { useModeModifiedQuery, useStandardExperienceModeQuery } from '../../queries/mode';
-import { Permissions } from '../../types/permissions';
-import { NoticeType } from '../../types/users';
-
-interface Props {
- as: 'facetBanner' | 'wideBanner';
-}
-
-export default function ModeBanner({ as }: Props) {
- const intl = useIntl();
- const { currentUser, updateDismissedNotices } = useCurrentUser();
- const { data: isStandardMode } = useStandardExperienceModeQuery();
- const { data: isModified, isLoading } = useModeModifiedQuery();
-
- const onDismiss = () => {
- dismissNotice(NoticeType.MQR_MODE_ADVERTISEMENT_BANNER)
- .then(() => {
- updateDismissedNotices(NoticeType.MQR_MODE_ADVERTISEMENT_BANNER, true);
- })
- .catch(() => {
- /* noop */
- });
- };
-
- if (
- !currentUser.permissions?.global.includes(Permissions.Admin) ||
- currentUser.dismissedNotices[NoticeType.MQR_MODE_ADVERTISEMENT_BANNER] ||
- isLoading ||
- isModified
- ) {
- return null;
- }
-
- return as === 'wideBanner' ? (
- <Banner className="sw-mt-8" variant="info" onDismiss={onDismiss}>
- <div>
- {intl.formatMessage(
- { id: `settings.mode.${isStandardMode ? 'standard' : 'mqr'}.advertisement` },
- {
- a: (text) => (
- <Link highlight={LinkHighlight.CurrentColor} to="/admin/settings?category=mode">
- {text}
- </Link>
- ),
- },
- )}
- </div>
- </Banner>
- ) : (
- <FacetBanner>
- <div className="sw-flex sw-gap-2">
- <div>
- {intl.formatMessage(
- { id: `mode.${isStandardMode ? 'standard' : 'mqr'}.advertisement` },
- {
- a: (text) => (
- <Link highlight={LinkHighlight.CurrentColor} to="/admin/settings?category=mode">
- {text}
- </Link>
- ),
- },
- )}
- </div>
- <ButtonIcon
- className="sw-flex-none"
- Icon={IconX}
- ariaLabel={intl.formatMessage({ id: 'dismiss' })}
- onClick={onDismiss}
- size={ButtonSize.Medium}
- variety={ButtonVariety.DefaultGhost}
- />
- </div>
- </FacetBanner>
- );
-}
-
-const FacetBanner = styled.div`
- ${tw`sw-p-2 sw-rounded-2`}
- background-color: var(--echoes-color-background-accent-weak-default);
-`;
diff --git a/server/sonar-web/src/main/js/components/common/PageCounter.tsx b/server/sonar-web/src/main/js/components/common/PageCounter.tsx
deleted file mode 100644
index 2defc4d3e8d..00000000000
--- a/server/sonar-web/src/main/js/components/common/PageCounter.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { MetricType } from '~sonar-aligned/types/metrics';
-
-export interface PageCounterProps {
- className?: string;
- label: string;
- total: number;
-}
-
-export default function PageCounter({ className, label, total }: Readonly<PageCounterProps>) {
- return (
- <div className={className}>
- <strong className="sw-mr-1">
- <span data-testid="page-counter-total">{formatMeasure(total, MetricType.Integer)}</span>
- </strong>
- {label}
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/common/PrivacyBadgeContainer.tsx b/server/sonar-web/src/main/js/components/common/PrivacyBadgeContainer.tsx
deleted file mode 100644
index 0d891543cc0..00000000000
--- a/server/sonar-web/src/main/js/components/common/PrivacyBadgeContainer.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { Visibility } from '~sonar-aligned/types/component';
-import Tooltip from '../../components/controls/Tooltip';
-import { translate } from '../../helpers/l10n';
-
-interface PrivacyBadgeContainerProps {
- className?: string;
- qualifier: string;
- visibility: Visibility;
-}
-
-export default function PrivacyBadgeContainer({
- className,
- qualifier,
- visibility,
-}: PrivacyBadgeContainerProps) {
- return (
- <Tooltip content={translate('visibility', visibility, 'description', qualifier)}>
- <div className={classNames('badge', className)}>{translate('visibility', visibility)}</div>
- </Tooltip>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/common/ResetPasswordForm.tsx b/server/sonar-web/src/main/js/components/common/ResetPasswordForm.tsx
deleted file mode 100644
index 6c3b71f1caf..00000000000
--- a/server/sonar-web/src/main/js/components/common/ResetPasswordForm.tsx
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, ButtonVariety } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { FlagMessage, FormField, InputField } from '~design-system';
-import { changePassword } from '../../api/users';
-import MandatoryFieldsExplanation from '../../components/ui/MandatoryFieldsExplanation';
-import { translate } from '../../helpers/l10n';
-import { ChangePasswordResults, LoggedInUser } from '../../types/users';
-import UserPasswordInput, { PasswordChangeHandlerParams } from './UserPasswordInput';
-
-interface Props {
- className?: string;
- onPasswordChange?: () => void;
- user: LoggedInUser;
-}
-
-export default function ResetPasswordForm({
- className,
- onPasswordChange,
- user: { login },
-}: Readonly<Props>) {
- const [error, setError] = React.useState<string | undefined>(undefined);
- const [oldPassword, setOldPassword] = React.useState('');
- const [password, setPassword] = React.useState<PasswordChangeHandlerParams>({
- value: '',
- isValid: false,
- });
- const [success, setSuccess] = React.useState(false);
-
- const handleSuccessfulChange = () => {
- setOldPassword('');
- setPassword({
- value: '',
- isValid: false,
- });
- setSuccess(true);
-
- onPasswordChange?.();
- };
-
- const handleChangePassword = (event: React.FormEvent) => {
- event.preventDefault();
-
- setError(undefined);
- setSuccess(false);
-
- changePassword({ login, password: password.value, previousPassword: oldPassword })
- .then(handleSuccessfulChange)
- .catch((result: ChangePasswordResults) => {
- if (result === ChangePasswordResults.OldPasswordIncorrect) {
- setError(translate('user.old_password_incorrect'));
- } else if (result === ChangePasswordResults.NewPasswordSameAsOld) {
- setError(translate('user.new_password_same_as_old'));
- }
- });
- };
-
- return (
- <form className={className} onSubmit={handleChangePassword}>
- {success && (
- <div className="sw-pb-4">
- <FlagMessage variant="success">{translate('my_profile.password.changed')}</FlagMessage>
- </div>
- )}
-
- {error !== undefined && (
- <div className="sw-pb-4">
- <FlagMessage variant="error">{error}</FlagMessage>
- </div>
- )}
-
- <MandatoryFieldsExplanation className="sw-block sw-clear-both sw-pb-4" />
-
- <div className="sw-pb-4">
- <FormField htmlFor="old_password" label={translate('my_profile.password.old')} required>
- <InputField
- size="large"
- autoComplete="off"
- id="old_password"
- name="old_password"
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => setOldPassword(e.target.value)}
- required
- type="password"
- value={oldPassword}
- />
- </FormField>
- </div>
-
- <div className="sw-pb-4">
- <UserPasswordInput onChange={setPassword} size="large" value={password.value} />
- </div>
-
- <div className="sw-py-3">
- <Button
- isDisabled={oldPassword === '' || !password.isValid}
- id="change-password"
- type="submit"
- variety={ButtonVariety.Primary}
- >
- {translate('update_verb')}
- </Button>
- </div>
- </form>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/common/RestartButton.tsx b/server/sonar-web/src/main/js/components/common/RestartButton.tsx
deleted file mode 100644
index b3ef6a973ea..00000000000
--- a/server/sonar-web/src/main/js/components/common/RestartButton.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, ButtonVariety } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { restart } from '../../api/system';
-import ConfirmButton from '../../components/controls/ConfirmButton';
-import { translate } from '../../helpers/l10n';
-import { SysStatus } from '../../types/types';
-
-interface Props {
- className?: string;
- fetchSystemStatus: () => void;
- systemStatus: SysStatus;
-}
-
-export default class RestartButton extends React.PureComponent<Props> {
- handleConfirm = () => restart().then(this.props.fetchSystemStatus);
-
- render() {
- const { className, systemStatus } = this.props;
- return (
- <ConfirmButton
- confirmButtonText={translate('restart')}
- modalBody={
- <>
- <p className="sw-my-2">{translate('system.are_you_sure_to_restart')}</p>
- <p className="sw-mb-2">{translate('system.forcing_shutdown_not_recommended')}</p>
- <p>{translate('system.restart_does_not_reload_sonar_properties')}</p>
- </>
- }
- modalHeader={translate('system.restart_server')}
- onConfirm={this.handleConfirm}
- >
- {({ onClick }) => (
- <Button
- className={className}
- isDisabled={systemStatus !== 'UP'}
- onClick={onClick}
- variety={ButtonVariety.DangerOutline}
- >
- {systemStatus === 'RESTARTING'
- ? translate('system.restart_in_progress')
- : translate('system.restart_server')}
- </Button>
- )}
- </ConfirmButton>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/common/ScreenPositionHelper.tsx b/server/sonar-web/src/main/js/components/common/ScreenPositionHelper.tsx
deleted file mode 100644
index 3023e3cde95..00000000000
--- a/server/sonar-web/src/main/js/components/common/ScreenPositionHelper.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { debounce } from 'lodash';
-import * as React from 'react';
-
-interface Props {
- children: (position: { left: number; top: number }) => React.ReactElement<any>;
- className?: string;
-}
-
-export const SCREEN_POSITION_COMPUTE_DELAY = 250;
-
-export default class ScreenPositionHelper extends React.PureComponent<Props> {
- container?: HTMLDivElement;
- debouncedOnResize: () => void;
-
- constructor(props: Props) {
- super(props);
- this.debouncedOnResize = debounce(() => this.forceUpdate(), SCREEN_POSITION_COMPUTE_DELAY);
- }
-
- componentDidMount() {
- this.forceUpdate();
- window.addEventListener('resize', this.debouncedOnResize);
- }
-
- componentWillUnmount() {
- window.removeEventListener('resize', this.debouncedOnResize);
- }
-
- getPosition = () => {
- const containerPos = this.container && this.container.getBoundingClientRect();
- if (!containerPos) {
- return { top: 0, left: 0 };
- }
- return {
- top: window.pageYOffset + containerPos.top,
- left: window.pageXOffset + containerPos.left,
- };
- };
-
- render() {
- return (
- <div
- className={this.props.className}
- ref={(container) => (this.container = container as HTMLDivElement)}
- >
- {this.props.children(this.getPosition())}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/common/StatusIndicator.tsx b/server/sonar-web/src/main/js/components/common/StatusIndicator.tsx
deleted file mode 100644
index 11fc02db2e0..00000000000
--- a/server/sonar-web/src/main/js/components/common/StatusIndicator.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CheckIcon, FlagErrorIcon, FlagWarningIcon } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { HealthTypes } from '../../types/types';
-
-export interface StatusIndicatorProps {
- color: HealthTypes;
-}
-
-const ICON_MAP = {
- [HealthTypes.GREEN]: CheckIcon,
- [HealthTypes.YELLOW]: FlagWarningIcon,
- [HealthTypes.RED]: FlagErrorIcon,
-};
-
-export default function StatusIndicator({ color }: Readonly<StatusIndicatorProps>) {
- const Icon = ICON_MAP[color];
-
- return (
- <>
- {translate('system.current_health', color.toLowerCase())}
- <Icon aria-hidden className="sw-ml-2" />
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/common/UserPasswordInput.tsx b/server/sonar-web/src/main/js/components/common/UserPasswordInput.tsx
deleted file mode 100644
index 4c7f4453484..00000000000
--- a/server/sonar-web/src/main/js/components/common/UserPasswordInput.tsx
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { IconCheck, IconCheckCircle, IconError, IconX, Text } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { FormField, InputField, InputSizeKeys } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import FocusOutHandler from '../controls/FocusOutHandler';
-
-const MIN_PASSWORD_LENGTH = 12;
-
-export type PasswordChangeHandlerParams = { isValid: boolean; value: string };
-
-export interface Props {
- onChange: (password: PasswordChangeHandlerParams) => void;
- size?: InputSizeKeys;
- value: string;
-}
-
-export default function UserPasswordInput(props: Readonly<Props>) {
- const { onChange, size = 'full', value } = props;
-
- const [isFocused, setIsFocused] = React.useState(false);
- const [confirmValue, setConfirmValue] = React.useState('');
-
- const isInvalid = !isFocused && value !== '' && !isPasswordValid(value);
- const isValid = !isFocused && isPasswordValid(value);
- const passwordMatch = isPasswordConfirmed(value, confirmValue);
- const passwordDontMatch = value !== confirmValue && confirmValue !== '';
-
- React.useEffect(() => {
- if (value === '') {
- setConfirmValue('');
- }
- }, [value]);
-
- return (
- <>
- <FocusOutHandler className="sw-flex sw-items-center" onFocusOut={() => setIsFocused(false)}>
- <FormField required label={translate('password')} htmlFor="create-password">
- <div className="sw-flex sw-items-center">
- <InputField
- isInvalid={isInvalid}
- isValid={isValid}
- onFocus={() => setIsFocused(true)}
- id="create-password"
- size={size}
- onChange={({ currentTarget }) => {
- onChange({
- value: currentTarget.value,
- isValid:
- isPasswordValid(currentTarget.value) &&
- isPasswordConfirmed(currentTarget.value, confirmValue),
- });
- }}
- type="password"
- value={value}
- />
- {isInvalid && <IconError className="sw-ml-2" color="echoes-color-icon-danger" />}
- {isValid && <IconCheckCircle color="echoes-color-icon-success" className="sw-ml-2" />}
- </div>
- {isInvalid && (
- <Text colorOverride="echoes-color-text-danger" className="sw-mt-2">
- {translate('user.password.invalid')}
- </Text>
- )}
- {isFocused && <PasswordConstraint value={value} />}
- </FormField>
- </FocusOutHandler>
-
- <FormField
- className="sw-mt-4"
- required
- label={translate('confirm_password')}
- htmlFor="confirm-password"
- >
- <div className="sw-flex sw-items-center">
- <InputField
- isInvalid={passwordDontMatch}
- isValid={passwordMatch}
- onFocus={() => setIsFocused(true)}
- id="confirm-password"
- size={size}
- onChange={({ currentTarget }) => {
- setConfirmValue(currentTarget.value);
- onChange({
- value,
- isValid:
- isPasswordValid(currentTarget.value) &&
- isPasswordConfirmed(value, currentTarget.value),
- });
- }}
- type="password"
- value={confirmValue}
- />
- {passwordDontMatch && <IconError className="sw-ml-2" color="echoes-color-icon-danger" />}
- {passwordMatch && (
- <IconCheckCircle color="echoes-color-icon-success" className="sw-ml-2" />
- )}
- </div>
- {passwordDontMatch && (
- <Text colorOverride="echoes-color-text-danger" className="sw-mt-2">
- {translate('user.password.do_not_match')}
- </Text>
- )}
- </FormField>
- </>
- );
-}
-
-function PasswordConstraint({ value }: Readonly<{ value: string }>) {
- return (
- <div className="sw-mt-2">
- <Text isSubdued>{translate('user.password.conditions')}</Text>
- <ul className="sw-list-none sw-p-0 sw-mt-1">
- <Condition
- condition={contains12Characters(value)}
- label={translate('user.password.condition.12_characters')}
- />
- <Condition
- condition={containsUppercase(value)}
- label={translate('user.password.condition.1_upper_case')}
- />
- <Condition
- condition={containsLowercase(value)}
- label={translate('user.password.condition.1_lower_case')}
- />
- <Condition
- condition={containsDigit(value)}
- label={translate('user.password.condition.1_number')}
- />
- <Condition
- condition={containsSpecialCharacter(value)}
- label={translate('user.password.condition.1_special_character')}
- />
- </ul>
- </div>
- );
-}
-
-function Condition({ condition, label }: Readonly<{ condition: boolean; label: string }>) {
- return (
- <li className="sw-mb-1">
- {condition ? (
- <Text colorOverride="echoes-color-text-success" data-testid="valid-condition">
- <IconCheck className="sw-mr-1" />
- {label}
- </Text>
- ) : (
- <Text isSubdued data-testid="failed-condition">
- <IconX className="sw-mr-1" />
- {label}
- </Text>
- )}
- </li>
- );
-}
-
-const contains12Characters = (password: string) => password.length >= MIN_PASSWORD_LENGTH;
-const containsUppercase = (password: string) => /[A-Z]/.test(password);
-const containsLowercase = (password: string) => /[a-z]/.test(password);
-const containsDigit = (password: string) => /\d/.test(password);
-const containsSpecialCharacter = (password: string) => /[^a-zA-Z0-9]/.test(password);
-
-const isPasswordValid = (password: string) =>
- contains12Characters(password) &&
- containsUppercase(password) &&
- containsLowercase(password) &&
- containsDigit(password) &&
- containsSpecialCharacter(password);
-
-const isPasswordConfirmed = (password: string, confirm: string) =>
- password === confirm && password !== '';
diff --git a/server/sonar-web/src/main/js/components/common/VisibilitySelector.tsx b/server/sonar-web/src/main/js/components/common/VisibilitySelector.tsx
deleted file mode 100644
index d70671f2673..00000000000
--- a/server/sonar-web/src/main/js/components/common/VisibilitySelector.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { RadioButtonGroup } from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import { Visibility } from '~sonar-aligned/types/component';
-import { translate } from '../../helpers/l10n';
-
-export interface VisibilitySelectorProps {
- canTurnToPrivate?: boolean;
- className?: string;
- disabled?: boolean;
- loading?: boolean;
- onChange: (visibility: Visibility) => void;
- visibility?: Visibility;
-}
-
-export default function VisibilitySelector(props: Readonly<VisibilitySelectorProps>) {
- const { className, canTurnToPrivate, visibility, disabled, loading = false, onChange } = props;
- return (
- <div className={classNames(className)}>
- <RadioButtonGroup
- ariaLabel={translate('roles.page.change_visibility')}
- id="project-visiblity-radio"
- isDisabled={disabled}
- options={Object.values(Visibility).map((v) => ({
- label: translate('visibility', v),
- value: v,
- isDisabled: (v === Visibility.Private && !canTurnToPrivate) || loading,
- }))}
- value={visibility}
- onChange={onChange}
- />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/common/__mocks__/ScreenPositionHelper.tsx b/server/sonar-web/src/main/js/components/common/__mocks__/ScreenPositionHelper.tsx
deleted file mode 100644
index 95af1031fe7..00000000000
--- a/server/sonar-web/src/main/js/components/common/__mocks__/ScreenPositionHelper.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-
-interface Props {
- children: (position: { top: number }) => React.ReactNode;
-}
-
-export default class ScreenPositionHelper extends React.Component<Props> {
- render() {
- return this.props.children({ top: 0 });
- }
-}
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/ActivityLink-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/ActivityLink-test.tsx
deleted file mode 100644
index 3f3c60c3d4f..00000000000
--- a/server/sonar-web/src/main/js/components/common/__tests__/ActivityLink-test.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { mockBranch } from '../../../helpers/mocks/branch-like';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { GraphType } from '../../../types/project-activity';
-import ActivityLink, { ActivityLinkProps } from '../ActivityLink';
-
-it('renders correctly without props', () => {
- renderActivityLink();
- expect(screen.getByText('portfolio.activity_link')).toBeInTheDocument();
-});
-
-it('renders correctly with props label and branch', () => {
- renderActivityLink({ label: 'Foo', branchLike: mockBranch() });
- expect(screen.getByText('Foo')).toBeInTheDocument();
-});
-
-it('renders correctly with graph', () => {
- renderActivityLink({ graph: GraphType.coverage });
- const anchorElement = screen.getByRole('link');
-
- expect(anchorElement).toBeInTheDocument();
- expect(anchorElement).toHaveAttribute('href', '/project/activity?id=foo&graph=coverage');
-});
-
-it('renders correctly with graph and metric', () => {
- renderActivityLink({ graph: GraphType.custom, metric: 'new_bugs,bugs' });
- const anchorElement = screen.getByRole('link');
-
- expect(anchorElement).toBeInTheDocument();
- expect(anchorElement).toHaveAttribute(
- 'href',
- '/project/activity?id=foo&graph=custom&custom_metrics=new_bugs%2Cbugs',
- );
-});
-
-function renderActivityLink(props: Partial<ActivityLinkProps> = {}) {
- return renderComponent(<ActivityLink component="foo" {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/FormattingTips-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/FormattingTips-test.tsx
deleted file mode 100644
index 5a47e0170cd..00000000000
--- a/server/sonar-web/src/main/js/components/common/__tests__/FormattingTips-test.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { FCProps } from '../../../types/misc';
-import FormattingTips from '../FormattingTips';
-
-const originalOpen = window.open;
-
-beforeAll(() => {
- Object.defineProperty(window, 'open', {
- writable: true,
- value: jest.fn(),
- });
-});
-
-afterAll(() => {
- Object.defineProperty(window, 'open', {
- writable: true,
- value: originalOpen,
- });
-});
-
-it('should render correctly', async () => {
- const user = userEvent.setup();
- renderFormattingTips();
- const link = screen.getByRole('link', { name: 'formatting.helplink' });
- expect(link).toBeInTheDocument();
- await user.click(link);
- expect(window.open).toHaveBeenCalled();
-});
-
-function renderFormattingTips(props: Partial<FCProps<typeof FormattingTips>> = {}) {
- return renderComponent(<FormattingTips {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/FormattingTipsWithLink-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/FormattingTipsWithLink-test.tsx
deleted file mode 100644
index aa6e93fdcd3..00000000000
--- a/server/sonar-web/src/main/js/components/common/__tests__/FormattingTipsWithLink-test.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import FormattingTipsWithLink from '../FormattingTipsWithLink';
-
-const originalOpen = window.open;
-
-beforeAll(() => {
- Object.defineProperty(window, 'open', {
- writable: true,
- value: jest.fn(),
- });
-});
-
-afterAll(() => {
- Object.defineProperty(window, 'open', {
- writable: true,
- value: originalOpen,
- });
-});
-
-it('should render correctly', async () => {
- const user = userEvent.setup();
- renderFormattingTipsWithLink();
- expect(screen.getByText('formatting.helplink')).toBeInTheDocument();
- expect(screen.getByText('formatting.example.link')).toBeInTheDocument();
-
- await user.click(screen.getByRole('link'));
- expect(window.open).toHaveBeenCalled();
-});
-
-function renderFormattingTipsWithLink(props: Partial<FormattingTipsWithLink['props']> = {}) {
- renderComponent(<FormattingTipsWithLink {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/Link-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/Link-test.tsx
deleted file mode 100644
index c8a1e5bdd54..00000000000
--- a/server/sonar-web/src/main/js/components/common/__tests__/Link-test.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import Link, { LinkProps } from '../Link';
-
-it('should correctly render an internal link', () => {
- renderLink();
- expect(screen.getByRole('link').getAttribute('rel')).not.toBe('noopener noreferrer');
- expect(screen.queryByLabelText('opens_in_new_window')).not.toBeInTheDocument();
-});
-
-it('should correctly render a link that opens in a new window, but is not considered external', () => {
- renderLink({ target: '_blank', to: '/path' });
- expect(screen.getByRole('link')).toHaveAttribute('rel', 'noopener noreferrer');
-});
-
-it('should correctly render an external link', () => {
- renderLink({ target: '_blank', to: 'http://example.com' });
- expect(screen.getByRole('link', { name: 'opens_in_new_window click me' })).toHaveAttribute(
- 'rel',
- 'noopener noreferrer',
- );
-});
-
-function renderLink(props: Partial<LinkProps> = {}) {
- return renderComponent(
- <Link to={{ pathname: 'to' }} {...props}>
- click me
- </Link>,
- );
-}
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/ModeBanner-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/ModeBanner-test.tsx
deleted file mode 100644
index 57e136a35f6..00000000000
--- a/server/sonar-web/src/main/js/components/common/__tests__/ModeBanner-test.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { ModeServiceMock } from '../../../api/mocks/ModeServiceMock';
-import UsersServiceMock from '../../../api/mocks/UsersServiceMock';
-import { mockCurrentUser } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { Mode } from '../../../types/mode';
-import { NoticeType } from '../../../types/users';
-import ModeBanner from '../ModeBanner';
-
-const modeHandler = new ModeServiceMock();
-const usersHandler = new UsersServiceMock();
-
-afterEach(() => {
- modeHandler.reset();
- usersHandler.reset();
-});
-
-describe('facetBanner', () => {
- it('renders as facetBanner for admins in MQR', async () => {
- const user = userEvent.setup();
- modeHandler.setMode(Mode.MQR);
- renderModeBanner(
- { as: 'facetBanner' },
- mockCurrentUser({ permissions: { global: ['admin'] } }),
- );
- expect(await screen.findByText('mode.mqr.advertisement')).toBeInTheDocument();
- await user.click(screen.getByRole('button', { name: 'dismiss' }));
- expect(screen.queryByText('mode.mqr.advertisement')).not.toBeInTheDocument();
- });
-
- it('renders as facetBanner for admins in Standard', async () => {
- const user = userEvent.setup();
- modeHandler.setMode(Mode.Standard);
- renderModeBanner(
- { as: 'facetBanner' },
- mockCurrentUser({ permissions: { global: ['admin'] } }),
- );
- expect(await screen.findByText('mode.standard.advertisement')).toBeInTheDocument();
- await user.click(screen.getByRole('button', { name: 'dismiss' }));
- expect(screen.queryByText('mode.standard.advertisement')).not.toBeInTheDocument();
- });
-
- it('does not render as facetBanner for regular users', () => {
- renderModeBanner({ as: 'facetBanner' }, mockCurrentUser());
- expect(screen.queryByText(/advertisement/)).not.toBeInTheDocument();
- });
-
- it('does not render if already dismissed', () => {
- renderModeBanner(
- { as: 'facetBanner' },
- mockCurrentUser({
- permissions: { global: ['admin'] },
- dismissedNotices: { [NoticeType.MQR_MODE_ADVERTISEMENT_BANNER]: true },
- }),
- );
- expect(screen.queryByText(/advertisement/)).not.toBeInTheDocument();
- });
-
- it('does not render if modified', () => {
- modeHandler.setModified();
- renderModeBanner(
- { as: 'facetBanner' },
- mockCurrentUser({
- permissions: { global: ['admin'] },
- }),
- );
- expect(screen.queryByText(/advertisement/)).not.toBeInTheDocument();
- });
-});
-
-describe('flagMessage', () => {
- it('renders as flagMessage for admins in MQR', async () => {
- const user = userEvent.setup();
- modeHandler.setMode(Mode.MQR);
- renderModeBanner({ as: 'wideBanner' }, mockCurrentUser({ permissions: { global: ['admin'] } }));
- expect(await screen.findByText('settings.mode.mqr.advertisement')).toBeInTheDocument();
- await user.click(screen.getByRole('button', { name: 'dismiss' }));
- expect(screen.queryByText('settings.mode.mqr.advertisement')).not.toBeInTheDocument();
- });
-
- it('renders as flagMessage for admins in Standard', async () => {
- const user = userEvent.setup();
- modeHandler.setMode(Mode.Standard);
- renderModeBanner({ as: 'wideBanner' }, mockCurrentUser({ permissions: { global: ['admin'] } }));
- expect(await screen.findByText('settings.mode.standard.advertisement')).toBeInTheDocument();
- await user.click(screen.getByRole('button', { name: 'dismiss' }));
- expect(screen.queryByText('settings.mode.standard.advertisement')).not.toBeInTheDocument();
- });
-
- it('does not render as flagMessage for regular users', () => {
- renderModeBanner({ as: 'wideBanner' }, mockCurrentUser());
- expect(screen.queryByText(/advertisement/)).not.toBeInTheDocument();
- });
-
- it('does not render if already dismissed', () => {
- renderModeBanner(
- { as: 'wideBanner' },
- mockCurrentUser({
- permissions: { global: ['admin'] },
- dismissedNotices: { [NoticeType.MQR_MODE_ADVERTISEMENT_BANNER]: true },
- }),
- );
- expect(screen.queryByText(/advertisement/)).not.toBeInTheDocument();
- });
-
- it('does not render if modified', () => {
- modeHandler.setModified();
- renderModeBanner(
- { as: 'wideBanner' },
- mockCurrentUser({
- permissions: { global: ['admin'] },
- }),
- );
- expect(screen.queryByText(/advertisement/)).not.toBeInTheDocument();
- });
-});
-
-function renderModeBanner(
- props: Parameters<typeof ModeBanner>[0],
- currentUser = mockCurrentUser(),
-) {
- return renderComponent(<ModeBanner {...props} />, '/', { currentUser });
-}
diff --git a/server/sonar-web/src/main/js/components/controls/ClickEventBoundary.tsx b/server/sonar-web/src/main/js/components/controls/ClickEventBoundary.tsx
deleted file mode 100644
index df6ad1259b3..00000000000
--- a/server/sonar-web/src/main/js/components/controls/ClickEventBoundary.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-
-export interface ClickEventBoundaryProps {
- children: React.ReactElement;
-}
-
-export default function ClickEventBoundary({ children }: ClickEventBoundaryProps) {
- return React.cloneElement(children, {
- onClick: (e: React.SyntheticEvent<MouseEvent>) => {
- e.stopPropagation();
- if (typeof children.props.onClick === 'function') {
- children.props.onClick(e);
- }
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/components/controls/ComponentReportActions.tsx b/server/sonar-web/src/main/js/components/controls/ComponentReportActions.tsx
deleted file mode 100644
index 4bad639dee6..00000000000
--- a/server/sonar-web/src/main/js/components/controls/ComponentReportActions.tsx
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { addGlobalSuccessMessage } from '~design-system';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import {
- getReportStatus,
- subscribeToEmailReport,
- unsubscribeFromEmailReport,
-} from '../../api/component-report';
-import withAppStateContext from '../../app/components/app-state/withAppStateContext';
-import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { AppState } from '../../types/appstate';
-import { Branch } from '../../types/branch-like';
-import { ComponentReportStatus } from '../../types/component-report';
-import { Component } from '../../types/types';
-import { CurrentUser, isLoggedIn } from '../../types/users';
-import ComponentReportActionsRenderer from './ComponentReportActionsRenderer';
-
-interface Props {
- appState: AppState;
- branch?: Branch;
- component: Component;
- currentUser: CurrentUser;
-}
-
-interface State {
- loadingStatus?: boolean;
- status?: ComponentReportStatus;
-}
-
-export class ComponentReportActions extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {};
-
- componentDidMount() {
- this.mounted = true;
- const governanceEnabled = this.props.appState.qualifiers.includes(ComponentQualifier.Portfolio);
-
- if (governanceEnabled) {
- this.loadReportStatus();
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- loadReportStatus = async () => {
- const { component, branch } = this.props;
-
- const status = await getReportStatus(component.key, branch?.name).catch(() => undefined);
-
- if (this.mounted) {
- this.setState({ status, loadingStatus: false });
- }
- };
-
- handleSubscription = (subscribed: boolean) => {
- const { component } = this.props;
- const { status } = this.state;
-
- const translationKey = subscribed
- ? 'component_report.subscribe_x_success'
- : 'component_report.unsubscribe_x_success';
-
- const frequencyTranslation = translate(
- 'report.frequency',
- status?.componentFrequency ?? status?.globalFrequency ?? '',
- ).toLowerCase();
-
- const qualifierTranslation = translate('qualifier', component.qualifier).toLowerCase();
-
- addGlobalSuccessMessage(
- translateWithParameters(translationKey, frequencyTranslation, qualifierTranslation),
- );
-
- this.loadReportStatus();
- };
-
- handleSubscribe = async () => {
- const { component, branch } = this.props;
-
- await subscribeToEmailReport(component.key, branch?.name);
-
- this.handleSubscription(true);
- };
-
- handleUnsubscribe = async () => {
- const { component, branch } = this.props;
-
- await unsubscribeFromEmailReport(component.key, branch?.name);
-
- this.handleSubscription(false);
- };
-
- render() {
- const { currentUser, component, branch } = this.props;
- const { status, loadingStatus } = this.state;
-
- if (loadingStatus || !status || (branch && !branch.excludedFromPurge)) {
- return null;
- }
-
- const currentUserHasEmail = isLoggedIn(currentUser) && !!currentUser.email;
-
- return (
- <ComponentReportActionsRenderer
- branch={branch}
- component={component}
- frequency={status.componentFrequency || status.globalFrequency}
- subscribed={status.subscribed}
- canSubscribe={status.canSubscribe}
- currentUserHasEmail={currentUserHasEmail}
- handleSubscription={this.handleSubscribe}
- handleUnsubscription={this.handleUnsubscribe}
- />
- );
- }
-}
-
-export default withCurrentUserContext(withAppStateContext(ComponentReportActions));
diff --git a/server/sonar-web/src/main/js/components/controls/ComponentReportActionsRenderer.tsx b/server/sonar-web/src/main/js/components/controls/ComponentReportActionsRenderer.tsx
deleted file mode 100644
index e331cd80522..00000000000
--- a/server/sonar-web/src/main/js/components/controls/ComponentReportActionsRenderer.tsx
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- ButtonSecondary,
- ChevronDownIcon,
- Dropdown,
- ItemButton,
- ItemDownload,
- PopupPlacement,
- PopupZLevel,
-} from '~design-system';
-import { getReportUrl } from '../../api/component-report';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { Branch } from '../../types/branch-like';
-import { Component } from '../../types/types';
-
-export interface ComponentReportActionsRendererProps {
- branch?: Branch;
- canSubscribe: boolean;
- component: Component;
- currentUserHasEmail: boolean;
- frequency: string;
- handleSubscription: () => void;
- handleUnsubscription: () => void;
- subscribed: boolean;
-}
-
-const getSubscriptionText = ({
- currentUserHasEmail,
- frequency,
- subscribed,
-}: Pick<
- ComponentReportActionsRendererProps,
- 'currentUserHasEmail' | 'frequency' | 'subscribed'
->) => {
- if (!currentUserHasEmail) {
- return translate('component_report.no_email_to_subscribe');
- }
-
- const translationKey = subscribed
- ? 'component_report.unsubscribe_x'
- : 'component_report.subscribe_x';
- const frequencyTranslation = translate('report.frequency', frequency).toLowerCase();
-
- return translateWithParameters(translationKey, frequencyTranslation);
-};
-
-export default function ComponentReportActionsRenderer(props: ComponentReportActionsRendererProps) {
- const { branch, component, frequency, subscribed, canSubscribe, currentUserHasEmail } = props;
-
- const downloadName = [component.name, branch?.name, 'PDF Report.pdf']
- .filter((s) => !!s)
- .join(' - ');
- const reportUrl = getReportUrl(component.key, branch?.name);
-
- return canSubscribe ? (
- <Dropdown
- id="component-report"
- size="auto"
- allowResizing
- placement={PopupPlacement.BottomRight}
- zLevel={PopupZLevel.Default}
- overlay={
- <>
- <ItemDownload download={downloadName} href={reportUrl}>
- {translate('download_verb')}
- </ItemDownload>
- <ItemButton
- disabled={!currentUserHasEmail}
- data-test="overview__subscribe-to-report-button"
- onClick={subscribed ? props.handleUnsubscription : props.handleSubscription}
- >
- {getSubscriptionText({ currentUserHasEmail, frequency, subscribed })}
- </ItemButton>
- </>
- }
- >
- <ButtonSecondary>
- {translateWithParameters(
- 'component_report.report',
- translate('qualifier', component.qualifier),
- )}
- <ChevronDownIcon className="sw-ml-1" />
- </ButtonSecondary>
- </Dropdown>
- ) : (
- <a download={downloadName} href={reportUrl} target="_blank" rel="noopener noreferrer">
- {translateWithParameters(
- 'component_report.download',
- translate('qualifier', component.qualifier).toLowerCase(),
- )}
- </a>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/controls/ConfirmButton.tsx b/server/sonar-web/src/main/js/components/controls/ConfirmButton.tsx
deleted file mode 100644
index b364c98bd67..00000000000
--- a/server/sonar-web/src/main/js/components/controls/ConfirmButton.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as Echoes from '@sonarsource/echoes-react';
-import * as React from 'react';
-import ConfirmModal, { ConfirmModalProps } from './ConfirmModal';
-import ModalButton, { ChildrenProps, ModalProps } from './ModalButton';
-
-interface Props<T> extends Omit<ConfirmModalProps<T>, 'children' | 'isOpen'> {
- children: (props: ChildrenProps) => React.ReactNode;
- modalBody: React.ReactNode;
- modalHeader: string;
- modalHeaderDescription?: React.ReactNode;
-}
-
-interface State {
- modal: boolean;
-}
-
-/** @deprecated Use {@link Echoes.ModalAlert | ModalAlert} from Echoes instead.
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3465543707/Modals | Migration Guide}
- */
-export default class ConfirmButton<T> extends React.PureComponent<Props<T>, State> {
- renderConfirmModal = ({ onClose }: ModalProps) => {
- const { children, modalBody, modalHeader, modalHeaderDescription, ...confirmModalProps } =
- this.props;
- return (
- <ConfirmModal
- header={modalHeader}
- headerDescription={modalHeaderDescription}
- onClose={onClose}
- isOpen
- {...confirmModalProps}
- >
- {modalBody}
- </ConfirmModal>
- );
- };
-
- render() {
- return <ModalButton modal={this.renderConfirmModal}>{this.props.children}</ModalButton>;
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/ConfirmModal.tsx b/server/sonar-web/src/main/js/components/controls/ConfirmModal.tsx
deleted file mode 100644
index 8df75495320..00000000000
--- a/server/sonar-web/src/main/js/components/controls/ConfirmModal.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as Echoes from '@sonarsource/echoes-react';
-import { Button, ButtonVariety, ModalAlert } from '@sonarsource/echoes-react';
-import React from 'react';
-import { translate } from '../../helpers/l10n';
-
-export interface ConfirmModalProps<T> {
- cancelButtonText?: string;
- children: React.ReactNode;
- confirmButtonText: string;
- confirmData?: T;
- confirmDisable?: boolean;
- isDestructive?: boolean;
- isOpen: boolean;
- onConfirm: (data?: T) => void | Promise<void | Response>;
-}
-
-interface Props<T> extends ConfirmModalProps<T> {
- header: string;
- headerDescription?: React.ReactNode;
- onClose: () => void;
-}
-
-/** @deprecated Use {@link Echoes.ModalAlert | ModalAlert} from Echoes instead.
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3465543707/Modals | Migration Guide}
- */
-export default function ConfirmModal<T = string>(props: Readonly<Props<T>>) {
- const {
- header,
- onClose,
- onConfirm,
- children,
- confirmButtonText,
- confirmData,
- confirmDisable,
- headerDescription,
- isDestructive,
- isOpen,
- cancelButtonText = translate('cancel'),
- } = props;
-
- const [submitting, setSubmitting] = React.useState(false);
-
- const handleSubmit = React.useCallback(() => {
- setSubmitting(true);
- const result = onConfirm(confirmData);
-
- if (result) {
- return result.then(
- () => {
- setSubmitting(false);
- onClose();
- },
- () => {
- setSubmitting(false);
- },
- );
- }
-
- setSubmitting(false);
- onClose();
- return undefined;
- }, [confirmData, onClose, onConfirm, setSubmitting]);
-
- return (
- <ModalAlert
- title={header}
- description={headerDescription}
- isOpen={isOpen}
- onOpenChange={onClose}
- content={children}
- primaryButton={
- <Button
- variety={isDestructive ? ButtonVariety.Danger : ButtonVariety.Primary}
- isDisabled={submitting || confirmDisable}
- isLoading={submitting}
- onClick={handleSubmit}
- >
- {confirmButtonText}
- </Button>
- }
- secondaryButtonLabel={cancelButtonText}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/controls/DocumentClickHandler.tsx b/server/sonar-web/src/main/js/components/controls/DocumentClickHandler.tsx
deleted file mode 100644
index b0b9a2cbdb9..00000000000
--- a/server/sonar-web/src/main/js/components/controls/DocumentClickHandler.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-
-interface Props {
- children: React.ReactNode;
- onClick: () => void;
-}
-
-export default class DocumentClickHandler extends React.Component<Props> {
- componentDidMount() {
- setTimeout(() => {
- this.addClickHandler();
- }, 0);
- }
-
- componentWillUnmount() {
- this.removeClickHandler();
- }
-
- addClickHandler = () => {
- document.addEventListener('click', this.handleDocumentClick);
- };
-
- removeClickHandler = () => {
- document.removeEventListener('click', this.handleDocumentClick);
- };
-
- handleDocumentClick = () => {
- this.props.onClick();
- };
-
- render() {
- return this.props.children;
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/EscKeydownHandler.tsx b/server/sonar-web/src/main/js/components/controls/EscKeydownHandler.tsx
deleted file mode 100644
index a5a51b4571e..00000000000
--- a/server/sonar-web/src/main/js/components/controls/EscKeydownHandler.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { KeyboardKeys } from '../../helpers/keycodes';
-
-interface Props {
- children: React.ReactNode;
- onKeydown: () => void;
-}
-
-export default class EscKeydownHandler extends React.Component<Props> {
- componentDidMount() {
- setTimeout(() => {
- document.addEventListener('keydown', this.handleKeyDown, false);
- }, 0);
- }
-
- componentWillUnmount() {
- document.removeEventListener('keydown', this.handleKeyDown, false);
- }
-
- handleKeyDown = (event: KeyboardEvent) => {
- if (event.key === KeyboardKeys.Escape) {
- this.props.onKeydown();
- }
- };
-
- render() {
- return this.props.children;
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/Favorite.tsx b/server/sonar-web/src/main/js/components/controls/Favorite.tsx
deleted file mode 100644
index 7df3737daa8..00000000000
--- a/server/sonar-web/src/main/js/components/controls/Favorite.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { FavoriteButton } from '~design-system';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { useToggleFavoriteMutation } from '../../queries/favorites';
-import Tooltip from './Tooltip';
-
-interface Props {
- className?: string;
- component: string;
- componentName?: string;
- favorite: boolean;
- handleFavorite?: (component: string, isFavorite: boolean) => void;
- qualifier: string;
-}
-
-export default function Favorite(props: Readonly<Props>) {
- const {
- className,
- componentName,
- qualifier,
- favorite: favoriteP,
- component,
- handleFavorite,
- } = props;
- const buttonRef = React.useRef<HTMLButtonElement>(null);
- // local state of favorite is only needed in case of portfolios, as they are not migrated to query yet
- const [favorite, setFavorite] = React.useState(favoriteP);
- const { mutate } = useToggleFavoriteMutation();
-
- const toggleFavorite = () => {
- const newFavorite = !favorite;
-
- return mutate(
- { component, addToFavorites: newFavorite },
- {
- onSuccess: () => {
- setFavorite(newFavorite);
- handleFavorite?.(component, newFavorite);
- buttonRef.current?.focus();
- },
- },
- );
- };
-
- const actionName = favorite ? 'remove' : 'add';
- const overlay = componentName
- ? translateWithParameters(`favorite.action.${qualifier}.${actionName}_x`, componentName)
- : translate('favorite.action', qualifier, actionName);
-
- React.useEffect(() => {
- setFavorite(favoriteP);
- }, [favoriteP]);
-
- return (
- <FavoriteButton
- className={className}
- overlay={overlay}
- toggleFavorite={toggleFavorite}
- tooltip={Tooltip}
- favorite={favorite}
- innerRef={buttonRef}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/controls/FocusOutHandler.tsx b/server/sonar-web/src/main/js/components/controls/FocusOutHandler.tsx
deleted file mode 100644
index 7081867d20e..00000000000
--- a/server/sonar-web/src/main/js/components/controls/FocusOutHandler.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-
-interface Props extends React.BaseHTMLAttributes<HTMLDivElement> {
- innerRef?: (instance: HTMLDivElement) => void;
- onFocusOut: () => void;
-}
-
-export default class FocusOutHandler extends React.PureComponent<React.PropsWithChildren<Props>> {
- ref?: HTMLDivElement;
-
- componentDidMount() {
- setTimeout(() => {
- document.addEventListener('focusin', this.handleFocusOut);
- }, 0);
- }
-
- componentWillUnmount() {
- document.removeEventListener('focusin', this.handleFocusOut);
- }
-
- nodeRef = (node: HTMLDivElement) => {
- const { innerRef } = this.props;
- this.ref = node;
- innerRef?.(node);
- };
-
- handleFocusOut = () => {
- if (this.ref?.querySelector(':focus') === null) {
- this.props.onFocusOut();
- }
- };
-
- render() {
- const { onFocusOut, innerRef, children, ...props } = this.props;
- return (
- <div ref={this.nodeRef} {...props}>
- {children}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx b/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx
deleted file mode 100644
index 460402bd51b..00000000000
--- a/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button } from '@sonarsource/echoes-react';
-import { useIntl } from 'react-intl';
-import { DiscreetInteractiveIcon, HomeFillIcon, HomeIcon } from '~design-system';
-import { setHomePage } from '../../api/users';
-import { CurrentUserContextInterface } from '../../app/components/current-user/CurrentUserContext';
-import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext';
-import { isSameHomePage } from '../../helpers/users';
-import { HomePage, isLoggedIn } from '../../types/users';
-import Tooltip from './Tooltip';
-
-interface Props
- extends Pick<CurrentUserContextInterface, 'currentUser' | 'updateCurrentUserHomepage'> {
- className?: string;
- currentPage: HomePage;
- type?: 'button' | 'icon';
-}
-
-export const DEFAULT_HOMEPAGE: HomePage = { type: 'PROJECTS' };
-
-export function HomePageSelect(props: Readonly<Props>) {
- const { currentPage, className, type = 'icon', currentUser, updateCurrentUserHomepage } = props;
- const intl = useIntl();
-
- if (!isLoggedIn(currentUser)) {
- return null;
- }
-
- const isChecked =
- currentUser.homepage !== undefined && isSameHomePage(currentUser.homepage, currentPage);
- const isDefault = isChecked && isSameHomePage(currentPage, DEFAULT_HOMEPAGE);
-
- const setCurrentUserHomepage = async (homepage: HomePage) => {
- if (isLoggedIn(currentUser)) {
- await setHomePage(homepage);
-
- updateCurrentUserHomepage(homepage);
- }
- };
-
- const tooltip = isChecked
- ? intl.formatMessage({ id: isDefault ? 'homepage.current.is_default' : 'homepage.current' })
- : intl.formatMessage({ id: 'homepage.check' });
-
- const handleClick = () => setCurrentUserHomepage?.(isChecked ? DEFAULT_HOMEPAGE : currentPage);
-
- const Icon = isChecked ? HomeFillIcon : HomeIcon;
-
- return (
- <Tooltip content={tooltip}>
- {type === 'icon' ? (
- <DiscreetInteractiveIcon
- aria-label={tooltip}
- className={className}
- disabled={isDefault}
- Icon={Icon}
- onClick={handleClick}
- />
- ) : (
- <Button
- aria-label={tooltip}
- prefix={<Icon />}
- className={className}
- isDisabled={isDefault}
- onClick={handleClick}
- >
- {intl.formatMessage({ id: 'overview.set_as_homepage' })}
- </Button>
- )}
- </Tooltip>
- );
-}
-
-export default withCurrentUserContext(HomePageSelect);
diff --git a/server/sonar-web/src/main/js/components/controls/InputValidationField.tsx b/server/sonar-web/src/main/js/components/controls/InputValidationField.tsx
deleted file mode 100644
index 889436fcedb..00000000000
--- a/server/sonar-web/src/main/js/components/controls/InputValidationField.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { InputField } from '~design-system';
-import ModalValidationField from './ModalValidationField';
-
-interface Props {
- autoFocus?: boolean;
- className?: string;
- description?: string;
- dirty: boolean;
- disabled: boolean;
- error: string | undefined;
- id?: string;
- label?: React.ReactNode;
- name: string;
- onBlur: (event: React.FocusEvent<HTMLInputElement>) => void;
- onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
- placeholder?: string;
- required?: boolean;
- touched: boolean | undefined;
- type?: string;
- value: string;
-}
-
-export default function InputValidationField({ ...props }: Readonly<Props>) {
- const { description, dirty, error, label, touched, required, ...inputProps } = props;
- const modalValidationProps = { description, dirty, error, label, touched, required };
- return (
- <ModalValidationField id={props.id} {...modalValidationProps}>
- {({ isInvalid, isValid }) => (
- <InputField size="full" isInvalid={isInvalid} isValid={isValid} {...inputProps} />
- )}
- </ModalValidationField>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/controls/ListFooter.tsx b/server/sonar-web/src/main/js/components/controls/ListFooter.tsx
deleted file mode 100644
index 9c1976e9903..00000000000
--- a/server/sonar-web/src/main/js/components/controls/ListFooter.tsx
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { Button } from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import * as React from 'react';
-import { Spinner } from '~design-system';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-
-export interface ListFooterProps {
- className?: string;
- count: number;
- loadMore?: () => void;
- loadMoreAriaLabel?: string;
- loading?: boolean;
- needReload?: boolean;
- pageSize?: number;
- ready?: boolean;
- reload?: () => void;
- total?: number;
-}
-
-export default function ListFooter(props: ListFooterProps) {
- const {
- loadMoreAriaLabel,
- className,
- count,
- loadMore,
- loading = false,
- needReload,
- total,
- pageSize,
- ready = true,
- } = props;
-
- const rootNode = React.useRef<HTMLDivElement>(null);
-
- const onLoadMore = React.useCallback(() => {
- if (loadMore) {
- loadMore();
- }
-
- if (rootNode.current) {
- rootNode.current.focus();
- }
- }, [loadMore, rootNode]);
-
- let hasMore = false;
- if (total !== undefined) {
- hasMore = total > count;
- } else if (pageSize !== undefined) {
- hasMore = count % pageSize === 0;
- }
-
- let button;
- if (needReload && props.reload) {
- button = (
- <Button
- data-test="reload"
- className="sw-ml-2 sw-typo-default"
- isDisabled={loading}
- onClick={props.reload}
- >
- {translate('reload')}
- </Button>
- );
- } else if (hasMore && props.loadMore) {
- button = (
- <Button
- aria-label={loadMoreAriaLabel}
- data-test="show-more"
- className="sw-ml-2 sw-typo-default"
- isDisabled={loading}
- onClick={onLoadMore}
- >
- {translate('show_more')}
- </Button>
- );
- }
-
- return (
- <StyledDiv
- tabIndex={-1}
- ref={rootNode}
- className={classNames(
- 'list-footer', // .list-footer is only used by Selenium tests; we should find a way to remove it.
- 'sw-typo-default sw-flex sw-items-center sw-justify-center',
- { 'sw-opacity-50 sw-duration-500 sw-ease-in-out': !ready },
- className,
- )}
- >
- <output aria-busy={loading}>
- {total !== undefined
- ? translateWithParameters(
- 'x_of_y_shown',
- formatMeasure(count, MetricType.Integer),
- formatMeasure(total, MetricType.Integer),
- )
- : translateWithParameters('x_show', formatMeasure(count, MetricType.Integer))}
- </output>
- {button}
- <Spinner loading={loading} className="sw-ml-2" />
- </StyledDiv>
- );
-}
-
-const StyledDiv = styled.div`
- color: var(--echoes-color-text-subdued);
-
- margin-top: 1rem /* 16px */;
-`;
diff --git a/server/sonar-web/src/main/js/components/controls/ManagedFilter.tsx b/server/sonar-web/src/main/js/components/controls/ManagedFilter.tsx
deleted file mode 100644
index 99de8ec6025..00000000000
--- a/server/sonar-web/src/main/js/components/controls/ManagedFilter.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ToggleButton } from '~design-system';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { Provider } from '../../types/types';
-
-interface ManagedFilterProps {
- loading: boolean;
- manageProvider: Provider | undefined;
- managed: boolean | undefined;
- setManaged: (managed: boolean | undefined) => void;
-}
-
-export function ManagedFilter(props: Readonly<ManagedFilterProps>) {
- const { manageProvider, loading, managed } = props;
-
- if (manageProvider === undefined) {
- return null;
- }
-
- return (
- <div className="sw-mr-4">
- <ToggleButton
- value={managed ?? 'all'}
- disabled={loading}
- options={[
- { label: translate('all'), value: 'all' },
- {
- label: translateWithParameters('managed', translate(`managed.${manageProvider}`)),
- value: true,
- },
- { label: translate('local'), value: false },
- ]}
- onChange={(filterOption) => {
- if (filterOption === 'all') {
- props.setManaged(undefined);
- } else {
- props.setManaged(filterOption);
- }
- }}
- />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/controls/ModalButton.tsx b/server/sonar-web/src/main/js/components/controls/ModalButton.tsx
deleted file mode 100644
index d87b638e6ae..00000000000
--- a/server/sonar-web/src/main/js/components/controls/ModalButton.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as Echoes from '@sonarsource/echoes-react';
-import * as React from 'react';
-
-export interface ChildrenProps {
- onClick: () => void;
- onFormSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
-}
-
-export interface ModalProps {
- onClose: () => void;
-}
-
-export interface Props {
- children: (props: ChildrenProps) => React.ReactNode;
- modal: (props: ModalProps) => React.ReactNode;
-}
-
-interface State {
- modal: boolean;
-}
-
-/** @deprecated Use either {@link Echoes.Modal | Modal} or {@link Echoes.ModalAlert | ModalAlert} from Echoes instead.
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3465543707/Modals | Migration Guide}
- */
-export default class ModalButton extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { modal: false };
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- handleButtonClick = () => {
- this.setState({ modal: true });
- };
-
- handleFormSubmit = (event?: React.FormEvent<HTMLFormElement>) => {
- if (event) {
- event.preventDefault();
- }
- this.setState({ modal: true });
- };
-
- handleCloseModal = () => {
- if (this.mounted) {
- this.setState({ modal: false });
- }
- };
-
- render() {
- return (
- <>
- {this.props.children({
- onClick: this.handleButtonClick,
- onFormSubmit: this.handleFormSubmit,
- })}
- {this.state.modal && this.props.modal({ onClose: this.handleCloseModal })}
- </>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/ModalValidationField.tsx b/server/sonar-web/src/main/js/components/controls/ModalValidationField.tsx
deleted file mode 100644
index a9c2bdf8861..00000000000
--- a/server/sonar-web/src/main/js/components/controls/ModalValidationField.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { IconCheckCircle, IconError } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { FormField, Note, themeColor } from '~design-system';
-import { translate } from '../../helpers/l10n';
-
-interface Props {
- children: (props: { isInvalid?: boolean; isValid?: boolean }) => React.ReactNode;
- description?: string;
- dirty: boolean;
- error: string | undefined;
- id?: string;
- label?: React.ReactNode;
- required?: boolean;
- touched: boolean | undefined;
-}
-
-export default function ModalValidationField(props: Readonly<Props>) {
- const { description, dirty, error, label, id, required } = props;
-
- const isValid = dirty && props.touched && error === undefined;
- const showError = dirty && props.touched && error !== undefined;
- return (
- <FormField
- label={label}
- htmlFor={id}
- required={required}
- requiredAriaLabel={translate('field_required')}
- >
- <div className="sw-flex sw-items-center sw-justify-between">
- {props.children({ isInvalid: showError, isValid })}
- {showError && <IconError color="echoes-color-icon-danger" className="sw-ml-2" />}
- {isValid && <IconCheckCircle color="echoes-color-icon-success" className="sw-ml-2" />}
- </div>
-
- <div aria-live="assertive">
- {isValid && (
- <span className="sw-mt-2 sw-sr-only">
- <FormattedMessage id="valid_input" />
- </span>
- )}
- {showError && <StyledNote className="sw-mt-2">{error}</StyledNote>}
- </div>
-
- {description !== undefined && <Note className="sw-mt-2">{description}</Note>}
- </FormField>
- );
-}
-
-const StyledNote = styled(Note)`
- color: ${themeColor('errorText')};
-`;
diff --git a/server/sonar-web/src/main/js/components/controls/OutsideClickHandler.tsx b/server/sonar-web/src/main/js/components/controls/OutsideClickHandler.tsx
deleted file mode 100644
index df72bfbf4fc..00000000000
--- a/server/sonar-web/src/main/js/components/controls/OutsideClickHandler.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { findDOMNode } from 'react-dom';
-
-interface Props {
- children: React.ReactNode;
- onClickOutside: () => void;
-}
-
-export default class OutsideClickHandler extends React.Component<Props> {
- mounted = false;
-
- componentDidMount() {
- this.mounted = true;
- setTimeout(() => {
- this.addClickHandler();
- }, 0);
- }
-
- componentWillUnmount() {
- this.mounted = false;
- this.removeClickHandler();
- }
-
- addClickHandler = () => {
- window.addEventListener('click', this.handleWindowClick);
- };
-
- removeClickHandler = () => {
- window.removeEventListener('click', this.handleWindowClick);
- };
-
- handleWindowClick = (event: MouseEvent) => {
- if (this.mounted) {
- // eslint-disable-next-line react/no-find-dom-node
- const node = findDOMNode(this);
- if (
- node &&
- !node.contains(event.target as Node) &&
- window.document.contains(event.target as Node)
- ) {
- this.props.onClickOutside();
- }
- }
- };
-
- render() {
- return this.props.children;
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/ScreenPositionFixer.tsx b/server/sonar-web/src/main/js/components/controls/ScreenPositionFixer.tsx
deleted file mode 100644
index 3d401474848..00000000000
--- a/server/sonar-web/src/main/js/components/controls/ScreenPositionFixer.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throttle } from 'lodash';
-import * as React from 'react';
-import { findDOMNode } from 'react-dom';
-
-interface Props {
- /**
- * First time `children` are rendered with `undefined` fixes to measure the offset.
- * Second time it renders with the computed fixes.
- */
- children: (props: Fixes) => React.ReactNode;
-
- /**
- * Use this flag to force re-positioning.
- * Use cases:
- * - when you need to measure `children` size first
- * - when you load content asynchronously
- */
- ready?: boolean;
-}
-
-interface Fixes {
- leftFix?: number;
- topFix?: number;
-}
-
-const EDGE_MARGIN = 4;
-
-export default class ScreenPositionFixer extends React.Component<Props, Fixes> {
- throttledPosition: () => void;
-
- constructor(props: Props) {
- super(props);
- this.state = {};
- this.throttledPosition = throttle(this.position, 50);
- }
-
- componentDidMount() {
- this.addEventListeners();
- this.position();
- }
-
- componentDidUpdate(prevProps: Props) {
- if (!prevProps.ready && this.props.ready) {
- this.position();
- } else if (prevProps.ready && !this.props.ready) {
- this.reset();
- }
- }
-
- componentWillUnmount() {
- this.removeEventListeners();
- }
-
- addEventListeners = () => {
- window.addEventListener('resize', this.throttledPosition);
- };
-
- removeEventListeners = () => {
- window.removeEventListener('resize', this.throttledPosition);
- };
-
- reset = () => {
- this.setState({ leftFix: undefined, topFix: undefined });
- };
-
- position = () => {
- // eslint-disable-next-line react/no-find-dom-node
- const node = findDOMNode(this);
- if (node && node instanceof Element) {
- const { width, height, left, top } = node.getBoundingClientRect();
- const { clientHeight, clientWidth } = document.documentElement;
-
- let leftFix = 0;
- if (left < EDGE_MARGIN) {
- leftFix = EDGE_MARGIN - left;
- } else if (left + width > clientWidth - EDGE_MARGIN) {
- leftFix = clientWidth - EDGE_MARGIN - left - width;
- }
-
- let topFix = 0;
- if (top < EDGE_MARGIN) {
- topFix = EDGE_MARGIN - top;
- } else if (top + height > clientHeight - EDGE_MARGIN) {
- topFix = clientHeight - EDGE_MARGIN - top - height;
- }
-
- this.setState({ leftFix, topFix });
- }
- };
-
- render() {
- return this.props.children(this.state);
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/SelectList.tsx b/server/sonar-web/src/main/js/components/controls/SelectList.tsx
deleted file mode 100644
index c0e6e469433..00000000000
--- a/server/sonar-web/src/main/js/components/controls/SelectList.tsx
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { InputSearch, PageContentFontWrapper, ToggleButton } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import ListFooter from './ListFooter';
-import SelectListListContainer from './SelectListListContainer';
-
-export enum SelectListFilter {
- All = 'all',
- Selected = 'selected',
- Unselected = 'deselected',
-}
-
-type Props = {
- allowBulkSelection?: boolean;
- autoFocusSearch?: boolean;
- disabledElements?: string[];
- elements: string[];
- elementsTotalCount?: number;
- labelAll?: string;
- labelSelected?: string;
- labelUnselected?: string;
- needToReload?: boolean;
- onSelect: (element: string) => Promise<void>;
- onUnselect: (element: string) => Promise<void>;
- pageSize?: number;
- readOnly?: boolean;
- renderElement: (element: string) => React.ReactNode;
- selectedElements: string[];
- withPaging?: boolean;
-} & (
- | {
- loading?: never;
- onSearch: (searchParams: SelectListSearchParams) => Promise<void>;
- }
- | {
- loading: boolean;
- onSearch: (searchParams: SelectListSearchParams) => void;
- }
-);
-
-export interface SelectListSearchParams {
- filter: SelectListFilter;
- page?: number;
- pageSize?: number;
- query: string;
-}
-
-interface State {
- lastSearchParams: SelectListSearchParams;
- loading: boolean;
-}
-
-const DEFAULT_PAGE_SIZE = 100;
-
-export default class SelectList extends React.PureComponent<Props, State> {
- mounted = false;
-
- constructor(props: Props) {
- super(props);
-
- this.state = {
- lastSearchParams: {
- filter: SelectListFilter.Selected,
- page: 1,
- pageSize: props.pageSize ? props.pageSize : DEFAULT_PAGE_SIZE,
- query: '',
- },
- loading: false,
- };
- }
-
- componentDidMount() {
- this.mounted = true;
- this.search({});
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- stopLoading = () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- };
-
- getFilter = () =>
- this.state.lastSearchParams.query === ''
- ? this.state.lastSearchParams.filter
- : SelectListFilter.All;
-
- search = (searchParams: Partial<SelectListSearchParams>) => {
- this.setState(
- (prevState) => ({
- loading: true,
- lastSearchParams: { ...prevState.lastSearchParams, ...searchParams },
- }),
- () => {
- const params = {
- filter: this.getFilter(),
- page: this.props.withPaging ? this.state.lastSearchParams.page : undefined,
- pageSize: this.props.withPaging ? this.state.lastSearchParams.pageSize : undefined,
- query: this.state.lastSearchParams.query,
- };
-
- if (this.props.loading !== undefined) {
- this.props.onSearch(params);
- } else {
- this.props.onSearch(params).then(this.stopLoading).catch(this.stopLoading);
- }
- },
- );
- };
-
- changeFilter = (filter: SelectListFilter) => this.search({ filter, page: 1 });
-
- handleQueryChange = (query: string) => this.search({ page: 1, query });
-
- onLoadMore = () =>
- this.search({
- page:
- this.state.lastSearchParams.page != null ? this.state.lastSearchParams.page + 1 : undefined,
- });
-
- onReload = () => this.search({ page: 1 });
-
- render() {
- const {
- labelSelected = translate('selected'),
- labelUnselected = translate('unselected'),
- labelAll = translate('all'),
- autoFocusSearch = true,
- } = this.props;
- const { filter } = this.state.lastSearchParams;
-
- const disabled = this.state.lastSearchParams.query !== '';
-
- return (
- <PageContentFontWrapper className="it__select-list">
- <div className="sw-flex sw-items-center">
- <span className="sw-mr-2">
- <ToggleButton
- onChange={this.changeFilter}
- disabled={disabled}
- options={[
- { label: labelSelected, value: SelectListFilter.Selected },
- { label: labelUnselected, value: SelectListFilter.Unselected },
- { label: labelAll, value: SelectListFilter.All },
- ]}
- value={filter}
- />
- </span>
- <InputSearch
- autoFocus={autoFocusSearch}
- loading={this.props.loading ?? this.state.loading}
- onChange={this.handleQueryChange}
- placeholder={translate('search_verb')}
- value={this.state.lastSearchParams.query}
- />
- </div>
- <SelectListListContainer
- allowBulkSelection={this.props.allowBulkSelection}
- disabledElements={this.props.disabledElements || []}
- elements={this.props.elements}
- filter={this.getFilter()}
- onSelect={this.props.onSelect}
- onUnselect={this.props.onUnselect}
- readOnly={this.props.readOnly}
- renderElement={this.props.renderElement}
- selectedElements={this.props.selectedElements}
- />
- {!!this.props.elementsTotalCount && (
- <ListFooter
- count={this.props.elements.length}
- loadMore={this.onLoadMore}
- needReload={this.props.needToReload}
- reload={this.onReload}
- total={this.props.elementsTotalCount}
- />
- )}
- </PageContentFontWrapper>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/SelectListListContainer.tsx b/server/sonar-web/src/main/js/components/controls/SelectListListContainer.tsx
deleted file mode 100644
index 1ea73e206d8..00000000000
--- a/server/sonar-web/src/main/js/components/controls/SelectListListContainer.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import * as React from 'react';
-import { Checkbox, ListItem, UnorderedList, themeBorder } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { SelectListFilter } from './SelectList';
-import SelectListListElement from './SelectListListElement';
-
-interface Props {
- allowBulkSelection?: boolean;
- disabledElements: string[];
- elements: string[];
- filter: SelectListFilter;
- onSelect: (element: string) => Promise<void>;
- onUnselect: (element: string) => Promise<void>;
- readOnly?: boolean;
- renderElement: (element: string) => React.ReactNode;
- selectedElements: string[];
-}
-
-interface State {
- loading: boolean;
-}
-
-export default class SelectListListContainer extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { loading: false };
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- stopLoading = () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- };
-
- isDisabled = (element: string): boolean => {
- return this.props.readOnly || this.props.disabledElements.includes(element);
- };
-
- isSelected = (element: string): boolean => {
- return this.props.selectedElements.includes(element);
- };
-
- handleBulkChange = (checked: boolean) => {
- this.setState({ loading: true });
- if (checked) {
- Promise.all(this.props.elements.map((element) => this.props.onSelect(element)))
- .then(this.stopLoading)
- .catch(this.stopLoading);
- } else {
- Promise.all(this.props.selectedElements.map((element) => this.props.onUnselect(element)))
- .then(this.stopLoading)
- .catch(this.stopLoading);
- }
- };
-
- renderBulkSelector() {
- const { elements, readOnly, selectedElements } = this.props;
- return (
- <BorderedListItem className="sw-pb-4">
- <Checkbox
- checked={selectedElements.length > 0}
- disabled={this.state.loading || readOnly}
- onCheck={this.handleBulkChange}
- thirdState={selectedElements.length > 0 && elements.length !== selectedElements.length}
- loading={this.state.loading}
- >
- <span className="sw-ml-4">{translate('bulk_change')}</span>
- </Checkbox>
- </BorderedListItem>
- );
- }
-
- render() {
- const { allowBulkSelection, elements, filter } = this.props;
-
- return (
- <ListContainer className="sw-mt-2 sw-p-3 sw-rounded-1 it__select-list-list-container">
- <UnorderedList className="-sw-mt-3">
- {allowBulkSelection &&
- elements.length > 0 &&
- filter === SelectListFilter.All &&
- this.renderBulkSelector()}
- {elements.map((element) => (
- <SelectListListElement
- disabled={this.isDisabled(element)}
- element={element}
- key={element}
- onSelect={this.props.onSelect}
- onUnselect={this.props.onUnselect}
- renderElement={this.props.renderElement}
- selected={this.isSelected(element)}
- />
- ))}
- </UnorderedList>
- </ListContainer>
- );
- }
-}
-
-const BorderedListItem = styled(ListItem)`
- border-bottom: ${themeBorder('default', 'discreetBorder')};
-`;
-
-const ListContainer = styled.div`
- overflow: auto;
- height: 330px;
- border: ${themeBorder('default')};
-`;
diff --git a/server/sonar-web/src/main/js/components/controls/SelectListListElement.tsx b/server/sonar-web/src/main/js/components/controls/SelectListListElement.tsx
deleted file mode 100644
index 59dfe201feb..00000000000
--- a/server/sonar-web/src/main/js/components/controls/SelectListListElement.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Checkbox, ListItem } from '~design-system';
-
-interface Props {
- disabled?: boolean;
- element: string;
- onSelect: (element: string) => Promise<void>;
- onUnselect: (element: string) => Promise<void>;
- renderElement: (element: string) => React.ReactNode | [React.ReactNode, React.ReactNode];
- selected: boolean;
-}
-
-export default function SelectListListElement(props: Readonly<Props>) {
- const { disabled, element, onSelect, onUnselect, renderElement, selected } = props;
-
- const [loading, setLoading] = React.useState(false);
-
- const handleCheck = React.useCallback(
- (checked: boolean) => {
- setLoading(true);
- const request = checked ? onSelect : onUnselect;
- request(element)
- .then(() => setLoading(false))
- .catch(() => setLoading(false));
- },
- [element, setLoading, onSelect, onUnselect],
- );
-
- let item = renderElement(element);
- let extra;
- if (Array.isArray(item)) {
- extra = item[1];
- item = item[0];
- }
- return (
- <ListItem className="sw-flex sw-justify-between">
- <Checkbox checked={selected} disabled={disabled} loading={loading} onCheck={handleCheck}>
- <span className="sw-ml-4">{item}</span>
- </Checkbox>
- {extra && <span>{extra}</span>}
- </ListItem>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/controls/Tooltip.css b/server/sonar-web/src/main/js/components/controls/Tooltip.css
deleted file mode 100644
index 8ccf9a2f409..00000000000
--- a/server/sonar-web/src/main/js/components/controls/Tooltip.css
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-.tooltip {
- position: absolute;
- z-index: 9001;
- display: block;
- height: auto;
- box-sizing: border-box;
- font-weight: 400;
- font-size: 14px;
- line-height: 20px;
- animation: fadeIn 0.3s forwards;
-}
-
-.tooltip.top {
- padding: 5px 0;
- margin-top: -3px;
-}
-
-.tooltip.right {
- padding: 0 5px;
- margin-left: 3px;
-}
-
-.tooltip.bottom {
- padding: 5px 0;
- margin-top: 3px;
-}
-
-.tooltip.left {
- padding: 0 5px;
- margin-left: -3px;
-}
-
-.tooltip-inner {
- font: var(--echoes-typography-paragraph-small-regular);
- max-width: 22rem;
- text-align: left;
- text-decoration: none;
- border-radius: var(--echoes-border-radius-200);
- overflow: hidden;
- word-break: break-word;
- padding: var(--echoes-dimension-space-50) var(--echoes-dimension-space-150);
- color: var(--echoes-color-text-on-color);
- background-color: var(--echoes-color-background-inverse);
-}
-
-.tooltip-inner .alert {
- margin-bottom: 5px;
- border-radius: 4px;
-}
-
-.tooltip-inner a {
- border-bottom-color: #bdc6ff;
- color: #bdc6ff;
-}
-
-.tooltip-inner hr {
- background-color: #5d6d75;
-}
-
-.tooltip-arrow {
- position: absolute;
- width: 0;
- height: 0;
- border: solid transparent;
-}
-
-.tooltip.top .tooltip-arrow {
- bottom: 0;
- left: 50%;
- border-width: 5px 5px 0;
- transform: translateX(-5px);
- border-top-color: #2a2f40;
-}
-
-.tooltip.right .tooltip-arrow {
- top: 50%;
- left: 0;
- transform: translateY(-5px);
- border-width: 5px 5px 5px 0;
- border-right-color: #2a2f40;
-}
-
-.tooltip.left .tooltip-arrow {
- top: 50%;
- right: 0;
- transform: translateY(-5px);
- border-width: 5px 0 5px 5px;
- border-left-color: #2a2f40;
-}
-
-.tooltip.bottom .tooltip-arrow {
- top: 0;
- left: 50%;
- transform: translateX(-5px);
- border-width: 0 5px 5px;
- border-bottom-color: #2a2f40;
-}
-
-/* Workaround for react issue with onMouseLeave in disabled buttons: https://github.com/facebook/react/issues/4251 */
-.tooltip button[disabled] {
- pointer-events: none;
-}
-
-.tooltip .issue-message-highlight-CODE {
- background-color: rgba(255, 255, 255, 0.18);
-}
-
-@keyframes fadeIn {
- from {
- opacity: 0;
- }
-
- to {
- opacity: 1;
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/Tooltip.tsx b/server/sonar-web/src/main/js/components/controls/Tooltip.tsx
deleted file mode 100644
index 472d3e9af39..00000000000
--- a/server/sonar-web/src/main/js/components/controls/Tooltip.tsx
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { throttle, uniqueId } from 'lodash';
-import * as React from 'react';
-import { createPortal, findDOMNode } from 'react-dom';
-import { ONE_SECOND } from '../../helpers/constants';
-import { translate } from '../../helpers/l10n';
-import EscKeydownHandler from './EscKeydownHandler';
-import FocusOutHandler from './FocusOutHandler';
-import ScreenPositionFixer from './ScreenPositionFixer';
-import './Tooltip.css';
-
-export type Placement = 'bottom' | 'right' | 'left' | 'top';
-
-interface TooltipProps {
- children: React.ReactElement;
- classNameInner?: string;
- classNameSpace?: string;
- content: React.ReactNode;
- // If tooltip overlay has interactive content (links for instance) we may set this to true to stop
- // default behavior of tabbing (other changes should be done outside of this component to make it work)
- // See example DocHelpTooltip
- isInteractive?: boolean;
- isOpen?: boolean;
- mouseEnterDelay?: number;
- mouseLeaveDelay?: number;
- onHide?: () => void;
- onShow?: () => void;
- side?: Placement;
-}
-
-interface Measurements {
- height: number;
- left: number;
- top: number;
- width: number;
-}
-
-interface OwnState {
- flipped: boolean;
- placement?: Placement;
- visible: boolean;
-}
-
-type State = OwnState & Partial<Measurements>;
-
-const FLIP_MAP: { [key in Placement]: Placement } = {
- left: 'right',
- right: 'left',
- top: 'bottom',
- bottom: 'top',
-};
-
-function isMeasured(state: State): state is OwnState & Measurements {
- return state.height !== undefined;
-}
-
-/** @deprecated Use {@link Echoes.Tooltip | Tooltip} from Echoes instead.
- *
- * Echoes Tooltip component should mainly be used on interactive element and contain very simple text based content.
- * If the content is more complex use a Popover component instead (not available yet).
- *
- * Some of the props have changed or been renamed:
- * - `children` is the trigger for the tooltip, should be an interactive Element. If not an Echoes component, make sure the component forwards the props and the ref to an interactive DOM node, it's needed by the tooltip to position itself.
- * - `overlay` is now `content`, that's the tooltip content. It's a ReactNode for convenience but should render only text based content, no interactivity is allowed inside the tooltip.
- * - ~`classNameSpace`~ doesn't exist anymore, was mostly used in situation that should be replaced by a Popover component.
- * - ~`mouseEnterDelay`~ doesn't exist anymore, was mostly used in situation that should be replaced by a Popover component.
- * - ~`mouseLeaveDelay`~ doesn't exist anymore, was mostly used in situation that should be replaced by a Popover component.
- * - ~`onHide`~ doesn't exist anymore, was mostly used in situation that should be replaced by a Popover component.
- * - ~`onShow`~ doesn't exist anymore, was mostly used in situation that should be replaced by a Popover component.
- * - `placement` is now `align` and `side`, based on the {@link Echoes.TooltipAlign | TooltipAlign} and {@link Echoes.TooltipSide | TooltipSide} enums.
- * - `visible` is now `isOpen`
- */
-export default function LegacyTooltip(props: TooltipProps) {
- // `overlay` is a ReactNode, so it can be `undefined` or `null`. This allows to easily
- // render a tooltip conditionally. More generally, we avoid rendering empty tooltips.
- return props.content != null && props.content !== '' ? (
- <TooltipInner {...props} />
- ) : (
- props.children
- );
-}
-
-export class TooltipInner extends React.Component<TooltipProps, State> {
- throttledPositionTooltip: () => void;
- mouseEnterTimeout?: number;
- mouseLeaveTimeout?: number;
- tooltipNode?: HTMLElement | null;
- mounted = false;
- mouseIn = false;
- id: string;
-
- static defaultProps = {
- mouseEnterDelay: 0.1,
- };
-
- constructor(props: TooltipProps) {
- super(props);
- this.state = {
- flipped: false,
- placement: props.side,
- visible: props.isOpen ?? false,
- };
- this.id = uniqueId('tooltip-');
- this.throttledPositionTooltip = throttle(this.positionTooltip, 10);
- }
-
- componentDidMount() {
- this.mounted = true;
- if (this.props.isOpen === true) {
- this.positionTooltip();
- this.addEventListeners();
- }
- }
-
- componentDidUpdate(prevProps: TooltipProps, prevState: State) {
- if (this.props.side !== prevProps.side) {
- this.setState({ placement: this.props.side });
- // Break. This will trigger a new componentDidUpdate() call, so the below
- // positionTooltip() call will be correct. Otherwise, it might not use
- // the new state.placement value.
- return;
- }
-
- if (
- // opens
- (this.props.isOpen === true && !prevProps.isOpen) ||
- (this.props.isOpen === undefined && this.state.visible && !prevState.visible)
- ) {
- this.positionTooltip();
- this.addEventListeners();
- } else if (
- // closes
- (!this.props.isOpen && prevProps.isOpen === true) ||
- (this.props.isOpen === undefined && !this.state.visible && prevState.visible)
- ) {
- this.clearPosition();
- this.removeEventListeners();
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- this.removeEventListeners();
- this.clearTimeouts();
- }
-
- addEventListeners = () => {
- window.addEventListener('resize', this.throttledPositionTooltip);
- window.addEventListener('scroll', this.throttledPositionTooltip);
- };
-
- removeEventListeners = () => {
- window.removeEventListener('resize', this.throttledPositionTooltip);
- window.removeEventListener('scroll', this.throttledPositionTooltip);
- };
-
- clearTimeouts = () => {
- window.clearTimeout(this.mouseEnterTimeout);
- window.clearTimeout(this.mouseLeaveTimeout);
- };
-
- isVisible = () => {
- return this.props.isOpen ?? this.state.visible;
- };
-
- getPlacement = (): Placement => {
- return this.state.placement ?? 'bottom';
- };
-
- tooltipNodeRef = (node: HTMLElement | null) => {
- this.tooltipNode = node;
- };
-
- adjustArrowPosition = (
- placement: Placement,
- { leftFix, topFix }: { leftFix: number; topFix: number },
- ) => {
- switch (placement) {
- case 'left':
- case 'right':
- return { marginTop: -topFix };
- default:
- return { marginLeft: -leftFix };
- }
- };
-
- positionTooltip = () => {
- // `findDOMNode(this)` will search for the DOM node for the current component.
- // First, it will find a React.Fragment (see `render`). It will skip this, and
- // it will get the DOM node of the first child, i.e. DOM node of `this.props.children`.
- // docs: https://reactjs.org/docs/refs-and-the-dom.html#exposing-dom-refs-to-parent-components
-
- // eslint-disable-next-line react/no-find-dom-node
- const toggleNode = findDOMNode(this);
-
- if (toggleNode && toggleNode instanceof Element && this.tooltipNode) {
- const toggleRect = toggleNode.getBoundingClientRect();
- const tooltipRect = this.tooltipNode.getBoundingClientRect();
- const { width, height } = tooltipRect;
-
- let left = 0;
- let top = 0;
-
- switch (this.getPlacement()) {
- case 'bottom':
- left = toggleRect.left + toggleRect.width / 2 - width / 2;
- top = toggleRect.top + toggleRect.height;
- break;
- case 'top':
- left = toggleRect.left + toggleRect.width / 2 - width / 2;
- top = toggleRect.top - height;
- break;
- case 'right':
- left = toggleRect.left + toggleRect.width;
- top = toggleRect.top + toggleRect.height / 2 - height / 2;
- break;
- case 'left':
- left = toggleRect.left - width;
- top = toggleRect.top + toggleRect.height / 2 - height / 2;
- break;
- }
-
- // Save width and height (and later set in `render`) to avoid resizing the tooltip
- // element when it's placed close to the window's edge.
- this.setState({
- left: window.pageXOffset + left,
- top: window.pageYOffset + top,
- width,
- height,
- });
- }
- };
-
- clearPosition = () => {
- this.setState({
- flipped: false,
- left: undefined,
- top: undefined,
- width: undefined,
- height: undefined,
- placement: this.props.side,
- });
- };
-
- handleMouseEnter = () => {
- this.mouseEnterTimeout = window.setTimeout(
- () => {
- // For some reason, even after the `this.mouseEnterTimeout` is cleared, it still
- // triggers. To workaround this issue, check that its value is not `undefined`
- // (if it's `undefined`, it means the timer has been reset).
- if (
- this.mounted &&
- this.props.isOpen === undefined &&
- this.mouseEnterTimeout !== undefined
- ) {
- this.setState({ visible: true });
- }
- },
- (this.props.mouseEnterDelay ?? 0) * ONE_SECOND,
- );
-
- if (this.props.onShow) {
- this.props.onShow();
- }
- };
-
- handleMouseLeave = () => {
- if (this.mouseEnterTimeout !== undefined) {
- window.clearTimeout(this.mouseEnterTimeout);
- this.mouseEnterTimeout = undefined;
- }
-
- if (!this.mouseIn) {
- this.mouseLeaveTimeout = window.setTimeout(
- () => {
- if (this.mounted && this.props.isOpen === undefined && !this.mouseIn) {
- this.setState({ visible: false });
- }
- if (this.props.onHide && !this.mouseIn) {
- this.props.onHide();
- }
- },
- (this.props.mouseLeaveDelay ?? 0) * ONE_SECOND,
- );
- }
- };
-
- handleFocus = () => {
- this.setState({ visible: true });
- if (this.props.onShow) {
- this.props.onShow();
- }
- };
-
- handleBlur = () => {
- if (!this.props.isInteractive) {
- this.closeTooltip();
- }
- };
-
- closeTooltip = () => {
- if (this.mounted) {
- this.setState({ visible: false });
- if (this.props.onHide) {
- this.props.onHide();
- }
- }
- };
-
- handleOverlayMouseEnter = () => {
- this.mouseIn = true;
- };
-
- handleOverlayMouseLeave = () => {
- this.mouseIn = false;
- this.handleMouseLeave();
- };
-
- needsFlipping = (leftFix: number, topFix: number) => {
- // We can live with a tooltip that's slightly positioned over the toggle
- // node. Only trigger if it really starts overlapping, as the re-positioning
- // is quite expensive, needing 2 re-renders.
- const threshold = 8;
- switch (this.getPlacement()) {
- case 'left':
- case 'right':
- return Math.abs(leftFix) > threshold;
- case 'top':
- case 'bottom':
- return Math.abs(topFix) > threshold;
- }
- return false;
- };
-
- renderActual = ({ leftFix = 0, topFix = 0 }) => {
- if (
- !this.state.flipped &&
- (leftFix !== 0 || topFix !== 0) &&
- this.needsFlipping(leftFix, topFix)
- ) {
- // Update state in a render function... Not a good idea, but we need to
- // render in order to know if we need to flip... To prevent React from
- // complaining, we update the state using a setTimeout() call.
- setTimeout(() => {
- this.setState(
- ({ placement = 'bottom' }) => ({
- flipped: true,
- // Set height to undefined to force ScreenPositionFixer to
- // re-compute our positioning.
- height: undefined,
- placement: FLIP_MAP[placement],
- }),
- () => {
- if (this.state.visible) {
- // Force a re-positioning, as "only" updating the state doesn't
- // recompute the position, only re-renders with the previous
- // position (which is no longer correct).
- this.positionTooltip();
- }
- },
- );
- }, 1);
- return null;
- }
-
- const { classNameSpace = 'tooltip' } = this.props;
- const currentPlacement = this.getPlacement();
- const style = isMeasured(this.state)
- ? {
- left: this.state.left + leftFix,
- top: this.state.top + topFix,
- width: this.state.width,
- height: this.state.height,
- }
- : undefined;
-
- return (
- <FocusOutHandler
- onFocusOut={this.closeTooltip}
- className={`${classNameSpace} ${currentPlacement}`}
- onPointerEnter={this.handleOverlayMouseEnter}
- onPointerLeave={this.handleOverlayMouseLeave}
- innerRef={this.tooltipNodeRef}
- style={style}
- >
- {this.renderOverlay()}
- <div
- className={`${classNameSpace}-arrow`}
- style={
- isMeasured(this.state)
- ? this.adjustArrowPosition(currentPlacement, { leftFix, topFix })
- : undefined
- }
- />
- </FocusOutHandler>
- );
- };
-
- renderOverlay() {
- const isVisible = this.isVisible();
- const {
- classNameSpace = 'tooltip',
- isInteractive,
- content: overlay,
- classNameInner,
- } = this.props;
- return (
- <div
- className={classNames(`${classNameSpace}-inner sw-font-sans`, classNameInner, {
- 'sw-hidden': !isVisible,
- })}
- id={this.id}
- role="tooltip"
- aria-hidden={!isVisible}
- >
- {isInteractive && <span className="sw-sr-only">{translate('tooltip_is_interactive')}</span>}
- {overlay}
- </div>
- );
- }
-
- render() {
- const isVisible = this.isVisible();
- const { isInteractive } = this.props;
- return (
- <>
- {React.cloneElement(this.props.children, {
- onPointerEnter: this.handleMouseEnter,
- onPointerLeave: this.handleMouseLeave,
- onFocus: this.handleFocus,
- onBlur: this.handleBlur,
- tabIndex: isInteractive ? 0 : undefined,
- // aria-describedby is the semantically correct property to use, but it's not
- // always well supported. We sometimes need to handle this differently, depending
- // on the triggering element. For example, we can add a child <description> element
- // if the triggering element is an SVG. See HelpTooltip for an example.
- // We should NOT use aria-labelledby, as this can have unintended effects (e.g., this
- // can mess up buttons that need a tooltip).
- 'aria-describedby': this.id,
- })}
- {!isVisible && <TooltipPortal>{this.renderOverlay()}</TooltipPortal>}
- {isVisible && (
- <EscKeydownHandler onKeydown={this.closeTooltip}>
- <TooltipPortal>
- <ScreenPositionFixer ready={isMeasured(this.state)}>
- {this.renderActual}
- </ScreenPositionFixer>
- </TooltipPortal>
- </EscKeydownHandler>
- )}
- </>
- );
- }
-}
-
-class TooltipPortal extends React.Component<React.PropsWithChildren<{}>> {
- el: HTMLElement;
-
- constructor(props: {}) {
- super(props);
- this.el = document.createElement('div');
- }
-
- componentDidMount() {
- document.body.appendChild(this.el);
- }
-
- componentWillUnmount() {
- document.body.removeChild(this.el);
- }
-
- render() {
- return createPortal(this.props.children, this.el);
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/UpDownKeyboardHandler.tsx b/server/sonar-web/src/main/js/components/controls/UpDownKeyboardHandler.tsx
deleted file mode 100644
index b833c14c39e..00000000000
--- a/server/sonar-web/src/main/js/components/controls/UpDownKeyboardHandler.tsx
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { isShortcut, isTextarea } from '../../helpers/keyboardEventHelpers';
-import { KeyboardKeys } from '../../helpers/keycodes';
-
-interface Props {
- containerClass?: string;
-}
-
-interface State {
- focusIndex?: number;
-}
-
-export default class UpDownKeyboardHanlder extends React.PureComponent<
- React.PropsWithChildren<Props>,
- State
-> {
- constructor(props: React.PropsWithChildren<Props>) {
- super(props);
- this.state = {};
- }
-
- componentDidMount() {
- document.addEventListener('keydown', this.handleKeyboard, true);
- }
-
- componentWillUnmount() {
- document.removeEventListener('keydown', this.handleKeyboard, true);
- }
-
- handleKeyboard = (event: KeyboardEvent) => {
- if (isShortcut(event) || isTextarea(event)) {
- return true;
- }
- switch (event.key) {
- case KeyboardKeys.DownArrow:
- event.stopPropagation();
- event.preventDefault();
- this.selectNextFocusElement();
- return false;
- case KeyboardKeys.UpArrow:
- event.stopPropagation();
- event.preventDefault();
- this.selectPreviousFocusElement();
- return false;
- }
- return true;
- };
-
- getFocusableElement() {
- const { containerClass = 'popup' } = this.props;
- const focussableElements = `.${containerClass} a,.${containerClass} button,.${containerClass} input[type=text],.${containerClass} textarea`;
- return document.querySelectorAll<HTMLElement>(focussableElements);
- }
-
- selectNextFocusElement() {
- const { focusIndex = -1 } = this.state;
- const focusableElement = this.getFocusableElement();
-
- for (const [index, focusable] of focusableElement.entries()) {
- if (focusable === document.activeElement) {
- focusableElement[(index + 1) % focusableElement.length].focus();
- this.setState({ focusIndex: (index + 1) % focusableElement.length });
- return;
- }
- }
-
- if (focusableElement[(focusIndex + 1) % focusableElement.length]) {
- focusableElement[(focusIndex + 1) % focusableElement.length].focus();
- this.setState({ focusIndex: (focusIndex + 1) % focusableElement.length });
- }
- }
-
- selectPreviousFocusElement() {
- const { focusIndex = 0 } = this.state;
- const focusableElement = this.getFocusableElement();
-
- for (const [index, focusable] of focusableElement.entries()) {
- if (focusable === document.activeElement) {
- focusableElement[(index - 1 + focusableElement.length) % focusableElement.length].focus();
- this.setState({
- focusIndex: (index - 1 + focusableElement.length) % focusableElement.length,
- });
- return;
- }
- }
-
- if (focusableElement[(focusIndex - 1 + focusableElement.length) % focusableElement.length]) {
- focusableElement[
- (focusIndex - 1 + focusableElement.length) % focusableElement.length
- ].focus();
- this.setState({
- focusIndex: (focusIndex - 1 + focusableElement.length) % focusableElement.length,
- });
- }
- }
-
- render() {
- return this.props.children;
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/ValidationForm.tsx b/server/sonar-web/src/main/js/components/controls/ValidationForm.tsx
deleted file mode 100644
index 219bace86bc..00000000000
--- a/server/sonar-web/src/main/js/components/controls/ValidationForm.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Formik, FormikHelpers, FormikProps, FormikValues } from 'formik';
-import * as React from 'react';
-
-export type ChildrenProps<V> = Omit<FormikProps<V>, 'handleSubmit'>;
-
-interface Props<V extends FormikValues> {
- children: (props: ChildrenProps<V>) => React.ReactNode;
- initialValues: V;
- onSubmit: (data: V) => Promise<void>;
- validate: (data: V) => { [P in keyof V]?: string } | Promise<{ [P in keyof V]?: string }>;
-}
-
-export default class ValidationForm<V extends FormikValues> extends React.Component<Props<V>> {
- mounted = false;
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- handleSubmit = (data: V, { setSubmitting }: FormikHelpers<V>) => {
- const stopSubmitting = () => {
- if (this.mounted) {
- setSubmitting(false);
- }
- };
-
- this.props.onSubmit(data).then(stopSubmitting, stopSubmitting);
- };
-
- render() {
- return (
- <Formik<V>
- initialValues={this.props.initialValues}
- onSubmit={this.handleSubmit}
- validate={this.props.validate}
- validateOnMount
- >
- {({ handleSubmit, ...props }) => (
- <form onSubmit={handleSubmit}>{this.props.children(props)}</form>
- )}
- </Formik>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/ValidationModal.tsx b/server/sonar-web/src/main/js/components/controls/ValidationModal.tsx
deleted file mode 100644
index 6570cf46729..00000000000
--- a/server/sonar-web/src/main/js/components/controls/ValidationModal.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, ButtonVariety } from '@sonarsource/echoes-react';
-import { FormikValues } from 'formik';
-import * as React from 'react';
-import { Modal } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import ValidationForm, { ChildrenProps } from './ValidationForm';
-
-interface Props<V> {
- children: (props: ChildrenProps<V>) => React.ReactNode;
- confirmButtonText: string;
- header: string;
- initialValues: V;
- onClose: () => void;
- onSubmit: (data: V) => Promise<void>;
- validate: (data: V) => { [P in keyof V]?: string };
-}
-
-export default class ValidationModal<V extends FormikValues> extends React.PureComponent<Props<V>> {
- handleSubmit = (data: V) => {
- return this.props.onSubmit(data).then(() => {
- this.props.onClose();
- });
- };
-
- render() {
- return (
- <Modal onClose={this.props.onClose}>
- <ValidationForm
- initialValues={this.props.initialValues}
- onSubmit={this.handleSubmit}
- validate={this.props.validate}
- >
- {(formState) => (
- <>
- <Modal.Header title={this.props.header} />
- <div className="sw-py-4">{this.props.children(formState)}</div>
- <Modal.Footer
- loading={formState.isSubmitting}
- primaryButton={
- <Button
- type="submit"
- isDisabled={formState.isSubmitting || !formState.isValid || !formState.dirty}
- variety={ButtonVariety.Primary}
- >
- {this.props.confirmButtonText}
- </Button>
- }
- secondaryButton={
- <Button
- className="sw-ml-2"
- isDisabled={formState.isSubmitting}
- onClick={this.props.onClose}
- >
- {translate('cancel')}
- </Button>
- }
- />
- </>
- )}
- </ValidationForm>
- </Modal>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/ComponentReportActions-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/ComponentReportActions-test.tsx
deleted file mode 100644
index 90e2a375dd1..00000000000
--- a/server/sonar-web/src/main/js/components/controls/__tests__/ComponentReportActions-test.tsx
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen, waitFor } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { addGlobalSuccessMessage } from '~design-system';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import {
- getReportStatus,
- subscribeToEmailReport,
- unsubscribeFromEmailReport,
-} from '../../../api/component-report';
-import { mockBranch } from '../../../helpers/mocks/branch-like';
-import { mockComponent } from '../../../helpers/mocks/component';
-import { mockComponentReportStatus } from '../../../helpers/mocks/component-report';
-import { mockAppState, mockCurrentUser, mockLoggedInUser } from '../../../helpers/testMocks';
-import { renderApp } from '../../../helpers/testReactTestingUtils';
-import { ComponentReportActions } from '../ComponentReportActions';
-
-jest.mock('~design-system', () => ({
- ...jest.requireActual('~design-system'),
- addGlobalSuccessMessage: jest.fn(),
-}));
-
-jest.mock('../../../api/component-report', () => ({
- ...jest.requireActual('../../../api/component-report'),
- getReportStatus: jest
- .fn()
- .mockResolvedValue(
- jest.requireActual('../../../helpers/mocks/component-report').mockComponentReportStatus(),
- ),
- subscribeToEmailReport: jest.fn().mockResolvedValue(undefined),
- unsubscribeFromEmailReport: jest.fn().mockResolvedValue(undefined),
-}));
-
-jest.mock('../../../helpers/system', () => ({
- ...jest.requireActual('../../../helpers/system'),
- getBaseUrl: jest.fn().mockReturnValue('baseUrl'),
-}));
-
-beforeEach(jest.clearAllMocks);
-
-it('should not render anything when no status', async () => {
- jest.mocked(getReportStatus).mockRejectedValueOnce('Nope');
-
- renderComponentReportActions();
-
- // Loading
- expect(screen.queryByRole('button')).not.toBeInTheDocument();
-
- await waitFor(() => expect(getReportStatus).toHaveBeenCalled());
-
- // No status
- expect(screen.queryByRole('button')).not.toBeInTheDocument();
-});
-
-it('should not render anything when branch is purgeable', async () => {
- renderComponentReportActions({
- branch: mockBranch({ excludedFromPurge: false }),
- });
-
- await waitFor(() => expect(getReportStatus).toHaveBeenCalled());
-
- expect(screen.queryByRole('button')).not.toBeInTheDocument();
-});
-
-it('should not render anything without governance', () => {
- renderComponentReportActions({ appState: mockAppState({ qualifiers: [] }) });
-
- expect(getReportStatus).not.toHaveBeenCalled();
-
- expect(screen.queryByRole('button')).not.toBeInTheDocument();
-});
-
-it('should allow user to (un)subscribe', async () => {
- jest
- .mocked(getReportStatus)
- .mockResolvedValueOnce(mockComponentReportStatus({ globalFrequency: 'monthly' }))
- .mockResolvedValueOnce(
- mockComponentReportStatus({ subscribed: true, globalFrequency: 'monthly' }),
- );
-
- const user = userEvent.setup();
- const component = mockComponent();
- const branch = mockBranch();
-
- renderComponentReportActions({
- component,
- branch,
- currentUser: mockLoggedInUser({ email: 'igot@nEmail.address' }),
- });
-
- expect(getReportStatus).toHaveBeenCalledWith(component.key, branch.name);
-
- const button = await screen.findByRole('button', {
- name: 'component_report.report.qualifier.TRK',
- });
- expect(button).toBeInTheDocument();
- await user.click(button);
-
- expect(screen.getByText('download_verb')).toBeInTheDocument();
-
- // Subscribe!
- const subscribeButton = screen.getByText('component_report.subscribe_x.report.frequency.monthly');
- expect(subscribeButton).toBeInTheDocument();
-
- await user.click(subscribeButton);
-
- expect(subscribeToEmailReport).toHaveBeenCalledWith(component.key, branch.name);
- expect(addGlobalSuccessMessage).toHaveBeenLastCalledWith(
- 'component_report.subscribe_x_success.report.frequency.monthly.qualifier.trk',
- );
-
- // And unsubscribe!
- await user.click(button);
-
- const unsubscribeButton = screen.getByText(
- 'component_report.unsubscribe_x.report.frequency.monthly',
- );
- expect(unsubscribeButton).toBeInTheDocument();
-
- await user.click(unsubscribeButton);
-
- expect(unsubscribeFromEmailReport).toHaveBeenCalledWith(component.key, branch.name);
- expect(addGlobalSuccessMessage).toHaveBeenLastCalledWith(
- 'component_report.unsubscribe_x_success.report.frequency.monthly.qualifier.trk',
- );
-});
-
-it('should prevent user to subscribe if no email', async () => {
- const user = userEvent.setup();
-
- renderComponentReportActions({ currentUser: mockLoggedInUser({ email: undefined }) });
-
- await user.click(
- await screen.findByRole('button', {
- name: 'component_report.report.qualifier.TRK',
- }),
- );
-
- const subscribeButton = screen.getByText('component_report.no_email_to_subscribe');
- expect(subscribeButton).toBeInTheDocument();
- expect(subscribeButton).toBeDisabled();
-});
-
-function renderComponentReportActions(props: Partial<ComponentReportActions['props']> = {}) {
- return renderApp(
- '/',
- <ComponentReportActions
- appState={mockAppState({ qualifiers: [ComponentQualifier.Portfolio] })}
- component={mockComponent()}
- currentUser={mockCurrentUser()}
- {...props}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/Favorite-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/Favorite-test.tsx
deleted file mode 100644
index a1889a3374d..00000000000
--- a/server/sonar-web/src/main/js/components/controls/__tests__/Favorite-test.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { setImmediate } from 'timers';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { addFavorite, removeFavorite } from '../../../api/favorites';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { FCProps } from '../../../types/misc';
-import Favorite from '../Favorite';
-
-jest.mock('../../../api/favorites', () => ({
- addFavorite: jest.fn().mockResolvedValue(null),
- removeFavorite: jest.fn().mockResolvedValue(null),
-}));
-
-it('renders and behaves correctly', async () => {
- const user = userEvent.setup();
- renderFavorite({ favorite: false });
- let button = screen.getByRole('button');
- expect(button).toBeInTheDocument();
-
- await user.click(button);
- await new Promise(setImmediate);
- expect(addFavorite).toHaveBeenCalled();
-
- button = screen.getByRole('button');
- expect(button).toBeInTheDocument();
- expect(button).toHaveFocus();
-
- await user.click(button);
- await new Promise(setImmediate);
- expect(removeFavorite).toHaveBeenCalled();
-
- button = screen.getByRole('button');
- expect(button).toBeInTheDocument();
- expect(button).toHaveFocus();
-});
-
-it('correctly calls handleFavorite if passed', async () => {
- const handleFavorite = jest.fn();
- const user = userEvent.setup();
- renderFavorite({ handleFavorite });
-
- await user.click(screen.getByRole('button'));
- expect(handleFavorite).toHaveBeenCalledWith('foo', false);
-
- await user.click(screen.getByRole('button'));
- expect(handleFavorite).toHaveBeenCalledWith('foo', true);
-});
-
-function renderFavorite(props: Partial<FCProps<typeof Favorite>> = {}) {
- return renderComponent(
- <Favorite component="foo" favorite qualifier={ComponentQualifier.Project} {...props} />,
- );
-}
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx
deleted file mode 100644
index e184dbef93e..00000000000
--- a/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { setImmediate } from 'timers';
-import { setHomePage } from '../../../api/users';
-import { mockLoggedInUser } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { FCProps } from '../../../types/misc';
-import { DEFAULT_HOMEPAGE, HomePageSelect } from '../HomePageSelect';
-
-jest.mock('../../../api/users', () => ({
- setHomePage: jest.fn().mockResolvedValue(null),
-}));
-
-it('renders and behaves correctly', async () => {
- const user = userEvent.setup();
- const updateCurrentUserHomepage = jest.fn();
- renderHomePageSelect({ updateCurrentUserHomepage });
- const button = screen.getByRole('button');
- expect(button).toBeInTheDocument();
-
- await user.click(button);
- await new Promise(setImmediate);
- expect(setHomePage).toHaveBeenCalledWith({ type: 'MY_PROJECTS' });
- expect(updateCurrentUserHomepage).toHaveBeenCalled();
- expect(button).toHaveFocus();
-});
-
-it('renders correctly if user is on the homepage', async () => {
- const user = userEvent.setup();
-
- renderHomePageSelect({ currentUser: mockLoggedInUser({ homepage: { type: 'MY_PROJECTS' } }) });
- const button = screen.getByRole('button');
- expect(button).toBeInTheDocument();
-
- await user.click(button);
- await new Promise(setImmediate);
- expect(setHomePage).toHaveBeenCalledWith(DEFAULT_HOMEPAGE);
- expect(button).toHaveFocus();
-});
-
-function renderHomePageSelect(props: Partial<FCProps<typeof HomePageSelect>> = {}) {
- return renderComponent(
- <HomePageSelect
- currentPage={{ type: 'MY_PROJECTS' }}
- currentUser={mockLoggedInUser()}
- updateCurrentUserHomepage={jest.fn()}
- {...props}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx
deleted file mode 100644
index 26d426ffddb..00000000000
--- a/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import ListFooter, { ListFooterProps } from '../ListFooter';
-
-describe('ListFooter', () => {
- describe('rendering', () => {
- it('should render correctly when loading', async () => {
- renderListFooter({ loading: true });
- expect(await screen.findByText('loading')).toBeInTheDocument();
- });
-
- it('should not render if there are neither loadmore nor reload props', () => {
- renderListFooter({ loadMore: undefined, reload: undefined });
- expect(screen.queryByRole('button')).not.toBeInTheDocument();
- });
-
- it.each([
- [undefined, 60, 30, true],
- [undefined, 45, 30, false],
- [undefined, 60, undefined, false],
- [60, 60, 30, false],
- ])(
- 'should handle showing load more button based on total, count and pageSize',
- (total, count, pageSize, expected) => {
- renderListFooter({ total, count, pageSize });
-
- /* eslint-disable jest/no-conditional-in-test */
- /* eslint-disable jest/no-conditional-expect */
- if (expected) {
- expect(screen.getByRole('button')).toBeInTheDocument();
- } else {
- expect(screen.queryByRole('button')).not.toBeInTheDocument();
- }
- /* eslint-enable jest/no-conditional-in-test */
- /* eslint-enable jest/no-conditional-expect */
- },
- );
- });
-
- it('should properly call load more callback', async () => {
- const user = userEvent.setup();
- const loadMore = jest.fn();
- renderListFooter({ loadMore });
-
- await user.click(screen.getByRole('button'));
- expect(loadMore).toHaveBeenCalled();
- });
-
- it('should properly call reload callback', async () => {
- const user = userEvent.setup();
- const reload = jest.fn();
- renderListFooter({ needReload: true, reload });
-
- await user.click(screen.getByRole('button'));
- expect(reload).toHaveBeenCalled();
- });
-
- function renderListFooter(props: Partial<ListFooterProps> = {}) {
- return renderComponent(<ListFooter count={3} loadMore={jest.fn()} total={5} {...props} />);
- }
-});
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/SelectList-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/SelectList-test.tsx
deleted file mode 100644
index 178a17959db..00000000000
--- a/server/sonar-web/src/main/js/components/controls/__tests__/SelectList-test.tsx
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import SelectList, { SelectListFilter } from '../SelectList';
-
-const elements = ['foo', 'bar', 'baz'];
-const selectedElements = [elements[0]];
-const disabledElements = [elements[1]];
-
-it('should render with extra', () => {
- renderSelectList({ renderElement: (element) => [element, 'with extra'] });
-
- expect(byText('with extra').getAll()).toHaveLength(3);
-});
-
-it('should cancel filter selection when search is active', async () => {
- const user = userEvent.setup();
-
- const spy = jest.fn().mockResolvedValue({});
- renderSelectList({ onSearch: spy });
-
- await user.click(ui.filterToggle(SelectListFilter.Unselected).get());
-
- expect(spy).toHaveBeenCalledWith({
- query: '',
- filter: SelectListFilter.Unselected,
- page: undefined,
- pageSize: undefined,
- });
-
- const query = 'test';
-
- await user.type(ui.searchInput.get(), query);
-
- expect(spy).toHaveBeenCalledWith({
- query,
- filter: SelectListFilter.All,
- page: undefined,
- pageSize: undefined,
- });
-
- await user.clear(ui.searchInput.get());
-
- expect(spy).toHaveBeenCalledWith({
- query: '',
- filter: SelectListFilter.Unselected,
- page: undefined,
- pageSize: undefined,
- });
-});
-
-it('should display pagination element properly and call search method with correct parameters', async () => {
- const user = userEvent.setup();
- const spy = jest.fn().mockResolvedValue({});
- renderSelectList({
- elementsTotalCount: 100,
- onSearch: spy,
- withPaging: true,
- });
- expect(spy).toHaveBeenCalledWith({
- query: '',
- filter: SelectListFilter.Selected,
- page: 1,
- pageSize: 100,
- }); // Basic default call
-
- await user.click(ui.footerLoadMore.get());
-
- expect(spy).toHaveBeenCalledWith({
- query: '',
- filter: SelectListFilter.Selected,
- page: 2,
- pageSize: 100,
- }); // Load more call
-});
-
-it('should allow to reload when needed', async () => {
- const user = userEvent.setup();
- const spy = jest.fn().mockResolvedValue({});
-
- renderSelectList({
- elementsTotalCount: 100,
- onSearch: spy,
- needToReload: true,
- withPaging: true,
- });
-
- expect(spy).toHaveBeenCalledWith({
- query: '',
- filter: SelectListFilter.Selected,
- page: 1,
- pageSize: 100,
- }); // Basic default call
-
- await user.click(await ui.footerReload.find());
-
- expect(spy).toHaveBeenCalledWith({
- query: '',
- filter: SelectListFilter.Selected,
- page: 1,
- pageSize: 100,
- }); // Reload call
-});
-
-function renderSelectList(props: Partial<SelectList['props']> = {}) {
- return renderComponent(
- <SelectList
- disabledElements={disabledElements}
- elements={elements}
- onSearch={jest.fn()}
- onSelect={jest.fn(() => Promise.resolve())}
- onUnselect={jest.fn(() => Promise.resolve())}
- renderElement={(foo: string) => foo}
- selectedElements={selectedElements}
- loading={false}
- {...props}
- />,
- );
-}
-
-const ui = {
- filterToggle: (filter: SelectListFilter) =>
- byRole('radio', { name: filter === SelectListFilter.Unselected ? 'unselected' : filter }),
-
- searchInput: byRole('searchbox', { name: 'search_verb' }),
-
- footerLoadMore: byRole('button', { name: 'show_more' }),
- footerReload: byRole('button', { name: 'reload' }),
-};
diff --git a/server/sonar-web/src/main/js/components/devops-platform/AlmSettingsInstanceSelector.tsx b/server/sonar-web/src/main/js/components/devops-platform/AlmSettingsInstanceSelector.tsx
deleted file mode 100644
index dd4e9013639..00000000000
--- a/server/sonar-web/src/main/js/components/devops-platform/AlmSettingsInstanceSelector.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { OptionProps, SingleValueProps, components } from 'react-select';
-import { InputSelect, LabelValueSelectOption, Note } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { AlmInstanceBase } from '../../types/alm-settings';
-
-function optionRenderer(props: OptionProps<LabelValueSelectOption<AlmInstanceBase>, false>) {
- // For tests and a11y
- props.innerProps.role = 'option';
- props.innerProps['aria-selected'] = props.isSelected;
-
- return <components.Option {...props}>{customOptions(props.data.value)}</components.Option>;
-}
-
-function singleValueRenderer(
- props: SingleValueProps<LabelValueSelectOption<AlmInstanceBase>, false>,
-) {
- return (
- <components.SingleValue {...props}>{customOptions(props.data.value)}</components.SingleValue>
- );
-}
-
-function customOptions(instance: AlmInstanceBase) {
- return instance.url ? (
- <>
- <span>{instance.key} — </span>
- <Note>{instance.url}</Note>
- </>
- ) : (
- <span>{instance.key}</span>
- );
-}
-
-function orgToOption(alm: AlmInstanceBase) {
- return { value: alm, label: alm.key };
-}
-
-interface Props {
- className: string;
- initialValue?: string;
- inputId: string;
- instances: AlmInstanceBase[];
- onChange: (instance: AlmInstanceBase) => void;
-}
-
-export default function AlmSettingsInstanceSelector(props: Props) {
- const { instances, initialValue, className, inputId } = props;
-
- return (
- <InputSelect
- inputId={inputId}
- className={className}
- isClearable={false}
- isSearchable={false}
- options={instances.map(orgToOption)}
- onChange={(data: LabelValueSelectOption<AlmInstanceBase>) => {
- props.onChange(data.value);
- }}
- components={{
- Option: optionRenderer,
- SingleValue: singleValueRenderer,
- }}
- placeholder={translate('alm.configuration.selector.placeholder')}
- getOptionValue={(opt: LabelValueSelectOption<AlmInstanceBase>) => opt.value.key}
- value={instances.map(orgToOption).find((opt) => opt.value.key === initialValue) ?? null}
- size="full"
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/DocItemLink.tsx b/server/sonar-web/src/main/js/components/embed-docs-modal/DocItemLink.tsx
deleted file mode 100644
index 7e795522211..00000000000
--- a/server/sonar-web/src/main/js/components/embed-docs-modal/DocItemLink.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { DropdownMenu } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { DocLink } from '../../helpers/doc-links';
-import { useDocUrl } from '../../helpers/docs';
-
-interface Props {
- children: React.ReactNode;
- to: DocLink;
-}
-
-export function DocItemLink({ to, children }: Readonly<Props>) {
- const toStatic = useDocUrl(to);
-
- return <DropdownMenu.ItemLink to={toStatic}>{children}</DropdownMenu.ItemLink>;
-}
diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx b/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx
deleted file mode 100644
index c131bb452fe..00000000000
--- a/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { DropdownMenu, IconSlideshow } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { HighlightRing } from '~design-system';
-import { useCurrentUser } from '../../app/components/current-user/CurrentUserContext';
-import { CustomEvents } from '../../helpers/constants';
-import { DocLink } from '../../helpers/doc-links';
-import { translate } from '../../helpers/l10n';
-import { Permissions } from '../../types/permissions';
-import { SuggestionLink } from '../../types/types';
-import { DocItemLink } from './DocItemLink';
-import { SuggestionsContext } from './SuggestionsContext';
-
-function Suggestions({ suggestions }: Readonly<{ suggestions: SuggestionLink[] }>) {
- return (
- <>
- <DropdownMenu.GroupLabel>{translate('docs.suggestion')}</DropdownMenu.GroupLabel>
-
- {suggestions.map((suggestion) => (
- <DocItemLink key={suggestion.link} to={suggestion.link}>
- {suggestion.text}
- </DocItemLink>
- ))}
-
- <DropdownMenu.Separator />
- </>
- );
-}
-
-export function EmbedDocsPopup() {
- const firstItemRef = React.useRef<HTMLAnchorElement>(null);
- const { currentUser } = useCurrentUser();
- const { suggestions } = React.useContext(SuggestionsContext);
-
- React.useEffect(() => {
- firstItemRef.current?.focus();
- }, []);
-
- const runModeTour = () => {
- document.dispatchEvent(new CustomEvent(CustomEvents.RunTourMode));
- };
-
- const isAdminOrQGAdmin =
- currentUser.permissions?.global.includes(Permissions.Admin) ||
- currentUser.permissions?.global.includes(Permissions.QualityGateAdmin);
-
- return (
- <>
- {suggestions.length !== 0 && <Suggestions suggestions={suggestions} />}
-
- <DocItemLink to={DocLink.Root}>{translate('docs.documentation')}</DocItemLink>
-
- <DropdownMenu.ItemLink to="/web_api">
- {translate('api_documentation.page')}
- </DropdownMenu.ItemLink>
-
- <DropdownMenu.ItemLink to="/web_api_v2">
- {translate('api_documentation.page.v2')}
- </DropdownMenu.ItemLink>
-
- <DropdownMenu.Separator />
-
- <DropdownMenu.ItemLink to="https://community.sonarsource.com/">
- {translate('docs.get_help')}
- </DropdownMenu.ItemLink>
-
- <DropdownMenu.Separator />
-
- <DropdownMenu.GroupLabel>{translate('docs.stay_connected')}</DropdownMenu.GroupLabel>
-
- <DropdownMenu.ItemLink to="https://www.sonarsource.com/products/sonarqube/whats-new/?referrer=sonarqube">
- {translate('docs.news')}
- </DropdownMenu.ItemLink>
-
- <DropdownMenu.ItemLink to="https://www.sonarsource.com/products/sonarqube/roadmap/?referrer=sonarqube">
- {translate('docs.roadmap')}
- </DropdownMenu.ItemLink>
-
- <DropdownMenu.ItemLink to="https://twitter.com/SonarQube">X @SonarQube</DropdownMenu.ItemLink>
-
- {isAdminOrQGAdmin && (
- <>
- <DropdownMenu.Separator />
-
- <DropdownMenu.GroupLabel>{translate('tours')}</DropdownMenu.GroupLabel>
-
- <HighlightRing data-guiding-id="mode-tour-2">
- <DropdownMenu.ItemButton prefix={<IconSlideshow />} onClick={runModeTour}>
- {translate('mode_tour.name')}
- </DropdownMenu.ItemButton>
- </HighlightRing>
- </>
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopupHelper.tsx b/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopupHelper.tsx
deleted file mode 100644
index 0e8066ddff2..00000000000
--- a/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopupHelper.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- ButtonIcon,
- ButtonVariety,
- DropdownMenu,
- DropdownMenuAlign,
- IconQuestionMark,
-} from '@sonarsource/echoes-react';
-import { useCallback, useEffect, useState } from 'react';
-import { CustomEvents } from '../../helpers/constants';
-import { translate } from '../../helpers/l10n';
-import { EmbedDocsPopup } from './EmbedDocsPopup';
-
-export default function EmbedDocsPopupHelper() {
- const [open, setOpen] = useState(false);
-
- useEffect(() => {
- const openListener = () => setOpen(true);
- const closeListener = () => setOpen(false);
- document.addEventListener(CustomEvents.OpenHelpMenu, openListener);
- document.addEventListener(CustomEvents.CloseHelpMenu, closeListener);
- return () => {
- document.removeEventListener(CustomEvents.OpenHelpMenu, openListener);
- document.addEventListener(CustomEvents.CloseHelpMenu, closeListener);
- };
- }, []);
-
- const handleClose = useCallback(() => {
- setOpen(false);
- document.dispatchEvent(new CustomEvent(CustomEvents.HelpMenuClosed));
- }, []);
-
- return (
- <div className="dropdown">
- <DropdownMenu.Root
- align={DropdownMenuAlign.End}
- id="help-menu-dropdown"
- isOpen={open}
- onOpen={() => setOpen(true)}
- onClose={handleClose}
- items={<EmbedDocsPopup />}
- >
- <ButtonIcon
- Icon={IconQuestionMark}
- data-guiding-id="issue-5"
- ariaLabel={translate('help')}
- isIconFilled
- variety={ButtonVariety.DefaultGhost}
- />
- </DropdownMenu.Root>
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/Suggestions.tsx b/server/sonar-web/src/main/js/components/embed-docs-modal/Suggestions.tsx
deleted file mode 100644
index 7a02556e3b9..00000000000
--- a/server/sonar-web/src/main/js/components/embed-docs-modal/Suggestions.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { DocSection, DocSectionKey, DocTitleKey } from '../../helpers/doc-links';
-import { isDefined } from '../../helpers/types';
-import { SuggestionsContext, SuggestionsContextShape } from './SuggestionsContext';
-
-type Props =
- | {
- suggestion: DocTitleKey;
- suggestionGroup?: never;
- }
- | {
- suggestion?: never;
- suggestionGroup: DocSectionKey;
- };
-
-export default function Suggestions({ suggestion, suggestionGroup }: Readonly<Props>) {
- return (
- <SuggestionsContext.Consumer>
- {({ addSuggestions, removeSuggestions }) => (
- <SuggestionsInner
- addSuggestions={addSuggestions}
- removeSuggestions={removeSuggestions}
- suggestion={suggestion}
- suggestionGroup={suggestionGroup}
- />
- )}
- </SuggestionsContext.Consumer>
- );
-}
-
-interface SuggestionsInnerProps {
- addSuggestions: SuggestionsContextShape['addSuggestions'];
- removeSuggestions: SuggestionsContextShape['removeSuggestions'];
- suggestion: Props['suggestion'];
- suggestionGroup: Props['suggestionGroup'];
-}
-
-class SuggestionsInner extends React.PureComponent<SuggestionsInnerProps> {
- componentDidMount() {
- this.props.addSuggestions(this.getSuggestionListFromProps());
- }
-
- componentWillUnmount() {
- this.props.removeSuggestions(this.getSuggestionListFromProps());
- }
-
- getSuggestionListFromProps() {
- const { suggestion, suggestionGroup } = this.props;
-
- const suggestions: DocTitleKey[] = isDefined(suggestion) ? [suggestion] : [];
-
- if (suggestionGroup) {
- suggestions.push(...DocSection[suggestionGroup]);
- }
-
- return suggestions;
- }
-
- render() {
- return null;
- }
-}
diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsContext.ts b/server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsContext.ts
deleted file mode 100644
index d71d4cef5c9..00000000000
--- a/server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsContext.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { createContext } from 'react';
-import { DocTitleKey } from '../../helpers/doc-links';
-import { SuggestionLink } from '../../types/types';
-
-export interface SuggestionsContextShape {
- addSuggestions: (keys: DocTitleKey[]) => void;
- removeSuggestions: (keys: DocTitleKey[]) => void;
- suggestions: SuggestionLink[];
-}
-
-export const SuggestionsContext = createContext<SuggestionsContextShape>({
- addSuggestions: () => {
- /* Implemented by Provider */
- },
- removeSuggestions: () => {
- /* Implemented by Provider */
- },
- suggestions: [],
-});
diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsProvider.tsx b/server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsProvider.tsx
deleted file mode 100644
index c0d680938c7..00000000000
--- a/server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsProvider.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { DocTitle, DocTitleKey } from '../../helpers/doc-links';
-import { SuggestionLink } from '../../types/types';
-import { SuggestionsContext } from './SuggestionsContext';
-
-interface State {
- suggestions: SuggestionLink[];
-}
-
-export default class SuggestionsProvider extends React.Component<React.PropsWithChildren, State> {
- keys: Array<DocTitleKey> = [];
- state: State = { suggestions: [] };
-
- fetchSuggestions = () => {
- let suggestions: SuggestionLink[] = [];
-
- this.keys.forEach((key) => {
- suggestions = [{ link: key, text: DocTitle[key] }, ...suggestions];
- });
-
- this.setState({ suggestions });
- };
-
- addSuggestions = (newKeys: DocTitleKey[]) => {
- newKeys.forEach((newKey) => {
- if (!this.keys.includes(newKey)) {
- this.keys = [...this.keys, newKey];
- }
- });
-
- this.fetchSuggestions();
- };
-
- removeSuggestions = (oldKeys: DocTitleKey[]) => {
- oldKeys.forEach((oldKey) => {
- this.keys = this.keys.filter((key) => key !== oldKey);
- });
-
- this.fetchSuggestions();
- };
-
- render() {
- return (
- <SuggestionsContext.Provider
- value={{
- addSuggestions: this.addSuggestions,
- removeSuggestions: this.removeSuggestions,
- suggestions: this.state.suggestions,
- }}
- >
- {this.props.children}
- </SuggestionsContext.Provider>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx b/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx
deleted file mode 100644
index 95b64a1af0e..00000000000
--- a/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import * as React from 'react';
-import { DocLink, DocTitleKey } from '../../../helpers/doc-links';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import EmbedDocsPopupHelper from '../EmbedDocsPopupHelper';
-import Suggestions from '../Suggestions';
-import SuggestionsProvider from '../SuggestionsProvider';
-
-it('should render with no suggestions', async () => {
- const user = userEvent.setup();
- renderEmbedDocsPopup();
-
- await user.click(screen.getByRole('button', { name: 'help' }));
-
- expect(screen.getByText('docs.documentation')).toBeInTheDocument();
- expect(screen.queryByText('docs.suggestion')).not.toBeInTheDocument();
-});
-
-it('should be able to render with suggestions and remove them', async () => {
- const user = userEvent.setup();
- renderEmbedDocsPopup();
-
- await user.click(screen.getByRole('button', { name: 'help' }));
- await user.click(screen.getByRole('button', { name: 'add.suggestion' }));
-
- await user.click(screen.getByRole('button', { name: 'help' }));
-
- expect(screen.getByText('docs.suggestion')).toBeInTheDocument();
- expect(screen.getByText('About Background Tasks')).toBeInTheDocument();
-
- await user.click(screen.getByRole('button', { name: 'remove.suggestion' }));
- await user.click(screen.getByRole('button', { name: 'help' }));
- expect(screen.queryByText('docs.suggestion')).not.toBeInTheDocument();
-});
-
-function renderEmbedDocsPopup() {
- function Test() {
- const [suggestions, setSuggestions] = React.useState<DocTitleKey[]>([]);
-
- const addSuggestion = () => {
- setSuggestions([...suggestions, DocLink.BackgroundTasks]);
- };
-
- return (
- <SuggestionsProvider>
- <button onClick={addSuggestion} type="button">
- add.suggestion
- </button>
- <button
- onClick={() => {
- setSuggestions([]);
- }}
- type="button"
- >
- remove.suggestion
- </button>
- <EmbedDocsPopupHelper />
- {suggestions.map((suggestion) => (
- <Suggestions key={suggestion} suggestion={suggestion} />
- ))}
- </SuggestionsProvider>
- );
- }
-
- return renderComponent(<Test />);
-}
diff --git a/server/sonar-web/src/main/js/components/facets/Facet.tsx b/server/sonar-web/src/main/js/components/facets/Facet.tsx
deleted file mode 100644
index f29cbaf70d5..00000000000
--- a/server/sonar-web/src/main/js/components/facets/Facet.tsx
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { orderBy, sortBy, without } from 'lodash';
-import * as React from 'react';
-import { FacetBox, FacetItem } from '~design-system';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import { FacetKey } from '../../apps/coding-rules/query';
-import { FacetItemsList } from '../../apps/issues/sidebar/FacetItemsList';
-import { MultipleSelectionHint } from '../../apps/issues/sidebar/MultipleSelectionHint';
-import { translate } from '../../helpers/l10n';
-import { Dict } from '../../types/types';
-import Tooltip from '../controls/Tooltip';
-
-export interface BasicProps {
- fetching?: boolean;
- help?: React.ReactNode;
- onChange: (changes: Dict<string | string[] | undefined>) => void;
- onToggle: (facet: FacetKey) => void;
- open: boolean;
- secondLine?: string;
- stats?: Dict<number>;
- values: string[];
-}
-
-interface Props extends BasicProps {
- disabled?: boolean;
- disabledHelper?: string;
- headerName?: string;
- options?: string[];
- property: FacetKey;
- renderFooter?: () => React.ReactNode;
- renderName?: (value: string, disabled: boolean) => React.ReactNode;
- renderTextName?: (value: string) => string;
- singleSelection?: boolean;
-}
-
-export default class Facet extends React.PureComponent<Props> {
- handleItemClick = (itemValue: string, multiple: boolean) => {
- const { values } = this.props;
- let newValue;
- if (this.props.singleSelection) {
- const value = values.length ? values[0] : undefined;
- newValue = itemValue === value ? undefined : itemValue;
- } else if (multiple) {
- newValue = orderBy(
- values.includes(itemValue) ? without(values, itemValue) : [...values, itemValue],
- );
- } else {
- newValue = values.includes(itemValue) && values.length < 2 ? [] : [itemValue];
- }
- this.props.onChange({ [this.props.property]: newValue });
- };
-
- handleHeaderClick = () => this.props.onToggle(this.props.property);
-
- handleClear = () => this.props.onChange({ [this.props.property]: [] });
-
- getStat = (value: string) => this.props.stats && this.props.stats[value];
-
- renderItem = (value: string) => {
- const active = this.props.values.includes(value);
- const stat = this.getStat(value);
- const disabled = stat === 0 || typeof stat === 'undefined';
- const { renderName = defaultRenderName, renderTextName = defaultRenderName } = this.props;
-
- return (
- <FacetItem
- className="it__search-navigator-facet"
- active={active}
- key={value}
- name={renderName(value, disabled)}
- onClick={this.handleItemClick}
- stat={stat && formatMeasure(stat, MetricType.ShortInteger)}
- value={value}
- tooltip={renderTextName(value)}
- />
- );
- };
-
- render() {
- const {
- disabled,
- disabledHelper,
- open,
- property,
- renderTextName = defaultRenderName,
- secondLine,
- stats,
- help,
- values,
- fetching,
- headerName,
- } = this.props;
- const items =
- this.props.options ||
- (stats &&
- sortBy(
- Object.keys(stats),
- (key) => -stats[key],
- (key) => renderTextName(key).toLowerCase(),
- ));
- const headerId = `facet_${property}`;
- const nbSelectableItems =
- items?.filter((item) => (stats ? stats[item] : undefined)).length ?? 0;
- const nbSelectedItems = values.length;
-
- return (
- <FacetBox
- className={classNames('it__search-navigator-facet-box it__search-navigator-facet-header', {
- 'it__search-navigator-facet-box-forbidden': disabled,
- })}
- data-property={property}
- loading={fetching}
- count={values.length}
- id={headerId}
- name={headerName ?? translate('coding_rules.facet', property)}
- onClear={this.handleClear}
- onClick={disabled ? undefined : this.handleHeaderClick}
- open={open && !disabled}
- disabled={disabled}
- disabledHelper={disabledHelper}
- tooltipComponent={Tooltip}
- help={help}
- secondLine={secondLine}
- >
- {open && items !== undefined && (
- <FacetItemsList labelledby={headerId}>{items.map(this.renderItem)}</FacetItemsList>
- )}
-
- {open && this.props.renderFooter !== undefined && this.props.renderFooter()}
-
- <MultipleSelectionHint
- nbSelectableItems={nbSelectableItems}
- nbSelectedItems={nbSelectedItems}
- />
- </FacetBox>
- );
- }
-}
-
-function defaultRenderName(value: string) {
- return value;
-}
diff --git a/server/sonar-web/src/main/js/components/facets/FacetHelp.tsx b/server/sonar-web/src/main/js/components/facets/FacetHelp.tsx
deleted file mode 100644
index 7c7609700ef..00000000000
--- a/server/sonar-web/src/main/js/components/facets/FacetHelp.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, ButtonVariety, IconQuestionMark, Popover } from '@sonarsource/echoes-react';
-import { useIntl } from 'react-intl';
-import { DocLink } from '../../helpers/doc-links';
-import DocumentationLink from '../common/DocumentationLink';
-
-type Props =
- | {
- description?: never;
- link: DocLink;
- linkText?: never;
- noDescription?: boolean;
- property: string;
- title?: never;
- }
- | {
- description?: string | React.ReactNode;
- link: DocLink;
- linkText: string;
- noDescription?: never;
- property?: never;
- title: string;
- };
-
-export function FacetHelp({ property, title, description, noDescription, link, linkText }: Props) {
- const intl = useIntl();
- return (
- <Popover
- title={
- property !== undefined
- ? intl.formatMessage({ id: `issues.facet.${property}.help.title` })
- : title
- }
- description={
- property
- ? !noDescription &&
- intl.formatMessage(
- { id: `issues.facet.${property}.help.description` },
- { p1: (text) => <p>{text}</p>, p: (text) => <p className="sw-mt-4">{text}</p> },
- )
- : description
- }
- footer={
- <DocumentationLink shouldOpenInNewTab standalone to={link}>
- {property ? intl.formatMessage({ id: `issues.facet.${property}.help.link` }) : linkText}
- </DocumentationLink>
- }
- >
- <Button
- className="sw-p-0 sw-h-fit sw-min-h-fit"
- aria-label={intl.formatMessage({ id: 'help' })}
- variety={ButtonVariety.DefaultGhost}
- >
- <IconQuestionMark color="echoes-color-icon-subdued" />
- </Button>
- </Popover>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/facets/SeverityFacet.tsx b/server/sonar-web/src/main/js/components/facets/SeverityFacet.tsx
deleted file mode 100644
index b516cabe002..00000000000
--- a/server/sonar-web/src/main/js/components/facets/SeverityFacet.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { useIntl } from 'react-intl';
-import QGMetricsMismatchHelp from '../../apps/issues/sidebar/QGMetricsMismatchHelp';
-import { IMPACT_SEVERITIES } from '../../helpers/constants';
-import { DocLink } from '../../helpers/doc-links';
-import { translate } from '../../helpers/l10n';
-import SoftwareImpactSeverityIcon from '../icon-mappers/SoftwareImpactSeverityIcon';
-import Facet, { BasicProps } from './Facet';
-import { FacetHelp } from './FacetHelp';
-
-export default function SeverityFacet(props: Readonly<BasicProps>) {
- const intl = useIntl();
- const renderName = React.useCallback(
- (severity: string, disabled: boolean) => (
- <div className="sw-flex sw-items-center">
- <SoftwareImpactSeverityIcon severity={severity} disabled={disabled} />
- <span className="sw-ml-1">{translate('severity_impact', severity)}</span>
- </div>
- ),
- [],
- );
-
- const renderTextName = React.useCallback(
- (severity: string) => translate('severity_impact', severity),
- [],
- );
-
- return (
- <Facet
- {...props}
- options={IMPACT_SEVERITIES}
- property="impactSeverities"
- renderName={renderName}
- renderTextName={renderTextName}
- help={
- props.secondLine ? (
- <QGMetricsMismatchHelp />
- ) : (
- <FacetHelp
- title={intl.formatMessage({ id: 'severity_impact.levels' })}
- description={intl.formatMessage(
- { id: `severity_impact.help.description` },
- { p1: (text) => <p>{text}</p>, p: (text) => <p className="sw-mt-4">{text}</p> },
- )}
- link={DocLink.MQRSeverity}
- linkText={intl.formatMessage({ id: 'severity_impact.help.link' })}
- />
- )
- }
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/facets/StandardSeverityFacet.tsx b/server/sonar-web/src/main/js/components/facets/StandardSeverityFacet.tsx
deleted file mode 100644
index ce8801954ea..00000000000
--- a/server/sonar-web/src/main/js/components/facets/StandardSeverityFacet.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import QGMetricsMismatchHelp from '../../apps/issues/sidebar/QGMetricsMismatchHelp';
-import { SEVERITIES } from '../../helpers/constants';
-import { translate } from '../../helpers/l10n';
-import SoftwareImpactSeverityIcon from '../icon-mappers/SoftwareImpactSeverityIcon';
-import Facet, { BasicProps } from './Facet';
-
-export default function StandardSeverityFacet(
- props: Readonly<BasicProps & { headerName?: string }>,
-) {
- const renderName = React.useCallback(
- (severity: string, disabled: boolean) => (
- <div className="sw-flex sw-items-center">
- <SoftwareImpactSeverityIcon severity={severity} disabled={disabled} />
- <span className="sw-ml-1">{translate('severity', severity)}</span>
- </div>
- ),
- [],
- );
-
- const renderTextName = React.useCallback(
- (severity: string) => translate('severity', severity),
- [],
- );
-
- return (
- <Facet
- {...props}
- help={Boolean(props.secondLine) && <QGMetricsMismatchHelp />}
- options={SEVERITIES}
- property="severities"
- renderName={renderName}
- renderTextName={renderTextName}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/hoc/__tests__/withIndexationGuard-test.tsx b/server/sonar-web/src/main/js/components/hoc/__tests__/withIndexationGuard-test.tsx
deleted file mode 100644
index 34fefeb8ff3..00000000000
--- a/server/sonar-web/src/main/js/components/hoc/__tests__/withIndexationGuard-test.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render, screen } from '@testing-library/react';
-import { IndexationContext } from '../../../app/components/indexation/IndexationContext';
-import withIndexationGuard from '../withIndexationGuard';
-
-describe('withIndexationGuard', () => {
- it('should render indexation message when showIndexationMessage returns true', () => {
- renderComponentWithIndexationGuard(() => true);
- expect(
- screen.getByText(/indexation\.page_unavailable\.description\.additional_information/),
- ).toBeInTheDocument();
- });
-
- it('should render children when showIndexationMessage returns false', () => {
- renderComponentWithIndexationGuard(() => false);
- expect(screen.getByText('TestComponent')).toBeInTheDocument();
- });
-});
-
-function renderComponentWithIndexationGuard(showIndexationMessage: () => boolean) {
- const TestComponentWithGuard = withIndexationGuard({
- Component: TestComponent,
- showIndexationMessage,
- });
-
- return render(
- <IndexationContext.Provider
- value={{
- status: { completedCount: 23, isCompleted: false, hasFailures: false, total: 42 },
- }}
- >
- <TestComponentWithGuard />
- </IndexationContext.Provider>,
- );
-}
-
-function TestComponent() {
- return <h1>TestComponent</h1>;
-}
diff --git a/server/sonar-web/src/main/js/components/hoc/whenLoggedIn.tsx b/server/sonar-web/src/main/js/components/hoc/whenLoggedIn.tsx
deleted file mode 100644
index f17cddd2d18..00000000000
--- a/server/sonar-web/src/main/js/components/hoc/whenLoggedIn.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { getWrappedDisplayName } from '~sonar-aligned/components/hoc/utils';
-import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext';
-import handleRequiredAuthentication from '../../helpers/handleRequiredAuthentication';
-import { CurrentUser, isLoggedIn } from '../../types/users';
-
-export function whenLoggedIn<P>(WrappedComponent: React.ComponentType<React.PropsWithChildren<P>>) {
- class Wrapper extends React.Component<P & { currentUser: CurrentUser }> {
- static displayName = getWrappedDisplayName(WrappedComponent, 'whenLoggedIn');
-
- componentDidMount() {
- if (!isLoggedIn(this.props.currentUser)) {
- handleRequiredAuthentication();
- }
- }
-
- render() {
- if (isLoggedIn(this.props.currentUser)) {
- return <WrappedComponent {...this.props} />;
- }
- return null;
- }
- }
-
- return withCurrentUserContext(Wrapper);
-}
diff --git a/server/sonar-web/src/main/js/components/hoc/withCLanguageFeature.tsx b/server/sonar-web/src/main/js/components/hoc/withCLanguageFeature.tsx
deleted file mode 100644
index 8a71491526f..00000000000
--- a/server/sonar-web/src/main/js/components/hoc/withCLanguageFeature.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { getWrappedDisplayName } from '~sonar-aligned/components/hoc/utils';
-import { LanguagesContext } from '../../app/components/languages/LanguagesContext';
-
-export function withCLanguageFeature<P>(
- WrappedComponent: React.ComponentType<
- React.PropsWithChildren<P & { hasCLanguageFeature: boolean }>
- >,
-) {
- class Wrapper extends React.Component<Omit<P, 'hasCLanguageFeature'>> {
- static displayName = getWrappedDisplayName(WrappedComponent, 'withCLanguageFeature');
-
- render() {
- return (
- <LanguagesContext.Consumer>
- {(languages) => {
- const hasCLanguageFeature = languages['c'] !== undefined;
-
- return (
- <WrappedComponent {...(this.props as P)} hasCLanguageFeature={hasCLanguageFeature} />
- );
- }}
- </LanguagesContext.Consumer>
- );
- }
- }
-
- return Wrapper;
-}
diff --git a/server/sonar-web/src/main/js/components/hoc/withIndexationContext.tsx b/server/sonar-web/src/main/js/components/hoc/withIndexationContext.tsx
deleted file mode 100644
index fd1e05c9756..00000000000
--- a/server/sonar-web/src/main/js/components/hoc/withIndexationContext.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { getWrappedDisplayName } from '~sonar-aligned/components/hoc/utils';
-import { IndexationContext } from '../../app/components/indexation/IndexationContext';
-import { IndexationContextInterface } from '../../types/indexation';
-
-export interface WithIndexationContextProps {
- indexationContext: IndexationContextInterface;
-}
-
-export default function withIndexationContext<P>(
- WrappedComponent: React.ComponentType<React.PropsWithChildren<P & WithIndexationContextProps>>,
-) {
- return class WithIndexationContext extends React.PureComponent<
- Omit<P, keyof WithIndexationContextProps>
- > {
- static displayName = getWrappedDisplayName(WrappedComponent, 'withIndexationContext');
-
- render() {
- return (
- <IndexationContext.Consumer>
- {(indexationContext) => {
- if (indexationContext) {
- return (
- <WrappedComponent indexationContext={indexationContext} {...(this.props as P)} />
- );
- }
-
- return null;
- }}
- </IndexationContext.Consumer>
- );
- }
- };
-}
diff --git a/server/sonar-web/src/main/js/components/hoc/withIndexationGuard.tsx b/server/sonar-web/src/main/js/components/hoc/withIndexationGuard.tsx
deleted file mode 100644
index c170b2f76e0..00000000000
--- a/server/sonar-web/src/main/js/components/hoc/withIndexationGuard.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import PageUnavailableDueToIndexation from '../../app/components/indexation/PageUnavailableDueToIndexation';
-
-export default function withIndexationGuard<P>({
- Component,
- showIndexationMessage,
-}: {
- Component: React.ComponentType<React.PropsWithChildren<P>>;
- showIndexationMessage: (props: P) => boolean;
-}) {
- return function WithIndexationGuard(props: React.PropsWithChildren<P>) {
- return showIndexationMessage(props) ? (
- <PageUnavailableDueToIndexation />
- ) : (
- <Component {...props} />
- );
- };
-}
diff --git a/server/sonar-web/src/main/js/components/hoc/withKeyboardNavigation.tsx b/server/sonar-web/src/main/js/components/hoc/withKeyboardNavigation.tsx
deleted file mode 100644
index eab7ab09de8..00000000000
--- a/server/sonar-web/src/main/js/components/hoc/withKeyboardNavigation.tsx
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { getWrappedDisplayName } from '~sonar-aligned/components/hoc/utils';
-import { getComponentMeasureUniqueKey } from '../../helpers/component';
-import { isInput, isShortcut } from '../../helpers/keyboardEventHelpers';
-import { KeyboardKeys } from '../../helpers/keycodes';
-import { ComponentMeasure } from '../../types/types';
-
-export interface WithKeyboardNavigationProps {
- components?: ComponentMeasure[];
- cycle?: boolean;
- isFile?: boolean;
- onEndOfList?: () => void;
- onGoToParent?: () => void;
- onHighlight?: (item: ComponentMeasure) => void;
- onSelect?: (item: ComponentMeasure) => void;
- selected?: ComponentMeasure;
-}
-
-export default function withKeyboardNavigation<P>(
- WrappedComponent: React.ComponentType<
- React.PropsWithChildren<P & Partial<WithKeyboardNavigationProps>>
- >,
-) {
- return class Wrapper extends React.Component<P & WithKeyboardNavigationProps> {
- static displayName = getWrappedDisplayName(WrappedComponent, 'withKeyboardNavigation');
-
- componentDidMount() {
- document.addEventListener('keydown', this.handleKeyDown);
- }
-
- componentWillUnmount() {
- document.removeEventListener('keydown', this.handleKeyDown);
- }
-
- handleKeyDown = (event: KeyboardEvent) => {
- if (isInput(event) || isShortcut(event)) {
- return true;
- }
- if (event.key === KeyboardKeys.UpArrow) {
- return this.skipIfFile(this.handleHighlightPrevious);
- } else if (event.key === KeyboardKeys.DownArrow) {
- return this.skipIfFile(this.handleHighlightNext);
- } else if (event.key === KeyboardKeys.RightArrow || event.key === KeyboardKeys.Enter) {
- return this.skipIfFile(this.handleSelectCurrent);
- } else if (event.key === KeyboardKeys.LeftArrow) {
- this.handleSelectParent();
- }
- return true;
- };
-
- getCurrentIndex = () => {
- const { selected, components = [] } = this.props;
- return selected
- ? components.findIndex(
- (component) =>
- getComponentMeasureUniqueKey(component) === getComponentMeasureUniqueKey(selected),
- )
- : -1;
- };
-
- skipIfFile = (handler: () => void) => {
- if (this.props.isFile) {
- return true;
- }
- handler();
- return false;
- };
-
- handleHighlightNext = () => {
- if (this.props.onHighlight === undefined) {
- return;
- }
-
- const { components = [], cycle } = this.props;
- const index = this.getCurrentIndex();
- const first = cycle ? 0 : index;
-
- this.props.onHighlight(
- index < components.length - 1 ? components[index + 1] : components[first],
- );
-
- if (index + 1 === components.length - 1 && this.props.onEndOfList) {
- this.props.onEndOfList();
- }
- };
-
- handleHighlightPrevious = () => {
- if (this.props.onHighlight === undefined) {
- return;
- }
- const { components = [], cycle } = this.props;
- const index = this.getCurrentIndex();
- const last = cycle ? components.length - 1 : index;
-
- this.props.onHighlight(index > 0 ? components[index - 1] : components[last]);
- };
-
- handleSelectCurrent = () => {
- if (this.props.onSelect === undefined) {
- return;
- }
-
- const { selected } = this.props;
- if (selected !== undefined) {
- this.props.onSelect(selected as ComponentMeasure);
- }
- };
-
- handleSelectNext = () => {
- if (this.props.onSelect === undefined) {
- return;
- }
-
- const { components = [] } = this.props;
- const index = this.getCurrentIndex();
-
- if (index !== -1 && index < components.length - 1) {
- this.props.onSelect(components[index + 1]);
- }
- };
-
- handleSelectParent = () => {
- if (this.props.onGoToParent !== undefined) {
- this.props.onGoToParent();
- }
- };
-
- handleSelectPrevious = () => {
- if (this.props.onSelect === undefined) {
- return;
- }
-
- const { components = [] } = this.props;
- const index = this.getCurrentIndex();
-
- if (components.length && index > 0) {
- this.props.onSelect(components[index - 1]);
- }
- };
-
- render() {
- return <WrappedComponent {...this.props} />;
- }
- };
-}
diff --git a/server/sonar-web/src/main/js/components/hoc/withLocation.tsx b/server/sonar-web/src/main/js/components/hoc/withLocation.tsx
deleted file mode 100644
index 98b43324e3e..00000000000
--- a/server/sonar-web/src/main/js/components/hoc/withLocation.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Location, useLocation } from 'react-router-dom';
-
-export default function withLocation<P>(
- WrappedComponent: React.ComponentType<React.PropsWithChildren<P & { location: Location }>>,
-) {
- return function WithLocation(props: Omit<P, 'location'>) {
- const location = useLocation();
-
- return <WrappedComponent location={location} {...(props as P)} />;
- };
-}
diff --git a/server/sonar-web/src/main/js/components/icon-mappers/AIAssuredIcon.tsx b/server/sonar-web/src/main/js/components/icon-mappers/AIAssuredIcon.tsx
deleted file mode 100644
index 1776e197ac6..00000000000
--- a/server/sonar-web/src/main/js/components/icon-mappers/AIAssuredIcon.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { SheildCheckIcon } from '../ui/icon/SheildCheckIcon';
-import { SheildCrossIcon } from '../ui/icon/SheildCrossIcon';
-import { ShieldIcon } from '../ui/icon/ShieldIcon';
-
-export enum AiIconColor {
- Disable = '--echoes-color-icon-disabled',
- Default = '--echoes-color-icon-default',
- Accent = '--echoes-color-icon-accent',
- Subdued = '--echoes-color-icon-subdued',
-}
-
-export enum AiIconVariant {
- Default,
- Check,
- Cross,
-}
-
-interface Props {
- className?: string;
- color?: AiIconColor;
- height?: number;
- variant?: AiIconVariant;
- width?: number;
-}
-
-const VariantComp = {
- [AiIconVariant.Check]: SheildCheckIcon,
- [AiIconVariant.Default]: ShieldIcon,
- [AiIconVariant.Cross]: SheildCrossIcon,
-};
-
-export default function AIAssuredIcon({
- color = AiIconColor.Accent,
- variant = AiIconVariant.Default,
- className,
- width = 20,
- height = 20,
-}: Readonly<Props>) {
- const Comp = VariantComp[variant];
- return <Comp className={className} height={height} fill={`var(${color})`} width={width} />;
-}
diff --git a/server/sonar-web/src/main/js/components/icon-mappers/BranchLikeIcon.tsx b/server/sonar-web/src/main/js/components/icon-mappers/BranchLikeIcon.tsx
deleted file mode 100644
index 88f699a1e46..00000000000
--- a/server/sonar-web/src/main/js/components/icon-mappers/BranchLikeIcon.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { IconBranch, IconGitBranch, IconProps, IconPullrequest } from '@sonarsource/echoes-react';
-import { StyledMutedText } from '~design-system';
-import { isMainBranch, isPullRequest } from '~sonar-aligned/helpers/branch-like';
-import { BranchLike } from '../../types/branch-like';
-
-export interface BranchLikeIconProps extends IconProps {
- branchLike: BranchLike;
-}
-
-function BranchIcon(props: Readonly<IconProps>) {
- return <IconGitBranch data-testid="branch-like-icon-branch" {...props} />;
-}
-
-function MainBranchIcon(props: Readonly<IconProps>) {
- return <IconBranch data-testid="branch-like-icon-main-branch" {...props} />;
-}
-
-function PullRequestIcon(props: Readonly<IconProps>) {
- return <IconPullrequest data-testid="branch-like-icon-pull-request" {...props} />;
-}
-
-export default function BranchLikeIcon({ branchLike, ...props }: Readonly<BranchLikeIconProps>) {
- let Icon;
-
- if (isPullRequest(branchLike)) {
- Icon = PullRequestIcon;
- } else if (isMainBranch(branchLike)) {
- Icon = MainBranchIcon;
- } else {
- Icon = BranchIcon;
- }
-
- return (
- <StyledMutedText>
- <Icon {...props} />
- </StyledMutedText>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/icon-mappers/IssueSeverityIcon.tsx b/server/sonar-web/src/main/js/components/icon-mappers/IssueSeverityIcon.tsx
deleted file mode 100644
index 14c23b5a793..00000000000
--- a/server/sonar-web/src/main/js/components/icon-mappers/IssueSeverityIcon.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React from 'react';
-import {
- IconProps,
- SeverityBlockerIcon,
- SeverityCriticalIcon,
- SeverityInfoIcon,
- SeverityMajorIcon,
- SeverityMinorIcon,
-} from '~design-system';
-import { IssueSeverity } from '../../types/issues';
-import { Dict } from '../../types/types';
-
-interface Props extends IconProps {
- severity: IssueSeverity | undefined;
-}
-
-const severityIcons: Dict<(props: IconProps) => React.ReactElement> = {
- blocker: SeverityBlockerIcon,
- critical: SeverityCriticalIcon,
- major: SeverityMajorIcon,
- minor: SeverityMinorIcon,
- info: SeverityInfoIcon,
-};
-
-export default function IssueSeverityIcon({ severity, ...iconProps }: Props) {
- if (!severity) {
- return null;
- }
-
- const IconComponent = severityIcons[severity.toLowerCase()];
- return IconComponent ? <IconComponent {...iconProps} /> : null;
-}
diff --git a/server/sonar-web/src/main/js/components/icon-mappers/IssueStatusIcon.tsx b/server/sonar-web/src/main/js/components/icon-mappers/IssueStatusIcon.tsx
deleted file mode 100644
index ace0e4df0de..00000000000
--- a/server/sonar-web/src/main/js/components/icon-mappers/IssueStatusIcon.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import {
- IconProps,
- StatusConfirmedIcon,
- StatusOpenIcon,
- StatusReopenedIcon,
- StatusResolvedIcon,
-} from '~design-system';
-import { IssueStatus } from '../../types/issues';
-import { Dict } from '../../types/types';
-
-interface Props extends IconProps {
- issueStatus: IssueStatus;
-}
-
-const statusIcons: Dict<(props: IconProps) => React.ReactElement> = {
- [IssueStatus.Accepted]: StatusConfirmedIcon,
- [IssueStatus.Confirmed]: StatusConfirmedIcon,
- [IssueStatus.FalsePositive]: StatusResolvedIcon,
- [IssueStatus.Fixed]: StatusResolvedIcon,
- [IssueStatus.Open]: StatusOpenIcon,
- closed: StatusResolvedIcon,
- confirm: StatusConfirmedIcon,
- confirmed: StatusConfirmedIcon,
- falsepositive: StatusResolvedIcon,
- in_review: StatusConfirmedIcon,
- open: StatusOpenIcon,
- reopened: StatusReopenedIcon,
- reopen: StatusReopenedIcon,
- unconfirm: StatusReopenedIcon,
- resolve: StatusResolvedIcon,
- resolved: StatusResolvedIcon,
- reviewed: StatusResolvedIcon,
- to_review: StatusOpenIcon,
- wontfix: StatusResolvedIcon,
-};
-
-export default function IssueStatusIcon({ issueStatus, ...iconProps }: Props) {
- const DesiredStatusIcon = statusIcons[issueStatus.toLowerCase()];
-
- return DesiredStatusIcon ? <DesiredStatusIcon {...iconProps} /> : null;
-}
diff --git a/server/sonar-web/src/main/js/components/icon-mappers/IssueTypeIcon.tsx b/server/sonar-web/src/main/js/components/icon-mappers/IssueTypeIcon.tsx
deleted file mode 100644
index 55d97562711..00000000000
--- a/server/sonar-web/src/main/js/components/icon-mappers/IssueTypeIcon.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- BugIcon,
- CodeSmellIcon,
- IconProps,
- SecurityHotspotIcon,
- VulnerabilityIcon,
-} from '~design-system';
-import { IssueType } from '../../types/issues';
-
-export interface Props extends IconProps {
- type: string | IssueType;
-}
-
-export default function IssueTypeIcon({ type, ...iconProps }: Props) {
- switch (type.toLowerCase()) {
- case IssueType.Bug.toLowerCase():
- case 'bugs':
- case 'new_bugs':
- case IssueType.Bug:
- return <BugIcon {...iconProps} />;
- case IssueType.Vulnerability.toLowerCase():
- case 'vulnerabilities':
- case 'new_vulnerabilities':
- case IssueType.Vulnerability:
- return <VulnerabilityIcon {...iconProps} />;
- case IssueType.CodeSmell.toLowerCase():
- case 'code_smells':
- case 'new_code_smells':
- case IssueType.CodeSmell:
- return <CodeSmellIcon {...iconProps} />;
- case IssueType.SecurityHotspot.toLowerCase():
- case 'security_hotspots':
- case 'new_security_hotspots':
- case IssueType.SecurityHotspot:
- return <SecurityHotspotIcon {...iconProps} />;
- default:
- return null;
- }
-}
diff --git a/server/sonar-web/src/main/js/components/icon-mappers/SeverityIcon.tsx b/server/sonar-web/src/main/js/components/icon-mappers/SeverityIcon.tsx
deleted file mode 100644
index 0dccb20ae3a..00000000000
--- a/server/sonar-web/src/main/js/components/icon-mappers/SeverityIcon.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import {
- IconProps,
- SeverityBlockerIcon,
- SeverityCriticalIcon,
- SeverityInfoIcon,
- SeverityMajorIcon,
- SeverityMinorIcon,
-} from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { isDefined } from '../../helpers/types';
-import { Dict } from '../../types/types';
-
-interface Props extends IconProps {
- severity: string | null | undefined;
-}
-
-const severityIcons: Dict<(props: IconProps) => React.ReactElement> = {
- blocker: SeverityBlockerIcon,
- critical: SeverityCriticalIcon,
- major: SeverityMajorIcon,
- minor: SeverityMinorIcon,
- info: SeverityInfoIcon,
-};
-
-export default function SeverityIcon({ severity, ...iconProps }: Omit<Props, 'label'>) {
- if (!isDefined(severity)) {
- return null;
- }
-
- const DesiredIcon = severityIcons[severity.toLowerCase()];
- return DesiredIcon ? (
- <DesiredIcon {...iconProps} aria-label={translate('severity', severity)} />
- ) : null;
-}
diff --git a/server/sonar-web/src/main/js/components/icon-mappers/SoftwareImpactSeverityIcon.tsx b/server/sonar-web/src/main/js/components/icon-mappers/SoftwareImpactSeverityIcon.tsx
deleted file mode 100644
index 0b19b703f15..00000000000
--- a/server/sonar-web/src/main/js/components/icon-mappers/SoftwareImpactSeverityIcon.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import {
- IconProps,
- SoftwareImpactSeverityBlockerIcon,
- SoftwareImpactSeverityHighIcon,
- SoftwareImpactSeverityInfoIcon,
- SoftwareImpactSeverityLowIcon,
- SoftwareImpactSeverityMediumIcon,
-} from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { useStandardExperienceModeQuery } from '../../queries/mode';
-import { SoftwareImpactSeverity } from '../../types/clean-code-taxonomy';
-import { IssueSeverity } from '../../types/issues';
-import { Dict } from '../../types/types';
-
-interface Props extends IconProps {
- disabled?: boolean;
- severity: string | null | undefined;
-}
-
-const defaultIconSize = 14;
-
-const severityIcons: Dict<(props: IconProps) => React.ReactElement> = {
- [SoftwareImpactSeverity.Blocker]: SoftwareImpactSeverityBlockerIcon,
- [SoftwareImpactSeverity.High]: SoftwareImpactSeverityHighIcon,
- [IssueSeverity.Critical]: SoftwareImpactSeverityHighIcon,
- [SoftwareImpactSeverity.Medium]: SoftwareImpactSeverityMediumIcon,
- [IssueSeverity.Major]: SoftwareImpactSeverityMediumIcon,
- [SoftwareImpactSeverity.Low]: SoftwareImpactSeverityLowIcon,
- [IssueSeverity.Minor]: SoftwareImpactSeverityLowIcon,
- [SoftwareImpactSeverity.Info]: SoftwareImpactSeverityInfoIcon,
-};
-
-export default function SoftwareImpactSeverityIcon({ severity, ...iconProps }: Readonly<Props>) {
- const { data: isStandardMode } = useStandardExperienceModeQuery();
- if (typeof severity !== 'string' || !severityIcons[severity]) {
- return null;
- }
-
- const DesiredIcon = severityIcons[severity];
- return (
- <DesiredIcon
- {...iconProps}
- width={iconProps?.width ?? defaultIconSize}
- height={iconProps?.height ?? defaultIconSize}
- aria-label={translate(isStandardMode ? 'severity' : 'severity_impact', severity)}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/icon-mappers/__tests__/BranchLikeIcon-test.tsx b/server/sonar-web/src/main/js/components/icon-mappers/__tests__/BranchLikeIcon-test.tsx
deleted file mode 100644
index f7350f550e3..00000000000
--- a/server/sonar-web/src/main/js/components/icon-mappers/__tests__/BranchLikeIcon-test.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render, screen } from '@testing-library/react';
-import { mockBranch, mockMainBranch, mockPullRequest } from '../../../helpers/mocks/branch-like';
-import BranchLikeIcon, { BranchLikeIconProps } from '../../icon-mappers/BranchLikeIcon';
-
-it('should render the branch icon correctly', () => {
- renderBranchLikeIcon({ branchLike: mockBranch() });
- expect(screen.getByTestId('branch-like-icon-branch')).toBeInTheDocument();
-});
-
-it('should render the main branch icon correctly', () => {
- renderBranchLikeIcon({ branchLike: mockMainBranch() });
- expect(screen.getByTestId('branch-like-icon-main-branch')).toBeInTheDocument();
-});
-
-it('should render the pull request icon correctly', () => {
- renderBranchLikeIcon({ branchLike: mockPullRequest() });
- expect(screen.getByTestId('branch-like-icon-pull-request')).toBeInTheDocument();
-});
-
-function renderBranchLikeIcon(props: BranchLikeIconProps) {
- return render(<BranchLikeIcon {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/components/illustrations/AiAssuredIllustration.tsx b/server/sonar-web/src/main/js/components/illustrations/AiAssuredIllustration.tsx
deleted file mode 100644
index a8a3ff03cf4..00000000000
--- a/server/sonar-web/src/main/js/components/illustrations/AiAssuredIllustration.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import AiCodeAssuranceCheckIllustration from './AiCodeAssuranceCheckIllustration';
-import AiCodeAssuranceIllustration from './AiCodeAssuranceIllustration';
-
-interface Props {
- className?: string;
- height?: number;
- variant?: AiIconVariant;
- width?: number;
-}
-
-export enum AiIconVariant {
- Default,
- Check,
-}
-
-const VariantComp = {
- [AiIconVariant.Check]: AiCodeAssuranceCheckIllustration,
- [AiIconVariant.Default]: AiCodeAssuranceIllustration,
-};
-
-export default function AIAssuredIllustration({
- variant = AiIconVariant.Default,
- className,
- width = 20,
- height = 20,
-}: Readonly<Props>) {
- const Comp = VariantComp[variant];
- return <Comp className={className} height={height} width={width} />;
-}
diff --git a/server/sonar-web/src/main/js/components/illustrations/AiCodeAssuranceCheckIllustration.tsx b/server/sonar-web/src/main/js/components/illustrations/AiCodeAssuranceCheckIllustration.tsx
deleted file mode 100644
index 2f41cf18b53..00000000000
--- a/server/sonar-web/src/main/js/components/illustrations/AiCodeAssuranceCheckIllustration.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-interface Props {
- className?: string;
- height?: number;
- width?: number;
-}
-
-export default function AiCodeAssuranceCheckIllustration({
- className,
- width = 168,
- height = 168,
-}: Readonly<Props>) {
- return (
- <svg
- className={className}
- width={width}
- height={height}
- viewBox="0 0 168 168"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- d="M81.6803 146.163C67.7412 142.236 56.0998 133.96 46.6909 121.017C36.8677 107.503 32 92.6055 32 76.1566V39.0003C32 38.1666 32.5171 37.4204 33.2978 37.1276L81.2982 19.1275C81.3571 19.1054 81.4168 19.0862 81.4771 19.0698L40 43.2648V76.1567C40 89.7648 45 107.765 53.5 119.265C61.9725 130.728 70.445 139.707 81.8885 146.202C81.8182 146.195 81.7485 146.182 81.6803 146.163Z"
- fill="#BDC6FF"
- />
- <path
- d="M81.6803 146.163C67.7412 142.236 56.0998 133.96 46.6909 121.016C36.8677 107.503 32 92.6053 32 76.1565V39.0002C32 38.1665 32.5171 37.4202 33.2978 37.1275L81.2982 19.1273C81.7509 18.9576 82.2499 18.9576 82.7027 19.1273L130.703 37.1275C131.484 37.4202 132.001 38.1665 132.001 39.0002V76.1565C132.001 87.4022 129.726 97.9228 125.147 107.772C127.283 107.819 129.362 108.102 131.357 108.595C135.786 98.4551 138.001 87.6423 138.001 76.1565V39.0002C138.001 35.6654 135.932 32.6804 132.81 31.5095L84.8094 13.5094C82.9983 12.8302 81.0025 12.8302 79.1914 13.5094L31.191 31.5095C28.0686 32.6804 26 35.6654 26 39.0002V76.1565C26 93.89 31.2792 110.019 41.8376 124.544C51.9705 138.484 64.709 147.615 80.0533 151.938C81.3261 152.296 82.6748 152.296 83.9475 151.938C88.8402 150.56 93.4679 148.692 97.8307 146.336C97.108 144.424 96.5851 142.413 96.2876 140.329C91.919 142.83 87.2643 144.77 82.3206 146.163C82.1118 146.221 81.8891 146.221 81.6803 146.163Z"
- fill="#6A7590"
- />
- <path
- d="M147 136.265C147 148.691 136.926 158.765 124.5 158.765C112.074 158.765 102 148.691 102 136.265C102 123.838 112.074 113.765 124.5 113.765C136.926 113.765 147 123.838 147 136.265Z"
- fill="#7B87D9"
- />
- <path
- fillRule="evenodd"
- clipRule="evenodd"
- d="M138.122 130.886L123 146.008L113.879 136.886L118.122 132.644L123 137.522L133.879 126.644L138.122 130.886Z"
- fill="white"
- />
- <path
- fillRule="evenodd"
- clipRule="evenodd"
- d="M68.9211 90.826C66.7316 92.1582 64.4181 93.311 62 94.2646C64.4181 95.2183 66.7316 96.3711 68.9211 97.7033C75.1049 101.466 80.2989 106.66 84.0614 112.844C85.3936 115.033 86.5463 117.347 87.5 119.765C88.4537 117.347 89.6064 115.033 90.9386 112.844C94.7011 106.66 99.8951 101.466 106.079 97.7033C108.268 96.3711 110.582 95.2183 113 94.2646C110.582 93.311 108.268 92.1582 106.079 90.826C99.8951 87.0635 94.7011 81.8695 90.9386 75.6858C89.6064 73.4963 88.4537 71.1827 87.5 68.7646C86.5463 71.1827 85.3936 73.4963 84.0614 75.6858C80.2989 81.8695 75.1049 87.0635 68.9211 90.826ZM74.6331 94.2646C79.6543 97.7516 84.013 102.11 87.5 107.132C90.987 102.11 95.3457 97.7516 100.367 94.2646C95.3457 90.7777 90.987 86.4189 87.5 81.3978C84.013 86.4189 79.6543 90.7777 74.6331 94.2646Z"
- fill="#7B87D9"
- />
- <path
- fillRule="evenodd"
- clipRule="evenodd"
- d="M55.0129 64.1416C53.4524 65.1832 51.774 66.065 50 66.7646C51.774 67.4643 53.4524 68.3461 55.0129 69.3877C57.9279 71.3335 60.4312 73.8368 62.3769 76.7518C63.4185 78.3122 64.3003 79.9906 65 81.7646C65.6997 79.9906 66.5815 78.3122 67.6231 76.7518C69.5688 73.8368 72.0721 71.3335 74.9871 69.3877C76.5476 68.3461 78.226 67.4643 80 66.7646C78.226 66.065 76.5476 65.1832 74.9871 64.1416C72.0721 62.1958 69.5688 59.6925 67.6231 56.7775C66.5815 55.2171 65.6997 53.5387 65 51.7646C64.3003 53.5387 63.4185 55.2171 62.3769 56.7775C60.4312 59.6925 57.9279 62.1958 55.0129 64.1416ZM59.0811 66.7647C61.3113 68.462 63.3026 70.4534 65 72.6836C66.6974 70.4534 68.6887 68.462 70.9189 66.7646C68.6887 65.0673 66.6974 63.0759 65 60.8457C63.3026 63.0759 61.3113 65.0673 59.0811 66.7647Z"
- fill="#7B87D9"
- />
- <path
- fillRule="evenodd"
- clipRule="evenodd"
- d="M83.1828 51.4705C82.2183 52.2052 81.1493 52.8114 80 53.2646C81.1493 53.7179 82.2183 54.3241 83.1828 55.0588C84.1331 55.7828 84.9819 56.6316 85.7058 57.5819C86.4406 58.5463 87.0467 59.6154 87.5 60.7646C87.9533 59.6154 88.5594 58.5463 89.2942 57.5819C90.0181 56.6316 90.8669 55.7828 91.8172 55.0588C92.7817 54.3241 93.8507 53.7179 95 53.2646C93.8507 52.8114 92.7817 52.2052 91.8172 51.4705C90.8669 50.7465 90.0181 49.8977 89.2942 48.9474C88.5594 47.9829 87.9533 46.9139 87.5 45.7646C87.0467 46.9139 86.4406 47.9829 85.7058 48.9474C84.9819 49.8977 84.1331 50.7465 83.1828 51.4705ZM85.7333 53.2646C86.3665 53.8075 86.9571 54.3982 87.5 55.0314C88.0429 54.3982 88.6335 53.8075 89.2667 53.2646C88.6335 52.7218 88.0429 52.1311 87.5 51.4979C86.9571 52.1311 86.3665 52.7218 85.7333 53.2646Z"
- fill="#7B87D9"
- />
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/illustrations/AiCodeAssuranceIllustration.tsx b/server/sonar-web/src/main/js/components/illustrations/AiCodeAssuranceIllustration.tsx
deleted file mode 100644
index a4afa7638c8..00000000000
--- a/server/sonar-web/src/main/js/components/illustrations/AiCodeAssuranceIllustration.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-interface Props {
- className?: string;
- height?: number;
- width?: number;
-}
-
-export default function AiCodeAssuranceIllustration({
- className,
- width = 168,
- height = 168,
-}: Readonly<Props>) {
- return (
- <svg
- className={className}
- width={width}
- height={height}
- viewBox="0 0 168 168"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- d="M83.6803 146.163C69.7412 142.236 58.0998 133.96 48.6909 121.017C38.8677 107.503 34 92.6055 34 76.1566V39.0003C34 38.1666 34.5171 37.4204 35.2978 37.1276L83.2982 19.1275C83.3571 19.1054 83.4168 19.0862 83.4771 19.0698L42 43.2648V76.1567C42 89.7648 47 107.765 55.5 119.265C63.9725 130.728 72.445 139.707 83.8885 146.202C83.8182 146.195 83.7485 146.182 83.6803 146.163Z"
- fill="#BDC6FF"
- />
- <path
- fillRule="evenodd"
- clipRule="evenodd"
- d="M48.6909 121.016C58.0998 133.96 69.7412 142.236 83.6803 146.163C83.8891 146.221 84.1118 146.221 84.3206 146.163C98.2596 142.236 109.901 133.96 119.31 121.016C129.133 107.503 134.001 92.6053 134.001 76.1565V39.0002C134.001 38.1665 133.484 37.4202 132.703 37.1275L84.7027 19.1273C84.2499 18.9576 83.7509 18.9576 83.2982 19.1273L35.2978 37.1275C34.5171 37.4202 34 38.1665 34 39.0002V76.1565C34 92.6053 38.8677 107.503 48.6909 121.016ZM82.0533 151.938C83.3261 152.296 84.6748 152.296 85.9475 151.938C101.292 147.615 114.03 138.484 124.163 124.544C134.722 110.019 140.001 93.89 140.001 76.1565V39.0002C140.001 35.6654 137.932 32.6804 134.81 31.5095L86.8094 13.5094C84.9983 12.8302 83.0025 12.8302 81.1914 13.5094L33.191 31.5095C30.0686 32.6804 28 35.6654 28 39.0002V76.1565C28 93.89 33.2792 110.019 43.8376 124.544C53.9705 138.484 66.709 147.615 82.0533 151.938Z"
- fill="#6A7590"
- />
- <path
- fillRule="evenodd"
- clipRule="evenodd"
- d="M70.9211 90.826C68.7316 92.1582 66.4181 93.311 64 94.2646C66.4181 95.2183 68.7316 96.3711 70.9211 97.7033C77.1049 101.466 82.2989 106.66 86.0614 112.844C87.3936 115.033 88.5463 117.347 89.5 119.765C90.4537 117.347 91.6064 115.033 92.9386 112.844C96.7011 106.66 101.895 101.466 108.079 97.7033C110.268 96.3711 112.582 95.2183 115 94.2646C112.582 93.311 110.268 92.1582 108.079 90.826C101.895 87.0635 96.7011 81.8695 92.9386 75.6858C91.6064 73.4963 90.4537 71.1827 89.5 68.7646C88.5463 71.1827 87.3936 73.4963 86.0614 75.6858C82.2989 81.8695 77.1049 87.0635 70.9211 90.826ZM76.6331 94.2646C81.6543 97.7516 86.013 102.11 89.5 107.132C92.987 102.11 97.3457 97.7516 102.367 94.2646C97.3457 90.7777 92.987 86.4189 89.5 81.3978C86.013 86.4189 81.6543 90.7777 76.6331 94.2646Z"
- fill="#7B87D9"
- />
- <path
- fillRule="evenodd"
- clipRule="evenodd"
- d="M57.0129 64.1416C55.4524 65.1832 53.774 66.065 52 66.7646C53.774 67.4643 55.4524 68.3461 57.0129 69.3877C59.9279 71.3335 62.4312 73.8368 64.3769 76.7518C65.4185 78.3122 66.3003 79.9906 67 81.7646C67.6997 79.9906 68.5815 78.3122 69.6231 76.7518C71.5688 73.8368 74.0721 71.3335 76.9871 69.3877C78.5476 68.3461 80.226 67.4643 82 66.7646C80.226 66.065 78.5476 65.1832 76.9871 64.1416C74.0721 62.1958 71.5688 59.6925 69.6231 56.7775C68.5815 55.2171 67.6997 53.5387 67 51.7646C66.3003 53.5387 65.4185 55.2171 64.3769 56.7775C62.4312 59.6925 59.9279 62.1958 57.0129 64.1416ZM61.0811 66.7647C63.3113 68.462 65.3026 70.4534 67 72.6836C68.6974 70.4534 70.6887 68.462 72.9189 66.7646C70.6887 65.0673 68.6974 63.0759 67 60.8457C65.3026 63.0759 63.3113 65.0673 61.0811 66.7647Z"
- fill="#7B87D9"
- />
- <path
- fillRule="evenodd"
- clipRule="evenodd"
- d="M85.1828 51.4705C84.2183 52.2052 83.1493 52.8114 82 53.2646C83.1493 53.7179 84.2183 54.3241 85.1828 55.0588C86.1331 55.7828 86.9819 56.6316 87.7058 57.5819C88.4406 58.5463 89.0467 59.6154 89.5 60.7646C89.9533 59.6154 90.5594 58.5463 91.2942 57.5819C92.0181 56.6316 92.8669 55.7828 93.8172 55.0588C94.7817 54.3241 95.8507 53.7179 97 53.2646C95.8507 52.8114 94.7817 52.2052 93.8172 51.4705C92.8669 50.7465 92.0181 49.8977 91.2942 48.9474C90.5594 47.9829 89.9533 46.9139 89.5 45.7646C89.0467 46.9139 88.4406 47.9829 87.7058 48.9474C86.9819 49.8977 86.1331 50.7465 85.1828 51.4705ZM87.7333 53.2646C88.3665 53.8075 88.9571 54.3982 89.5 55.0314C90.0429 54.3982 90.6335 53.8075 91.2667 53.2646C90.6335 52.7218 90.0429 52.1311 89.5 51.4979C88.9571 52.1311 88.3665 52.7218 87.7333 53.2646Z"
- fill="#7B87D9"
- />
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/intl/DateFormatter.tsx b/server/sonar-web/src/main/js/components/intl/DateFormatter.tsx
deleted file mode 100644
index 22286f71ccb..00000000000
--- a/server/sonar-web/src/main/js/components/intl/DateFormatter.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { FormatDateOptions, FormattedDate } from 'react-intl';
-import { parseDate } from '../../helpers/dates';
-import { ParsableDate } from '../../types/dates';
-
-export interface DateFormatterProps {
- children?: (formattedDate: string) => React.ReactNode;
- date: ParsableDate;
- long?: boolean;
-}
-
-export const formatterOption: FormatDateOptions = {
- year: 'numeric',
- month: 'short',
- day: '2-digit',
-};
-
-export const longFormatterOption: FormatDateOptions = {
- year: 'numeric',
- month: 'long',
- day: 'numeric',
-};
-
-export default function DateFormatter({ children, date, long }: DateFormatterProps) {
- return (
- <FormattedDate value={parseDate(date)} {...(long ? longFormatterOption : formatterOption)}>
- {children ? (d) => <>{children(d)}</> : undefined}
- </FormattedDate>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/intl/DateFromNow.tsx b/server/sonar-web/src/main/js/components/intl/DateFromNow.tsx
deleted file mode 100644
index 4cb3fb23123..00000000000
--- a/server/sonar-web/src/main/js/components/intl/DateFromNow.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { differenceInHours } from 'date-fns';
-import * as React from 'react';
-import { FormattedRelativeTime } from 'react-intl';
-import { parseDate } from '../../helpers/dates';
-import { translate } from '../../helpers/l10n';
-import { ParsableDate } from '../../types/dates';
-import DateTimeFormatter from './DateTimeFormatter';
-import { getRelativeTimeProps } from './dateUtils';
-
-export interface DateFromNowProps {
- children?: (formattedDate: string) => React.ReactNode;
- className?: string;
- date?: ParsableDate;
- hourPrecision?: boolean;
-}
-
-export default function DateFromNow(props: DateFromNowProps) {
- const { children: originalChildren = (f: string) => f, date, hourPrecision, className } = props;
- let children = originalChildren;
-
- if (!date) {
- /*
- * We return a JSX.Element to bypass typescript issue with functional components return type
- * (https://github.com/DefinitelyTyped/DefinitelyTyped/issues/20544)
- */
- // eslint-disable-next-line react/jsx-no-useless-fragment
- return <>{originalChildren(translate('never'))}</>;
- }
-
- if (hourPrecision && differenceInHours(Date.now(), parseDate(date)) < 1) {
- children = () => originalChildren(translate('less_than_1_hour_ago'));
- }
-
- const parsedDate = parseDate(date);
-
- const relativeTimeProps = getRelativeTimeProps(date);
-
- return (
- <DateTimeFormatter date={parsedDate}>
- {(formattedDate) => (
- <span className={className} title={formattedDate}>
- <FormattedRelativeTime {...relativeTimeProps}>
- {(d) => <>{children(d)}</>}
- </FormattedRelativeTime>
- </span>
- )}
- </DateTimeFormatter>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/intl/DateTimeFormatter.tsx b/server/sonar-web/src/main/js/components/intl/DateTimeFormatter.tsx
deleted file mode 100644
index 5cf5b770911..00000000000
--- a/server/sonar-web/src/main/js/components/intl/DateTimeFormatter.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { FormatDateOptions, FormattedDate } from 'react-intl';
-import { parseDate } from '../../helpers/dates';
-import { ParsableDate } from '../../types/dates';
-
-interface Props {
- children?: (formattedDate: string) => React.ReactNode;
- date: ParsableDate;
- timeZone?: string;
-}
-
-export const formatterOption: FormatDateOptions = {
- year: 'numeric',
- month: 'long',
- day: 'numeric',
- hour: 'numeric',
- minute: 'numeric',
-};
-
-export default function DateTimeFormatter({ children, date, ...rest }: Props) {
- return (
- <FormattedDate {...rest} value={parseDate(date)} {...formatterOption}>
- {children ? (d) => <>{children(d)}</> : undefined}
- </FormattedDate>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/intl/TimeFormatter.tsx b/server/sonar-web/src/main/js/components/intl/TimeFormatter.tsx
deleted file mode 100644
index 83de9dbf257..00000000000
--- a/server/sonar-web/src/main/js/components/intl/TimeFormatter.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { FormatDateOptions, FormattedTime } from 'react-intl';
-import { parseDate } from '../../helpers/dates';
-import { ParsableDate } from '../../types/dates';
-
-export interface TimeFormatterProps {
- children?: (formattedDate: string) => React.ReactNode;
- date: ParsableDate;
- long?: boolean;
- timeZone?: string;
-}
-
-export const formatterOption: FormatDateOptions = { hour: 'numeric', minute: 'numeric' };
-
-export const longFormatterOption: FormatDateOptions = {
- hour: 'numeric',
- minute: 'numeric',
- second: 'numeric',
-};
-
-export default function TimeFormatter({ children, date, long, ...rest }: TimeFormatterProps) {
- return (
- <FormattedTime
- {...rest}
- value={parseDate(date)}
- {...(long ? longFormatterOption : formatterOption)}
- >
- {children ? (d) => <>{children(d)}</> : undefined}
- </FormattedTime>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/intl/TranslatedMessage.tsx b/server/sonar-web/src/main/js/components/intl/TranslatedMessage.tsx
deleted file mode 100644
index 497103386cd..00000000000
--- a/server/sonar-web/src/main/js/components/intl/TranslatedMessage.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentProps } from 'react';
-import { FormattedMessage } from 'react-intl';
-
-type Props = ComponentProps<typeof FormattedMessage>;
-
-export function TranslatedMessage(props: Props) {
- return <FormattedMessage {...props} />;
-}
diff --git a/server/sonar-web/src/main/js/components/intl/__mocks__/DateFromNow.tsx b/server/sonar-web/src/main/js/components/intl/__mocks__/DateFromNow.tsx
deleted file mode 100644
index 5e3640363f7..00000000000
--- a/server/sonar-web/src/main/js/components/intl/__mocks__/DateFromNow.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { ParsableDate } from '../../../types/dates';
-
-interface Props {
- children?: (formattedDate: string) => React.ReactNode;
- date: ParsableDate;
-}
-
-export default function DateFromNow({ children, date }: Props) {
- return children ? children(date.toString()) : date.toString();
-}
diff --git a/server/sonar-web/src/main/js/components/intl/__tests__/DateFormatter-test.tsx b/server/sonar-web/src/main/js/components/intl/__tests__/DateFormatter-test.tsx
deleted file mode 100644
index ba14f5a1f82..00000000000
--- a/server/sonar-web/src/main/js/components/intl/__tests__/DateFormatter-test.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import * as React from 'react';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import DateFormatter, { DateFormatterProps } from '../DateFormatter';
-
-it('should render correctly', () => {
- renderDateFormatter({}, (formatted: string) => <span>{formatted}</span>);
- expect(screen.getByText('Feb 20, 2020')).toBeInTheDocument();
-
- renderDateFormatter({ long: true });
- expect(screen.getByText('February 20, 2020')).toBeInTheDocument();
-});
-
-function renderDateFormatter(
- overrides: Partial<DateFormatterProps> = {},
- children?: (d: string) => React.ReactNode,
-) {
- return renderComponent(
- <DateFormatter date={new Date('2020-02-20T20:20:20Z')} {...overrides}>
- {children}
- </DateFormatter>,
- );
-}
diff --git a/server/sonar-web/src/main/js/components/intl/__tests__/DateFromNow-test.tsx b/server/sonar-web/src/main/js/components/intl/__tests__/DateFromNow-test.tsx
deleted file mode 100644
index 4133bd00f09..00000000000
--- a/server/sonar-web/src/main/js/components/intl/__tests__/DateFromNow-test.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import DateFromNow, { DateFromNowProps } from '../DateFromNow';
-
-jest.mock('../dateUtils', () => ({
- getRelativeTimeProps: jest.fn().mockReturnValue({ value: -1, unit: 'year' }),
-}));
-
-const date = '2020-02-20T20:20:20Z';
-
-it('should render correctly', () => {
- renderDateFromNow({ date });
-
- expect(screen.getByText('1 year ago')).toBeInTheDocument();
-});
-
-it('should render correctly when there is no date or no children', () => {
- renderDateFromNow({ date: undefined });
-
- expect(screen.getByText('never')).toBeInTheDocument();
-});
-
-it('should render correctly when the date is less than one hour in the past', () => {
- const veryCloseDate = new Date(date);
- veryCloseDate.setMinutes(veryCloseDate.getMinutes() - 10);
- const mockDateNow = jest
- .spyOn(Date, 'now')
- .mockImplementation(() => new Date(date) as unknown as number);
-
- renderDateFromNow({ date: veryCloseDate, hourPrecision: true });
-
- expect(screen.getByText('less_than_1_hour_ago')).toBeInTheDocument();
- mockDateNow.mockRestore();
-});
-
-function renderDateFromNow(
- overrides: Partial<DateFromNowProps> = {},
- children: jest.Mock = jest.fn((d) => <>{d}</>),
-) {
- return renderComponent(
- <DateFromNow date={date} {...overrides}>
- {children}
- </DateFromNow>,
- );
-}
diff --git a/server/sonar-web/src/main/js/components/intl/__tests__/DateTimeFormatter-test.tsx b/server/sonar-web/src/main/js/components/intl/__tests__/DateTimeFormatter-test.tsx
deleted file mode 100644
index dd4c4c04aca..00000000000
--- a/server/sonar-web/src/main/js/components/intl/__tests__/DateTimeFormatter-test.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import * as React from 'react';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import DateTimeFormatter from '../DateTimeFormatter';
-
-it('should render correctly', () => {
- renderDateTimeFormatter();
- expect(screen.getByText(/February 20, 2020(\sat|,) 8:20 PM/)).toBeInTheDocument();
-
- renderDateTimeFormatter((formatted: string) => <span>Nice date: {formatted}</span>);
- expect(screen.getByText(/Nice date: February 20, 2020(\sat|,) 8:20 PM/)).toBeInTheDocument();
-});
-
-function renderDateTimeFormatter(children?: (d: string) => React.ReactNode) {
- return renderComponent(
- <DateTimeFormatter date={new Date('2020-02-20T20:20:20Z')} timeZone="UTC">
- {children}
- </DateTimeFormatter>,
- );
-}
diff --git a/server/sonar-web/src/main/js/components/intl/__tests__/TimeFormatter-test.tsx b/server/sonar-web/src/main/js/components/intl/__tests__/TimeFormatter-test.tsx
deleted file mode 100644
index fe81e754ae1..00000000000
--- a/server/sonar-web/src/main/js/components/intl/__tests__/TimeFormatter-test.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import * as React from 'react';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import TimeFormatter, { TimeFormatterProps } from '../TimeFormatter';
-
-it('should render correctly', () => {
- renderTimeFormatter({}, (formatted: string) => <span>{formatted}</span>);
- expect(screen.getByText('8:20 PM')).toBeInTheDocument();
-
- renderTimeFormatter({ long: true });
- expect(screen.getByText('8:20:20 PM')).toBeInTheDocument();
-});
-
-function renderTimeFormatter(
- overrides: Partial<TimeFormatterProps> = {},
- children?: (d: string) => React.ReactNode,
-) {
- return renderComponent(
- <TimeFormatter date={new Date('2020-02-20T20:20:20Z')} timeZone="UTC" {...overrides}>
- {children}
- </TimeFormatter>,
- );
-}
diff --git a/server/sonar-web/src/main/js/components/intl/__tests__/dateUtils-test.ts b/server/sonar-web/src/main/js/components/intl/__tests__/dateUtils-test.ts
deleted file mode 100644
index 5d7e250e6f6..00000000000
--- a/server/sonar-web/src/main/js/components/intl/__tests__/dateUtils-test.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getRelativeTimeProps } from '../dateUtils';
-
-const mockDateNow = jest.spyOn(Date, 'now');
-
-describe('getRelativeTimeProps', () => {
- mockDateNow.mockImplementation(() => new Date('2021-02-20T20:20:20Z').getTime());
-
- it.each([
- ['year', '2020-02-19T20:20:20Z', -1],
- ['month', '2020-11-18T20:20:20Z', -3],
- ['day', '2021-02-18T18:20:20Z', -2],
- ])('should return the correct props for dates older than a %s', (unit, date, value) => {
- expect(getRelativeTimeProps(date)).toEqual({ value, unit });
- });
-
- it('should return the correct props for dates from less than a day ago', () => {
- expect(getRelativeTimeProps('2021-02-20T20:19:45Z')).toEqual({
- value: -35,
- unit: 'second',
- updateIntervalInSeconds: 10,
- });
- });
-});
diff --git a/server/sonar-web/src/main/js/components/intl/dateUtils.ts b/server/sonar-web/src/main/js/components/intl/dateUtils.ts
deleted file mode 100644
index aac31d5bad5..00000000000
--- a/server/sonar-web/src/main/js/components/intl/dateUtils.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- differenceInDays,
- differenceInMonths,
- differenceInSeconds,
- differenceInYears,
-} from 'date-fns';
-import { Props as FormattedRelativeTimeProps } from 'react-intl/src/components/relative';
-import { parseDate } from '../../helpers/dates';
-import { ParsableDate } from '../../types/dates';
-
-const UPDATE_INTERVAL_IN_SECONDS = 10;
-
-export function getRelativeTimeProps(
- parsableDate: ParsableDate,
-): Pick<FormattedRelativeTimeProps, 'unit' | 'value' | 'updateIntervalInSeconds'> {
- const date = parseDate(parsableDate);
- const y = differenceInYears(date, Date.now());
-
- if (Math.abs(y) > 0) {
- return { value: y, unit: 'year' };
- }
-
- const m = differenceInMonths(date, Date.now());
- if (Math.abs(m) > 0) {
- return { value: m, unit: 'month' };
- }
-
- const d = differenceInDays(date, Date.now());
- if (Math.abs(d) > 0) {
- return { value: d, unit: 'day' };
- }
-
- return {
- value: differenceInSeconds(date, Date.now()),
- unit: 'second',
- updateIntervalInSeconds: UPDATE_INTERVAL_IN_SECONDS,
- };
-}
diff --git a/server/sonar-web/src/main/js/components/issue/Issue.css b/server/sonar-web/src/main/js/components/issue/Issue.css
deleted file mode 100644
index 8d3e774fc5b..00000000000
--- a/server/sonar-web/src/main/js/components/issue/Issue.css
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-.issue {
- position: relative;
- padding-top: 8px;
- padding-bottom: 8px;
- background-color: #f2dede;
- transition: all 0.3s ease;
- border: 2px solid transparent;
- cursor: pointer;
-}
-
-.issue.no-click {
- cursor: initial;
-}
-
-.issue.selected,
-.issue-message-box.selected {
- box-shadow: none;
- outline: none;
- border: 2px solid #4b9fd5 !important;
-}
-
-.issue + .issue,
-.issue-container + .issue-container {
- margin-top: 5px;
-}
-
-.issue-row {
- display: flex;
- margin-bottom: 5px;
- align-items: flex-start;
-}
-
-.issue-row-meta {
- padding-right: 5px;
- white-space: nowrap;
-}
-
-.issue-message .button-plain {
- line-height: 18px;
- font-size: 13px;
- font-weight: 600;
- text-align: left;
-}
-
-.issue-message {
- flex: 1;
- padding-left: 8px;
- padding-right: 8px;
- line-height: 18px;
- font-size: 13px;
- font-weight: 600;
- text-overflow: ellipsis;
-}
-
-.issue-actions {
- display: flex;
- justify-content: space-between;
- flex-wrap: wrap;
- align-items: center;
-}
-
-.issue-meta-list {
- display: flex;
- align-items: center;
-}
-
-.issue-meta {
- line-height: 12px;
- font-size: 12px;
- display: flex;
-}
-
-.issue-meta + .issue-meta {
- margin-left: 8px;
-}
-
-.issue-meta-label {
- display: inline-block;
- vertical-align: top;
- max-width: 180px;
- line-height: 16px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.issue-changelog {
- width: 450px;
- max-height: 320px;
- overflow: auto;
- white-space: normal;
-}
-
-.issue-comments {
- margin-top: 5px;
- padding-left: 8px;
- font-size: 12px;
-}
-
-.issue-comment {
- display: flex;
-}
-
-.issue-comment + .issue-comment {
- margin-top: 4px;
-}
-
-.issue-comment-author {
- flex-shrink: 0;
- max-width: 130px;
- line-height: 18px;
- color: #656565;
- font-weight: 600;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.issue-comment-age {
- flex-shrink: 0;
- line-height: 18px;
- white-space: nowrap;
- color: #656565;
-}
-
-.issue-comment-actions {
- flex-shrink: 0;
- padding-left: 5px;
- line-height: 18px;
- white-space: nowrap;
-}
-
-.issue-comment-bubble-popup {
- width: 440px;
- font-size: 12px;
-}
-
-.issue-comment-form-text textarea {
- width: 100%;
- max-width: 100%;
-}
-
-.issue-comment-form-footer {
- margin-top: 5px;
- line-height: 22px;
-}
-
-.issue-comment-form-footer:before,
-.issue-comment-form-footer:after {
- display: table;
- content: '';
- line-height: 0;
-}
-
-.issue-comment-form-footer:after {
- clear: both;
-}
-
-.issue-comment-form-actions {
- float: right;
-}
-
-.issue-comment-form-tips {
- float: left;
-}
-
-.issue-with-checkbox {
- padding-left: 24px;
-}
-
-.issue-with-checkbox .issue-checkbox-container {
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-.issue-checkbox-container {
- display: none;
- position: absolute;
- width: 28px;
- top: 0;
- bottom: 0;
- left: 0;
- border: none;
-}
-
-.issue-checkbox-container:hover {
- background-color: rgba(0, 0, 0, 0.05);
-}
-
-.issue:not(.selected) .location-index {
- background-color: #888;
-}
-
-.issue .menu:not(.issues-similar-issues-menu):not(.issue-changelog) {
- max-height: 120px;
- overflow: auto;
-}
-
-.issue-message-box {
- background-color: #f2dede;
- border: 2px solid transparent;
- margin: 10px 0px;
-}
-
-.issue-message-highlight-CODE {
- background-color: rgba(255, 255, 255, 0.6);
- border-radius: 4px;
- font-family: Consolas, 'Ubuntu Mono', 'Liberation Mono', Menlo, Courier, monospace;
- font-weight: 400;
- line-height: 1.4em;
- padding: 2px 2px 0;
-}
-
-.issue-message-box.secondary-issue {
- background-color: #f8eeee;
-}
-
-.issue-message-box.secondary-issue:hover,
-.issue:hover {
- border: 2px dashed #4b9fd5;
- outline: 0;
- cursor: pointer;
-}
-
-.issue-get-perma-link {
- flex-shrink: 0;
-}
-
-.issue-comment-list-wrapper {
- max-height: 400px;
- overflow-y: auto;
-}
-
-.issue-comment-tile {
- background-color: #f3f3f3;
-}
-
-.issue .button-link {
- color: #0e516f;
-}
-
-.issue .button-link:hover,
-.issue .button-link:focus,
-.issue .button-link:active {
- color: #236a97;
-}
diff --git a/server/sonar-web/src/main/js/components/issue/Issue.tsx b/server/sonar-web/src/main/js/components/issue/Issue.tsx
deleted file mode 100644
index db01bf69c83..00000000000
--- a/server/sonar-web/src/main/js/components/issue/Issue.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { flow } from 'lodash';
-import { memo, useCallback, useEffect } from 'react';
-import { setIssueAssignee } from '../../api/issues';
-import { useComponent } from '../../app/components/componentContext/withComponentContext';
-import { isInput, isShortcut } from '../../helpers/keyboardEventHelpers';
-import { KeyboardKeys } from '../../helpers/keycodes';
-import { getKeyboardShortcutEnabled } from '../../helpers/preferences';
-import { useRefreshBranchStatus } from '../../queries/branch';
-import { BranchLike } from '../../types/branch-like';
-import { Issue as TypeIssue } from '../../types/types';
-import { updateIssue } from './actions';
-import IssueView from './components/IssueView';
-
-interface Props {
- branchLike?: BranchLike;
- checked?: boolean;
- displayWhyIsThisAnIssue?: boolean;
- issue: TypeIssue;
- onChange: (issue: TypeIssue) => void;
- onCheck?: (issue: string) => void;
- onPopupToggle: (issue: string, popupName: string, open?: boolean) => void;
- onSelect: (issueKey: string) => void;
- openPopup?: string;
- selected: boolean;
-}
-
-function Issue(props: Readonly<Props>) {
- const {
- selected = false,
- issue,
- branchLike,
- checked,
- openPopup,
- displayWhyIsThisAnIssue,
- onCheck,
- onPopupToggle,
- } = props;
-
- const { component } = useComponent();
-
- const refreshStatus = useRefreshBranchStatus(component?.key);
-
- const onChange = flow([props.onChange, refreshStatus]);
-
- const togglePopup = useCallback(
- (popupName: string, open?: boolean) => {
- onPopupToggle(issue.key, popupName, open);
- },
- [issue.key, onPopupToggle],
- );
-
- const handleAssignement = useCallback(
- (login: string) => {
- if (issue.assignee !== login) {
- updateIssue(onChange, setIssueAssignee({ issue: issue.key, assignee: login }));
- }
- togglePopup('assign', false);
- },
- [issue.assignee, issue.key, onChange, togglePopup],
- );
-
- const handleKeyDown = useCallback(
- (event: KeyboardEvent) => {
- if (!getKeyboardShortcutEnabled() || isInput(event) || isShortcut(event)) {
- return true;
- } else if (event.key === KeyboardKeys.KeyF) {
- event.preventDefault();
- return togglePopup('transition');
- } else if (event.key === KeyboardKeys.KeyA) {
- event.preventDefault();
- return togglePopup('assign');
- } else if (event.key === KeyboardKeys.KeyM && issue.actions.includes('assign')) {
- event.preventDefault();
- return handleAssignement('_me');
- } else if (event.key === KeyboardKeys.KeyI) {
- event.preventDefault();
- return togglePopup('set-severity');
- } else if (event.key === KeyboardKeys.KeyT) {
- event.preventDefault();
- return togglePopup('edit-tags');
- } else if (event.key === KeyboardKeys.Space) {
- event.preventDefault();
- if (onCheck) {
- return onCheck(issue.key);
- }
- }
- return true;
- },
- [issue.actions, issue.key, togglePopup, handleAssignement, onCheck],
- );
-
- useEffect(() => {
- if (selected) {
- document.addEventListener('keydown', handleKeyDown, { capture: true });
- }
- return () => document.removeEventListener('keydown', handleKeyDown, { capture: true });
- }, [handleKeyDown, selected]);
-
- return (
- <IssueView
- branchLike={branchLike}
- checked={checked}
- currentPopup={openPopup}
- displayWhyIsThisAnIssue={displayWhyIsThisAnIssue}
- issue={issue}
- onAssign={handleAssignement}
- onChange={onChange}
- onCheck={props.onCheck}
- onSelect={props.onSelect}
- selected={selected}
- togglePopup={togglePopup}
- />
- );
-}
-
-export default memo(Issue);
diff --git a/server/sonar-web/src/main/js/components/issue/__tests__/Issue-it.tsx b/server/sonar-web/src/main/js/components/issue/__tests__/Issue-it.tsx
deleted file mode 100644
index 5c333a465b8..00000000000
--- a/server/sonar-web/src/main/js/components/issue/__tests__/Issue-it.tsx
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { omit, pick } from 'lodash';
-import * as React from 'react';
-import { Route } from 'react-router-dom';
-import { byLabelText, byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import IssuesServiceMock from '../../../api/mocks/IssuesServiceMock';
-import { ModeServiceMock } from '../../../api/mocks/ModeServiceMock';
-import UsersServiceMock from '../../../api/mocks/UsersServiceMock';
-import { KeyboardKeys } from '../../../helpers/keycodes';
-import { mockIssue, mockLoggedInUser, mockRawIssue } from '../../../helpers/testMocks';
-import { renderAppRoutes } from '../../../helpers/testReactTestingUtils';
-import { ComponentPropsType } from '../../../helpers/testUtils';
-import {
- CleanCodeAttributeCategory,
- SoftwareImpactSeverity,
- SoftwareQuality,
-} from '../../../types/clean-code-taxonomy';
-import {
- IssueActions,
- IssueSeverity,
- IssueStatus,
- IssueTransition,
- IssueType,
-} from '../../../types/issues';
-import { Mode } from '../../../types/mode';
-import { RestUserDetailed } from '../../../types/users';
-import Issue from '../Issue';
-
-jest.mock('../../../helpers/preferences', () => ({
- getKeyboardShortcutEnabled: jest.fn(() => true),
-}));
-
-const usersHandler = new UsersServiceMock();
-const issuesHandler = new IssuesServiceMock(usersHandler);
-const modeHandler = new ModeServiceMock();
-
-beforeEach(() => {
- issuesHandler.reset();
- usersHandler.reset();
- modeHandler.reset();
- usersHandler.users = [mockLoggedInUser() as unknown as RestUserDetailed];
-});
-
-describe('rendering', () => {
- it('should render correctly for issue message and effort', async () => {
- const { ui } = getPageObject();
- const issue = mockIssue(true, { effort: '2 days', message: 'This is an issue' });
- const onClick = jest.fn();
- renderIssue(
- { issue, onSelect: onClick },
- 'scopes=MAIN&impactSeverities=LOW&types=VULNERABILITY',
- );
-
- expect(ui.effort('2 days').get()).toBeInTheDocument();
- expect(ui.issueMessageLink.get()).toHaveAttribute(
- 'href',
- '/issues?scopes=MAIN&impactSeverities=LOW&types=VULNERABILITY&open=AVsae-CQS-9G3txfbFN2',
- );
-
- await ui.clickIssueMessage();
- expect(onClick).toHaveBeenCalledWith(issue.key);
- });
-
- it('should render correctly for external rule engines', () => {
- renderIssue({ issue: mockIssue(true, { externalRuleEngine: 'ESLINT' }) });
- expect(screen.getByText('ESLINT')).toBeInTheDocument();
- });
-
- it('should render the SonarLint icon correctly', async () => {
- renderIssue({ issue: mockIssue(false, { quickFixAvailable: true }) });
- await expect(
- screen.getByText('issue.quick_fix_available_with_sonarlint_no_link'),
- ).toHaveATooltipWithContent('issue.quick_fix_available_with_sonarlint');
- });
-
- it('should render correctly with a checkbox', async () => {
- const { ui } = getPageObject();
- const onCheck = jest.fn();
- const issue = mockIssue();
- renderIssue({ onCheck, issue });
- await ui.toggleCheckbox();
- expect(onCheck).toHaveBeenCalledWith(issue.key);
- });
-
- it('should correctly render any code variants', async () => {
- const { ui } = getPageObject();
- renderIssue({ issue: mockIssue(false, { codeVariants: ['variant 1', 'variant 2'] }) });
- await expect(ui.variants(2).get()).toHaveATooltipWithContent('variant 1, variant 2');
- });
-
- it('should correctly render in MQR mode', async () => {
- const { ui } = getPageObject();
- renderIssue();
- expect(await ui.softwareQuality(SoftwareQuality.Maintainability).find()).toBeInTheDocument();
- expect(ui.softwareQualitySeverity(SoftwareImpactSeverity.Medium).get()).toBeInTheDocument();
- expect(ui.cleanCodeAttribute(CleanCodeAttributeCategory.Responsible).get()).toBeInTheDocument();
-
- expect(ui.issueType(IssueType.Bug).query()).not.toBeInTheDocument();
- expect(ui.standardSeverity(IssueSeverity.Major).query()).not.toBeInTheDocument();
- });
-
- it('should correctly render in Standard mode', async () => {
- const { ui } = getPageObject();
- modeHandler.setMode(Mode.Standard);
- renderIssue();
- expect(await ui.issueType(IssueType.Bug).find()).toBeInTheDocument();
- expect(ui.standardSeverity(IssueSeverity.Major).get()).toBeInTheDocument();
-
- expect(ui.softwareQuality(SoftwareQuality.Maintainability).query()).not.toBeInTheDocument();
- expect(
- ui.softwareQualitySeverity(SoftwareImpactSeverity.Medium).query(),
- ).not.toBeInTheDocument();
- expect(
- ui.cleanCodeAttribute(CleanCodeAttributeCategory.Responsible).query(),
- ).not.toBeInTheDocument();
- });
-});
-
-describe('updating', () => {
- it('should allow updating the status', async () => {
- const { ui } = getPageObject();
- const issue = mockRawIssue(false, {
- issueStatus: IssueStatus.Open,
- transitions: [IssueTransition.Confirm, IssueTransition.UnConfirm],
- });
- issuesHandler.setIssueList([{ issue, snippets: {} }]);
- renderIssue({
- issue: mockIssue(false, { ...pick(issue, 'key', 'status', 'transitions') }),
- });
-
- await ui.updateStatus(IssueStatus.Open, IssueTransition.Confirm);
- expect(ui.updateStatusBtn(IssueStatus.Confirmed).get()).toBeInTheDocument();
- });
-
- it('should allow assigning', async () => {
- const { ui } = getPageObject();
- const issue = mockRawIssue(false, {
- assignee: 'leia',
- actions: [IssueActions.Assign],
- });
- issuesHandler.setIssueList([{ issue, snippets: {} }]);
- renderIssue({
- issue: mockIssue(false, { ...pick(issue, 'actions', 'key', 'assignee') }),
- });
-
- await ui.updateAssignee('leia', 'Skywalker');
- expect(ui.updateAssigneeBtn('luke').get()).toBeInTheDocument();
- });
-
- it('should allow updating the tags', async () => {
- const { ui } = getPageObject();
- const issue = mockRawIssue(false, {
- tags: [],
- actions: [IssueActions.SetTags],
- });
- issuesHandler.setIssueList([{ issue, snippets: {} }]);
- renderIssue({ issue: mockIssue(false, { ...pick(issue, 'actions', 'key', 'tags') }) });
-
- await ui.addTag('accessibility');
- await ui.addTag('android', ['accessibility']);
- expect(ui.updateTagsBtn(['accessibility', 'android']).get()).toBeInTheDocument();
- });
-
- it('should allow updating the severity in MQR mode', async () => {
- const { ui, user } = getPageObject();
- const issue = mockRawIssue(false, {
- impacts: [
- { softwareQuality: SoftwareQuality.Maintainability, severity: SoftwareImpactSeverity.Low },
- ],
- actions: [IssueActions.SetSeverity],
- });
- issuesHandler.setIssueList([{ issue, snippets: {} }]);
- renderIssue({
- issue: mockIssue(false, { ...pick(issue, 'actions', 'key', 'impacts') }),
- });
- expect(ui.softwareQuality(SoftwareQuality.Maintainability).get()).toBeInTheDocument();
-
- await user.click(ui.softwareQuality(SoftwareQuality.Maintainability).get());
- await user.click(ui.softwareQualitySeverity(SoftwareImpactSeverity.Medium).get());
- expect(ui.softwareQualitySeverity(SoftwareImpactSeverity.Medium).get()).toBeInTheDocument();
- expect(byText(/issue.severity.updated_notification.link.mqr/).get()).toBeInTheDocument();
- });
-
- it('cannot update the severity in MQR mode without permission', async () => {
- const { ui, user } = getPageObject();
- const issue = mockRawIssue(false, {
- impacts: [
- { softwareQuality: SoftwareQuality.Maintainability, severity: SoftwareImpactSeverity.Low },
- ],
- });
- issuesHandler.setIssueList([{ issue, snippets: {} }]);
- renderIssue({
- issue: mockIssue(false, { ...pick(issue, 'actions', 'key', 'impacts') }),
- });
- expect(ui.softwareQuality(SoftwareQuality.Maintainability).get()).toBeInTheDocument();
- await user.click(ui.softwareQuality(SoftwareQuality.Maintainability).get());
- expect(
- ui.softwareQualitySeverity(SoftwareImpactSeverity.Medium).query(),
- ).not.toBeInTheDocument();
- // popover visible
- expect(byRole('heading', { name: /severity_impact.title/ }).get()).toBeInTheDocument();
- });
-
- it('should allow updating the severity in Standard experience', async () => {
- const { ui, user } = getPageObject();
- const issue = mockRawIssue(false, {
- actions: [IssueActions.SetSeverity],
- });
- modeHandler.setMode(Mode.Standard);
- issuesHandler.setIssueList([{ issue, snippets: {} }]);
- renderIssue({
- issue: mockIssue(false, { ...pick(issue, 'actions', 'key', 'severity') }),
- });
- expect(await ui.standardSeverity(IssueSeverity.Major).find()).toBeInTheDocument();
-
- await user.click(ui.standardSeverity(IssueSeverity.Major).get());
- await user.click(ui.standardSeverity(IssueSeverity.Info).get());
- expect(ui.standardSeverity(IssueSeverity.Info).get()).toBeInTheDocument();
- expect(byText(/issue.severity.updated_notification.link.standard/).get()).toBeInTheDocument();
- });
-
- it('cannot update the severity in Standard mode without permission', async () => {
- const { ui, user } = getPageObject();
- const issue = mockRawIssue(false);
- issuesHandler.setIssueList([{ issue, snippets: {} }]);
- modeHandler.setMode(Mode.Standard);
- renderIssue({
- issue: mockIssue(false, { ...pick(issue, 'actions', 'key', 'impacts') }),
- });
- expect(await ui.standardSeverity(IssueSeverity.Major).find()).toBeInTheDocument();
- await user.click(ui.standardSeverity(IssueSeverity.Major).get());
- expect(ui.standardSeverity(IssueSeverity.Info).query()).not.toBeInTheDocument();
- });
-});
-
-it('should correctly handle keyboard shortcuts', async () => {
- const { ui } = getPageObject();
- const onCheck = jest.fn();
- const issue = mockRawIssue(false, {
- actions: Object.values(IssueActions),
- assignee: 'luke',
- transitions: [IssueTransition.Confirm, IssueTransition.UnConfirm],
- });
- issuesHandler.setIssueList([{ issue, snippets: {} }]);
- usersHandler.setCurrentUser(mockLoggedInUser({ login: 'leia', name: 'Organa' }));
- renderIssue({
- onCheck,
- selected: true,
- issue: mockIssue(false, { ...pick(issue, 'actions', 'key', 'assignee', 'transitions') }),
- });
-
- await ui.pressTransitionShortcut();
- expect(ui.setStatusBtn(IssueTransition.UnConfirm).get()).toBeInTheDocument();
- await ui.pressDismissShortcut();
-
- await ui.pressAssignShortcut();
- expect(ui.setAssigneeBtn(/Organa/).get()).toBeInTheDocument();
- await ui.pressDismissShortcut();
-
- await ui.pressTagsShortcut();
- expect(ui.tagsSearchInput.get()).toBeInTheDocument();
- await ui.pressDismissShortcut();
-
- await ui.pressCheckShortcut();
- expect(onCheck).toHaveBeenCalled();
-
- expect(ui.updateAssigneeBtn('luke').get()).toBeInTheDocument();
- await ui.pressAssignToMeShortcut();
- expect(ui.updateAssigneeBtn('leia').get()).toBeInTheDocument();
-});
-
-function getPageObject() {
- const user = userEvent.setup();
-
- const selectors = {
- // Issue
- locationsBadge: (count: number) => byText(count),
- lineInfo: (line: number) => byText(`L${line}`),
- effort: (effort: string) => byText(`issue.x_effort.${effort}`),
- whyLink: byRole('link', { name: 'issue.why_this_issue.long' }),
- checkbox: byRole('checkbox'),
- issueMessageLink: byRole('link', { name: 'This is an issue' }),
- variants: (n: number) => byText(`issue.x_code_variants.${n}`),
- softwareQuality: (quality: SoftwareQuality) => byText(`software_quality.${quality}`),
- softwareQualitySeverity: (severity: SoftwareImpactSeverity) =>
- byLabelText(`severity_impact.${severity}`),
- cleanCodeAttribute: (category: CleanCodeAttributeCategory) =>
- byText(`issue.clean_code_attribute_category.${category}`),
- issueType: (type: IssueType) => byText(`issue.type.${type}`),
- standardSeverity: (severity: IssueSeverity) => byLabelText(`severity.${severity}`),
-
- // Changelog
- toggleChangelogBtn: byRole('button', {
- name: /issue.changelog.found_on_x_show_more/,
- }),
- changelogRow: (key: string, oldValue: string, newValue: string) =>
- byRole('row', {
- name: new RegExp(
- `issue\\.changelog\\.changed_to\\.issue\\.changelog\\.field\\.${key}\\.${newValue} \\(issue\\.changelog\\.was\\.${oldValue}\\)`,
- ),
- }),
-
- // Similar issues
- toggleSimilarIssuesBtn: byRole('button', { name: 'issue.filter_similar_issues' }),
- similarIssueTypeLink: byRole('button', { name: 'issue.type.BUG' }),
- similarIssueSeverityLink: byRole('button', { name: 'severity.MAJOR' }),
- similarIssueStatusLink: byRole('button', { name: 'issue.status.OPEN' }),
- similarIssueResolutionLink: byRole('button', { name: 'unresolved' }),
- similarIssueAssigneeLink: byRole('button', { name: 'unassigned' }),
- similarIssueRuleLink: byRole('button', { name: 'Rule Foo' }),
- similarIssueTagLink: (name: string) => byRole('button', { name }),
- similarIssueProjectLink: byRole('button', { name: 'qualifier.TRK Project Bar' }),
- similarIssueFileLink: byRole('button', { name: 'qualifier.FIL main.js' }),
-
- // Comment
- commentsList: () => {
- const list = byRole('list')
- .getAll()
- .find((el) => el.getAttribute('data-testid') === 'issue-comments');
- if (list === undefined) {
- throw new Error('Could not find comments list');
- }
- return list;
- },
- commentAddBtn: byRole('button', { name: 'issue.comment.add_comment' }),
- commentEditBtn: byRole('button', { name: 'issue.comment.edit' }),
- commentTextInput: byRole('textbox', { name: 'issue.comment.enter_comment' }),
- commentSaveBtn: byRole('button', { name: 'issue.comment.formlink' }),
- commentUpdateBtn: byRole('button', { name: 'save' }),
- commentDeleteBtn: byRole('button', { name: 'issue.comment.delete' }),
- commentConfirmDeleteBtn: byRole('button', { name: 'delete' }),
-
- // Status
- updateStatusBtn: (currentStatus: IssueStatus) =>
- byLabelText(`issue.transition.status_x_click_to_change.issue.issue_status.${currentStatus}`),
- setStatusBtn: (transition: IssueTransition) => byText(`issue.transition.${transition}`),
-
- // Assignee
- assigneeSearchInput: byLabelText('search.search_for_users'),
- updateAssigneeBtn: (currentAssignee: string) =>
- byRole('combobox', {
- name: `issue.assign.assigned_to_x_click_to_change.${currentAssignee}`,
- }),
- setAssigneeBtn: (name: RegExp) => byLabelText(name),
-
- // Tags
- tagsSearchInput: byRole('searchbox'),
- updateTagsBtn: (currentTags?: string[]) =>
- byRole('button', { name: `${currentTags ? currentTags.join(' ') : 'issue.no_tag'} +` }),
- toggleTagCheckbox: (name: string) => byRole('checkbox', { name }),
- };
-
- const ui = {
- ...selectors,
- async addComment(content: string) {
- await user.click(selectors.commentAddBtn.get());
- await user.type(selectors.commentTextInput.get(), content);
- await user.click(selectors.commentSaveBtn.get());
- },
- async updateComment(content: string) {
- await user.click(selectors.commentEditBtn.get());
- await user.type(selectors.commentTextInput.get(), content);
- await user.keyboard(`{Control>}{${KeyboardKeys.Enter}}{/Control}`);
- },
- async deleteComment() {
- await user.click(selectors.commentDeleteBtn.get());
- await user.click(selectors.commentConfirmDeleteBtn.get());
- },
- async updateStatus(currentStatus: IssueStatus, transition: IssueTransition) {
- await user.click(selectors.updateStatusBtn(currentStatus).get());
- await user.click(selectors.setStatusBtn(transition).get());
- },
- async updateAssignee(currentAssignee: string, newAssignee: string) {
- await user.click(selectors.updateAssigneeBtn(currentAssignee).get());
- await user.type(selectors.assigneeSearchInput.get(), newAssignee);
- await user.click(selectors.setAssigneeBtn(new RegExp(newAssignee)).get());
- },
- async addTag(tag: string, currentTagList?: string[]) {
- await user.click(selectors.updateTagsBtn(currentTagList).get());
- await user.click(selectors.toggleTagCheckbox(tag).get());
- await user.keyboard('{Escape}');
- },
- async showChangelog() {
- await user.click(selectors.toggleChangelogBtn.get());
- },
-
- async toggleCheckbox() {
- await user.click(selectors.checkbox.get());
- },
- async clickIssueMessage() {
- await user.click(selectors.issueMessageLink.get());
- },
- async pressDismissShortcut() {
- await user.keyboard(`{${KeyboardKeys.Escape}}`);
- },
- async pressTransitionShortcut() {
- await user.keyboard(`{${KeyboardKeys.KeyF}}`);
- },
- async pressAssignShortcut() {
- await user.keyboard(`{${KeyboardKeys.KeyA}}`);
- },
- async pressAssignToMeShortcut() {
- await user.keyboard(`{${KeyboardKeys.KeyM}}`);
- },
- async pressSeverityShortcut() {
- await user.keyboard(`{${KeyboardKeys.KeyI}}`);
- },
- async pressTagsShortcut() {
- await user.keyboard(`{${KeyboardKeys.KeyT}}`);
- },
- async pressCheckShortcut() {
- await user.keyboard(`{${KeyboardKeys.Space}}`);
- },
- };
-
- return { ui, user };
-}
-
-function renderIssue(
- props: Partial<Omit<ComponentPropsType<typeof Issue>, 'onChange' | 'onPopupToggle'>> = {},
- query?: string,
-) {
- function Wrapper(
- wrapperProps: Omit<ComponentPropsType<typeof Issue>, 'onChange' | 'onPopupToggle'>,
- ) {
- const [issue, setIssue] = React.useState(wrapperProps.issue);
- const [openPopup, setOpenPopup] = React.useState<string | undefined>();
- return (
- <Issue
- issue={issue}
- openPopup={openPopup}
- onChange={(newIssue) => {
- setIssue({ ...issue, ...newIssue });
- }}
- onPopupToggle={(_key, popup, open) => {
- setOpenPopup(open === false ? undefined : popup);
- }}
- {...omit(wrapperProps, 'issue')}
- />
- );
- }
-
- return renderAppRoutes(
- `issues${query ? `?${query}` : ''}`,
- () => (
- <Route
- path="issues"
- element={<Wrapper onSelect={jest.fn()} issue={mockIssue()} selected={false} {...props} />}
- />
- ),
- {
- currentUser: mockLoggedInUser({ login: 'leia', name: 'Organa' }),
- },
- );
-}
diff --git a/server/sonar-web/src/main/js/components/issue/__tests__/actions-test.ts b/server/sonar-web/src/main/js/components/issue/__tests__/actions-test.ts
deleted file mode 100644
index 45fea41b231..00000000000
--- a/server/sonar-web/src/main/js/components/issue/__tests__/actions-test.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { setImmediate } from 'timers';
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { parseIssueFromResponse } from '../../../helpers/issues';
-import { mockComponent } from '../../../helpers/mocks/component';
-import { mockIssue } from '../../../helpers/testMocks';
-import { updateIssue } from '../actions';
-
-jest.mock('~sonar-aligned/helpers/error', () => ({ throwGlobalError: jest.fn() }));
-
-jest.mock('../../../helpers/issues', () => ({
- parseIssueFromResponse: jest.fn(),
-}));
-
-describe('updateIssue', () => {
- const onChange = jest.fn();
- const oldIssue = mockIssue(false, { key: 'old' });
- const newIssue = mockIssue(false, { key: 'new' });
- const parsedIssue = mockIssue(false, { key: 'parsed' });
- const successPromise = jest.fn().mockResolvedValue({
- issue: mockIssue(),
- components: [mockComponent()],
- });
- const errorPromise = jest.fn().mockRejectedValue(null);
- (parseIssueFromResponse as jest.Mock).mockReturnValue(parsedIssue);
-
- beforeEach(jest.clearAllMocks);
-
- it('makes successful optimistic updates', async () => {
- updateIssue(onChange, successPromise(), oldIssue, newIssue);
- expect(onChange).toHaveBeenCalledWith(newIssue);
-
- await new Promise(setImmediate);
-
- expect(onChange).toHaveBeenCalledTimes(1);
- });
-
- it('makes successful non-optimistic updates', async () => {
- updateIssue(onChange, successPromise());
- expect(onChange).not.toHaveBeenCalled();
-
- await new Promise(setImmediate);
- expect(onChange).toHaveBeenCalledWith(parsedIssue);
- expect(onChange).toHaveBeenCalledTimes(1);
- });
-
- it('makes unsuccessful optimistic updates', async () => {
- updateIssue(onChange, errorPromise(), oldIssue, newIssue);
- expect(onChange).toHaveBeenCalledWith(newIssue);
-
- await new Promise(setImmediate);
-
- expect(onChange).toHaveBeenCalledWith(oldIssue);
- expect(onChange).toHaveBeenCalledTimes(2);
- });
-
- it('makes unsuccessful non-optimistic updates', async () => {
- updateIssue(onChange, errorPromise());
- expect(onChange).not.toHaveBeenCalled();
-
- await new Promise(setImmediate);
- expect(parseIssueFromResponse).not.toHaveBeenCalled();
- expect(throwGlobalError).toHaveBeenCalled();
- });
-});
diff --git a/server/sonar-web/src/main/js/components/issue/actions.ts b/server/sonar-web/src/main/js/components/issue/actions.ts
deleted file mode 100644
index 2845ab40fca..00000000000
--- a/server/sonar-web/src/main/js/components/issue/actions.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-import { parseIssueFromResponse } from '../../helpers/issues';
-import { IssueResponse } from '../../types/issues';
-import { Issue } from '../../types/types';
-
-export const updateIssue = (
- onChange: (issue: Issue) => void,
- resultPromise: Promise<IssueResponse>,
- oldIssue?: Issue,
- newIssue?: Issue,
-): Promise<void> => {
- const optimisticUpdate = oldIssue !== undefined && newIssue !== undefined;
- if (optimisticUpdate) {
- onChange(newIssue);
- }
-
- return resultPromise.then(
- (response) => {
- if (!optimisticUpdate) {
- const issue = parseIssueFromResponse(
- response.issue,
- response.components,
- response.users,
- response.rules,
- );
- onChange(issue);
- }
- },
- (param) => {
- if (optimisticUpdate) {
- onChange(oldIssue);
- }
- throwGlobalError(param);
- },
- );
-};
diff --git a/server/sonar-web/src/main/js/components/issue/components/DeprecatedFieldTooltip.tsx b/server/sonar-web/src/main/js/components/issue/components/DeprecatedFieldTooltip.tsx
deleted file mode 100644
index 6484133da9a..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/DeprecatedFieldTooltip.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { translate } from '../../../helpers/l10n';
-
-export interface DeprecatedTooltipProps {
- field: 'type' | 'severity';
-}
-
-const FILTERS_LIST = {
- type: ['issue.clean_code_attribute', 'software_quality'],
- severity: ['software_quality', 'issue.severity.new'],
-};
-
-export function DeprecatedFieldTooltip({ field }: DeprecatedTooltipProps) {
- return (
- <>
- <p className="sw-mb-4">{translate('issue', field, 'deprecation.title')}</p>
- <p>{translate('issue', field, 'deprecation.filter_by')}</p>
- <ul className="sw-list-disc sw-ml-6">
- {FILTERS_LIST[field].map((key) => (
- <li key={key}>{translate(key)}</li>
- ))}
- </ul>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueActionsBar.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueActionsBar.tsx
deleted file mode 100644
index d28648a19f0..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssueActionsBar.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { HighlightRing } from '~design-system';
-import { IssueActions } from '../../../types/issues';
-import { Issue } from '../../../types/types';
-import IssueAssign from './IssueAssign';
-import IssueTags from './IssueTags';
-import IssueTransition from './IssueTransition';
-import SonarLintBadge from './SonarLintBadge';
-
-interface Props {
- canSetTags?: boolean;
- currentPopup?: string;
- issue: Issue;
- onAssign: (login: string) => void;
- onChange: (issue: Issue) => void;
- showSonarLintBadge?: boolean;
- showTags?: boolean;
- togglePopup: (popup: string, show?: boolean) => void;
-}
-
-export default function IssueActionsBar(props: Readonly<Props>) {
- const {
- issue,
- currentPopup,
- onAssign,
- onChange,
- togglePopup,
- showSonarLintBadge,
- showTags,
- canSetTags,
- } = props;
-
- const canAssign = issue.actions.includes(IssueActions.Assign);
- const tagsPopupOpen = currentPopup === 'edit-tags' && canSetTags;
-
- return (
- <div className="sw-flex sw-gap-3 sw-min-w-0">
- <ul className="it__issue-header-actions sw-flex sw-items-center sw-gap-3 sw-typo-default sw-min-w-0">
- <HighlightRing
- as="li"
- className="sw-relative"
- data-guiding-id={`issue-transition-${issue.key}`}
- >
- <IssueTransition
- isOpen={currentPopup === 'transition'}
- togglePopup={togglePopup}
- issue={issue}
- onChange={onChange}
- />
- </HighlightRing>
-
- <li className="sw-min-w-0">
- <IssueAssign
- isOpen={currentPopup === 'assign'}
- togglePopup={togglePopup}
- canAssign={canAssign}
- issue={issue}
- onAssign={onAssign}
- />
- </li>
-
- {showTags && (
- <li>
- <IssueTags
- canSetTags={canSetTags}
- issue={issue}
- onChange={props.onChange}
- open={tagsPopupOpen}
- togglePopup={props.togglePopup}
- tagsToDisplay={1}
- />
- </li>
- )}
-
- {showSonarLintBadge && issue.quickFixAvailable && (
- <li>
- <SonarLintBadge />
- </li>
- )}
- </ul>
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueAssign.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueAssign.tsx
deleted file mode 100644
index 3f7b03a91e6..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssueAssign.tsx
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Options, SingleValue } from 'react-select';
-import { LabelValueSelectOption, PopupZLevel, SearchSelectDropdown } from '~design-system';
-import { getUsers } from '../../../api/users';
-import { CurrentUserContext } from '../../../app/components/current-user/CurrentUserContext';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { Issue } from '../../../types/types';
-import { RestUser, isLoggedIn, isUserActive } from '../../../types/users';
-import Avatar from '../../ui/Avatar';
-
-interface Props {
- canAssign: boolean;
- isOpen: boolean;
- issue: Issue;
- onAssign: (login: string) => void;
- togglePopup: (popup: string, show?: boolean) => void;
-}
-
-const minSearchLength = 2;
-
-const UNASSIGNED = { value: '', label: translate('unassigned') };
-
-const renderAvatar = (name?: string, avatar?: string) => (
- <Avatar hash={avatar} name={name} size="xs" className="sw-my-1" />
-);
-
-export default function IssueAssignee(props: Props) {
- const {
- canAssign,
- issue: { assignee, assigneeName, assigneeLogin, assigneeAvatar },
- } = props;
-
- const assinedUser = assigneeName ?? assignee;
- const { currentUser } = React.useContext(CurrentUserContext);
-
- const allowCurrentUserSelection = isLoggedIn(currentUser) && currentUser?.login !== assigneeLogin;
-
- const defaultOptions = allowCurrentUserSelection
- ? [
- UNASSIGNED,
- {
- value: currentUser.login,
- label: currentUser.name,
- Icon: renderAvatar(currentUser.name, currentUser.avatar),
- },
- ]
- : [UNASSIGNED];
-
- const controlLabel = assinedUser ? (
- <>
- {renderAvatar(assinedUser, assigneeAvatar)} {assinedUser}
- </>
- ) : (
- UNASSIGNED.label
- );
-
- const toggleAssign = (open?: boolean) => {
- props.togglePopup('assign', open);
- };
-
- const handleClose = () => {
- toggleAssign(false);
- };
-
- const handleSearchAssignees = (
- query: string,
- cb: (options: Options<LabelValueSelectOption<string>>) => void,
- ) => {
- getUsers<RestUser>({ q: query })
- .then((result) => {
- const options: Array<LabelValueSelectOption<string>> = result.users
- .filter(isUserActive)
- .map((u) => ({
- label: u.name ?? u.login,
- value: u.login,
- Icon: renderAvatar(u.name, u.avatar),
- }));
- cb(options);
- })
- .catch(() => {
- cb([]);
- });
- };
-
- const renderAssignee = () => {
- const { issue } = props;
- const assigneeName = (issue.assigneeActive && issue.assigneeName) || issue.assignee;
-
- if (assigneeName) {
- return (
- <span className="sw-flex sw-items-center sw-gap-1">
- <Avatar className="sw-mr-1" hash={issue.assigneeAvatar} name={assigneeName} size="xs" />
- <span className="sw-truncate sw-max-w-abs-300 fs-mask">
- {issue.assigneeActive
- ? assigneeName
- : translateWithParameters('user.x_deleted', assigneeName)}
- </span>
- </span>
- );
- }
-
- return <span className="sw-flex sw-items-center sw-gap-1">{translate('unassigned')}</span>;
- };
-
- const handleAssign = (userOption: SingleValue<LabelValueSelectOption<string>>) => {
- if (userOption) {
- props.onAssign(userOption.value);
- }
- };
-
- if (!canAssign) {
- return renderAssignee();
- }
-
- return (
- <div className="sw-relative">
- <SearchSelectDropdown
- size="medium"
- className="it__issue-assign"
- controlAriaLabel={
- assinedUser
- ? translateWithParameters('issue.assign.assigned_to_x_click_to_change', assinedUser)
- : translate('issue.assign.unassigned_click_to_assign')
- }
- defaultOptions={defaultOptions}
- onChange={handleAssign}
- loadOptions={handleSearchAssignees}
- menuIsOpen={props.isOpen}
- minLength={minSearchLength}
- onMenuOpen={() => toggleAssign(true)}
- onMenuClose={handleClose}
- isDiscreet
- controlLabel={controlLabel}
- placeholder={translate('search.search_for_users')}
- aria-label={translate('search.search_for_users')}
- zLevel={PopupZLevel.Absolute}
- />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueChangelogDiff.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueChangelogDiff.tsx
deleted file mode 100644
index 56626b5401f..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssueChangelogDiff.tsx
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { IssueChangelogDiff as TypeIssueChangelogDiff } from '../../../types/types';
-
-export interface IssueChangelogDiffProps {
- diff: TypeIssueChangelogDiff;
-}
-
-export default function IssueChangelogDiff({ diff }: Readonly<IssueChangelogDiffProps>) {
- const diffComputedValues = {
- newValue: diff.newValue ?? '',
- oldValue: diff.oldValue ?? '',
- };
-
- if (diff.key === 'file') {
- return (
- <p>
- {translateWithParameters(
- 'issue.change.file_move',
- diffComputedValues.oldValue,
- diffComputedValues.newValue,
- )}
- </p>
- );
- }
-
- if (['from_long_branch', 'from_branch'].includes(diff.key)) {
- return (
- <p>
- {translateWithParameters(
- 'issue.change.from_branch',
- diffComputedValues.oldValue,
- diffComputedValues.newValue,
- )}
- </p>
- );
- }
-
- if (diff.key === 'from_short_branch') {
- // Applies to both legacy short lived branch and pull request
- return (
- <p>
- {translateWithParameters(
- 'issue.change.from_non_branch',
- diffComputedValues.oldValue,
- diffComputedValues.newValue,
- )}
- </p>
- );
- }
-
- if (diff.key === 'line') {
- return (
- <p>
- {translateWithParameters('issue.changelog.line_removed_X', diffComputedValues.oldValue)}
- </p>
- );
- }
-
- if (diff.key === 'impactSeverity') {
- const [softwareQuality, newSeverity] = diffComputedValues.newValue.split(':');
- const [_, oldSeverity] = diffComputedValues.oldValue.split(':');
- return (
- <p>
- {translateWithParameters(
- 'issue.changelog.impactSeverity',
- softwareQuality,
- newSeverity,
- oldSeverity,
- )}
- </p>
- );
- }
-
- if (diff.key === 'effort') {
- diffComputedValues.newValue = formatMeasure(diff.newValue, 'WORK_DUR');
- diffComputedValues.oldValue = formatMeasure(diff.oldValue, 'WORK_DUR');
- }
-
- let message =
- diff.newValue !== undefined
- ? translateWithParameters(
- 'issue.changelog.changed_to',
- translate('issue.changelog.field', diff.key),
- diffComputedValues.newValue,
- )
- : translateWithParameters(
- 'issue.changelog.removed',
- translate('issue.changelog.field', diff.key),
- );
-
- if (diff.oldValue !== undefined) {
- message += ` (${translateWithParameters('issue.changelog.was', diffComputedValues.oldValue)})`;
- }
-
- return <p>{message}</p>;
-}
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueMessage.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueMessage.tsx
deleted file mode 100644
index 51b3b682d3a..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssueMessage.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { IssueMessageHighlighting, StandoutLink } from '~design-system';
-import { useLocation } from '~sonar-aligned/components/hoc/withRouter';
-import { getBranchLikeQuery } from '~sonar-aligned/helpers/branch-like';
-import { getComponentIssuesUrl } from '~sonar-aligned/helpers/urls';
-import { ComponentContext } from '../../../app/components/componentContext/ComponentContext';
-import { areMyIssuesSelected, parseQuery, serializeQuery } from '../../../apps/issues/utils';
-import { translate } from '../../../helpers/l10n';
-import { getIssuesUrl } from '../../../helpers/urls';
-import { BranchLike } from '../../../types/branch-like';
-import { Issue } from '../../../types/types';
-
-export interface IssueMessageProps {
- branchLike?: BranchLike;
- displayWhyIsThisAnIssue?: boolean;
- issue: Issue;
-}
-
-export default function IssueMessage(props: IssueMessageProps) {
- const { issue, branchLike, displayWhyIsThisAnIssue } = props;
- const location = useLocation();
- const query = parseQuery(location.query);
- const myIssuesSelected = areMyIssuesSelected(location.query);
-
- const { component } = React.useContext(ComponentContext);
-
- const { message, messageFormattings } = issue;
-
- const whyIsThisAnIssueUrl = getComponentIssuesUrl(issue.project, {
- ...getBranchLikeQuery(branchLike),
- files: issue.componentLongName,
- open: issue.key,
- why: '1',
- });
-
- const urlQuery = {
- ...getBranchLikeQuery(branchLike),
- ...serializeQuery(query),
- myIssues: myIssuesSelected ? 'true' : undefined,
- open: issue.key,
- };
-
- const issueUrl = component?.key
- ? getComponentIssuesUrl(component?.key, urlQuery)
- : getIssuesUrl(urlQuery);
-
- return (
- <>
- <StandoutLink className="it__issue-message" to={issueUrl}>
- <IssueMessageHighlighting message={message} messageFormattings={messageFormattings} />
- </StandoutLink>
-
- {displayWhyIsThisAnIssue && (
- <StandoutLink
- aria-label={translate('issue.why_this_issue.long')}
- target="_blank"
- className="sw-ml-2"
- to={whyIsThisAnIssueUrl}
- >
- {translate('issue.why_this_issue')}
- </StandoutLink>
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueMetaBar.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueMetaBar.tsx
deleted file mode 100644
index 2c82fefc519..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssueMetaBar.tsx
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import * as React from 'react';
-import { Badge, CommentIcon, SeparatorCircleIcon } from '~design-system';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { isDefined } from '../../../helpers/types';
-import { useStandardExperienceModeQuery } from '../../../queries/mode';
-import { useLocation } from '../../../sonar-aligned/components/hoc/withRouter';
-import { Issue } from '../../../types/types';
-import Tooltip from '../../controls/Tooltip';
-import DateFromNow from '../../intl/DateFromNow';
-import { WorkspaceContext } from '../../workspace/context';
-import IssuePrioritized from './IssuePrioritized';
-import IssueSeverity from './IssueSeverity';
-import IssueType from './IssueType';
-import SonarLintBadge from './SonarLintBadge';
-
-interface Props {
- issue: Issue;
- showLine?: boolean;
-}
-
-export default function IssueMetaBar(props: Readonly<Props>) {
- const { issue, showLine } = props;
- const location = useLocation();
-
- const { externalRulesRepoNames } = React.useContext(WorkspaceContext);
- const { data: isStandardMode } = useStandardExperienceModeQuery();
-
- const ruleEngine =
- (issue.externalRuleEngine && externalRulesRepoNames[issue.externalRuleEngine]) ||
- issue.externalRuleEngine;
-
- const hasComments = !!issue.comments?.length;
-
- const issueMetaListItemClassNames =
- 'sw-typo-sm sw-overflow-hidden sw-whitespace-nowrap sw-max-w-abs-150';
-
- return (
- <ul className="sw-flex sw-items-center sw-gap-1 sw-typo-sm sw-whitespace-nowrap">
- {issue.line && (
- <>
- <IssueMetaListItem className={issueMetaListItemClassNames}>
- L{issue.line}
- </IssueMetaListItem>
-
- <SeparatorCircleIcon aria-hidden as="li" />
- </>
- )}
-
- {issue.quickFixAvailable && (
- <>
- <li className={issueMetaListItemClassNames}>
- <SonarLintBadge compact />
- </li>
- <SeparatorCircleIcon aria-hidden as="li" />
- </>
- )}
-
- {ruleEngine && (
- <>
- <li className={issueMetaListItemClassNames}>
- <Tooltip
- content={translateWithParameters('issue.from_external_rule_engine', ruleEngine)}
- >
- <span>
- <Badge>{ruleEngine}</Badge>
- </span>
- </Tooltip>
- </li>
- <SeparatorCircleIcon aria-hidden as="li" />
- </>
- )}
-
- {!!issue.codeVariants?.length && (
- <>
- <IssueMetaListItem>
- <Tooltip content={issue.codeVariants.join(', ')}>
- <span>
- {issue.codeVariants.length > 1
- ? translateWithParameters('issue.x_code_variants', issue.codeVariants.length)
- : translate('issue.1_code_variant')}
- </span>
- </Tooltip>
- </IssueMetaListItem>
- <SeparatorCircleIcon aria-hidden as="li" />
- </>
- )}
-
- {hasComments && (
- <>
- <IssueMetaListItem
- className={classNames(issueMetaListItemClassNames, 'sw-flex sw-gap-1')}
- >
- <CommentIcon aria-label={translate('issue.comment.formlink')} />
- {issue.comments?.length}
- </IssueMetaListItem>
-
- <SeparatorCircleIcon aria-hidden as="li" />
- </>
- )}
-
- {showLine && isDefined(issue.textRange) && (
- <>
- <Tooltip content={translate('line_number')}>
- <IssueMetaListItem className={issueMetaListItemClassNames}>
- {translateWithParameters('issue.ncloc_x.short', issue.textRange.endLine)}
- </IssueMetaListItem>
- </Tooltip>
-
- <SeparatorCircleIcon aria-hidden as="li" />
- </>
- )}
-
- {issue.effort && (
- <>
- <IssueMetaListItem className={issueMetaListItemClassNames}>
- {translateWithParameters('issue.x_effort', issue.effort)}
- </IssueMetaListItem>
-
- <SeparatorCircleIcon aria-hidden as="li" />
- </>
- )}
-
- <IssueMetaListItem className={issueMetaListItemClassNames}>
- <DateFromNow date={issue.creationDate} />
- </IssueMetaListItem>
- {!isStandardMode && (location.query.types || location.query.severities) && (
- <>
- <SeparatorCircleIcon aria-hidden as="li" />
-
- <IssueType issue={issue} height={12} width={12} />
-
- <SeparatorCircleIcon data-guiding-id="issue-4" aria-hidden as="li" />
-
- <IssueSeverity issue={issue} height={12} width={12} />
- </>
- )}
-
- {issue.prioritizedRule && (
- <>
- <SeparatorCircleIcon aria-hidden as="li" />
-
- <IssueMetaListItem className={issueMetaListItemClassNames}>
- <IssuePrioritized />
- </IssueMetaListItem>
- </>
- )}
- </ul>
- );
-}
-
-const IssueMetaListItem = styled.li`
- color: var(--echoes-color-text-subdued);
-`;
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssuePrioritized.tsx b/server/sonar-web/src/main/js/components/issue/components/IssuePrioritized.tsx
deleted file mode 100644
index b9e8221b623..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssuePrioritized.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Tooltip } from '@sonarsource/echoes-react';
-import { TextSubdued } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-
-export default function IssuePrioritized() {
- return (
- <Tooltip content={translate('issue.prioritized_rule.description')}>
- <TextSubdued>{translate('prioritized')}</TextSubdued>
- </Tooltip>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueSeverity.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueSeverity.tsx
deleted file mode 100644
index 447718f0f1a..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssueSeverity.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Text } from '@sonarsource/echoes-react';
-import { IconProps } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { IssueSeverity as IssueSeverityType } from '../../../types/issues';
-import { Issue } from '../../../types/types';
-import SoftwareImpactSeverityIcon from '../../icon-mappers/SoftwareImpactSeverityIcon';
-
-interface Props extends IconProps {
- issue: Pick<Issue, 'severity'>;
-}
-
-export default function IssueSeverity({ issue, ...iconProps }: Readonly<Props>) {
- return (
- <Text isSubdued className="sw-flex sw-items-center sw-gap-1/2">
- <SoftwareImpactSeverityIcon
- aria-hidden
- disabled
- severity={issue.severity as IssueSeverityType}
- {...iconProps}
- />
- {translate('severity', issue.severity)}
- </Text>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueTags.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueTags.tsx
deleted file mode 100644
index cf677b0953a..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssueTags.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { PopupPlacement, Tags } from '~design-system';
-import { setIssueTags } from '../../../api/issues';
-import withComponentContext from '../../../app/components/componentContext/withComponentContext';
-import { translate } from '../../../helpers/l10n';
-import { ComponentContextShape } from '../../../types/component';
-import { Issue } from '../../../types/types';
-import Tooltip from '../../controls/Tooltip';
-import { updateIssue } from '../actions';
-import IssueTagsPopup from '../popups/IssueTagsPopup';
-
-interface Props extends ComponentContextShape {
- canSetTags?: boolean;
- issue: Pick<Issue, 'key' | 'tags'>;
- onChange: (issue: Issue) => void;
- open?: boolean;
- tagsToDisplay?: number;
- togglePopup: (popup: string, show?: boolean) => void;
-}
-
-export class IssueTags extends React.PureComponent<Props> {
- toggleSetTags = (open = false) => {
- this.props.togglePopup('edit-tags', open);
- };
-
- setTags = (tags: string[]) => {
- const { issue } = this.props;
- const newIssue = { ...issue, tags };
-
- updateIssue(
- this.props.onChange,
- setIssueTags({ issue: issue.key, tags: tags.join(',') }),
- issue as Issue,
- newIssue as Issue,
- );
- };
-
- handleClose = () => {
- this.toggleSetTags(false);
- };
-
- render() {
- const { component, issue, open, tagsToDisplay = 2 } = this.props;
- const { tags = [] } = issue;
-
- return (
- <Tags
- allowUpdate={this.props.canSetTags && !component?.needIssueSync}
- ariaTagsListLabel={translate('issue.tags')}
- className="js-issue-edit-tags sw-typo-sm"
- tagsClassName="sw-typo-sm"
- emptyText={translate('issue.no_tag')}
- menuId="issue-tags-menu"
- onClose={this.handleClose}
- open={open}
- overlay={<IssueTagsPopup selectedTags={tags} setTags={this.setTags} />}
- popupPlacement={PopupPlacement.Bottom}
- tags={tags}
- tagsToDisplay={tagsToDisplay}
- tooltip={Tooltip}
- />
- );
- }
-}
-
-export default withComponentContext(IssueTags);
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.tsx
deleted file mode 100644
index 6dc99bd093d..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useStandardExperienceModeQuery } from '../../../queries/mode';
-import { BranchLike } from '../../../types/branch-like';
-import { Issue } from '../../../types/types';
-import { CleanCodeAttributePill } from '../../shared/CleanCodeAttributePill';
-import IssueMessage from './IssueMessage';
-
-export interface IssueTitleBarProps {
- branchLike?: BranchLike;
- displayWhyIsThisAnIssue?: boolean;
- issue: Issue;
-}
-
-export default function IssueTitleBar(props: Readonly<IssueTitleBarProps>) {
- const { issue, displayWhyIsThisAnIssue, branchLike } = props;
- const { data: isStandardMode } = useStandardExperienceModeQuery();
-
- return (
- <div className="sw-mt-1 sw-flex sw-items-start sw-justify-between sw-gap-8">
- <div className="sw-w-fit">
- <IssueMessage
- issue={issue}
- branchLike={branchLike}
- displayWhyIsThisAnIssue={displayWhyIsThisAnIssue}
- />
- </div>
-
- {!isStandardMode && (
- <CleanCodeAttributePill cleanCodeAttributeCategory={issue.cleanCodeAttributeCategory} />
- )}
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueTransition.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueTransition.tsx
deleted file mode 100644
index 01bb1ad3841..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssueTransition.tsx
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import * as React from 'react';
-import {
- Dropdown,
- DropdownMenuWrapper,
- ItemDivider,
- PopupPlacement,
- PopupZLevel,
- SearchSelectDropdownControl,
-} from '~design-system';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { useIssueCommentMutation, useIssueTransitionMutation } from '../../../queries/issues';
-import { Issue } from '../../../types/types';
-import StatusHelper from '../../shared/StatusHelper';
-import { updateIssue } from '../actions';
-import { IssueTransitionOverlay } from './IssueTransitionOverlay';
-
-interface Props {
- isOpen: boolean;
- issue: Pick<Issue, 'key' | 'resolution' | 'issueStatus' | 'transitions' | 'type' | 'actions'>;
- onChange: (issue: Issue) => void;
- togglePopup: (popup: string, show?: boolean) => void;
-}
-
-export default function IssueTransition(props: Readonly<Props>) {
- const { isOpen, issue, onChange, togglePopup } = props;
-
- const [transitioning, setTransitioning] = React.useState(false);
- const { mutateAsync: setIssueTransition } = useIssueTransitionMutation();
- const { mutateAsync: addIssueComment } = useIssueCommentMutation();
-
- async function handleSetTransition(transition: string, comment?: string) {
- setTransitioning(true);
-
- try {
- if (typeof comment === 'string' && comment.length > 0) {
- await setIssueTransition({ issue: issue.key, transition });
- await updateIssue(onChange, addIssueComment({ issue: issue.key, text: comment }));
- } else {
- await updateIssue(onChange, setIssueTransition({ issue: issue.key, transition }));
- }
- togglePopup('transition', false);
- } finally {
- setTransitioning(false);
- }
- }
-
- function handleClose() {
- togglePopup('transition', false);
- }
-
- function onToggleClick() {
- togglePopup('transition', !isOpen);
- }
-
- if (issue.transitions?.length) {
- return (
- <StyledDropdown
- allowResizing
- closeOnClick={false}
- id="issue-transition"
- onClose={handleClose}
- openDropdown={isOpen}
- overlay={
- <IssueTransitionOverlay
- issue={issue}
- onClose={handleClose}
- onSetTransition={handleSetTransition}
- loading={transitioning}
- />
- }
- placement={PopupPlacement.Bottom}
- zLevel={PopupZLevel.Absolute}
- size="full"
- >
- {({ a11yAttrs }) => (
- <SearchSelectDropdownControl
- {...a11yAttrs}
- onClick={onToggleClick}
- onClear={handleClose}
- isDiscreet
- className="it__issue-transition sw-px-1"
- label={
- <StatusHelper className="sw-flex sw-items-center" issueStatus={issue.issueStatus} />
- }
- ariaLabel={translateWithParameters(
- 'issue.transition.status_x_click_to_change',
- translate('issue.issue_status', issue.issueStatus),
- )}
- />
- )}
- </StyledDropdown>
- );
- }
-
- return <StatusHelper issueStatus={issue.issueStatus} />;
-}
-
-const StyledDropdown = styled(Dropdown)`
- overflow: auto;
-
- & ${DropdownMenuWrapper} {
- border-radius: 8px;
-
- ${ItemDivider} {
- margin-left: 0;
- margin-right: 0;
- }
- }
-`;
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueTransitionItem.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueTransitionItem.tsx
deleted file mode 100644
index 604fa6f5c3c..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssueTransitionItem.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { IconArrowRight, IconQuestionMark } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { useIntl } from 'react-intl';
-import { ItemButton, PageContentFontWrapper, TextBold, TextMuted } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
-import { IssueTransition } from '../../../types/issues';
-
-type Props = {
- hasCommentAction?: boolean;
- onSelectTransition: (transition: IssueTransition) => void;
- selected: boolean;
- transition: IssueTransition;
-};
-
-export function IssueTransitionItem({
- transition,
- selected,
- onSelectTransition,
- hasCommentAction = false,
-}: Readonly<Props>) {
- const intl = useIntl();
-
- const tooltips: Record<string, React.JSX.Element> = {
- [IssueTransition.Confirm]: (
- <div className="sw-flex sw-flex-col sw-gap-2">
- <span>{translate('issue.transition.confirm.deprecated_tooltip.1')}</span>
- <span>{translate('issue.transition.confirm.deprecated_tooltip.2')}</span>
- <span>{translate('issue.transition.confirm.deprecated_tooltip.3')}</span>
- </div>
- ),
- [IssueTransition.Resolve]: (
- <div className="sw-flex sw-flex-col sw-gap-2">
- <span>{translate('issue.transition.resolve.deprecated_tooltip.1')}</span>
- <span>{translate('issue.transition.resolve.deprecated_tooltip.2')}</span>
- <span>{translate('issue.transition.resolve.deprecated_tooltip.3')}</span>
- </div>
- ),
- };
-
- return (
- <ItemButton
- key={transition}
- onClick={() => onSelectTransition(transition)}
- selected={selected}
- className="sw-flex sw-items-center sw-justify-between sw-px-4"
- >
- <div className="it__issue-transition-option sw-flex sw-flex-col">
- <PageContentFontWrapper className="sw-font-semibold sw-flex sw-gap-1 sw-items-center">
- <TextBold name={intl.formatMessage({ id: `issue.transition.${transition}` })} />
- {tooltips[transition] && (
- <HelpTooltip overlay={tooltips[transition]} placement="right">
- <IconQuestionMark />
- </HelpTooltip>
- )}
- </PageContentFontWrapper>
- <TextMuted text={translate('issue.transition', transition, 'description')} />
- </div>
- {hasCommentAction && <IconArrowRight />}
- </ItemButton>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueTransitionOverlay.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueTransitionOverlay.tsx
deleted file mode 100644
index ddd3899df97..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssueTransitionOverlay.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, ButtonVariety, DropdownMenu, Spinner } from '@sonarsource/echoes-react';
-import { useState } from 'react';
-import { InputTextArea } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { IssueActions, IssueTransition } from '../../../types/issues';
-import { Issue } from '../../../types/types';
-import { isTransitionHidden, transitionRequiresComment } from '../helpers';
-import { IssueTransitionItem } from './IssueTransitionItem';
-import IssueTransitionOverlayHeader from './IssueTransitionOverlayHeader';
-import { SelectedTransitionItem } from './SelectedTransitionItem';
-
-export type Props = {
- issue: Pick<Issue, 'transitions' | 'actions'>;
- loading?: boolean;
- onClose: () => void;
- onSetTransition: (transition: IssueTransition, comment?: string) => void;
-};
-
-export function IssueTransitionOverlay(props: Readonly<Props>) {
- const { issue, onClose, onSetTransition, loading } = props;
-
- const [comment, setComment] = useState('');
- const [selectedTransition, setSelectedTransition] = useState<IssueTransition>();
-
- const hasCommentAction = issue.actions.includes(IssueActions.Comment);
-
- function selectTransition(transition: IssueTransition) {
- if (!transitionRequiresComment(transition) || !hasCommentAction) {
- onSetTransition(transition);
- } else {
- setSelectedTransition(transition);
- }
- }
-
- function handleResolve() {
- if (selectedTransition) {
- onSetTransition(selectedTransition, comment);
- }
- }
-
- // Filter out hidden transitions and separate deprecated transitions in a different list
- const filteredTransitions = issue.transitions.filter(
- (transition) => !isTransitionHidden(transition),
- );
-
- return (
- <Spinner isLoading={!selectedTransition && loading} className="sw-ml-4">
- <IssueTransitionOverlayHeader
- onBack={() => setSelectedTransition(undefined)}
- onClose={onClose}
- selected={Boolean(selectedTransition)}
- />
- <DropdownMenu.Separator />
- <ul className="sw-flex sw-flex-col">
- {!selectedTransition &&
- filteredTransitions.map((transition, index) => (
- <div key={transition}>
- <IssueTransitionItem
- transition={transition}
- selected={selectedTransition === transition}
- hasCommentAction={transitionRequiresComment(transition)}
- onSelectTransition={selectTransition}
- />
- {index !== filteredTransitions.length - 1 && <DropdownMenu.Separator />}
- </div>
- ))}
-
- {selectedTransition && (
- <>
- <SelectedTransitionItem transition={selectedTransition} />
- <DropdownMenu.Separator />
- <div className="sw-mx-3 sw-mt-2">
- <div className="sw-font-semibold">{translate('issue.transition.comment')}</div>
- <div className="sw-flex sw-flex-col">
- <InputTextArea
- autoFocus
- className="sw-mt-2 sw-resize"
- onChange={(event) => setComment(event.currentTarget.value)}
- placeholder={translate(
- 'issue.transition.comment.placeholder',
- selectedTransition ?? '',
- )}
- rows={3}
- size="large"
- value={comment}
- />
- </div>
- <div className="sw-mt-2 sw-flex sw-gap-3 sw-justify-end">
- <Button variety={ButtonVariety.Primary} onClick={handleResolve}>
- {translate('issue.transition.change_status')}
- </Button>
- <Button variety={ButtonVariety.Default} onClick={onClose}>
- {translate('cancel')}
- </Button>
- </div>
- </div>
- </>
- )}
- </ul>
- </Spinner>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueTransitionOverlayHeader.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueTransitionOverlayHeader.tsx
deleted file mode 100644
index f28cbd4c2a9..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssueTransitionOverlayHeader.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ButtonIcon, ButtonVariety, IconArrowLeft, IconX } from '@sonarsource/echoes-react';
-import { translate } from '../../../helpers/l10n';
-
-interface Props {
- onBack: VoidFunction;
- onClose: VoidFunction;
- selected: boolean;
-}
-
-export default function IssueTransitionOverlayHeader({
- onBack,
- onClose,
- selected,
-}: Readonly<Props>) {
- if (selected) {
- return (
- <div className="sw-flex sw-items-center sw-gap-2 sw-px-3 sw-mb-1">
- <ButtonIcon
- Icon={IconArrowLeft}
- ariaLabel={translate('go_back')}
- className="sw-flex sw-justify-center sw-p-0"
- onClick={onBack}
- variety={ButtonVariety.DefaultGhost}
- />
- <span className="sw-font-semibold">
- {translate('issue.transition.go_back_change_status')}
- </span>
- </div>
- );
- }
-
- return (
- <div className="sw-flex sw-justify-between sw-items-center sw-px-3 sw-mb-1">
- <span className="sw-font-semibold">{translate('issue.transition.status_change')}</span>
- <ButtonIcon
- Icon={IconX}
- ariaLabel={translate('close')}
- className="sw-flex sw-justify-center sw-p-0"
- onClick={onClose}
- variety={ButtonVariety.DefaultGhost}
- />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueType.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueType.tsx
deleted file mode 100644
index a5b4d54ca54..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssueType.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Text } from '@sonarsource/echoes-react';
-import { IconProps } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { Issue } from '../../../types/types';
-import IssueTypeIcon from '../../icon-mappers/IssueTypeIcon';
-
-interface Props extends IconProps {
- issue: Pick<Issue, 'type'>;
-}
-
-export default function IssueType({ issue, ...iconProps }: Readonly<Props>) {
- return (
- <Text isSubdued className="sw-flex sw-items-center sw-gap-1/2">
- <IssueTypeIcon
- aria-hidden
- fill="var(--echoes-color-icon-disabled)"
- type={issue.type}
- {...iconProps}
- />
- {translate('issue.type', issue.type)}
- </Text>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueView.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueView.tsx
deleted file mode 100644
index 14f0a1b5027..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/IssueView.tsx
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { Checkbox, Link, LinkHighlight } from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import { useEffect, useRef } from 'react';
-import { FormattedMessage, useIntl } from 'react-intl';
-import { addGlobalSuccessMessage, BasicSeparator, themeBorder } from '~design-system';
-import { setIssueSeverity } from '../../../api/issues';
-import { useComponent } from '../../../app/components/componentContext/withComponentContext';
-import { areMyIssuesSelected, parseQuery, serializeQuery } from '../../../apps/issues/utils';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { getIssuesUrl } from '../../../helpers/urls';
-import { useLocation } from '../../../sonar-aligned/components/hoc/withRouter';
-import { getBranchLikeQuery } from '../../../sonar-aligned/helpers/branch-like';
-import { getComponentIssuesUrl } from '../../../sonar-aligned/helpers/urls';
-import { BranchLike } from '../../../types/branch-like';
-import { SoftwareImpactSeverity, SoftwareQuality } from '../../../types/clean-code-taxonomy';
-import { IssueActions, IssueSeverity } from '../../../types/issues';
-import { Issue } from '../../../types/types';
-import SoftwareImpactPillList from '../../shared/SoftwareImpactPillList';
-import { updateIssue } from '../actions';
-import IssueActionsBar from './IssueActionsBar';
-import IssueMetaBar from './IssueMetaBar';
-import IssueTags from './IssueTags';
-import IssueTitleBar from './IssueTitleBar';
-
-interface Props {
- branchLike?: BranchLike;
- checked?: boolean;
- currentPopup?: string;
- displayWhyIsThisAnIssue?: boolean;
- issue: Issue;
- onAssign: (login: string) => void;
- onChange: (issue: Issue) => void;
- onCheck?: (issue: string) => void;
- onSelect: (issueKey: string) => void;
- selected: boolean;
- togglePopup: (popup: string, show: boolean | void) => void;
-}
-
-export default function IssueView(props: Readonly<Props>) {
- const {
- issue,
- branchLike,
- checked,
- currentPopup,
- displayWhyIsThisAnIssue,
- onAssign,
- onChange,
- onSelect,
- togglePopup,
- selected,
- onCheck,
- } = props;
- const intl = useIntl();
- const nodeRef = useRef<HTMLLIElement>(null);
- const { component } = useComponent();
- const location = useLocation();
- const query = parseQuery(location.query);
-
- const hasCheckbox = onCheck != null;
- const canSetTags = issue.actions.includes(IssueActions.SetTags);
- const canSetSeverity = issue.actions.includes(IssueActions.SetSeverity);
-
- const handleCheck = () => {
- if (onCheck) {
- onCheck(issue.key);
- }
- };
-
- const setSeverity = (
- severity: IssueSeverity | SoftwareImpactSeverity,
- quality?: SoftwareQuality,
- ) => {
- const { issue } = props;
-
- const data = quality
- ? { issue: issue.key, impact: `${quality}=${severity}` }
- : { issue: issue.key, severity: severity as IssueSeverity };
-
- const severityBefore = quality
- ? issue.impacts.find((impact) => impact.softwareQuality === quality)?.severity
- : issue.severity;
-
- const linkQuery = {
- ...getBranchLikeQuery(branchLike),
- ...serializeQuery(query),
- myIssues: areMyIssuesSelected(location.query) ? 'true' : undefined,
- open: issue.key,
- };
-
- return updateIssue(
- onChange,
- setIssueSeverity(data).then((r) => {
- addGlobalSuccessMessage(
- <FormattedMessage
- id="issue.severity.updated_notification"
- values={{
- issueLink: (
- <Link
- highlight={LinkHighlight.Default}
- to={
- component
- ? getComponentIssuesUrl(component.key, linkQuery)
- : getIssuesUrl(linkQuery)
- }
- >
- {intl.formatMessage(
- {
- id: `issue.severity.updated_notification.link.${!quality ? 'standard' : 'mqr'}`,
- },
- {
- type: translate('issue.type', issue.type).toLowerCase(),
- },
- )}
- </Link>
- ),
- quality: quality ? translate('software_quality', quality) : undefined,
- before: translate(quality ? 'severity_impact' : 'severity', severityBefore ?? ''),
- after: translate(quality ? 'severity_impact' : 'severity', severity),
- }}
- />,
- );
-
- return r;
- }),
- );
- };
- useEffect(() => {
- if (selected && nodeRef.current) {
- nodeRef.current.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });
- }
- }, [selected]);
-
- return (
- <IssueItem
- onClick={() => onSelect(issue.key)}
- className={classNames('it__issue-item sw-p-3 sw-mb-4 sw-rounded-1 sw-bg-white', {
- selected,
- })}
- ref={nodeRef}
- >
- <section aria-label={issue.message} className="sw-flex sw-gap-3">
- {hasCheckbox && (
- <span className="sw-mt-1/2 sw-ml-1 sw-self-start">
- <Checkbox
- ariaLabel={translateWithParameters('issues.action_select.label', issue.message)}
- checked={checked ?? false}
- onCheck={handleCheck}
- title={translate('issues.action_select')}
- />
- </span>
- )}
-
- <div className="sw-flex sw-flex-col sw-grow sw-gap-3 sw-min-w-0">
- <IssueTitleBar
- branchLike={branchLike}
- displayWhyIsThisAnIssue={displayWhyIsThisAnIssue}
- issue={issue}
- />
-
- <div className="sw-mt-1 sw-flex sw-items-start sw-justify-between">
- <SoftwareImpactPillList
- data-guiding-id="issue-2"
- softwareImpacts={issue.impacts}
- onSetSeverity={canSetSeverity ? setSeverity : undefined}
- issueSeverity={issue.severity as IssueSeverity}
- issueType={issue.type}
- />
- <div className="sw-grow-0 sw-whitespace-nowrap">
- <IssueTags
- issue={issue}
- onChange={onChange}
- togglePopup={togglePopup}
- canSetTags={canSetTags}
- open={currentPopup === 'edit-tags' && canSetTags}
- />
- </div>
- </div>
-
- <BasicSeparator />
-
- <div className="sw-flex sw-gap-2 sw-flex-nowrap sw-items-center sw-justify-between">
- <IssueActionsBar
- currentPopup={currentPopup}
- issue={issue}
- onAssign={onAssign}
- onChange={onChange}
- togglePopup={togglePopup}
- />
- <IssueMetaBar issue={issue} />
- </div>
- </div>
- </section>
- </IssueItem>
- );
-}
-
-const IssueItem = styled.li`
- outline: ${themeBorder('default', 'almCardBorder')};
- outline-offset: -1px;
-
- &.selected {
- outline: ${themeBorder('heavy', 'primary')};
- outline-offset: -2px;
- }
-`;
diff --git a/server/sonar-web/src/main/js/components/issue/components/SelectedTransitionItem.tsx b/server/sonar-web/src/main/js/components/issue/components/SelectedTransitionItem.tsx
deleted file mode 100644
index d5d9e9ab8c5..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/SelectedTransitionItem.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { IconCheck } from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import { noop } from 'lodash';
-import { ItemButton, Note } from '../../../design-system';
-import { translate } from '../../../helpers/l10n';
-import DocHelpTooltip from '../../../sonar-aligned/components/controls/DocHelpTooltip';
-import { IssueTransition } from '../../../types/issues';
-import { isTransitionDeprecated } from '../helpers';
-
-interface Props {
- transition: IssueTransition;
-}
-
-export function SelectedTransitionItem({ transition }: Readonly<Props>) {
- return (
- <ItemButton className={classNames('sw-px-3 selected')} key={transition} onClick={noop}>
- <IconCheck className="sw-mr-2" />
- <div className="sw-flex">
- <div className="sw-flex sw-flex-col">
- <div className="sw-font-semibold sw-flex sw-gap-1 sw-items-center">
- {translate('issue.transition', transition)}
- {isTransitionDeprecated(transition) && (
- <DocHelpTooltip
- className="sw-ml-1"
- content={translate('issue.transition', transition, 'deprecated_tooltip')}
- />
- )}
- </div>
- <Note className="sw-whitespace-break-spaces">
- {translate('issue.transition', transition, 'description')}
- </Note>
- </div>
- </div>
- </ItemButton>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/issue/components/SonarLintBadge.tsx b/server/sonar-web/src/main/js/components/issue/components/SonarLintBadge.tsx
deleted file mode 100644
index c67ce5ddd1f..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/SonarLintBadge.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkHighlight, LinkStandalone } from '@sonarsource/echoes-react';
-import { FormattedMessage } from 'react-intl';
-import { translate } from '../../../helpers/l10n';
-import Link from '../../common/Link';
-import Tooltip from '../../controls/Tooltip';
-import { SonarLintLogo } from '../../logos/SonarLintLogo';
-
-const SONARLINT_URL =
- 'https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=sonarqube-quick-fix';
-
-interface Props {
- compact?: boolean;
-}
-
-export default function SonarLintBadge({ compact }: Readonly<Props>) {
- return compact ? <SonarLintBadgeCompact /> : <SonarLintBadgeFull />;
-}
-
-function SonarLintBadgeFull() {
- return (
- <Tooltip
- content={translate('issue.quick_fix_available_with_sonarlint_no_link')}
- mouseLeaveDelay={0.5}
- >
- <LinkStandalone
- className="sw-flex sw-items-center"
- highlight={LinkHighlight.Default}
- iconLeft={
- <SonarLintLogo
- className="it__issues-sonarlint-quick-fix"
- size={20}
- description={translate('issue.quick_fix_available_with_sonarlint_no_link')}
- />
- }
- shouldOpenInNewTab
- to={SONARLINT_URL}
- >
- {translate('issue.quick_fix')}
- </LinkStandalone>
- </Tooltip>
- );
-}
-
-function SonarLintBadgeCompact() {
- return (
- <Tooltip
- content={
- <FormattedMessage
- id="issue.quick_fix_available_with_sonarlint"
- defaultMessage={translate('issue.quick_fix_available_with_sonarlint')}
- values={{
- link: (
- <Link to={SONARLINT_URL} target="_blank">
- SonarLint
- </Link>
- ),
- }}
- />
- }
- mouseLeaveDelay={0.5}
- >
- <div className="sw-flex sw-items-center">
- <SonarLintLogo
- className="it__issues-sonarlint-quick-fix"
- size={15}
- description={translate('issue.quick_fix_available_with_sonarlint_no_link')}
- />
- </div>
- </Tooltip>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueChangelogDiff-test.tsx b/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueChangelogDiff-test.tsx
deleted file mode 100644
index 28710fab0d0..00000000000
--- a/server/sonar-web/src/main/js/components/issue/components/__tests__/IssueChangelogDiff-test.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { mockIssueChangelogDiff } from '../../../../helpers/mocks/issues';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import IssueChangelogDiff, { IssueChangelogDiffProps } from '../IssueChangelogDiff';
-
-jest.mock('~sonar-aligned/helpers/measures', () => ({
- formatMeasure: jest
- .fn()
- .mockImplementation((value: string, type: string) => `formatted.${value}.as.${type}`),
-}));
-
-it.each([
- ['file', 'issue.change.file_move.oldValue.newValue', undefined],
- ['from_branch', 'issue.change.from_branch.oldValue.newValue', undefined],
- ['line', 'issue.changelog.line_removed_X.oldValue', undefined],
- [
- 'effort',
- 'issue.changelog.changed_to.issue.changelog.field.effort.formatted.12.as.WORK_DUR',
- { newValue: '12', oldValue: undefined },
- ],
- [
- 'effort',
- 'issue.changelog.removed.issue.changelog.field.effort (issue.changelog.was.formatted.14.as.WORK_DUR)',
- { newValue: undefined, oldValue: '14' },
- ],
- [
- 'effort',
- 'issue.changelog.removed.issue.changelog.field.effort',
- { newValue: undefined, oldValue: undefined },
- ],
- [
- 'assign',
- 'issue.changelog.changed_to.issue.changelog.field.assign.newValue (issue.changelog.was.oldValue)',
- undefined,
- ],
- ['from_short_branch', 'issue.change.from_non_branch.oldValue.newValue', undefined],
-
- // This should be deprecated. Can this still happen?
- ['from_long_branch', 'issue.change.from_branch.oldValue.newValue', undefined],
-])(
- 'should render correctly for "%s" diff types',
- (key, expected, diff?: Partial<IssueChangelogDiffProps['diff']>) => {
- renderIssueChangelogDiff({
- diff: mockIssueChangelogDiff({ key, newValue: 'newValue', oldValue: 'oldValue', ...diff }),
- });
- expect(screen.getByText(expected)).toBeInTheDocument();
- },
-);
-
-function renderIssueChangelogDiff(props: Partial<IssueChangelogDiffProps> = {}) {
- return renderComponent(<IssueChangelogDiff diff={mockIssueChangelogDiff()} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/components/issue/helpers.ts b/server/sonar-web/src/main/js/components/issue/helpers.ts
deleted file mode 100644
index a8bd5cec665..00000000000
--- a/server/sonar-web/src/main/js/components/issue/helpers.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { IssueTransition } from '../../types/issues';
-
-export function isTransitionDeprecated(transition: IssueTransition) {
- return transition === IssueTransition.Confirm || transition === IssueTransition.Resolve;
-}
-
-export function isTransitionHidden(transition: IssueTransition) {
- return transition === IssueTransition.WontFix;
-}
-
-export function transitionRequiresComment(transition: IssueTransition) {
- return [IssueTransition.Accept, IssueTransition.FalsePositive].includes(transition);
-}
diff --git a/server/sonar-web/src/main/js/components/issue/popups/IssueTagsPopup.tsx b/server/sonar-web/src/main/js/components/issue/popups/IssueTagsPopup.tsx
deleted file mode 100644
index ba29278d1e7..00000000000
--- a/server/sonar-web/src/main/js/components/issue/popups/IssueTagsPopup.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { difference, noop, without } from 'lodash';
-import * as React from 'react';
-import { MultiSelector } from '~design-system';
-import { searchIssueTags } from '../../../api/issues';
-import { translate } from '../../../helpers/l10n';
-
-interface IssueTagsPopupProps {
- selectedTags: string[];
- setTags: (tags: string[]) => void;
-}
-
-function IssueTagsPopup({ selectedTags, setTags }: IssueTagsPopupProps) {
- const [searchResult, setSearchResult] = React.useState<string[]>([]);
- const LIST_SIZE = 10;
-
- function onSearch(query: string) {
- return searchIssueTags({
- q: query,
- ps: Math.min(selectedTags.length - 1 + LIST_SIZE, 100),
- }).then((tags: string[]) => {
- setSearchResult(tags);
- }, noop);
- }
-
- function onSelect(tag: string) {
- setTags([...selectedTags, tag]);
- }
-
- function onUnselect(tag: string) {
- setTags(without(selectedTags, tag));
- }
-
- const availableTags = difference(searchResult, selectedTags);
-
- return (
- <MultiSelector
- headerLabel={translate('issue.tags')}
- searchInputAriaLabel={translate('search.search_for_tags')}
- createElementLabel={translate('issue.create_tag')}
- noResultsLabel={translate('no_results')}
- onSearch={onSearch}
- onSelect={onSelect}
- onUnselect={onUnselect}
- selectedElements={selectedTags}
- elements={availableTags}
- />
- );
-}
-
-export default IssueTagsPopup;
diff --git a/server/sonar-web/src/main/js/components/locations/SingleFileLocationNavigator.css b/server/sonar-web/src/main/js/components/locations/SingleFileLocationNavigator.css
deleted file mode 100644
index 7db34335f2a..00000000000
--- a/server/sonar-web/src/main/js/components/locations/SingleFileLocationNavigator.css
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-button.locations-navigator {
- display: flex;
- align-items: flex-start;
- border: 1px solid transparent;
- border-radius: 4px;
- padding: calc(1 / 2 * 8px);
- margin-bottom: calc(1 / 4 * 8px);
- color: inherit;
- text-align: left;
-}
-
-button.locations-navigator:hover,
-button.locations-navigator:active {
- border-color: #4b9fd5;
-}
-
-button.locations-navigator:focus {
- border-color: transparent;
-}
-
-button.locations-navigator.selected {
- border-color: #4b9fd5;
- background-color: #ecf6fe;
-}
diff --git a/server/sonar-web/src/main/js/components/locations/SingleFileLocationNavigator.tsx b/server/sonar-web/src/main/js/components/locations/SingleFileLocationNavigator.tsx
deleted file mode 100644
index c1f70579984..00000000000
--- a/server/sonar-web/src/main/js/components/locations/SingleFileLocationNavigator.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import * as React from 'react';
-import { IssueMessageHighlighting, LocationMarker, StyledMarker, themeColor } from '~design-system';
-import { translateWithParameters } from '../../helpers/l10n';
-import { MessageFormatting } from '../../types/issues';
-import LocationMessage from '../common/LocationMessage';
-import './SingleFileLocationNavigator.css';
-
-interface Props {
- concealedMarker?: boolean;
- index: number;
- message: string | undefined;
- messageFormattings?: MessageFormatting[];
- onClick: (index: number) => void;
- selected: boolean;
-}
-
-export default class SingleFileLocationNavigator extends React.PureComponent<Props> {
- node?: HTMLElement | null;
-
- componentDidMount() {
- if (this.props.selected && this.node) {
- this.node.scrollIntoView({
- behavior: 'smooth',
- block: 'center',
- inline: 'center',
- });
- }
- }
-
- componentDidUpdate(prevProps: Props) {
- if (this.props.selected && prevProps.selected !== this.props.selected && this.node) {
- this.node.scrollIntoView({
- behavior: 'smooth',
- block: 'center',
- inline: 'center',
- });
- }
- }
-
- handleClick = () => {
- this.props.onClick(this.props.index);
- };
-
- render() {
- const { index, concealedMarker, message, messageFormattings, selected } = this.props;
-
- return (
- <StyledButton
- onClick={this.handleClick}
- aria-current={selected ? 'location' : false}
- className={classNames('sw-p-1 sw-flex sw-items-center sw-gap-2', {
- selected,
- })}
- ref={(n) => (this.node = n)}
- >
- <LocationMarker selected={selected} text={concealedMarker ? undefined : index + 1} />
- <LocationMessage>
- {message ? (
- <IssueMessageHighlighting message={message} messageFormattings={messageFormattings} />
- ) : (
- translateWithParameters('issue.location_x', index + 1)
- )}
- </LocationMessage>
- </StyledButton>
- );
- }
-}
-
-const StyledButton = styled.button`
- color: ${themeColor('pageContent')};
- cursor: pointer;
- outline: none;
- border: none;
- background: transparent;
-
- &.selected,
- &:hover,
- &:focus {
- background-color: ${themeColor('subnavigationSelected')};
- }
-
- &:hover ${StyledMarker} {
- background-color: ${themeColor('codeLineLocationMarkerSelected')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/components/logos/SonarLintLogo.tsx b/server/sonar-web/src/main/js/components/logos/SonarLintLogo.tsx
deleted file mode 100644
index b50a0b02dd7..00000000000
--- a/server/sonar-web/src/main/js/components/logos/SonarLintLogo.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { uniqueId } from 'lodash';
-import * as React from 'react';
-import { isDefined } from '../../helpers/types';
-
-interface Props {
- className?: string;
- description?: React.ReactNode;
- size?: number;
-}
-
-export function SonarLintLogo({ className, description, size }: Readonly<Props>) {
- const id = uniqueId('icon');
- return (
- <svg
- className={className}
- height={size}
- style={{
- fillRule: 'evenodd',
- clipRule: 'evenodd',
- strokeLinejoin: 'round',
- strokeMiterlimit: 1.41421,
- }}
- version="1.1"
- viewBox="0 0 512 512"
- width={size}
- xmlnsXlink="http://www.w3.org/1999/xlink"
- xmlSpace="preserve"
- aria-describedby={isDefined(description) && description !== '' ? id : undefined}
- >
- {isDefined(description) && description !== '' && <desc id={id}>{description}</desc>}
- <defs>
- <path id="a" d="M0 0h512v512H0z" />
- </defs>
- <clipPath id="b">
- <use xlinkHref="#a" style={{ overflow: 'visible' }} />
- </clipPath>
- <path
- d="M255.7 450.7c-107.8 0-195.5-87.6-195.5-195.3 0-107.7 87.7-195.3 195.5-195.3s195.5 87.6 195.5 195.3c0 107.7-87.7 195.3-195.5 195.3m0-355.2c-88.2 0-160 71.7-160 159.8 0 88.1 71.8 159.8 160 159.8s160-71.7 160-159.8c0-88.1-71.8-159.8-160-159.8"
- style={{ clipPath: 'url(#b)', fill: '#cb2029' }}
- />
- <path
- d="M392.6 244.9c-5.1-10.2-11.5-23-24.1-23-12.5 0-18.9 12.7-24.1 23-4.8 9.5-7.5 14.5-13.5 14.5s-8.7-5-13.5-14.5c-5.1-10.2-11.5-23-24.1-23s-18.9 12.7-24.1 23c-4.8 9.5-7.5 14.5-13.5 14.5s-8.7-5-13.5-14.5c-5.1-10.2-11.5-23-24.1-23s-18.9 12.7-24.1 23c-4.8 9.5-7.5 14.5-13.5 14.5s-8.7-5-13.5-14.5c-5.1-10.2-11.5-23-24.1-23-12.5 0-18.9 12.1-24 22.3 0 0-3.9 8.7-5.6 12.8-1.7 4.1-8.3 19.7-2.3 27.2 3.4 4.2 8.3-1.8 11.1-6.2 2.1-3.4 7.1-13.2 7.1-13.2 5.1-9.1 7.8-14 13.7-14 6 0 8.7 5 13.5 14.5 5.1 10.2 11.5 23 24.1 23 12.5 0 18.9-12.7 24.1-23 4.8-9.5 7.5-14.5 13.5-14.5s8.7 5 13.5 14.5c5.1 10.2 11.5 23 24.1 23 12.5 0 18.9-12.7 24.1-23 4.8-9.5 7.5-14.5 13.5-14.5s8.7 5 13.5 14.5c5.1 10.2 11.5 23 24.1 23s18.9-12.7 24.1-23c4.8-9.5 7.5-14.5 13.5-14.5s8.7 5 13.5 14.5c0 0 2.2 4.3 5.4 9.9 1.4 2.3 6.6 11.1 11.2 10.8 4.1-.3 5.6-13.3 1-24.7-3.1-7.6-7-16.4-7-16.4z"
- style={{ fill: '#cb2029' }}
- />
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/measure/MeasureIndicator.tsx b/server/sonar-web/src/main/js/components/measure/MeasureIndicator.tsx
deleted file mode 100644
index 3b92e916fe3..00000000000
--- a/server/sonar-web/src/main/js/components/measure/MeasureIndicator.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CoverageIndicator, DuplicationsIndicator } from '~design-system';
-import Measure from '~sonar-aligned/components/measure/Measure';
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import { BranchLike } from '../../types/branch-like';
-import { duplicationRatingConverter } from './utils';
-
-interface Props {
- branchLike?: BranchLike;
- className?: string;
- componentKey: string;
- decimals?: number;
- forceRatingMetric?: boolean;
- metricKey: string;
- metricType: string;
- small?: boolean;
- value: string | undefined;
-}
-
-export default function MeasureIndicator(props: Props) {
- const { className, metricKey, metricType, value } = props;
-
- if (
- metricType === MetricType.Percent &&
- (metricKey === MetricKey.duplicated_lines_density ||
- metricKey === MetricKey.new_duplicated_lines_density)
- ) {
- return (
- <div className={className}>
- <DuplicationsIndicator rating={duplicationRatingConverter(Number(value))} />
- </div>
- );
- }
-
- if (metricType === MetricType.Percent) {
- return (
- <div className={className}>
- <CoverageIndicator value={value} />
- </div>
- );
- }
-
- return <Measure {...props} badgeSize="sm" />;
-}
diff --git a/server/sonar-web/src/main/js/components/measure/RatingTooltipContent.tsx b/server/sonar-web/src/main/js/components/measure/RatingTooltipContent.tsx
deleted file mode 100644
index 9d6d8c39d49..00000000000
--- a/server/sonar-web/src/main/js/components/measure/RatingTooltipContent.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import withAppStateContext from '../../app/components/app-state/withAppStateContext';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { isDiffMetric } from '../../helpers/measures';
-import {
- DIFF_METRIC_PREFIX_LENGTH,
- GRID_INDEX_OFFSET,
- PERCENT_MULTIPLIER,
- getMaintainabilityGrid,
-} from '../../helpers/ratings';
-import { AppState } from '../../types/appstate';
-import { GlobalSettingKeys } from '../../types/settings';
-import { KNOWN_RATINGS } from './utils';
-
-export interface RatingTooltipContentProps {
- appState: AppState;
- metricKey: MetricKey | string;
- value: number | string;
-}
-
-export function RatingTooltipContent(props: Readonly<RatingTooltipContentProps>) {
- const {
- appState: { settings },
- metricKey,
- value,
- } = props;
-
- const finalMetricKey = isDiffMetric(metricKey)
- ? metricKey.slice(DIFF_METRIC_PREFIX_LENGTH)
- : metricKey;
-
- if (!KNOWN_RATINGS.includes(finalMetricKey)) {
- return null;
- }
-
- const rating = Number(value);
- const ratingLetter = formatMeasure(value, MetricType.Rating);
-
- if (
- finalMetricKey !== MetricKey.sqale_rating &&
- finalMetricKey !== 'maintainability_rating' &&
- finalMetricKey !== MetricKey.software_quality_maintainability_rating
- ) {
- return <>{translate('metric', finalMetricKey, 'tooltip', ratingLetter)}</>;
- }
-
- const maintainabilityGrid = getMaintainabilityGrid(settings[GlobalSettingKeys.RatingGrid] ?? '');
- const maintainabilityRatingThreshold =
- maintainabilityGrid[Math.floor(rating) - GRID_INDEX_OFFSET];
-
- const metricForTooltipText =
- finalMetricKey === 'maintainability_rating' ? MetricKey.sqale_rating : finalMetricKey;
-
- return (
- // Required to correctly satisfy the context typing
- // eslint-disable-next-line react/jsx-no-useless-fragment
- <>
- {rating === 1
- ? translateWithParameters(
- `metric.${metricForTooltipText}.tooltip.A`,
- formatMeasure(maintainabilityGrid[0] * PERCENT_MULTIPLIER, MetricType.Percent),
- )
- : translateWithParameters(
- `metric.${metricForTooltipText}.tooltip`,
- ratingLetter,
- formatMeasure(maintainabilityRatingThreshold * PERCENT_MULTIPLIER, MetricType.Percent),
- )}
- </>
- );
-}
-
-export default withAppStateContext(RatingTooltipContent);
diff --git a/server/sonar-web/src/main/js/components/measure/__tests__/MeasureIndicator-test.tsx b/server/sonar-web/src/main/js/components/measure/__tests__/MeasureIndicator-test.tsx
deleted file mode 100644
index 6116d16c949..00000000000
--- a/server/sonar-web/src/main/js/components/measure/__tests__/MeasureIndicator-test.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render } from '@testing-library/react';
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import { Status } from '../../../apps/overview/utils';
-import MeasureIndicator from '../MeasureIndicator';
-
-it('renders correctly for coverage', () => {
- const wrapper = render(
- <MeasureIndicator
- componentKey="test"
- metricKey={MetricKey.coverage}
- metricType={MetricType.Percent}
- value="73.0"
- />,
- );
- expect(wrapper.baseElement).toMatchSnapshot();
-});
-
-it('renders correctly for failed quality gate', () => {
- const wrapper = render(
- <MeasureIndicator
- componentKey="test"
- metricKey={MetricKey.alert_status}
- metricType={MetricType.Level}
- small
- value={Status.ERROR}
- />,
- );
- expect(wrapper.baseElement).toMatchSnapshot();
-});
-
-it('renders correctly for passed quality gate', () => {
- const wrapper = render(
- <MeasureIndicator
- componentKey="test"
- metricKey={MetricKey.alert_status}
- metricType={MetricType.Level}
- value={Status.OK}
- />,
- );
- expect(wrapper.baseElement).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/components/measure/__tests__/__snapshots__/MeasureIndicator-test.tsx.snap b/server/sonar-web/src/main/js/components/measure/__tests__/__snapshots__/MeasureIndicator-test.tsx.snap
deleted file mode 100644
index 9891aa5fe8e..00000000000
--- a/server/sonar-web/src/main/js/components/measure/__tests__/__snapshots__/MeasureIndicator-test.tsx.snap
+++ /dev/null
@@ -1,116 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly for coverage 1`] = `
-<body>
- <div>
- <div>
- <svg
- class="donut-chart"
- height="24"
- width="24"
- >
- <g
- transform="translate(0, 0)"
- >
- <g
- transform="translate(12, 12)"
- >
- <path
- d="M0.75,-11.977A12,12,0,1,1,-11.672,2.785L-8.709,2.271A9,9,0,1,0,0.75,-8.969Z"
- style="fill: rgb(18,183,106);"
- />
- <path
- d="M-11.929,1.307A12,12,0,0,1,-0.75,-11.977L-0.75,-8.969A9,9,0,0,0,-8.965,0.793Z"
- style="fill: rgb(180,35,24);"
- />
- </g>
- </g>
- </svg>
- </div>
- </div>
-</body>
-`;
-
-exports[`renders correctly for failed quality gate 1`] = `
-<body>
- <div>
- <div
- class="sw-flex sw-justify-center sw-items-center"
- >
- <svg
- class="sw-mr-2"
- fill="none"
- height="1rem"
- role="img"
- width="1rem"
- xmlns="http://www.w3.org/2000/svg"
- >
- <title>
- overview.quality_gate_x.metric.level.ERROR
- </title>
- <rect
- fill="rgb(254,205,202)"
- height="1rem"
- rx="2"
- width="1rem"
- />
- <path
- d="m10.227 5 .871.871-5.227 5.227L5 10.227z"
- fill="rgb(128,27,20)"
- />
- <path
- d="m11.098 10.227-.871.87L5 5.872 5.87 5z"
- fill="rgb(128,27,20)"
- />
- </svg>
- </div>
- <span
- class=""
- >
- ERROR
- </span>
- </div>
-</body>
-`;
-
-exports[`renders correctly for passed quality gate 1`] = `
-<body>
- <div>
- <div
- class="sw-flex sw-justify-center sw-items-center"
- >
- <svg
- class="sw-mr-2"
- fill="none"
- height="1.5rem"
- role="img"
- width="1.5rem"
- xmlns="http://www.w3.org/2000/svg"
- >
- <title>
- overview.quality_gate_x.metric.level.OK
- </title>
- <rect
- fill="rgb(209,250,223)"
- height="1.5rem"
- rx="2"
- width="1.5rem"
- />
- <path
- d="m16.95 7.5 1.308 1.307-7.84 7.84-1.308-1.306z"
- fill="rgb(5,96,58)"
- />
- <path
- d="m11.79 15.34-1.307 1.307-4.484-4.483 1.307-1.306z"
- fill="rgb(5,96,58)"
- />
- </svg>
- </div>
- <span
- class="sw-typo-lg"
- >
- OK
- </span>
- </div>
-</body>
-`;
diff --git a/server/sonar-web/src/main/js/components/measure/__tests__/utils-test.tsx b/server/sonar-web/src/main/js/components/measure/__tests__/utils-test.tsx
deleted file mode 100644
index 3bd6d1c9d77..00000000000
--- a/server/sonar-web/src/main/js/components/measure/__tests__/utils-test.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { duplicationRatingConverter } from '../utils';
-
-describe('duplicationRatingConverter', () => {
- it.each([
- [0, 'A'],
- [2, 'B'],
- [4, 'C'],
- [8, 'D'],
- [18, 'E'],
- [20, 'F'],
- [25, 'F'],
- ])('should work correctly when value is %s', (value: number, result: string) => {
- expect(duplicationRatingConverter(value)).toEqual(result);
- });
-});
diff --git a/server/sonar-web/src/main/js/components/measure/utils.ts b/server/sonar-web/src/main/js/components/measure/utils.ts
deleted file mode 100644
index c242ab21ad4..00000000000
--- a/server/sonar-web/src/main/js/components/measure/utils.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { MetricKey } from '../../sonar-aligned/types/metrics';
-import { Dict, Measure, MeasureEnhanced, MeasureIntern, Metric } from '../../types/types';
-
-export const KNOWN_RATINGS = [
- MetricKey.sqale_rating,
- MetricKey.reliability_rating,
- MetricKey.security_rating,
- MetricKey.security_review_rating,
- MetricKey.software_quality_maintainability_rating,
- MetricKey.software_quality_reliability_rating,
- MetricKey.software_quality_security_rating,
- 'maintainability_rating', // Needed to provide the label for "new_maintainability_rating"
-];
-
-export function enhanceMeasure(measure: Measure, metrics: Dict<Metric>): MeasureEnhanced {
- return {
- ...measure,
- metric: metrics[measure.metric],
- leak: getLeakValue(measure),
- };
-}
-
-export function getLeakValue(measure: MeasureIntern | undefined): string | undefined {
- return measure?.period?.value;
-}
-
-export function duplicationRatingConverter(val: number) {
- const value = val || 0;
- const THRESHOLD_B = 3;
- const THRESHOLD_C = 5;
- const THRESHOLD_D = 10;
- const THRESHOLD_E = 20;
-
- if (value === 0) {
- return 'A';
- } else if (value < THRESHOLD_B) {
- return 'B';
- } else if (value < THRESHOLD_C) {
- return 'C';
- } else if (value < THRESHOLD_D) {
- return 'D';
- } else if (value < THRESHOLD_E) {
- return 'E';
- }
- return 'F';
-}
diff --git a/server/sonar-web/src/main/js/components/new-code-definition/BranchNCDAutoUpdateMessage.tsx b/server/sonar-web/src/main/js/components/new-code-definition/BranchNCDAutoUpdateMessage.tsx
deleted file mode 100644
index d69ef516c07..00000000000
--- a/server/sonar-web/src/main/js/components/new-code-definition/BranchNCDAutoUpdateMessage.tsx
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useCallback, useEffect, useState } from 'react';
-import { FormattedMessage, useIntl } from 'react-intl';
-import { DismissableFlagMessage, Link } from '~design-system';
-import { MessageTypes, checkMessageDismissed, setMessageDismissed } from '../../api/messages';
-import { DocLink } from '../../helpers/doc-links';
-import { useDocUrl } from '../../helpers/docs';
-import { Component } from '../../types/types';
-import { PreviouslyNonCompliantBranchNCD } from './utils';
-
-interface NCDAutoUpdateMessageProps {
- component: Component;
- previouslyNonCompliantBranchNCDs: PreviouslyNonCompliantBranchNCD[];
-}
-
-export default function NCDAutoUpdateMessage(props: NCDAutoUpdateMessageProps) {
- const { component, previouslyNonCompliantBranchNCDs } = props;
- const intl = useIntl();
- const toUrl = useDocUrl(DocLink.NewCodeDefinitionOptions);
-
- const [dismissed, setDismissed] = useState(true);
-
- const handleBannerDismiss = useCallback(async () => {
- await setMessageDismissed({ messageType: MessageTypes.BranchNcd90, projectKey: component.key });
- setDismissed(true);
- }, [component]);
-
- useEffect(() => {
- async function checkBranchMessageDismissed() {
- if (previouslyNonCompliantBranchNCDs.length > 0) {
- const messageStatus = await checkMessageDismissed({
- messageType: MessageTypes.BranchNcd90,
- projectKey: component.key,
- });
- setDismissed(messageStatus.dismissed);
- }
- }
-
- if (previouslyNonCompliantBranchNCDs.length > 0) {
- checkBranchMessageDismissed();
- }
- }, [component, previouslyNonCompliantBranchNCDs]);
-
- if (dismissed || previouslyNonCompliantBranchNCDs.length === 0) {
- return null;
- }
-
- const branchesList = (
- <ul className="sw-list-disc sw-my-4 sw-list-inside">
- {previouslyNonCompliantBranchNCDs.map((branchNCD) => (
- <li key={branchNCD.branchKey}>
- <FormattedMessage
- id="new_code_definition.auto_update.branch.list_item"
- values={{
- branchName: branchNCD.branchKey,
- days: branchNCD.value,
- previousDays: branchNCD.previousNonCompliantValue,
- }}
- />
- </li>
- ))}
- </ul>
- );
-
- return (
- <DismissableFlagMessage className="sw-my-4" onDismiss={handleBannerDismiss} variant="info">
- <div>
- <FormattedMessage
- id="new_code_definition.auto_update.branch.message"
- values={{
- date: new Date(previouslyNonCompliantBranchNCDs[0].updatedAt).toLocaleDateString(),
- branchesList,
- link: <Link to={toUrl}>{intl.formatMessage({ id: 'learn_more' })}</Link>,
- }}
- />
- </div>
- </DismissableFlagMessage>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/new-code-definition/GlobalNewCodeDefinitionDescription.tsx b/server/sonar-web/src/main/js/components/new-code-definition/GlobalNewCodeDefinitionDescription.tsx
deleted file mode 100644
index 20d14ab9b74..00000000000
--- a/server/sonar-web/src/main/js/components/new-code-definition/GlobalNewCodeDefinitionDescription.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { TextSubdued } from '~design-system';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { NewCodeDefinition, NewCodeDefinitionType } from '../../types/new-code-definition';
-
-interface Props {
- className?: string;
- globalNcd: NewCodeDefinition;
-}
-
-export default function GlobalNewCodeDefinitionDescription({
- globalNcd,
- className,
-}: Readonly<Props>) {
- let setting: string;
- let description: string;
- let useCase: string;
-
- if (globalNcd.type === NewCodeDefinitionType.NumberOfDays) {
- setting = `${translate('new_code_definition.number_days')} (${translateWithParameters(
- 'duration.days',
- globalNcd.value ?? '?',
- )})`;
-
- description = translate('new_code_definition.number_days.description');
- useCase = translate('new_code_definition.number_days.usecase');
- } else {
- setting = translate('new_code_definition.previous_version');
- description = translate('new_code_definition.previous_version.description');
- useCase = translate('new_code_definition.previous_version.usecase');
- }
-
- return (
- <div className={classNames('sw-flex sw-flex-col sw-gap-2 sw-max-w-[800px]', className)}>
- <TextSubdued>
- <strong className="sw-font-bold">{setting}</strong>
- </TextSubdued>
-
- <TextSubdued>
- <span>{description}</span>
- </TextSubdued>
-
- <TextSubdued>
- <span>{useCase}</span>
- </TextSubdued>
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/new-code-definition/NCDAutoUpdateMessage.tsx b/server/sonar-web/src/main/js/components/new-code-definition/NCDAutoUpdateMessage.tsx
deleted file mode 100644
index a86eb5d6b93..00000000000
--- a/server/sonar-web/src/main/js/components/new-code-definition/NCDAutoUpdateMessage.tsx
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useCallback, useEffect, useMemo, useState } from 'react';
-import { FormattedMessage, useIntl } from 'react-intl';
-import { Banner, Link } from '~design-system';
-import { queryToSearchString } from '~sonar-aligned/helpers/urls';
-import { MessageTypes, checkMessageDismissed, setMessageDismissed } from '../../api/messages';
-import { CurrentUserContextInterface } from '../../app/components/current-user/CurrentUserContext';
-import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext';
-import { NEW_CODE_PERIOD_CATEGORY } from '../../apps/settings/constants';
-import { useNewCodeDefinitionQuery } from '../../queries/newCodeDefinition';
-import { Component } from '../../types/types';
-import {
- PreviouslyNonCompliantNCD,
- isGlobalOrProjectAdmin,
- isPreviouslyNonCompliantDaysNCD,
-} from './utils';
-
-interface NCDAutoUpdateMessageProps extends Pick<CurrentUserContextInterface, 'currentUser'> {
- branchName?: string;
- component?: Component;
-}
-
-function NCDAutoUpdateMessage(props: Readonly<NCDAutoUpdateMessageProps>) {
- const { branchName, component, currentUser } = props;
- const isGlobalBanner = component === undefined;
- const intl = useIntl();
-
- const [dismissed, setDismissed] = useState(true);
- const [previouslyNonCompliantNewCodeDefinition, setPreviouslyNonCompliantNewCodeDefinition] =
- useState<PreviouslyNonCompliantNCD | undefined>(undefined);
-
- const isAdmin = isGlobalOrProjectAdmin(currentUser, component);
-
- const { data: newCodeDefinition } = useNewCodeDefinitionQuery({
- branchName,
- enabled: isAdmin,
- projectKey: component?.key,
- });
-
- const ncdReviewLinkTo = useMemo(
- () =>
- isGlobalBanner
- ? {
- pathname: '/admin/settings',
- search: queryToSearchString({
- category: NEW_CODE_PERIOD_CATEGORY,
- }),
- }
- : {
- pathname: '/project/baseline',
- search: queryToSearchString({
- id: component.key,
- }),
- },
- [component, isGlobalBanner],
- );
-
- const handleBannerDismiss = useCallback(async () => {
- await setMessageDismissed(
- isGlobalBanner
- ? { messageType: MessageTypes.GlobalNcd90 }
- : { messageType: MessageTypes.ProjectNcd90, projectKey: component.key },
- );
- setDismissed(true);
- }, [component, isGlobalBanner]);
-
- useEffect(() => {
- async function updateMessageStatus() {
- const messageStatus = await checkMessageDismissed(
- isGlobalBanner
- ? {
- messageType: MessageTypes.GlobalNcd90,
- }
- : {
- messageType: MessageTypes.ProjectNcd90,
- projectKey: component.key,
- },
- );
-
- setDismissed(messageStatus.dismissed);
- }
-
- if (newCodeDefinition && isPreviouslyNonCompliantDaysNCD(newCodeDefinition)) {
- setPreviouslyNonCompliantNewCodeDefinition(newCodeDefinition);
- updateMessageStatus();
- } else {
- setPreviouslyNonCompliantNewCodeDefinition(undefined);
- }
- }, [component?.key, isGlobalBanner, newCodeDefinition]);
-
- if (dismissed || !previouslyNonCompliantNewCodeDefinition) {
- return null;
- }
-
- const { updatedAt, previousNonCompliantValue, value } = previouslyNonCompliantNewCodeDefinition;
- const bannerMessageId = isGlobalBanner
- ? 'new_code_definition.auto_update.global.message'
- : 'new_code_definition.auto_update.project.message';
-
- return (
- <Banner onDismiss={handleBannerDismiss} variant="info">
- <p>
- <FormattedMessage
- id={bannerMessageId}
- values={{
- date: new Date(updatedAt).toLocaleDateString(),
- days: value,
- link: (
- <Link to={ncdReviewLinkTo}>
- {intl.formatMessage({ id: 'new_code_definition.auto_update.review_link' })}
- </Link>
- ),
- previousDays: previousNonCompliantValue,
- }}
- />
- </p>
- </Banner>
- );
-}
-
-export default withCurrentUserContext(NCDAutoUpdateMessage);
diff --git a/server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionAnalysisWarning.tsx b/server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionAnalysisWarning.tsx
deleted file mode 100644
index 82ad023bee1..00000000000
--- a/server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionAnalysisWarning.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FlagMessage, Link } from '~design-system';
-import { DocLink } from '../../helpers/doc-links';
-import { useDocUrl } from '../../helpers/docs';
-import { translate } from '../../helpers/l10n';
-
-export default function NewCodeDefinitionAnalysisWarning() {
- const toStatic = useDocUrl(DocLink.NewCodeDefinition);
- return (
- <FlagMessage variant="warning" className="sw-mb-4 sw-max-w-[800px]">
- <div>
- <p className="sw-mb-2 sw-font-bold">
- {translate('baseline.specific_analysis.compliance_warning.title')}
- </p>
- <p className="sw-mb-2">
- {translate('baseline.specific_analysis.compliance_warning.explanation')}
- </p>
- <p>
- {translate('learn_more')}:
- <Link className="sw-ml-2" to={toStatic}>
- {translate('learn_more')}
- </Link>
- </p>
- </div>
- </FlagMessage>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionDaysOption.tsx b/server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionDaysOption.tsx
deleted file mode 100644
index 85b78f02688..00000000000
--- a/server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionDaysOption.tsx
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { noop } from 'lodash';
-import { useCallback, useEffect, useMemo, useState } from 'react';
-import { FormattedMessage } from 'react-intl';
-import {
- DismissableFlagMessage,
- FlagErrorIcon,
- InputField,
- Note,
- SelectionCard,
-} from '~design-system';
-import { MessageTypes, checkMessageDismissed, setMessageDismissed } from '../../api/messages';
-import { DocLink } from '../../helpers/doc-links';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import {
- NUMBER_OF_DAYS_MAX_VALUE,
- NUMBER_OF_DAYS_MIN_VALUE,
-} from '../../helpers/new-code-definition';
-import { isDefined } from '../../helpers/types';
-import { NewCodeDefinitionType } from '../../types/new-code-definition';
-import DocumentationLink from '../common/DocumentationLink';
-import { NewCodeDefinitionLevels } from './utils';
-
-export interface Props {
- className?: string;
- currentDaysValue?: string;
- days: string;
- disabled?: boolean;
- isValid: boolean;
- onChangeDays: (value: string) => void;
- onSelect: (selection: NewCodeDefinitionType) => void;
- previousNonCompliantValue?: string;
- projectKey?: string;
- selected: boolean;
- settingLevel: NewCodeDefinitionLevels;
- updatedAt?: number;
-}
-
-export default function NewCodeDefinitionDaysOption(props: Props) {
- const {
- className,
- days,
- currentDaysValue,
- previousNonCompliantValue,
- projectKey,
- updatedAt,
- disabled,
- isValid,
- onChangeDays,
- onSelect,
- selected,
- settingLevel,
- } = props;
-
- const [ncdAutoUpdateBannerDismissed, setNcdAutoUpdateBannerDismissed] = useState(true);
-
- useEffect(() => {
- async function fetchMessageDismissed() {
- const messageStatus = await checkMessageDismissed(
- projectKey
- ? {
- messageType: MessageTypes.ProjectNcdPage90,
- projectKey,
- }
- : {
- messageType: MessageTypes.GlobalNcdPage90,
- },
- );
- setNcdAutoUpdateBannerDismissed(messageStatus.dismissed);
- }
-
- if (isDefined(previousNonCompliantValue)) {
- fetchMessageDismissed().catch(noop);
- }
- }, [previousNonCompliantValue, projectKey, settingLevel]);
-
- const shouldShowAutoUpdateBanner = useMemo(() => {
- return (
- (settingLevel === NewCodeDefinitionLevels.Global ||
- settingLevel === NewCodeDefinitionLevels.Project) &&
- isDefined(previousNonCompliantValue) &&
- isDefined(updatedAt) &&
- !disabled &&
- !ncdAutoUpdateBannerDismissed
- );
- }, [disabled, ncdAutoUpdateBannerDismissed, previousNonCompliantValue, settingLevel, updatedAt]);
-
- const handleBannerDismiss = useCallback(async () => {
- await setMessageDismissed({ messageType: MessageTypes.GlobalNcdPage90 });
- setNcdAutoUpdateBannerDismissed(true);
- }, []);
-
- return (
- <SelectionCard
- className={className}
- disabled={disabled}
- onClick={() => onSelect(NewCodeDefinitionType.NumberOfDays)}
- selected={selected}
- title={translate('new_code_definition.number_days')}
- >
- <>
- <div>
- <p className="sw-mb-2">{translate('new_code_definition.number_days.description')}</p>
- <p>{translate('new_code_definition.number_days.usecase')}</p>
- </div>
- {selected && (
- <div className="sw-mt-4">
- <label>
- {translate('new_code_definition.number_days.specify_days')}
- <div className="sw-my-2 sw-flex sw-items-center">
- <InputField
- id="baseline_number_of_days"
- isInvalid={!isValid}
- max={NUMBER_OF_DAYS_MAX_VALUE}
- min={NUMBER_OF_DAYS_MIN_VALUE}
- onChange={(e) => onChangeDays(e.currentTarget.value)}
- required
- type="number"
- value={days}
- />
- {!isValid && <FlagErrorIcon className="sw-ml-2" />}
- </div>
- </label>
- <Note>
- {translateWithParameters(
- 'new_code_definition.number_days.invalid',
- NUMBER_OF_DAYS_MIN_VALUE,
- NUMBER_OF_DAYS_MAX_VALUE,
- )}
- </Note>
-
- {shouldShowAutoUpdateBanner && (
- <DismissableFlagMessage
- variant="info"
- className="sw-mt-4 sw-max-w-[800px]"
- onDismiss={handleBannerDismiss}
- >
- <FormattedMessage
- defaultMessage="new_code_definition.auto_update.ncd_page.message"
- id="new_code_definition.auto_update.ncd_page.message"
- tagName="span"
- values={{
- previousDays: previousNonCompliantValue,
- days: currentDaysValue,
- date: isDefined(updatedAt) && new Date(updatedAt).toLocaleDateString(),
- link: (
- <DocumentationLink to={DocLink.NewCodeDefinitionOptions}>
- {translate('learn_more')}
- </DocumentationLink>
- ),
- }}
- />
- </DismissableFlagMessage>
- )}
- </div>
- )}
- </>
- </SelectionCard>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionPreviousVersionOption.tsx b/server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionPreviousVersionOption.tsx
deleted file mode 100644
index d5b794fbe53..00000000000
--- a/server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionPreviousVersionOption.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { SelectionCard } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { NewCodeDefinitionType } from '../../types/new-code-definition';
-
-interface Props {
- disabled?: boolean;
- isDefault?: boolean;
- onSelect: (selection: NewCodeDefinitionType) => void;
- selected: boolean;
-}
-
-export default function NewCodeDefinitionPreviousVersionOption({
- disabled,
- isDefault,
- onSelect,
- selected,
-}: Props) {
- return (
- <SelectionCard
- disabled={disabled}
- onClick={() => onSelect(NewCodeDefinitionType.PreviousVersion)}
- selected={selected}
- title={
- translate('new_code_definition.previous_version') +
- (isDefault ? ` (${translate('default')})` : '')
- }
- >
- <div>
- <p className="sw-mb-2">{translate('new_code_definition.previous_version.description')}</p>
- <p>{translate('new_code_definition.previous_version.usecase')}</p>
- </div>
- </SelectionCard>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionSelector.tsx b/server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionSelector.tsx
deleted file mode 100644
index 35e1d24eb62..00000000000
--- a/server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionSelector.tsx
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { noop } from 'lodash';
-import * as React from 'react';
-import { FlagMessage, PageContentFontWrapper, RadioButton, SelectionCard } from '~design-system';
-import { getNewCodeDefinition } from '../../api/newCodeDefinition';
-import { translate } from '../../helpers/l10n';
-import {
- getNumberOfDaysDefaultValue,
- isNewCodeDefinitionCompliant,
-} from '../../helpers/new-code-definition';
-import {
- NewCodeDefinition,
- NewCodeDefinitionType,
- NewCodeDefinitiondWithCompliance,
-} from '../../types/new-code-definition';
-import GlobalNewCodeDefinitionDescription from './GlobalNewCodeDefinitionDescription';
-import NewCodeDefinitionDaysOption from './NewCodeDefinitionDaysOption';
-import NewCodeDefinitionPreviousVersionOption from './NewCodeDefinitionPreviousVersionOption';
-import { NewCodeDefinitionLevels } from './utils';
-
-interface Props {
- isMultipleProjects?: boolean;
- onNcdChanged: (ncd: NewCodeDefinitiondWithCompliance) => void;
-}
-
-export default function NewCodeDefinitionSelector(props: Props) {
- const { onNcdChanged, isMultipleProjects } = props;
-
- const [globalNcd, setGlobalNcd] = React.useState<NewCodeDefinition | null>(null);
- const [selectedNcdType, setSelectedNcdType] = React.useState<NewCodeDefinitionType | null>(null);
- const [days, setDays] = React.useState<string>('');
-
- React.useEffect(() => {
- const numberOfDays = getNumberOfDaysDefaultValue(globalNcd);
- setDays(numberOfDays);
- }, [globalNcd]);
-
- const isCompliant = React.useMemo(
- () =>
- !!selectedNcdType &&
- isNewCodeDefinitionCompliant({
- type: selectedNcdType,
- value: days,
- }),
- [selectedNcdType, days],
- );
-
- const handleNcdChanged = React.useCallback(
- (newNcdType: NewCodeDefinitionType) => {
- if (newNcdType && newNcdType !== selectedNcdType) {
- setSelectedNcdType(newNcdType);
- }
- },
- [selectedNcdType],
- );
-
- React.useEffect(() => {
- function fetchGlobalNcd() {
- getNewCodeDefinition().then(setGlobalNcd, noop);
- }
-
- fetchGlobalNcd();
- }, []);
-
- React.useEffect(() => {
- if (selectedNcdType) {
- const type =
- selectedNcdType === NewCodeDefinitionType.Inherited ? undefined : selectedNcdType;
- const value = selectedNcdType === NewCodeDefinitionType.NumberOfDays ? days : undefined;
- onNcdChanged({ isCompliant, type, value });
- }
- }, [selectedNcdType, days, isCompliant, onNcdChanged]);
-
- return (
- <PageContentFontWrapper>
- <p className="sw-mt-10">
- <strong className="sw-typo-lg-semibold">
- {isMultipleProjects
- ? translate('new_code_definition.question.multiple_projects')
- : translate('new_code_definition.question')}
- </strong>
- </p>
- <div className="sw-mt-7 sw-ml-1" role="radiogroup">
- <RadioButton
- aria-label={translate('new_code_definition.global_setting')}
- checked={selectedNcdType === NewCodeDefinitionType.Inherited}
- onCheck={() => handleNcdChanged(NewCodeDefinitionType.Inherited)}
- value="general"
- >
- <span className="sw-font-semibold">
- {translate('new_code_definition.global_setting')}
- </span>
- </RadioButton>
-
- <StyledGlobalSettingWrapper
- className="sw-mt-4 sw-ml-6"
- selected={selectedNcdType === NewCodeDefinitionType.Inherited}
- >
- {globalNcd && <GlobalNewCodeDefinitionDescription globalNcd={globalNcd} />}
- </StyledGlobalSettingWrapper>
-
- <RadioButton
- aria-label={
- isMultipleProjects
- ? translate('new_code_definition.specific_setting.multiple_projects')
- : translate('new_code_definition.specific_setting')
- }
- checked={Boolean(selectedNcdType && selectedNcdType !== NewCodeDefinitionType.Inherited)}
- className="sw-mt-12 sw-font-semibold"
- onCheck={() => handleNcdChanged(NewCodeDefinitionType.PreviousVersion)}
- value="specific"
- >
- {isMultipleProjects
- ? translate('new_code_definition.specific_setting.multiple_projects')
- : translate('new_code_definition.specific_setting')}
- </RadioButton>
- </div>
-
- <div className="sw-flex sw-flex-col sw-my-4 sw-mr-4 sw-gap-4" role="radiogroup">
- <NewCodeDefinitionPreviousVersionOption
- disabled={Boolean(
- !selectedNcdType || selectedNcdType === NewCodeDefinitionType.Inherited,
- )}
- onSelect={handleNcdChanged}
- selected={selectedNcdType === NewCodeDefinitionType.PreviousVersion}
- />
-
- <NewCodeDefinitionDaysOption
- days={days}
- disabled={Boolean(
- !selectedNcdType || selectedNcdType === NewCodeDefinitionType.Inherited,
- )}
- isValid={isCompliant}
- onChangeDays={setDays}
- onSelect={handleNcdChanged}
- selected={selectedNcdType === NewCodeDefinitionType.NumberOfDays}
- settingLevel={NewCodeDefinitionLevels.NewProject}
- />
-
- <SelectionCard
- disabled={Boolean(
- !selectedNcdType || selectedNcdType === NewCodeDefinitionType.Inherited,
- )}
- onClick={() => handleNcdChanged(NewCodeDefinitionType.ReferenceBranch)}
- selected={selectedNcdType === NewCodeDefinitionType.ReferenceBranch}
- title={translate('new_code_definition.reference_branch')}
- >
- <div>
- <p className="sw-mb-2">
- {translate('new_code_definition.reference_branch.description')}
- </p>
- <p>{translate('new_code_definition.reference_branch.usecase')}</p>
- {selectedNcdType === NewCodeDefinitionType.ReferenceBranch && (
- <FlagMessage className="sw-mt-4" variant="info">
- {translate('new_code_definition.reference_branch.notice')}
- </FlagMessage>
- )}
- </div>
- </SelectionCard>
- </div>
- </PageContentFontWrapper>
- );
-}
-
-const StyledGlobalSettingWrapper = styled.div<{ selected: boolean }>`
- color: ${({ selected }) => (selected ? 'inherit' : 'var(--echoes-color-text-subdued)')};
-`;
diff --git a/server/sonar-web/src/main/js/components/new-code-definition/__tests__/NCDAutoUpdateMessage-test.tsx b/server/sonar-web/src/main/js/components/new-code-definition/__tests__/NCDAutoUpdateMessage-test.tsx
deleted file mode 100644
index 75326e0af95..00000000000
--- a/server/sonar-web/src/main/js/components/new-code-definition/__tests__/NCDAutoUpdateMessage-test.tsx
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import { Route } from 'react-router-dom';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { MessageTypes } from '../../../api/messages';
-import MessagesServiceMock from '../../../api/mocks/MessagesServiceMock';
-import NewCodeDefinitionServiceMock from '../../../api/mocks/NewCodeDefinitionServiceMock';
-import { mockComponent } from '../../../helpers/mocks/component';
-import { mockLoggedInUser } from '../../../helpers/testMocks';
-import { renderAppRoutes } from '../../../helpers/testReactTestingUtils';
-import { NewCodeDefinitionType } from '../../../types/new-code-definition';
-import { Component } from '../../../types/types';
-import NCDAutoUpdateMessage from '../NCDAutoUpdateMessage';
-
-let newCodeDefinitionMock: NewCodeDefinitionServiceMock;
-let messagesMock: MessagesServiceMock;
-
-describe('Global NCD update notification banner', () => {
- function renderGlobalMessage(
- currentUser = mockLoggedInUser({ permissions: { global: ['admin'] } }),
- ) {
- return renderAppRoutes(
- '/',
- () => (
- <>
- <Route path="/" element={<NCDAutoUpdateMessage />} />
- <Route path="/admin/settings" element={<div>Admin NCD</div>} />
- </>
- ),
- {
- currentUser,
- },
- );
- }
-
- beforeAll(() => {
- newCodeDefinitionMock = new NewCodeDefinitionServiceMock();
- messagesMock = new MessagesServiceMock();
- });
-
- afterEach(() => {
- newCodeDefinitionMock.reset();
- messagesMock.reset();
- });
-
- const ui = {
- dismissButton: byRole('button', { name: 'dismiss' }),
- globalBannerContent: byText(/new_code_definition.auto_update.global.message/),
- reviewLink: byText('new_code_definition.auto_update.review_link'),
- adminNcdMessage: byText('Admin NCD'),
- };
- const previouslyNonCompliantNewCodeDefinition = {
- previousNonCompliantValue: '120',
- type: NewCodeDefinitionType.NumberOfDays,
- updatedAt: 1692106874855,
- value: '90',
- };
-
- it('renders no global banner if user is not global admin', () => {
- const { container } = renderGlobalMessage(mockLoggedInUser());
- expect(container).toContainHTML('<div><div class="Toastify" /></div>');
- });
-
- it('renders global banner if user is global admin', async () => {
- newCodeDefinitionMock.setNewCodePeriod(previouslyNonCompliantNewCodeDefinition);
- renderGlobalMessage();
- expect(await ui.globalBannerContent.find()).toBeVisible();
- });
-
- it('dismisses global banner', async () => {
- newCodeDefinitionMock.setNewCodePeriod(previouslyNonCompliantNewCodeDefinition);
- renderGlobalMessage();
- expect(await ui.globalBannerContent.find()).toBeVisible();
- const user = userEvent.setup();
- await user.click(ui.dismissButton.get());
- expect(ui.globalBannerContent.query()).not.toBeInTheDocument();
- });
-
- it('does not render global banner if dismissed', () => {
- newCodeDefinitionMock.setNewCodePeriod(previouslyNonCompliantNewCodeDefinition);
- messagesMock.setMessageDismissed({ messageType: MessageTypes.GlobalNcd90 });
- renderGlobalMessage();
- expect(ui.globalBannerContent.query()).not.toBeInTheDocument();
- });
-
- it('does not render global banner if global new code definition has not been automatically updated', () => {
- newCodeDefinitionMock.setNewCodePeriod({
- type: NewCodeDefinitionType.NumberOfDays,
- value: '45',
- });
- renderGlobalMessage();
- expect(ui.globalBannerContent.query()).not.toBeInTheDocument();
- });
-
- it('clicking on review link redirects to global NCD admin page', async () => {
- newCodeDefinitionMock.setNewCodePeriod(previouslyNonCompliantNewCodeDefinition);
- renderGlobalMessage();
- expect(await ui.globalBannerContent.find()).toBeVisible();
- const user = userEvent.setup();
- await user.click(ui.reviewLink.get());
- expect(await ui.adminNcdMessage.find()).toBeVisible();
- });
-});
-
-describe('Project NCD update notification banner', () => {
- function renderProjectMessage(component: Component, currentUser = mockLoggedInUser()) {
- return renderAppRoutes(
- '/',
- () => (
- <>
- <Route path="/" element={<NCDAutoUpdateMessage component={component} />} />
- <Route path="/project/baseline" element={<div>Project NCD</div>} />
- </>
- ),
- {
- currentUser,
- },
- );
- }
-
- beforeAll(() => {
- newCodeDefinitionMock = new NewCodeDefinitionServiceMock();
- messagesMock = new MessagesServiceMock();
- });
-
- afterEach(() => {
- newCodeDefinitionMock.reset();
- messagesMock.reset();
- });
-
- const ui = {
- dismissButton: byRole('button', { name: 'dismiss' }),
- projectBannerContent: byText(/new_code_definition.auto_update.project.message/),
- projectNcdMessage: byText('Project NCD'),
- reviewLink: byText('new_code_definition.auto_update.review_link'),
- };
-
- const component = mockComponent({
- key: 'test-project:test',
- configuration: { showSettings: true },
- });
- const previouslyNonCompliantNewCodeDefinition = {
- previousNonCompliantValue: '120',
- projectKey: component.key,
- type: NewCodeDefinitionType.NumberOfDays,
- updatedAt: 1692106874855,
- value: '90',
- };
-
- it('renders no project banner if user is not project admin', () => {
- const { container } = renderProjectMessage(
- mockComponent({ configuration: { showSettings: false } }),
- );
- expect(container).toContainHTML('<div><div class="Toastify" /></div>');
- });
-
- it('renders project banner if user is project admin', async () => {
- newCodeDefinitionMock.setNewCodePeriod(previouslyNonCompliantNewCodeDefinition);
- renderProjectMessage(component);
- expect(await ui.projectBannerContent.find()).toBeVisible();
- });
-
- it('dismisses project banner', async () => {
- newCodeDefinitionMock.setNewCodePeriod(previouslyNonCompliantNewCodeDefinition);
- renderProjectMessage(component);
- expect(await ui.projectBannerContent.find()).toBeVisible();
- const user = userEvent.setup();
- await user.click(ui.dismissButton.get());
- expect(ui.projectBannerContent.query()).not.toBeInTheDocument();
- });
-
- it('does not render project banner if dismissed', () => {
- newCodeDefinitionMock.setNewCodePeriod(previouslyNonCompliantNewCodeDefinition);
- messagesMock.setMessageDismissed({ messageType: MessageTypes.GlobalNcd90 });
- renderProjectMessage(component);
- expect(ui.projectBannerContent.query()).not.toBeInTheDocument();
- });
-
- it('does not render project banner if project new code definition has not been automatically updated', () => {
- newCodeDefinitionMock.setNewCodePeriod({
- projectKey: component.key,
- type: NewCodeDefinitionType.NumberOfDays,
- value: '45',
- });
- renderProjectMessage(component);
- expect(ui.projectBannerContent.query()).not.toBeInTheDocument();
- });
-
- it('clicking on review link redirects to project NCD admin page', async () => {
- newCodeDefinitionMock.setNewCodePeriod(previouslyNonCompliantNewCodeDefinition);
- renderProjectMessage(component);
- expect(await ui.projectBannerContent.find()).toBeVisible();
- const user = userEvent.setup();
- await user.click(ui.reviewLink.get());
- expect(await ui.projectNcdMessage.find()).toBeVisible();
- });
-});
diff --git a/server/sonar-web/src/main/js/components/new-code-definition/utils.ts b/server/sonar-web/src/main/js/components/new-code-definition/utils.ts
deleted file mode 100644
index 9c691d82af3..00000000000
--- a/server/sonar-web/src/main/js/components/new-code-definition/utils.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { hasGlobalPermission } from '../../helpers/users';
-import {
- NewCodeDefinition,
- NewCodeDefinitionBranch,
- NewCodeDefinitionType,
-} from '../../types/new-code-definition';
-import { Permissions } from '../../types/permissions';
-import { Component } from '../../types/types';
-import { CurrentUser, isLoggedIn } from '../../types/users';
-
-export enum NewCodeDefinitionLevels {
- Global = 'GLOBAL',
- Project = 'PROJECT',
- Branch = 'BRANCH',
- NewProject = 'NEW_PROJECT',
-}
-
-export type PreviouslyNonCompliantNCD = NewCodeDefinition &
- Required<Pick<NewCodeDefinition, 'previousNonCompliantValue' | 'updatedAt'>>;
-
-export type PreviouslyNonCompliantBranchNCD = PreviouslyNonCompliantNCD & NewCodeDefinitionBranch;
-
-export function isPreviouslyNonCompliantDaysNCD(
- newCodeDefinition: NewCodeDefinition,
-): newCodeDefinition is PreviouslyNonCompliantNCD;
-export function isPreviouslyNonCompliantDaysNCD(
- newCodeDefinition: NewCodeDefinitionBranch,
-): newCodeDefinition is PreviouslyNonCompliantBranchNCD;
-export function isPreviouslyNonCompliantDaysNCD(
- newCodeDefinition: NewCodeDefinition | NewCodeDefinitionBranch,
-): newCodeDefinition is PreviouslyNonCompliantNCD | PreviouslyNonCompliantBranchNCD {
- return (
- newCodeDefinition.type === NewCodeDefinitionType.NumberOfDays &&
- newCodeDefinition.previousNonCompliantValue !== undefined &&
- newCodeDefinition.updatedAt !== undefined &&
- !newCodeDefinition.inherited
- );
-}
-
-export function isGlobalOrProjectAdmin(currentUser: CurrentUser, component?: Component) {
- if (!isLoggedIn(currentUser)) {
- return false;
- }
-
- if (component !== undefined) {
- return !!component.configuration?.showSettings;
- }
-
- return hasGlobalPermission(currentUser, Permissions.Admin);
-}
diff --git a/server/sonar-web/src/main/js/components/notifications/NotificationsList.tsx b/server/sonar-web/src/main/js/components/notifications/NotificationsList.tsx
deleted file mode 100644
index 2d30e75e98e..00000000000
--- a/server/sonar-web/src/main/js/components/notifications/NotificationsList.tsx
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Checkbox, Label, Spinner, Text } from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import { useCallback } from 'react';
-import { FormattedMessage, useIntl } from 'react-intl';
-import { CellComponent, Switch, Table, TableRowInteractive } from '~design-system';
-import { hasMessage, translate } from '../../helpers/l10n';
-import {
- useAddNotificationMutation,
- useNotificationsQuery,
- useRemoveNotificationMutation,
-} from '../../queries/notifications';
-
-interface Props {
- className?: string;
- projectKey?: string;
- projectName?: string;
-}
-
-function getDispatcherLabel(dispatcher: string, project?: string) {
- const globalMessageKey = ['notification.dispatcher', dispatcher];
- const projectMessageKey = [...globalMessageKey, 'project'];
- const shouldUseProjectMessage = project !== undefined && hasMessage(...projectMessageKey);
-
- return shouldUseProjectMessage ? translate(...projectMessageKey) : translate(...globalMessageKey);
-}
-
-export default function NotificationsList({
- projectKey,
- projectName,
- className = '',
-}: Readonly<Props>) {
- const intl = useIntl();
- const { data, isLoading } = useNotificationsQuery();
- const { mutate: add, isPending: isPendingAdd } = useAddNotificationMutation();
- const { mutate: remove, isPending: isPendingRemove } = useRemoveNotificationMutation();
- const types = (projectKey ? data?.perProjectTypes : data?.globalTypes) || [];
- const channels = data?.channels || [];
-
- const checkboxId = useCallback(
- (type: string, channel: string) => {
- return projectKey === undefined
- ? `global-notification-${type}-${channel}`
- : `project-notification-${projectKey}-${type}-${channel}`;
- },
- [projectKey],
- );
-
- const isEnabled = useCallback(
- (type: string, channel: string) =>
- !!data?.notifications.find(
- (notification) =>
- notification.type === type &&
- notification.channel === channel &&
- notification.project === projectKey,
- ),
- [data?.notifications, projectKey],
- );
-
- const handleCheck = useCallback(
- (type: string, channel: string, checked: boolean) => {
- if (checked) {
- add({ type, channel, project: projectKey });
- } else {
- remove({ type, channel, project: projectKey });
- }
- },
- [add, projectKey, remove],
- );
-
- if (channels.length !== 1) {
- return (
- <Spinner isLoading={isLoading}>
- <Table
- className={classNames('sw-w-full', className)}
- columnCount={channels.length + 1}
- header={
- <tr>
- <th className="sw-typo-semibold">{translate('notification.for')}</th>
-
- {channels.map((channel) => (
- <th className="sw-typo-semibold sw-text-right" key={channel}>
- <FormattedMessage
- id="notification.by"
- values={{
- channel: <FormattedMessage id={`notification.channel.${channel}`} />,
- }}
- />
- </th>
- ))}
- </tr>
- }
- >
- {types.map((type) => (
- <TableRowInteractive className="sw-h-9" key={type}>
- <CellComponent className="sw-py-0 sw-border-0">
- {getDispatcherLabel(type, projectKey)}
- </CellComponent>
-
- {channels.map((channel) => (
- <CellComponent className="sw-py-0 sw-border-0" key={channel}>
- <div className="sw-justify-end sw-flex sw-items-center">
- <Checkbox
- ariaLabel={intl.formatMessage(
- { id: 'notification.dispatcher.description_x' },
- { project: getDispatcherLabel(type, projectKey) },
- )}
- isDisabled={isPendingRemove || isPendingAdd}
- checked={isEnabled(type, channel)}
- id={checkboxId(type, channel)}
- onCheck={(checked) => handleCheck(type, channel, checked as boolean)}
- />
- </div>
- </CellComponent>
- ))}
- </TableRowInteractive>
- ))}
- </Table>
- </Spinner>
- );
- }
-
- return (
- <Spinner isLoading={isLoading}>
- <ul
- aria-label={
- projectName
- ? intl.formatMessage(
- { id: 'notification.dispatcher.group.label' },
- { project: projectName },
- )
- : ''
- }
- >
- {types.map((type) => (
- <li key={type} className="sw-mt-4">
- <Label className="sw-flex sw-gap-2">
- {/* For screen readers we want to hide the label and apply aria-label on element to avoid duplication of label */}
- <Switch
- id={checkboxId(type, channels[0])}
- ariaLabel={getDispatcherLabel(type, projectKey)}
- value={isEnabled(type, channels[0])}
- onChange={(value) => handleCheck(type, channels[0], value)}
- />
- <Text aria-hidden>{getDispatcherLabel(type, projectKey)}</Text>
- </Label>
- </li>
- ))}
- </ul>
- </Spinner>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/permissions/AllHoldersList.tsx b/server/sonar-web/src/main/js/components/permissions/AllHoldersList.tsx
deleted file mode 100644
index 33830099a4d..00000000000
--- a/server/sonar-web/src/main/js/components/permissions/AllHoldersList.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { BasicSeparator, Spinner } from '~design-system';
-import {
- Paging,
- PermissionDefinition,
- PermissionDefinitionGroup,
- PermissionGroup,
- PermissionUser,
-} from '../../types/types';
-import ListFooter from '../controls/ListFooter';
-import HoldersList from './HoldersList';
-import SearchForm, { FilterOption } from './SearchForm';
-
-interface Props {
- filter: FilterOption;
- groups: PermissionGroup[];
- groupsPaging?: Paging;
- isProjectManaged?: boolean;
- loading?: boolean;
- onFilter: (filter: string) => void;
- onGrantPermissionToGroup: (group: string, permission: string) => Promise<void>;
- onGrantPermissionToUser: (user: string, permission: string) => Promise<void>;
- onLoadMore: () => void;
- onQuery: (query: string) => void;
- onRevokePermissionFromGroup: (group: string, permission: string) => Promise<void>;
- onRevokePermissionFromUser: (user: string, permission: string) => Promise<void>;
- onSelectPermission?: (permissions?: string) => void;
- permissions: Array<PermissionDefinition | PermissionDefinitionGroup>;
- query: string;
- selectedPermission?: string;
- users: PermissionUser[];
- usersPaging?: Paging;
-}
-
-export default class AllHoldersList extends React.PureComponent<Props> {
- handleToggleUser = (user: PermissionUser, permission: string) => {
- const hasPermission = user.permissions.includes(permission);
-
- if (hasPermission) {
- return this.props.onRevokePermissionFromUser(user.login, permission);
- }
- return this.props.onGrantPermissionToUser(user.login, permission);
- };
-
- handleToggleGroup = (group: PermissionGroup, permission: string) => {
- const hasPermission = group.permissions.includes(permission);
-
- if (hasPermission) {
- return this.props.onRevokePermissionFromGroup(group.name, permission);
- }
-
- return this.props.onGrantPermissionToGroup(group.name, permission);
- };
-
- getPaging = () => {
- const { filter, groups, groupsPaging, users, usersPaging } = this.props;
-
- let count = 0;
- let total = 0;
- if (filter !== 'users') {
- count += groups.length;
- total += groupsPaging ? groupsPaging.total : groups.length;
- }
- if (filter !== 'groups') {
- count += users.length;
- total += usersPaging ? usersPaging.total : users.length;
- }
-
- return { count, total };
- };
-
- render() {
- const {
- filter,
- query,
- groups,
- users,
- permissions,
- selectedPermission,
- loading = false,
- isProjectManaged,
- } = this.props;
- const { count, total } = this.getPaging();
-
- return (
- <>
- <div>
- <div className="sw-flex sw-justify-between">
- <SearchForm
- filter={filter}
- onFilter={this.props.onFilter}
- onSearch={this.props.onQuery}
- query={query}
- />
- <Spinner loading={loading} />
- </div>
- <BasicSeparator className="sw-mt-4" />
- </div>
- <HoldersList
- isProjectManaged={!!isProjectManaged}
- loading={loading}
- filter={filter}
- groups={groups}
- onSelectPermission={this.props.onSelectPermission}
- onToggleGroup={this.handleToggleGroup}
- onToggleUser={this.handleToggleUser}
- permissions={permissions}
- query={query}
- selectedPermission={selectedPermission}
- users={users}
- />
- <ListFooter count={count} loadMore={this.props.onLoadMore} total={total} />
- </>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/permissions/GroupHolder.tsx b/server/sonar-web/src/main/js/components/permissions/GroupHolder.tsx
deleted file mode 100644
index c7c7a272cd6..00000000000
--- a/server/sonar-web/src/main/js/components/permissions/GroupHolder.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Badge, ContentCell, TableRowInteractive, UserGroupIcon } from '~design-system';
-import { Image } from '~sonar-aligned/components/common/Image';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { isPermissionDefinitionGroup } from '../../helpers/permissions';
-import { isDefined } from '../../helpers/types';
-import { Permissions } from '../../types/permissions';
-import { PermissionDefinitions, PermissionGroup } from '../../types/types';
-import PermissionCell from './PermissionCell';
-import usePermissionChange from './usePermissionChange';
-
-interface Props {
- group: PermissionGroup;
- isComponentPrivate?: boolean;
- isGitHubUser: boolean | undefined;
- isGitLabUser: boolean | undefined;
- onToggle: (group: PermissionGroup, permission: string) => Promise<void>;
- permissions: PermissionDefinitions;
- removeOnly?: boolean;
- selectedPermission?: string;
-}
-
-export const ANYONE = 'Anyone';
-
-export default function GroupHolder(props: Props) {
- const {
- group,
- isComponentPrivate,
- permissions,
- selectedPermission,
- removeOnly,
- isGitHubUser,
- isGitLabUser,
- } = props;
- const { loading, handleCheck, modal } = usePermissionChange({
- holder: group,
- onToggle: props.onToggle,
- permissions,
- removeOnly,
- });
-
- const description =
- group.name === ANYONE ? translate('user_groups.anyone.description') : group.description;
-
- return (
- <TableRowInteractive>
- <ContentCell>
- <div className="sw-flex sw-items-center">
- <UserGroupIcon className="sw-mr-4" />
- <div className="sw-max-w-abs-800">
- <div className="sw-flex sw-w-fit sw-max-w-full">
- <div className="sw-flex-1 sw-text-ellipsis sw-whitespace-nowrap sw-overflow-hidden sw-min-w-0">
- <strong>{group.name}</strong>
- </div>
- {isGitHubUser && (
- <Image
- alt="github"
- className="sw-ml-2"
- aria-label={translateWithParameters(
- 'project_permission.managed',
- translate('alm.github'),
- )}
- height={16}
- src="/images/alm/github.svg"
- />
- )}
- {isGitLabUser && (
- <Image
- alt="gitlab"
- className="sw-ml-2"
- aria-label={translateWithParameters(
- 'project_permission.managed',
- translate('alm.gitlab'),
- )}
- height={16}
- src="/images/alm/gitlab.svg"
- />
- )}
- {group.name === ANYONE && (
- <Badge className="sw-ml-2" variant="deleted">
- {translate('deprecated')}
- </Badge>
- )}
- </div>
- {isDefined(description) && (
- <div className="sw-mt-2 sw-whitespace-normal">{description}</div>
- )}
- </div>
- </div>
- </ContentCell>
- {permissions.map((permission) => {
- const isPermissionGroup = isPermissionDefinitionGroup(permission);
- const permissionKey = isPermissionGroup ? permission.category : permission.key;
- const isAdminPermission = !isPermissionGroup && permissionKey === Permissions.Admin;
-
- return (
- <PermissionCell
- disabled={
- isGitHubUser ||
- isGitLabUser ||
- (group.name === ANYONE && (isComponentPrivate || isAdminPermission))
- }
- removeOnly={removeOnly}
- key={permissionKey}
- loading={loading}
- onCheck={handleCheck}
- permission={permission}
- permissionItem={group}
- prefixID={group.name}
- selectedPermission={selectedPermission}
- />
- );
- })}
- {modal}
- </TableRowInteractive>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/permissions/HoldersList.tsx b/server/sonar-web/src/main/js/components/permissions/HoldersList.tsx
deleted file mode 100644
index 0dfbb375f55..00000000000
--- a/server/sonar-web/src/main/js/components/permissions/HoldersList.tsx
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { partition } from 'lodash';
-import * as React from 'react';
-import { ContentCell, Table, TableRow, TableSeparator } from '~design-system';
-import UseQuery from '../../helpers/UseQuery';
-import { translate } from '../../helpers/l10n';
-import { isPermissionDefinitionGroup } from '../../helpers/permissions';
-import { useIsGitHubProjectQuery, useIsGitLabProjectQuery } from '../../queries/devops-integration';
-import { useGithubProvisioningEnabledQuery } from '../../queries/identity-provider/github';
-import { Dict, PermissionDefinitions, PermissionGroup, PermissionUser } from '../../types/types';
-import GroupHolder from './GroupHolder';
-import PermissionHeader from './PermissionHeader';
-import UserHolder from './UserHolder';
-
-interface Props {
- filter?: string;
- groups: PermissionGroup[];
- isComponentPrivate?: boolean;
- isProjectManaged: boolean;
- loading?: boolean;
- onSelectPermission?: (permission: string) => void;
- onToggleGroup: (group: PermissionGroup, permission: string) => Promise<void>;
- onToggleUser: (user: PermissionUser, permission: string) => Promise<void>;
- permissions: PermissionDefinitions;
- query?: string;
- selectedPermission?: string;
- users: PermissionUser[];
-}
-
-interface State {
- initialPermissionsCount: Dict<number>;
-}
-export default class HoldersList extends React.PureComponent<
- React.PropsWithChildren<Props>,
- State
-> {
- state: State = { initialPermissionsCount: {} };
- componentDidUpdate(prevProps: Props) {
- if (this.props.filter !== prevProps.filter || this.props.query !== prevProps.query) {
- this.setState({ initialPermissionsCount: {} });
- }
- }
-
- getKey = (item: PermissionGroup | PermissionUser) =>
- this.isPermissionUser(item) ? item.login : (item.id ?? item.name);
-
- isPermissionUser(item: PermissionGroup | PermissionUser): item is PermissionUser {
- return (item as PermissionUser).login !== undefined;
- }
-
- handleGroupToggle = (group: PermissionGroup, permission: string) => {
- const key = group.id || group.name;
- if (this.state.initialPermissionsCount[key] === undefined) {
- this.setState((state) => ({
- initialPermissionsCount: {
- ...state.initialPermissionsCount,
- [key]: group.permissions.length,
- },
- }));
- }
- return this.props.onToggleGroup(group, permission);
- };
-
- handleUserToggle = (user: PermissionUser, permission: string) => {
- if (this.state.initialPermissionsCount[user.login] === undefined) {
- this.setState((state) => ({
- initialPermissionsCount: {
- ...state.initialPermissionsCount,
- [user.login]: user.permissions.length,
- },
- }));
- }
- return this.props.onToggleUser(user, permission);
- };
-
- getItemInitialPermissionsCount = (item: PermissionGroup | PermissionUser) => {
- const key = this.getKey(item);
- return this.state.initialPermissionsCount[key] !== undefined
- ? this.state.initialPermissionsCount[key]
- : item.permissions.length;
- };
-
- renderEmpty() {
- const columns = this.props.permissions.length + 1;
- return (
- <tr>
- <td colSpan={columns}>{translate('no_results_search')}</td>
- </tr>
- );
- }
-
- renderItem(item: PermissionUser | PermissionGroup, permissions: PermissionDefinitions) {
- const { selectedPermission, isComponentPrivate, isProjectManaged } = this.props;
-
- return (
- <UseQuery key={this.getKey(item)} query={useIsGitHubProjectQuery}>
- {({ data: isGitHubProject }) => (
- <UseQuery key={this.getKey(item)} query={useIsGitLabProjectQuery}>
- {({ data: isGitLabProject }) => (
- <UseQuery query={useGithubProvisioningEnabledQuery}>
- {({ data: githubProvisioningStatus }) => (
- <>
- {this.isPermissionUser(item) ? (
- <UserHolder
- key={`user-${item.login}`}
- onToggle={this.handleUserToggle}
- permissions={permissions}
- selectedPermission={selectedPermission}
- user={item}
- isGitHubUser={isGitHubProject && !!githubProvisioningStatus && item.managed}
- isGitLabUser={isGitLabProject && item.managed}
- removeOnly={
- (isGitHubProject && !!githubProvisioningStatus && !item.managed) ||
- (isGitLabProject && isProjectManaged && !item.managed)
- }
- />
- ) : (
- <GroupHolder
- group={item}
- isComponentPrivate={isComponentPrivate}
- key={`group-${item.id || item.name}`}
- onToggle={this.handleGroupToggle}
- permissions={permissions}
- selectedPermission={selectedPermission}
- isGitHubUser={isGitHubProject && !!githubProvisioningStatus && item.managed}
- isGitLabUser={isGitLabProject && item.managed}
- removeOnly={
- (isGitHubProject && !!githubProvisioningStatus && !item.managed) ||
- (isGitLabProject && isProjectManaged && !item.managed)
- }
- />
- )}
- </>
- )}
- </UseQuery>
- )}
- </UseQuery>
- )}
- </UseQuery>
- );
- }
-
- render() {
- const { permissions, users, groups, loading, selectedPermission } = this.props;
- const items = [...groups, ...users];
- const [itemWithPermissions, itemWithoutPermissions] = partition(items, (item) =>
- this.getItemInitialPermissionsCount(item),
- );
-
- const HEADER_COLUMNS = permissions.length + 1;
-
- const tableHeader = (
- <TableRow>
- <ContentCell />
- {permissions.map((permission) => (
- <PermissionHeader
- key={isPermissionDefinitionGroup(permission) ? permission.category : permission.key}
- onSelectPermission={this.props.onSelectPermission}
- permission={permission}
- selectedPermission={selectedPermission}
- />
- ))}
- </TableRow>
- );
-
- return (
- <div>
- <Table
- columnWidths={[500, ...permissions.map(() => 100)]}
- className="it__permission-list"
- noHeaderTopBorder
- columnCount={HEADER_COLUMNS}
- header={tableHeader}
- >
- {items.length === 0 && !loading && this.renderEmpty()}
- {itemWithPermissions.map((item) => this.renderItem(item, permissions))}
- {itemWithPermissions.length > 0 && itemWithoutPermissions.length > 0 && (
- <TableSeparator />
- )}
- {itemWithoutPermissions.map((item) => this.renderItem(item, permissions))}
- </Table>
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/permissions/PermissionCell.tsx b/server/sonar-web/src/main/js/components/permissions/PermissionCell.tsx
deleted file mode 100644
index ab871566f6c..00000000000
--- a/server/sonar-web/src/main/js/components/permissions/PermissionCell.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { Checkbox, CheckboxCell } from '~design-system';
-import { translateWithParameters } from '../../helpers/l10n';
-import { isPermissionDefinitionGroup } from '../../helpers/permissions';
-import {
- PermissionDefinition,
- PermissionDefinitionGroup,
- PermissionGroup,
- PermissionUser,
-} from '../../types/types';
-
-export interface PermissionCellProps {
- disabled?: boolean;
- loading: string[];
- onCheck: (checked: boolean, permission?: string) => void;
- permission: PermissionDefinition | PermissionDefinitionGroup;
- permissionItem: PermissionGroup | PermissionUser;
- prefixID: string;
- removeOnly?: boolean;
- selectedPermission?: string;
-}
-
-export default function PermissionCell(props: PermissionCellProps) {
- const {
- disabled,
- loading,
- onCheck,
- permission,
- permissionItem,
- selectedPermission,
- removeOnly,
- prefixID,
- } = props;
-
- if (isPermissionDefinitionGroup(permission)) {
- return (
- <CheckboxCell>
- <div className="sw-flex sw-flex-col sw-text-left">
- {permission.permissions.map((permissionDefinition) => {
- const isChecked = permissionItem.permissions.includes(permissionDefinition.key);
- const isDisabled = disabled || loading.includes(permissionDefinition.key);
-
- return (
- <div key={permissionDefinition.key}>
- <Checkbox
- aria-disabled={isDisabled || (!isChecked && removeOnly)}
- checked={isChecked}
- disabled={isDisabled || (!isChecked && removeOnly)}
- id={`${permissionDefinition.key}`}
- label={translateWithParameters(
- 'permission.assign_x_to_y',
- permissionDefinition.name,
- permissionItem.name,
- )}
- onCheck={() => onCheck(isChecked, permissionDefinition.key)}
- >
- <span className="sw-ml-2">{permissionDefinition.name}</span>
- </Checkbox>
- </div>
- );
- })}
- </div>
- </CheckboxCell>
- );
- }
-
- const isChecked = permissionItem.permissions.includes(permission.key);
- const isDisabled = disabled || loading.includes(permission.key);
-
- return (
- <CheckboxCell
- className={classNames({
- selected: permission.key === selectedPermission,
- })}
- >
- <Checkbox
- aria-disabled={isDisabled || (!isChecked && removeOnly)}
- checked={isChecked}
- disabled={isDisabled || (!isChecked && removeOnly)}
- id={`${prefixID}-${permission.key}`}
- label={translateWithParameters(
- 'permission.assign_x_to_y',
- permission.name,
- permissionItem.name,
- )}
- onCheck={() => onCheck(isChecked, permission.key)}
- />
- </CheckboxCell>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/permissions/PermissionHeader.tsx b/server/sonar-web/src/main/js/components/permissions/PermissionHeader.tsx
deleted file mode 100644
index f25c86e27dd..00000000000
--- a/server/sonar-web/src/main/js/components/permissions/PermissionHeader.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import * as React from 'react';
-import { BareButton, ContentCell, HelperHintIcon } from '~design-system';
-import HelpTooltip from '~sonar-aligned/components/controls/HelpTooltip';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { isPermissionDefinitionGroup } from '../../helpers/permissions';
-import { PermissionDefinition, PermissionDefinitionGroup } from '../../types/types';
-import InstanceMessage from '../common/InstanceMessage';
-import ClickEventBoundary from '../controls/ClickEventBoundary';
-import Tooltip from '../controls/Tooltip';
-
-interface Props {
- onSelectPermission?: (permission: string) => void;
- permission: PermissionDefinition | PermissionDefinitionGroup;
- selectedPermission?: string;
-}
-
-export default class PermissionHeader extends React.PureComponent<Props> {
- handlePermissionClick = () => {
- const { permission } = this.props;
- if (this.props.onSelectPermission && !isPermissionDefinitionGroup(permission)) {
- this.props.onSelectPermission(permission.key);
- }
- };
-
- getTooltipOverlay = () => {
- const { permission } = this.props;
-
- if (isPermissionDefinitionGroup(permission)) {
- return permission.permissions.map((permission) => (
- <React.Fragment key={permission.key}>
- <b className="sw-mr-1">{permission.name}:</b>
- <InstanceMessage key={permission.key} message={permission.description} />
- <br />
- </React.Fragment>
- ));
- }
-
- return <InstanceMessage message={permission.description} />;
- };
-
- render() {
- const { onSelectPermission, permission } = this.props;
- let name;
- if (isPermissionDefinitionGroup(permission)) {
- name = translate('global_permissions', permission.category);
- } else {
- name = onSelectPermission ? (
- <ClickEventBoundary>
- <BareButton onClick={this.handlePermissionClick}>
- <Tooltip
- content={translateWithParameters(
- 'global_permissions.filter_by_x_permission',
- permission.name,
- )}
- >
- <span>{permission.name}</span>
- </Tooltip>
- </BareButton>
- </ClickEventBoundary>
- ) : (
- permission.name
- );
- }
- return (
- <ContentCell
- scope="col"
- className={classNames('sw-justify-center', {
- selected:
- !isPermissionDefinitionGroup(permission) &&
- permission.key === this.props.selectedPermission,
- })}
- >
- <div className="sw-flex sw-content-center">
- <div className="sw-grow-1 sw-text-center">{name}</div>
-
- <HelpTooltip className="sw-ml-2" overlay={this.getTooltipOverlay()}>
- <HelperHintIcon aria-label="help-tooltip" />
- </HelpTooltip>
- </div>
- </ContentCell>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/permissions/SearchForm.tsx b/server/sonar-web/src/main/js/components/permissions/SearchForm.tsx
deleted file mode 100644
index fd94aaaa6c4..00000000000
--- a/server/sonar-web/src/main/js/components/permissions/SearchForm.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { InputSearch, ToggleButton } from '~design-system';
-import { translate } from '../../helpers/l10n';
-
-export type FilterOption = 'all' | 'users' | 'groups';
-interface Props {
- filter: FilterOption;
- onFilter: (value: FilterOption) => void;
- onSearch: (value: string) => void;
- query: string;
-}
-
-export default function SearchForm(props: Props) {
- const filterOptions = [
- { value: 'all', label: translate('all') },
- { value: 'users', label: translate('users.page') },
- { value: 'groups', label: translate('user_groups.page') },
- ];
-
- return (
- <div className="sw-flex sw-flex-row">
- <ToggleButton onChange={props.onFilter} options={filterOptions} value={props.filter} />
-
- <div className="sw-flex-1 sw-ml-2">
- <InputSearch
- minLength={3}
- onChange={props.onSearch}
- placeholder={translate('search.search_for_users_or_groups')}
- value={props.query}
- />
- </div>
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/permissions/UserHolder.tsx b/server/sonar-web/src/main/js/components/permissions/UserHolder.tsx
deleted file mode 100644
index f3c95711946..00000000000
--- a/server/sonar-web/src/main/js/components/permissions/UserHolder.tsx
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Avatar, ContentCell, Note, TableRowInteractive } from '~design-system';
-import { Image } from '~sonar-aligned/components/common/Image';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { isPermissionDefinitionGroup } from '../../helpers/permissions';
-import { isDefined } from '../../helpers/types';
-import { PermissionDefinitions, PermissionUser } from '../../types/types';
-import PermissionCell from './PermissionCell';
-import usePermissionChange from './usePermissionChange';
-
-interface Props {
- isGitHubUser: boolean | undefined;
- isGitLabUser: boolean | undefined;
- onToggle: (user: PermissionUser, permission: string) => Promise<void>;
- permissions: PermissionDefinitions;
- removeOnly?: boolean;
- selectedPermission?: string;
- user: PermissionUser;
-}
-
-export default function UserHolder(props: Props) {
- const { user, removeOnly, permissions, selectedPermission, isGitHubUser, isGitLabUser } = props;
- const { loading, handleCheck, modal } = usePermissionChange({
- holder: user,
- onToggle: props.onToggle,
- permissions,
- removeOnly,
- });
-
- const permissionCells = permissions.map((permission) => (
- <PermissionCell
- key={isPermissionDefinitionGroup(permission) ? permission.category : permission.key}
- loading={loading}
- onCheck={handleCheck}
- permission={permission}
- disabled={isGitHubUser || isGitLabUser}
- removeOnly={removeOnly}
- permissionItem={user}
- prefixID={user.login}
- selectedPermission={selectedPermission}
- />
- ));
-
- if (user.login === '<creator>') {
- return (
- <TableRowInteractive>
- <ContentCell>
- <div className="sw-max-w-abs-800">
- <div className="sw-flex sw-flex-col sw-w-fit sw-max-w-full">
- <strong className="sw-text-ellipsis sw-whitespace-nowrap sw-overflow-hidden">
- {user.name}
- </strong>
- <p className="sw-mt-2">
- {translate('permission_templates.project_creators.explanation')}
- </p>
- </div>
- </div>
- </ContentCell>
- {permissionCells}
- </TableRowInteractive>
- );
- }
-
- return (
- <TableRowInteractive>
- <ContentCell>
- <div className="sw-flex sw-items-center">
- <Avatar className="sw-mr-4" hash={user.avatar} name={user.name} size="md" />
- <div className="sw-max-w-abs-800">
- <div className="sw-flex sw-w-fit sw-max-w-full">
- <div className="sw-flex-1 sw-text-ellipsis sw-whitespace-nowrap sw-overflow-hidden">
- <strong>{user.name}</strong>
- <Note className="sw-ml-2">{user.login}</Note>
- </div>
- {isGitHubUser && (
- <Image
- alt="github"
- className="sw-ml-2"
- height={16}
- aria-label={translateWithParameters(
- 'project_permission.managed',
- translate('alm.github'),
- )}
- src="/images/alm/github.svg"
- />
- )}
- {isGitLabUser && (
- <Image
- alt="gitlab"
- className="sw-ml-2"
- height={16}
- aria-label={translateWithParameters(
- 'project_permission.managed',
- translate('alm.gitlab'),
- )}
- src="/images/alm/gitlab.svg"
- />
- )}
- </div>
- {isDefined(user.email) && (
- <div className="sw-mt-2 sw-max-w-100 sw-text-ellipsis sw-whitespace-nowrap sw-overflow-hidden">
- {user.email}
- </div>
- )}
- </div>
- </div>
- </ContentCell>
- {permissionCells}
- {modal}
- </TableRowInteractive>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/permissions/usePermissionChange.tsx b/server/sonar-web/src/main/js/components/permissions/usePermissionChange.tsx
deleted file mode 100644
index 2bddd7d9e5f..00000000000
--- a/server/sonar-web/src/main/js/components/permissions/usePermissionChange.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { without } from 'lodash';
-import React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { translate } from '../../helpers/l10n';
-import { isPermissionDefinitionGroup } from '../../helpers/permissions';
-import {
- PermissionDefinition,
- PermissionDefinitions,
- PermissionGroup,
- PermissionUser,
-} from '../../types/types';
-import ConfirmModal from '../controls/ConfirmModal';
-
-interface Props<T extends PermissionGroup | PermissionUser> {
- holder: T;
- onToggle: (holder: T, permission: string) => Promise<void>;
- permissions: PermissionDefinitions;
- removeOnly?: boolean;
-}
-
-export default function usePermissionChange<T extends PermissionGroup | PermissionUser>(
- props: Props<T>,
-) {
- const { holder, removeOnly, permissions } = props;
- const [loading, setLoading] = React.useState<string[]>([]);
- const [confirmPermission, setConfirmPermission] = React.useState<PermissionDefinition | null>(
- null,
- );
-
- const stopLoading = (permission: string) => {
- setLoading((prevState) => without(prevState, permission));
- };
-
- const handleCheck = (_checked: boolean, permissionKey?: string) => {
- if (permissionKey !== undefined) {
- if (removeOnly) {
- const flatPermissions = permissions.reduce<PermissionDefinition[]>(
- (acc, p) => (isPermissionDefinitionGroup(p) ? [...acc, ...p.permissions] : [...acc, p]),
- [],
- );
- setConfirmPermission(flatPermissions.find((p) => p.key === permissionKey) ?? null);
- } else {
- handleChangePermission(permissionKey);
- }
- }
- };
-
- const handleChangePermission = (permission: string) => {
- setLoading((prevState) => [...prevState, permission]);
- return props.onToggle(holder, permission).then(
- () => stopLoading(permission),
- () => stopLoading(permission),
- );
- };
-
- const modal = (
- <>
- {confirmPermission && (
- <ConfirmModal
- confirmButtonText={translate('confirm')}
- header={translate('project_permission.remove_only_confirmation_title')}
- isDestructive
- isOpen
- onClose={() => setConfirmPermission(null)}
- onConfirm={() => handleChangePermission(confirmPermission.key)}
- >
- <FormattedMessage
- defaultMessage={translate('project_permission.remove_only_confirmation')}
- id="project_permission.remove_only_confirmation"
- values={{
- permission: <b>{confirmPermission.name}</b>,
- holder: <b>{holder.name}</b>,
- }}
- />
- </ConfirmModal>
- )}
- </>
- );
-
- return { handleCheck, modal, loading };
-}
diff --git a/server/sonar-web/src/main/js/components/rules/AiCodeFixTab.tsx b/server/sonar-web/src/main/js/components/rules/AiCodeFixTab.tsx
deleted file mode 100644
index 40085e539ca..00000000000
--- a/server/sonar-web/src/main/js/components/rules/AiCodeFixTab.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, ButtonVariety } from '@sonarsource/echoes-react';
-import { InProgressVisual, OverviewQGNotComputedIcon, OverviewQGPassedIcon } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { usePrefetchSuggestion, useUnifiedSuggestionsQuery } from '../../queries/fix-suggestions';
-import { useRawSourceQuery } from '../../queries/sources';
-import { getBranchLikeQuery } from '../../sonar-aligned/helpers/branch-like';
-import { BranchLike } from '../../types/branch-like';
-import { Issue } from '../../types/types';
-import { IssueSuggestionFileSnippet } from './IssueSuggestionFileSnippet';
-
-interface Props {
- branchLike?: BranchLike;
- issue: Issue;
- language?: string;
-}
-
-export function AiCodeFixTab({ branchLike, issue, language }: Readonly<Props>) {
- const prefetchSuggestion = usePrefetchSuggestion(issue.key);
- const { isPending, isLoading, isError, refetch } = useUnifiedSuggestionsQuery(issue, false);
- const { isError: isIssueRawError } = useRawSourceQuery({
- ...getBranchLikeQuery(branchLike),
- key: issue.component,
- });
-
- return (
- <>
- {isPending && !isLoading && !isError && (
- <div className="sw-flex sw-flex-col sw-items-center">
- <OverviewQGPassedIcon className="sw-mt-6" />
- <p className="sw-typo-semibold sw-mt-4">
- {translate('issues.code_fix.let_us_suggest_fix')}
- </p>
- <Button
- className="sw-mt-4"
- onClick={() => prefetchSuggestion()}
- variety={ButtonVariety.Primary}
- >
- {translate('issues.code_fix.get_a_fix_suggestion')}
- </Button>
- </div>
- )}
- {isLoading && (
- <div className="sw-flex sw-pt-6 sw-flex-col sw-items-center">
- <InProgressVisual />
- <p className="sw-typo-semibold sw-mt-4">
- {translate('issues.code_fix.fix_is_being_generated')}
- </p>
- </div>
- )}
- {isError && (
- <div className="sw-flex sw-flex-col sw-items-center">
- <OverviewQGNotComputedIcon className="sw-mt-6" />
- <p className="sw-typo-semibold sw-mt-4">
- {translate('issues.code_fix.something_went_wrong')}
- </p>
- <p className="sw-my-4">{translate('issues.code_fix.not_able_to_generate_fix')}</p>
- {translate('issues.code_fix.check_how_to_fix')}
- {!isIssueRawError && (
- <Button className="sw-mt-4" onClick={() => refetch()} variety={ButtonVariety.Primary}>
- {translate('issues.code_fix.get_a_fix_suggestion')}
- </Button>
- )}
- </div>
- )}
-
- {!isPending && !isError && (
- <IssueSuggestionFileSnippet branchLike={branchLike} issue={issue} language={language} />
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/rules/CveDetails.tsx b/server/sonar-web/src/main/js/components/rules/CveDetails.tsx
deleted file mode 100644
index c5b6b84816e..00000000000
--- a/server/sonar-web/src/main/js/components/rules/CveDetails.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ContentCell, Table, TableRow } from '~design-system';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { Cve } from '../../types/cves';
-import DateFormatter from '../intl/DateFormatter';
-
-type Props = {
- cve: Cve;
-};
-
-export function CveDetails({ cve }: Readonly<Props>) {
- const { id, description, cwes, cvssScore, epssScore, epssPercentile, publishedAt } = cve;
- return (
- <>
- <h2>{id}</h2>
- <p>{description}</p>
- <Table columnCount={2} aria-label={translate('rule.cve_details')}>
- {cwes.length > 0 && (
- <TableRow>
- <ContentCell>{translate('rule.cve_details.cwes')}</ContentCell>
- <ContentCell>{cwes.join(', ')}</ContentCell>
- </TableRow>
- )}
- <TableRow>
- <ContentCell>{translate('rule.cve_details.epss_score')}</ContentCell>
- <ContentCell>
- {translateWithParameters(
- 'rule.cve_details.epss_score.value',
- Math.round(epssScore * 100),
- Math.round(epssPercentile * 100),
- )}
- </ContentCell>
- </TableRow>
- {typeof cvssScore === 'number' && (
- <TableRow>
- <ContentCell>{translate('rule.cve_details.cvss_score')}</ContentCell>
- <ContentCell>{cvssScore.toFixed(1)}</ContentCell>
- </TableRow>
- )}
- <TableRow>
- <ContentCell>{translate('rule.cve_details.published_date')}</ContentCell>
- <ContentCell>
- <DateFormatter date={publishedAt} />
- </ContentCell>
- </TableRow>
- </Table>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/rules/IssueSuggestionFileSnippet.tsx b/server/sonar-web/src/main/js/components/rules/IssueSuggestionFileSnippet.tsx
deleted file mode 100644
index 082999567ec..00000000000
--- a/server/sonar-web/src/main/js/components/rules/IssueSuggestionFileSnippet.tsx
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { max } from 'lodash';
-import { Fragment, useCallback, useEffect, useState } from 'react';
-
-import {
- ClipboardIconButton,
- CodeEllipsisDirection,
- CodeEllipsisIcon,
- LineCodeEllipsisStyled,
- SonarCodeColorizer,
- themeColor,
-} from '~design-system';
-import { OpenFixInIde } from '../../apps/issues/components/OpenFixInIde';
-import { IssueSourceViewerHeader } from '../../apps/issues/crossComponentSourceViewer/IssueSourceViewerHeader';
-import { translate } from '../../helpers/l10n';
-import { useComponentForSourceViewer } from '../../queries/component';
-import {
- DisplayedLine,
- LineTypeEnum,
- useUnifiedSuggestionsQuery,
-} from '../../queries/fix-suggestions';
-import { BranchLike } from '../../types/branch-like';
-import { Issue } from '../../types/types';
-import { IssueSuggestionLine } from './IssueSuggestionLine';
-
-interface Props {
- branchLike?: BranchLike;
- issue: Issue;
- language?: string;
-}
-
-const EXPAND_SIZE = 10;
-const BUFFER_CODE = 3;
-
-export function IssueSuggestionFileSnippet({ branchLike, issue, language }: Readonly<Props>) {
- const [displayedLine, setDisplayedLine] = useState<DisplayedLine[]>([]);
-
- const { data: suggestion } = useUnifiedSuggestionsQuery(issue);
-
- const { data: sourceViewerFile } = useComponentForSourceViewer(issue.component, branchLike);
-
- useEffect(() => {
- if (suggestion !== undefined) {
- setDisplayedLine(
- suggestion.unifiedLines.filter((line, index) => {
- if (line.type !== LineTypeEnum.CODE) {
- return true;
- }
- return suggestion.unifiedLines
- .slice(max([index - BUFFER_CODE, 0]), index + BUFFER_CODE + 1)
- .some((line) => line.type !== LineTypeEnum.CODE);
- }),
- );
- }
- }, [suggestion]);
-
- const handleExpand = useCallback(
- (index: number | undefined, at: number | undefined, to: number) => {
- if (suggestion !== undefined) {
- setDisplayedLine((current) => {
- return [
- ...current.slice(0, index),
- ...suggestion.unifiedLines.filter(
- (line) => at !== undefined && at <= line.lineBefore && line.lineBefore < to,
- ),
- ...current.slice(index),
- ];
- });
- }
- },
- [suggestion],
- );
-
- if (suggestion === undefined) {
- return null;
- }
-
- return (
- <div>
- {sourceViewerFile && (
- <IssueSourceViewerHeader
- issueKey={issue.key}
- sourceViewerFile={sourceViewerFile}
- shouldShowOpenInIde={false}
- shouldShowViewAllIssues={false}
- secondaryActions={<OpenFixInIde aiSuggestion={suggestion} issue={issue} />}
- />
- )}
- <SourceFileWrapper className="js-source-file sw-mb-4">
- <SonarCodeColorizer>
- {displayedLine[0]?.lineBefore !== 1 && (
- <LineCodeEllipsisStyled
- onClick={() =>
- handleExpand(
- 0,
- max([displayedLine[0].lineBefore - EXPAND_SIZE, 0]),
- displayedLine[0].lineBefore,
- )
- }
- style={{ borderTop: 'none' }}
- >
- <CodeEllipsisIcon direction={CodeEllipsisDirection.Up} />
- </LineCodeEllipsisStyled>
- )}
- {displayedLine.map((line, index) => (
- <Fragment key={`${line.lineBefore} -> ${line.lineAfter} `}>
- {displayedLine[index - 1] !== undefined &&
- displayedLine[index - 1].lineBefore !== -1 &&
- line.lineBefore !== -1 &&
- displayedLine[index - 1].lineBefore !== line.lineBefore - 1 && (
- <>
- {line.lineBefore - displayedLine[index - 1].lineBefore > EXPAND_SIZE ? (
- <>
- <LineCodeEllipsisStyled
- onClick={() =>
- handleExpand(
- index,
- displayedLine[index - 1].lineBefore + 1,
- displayedLine[index - 1].lineBefore + EXPAND_SIZE + 1,
- )
- }
- >
- <CodeEllipsisIcon direction={CodeEllipsisDirection.Down} />
- </LineCodeEllipsisStyled>
- <LineCodeEllipsisStyled
- onClick={() =>
- handleExpand(index, line.lineBefore - EXPAND_SIZE, line.lineBefore)
- }
- style={{ borderTop: 'none' }}
- >
- <CodeEllipsisIcon direction={CodeEllipsisDirection.Up} />
- </LineCodeEllipsisStyled>
- </>
- ) : (
- <LineCodeEllipsisStyled
- onClick={() =>
- handleExpand(
- index,
- displayedLine[index - 1].lineBefore + 1,
- line.lineBefore,
- )
- }
- >
- <CodeEllipsisIcon direction={CodeEllipsisDirection.Middle} />
- </LineCodeEllipsisStyled>
- )}
- </>
- )}
- <div className="sw-relative">
- {line.copy !== undefined && (
- <StyledClipboardIconButton
- aria-label={translate('component_viewer.copy_path_to_clipboard')}
- copyValue={line.copy}
- />
- )}
- <IssueSuggestionLine
- language={language}
- line={line.code}
- lineAfter={line.lineAfter}
- lineBefore={line.lineBefore}
- type={line.type}
- />
- </div>
- </Fragment>
- ))}
-
- {displayedLine[displayedLine.length - 1]?.lineBefore !==
- suggestion.unifiedLines[suggestion.unifiedLines.length - 1]?.lineBefore && (
- <LineCodeEllipsisStyled
- onClick={() =>
- handleExpand(
- displayedLine.length,
- displayedLine[displayedLine.length - 1].lineBefore + 1,
- displayedLine[displayedLine.length - 1].lineBefore + EXPAND_SIZE + 1,
- )
- }
- style={{ borderBottom: 'none' }}
- >
- <CodeEllipsisIcon direction={CodeEllipsisDirection.Down} />
- </LineCodeEllipsisStyled>
- )}
- </SonarCodeColorizer>
- </SourceFileWrapper>
- <p className="sw-mt-4">{suggestion.explanation}</p>
- </div>
- );
-}
-
-const StyledClipboardIconButton = styled(ClipboardIconButton)`
- position: absolute;
- right: 4px;
- top: -4px;
- z-index: 9;
-`;
-
-const SourceFileWrapper = styled.div`
- border: 1px solid ${themeColor('codeLineBorder')};
-`;
diff --git a/server/sonar-web/src/main/js/components/rules/IssueSuggestionLine.tsx b/server/sonar-web/src/main/js/components/rules/IssueSuggestionLine.tsx
deleted file mode 100644
index bc041592846..00000000000
--- a/server/sonar-web/src/main/js/components/rules/IssueSuggestionLine.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import {
- CodeSyntaxHighlighter,
- LineMeta,
- LineStyled,
- SuggestedLineWrapper,
- themeBorder,
- themeColor,
-} from '~design-system';
-import { LineTypeEnum } from '../../queries/fix-suggestions';
-
-type LineType = 'code' | 'added' | 'removed';
-
-export function IssueSuggestionLine({
- language,
- line,
- lineAfter,
- lineBefore,
- type = 'code',
-}: Readonly<{
- language?: string;
- line: string;
- lineAfter: number;
- lineBefore: number;
- type: LineType;
-}>) {
- return (
- <SuggestedLineWrapper>
- <LineMeta as="div">
- {type !== LineTypeEnum.ADDED && (
- <LineNumberStyled className="sw-px-1 sw-inline-block">{lineBefore}</LineNumberStyled>
- )}
- </LineMeta>
- <LineMeta as="div">
- {type !== LineTypeEnum.REMOVED && (
- <LineNumberStyled className="sw-px-1 sw-inline-block">{lineAfter}</LineNumberStyled>
- )}
- </LineMeta>
- <LineDirectionMeta as="div">
- {type === LineTypeEnum.REMOVED && (
- <RemovedLineLayer className="sw-px-2">-</RemovedLineLayer>
- )}
- {type === LineTypeEnum.ADDED && <AddedLineLayer className="sw-px-2">+</AddedLineLayer>}
- </LineDirectionMeta>
- <LineCodeLayers>
- {type === LineTypeEnum.CODE && (
- <LineCodeLayer className="sw-px-3">
- <CodeSyntaxHighlighter
- htmlAsString={`<pre style="white-space: pre-wrap;">${line}</pre>`}
- language={language}
- escapeDom={false}
- />
- </LineCodeLayer>
- )}
- {type === LineTypeEnum.REMOVED && (
- <RemovedLineLayer className="sw-px-3">
- <LineCodePreFormatted>
- <CodeSyntaxHighlighter
- htmlAsString={`<pre style="white-space: pre-wrap;">${line}</pre>`}
- language={language}
- escapeDom={false}
- />
- </LineCodePreFormatted>
- </RemovedLineLayer>
- )}
- {type === LineTypeEnum.ADDED && (
- <AddedLineLayer className="sw-px-3">
- <LineCodePreFormatted>
- <CodeSyntaxHighlighter
- htmlAsString={`<pre style="white-space: pre-wrap;">${line}</pre>`}
- language={language}
- escapeDom={false}
- />
- </LineCodePreFormatted>
- </AddedLineLayer>
- )}
- </LineCodeLayers>
- </SuggestedLineWrapper>
- );
-}
-
-const LineNumberStyled = styled.div`
- &:hover {
- color: var(--echoes-color-text-subdued);
- }
-
- &:focus-visible {
- outline-offset: -1px;
- }
-`;
-
-const LineCodeLayers = styled.div`
- position: relative;
- display: grid;
- height: 100%;
- background-color: var(--line-background);
-
- ${LineStyled}:hover & {
- background-color: ${themeColor('codeLineHover')};
- }
-`;
-
-const LineDirectionMeta = styled(LineMeta)`
- border-left: ${themeBorder('default', 'codeLineBorder')};
-`;
-
-const LineCodeLayer = styled.div`
- grid-row: 1;
- grid-column: 1;
-`;
-
-const LineCodePreFormatted = styled.pre`
- position: relative;
- white-space: pre-wrap;
- overflow-wrap: anywhere;
- tab-size: 4;
-`;
-
-const AddedLineLayer = styled.div`
- background-color: ${themeColor('codeLineCoveredUnderline')};
-`;
-
-const RemovedLineLayer = styled.div`
- background-color: ${themeColor('codeLineUncoveredUnderline')};
-`;
diff --git a/server/sonar-web/src/main/js/components/rules/IssueTabViewer.tsx b/server/sonar-web/src/main/js/components/rules/IssueTabViewer.tsx
deleted file mode 100644
index a404df9802a..00000000000
--- a/server/sonar-web/src/main/js/components/rules/IssueTabViewer.tsx
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { cloneDeep, debounce, groupBy } from 'lodash';
-import * as React from 'react';
-import { Location } from 'react-router-dom';
-import { LAYOUT_FOOTER_HEIGHT, ToggleButton } from '~design-system';
-import { dismissNotice } from '../../api/users';
-import { CurrentUserContextInterface } from '../../app/components/current-user/CurrentUserContext';
-import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext';
-import { RuleDescriptionSections } from '../../apps/coding-rules/rule';
-import IssueHeader from '../../apps/issues/components/IssueHeader';
-import StyledHeader from '../../apps/issues/components/StyledHeader';
-import { fillBranchLike } from '../../helpers/branch-like';
-import { translate } from '../../helpers/l10n';
-import { withUseGetFixSuggestionsIssues } from '../../queries/fix-suggestions';
-import { Issue, RuleDetails } from '../../types/types';
-import { CurrentUser, NoticeType } from '../../types/users';
-import ScreenPositionHelper from '../common/ScreenPositionHelper';
-import withLocation from '../hoc/withLocation';
-import MoreInfoRuleDescription from './MoreInfoRuleDescription';
-import RuleDescription from './RuleDescription';
-import { TabSelectorContext } from './TabSelectorContext';
-
-interface IssueTabViewerProps extends CurrentUserContextInterface {
- activityTabContent?: React.ReactNode;
- aiSuggestionAvailable: boolean;
- codeTabContent?: React.ReactNode;
- currentUser: CurrentUser;
- cveId?: string;
- extendedDescription?: string;
- issue: Issue;
- location: Location;
- onIssueChange: (issue: Issue) => void;
- ruleDescriptionContextKey?: string;
- ruleDetails: RuleDetails;
- selectedFlowIndex?: number;
- selectedLocationIndex?: number;
- suggestionTabContent?: React.ReactNode;
-}
-interface State {
- displayEducationalPrinciplesNotification?: boolean;
- educationalPrinciplesNotificationHasBeenDismissed?: boolean;
- selectedTab?: Tab;
- tabs: Tab[];
-}
-
-export interface Tab {
- content: React.ReactNode;
- counter?: number;
- key: TabKeys;
- label: string;
- value: TabKeys;
-}
-
-export enum TabKeys {
- Code = 'code',
- WhyIsThisAnIssue = 'why',
- HowToFixIt = 'how_to_fix',
- AssessTheIssue = 'assess_the_problem',
- CodeFix = 'code_fix',
- Activity = 'activity',
- MoreInfo = 'more_info',
-}
-
-const DEBOUNCE_FOR_SCROLL = 250;
-
-export class IssueTabViewer extends React.PureComponent<IssueTabViewerProps, State> {
- headerNode?: HTMLElement | null = null;
- state: State = {
- tabs: [],
- };
-
- educationPrinciplesRef: React.RefObject<HTMLDivElement>;
-
- constructor(props: IssueTabViewerProps) {
- super(props);
-
- this.educationPrinciplesRef = React.createRef();
-
- this.checkIfEducationPrinciplesAreVisible = debounce(
- this.checkIfEducationPrinciplesAreVisible,
- DEBOUNCE_FOR_SCROLL,
- );
- }
-
- componentDidMount() {
- this.setState((prevState) => this.computeState(prevState));
- this.attachScrollEvent();
-
- const tabs = this.computeTabs(Boolean(this.state.displayEducationalPrinciplesNotification));
-
- const query = new URLSearchParams(this.props.location.search);
-
- if (query.has('why')) {
- this.setState({
- selectedTab: tabs.find((tab) => tab.key === TabKeys.WhyIsThisAnIssue) || tabs[0],
- });
- }
- }
-
- componentDidUpdate(prevProps: IssueTabViewerProps, prevState: State) {
- const {
- ruleDetails,
- ruleDescriptionContextKey,
- currentUser,
- issue,
- selectedFlowIndex,
- selectedLocationIndex,
- aiSuggestionAvailable,
- } = this.props;
-
- const { selectedTab } = this.state;
-
- if (
- prevProps.ruleDetails.key !== ruleDetails.key ||
- prevProps.ruleDescriptionContextKey !== ruleDescriptionContextKey ||
- prevProps.issue !== issue ||
- prevProps.selectedFlowIndex !== selectedFlowIndex ||
- (prevProps.selectedLocationIndex ?? -1) !== (selectedLocationIndex ?? -1) ||
- prevProps.currentUser !== currentUser ||
- prevProps.aiSuggestionAvailable !== aiSuggestionAvailable
- ) {
- this.setState((pState) =>
- this.computeState(
- pState,
- prevProps.ruleDetails !== ruleDetails ||
- (prevProps.issue && issue && prevProps.issue.key !== issue.key) ||
- prevProps.selectedFlowIndex !== selectedFlowIndex ||
- prevProps.selectedLocationIndex !== selectedLocationIndex,
- ),
- );
- }
-
- if (selectedTab?.key === TabKeys.MoreInfo) {
- this.checkIfEducationPrinciplesAreVisible();
- }
-
- if (
- prevState.selectedTab?.key === TabKeys.MoreInfo &&
- prevState.displayEducationalPrinciplesNotification &&
- prevState.educationalPrinciplesNotificationHasBeenDismissed
- ) {
- this.props.updateDismissedNotices(NoticeType.EDUCATION_PRINCIPLES, true);
- }
- }
-
- componentWillUnmount() {
- this.detachScrollEvent();
- }
-
- computeState = (prevState: State, resetSelectedTab = false) => {
- const {
- ruleDetails,
- currentUser: { isLoggedIn, dismissedNotices },
- } = this.props;
-
- const displayEducationalPrinciplesNotification =
- !!ruleDetails.educationPrinciples &&
- ruleDetails.educationPrinciples.length > 0 &&
- isLoggedIn &&
- !dismissedNotices[NoticeType.EDUCATION_PRINCIPLES];
-
- const tabs = this.computeTabs(displayEducationalPrinciplesNotification);
-
- const selectedTab =
- resetSelectedTab || !prevState.selectedTab ? tabs[0] : prevState.selectedTab;
-
- return {
- tabs,
- selectedTab,
- displayEducationalPrinciplesNotification,
- };
- };
-
- computeTabs = (displayEducationalPrinciplesNotification: boolean) => {
- const {
- codeTabContent,
- ruleDetails: { descriptionSections, educationPrinciples, lang: ruleLanguage, type: ruleType },
- ruleDescriptionContextKey,
- extendedDescription,
- activityTabContent,
- cveId,
- issue,
- suggestionTabContent,
- aiSuggestionAvailable,
- } = this.props;
-
- // As we might tamper with the description later on, we clone to avoid any side effect
- const descriptionSectionsByKey = cloneDeep(
- groupBy(descriptionSections, (section) => section.key),
- );
-
- if (extendedDescription) {
- if (descriptionSectionsByKey[RuleDescriptionSections.RESOURCES]?.length > 0) {
- // We add the extended description (htmlNote) in the first context, in case there are contexts
- // Extended description will get reworked in future
- descriptionSectionsByKey[RuleDescriptionSections.RESOURCES][0].content +=
- '<br/>' + extendedDescription;
- } else {
- descriptionSectionsByKey[RuleDescriptionSections.RESOURCES] = [
- {
- key: RuleDescriptionSections.RESOURCES,
- content: extendedDescription,
- },
- ];
- }
- }
-
- const tabs: Tab[] = [
- {
- value: TabKeys.WhyIsThisAnIssue,
- key: TabKeys.WhyIsThisAnIssue,
- label:
- ruleType === 'SECURITY_HOTSPOT'
- ? translate('coding_rules.description_section.title.root_cause.SECURITY_HOTSPOT')
- : translate('coding_rules.description_section.title.root_cause'),
- content: (descriptionSectionsByKey[RuleDescriptionSections.DEFAULT] ||
- descriptionSectionsByKey[RuleDescriptionSections.ROOT_CAUSE]) && (
- <RuleDescription
- defaultContextKey={ruleDescriptionContextKey}
- language={ruleLanguage}
- sections={(
- descriptionSectionsByKey[RuleDescriptionSections.DEFAULT] ??
- descriptionSectionsByKey[RuleDescriptionSections.ROOT_CAUSE]
- ).concat(descriptionSectionsByKey[RuleDescriptionSections.INTRODUCTION] ?? [])}
- cveId={cveId}
- />
- ),
- },
- {
- value: TabKeys.AssessTheIssue,
- key: TabKeys.AssessTheIssue,
- label: translate('coding_rules.description_section.title', TabKeys.AssessTheIssue),
- content: descriptionSectionsByKey[RuleDescriptionSections.ASSESS_THE_PROBLEM] && (
- <RuleDescription
- language={ruleLanguage}
- sections={descriptionSectionsByKey[RuleDescriptionSections.ASSESS_THE_PROBLEM]}
- />
- ),
- },
- {
- value: TabKeys.HowToFixIt,
- key: TabKeys.HowToFixIt,
- label: translate('coding_rules.description_section.title', TabKeys.HowToFixIt),
- content: descriptionSectionsByKey[RuleDescriptionSections.HOW_TO_FIX] && (
- <RuleDescription
- defaultContextKey={ruleDescriptionContextKey}
- language={ruleLanguage}
- sections={descriptionSectionsByKey[RuleDescriptionSections.HOW_TO_FIX]}
- />
- ),
- },
- ...(aiSuggestionAvailable
- ? [
- {
- value: TabKeys.CodeFix,
- key: TabKeys.CodeFix,
- label: translate('coding_rules.description_section.title', TabKeys.CodeFix),
- content: suggestionTabContent,
- },
- ]
- : []),
- {
- value: TabKeys.Activity,
- key: TabKeys.Activity,
- label: translate('coding_rules.description_section.title', TabKeys.Activity),
- content: activityTabContent,
- counter: issue?.comments?.length,
- },
- {
- value: TabKeys.MoreInfo,
- key: TabKeys.MoreInfo,
- label: translate('coding_rules.description_section.title', TabKeys.MoreInfo),
- content: ((educationPrinciples && educationPrinciples.length > 0) ||
- descriptionSectionsByKey[RuleDescriptionSections.RESOURCES]) && (
- <MoreInfoRuleDescription
- displayEducationalPrinciplesNotification={displayEducationalPrinciplesNotification}
- educationPrinciples={educationPrinciples}
- educationPrinciplesRef={this.educationPrinciplesRef}
- language={ruleLanguage}
- sections={descriptionSectionsByKey[RuleDescriptionSections.RESOURCES]}
- />
- ),
- counter: displayEducationalPrinciplesNotification ? 1 : undefined,
- },
- ];
-
- if (codeTabContent !== undefined) {
- tabs.unshift({
- value: TabKeys.Code,
- key: TabKeys.Code,
- label: translate('issue.tabs', TabKeys.Code),
- content: codeTabContent,
- });
- }
-
- return tabs.filter((tab) => tab.content);
- };
-
- attachScrollEvent = () => {
- document.addEventListener('scroll', this.checkIfEducationPrinciplesAreVisible, {
- capture: true,
- });
- };
-
- detachScrollEvent = () => {
- document.removeEventListener('scroll', this.checkIfEducationPrinciplesAreVisible, {
- capture: true,
- });
- };
-
- checkIfEducationPrinciplesAreVisible = () => {
- const {
- displayEducationalPrinciplesNotification,
- educationalPrinciplesNotificationHasBeenDismissed,
- } = this.state;
-
- if (this.educationPrinciplesRef.current) {
- const rect = this.educationPrinciplesRef.current.getBoundingClientRect();
- const isVisible = rect.top <= (window.innerHeight || document.documentElement.clientHeight);
-
- if (
- isVisible &&
- displayEducationalPrinciplesNotification &&
- !educationalPrinciplesNotificationHasBeenDismissed
- ) {
- dismissNotice(NoticeType.EDUCATION_PRINCIPLES)
- .then(() => {
- this.detachScrollEvent();
- this.setState({ educationalPrinciplesNotificationHasBeenDismissed: true });
- })
- .catch(() => {
- /* noop */
- });
- }
- }
- };
-
- handleSelectTabs = (currentTabKey: TabKeys) => {
- this.setState(({ tabs }) => {
- return {
- selectedTab: tabs.find((tab) => tab.key === currentTabKey) || tabs[0],
- };
- });
- };
-
- render() {
- const { issue, ruleDetails } = this.props;
- const { tabs, selectedTab } = this.state;
-
- if (!tabs || tabs.length === 0 || !selectedTab) {
- return null;
- }
-
- return (
- <ScreenPositionHelper>
- {({ top }) => (
- <div
- style={{
- height: `calc(100vh - ${top + 20 + LAYOUT_FOOTER_HEIGHT}px)`,
- }}
- className="sw-overflow-y-auto"
- >
- <StyledHeader
- headerHeight={this.headerNode?.clientHeight ?? 0}
- className="sw-z-issue-header"
- >
- <div className="sw-p-6 sw-pb-4" ref={(node) => (this.headerNode = node)}>
- <IssueHeader
- issue={issue}
- ruleDetails={ruleDetails}
- branchLike={fillBranchLike(issue.branch, issue.pullRequest)}
- onIssueChange={this.props.onIssueChange}
- />
- <ToggleButton
- role="tablist"
- value={selectedTab.key}
- options={tabs}
- onChange={this.handleSelectTabs}
- />
- </div>
- </StyledHeader>
- <div
- className="sw-flex sw-flex-col sw-px-6"
- role="tabpanel"
- aria-labelledby={`tab-${selectedTab.key}`}
- id={`tabpanel-${selectedTab.key}`}
- >
- {tabs
- .filter((t) => t.key === selectedTab.key)
- .map((tab) => (
- <div
- className={classNames({
- 'sw-hidden': tab.key !== selectedTab.key,
- })}
- key={tab.key}
- >
- <TabSelectorContext.Provider value={this.handleSelectTabs}>
- {tab.content}
- </TabSelectorContext.Provider>
- </div>
- ))}
- </div>
- </div>
- )}
- </ScreenPositionHelper>
- );
- }
-}
-
-export default withCurrentUserContext(
- withLocation(withUseGetFixSuggestionsIssues<IssueTabViewerProps>(IssueTabViewer)),
-);
diff --git a/server/sonar-web/src/main/js/components/rules/MoreInfoRuleDescription.tsx b/server/sonar-web/src/main/js/components/rules/MoreInfoRuleDescription.tsx
deleted file mode 100644
index 7b992db0ed4..00000000000
--- a/server/sonar-web/src/main/js/components/rules/MoreInfoRuleDescription.tsx
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { Button } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { FlagMessage, SubTitle, themeBorder, themeColor } from '~design-system';
-import { RuleDescriptionSection } from '../../apps/coding-rules/rule';
-import { translate } from '../../helpers/l10n';
-import { Dict } from '../../types/types';
-import RuleDescription from './RuleDescription';
-import DefenseInDepth from './educationPrinciples/DefenseInDepth';
-import NeverTrustUserInput from './educationPrinciples/NeverTrustUserInput';
-
-interface Props {
- displayEducationalPrinciplesNotification?: boolean;
- educationPrinciples?: string[];
- educationPrinciplesRef?: React.RefObject<HTMLDivElement>;
- language?: string;
- sections?: RuleDescriptionSection[];
-}
-
-const EDUCATION_PRINCIPLES_MAP: Dict<React.ComponentType<React.PropsWithChildren>> = {
- defense_in_depth: DefenseInDepth,
- never_trust_user_input: NeverTrustUserInput,
-};
-
-export default class MoreInfoRuleDescription extends React.PureComponent<Props> {
- handleNotificationScroll = () => {
- const element = this.props.educationPrinciplesRef?.current;
-
- if (element) {
- element.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' });
- }
- };
-
- render() {
- const {
- displayEducationalPrinciplesNotification,
- language,
- sections = [],
- educationPrinciples = [],
- educationPrinciplesRef,
- } = this.props;
-
- return (
- <div className="sw-my-6 rule-desc">
- {displayEducationalPrinciplesNotification && (
- <FlagMessage variant="info">
- <p className="sw-my-1">{translate('coding_rules.more_info.notification_message')}</p>
-
- <Button
- className="sw-whitespace-nowrap"
- onClick={() => {
- this.handleNotificationScroll();
- }}
- >
- {translate('coding_rules.more_info.scroll_message')}
- </Button>
- </FlagMessage>
- )}
-
- {sections.length > 0 && (
- <>
- <SubTitle>{translate('coding_rules.more_info.resources.title')}</SubTitle>
- <RuleDescription language={language} sections={sections} />
- </>
- )}
-
- {educationPrinciples.length > 0 && (
- <>
- <SubTitle ref={educationPrinciplesRef}>
- {translate('coding_rules.more_info.education_principles.title')}
- </SubTitle>
-
- {educationPrinciples.map((key) => {
- const Concept = EDUCATION_PRINCIPLES_MAP[key];
-
- if (Concept === undefined) {
- return null;
- }
-
- return (
- <StyledEducationPrinciples key={key} className="sw-mt-4 sw-p-4 sw-rounded-1">
- <Concept />
- </StyledEducationPrinciples>
- );
- })}
- </>
- )}
- </div>
- );
- }
-}
-
-const StyledEducationPrinciples = styled.div`
- background-color: ${themeColor('educationPrincipleBackground')};
- border: ${themeBorder('default', 'educationPrincipleBorder')};
-
- & h3:first-of-type {
- margin-top: 0;
- }
-`;
diff --git a/server/sonar-web/src/main/js/components/rules/OtherContextOption.tsx b/server/sonar-web/src/main/js/components/rules/OtherContextOption.tsx
deleted file mode 100644
index 76050fe6759..00000000000
--- a/server/sonar-web/src/main/js/components/rules/OtherContextOption.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CheckIcon, CloseIcon, Link } from '~design-system';
-import { translate } from '../../helpers/l10n';
-
-export default function OtherContextOption() {
- return (
- <>
- <h2>{translate('coding_rules.context.others.title')}</h2>
- <p>{translate('coding_rules.context.others.description.first')}</p>
- <p>{translate('coding_rules.context.others.description.second')}</p>
- <p>
- <span className="sw-flex sw-items-center sw-ml-4">
- <CheckIcon className="sw-mr-2" fill="iconSuccess" />
- {translate('coding_rules.context.others.description.do')}
- </span>
- <span className="sw-flex sw-items-center sw-ml-4">
- <CloseIcon className="sw-mr-2" fill="iconError" />
- {translate('coding_rules.context.others.description.dont')}
- </span>
- </p>
- <h2>{translate('coding_rules.context.others.title_feedback')}</h2>
- <p>{translate('coding_rules.context.others.feedback_description_1')}</p>
- <Link
- to="https://portal.productboard.com/sonarsource/3-sonarqube/submit-idea"
- target="_blank"
- >
- {translate('coding_rules.context.others.feedback_description.link')}
- </Link>
- <p>{translate('coding_rules.context.others.feedback_description_2')}</p>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/rules/RuleDescription.tsx b/server/sonar-web/src/main/js/components/rules/RuleDescription.tsx
deleted file mode 100644
index 275280497be..00000000000
--- a/server/sonar-web/src/main/js/components/rules/RuleDescription.tsx
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import * as React from 'react';
-import {
- CodeSyntaxHighlighter,
- FlagMessage,
- HtmlFormatter,
- SanitizeLevel,
- ToggleButton,
- themeBorder,
- themeColor,
-} from '~design-system';
-import { RuleDescriptionSection, RuleDescriptionSections } from '../../apps/coding-rules/rule';
-import applyCodeDifferences from '../../helpers/code-difference';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { isDefined } from '../../helpers/types';
-import { useCveQuery } from '../../queries/cves';
-import { CveDetails } from './CveDetails';
-import OtherContextOption from './OtherContextOption';
-
-const OTHERS_KEY = 'others';
-
-interface Props {
- className?: string;
- cveId?: string;
- defaultContextKey?: string;
- language?: string;
- sections: RuleDescriptionSection[];
-}
-
-interface RuleDescriptionContextDisplay {
- content: string;
- displayName: string;
- key: string;
-}
-
-export default function RuleDescription({
- className,
- cveId,
- defaultContextKey,
- language,
- sections,
-}: Readonly<Props>) {
- const [contexts, setContexts] = React.useState<RuleDescriptionContextDisplay[]>([]);
- const [defaultContext, setDefaultContext] = React.useState<
- RuleDescriptionContextDisplay | undefined
- >();
- const [selectedContext, setSelectedContext] = React.useState<
- RuleDescriptionContextDisplay | undefined
- >();
-
- const { data: cveData } = useCveQuery({ cveId });
-
- React.useEffect(() => {
- const contexts = sections
- .filter(
- (
- section,
- ): section is RuleDescriptionSection & Required<Pick<RuleDescriptionSection, 'context'>> =>
- section.context != null,
- )
- .map((section) => ({
- displayName: section.context.displayName || section.context.key,
- content: section.content,
- key: section.context.key,
- }))
- .sort((a, b) => a.displayName.localeCompare(b.displayName));
-
- if (contexts.length > 0) {
- contexts.push({
- displayName: translate('coding_rules.description_context.other'),
- content: '',
- key: OTHERS_KEY,
- });
- }
-
- let defaultContext: RuleDescriptionContextDisplay | undefined;
-
- if (defaultContextKey) {
- defaultContext = contexts.find((context) => context.key === defaultContextKey);
- }
-
- setContexts(contexts);
- setDefaultContext(defaultContext);
- setSelectedContext(defaultContext ?? contexts[0]);
- }, [sections, defaultContextKey]);
-
- const handleToggleContext = (value: string) => {
- const selected = contexts.find((ctxt) => ctxt.displayName === value);
- if (selected) {
- setSelectedContext(selected);
- }
- };
-
- const introductionSection = sections?.find(
- (section) => section.key === RuleDescriptionSections.INTRODUCTION,
- )?.content;
-
- const options = contexts.map((ctxt) => ({
- label: ctxt.displayName,
- value: ctxt.displayName,
- }));
-
- if (contexts.length > 0 && selectedContext) {
- return (
- <StyledHtmlFormatter
- className={className}
- ref={(node: HTMLDivElement) => {
- applyCodeDifferences(node);
- }}
- >
- <h2 className="sw-typo-semibold sw-mb-4">
- {translate('coding_rules.description_context.title')}
- </h2>
- {isDefined(introductionSection) && (
- <CodeSyntaxHighlighter
- className="rule-desc"
- htmlAsString={introductionSection}
- language={language}
- sanitizeLevel={SanitizeLevel.FORBID_SVG_MATHML}
- />
- )}
- {defaultContext && (
- <FlagMessage variant="info" className="sw-mb-4">
- {translateWithParameters(
- 'coding_rules.description_context.default_information',
- defaultContext.displayName,
- )}
- </FlagMessage>
- )}
- <div className="sw-mb-4">
- <ToggleButton
- label={translate('coding_rules.description_context.title')}
- onChange={handleToggleContext}
- options={options}
- value={selectedContext.displayName}
- />
-
- {selectedContext.key !== OTHERS_KEY && (
- <h2>
- {translateWithParameters(
- 'coding_rules.description_context.subtitle',
- selectedContext.displayName,
- )}
- </h2>
- )}
- </div>
- {selectedContext.key === OTHERS_KEY ? (
- <OtherContextOption />
- ) : (
- <CodeSyntaxHighlighter
- htmlAsString={selectedContext.content}
- language={language}
- sanitizeLevel={SanitizeLevel.FORBID_SVG_MATHML}
- />
- )}
-
- {cveData && <CveDetails cve={cveData} />}
- </StyledHtmlFormatter>
- );
- }
-
- return (
- <StyledHtmlFormatter
- className={className}
- ref={(node: HTMLDivElement) => {
- applyCodeDifferences(node);
- }}
- >
- {isDefined(introductionSection) && (
- <CodeSyntaxHighlighter
- className="rule-desc"
- htmlAsString={introductionSection}
- language={language}
- sanitizeLevel={SanitizeLevel.FORBID_SVG_MATHML}
- />
- )}
-
- <CodeSyntaxHighlighter
- htmlAsString={sections[0].content}
- language={language}
- sanitizeLevel={SanitizeLevel.FORBID_SVG_MATHML}
- />
-
- {cveData && <CveDetails cve={cveData} />}
- </StyledHtmlFormatter>
- );
-}
-
-const StyledHtmlFormatter = styled(HtmlFormatter)`
- margin-top: 1.5rem;
- margin-bottom: 1.5rem;
-
- .code-difference-container {
- flex-direction: column;
- width: fit-content;
- min-width: 100%;
- }
-
- .code-difference-scrollable {
- background-color: ${themeColor('codeSnippetBackground')};
- border: ${themeBorder('default', 'codeSnippetBorder')};
- border-radius: 0.5rem;
- padding: 1.5rem;
- overflow-x: auto;
- }
-
- .code-difference-scrollable .code-added,
- .code-difference-scrollable .code-removed {
- padding-left: 1.5rem;
- margin-left: -1.5rem;
- padding-right: 1.5rem;
- margin-right: -1.5rem;
- border-radius: 0;
- }
-
- .code-difference-scrollable .code-added {
- background-color: ${themeColor('codeLineCoveredUnderline')};
- }
-
- .code-difference-scrollable .code-removed {
- background-color: ${themeColor('codeLineUncoveredUnderline')};
- }
-
- a:has(code) {
- padding-bottom: 0.125rem;
- }
-`;
diff --git a/server/sonar-web/src/main/js/components/rules/RuleTabViewer.tsx b/server/sonar-web/src/main/js/components/rules/RuleTabViewer.tsx
deleted file mode 100644
index 68c17f4e1ca..00000000000
--- a/server/sonar-web/src/main/js/components/rules/RuleTabViewer.tsx
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { cloneDeep, debounce, groupBy, isEqual } from 'lodash';
-import * as React from 'react';
-import { Location } from 'react-router-dom';
-import { ToggleButton, getTabId, getTabPanelId } from '~design-system';
-import { dismissNotice } from '../../api/users';
-import { CurrentUserContextInterface } from '../../app/components/current-user/CurrentUserContext';
-import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext';
-import { RuleDescriptionSections } from '../../apps/coding-rules/rule';
-import { translate } from '../../helpers/l10n';
-import { RuleDetails } from '../../types/types';
-import { NoticeType } from '../../types/users';
-import withLocation from '../hoc/withLocation';
-import MoreInfoRuleDescription from './MoreInfoRuleDescription';
-import RuleDescription from './RuleDescription';
-
-interface RuleTabViewerProps extends CurrentUserContextInterface {
- location: Location;
- ruleDetails: RuleDetails;
-}
-
-interface State {
- displayEducationalPrinciplesNotification?: boolean;
- educationalPrinciplesNotificationHasBeenDismissed?: boolean;
- selectedTab?: Tab;
- tabs: Tab[];
-}
-
-export interface Tab {
- content: React.ReactNode;
- counter?: number;
- label: string;
- value: TabKeys;
-}
-
-export enum TabKeys {
- Code = 'code',
- WhyIsThisAnIssue = 'why',
- HowToFixIt = 'how_to_fix',
- AssessTheIssue = 'assess_the_problem',
- Activity = 'activity',
- MoreInfo = 'more_info',
-}
-
-const DEBOUNCE_FOR_SCROLL = 250;
-
-export class RuleTabViewer extends React.PureComponent<RuleTabViewerProps, State> {
- state: State = {
- tabs: [],
- };
-
- educationPrinciplesRef: React.RefObject<HTMLDivElement>;
-
- constructor(props: RuleTabViewerProps) {
- super(props);
-
- this.educationPrinciplesRef = React.createRef();
-
- this.checkIfEducationPrinciplesAreVisible = debounce(
- this.checkIfEducationPrinciplesAreVisible,
- DEBOUNCE_FOR_SCROLL,
- );
- }
-
- componentDidMount() {
- this.setState((prevState) => this.computeState(prevState));
- this.attachScrollEvent();
-
- const tabs = this.computeTabs(Boolean(this.state.displayEducationalPrinciplesNotification));
-
- const query = new URLSearchParams(this.props.location.search);
-
- if (query.has('why')) {
- this.setState({
- selectedTab: tabs.find((tab) => tab.value === TabKeys.WhyIsThisAnIssue) ?? tabs[0],
- });
- }
- }
-
- componentDidUpdate(prevProps: RuleTabViewerProps, prevState: State) {
- const { ruleDetails, currentUser } = this.props;
-
- const { selectedTab } = this.state;
-
- if (
- !isEqual(prevProps.ruleDetails, ruleDetails) ||
- !isEqual(prevProps.currentUser, currentUser)
- ) {
- this.setState((pState) =>
- this.computeState(pState, prevProps.ruleDetails.key !== ruleDetails.key),
- );
- }
-
- if (selectedTab?.value === TabKeys.MoreInfo) {
- this.checkIfEducationPrinciplesAreVisible();
- }
-
- if (
- prevState.selectedTab?.value === TabKeys.MoreInfo &&
- prevState.displayEducationalPrinciplesNotification &&
- prevState.educationalPrinciplesNotificationHasBeenDismissed
- ) {
- this.props.updateDismissedNotices(NoticeType.EDUCATION_PRINCIPLES, true);
- }
- }
-
- componentWillUnmount() {
- this.detachScrollEvent();
- }
-
- computeState = (prevState: State, resetSelectedTab = false) => {
- const {
- ruleDetails,
- currentUser: { isLoggedIn, dismissedNotices },
- } = this.props;
-
- const displayEducationalPrinciplesNotification =
- !!ruleDetails.educationPrinciples &&
- ruleDetails.educationPrinciples.length > 0 &&
- isLoggedIn &&
- !dismissedNotices[NoticeType.EDUCATION_PRINCIPLES];
-
- const tabs = this.computeTabs(displayEducationalPrinciplesNotification);
-
- return {
- tabs,
- selectedTab: resetSelectedTab || !prevState.selectedTab ? tabs[0] : prevState.selectedTab,
- displayEducationalPrinciplesNotification,
- };
- };
-
- computeTabs = (displayEducationalPrinciplesNotification: boolean) => {
- const {
- ruleDetails: { descriptionSections, educationPrinciples, lang: ruleLanguage, type: ruleType },
- } = this.props;
-
- // As we might tamper with the description later on, we clone to avoid any side effect
- const descriptionSectionsByKey = cloneDeep(
- groupBy(descriptionSections, (section) => section.key),
- );
-
- const tabs: Tab[] = [
- {
- content: (descriptionSectionsByKey[RuleDescriptionSections.DEFAULT] ||
- descriptionSectionsByKey[RuleDescriptionSections.ROOT_CAUSE]) && (
- <RuleDescription
- language={ruleLanguage}
- sections={(
- descriptionSectionsByKey[RuleDescriptionSections.DEFAULT] ??
- descriptionSectionsByKey[RuleDescriptionSections.ROOT_CAUSE]
- ).concat(descriptionSectionsByKey[RuleDescriptionSections.INTRODUCTION] ?? [])}
- />
- ),
- value: TabKeys.WhyIsThisAnIssue,
- label:
- ruleType === 'SECURITY_HOTSPOT'
- ? translate('coding_rules.description_section.title.root_cause.SECURITY_HOTSPOT')
- : translate('coding_rules.description_section.title.root_cause'),
- },
- {
- content: descriptionSectionsByKey[RuleDescriptionSections.ASSESS_THE_PROBLEM] && (
- <RuleDescription
- language={ruleLanguage}
- sections={descriptionSectionsByKey[RuleDescriptionSections.ASSESS_THE_PROBLEM]}
- />
- ),
- value: TabKeys.AssessTheIssue,
- label: translate('coding_rules.description_section.title', TabKeys.AssessTheIssue),
- },
- {
- content: descriptionSectionsByKey[RuleDescriptionSections.HOW_TO_FIX] && (
- <RuleDescription
- language={ruleLanguage}
- sections={descriptionSectionsByKey[RuleDescriptionSections.HOW_TO_FIX]}
- />
- ),
- value: TabKeys.HowToFixIt,
- label: translate('coding_rules.description_section.title', TabKeys.HowToFixIt),
- },
- {
- content: ((educationPrinciples && educationPrinciples.length > 0) ||
- descriptionSectionsByKey[RuleDescriptionSections.RESOURCES]) && (
- <MoreInfoRuleDescription
- displayEducationalPrinciplesNotification={displayEducationalPrinciplesNotification}
- educationPrinciples={educationPrinciples}
- educationPrinciplesRef={this.educationPrinciplesRef}
- language={ruleLanguage}
- sections={descriptionSectionsByKey[RuleDescriptionSections.RESOURCES]}
- />
- ),
- value: TabKeys.MoreInfo,
- label: translate('coding_rules.description_section.title', TabKeys.MoreInfo),
- counter: displayEducationalPrinciplesNotification ? 1 : undefined,
- },
- ];
-
- return tabs.filter((tab) => tab.content);
- };
-
- attachScrollEvent = () => {
- document.addEventListener('scroll', this.checkIfEducationPrinciplesAreVisible, {
- capture: true,
- });
- };
-
- detachScrollEvent = () => {
- document.removeEventListener('scroll', this.checkIfEducationPrinciplesAreVisible, {
- capture: true,
- });
- };
-
- checkIfEducationPrinciplesAreVisible = () => {
- const {
- displayEducationalPrinciplesNotification,
- educationalPrinciplesNotificationHasBeenDismissed,
- } = this.state;
-
- if (this.educationPrinciplesRef.current) {
- const rect = this.educationPrinciplesRef.current.getBoundingClientRect();
- const isVisible = rect.top <= (window.innerHeight || document.documentElement.clientHeight);
-
- if (
- isVisible &&
- displayEducationalPrinciplesNotification &&
- !educationalPrinciplesNotificationHasBeenDismissed
- ) {
- dismissNotice(NoticeType.EDUCATION_PRINCIPLES)
- .then(() => {
- this.detachScrollEvent();
- this.setState({ educationalPrinciplesNotificationHasBeenDismissed: true });
- })
- .catch(() => {
- /* noop */
- });
- }
- }
- };
-
- handleSelectTabs = (currentTabKey: TabKeys) => {
- this.setState(({ tabs }) => ({
- selectedTab: tabs.find((tab) => tab.value === currentTabKey) ?? tabs[0],
- }));
- };
-
- render() {
- const { tabs, selectedTab } = this.state;
-
- if (!tabs || tabs.length === 0 || !selectedTab) {
- return null;
- }
-
- return (
- <>
- <div className="sw-mt-4">
- <ToggleButton
- role="tablist"
- onChange={this.handleSelectTabs}
- options={tabs}
- value={selectedTab.value}
- />
- </div>
-
- <div
- aria-labelledby={getTabId(selectedTab.value)}
- className="sw-flex sw-flex-col"
- id={getTabPanelId(selectedTab.value)}
- role="tabpanel"
- >
- {
- // Preserve tabs state by always rendering all of them. Only hide them when not selected
- tabs.map((tab) => (
- <div
- className={classNames({
- 'sw-hidden': tab.value !== selectedTab.value,
- })}
- key={tab.value}
- >
- {tab.content}
- </div>
- ))
- }
- </div>
- </>
- );
- }
-}
-
-export default withCurrentUserContext(withLocation(RuleTabViewer));
diff --git a/server/sonar-web/src/main/js/components/rules/TabSelectorContext.ts b/server/sonar-web/src/main/js/components/rules/TabSelectorContext.ts
deleted file mode 100644
index bad4e8f4e5a..00000000000
--- a/server/sonar-web/src/main/js/components/rules/TabSelectorContext.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { noop } from 'lodash';
-import { createContext } from 'react';
-import { TabKeys } from './IssueTabViewer';
-
-export const TabSelectorContext = createContext<(selectedTab: TabKeys) => void>(noop);
diff --git a/server/sonar-web/src/main/js/components/rules/educationPrinciples/DefenseInDepth.tsx b/server/sonar-web/src/main/js/components/rules/educationPrinciples/DefenseInDepth.tsx
deleted file mode 100644
index 3012cf712eb..00000000000
--- a/server/sonar-web/src/main/js/components/rules/educationPrinciples/DefenseInDepth.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export default function DefenseInDepth() {
- return (
- <>
- <h3>Defense-In-Depth</h3>
- <p>
- Applications and infrastructure benefit greatly from relying on multiple security mechanisms
- layered on top of each other. If one security mechanism fails, there is a high probability
- that the subsequent layers of security will successfully defend against the attack.
- </p>
-
- <p>A non-exhaustive list of these code protection ramparts includes the following:</p>
- <ul>
- <li>Minimizing the attack surface of the code</li>
- <li>Application of the principle of least privilege</li>
- <li>Validation and sanitization of data</li>
- <li>Encrypting incoming, outgoing, or stored data with secure cryptography</li>
- <li>Ensuring that internal errors cannot disrupt the overall runtime</li>
- <li>Separation of tasks and access to information</li>
- </ul>
-
- <p>
- Note that these layers must be simple enough to use in an everyday workflow. Security
- measures should not break usability.
- </p>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/rules/educationPrinciples/NeverTrustUserInput.tsx b/server/sonar-web/src/main/js/components/rules/educationPrinciples/NeverTrustUserInput.tsx
deleted file mode 100644
index 6f21824be86..00000000000
--- a/server/sonar-web/src/main/js/components/rules/educationPrinciples/NeverTrustUserInput.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export default function NeverTrustUserInput() {
- return (
- <>
- <h3>Never Trust User Input</h3>
- <p>
- Applications must treat all user input and, more generally, all third-party data as
- attacker-controlled data.
- </p>
- <p>
- The application must determine where the third-party data comes from and treat that data
- source as an attack vector. Two rules apply:
- </p>
-
- <p>
- First, before using it in the application&apos;s business logic, the application must
- validate the attacker-controlled data against predefined formats, such as:
- </p>
- <ul>
- <li>Character sets</li>
- <li>Sizes</li>
- <li>Types</li>
- <li>Or any strict schema</li>
- </ul>
-
- <p>
- Second, the application must sanitize string data before inserting it into interpreted
- contexts (client-side code, file paths, SQL queries). Unsanitized code can corrupt the
- application&apos;s logic.
- </p>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/search-navigator.css b/server/sonar-web/src/main/js/components/search-navigator.css
deleted file mode 100644
index 916f726d785..00000000000
--- a/server/sonar-web/src/main/js/components/search-navigator.css
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-/* TODO this file is HUGE and should be cut into smaller components */
-
-.search-navigator.sticky .search-navigator-workspace-header {
- position: fixed;
- z-index: 50;
- top: 0;
- left: 300px;
- right: 0;
-}
-
-.search-navigator.sticky .search-navigator-workspace-list,
-.search-navigator.sticky .search-navigator-workspace-details {
- padding-top: 43px;
-}
-
-.search-navigator-facet-box {
- background-color: #f3f3f3;
- font-size: 13px;
-}
-
-.search-navigator-facet-box.leak-facet-box {
- background-color: #fbf3d5;
- border: 1px solid #f1e8cb;
-}
-
-.search-navigator-facet-box.is-inner {
- margin-left: 8px;
- padding-left: 12px;
- border-left: 1px solid #e6e6e6;
-}
-
-.search-navigator-facet-box.is-inner .search-navigator-facet-header {
- padding-top: 6px;
- padding-bottom: 6px;
-}
-
-.leak-facet-box:not(.hidden) + .leak-facet-box {
- border-top: none;
-}
-
-.search-navigator-facet-box-forbidden {
- background-color: transparent;
-}
-
-.search-navigator-facet-box-forbidden .search-navigator-facet-list,
-.search-navigator-facet-box-forbidden .search-navigator-facet-empty,
-.search-navigator-facet-box-forbidden .search-navigator-facet-container {
- display: none;
-}
-
-.search-navigator-facet-box-forbidden .search-navigator-facet-header {
- cursor: default;
- color: #888;
-}
-
-.search-navigator-facet,
-button.search-navigator-facet {
- position: relative;
- display: inline-flex;
- justify-content: space-between;
- align-items: center;
- width: 100%;
- height: calc(3.5 * 8px);
- margin-bottom: 1px;
- padding: 0 calc(0.75 * 8px);
- border: 1px solid transparent;
- border-radius: 2px;
- box-sizing: border-box;
- white-space: normal;
- opacity: 0.3;
- cursor: not-allowed;
- transition: none;
-}
-
-button.search-navigator-facet {
- opacity: 1;
- cursor: pointer;
-}
-
-button.search-navigator-facet .facet-name {
- color: #333;
-}
-
-button.search-navigator-facet:hover,
-button.search-navigator-facet:focus,
-.search-navigator-facet.active {
- border-color: #4b9fd5;
-}
-
-.search-navigator-facet.facet-category {
- opacity: 1;
- cursor: default;
-}
-
-.search-navigator-facet.facet-category .facet-name {
- color: #656565;
-}
-
-.search-navigator-facet .facet-name {
- flex: 1 1 auto;
- min-width: 0;
- line-height: 16px;
- padding: 1px 0; /* needed to fit small ratings and levels */
- color: #656565;
- font-size: 12px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.search-navigator-facet .facet-stat {
- display: flex;
- align-items: center;
- margin-left: 8px;
- color: #656565;
- font-size: 12px;
-}
-
-.search-navigator-facet .facet-toggle {
- display: none;
- float: left;
- height: 16px;
- line-height: 16px;
- margin-top: -1px;
- padding: 0 5px;
- border-radius: 2px;
- font-size: 11px;
- text-transform: lowercase;
-}
-
-.search-navigator-facet .facet-toggle:hover {
- color: #333;
-}
-
-.search-navigator-facet .facet-toggle-active.facet-toggle-green {
- background-color: #00aa00;
- color: #ffffff;
-}
-
-.search-navigator-facet .facet-toggle-active.facet-toggle-red {
- background-color: #d02f3a;
- color: #ffffff;
-}
-
-.leak-facet-box .search-navigator-facet .facet-name {
- background-color: #fbf3d5;
-}
-
-.leak-facet-box .search-navigator-facet .facet-stat {
- background-color: #fbf3d5;
-}
-
-.leak-facet-box .search-navigator-facet .facet-stat:before {
- background-image: linear-gradient(to right, rgba(251, 243, 213, 0), #fbf3d5 75%);
-}
-
-.search-navigator-facet.active {
- background-color: #f2faff;
- text-decoration: none;
-}
-
-.search-navigator-facet.active .facet-toggle {
- display: inline;
-}
-
-.search-navigator-facet.compare .facet-toggle {
- cursor: not-allowed;
- opacity: 0.5;
-}
-
-.search-navigator-facet.compare .facet-toggle.facet-toggle-green {
- background-color: #00aa00;
- color: #ffffff;
-}
-
-.search-navigator-facet.compare .facet-toggle.facet-toggle-red {
- background-color: transparent;
- color: #656565;
-}
-
-.search-navigator-facet-half {
- display: inline-flex;
- width: 45%;
-}
-
-.search-navigator-facet-half:nth-child(odd) {
- margin-right: 10%;
-}
-
-.search-navigator-facet-header {
- display: block;
- flex-shrink: 0;
- padding: 8px 1px;
- color: #333;
- font-weight: 600;
- overflow: hidden;
- white-space: nowrap;
-}
-
-.search-navigator-facet-header > button {
- border-bottom: none;
- color: #333;
- cursor: pointer;
- font-weight: inherit;
-}
-
-.search-navigator-facet-header > button:focus,
-.search-navigator-facet-header > button:hover {
- color: #236a97;
-}
-
-.search-navigator-facet-header > h3,
-.search-navigator-facet-header > h4 {
- line-height: inherit;
- display: inline;
-}
-
-.search-navigator-facet-header-value {
- display: block;
- overflow: hidden;
-}
-
-.search-navigator-facet-header-value > .badge {
- display: block;
-}
-
-.search-navigator-facet-header-button {
- flex-shrink: 0;
- margin-left: auto;
-}
-
-.search-navigator-facet-header-wrapper {
- display: flex;
- align-items: center;
-}
-
-.search-navigator-facet-header-wrapper:not(.expandable-header) .search-navigator-facet-header {
- padding-left: 21px;
-}
-
-.search-navigator-facet-list {
- padding-bottom: 8px;
- font-size: 0;
-}
-
-.search-navigator-facet-list-title {
- margin: 0 8px calc(8px / 2);
- font-size: 12px;
- font-weight: bold;
-}
-
-.search-navigator-facet-list + .search-navigator-facet-list > .search-navigator-facet-list-title {
- border-top: 1px solid #e6e6e6;
- padding-top: 8px;
-}
-
-.search-navigator-facet-empty {
- margin: 0 0 0 0;
- padding: 0 10px 10px;
- color: #333;
- font-size: 12px;
-}
-
-.search-navigator-facet-footer {
- display: block;
- padding-bottom: 8px;
- border-bottom: none;
-}
-
-.search-navigator-facet-container {
- margin-top: 6px;
- padding: 0 10px 16px;
-}
-
-.search-navigator-filters {
- position: relative;
- padding: 5px 10px;
- background-color: #f3f3f3;
-}
-
-.search-navigator-filters:before,
-.search-navigator-filters:after {
- display: table;
- content: '';
- line-height: 0;
-}
-
-.search-navigator-filters:after {
- clear: both;
-}
-
-.search-navigator-filters-header {
- margin-bottom: 12px;
- padding-bottom: 11px;
- border-bottom: 1px solid #e6e6e6;
-}
-.search-navigator-intro {
- width: 500px;
- margin: 0 auto;
- padding-top: 100px;
-}
diff --git a/server/sonar-web/src/main/js/components/shared/AppVersionStatus.tsx b/server/sonar-web/src/main/js/components/shared/AppVersionStatus.tsx
deleted file mode 100644
index 6af7f6e8f56..00000000000
--- a/server/sonar-web/src/main/js/components/shared/AppVersionStatus.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkHighlight, LinkStandalone } from '@sonarsource/echoes-react';
-import { useMemo } from 'react';
-import { FormattedMessage, useIntl } from 'react-intl';
-import { useAppState } from '../../app/components/app-state/withAppStateContext';
-import { DocLink } from '../../helpers/doc-links';
-import { useDocUrl } from '../../helpers/docs';
-import { getInstanceVersionNumber } from '../../helpers/strings';
-import { isCurrentVersionEOLActive } from '../../helpers/system';
-import { useSystemUpgrades } from '../../queries/system';
-import { EditionKey } from '../../types/editions';
-
-export default function AppVersionStatus({ statusOnly }: Readonly<{ statusOnly?: boolean }>) {
- const { data } = useSystemUpgrades();
- const { edition, version, versionEOL } = useAppState();
-
- const isActiveVersion = useMemo(() => {
- if (data?.installedVersionActive !== undefined) {
- return data.installedVersionActive;
- }
-
- return isCurrentVersionEOLActive(versionEOL);
- }, [data?.installedVersionActive, versionEOL]);
-
- const docUrl = useDocUrl(DocLink.ActiveVersions);
- const intl = useIntl();
-
- return intl.formatMessage(
- { id: statusOnly ? `footer.version.status` : `footer.version.full` },
- {
- version: getInstanceVersionNumber(version),
- status: edition && edition !== EditionKey.community && (
- <LinkStandalone className="sw-ml-1" highlight={LinkHighlight.CurrentColor} to={docUrl}>
- <FormattedMessage
- id={`footer.version.status.${isActiveVersion ? 'active' : 'inactive'}`}
- />
- </LinkStandalone>
- ),
- },
- );
-}
diff --git a/server/sonar-web/src/main/js/components/shared/CleanCodeAttributePill.tsx b/server/sonar-web/src/main/js/components/shared/CleanCodeAttributePill.tsx
deleted file mode 100644
index 9467dc6fedb..00000000000
--- a/server/sonar-web/src/main/js/components/shared/CleanCodeAttributePill.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Popover } from '@sonarsource/echoes-react';
-import { Pill, PillVariant } from '~design-system';
-import { DocLink } from '../../helpers/doc-links';
-import { translate } from '../../helpers/l10n';
-import { CleanCodeAttribute, CleanCodeAttributeCategory } from '../../types/clean-code-taxonomy';
-import DocumentationLink from '../common/DocumentationLink';
-
-export interface Props {
- className?: string;
- cleanCodeAttribute?: CleanCodeAttribute;
- cleanCodeAttributeCategory: CleanCodeAttributeCategory;
- type?: 'issue' | 'rule';
-}
-
-export function CleanCodeAttributePill(props: Readonly<Props>) {
- const { className, cleanCodeAttributeCategory, cleanCodeAttribute, type = 'issue' } = props;
-
- return (
- <Popover
- title={translate(
- type,
- cleanCodeAttribute ? 'clean_code_attribute' : 'clean_code_attribute_category',
- cleanCodeAttribute ?? cleanCodeAttributeCategory,
- 'title',
- )}
- description={translate(
- 'issue',
- cleanCodeAttribute ? 'clean_code_attribute' : 'clean_code_attribute_category',
- cleanCodeAttribute ?? cleanCodeAttributeCategory,
- 'advice',
- )}
- footer={
- <DocumentationLink shouldOpenInNewTab standalone to={DocLink.CleanCodeIntroduction}>
- {translate('clean_code_attribute.learn_more')}
- </DocumentationLink>
- }
- >
- <Pill variant={PillVariant.Accent} data-guiding-id="issue-1" className={className}>
- <span className="sw-font-semibold">
- {translate(type, 'clean_code_attribute_category', cleanCodeAttributeCategory)}
- </span>
- {cleanCodeAttribute && (
- <span> | {translate(type, 'clean_code_attribute', cleanCodeAttribute)}</span>
- )}
- </Pill>
- </Popover>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/shared/ComponentMissingMqrMetricsMessage.tsx b/server/sonar-web/src/main/js/components/shared/ComponentMissingMqrMetricsMessage.tsx
deleted file mode 100644
index 17e30d7638f..00000000000
--- a/server/sonar-web/src/main/js/components/shared/ComponentMissingMqrMetricsMessage.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkHighlight } from '@sonarsource/echoes-react';
-import { FormattedMessage } from 'react-intl';
-import { DocLink } from '../../helpers/doc-links';
-import { useCurrentBranchQuery } from '../../queries/branch';
-import { useMeasureQuery } from '../../queries/measures';
-import { useStandardExperienceModeQuery } from '../../queries/mode';
-import { isPullRequest } from '../../sonar-aligned/helpers/branch-like';
-import { LightComponent } from '../../sonar-aligned/types/component';
-import { MetricKey } from '../../sonar-aligned/types/metrics';
-import DocumentationLink from '../common/DocumentationLink';
-import { DismissableAlert } from '../ui/DismissableAlert';
-
-interface AnalysisMissingInfoMessageProps {
- component: LightComponent;
-}
-
-const ALERT_KEY = 'sonarqube.dismissed_calculation_change_alert.component';
-
-export function ComponentMissingMqrMetricsMessage({
- component,
-}: Readonly<AnalysisMissingInfoMessageProps>) {
- const { key: componentKey, qualifier } = component;
- const { data: isStandardMode, isLoading } = useStandardExperienceModeQuery();
- const { data: branchLike, isLoading: loadingBranch } = useCurrentBranchQuery(component);
- const { data: standardMeasure, isLoading: loadingStandardMeasure } = useMeasureQuery(
- {
- componentKey,
- metricKey: MetricKey.security_rating,
- branchLike,
- },
- { enabled: !isLoading && !isStandardMode && !loadingBranch },
- );
- const { data: mqrMeasure, isLoading: loadingMQRMeasure } = useMeasureQuery(
- {
- componentKey,
- metricKey: isPullRequest(branchLike)
- ? MetricKey.new_software_quality_security_rating
- : MetricKey.software_quality_security_rating,
- branchLike,
- },
- { enabled: !isLoading && !isStandardMode && !loadingBranch && Boolean(standardMeasure) },
- );
- const loading = loadingMQRMeasure || loadingStandardMeasure || isLoading || loadingBranch;
-
- if (loading || isStandardMode || Boolean(mqrMeasure) || !standardMeasure) {
- return null;
- }
-
- return (
- <DismissableAlert variant="info" alertKey={`${ALERT_KEY}_${componentKey}`}>
- <FormattedMessage
- id="overview.missing_project_data"
- tagName="div"
- values={{
- qualifier,
- link: (text) => (
- <DocumentationLink
- shouldOpenInNewTab
- highlight={LinkHighlight.CurrentColor}
- className="sw-whitespace-nowrap"
- to={DocLink.MetricDefinitions}
- >
- {text}
- </DocumentationLink>
- ),
- }}
- />
- </DismissableAlert>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/shared/DrilldownLink.tsx b/server/sonar-web/src/main/js/components/shared/DrilldownLink.tsx
deleted file mode 100644
index c313ccaa720..00000000000
--- a/server/sonar-web/src/main/js/components/shared/DrilldownLink.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { getBranchLikeQuery } from '~sonar-aligned/helpers/branch-like';
-import { getComponentIssuesUrl } from '~sonar-aligned/helpers/urls';
-import { getComponentDrilldownUrl } from '../../helpers/urls';
-import { BranchLike } from '../../types/branch-like';
-import Link from '../common/Link';
-import { isIssueMeasure, propsToIssueParams } from './utils';
-
-interface Props {
- ariaLabel?: string;
- branchLike?: BranchLike;
- children?: React.ReactNode;
- className?: string;
- component: string;
- inNewCodePeriod?: boolean;
- metric: string;
-}
-
-export default class DrilldownLink extends React.PureComponent<Props> {
- renderIssuesLink = () => {
- const { ariaLabel, className, component, children, branchLike, metric, inNewCodePeriod } =
- this.props;
-
- const url = getComponentIssuesUrl(component, {
- ...propsToIssueParams(metric, inNewCodePeriod),
- ...getBranchLikeQuery(branchLike),
- });
-
- return (
- <Link aria-label={ariaLabel} className={className} to={url}>
- {children}
- </Link>
- );
- };
-
- render() {
- const { ariaLabel, className, metric, component, children, branchLike } = this.props;
-
- if (isIssueMeasure(metric)) {
- return this.renderIssuesLink();
- }
-
- const url = getComponentDrilldownUrl({
- componentKey: component,
- metric,
- branchLike,
- listView: true,
- });
-
- return (
- <Link aria-label={ariaLabel} className={className} to={url}>
- {children}
- </Link>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/shared/IssueTypePill.tsx b/server/sonar-web/src/main/js/components/shared/IssueTypePill.tsx
deleted file mode 100644
index 3cffb58f3af..00000000000
--- a/server/sonar-web/src/main/js/components/shared/IssueTypePill.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { DropdownMenu, DropdownMenuAlign, Spinner, Tooltip } from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import { useState } from 'react';
-import { useIntl } from 'react-intl';
-import { Pill, PillVariant } from '~design-system';
-import { IssueSeverity, IssueType } from '../../types/issues';
-import IssueTypeIcon from '../icon-mappers/IssueTypeIcon';
-import SoftwareImpactSeverityIcon from '../icon-mappers/SoftwareImpactSeverityIcon';
-
-export interface Props {
- className?: string;
- issueType: string;
- onSetSeverity?: (severity: IssueSeverity) => Promise<void>;
- severity: IssueSeverity;
-}
-
-export default function IssueTypePill(props: Readonly<Props>) {
- const { className, severity, issueType, onSetSeverity } = props;
- const intl = useIntl();
- const [updatingSeverity, setUpdatingSeverity] = useState(false);
- const variant = {
- [IssueSeverity.Blocker]: PillVariant.Critical,
- [IssueSeverity.Critical]: PillVariant.Danger,
- [IssueSeverity.Major]: PillVariant.Warning,
- [IssueSeverity.Minor]: PillVariant.Caution,
- [IssueSeverity.Info]: PillVariant.Info,
- }[severity];
-
- const renderPill = (notClickable = false) => (
- <Pill
- notClickable={notClickable}
- className={classNames('sw-flex sw-gap-1 sw-items-center', className)}
- variant={issueType !== IssueType.SecurityHotspot ? variant : PillVariant.Accent}
- >
- <IssueTypeIcon type={issueType} />
- {intl.formatMessage({ id: `issue.type.${issueType}` })}
- <Spinner isLoading={updatingSeverity} className="sw-ml-1/2">
- {issueType !== IssueType.SecurityHotspot && (
- <SoftwareImpactSeverityIcon
- width={14}
- height={14}
- severity={severity}
- data-guiding-id="issue-3"
- />
- )}
- </Spinner>
- </Pill>
- );
-
- const handleSetSeverity = async (severity: IssueSeverity) => {
- setUpdatingSeverity(true);
- await onSetSeverity?.(severity);
- setUpdatingSeverity(false);
- };
-
- if (onSetSeverity) {
- return (
- <DropdownMenu.Root
- align={DropdownMenuAlign.Start}
- items={Object.values(IssueSeverity).map((severityItem) => (
- <DropdownMenu.ItemButtonCheckable
- key={severityItem}
- isDisabled={severityItem === severity}
- isChecked={severityItem === severity}
- onClick={() => handleSetSeverity(severityItem)}
- >
- <div className="sw-flex sw-items-center sw-gap-2">
- <SoftwareImpactSeverityIcon width={14} height={14} severity={severityItem} />
- {intl.formatMessage({ id: `severity.${severityItem}` })}
- </div>
- </DropdownMenu.ItemButtonCheckable>
- ))}
- >
- <Tooltip
- content={intl.formatMessage(
- {
- id: `issue.type.tooltip_with_change`,
- },
- {
- severity: intl.formatMessage({ id: `severity.${severity}` }),
- },
- )}
- >
- {renderPill()}
- </Tooltip>
- </DropdownMenu.Root>
- );
- }
-
- return (
- <Tooltip
- content={
- issueType === IssueType.SecurityHotspot
- ? ''
- : intl.formatMessage(
- {
- id: `issue.type.tooltip`,
- },
- {
- severity: intl.formatMessage({ id: `severity.${severity}` }),
- },
- )
- }
- >
- {renderPill(true)}
- </Tooltip>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/shared/SeverityHelper.tsx b/server/sonar-web/src/main/js/components/shared/SeverityHelper.tsx
deleted file mode 100644
index 6fee4db5236..00000000000
--- a/server/sonar-web/src/main/js/components/shared/SeverityHelper.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { isEmpty } from 'lodash';
-import { translate } from '../../helpers/l10n';
-import SeverityIcon from '../icon-mappers/SeverityIcon';
-
-interface Props {
- className?: string;
- severity: string;
-}
-
-export default function SeverityHelper({ className, severity }: Readonly<Props>) {
- if (isEmpty(severity)) {
- return null;
- }
- return (
- <span className={className}>
- <SeverityIcon className="sw-mr-1" severity={severity} aria-hidden />
- {translate('severity', severity)}
- </span>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/shared/SoftwareImpactPill.tsx b/server/sonar-web/src/main/js/components/shared/SoftwareImpactPill.tsx
deleted file mode 100644
index 3c7cb8c6657..00000000000
--- a/server/sonar-web/src/main/js/components/shared/SoftwareImpactPill.tsx
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- DropdownMenu,
- DropdownMenuAlign,
- Popover,
- Spinner,
- Tooltip,
-} from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import { noop } from 'lodash';
-import { useState } from 'react';
-import { FormattedMessage, useIntl } from 'react-intl';
-import { Pill, PillVariant } from '~design-system';
-import { IMPACT_SEVERITIES } from '../../helpers/constants';
-import { DocLink } from '../../helpers/doc-links';
-import { translate } from '../../helpers/l10n';
-import { SoftwareImpactSeverity, SoftwareQuality } from '../../types/clean-code-taxonomy';
-import DocumentationLink from '../common/DocumentationLink';
-import SoftwareImpactSeverityIcon from '../icon-mappers/SoftwareImpactSeverityIcon';
-
-export interface Props {
- className?: string;
- onSetSeverity?: (severity: SoftwareImpactSeverity, quality: SoftwareQuality) => Promise<void>;
- severity: SoftwareImpactSeverity;
- softwareQuality: SoftwareQuality;
- type?: 'issue' | 'rule';
-}
-
-export default function SoftwareImpactPill(props: Props) {
- const { className, severity, softwareQuality, type = 'issue', onSetSeverity } = props;
- const intl = useIntl();
- const quality = getQualityLabel(softwareQuality);
- const [updatingSeverity, setUpdatingSeverity] = useState(false);
-
- const variant = {
- [SoftwareImpactSeverity.Blocker]: PillVariant.Critical,
- [SoftwareImpactSeverity.High]: PillVariant.Danger,
- [SoftwareImpactSeverity.Medium]: PillVariant.Warning,
- [SoftwareImpactSeverity.Low]: PillVariant.Caution,
- [SoftwareImpactSeverity.Info]: PillVariant.Info,
- }[severity];
-
- const pill = (
- <Pill
- className={classNames('sw-flex sw-gap-1 sw-items-center', className)}
- onClick={noop}
- variant={variant}
- >
- {quality}
- <Spinner isLoading={updatingSeverity} className="sw-ml-1/2">
- <SoftwareImpactSeverityIcon
- width={14}
- height={14}
- severity={severity}
- data-guiding-id="issue-3"
- />
- </Spinner>
- </Pill>
- );
-
- const handleSetSeverity = async (severity: SoftwareImpactSeverity, quality: SoftwareQuality) => {
- setUpdatingSeverity(true);
- await onSetSeverity?.(severity, quality);
- setUpdatingSeverity(false);
- };
-
- if (onSetSeverity && type === 'issue') {
- return (
- <DropdownMenu.Root
- align={DropdownMenuAlign.Start}
- items={IMPACT_SEVERITIES.map((impactSeverity) => (
- <DropdownMenu.ItemButtonCheckable
- key={impactSeverity}
- isDisabled={impactSeverity === severity}
- isChecked={impactSeverity === severity}
- onClick={() => handleSetSeverity(impactSeverity, softwareQuality)}
- >
- <div className="sw-flex sw-items-center sw-gap-2">
- <SoftwareImpactSeverityIcon width={14} height={14} severity={impactSeverity} />
- {translate('severity_impact', impactSeverity)}
- </div>
- </DropdownMenu.ItemButtonCheckable>
- ))}
- >
- <Tooltip
- content={intl.formatMessage(
- {
- id: `issue.type.tooltip_with_change`,
- },
- {
- severity: intl.formatMessage({ id: `severity_impact.${severity}` }),
- },
- )}
- >
- {pill}
- </Tooltip>
- </DropdownMenu.Root>
- );
- }
-
- return (
- <Popover
- title={intl.formatMessage(
- { id: 'severity_impact.title' },
- { x: translate('severity_impact', severity) },
- )}
- description={
- <>
- <FormattedMessage
- id={`${type}.impact.severity.tooltip`}
- values={{
- severity: translate('severity_impact', severity).toLowerCase(),
- quality: quality.toLowerCase(),
- }}
- />
- <div className="sw-mt-2">
- {intl.formatMessage(
- { id: `severity_impact.help.description` },
- {
- p1: (text) => <p>{text}</p>,
- p: (text) => (type === 'issue' ? <p className="sw-mt-2">{text}</p> : ''),
- },
- )}
- </div>
- </>
- }
- footer={
- <DocumentationLink shouldOpenInNewTab standalone to={DocLink.MQRSeverity}>
- {translate('severity_impact.help.link')}
- </DocumentationLink>
- }
- >
- <Tooltip
- content={intl.formatMessage(
- {
- id: `issue.type.tooltip`,
- },
- {
- severity: intl.formatMessage({ id: `severity_impact.${severity}` }),
- },
- )}
- >
- {pill}
- </Tooltip>
- </Popover>
- );
-}
-
-const getQualityLabel = (quality: SoftwareQuality) => translate('software_quality', quality);
diff --git a/server/sonar-web/src/main/js/components/shared/SoftwareImpactPillList.tsx b/server/sonar-web/src/main/js/components/shared/SoftwareImpactPillList.tsx
deleted file mode 100644
index f0967a62802..00000000000
--- a/server/sonar-web/src/main/js/components/shared/SoftwareImpactPillList.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import React from 'react';
-import { useStandardExperienceModeQuery } from '../../queries/mode';
-import {
- SoftwareImpact,
- SoftwareImpactSeverity,
- SoftwareQuality,
-} from '../../types/clean-code-taxonomy';
-import { IssueSeverity } from '../../types/issues';
-import IssueTypePill from './IssueTypePill';
-import SoftwareImpactPill from './SoftwareImpactPill';
-
-interface SoftwareImpactPillListProps extends React.HTMLAttributes<HTMLUListElement> {
- className?: string;
- issueSeverity?: IssueSeverity;
- issueType?: string;
- onSetSeverity?: ((severity: IssueSeverity) => Promise<void>) &
- ((severity: SoftwareImpactSeverity, quality: SoftwareQuality) => Promise<void>);
- softwareImpacts: SoftwareImpact[];
- type?: Parameters<typeof SoftwareImpactPill>[0]['type'];
-}
-
-const sqOrderMap = {
- [SoftwareQuality.Security]: 3,
- [SoftwareQuality.Reliability]: 2,
- [SoftwareQuality.Maintainability]: 1,
-};
-
-export default function SoftwareImpactPillList({
- softwareImpacts,
- onSetSeverity,
- issueSeverity,
- issueType,
- type,
- className,
- ...props
-}: Readonly<SoftwareImpactPillListProps>) {
- const { data: isStandardMode } = useStandardExperienceModeQuery();
- const sortingFn = (a: SoftwareImpact, b: SoftwareImpact) =>
- sqOrderMap[b.softwareQuality] - sqOrderMap[a.softwareQuality];
-
- return (
- <ul className={classNames('sw-flex sw-gap-2', className)} {...props}>
- {!isStandardMode &&
- softwareImpacts
- .slice()
- .sort(sortingFn)
- .map(({ severity, softwareQuality }) => (
- <li key={softwareQuality}>
- <SoftwareImpactPill
- onSetSeverity={onSetSeverity}
- severity={severity}
- softwareQuality={softwareQuality}
- type={type}
- />
- </li>
- ))}
- {!isStandardMode && softwareImpacts.length === 0 && issueType === 'SECURITY_HOTSPOT' && (
- <IssueTypePill severity={issueSeverity ?? IssueSeverity.Info} issueType={issueType} />
- )}
- {isStandardMode && issueType && issueSeverity && (
- <IssueTypePill
- onSetSeverity={onSetSeverity}
- severity={issueSeverity}
- issueType={issueType}
- />
- )}
- </ul>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/shared/StatusHelper.tsx b/server/sonar-web/src/main/js/components/shared/StatusHelper.tsx
deleted file mode 100644
index da26dbc0996..00000000000
--- a/server/sonar-web/src/main/js/components/shared/StatusHelper.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { translate } from '../../helpers/l10n';
-import { IssueStatus } from '../../types/issues';
-import IssueStatusIcon from '../icon-mappers/IssueStatusIcon';
-
-interface Props {
- className?: string;
- issueStatus: IssueStatus;
-}
-
-export default function StatusHelper(props: Props) {
- return (
- <span className={props.className}>
- <IssueStatusIcon className="sw-mr-1" issueStatus={props.issueStatus} />
- {translate('issue.issue_status', props.issueStatus)}
- </span>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/shared/TypeHelper.tsx b/server/sonar-web/src/main/js/components/shared/TypeHelper.tsx
deleted file mode 100644
index 6701e58ce8c..00000000000
--- a/server/sonar-web/src/main/js/components/shared/TypeHelper.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { IconProps } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { IssueType, RuleType } from '../../types/types';
-import IssueTypeIcon from '../icon-mappers/IssueTypeIcon';
-
-interface Props {
- className?: string;
- iconFill?: IconProps['fill'];
- type: IssueType | RuleType;
-}
-
-export default function TypeHelper(props: Props) {
- return (
- <span className={props.className}>
- <IssueTypeIcon
- className="sw-mr-1"
- type={props.type}
- fill={props.iconFill}
- height={12}
- width={12}
- />
- {translate('issue.type', props.type)}
- </span>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/shared/__tests__/utils-test.ts b/server/sonar-web/src/main/js/components/shared/__tests__/utils-test.ts
deleted file mode 100644
index a2d00d503b6..00000000000
--- a/server/sonar-web/src/main/js/components/shared/__tests__/utils-test.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { SoftwareImpactSeverity, SoftwareQuality } from '../../../types/clean-code-taxonomy';
-import { propsToIssueParams } from '../utils';
-
-describe('propsToIssueParams', () => {
- it('should render correct default parameters', () => {
- expect(propsToIssueParams('other')).toEqual({ issueStatuses: 'OPEN,CONFIRMED' });
- });
-
- it(`should render correct params`, () => {
- expect(propsToIssueParams(MetricKey.false_positive_issues, true)).toEqual({
- inNewCodePeriod: true,
- issueStatuses: 'FALSE_POSITIVE',
- });
- });
- it.each([
- [MetricKey.software_quality_info_issues, { impactSeverities: SoftwareImpactSeverity.Info }],
- [MetricKey.software_quality_low_issues, { impactSeverities: SoftwareImpactSeverity.Low }],
- [MetricKey.software_quality_medium_issues, { impactSeverities: SoftwareImpactSeverity.Medium }],
- [MetricKey.software_quality_high_issues, { impactSeverities: SoftwareImpactSeverity.High }],
- [
- MetricKey.software_quality_blocker_issues,
- { impactSeverities: SoftwareImpactSeverity.Blocker },
- ],
- [MetricKey.new_software_quality_info_issues, { impactSeverities: SoftwareImpactSeverity.Info }],
- [MetricKey.new_software_quality_low_issues, { impactSeverities: SoftwareImpactSeverity.Low }],
- [
- MetricKey.new_software_quality_medium_issues,
- { impactSeverities: SoftwareImpactSeverity.Medium },
- ],
- [MetricKey.new_software_quality_high_issues, { impactSeverities: SoftwareImpactSeverity.High }],
- [
- MetricKey.new_software_quality_blocker_issues,
- { impactSeverities: SoftwareImpactSeverity.Blocker },
- ],
- [
- MetricKey.software_quality_reliability_issues,
- { impactSoftwareQualities: SoftwareQuality.Reliability },
- ],
- [
- MetricKey.software_quality_maintainability_issues,
- { impactSoftwareQualities: SoftwareQuality.Maintainability },
- ],
- [
- MetricKey.software_quality_security_issues,
- { impactSoftwareQualities: SoftwareQuality.Security },
- ],
- [
- MetricKey.new_software_quality_reliability_issues,
- { impactSoftwareQualities: SoftwareQuality.Reliability },
- ],
- [
- MetricKey.new_software_quality_maintainability_issues,
- { impactSoftwareQualities: SoftwareQuality.Maintainability },
- ],
- [
- MetricKey.new_software_quality_security_issues,
- { impactSoftwareQualities: SoftwareQuality.Security },
- ],
- ])(`should render correct params for %s`, (metricKey, result) => {
- expect(propsToIssueParams(metricKey)).toEqual({
- issueStatuses: 'OPEN,CONFIRMED',
- ...result,
- });
- });
-});
diff --git a/server/sonar-web/src/main/js/components/shared/utils.ts b/server/sonar-web/src/main/js/components/shared/utils.ts
deleted file mode 100644
index b0bef60343a..00000000000
--- a/server/sonar-web/src/main/js/components/shared/utils.ts
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { SoftwareImpactSeverity, SoftwareQuality } from '../../types/clean-code-taxonomy';
-import { IssueStatus } from '../../types/issues';
-import { Dict } from '../../types/types';
-
-const ISSUE_MEASURES = [
- MetricKey.violations,
- MetricKey.new_violations,
- MetricKey.blocker_violations,
- MetricKey.critical_violations,
- MetricKey.major_violations,
- MetricKey.minor_violations,
- MetricKey.info_violations,
- MetricKey.new_blocker_violations,
- MetricKey.new_critical_violations,
- MetricKey.new_major_violations,
- MetricKey.new_minor_violations,
- MetricKey.new_info_violations,
- MetricKey.open_issues,
- MetricKey.reopened_issues,
- MetricKey.confirmed_issues,
- MetricKey.false_positive_issues,
- MetricKey.code_smells,
- MetricKey.new_code_smells,
- MetricKey.bugs,
- MetricKey.new_bugs,
- MetricKey.vulnerabilities,
- MetricKey.new_vulnerabilities,
- MetricKey.prioritized_rule_issues,
- // MQR
- MetricKey.new_software_quality_info_issues,
- MetricKey.new_software_quality_low_issues,
- MetricKey.new_software_quality_medium_issues,
- MetricKey.new_software_quality_high_issues,
- MetricKey.new_software_quality_blocker_issues,
- MetricKey.software_quality_info_issues,
- MetricKey.software_quality_low_issues,
- MetricKey.software_quality_medium_issues,
- MetricKey.software_quality_high_issues,
- MetricKey.software_quality_blocker_issues,
- MetricKey.new_software_quality_maintainability_issues,
- MetricKey.new_software_quality_reliability_issues,
- MetricKey.new_software_quality_security_issues,
- MetricKey.software_quality_maintainability_issues,
- MetricKey.software_quality_reliability_issues,
- MetricKey.software_quality_security_issues,
- MetricKey.new_software_quality_maintainability_rating,
- MetricKey.software_quality_maintainability_rating,
-];
-
-export const DEFAULT_ISSUES_QUERY = {
- issueStatuses: `${IssueStatus.Open},${IssueStatus.Confirmed}`,
-};
-
-const issueParamsPerMetric: Dict<Dict<string>> = {
- [MetricKey.blocker_violations]: { severities: 'BLOCKER' },
- [MetricKey.new_blocker_violations]: { severities: 'BLOCKER' },
- [MetricKey.critical_violations]: { severities: 'CRITICAL' },
- [MetricKey.new_critical_violations]: { severities: 'CRITICAL' },
- [MetricKey.major_violations]: { severities: 'MAJOR' },
- [MetricKey.new_major_violations]: { severities: 'MAJOR' },
- [MetricKey.minor_violations]: { severities: 'MINOR' },
- [MetricKey.new_minor_violations]: { severities: 'MINOR' },
- [MetricKey.info_violations]: { severities: 'INFO' },
- [MetricKey.new_info_violations]: { severities: 'INFO' },
- [MetricKey.open_issues]: { issueStatuses: IssueStatus.Open },
- [MetricKey.reopened_issues]: { issueStatuses: IssueStatus.Open },
- [MetricKey.confirmed_issues]: { issueStatuses: IssueStatus.Confirmed },
- [MetricKey.false_positive_issues]: { issueStatuses: IssueStatus.FalsePositive },
- [MetricKey.code_smells]: { types: 'CODE_SMELL' },
- [MetricKey.new_code_smells]: { types: 'CODE_SMELL' },
- [MetricKey.bugs]: { types: 'BUG' },
- [MetricKey.new_bugs]: { types: 'BUG' },
- [MetricKey.vulnerabilities]: { types: 'VULNERABILITY' },
- [MetricKey.new_vulnerabilities]: { types: 'VULNERABILITY' },
- [MetricKey.prioritized_rule_issues]: { prioritizedRule: 'true' },
- // MQR
- [MetricKey.new_software_quality_info_issues]: { impactSeverities: SoftwareImpactSeverity.Info },
- [MetricKey.new_software_quality_low_issues]: { impactSeverities: SoftwareImpactSeverity.Low },
- [MetricKey.new_software_quality_medium_issues]: {
- impactSeverities: SoftwareImpactSeverity.Medium,
- },
- [MetricKey.new_software_quality_high_issues]: { impactSeverities: SoftwareImpactSeverity.High },
- [MetricKey.new_software_quality_blocker_issues]: {
- impactSeverities: SoftwareImpactSeverity.Blocker,
- },
- [MetricKey.software_quality_info_issues]: { impactSeverities: SoftwareImpactSeverity.Info },
- [MetricKey.software_quality_low_issues]: { impactSeverities: SoftwareImpactSeverity.Low },
- [MetricKey.software_quality_medium_issues]: { impactSeverities: SoftwareImpactSeverity.Medium },
- [MetricKey.software_quality_high_issues]: { impactSeverities: SoftwareImpactSeverity.High },
- [MetricKey.software_quality_blocker_issues]: { impactSeverities: SoftwareImpactSeverity.Blocker },
- [MetricKey.new_software_quality_maintainability_issues]: {
- impactSoftwareQualities: SoftwareQuality.Maintainability,
- },
- [MetricKey.new_software_quality_reliability_issues]: {
- impactSoftwareQualities: SoftwareQuality.Reliability,
- },
- [MetricKey.new_software_quality_security_issues]: {
- impactSoftwareQualities: SoftwareQuality.Security,
- },
- [MetricKey.software_quality_maintainability_issues]: {
- impactSoftwareQualities: SoftwareQuality.Maintainability,
- },
- [MetricKey.software_quality_reliability_issues]: {
- impactSoftwareQualities: SoftwareQuality.Reliability,
- },
- [MetricKey.software_quality_security_issues]: {
- impactSoftwareQualities: SoftwareQuality.Security,
- },
-};
-
-export function isIssueMeasure(metric: string) {
- return ISSUE_MEASURES.indexOf(metric as MetricKey) !== -1;
-}
-
-export function propsToIssueParams(metric: string, inNewCodePeriod = false) {
- const params: Dict<string | boolean> = {
- ...DEFAULT_ISSUES_QUERY,
- ...issueParamsPerMetric[metric],
- };
-
- if (inNewCodePeriod) {
- params.inNewCodePeriod = true;
- }
-
- return params;
-}
diff --git a/server/sonar-web/src/main/js/components/tags/TagsList.tsx b/server/sonar-web/src/main/js/components/tags/TagsList.tsx
deleted file mode 100644
index 668862b8cbf..00000000000
--- a/server/sonar-web/src/main/js/components/tags/TagsList.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { PopupPlacement, Tags } from '~design-system';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import Tooltip from '../controls/Tooltip';
-
-interface Props {
- allowUpdate?: boolean;
- className?: string;
- overlay?: React.ReactNode;
- tags: string[];
- tagsClassName?: string;
- tagsToDisplay?: number;
-}
-
-export default function TagsList({
- allowUpdate = false,
- className,
- tags,
- overlay,
- tagsClassName,
- tagsToDisplay = 2,
-}: Readonly<Props>) {
- const [open, setOpen] = React.useState(false);
-
- return (
- <Tags
- allowUpdate={allowUpdate}
- ariaTagsListLabel={translateWithParameters('tags_list_x', tags.join(', '))}
- className={className}
- emptyText={translate('no_tags')}
- menuId="rule-tags-menu"
- onClose={() => setOpen(false)}
- open={open}
- overlay={overlay}
- popupPlacement={PopupPlacement.Bottom}
- tags={tags}
- tagsClassName={tagsClassName}
- tagsToDisplay={tagsToDisplay}
- tooltip={Tooltip}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/templates/FilterBarTemplate.tsx b/server/sonar-web/src/main/js/components/templates/FilterBarTemplate.tsx
deleted file mode 100644
index cdd3b82e928..00000000000
--- a/server/sonar-web/src/main/js/components/templates/FilterBarTemplate.tsx
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import React from 'react';
-import {
- LAYOUT_FILTERBAR_HEADER,
- LAYOUT_FOOTER_HEIGHT,
- LAYOUT_GLOBAL_NAV_HEIGHT,
- LAYOUT_PROJECT_NAV_HEIGHT,
- themeBorder,
- themeColor,
-} from '~design-system';
-import { translate } from '../../helpers/l10n';
-
-import useFollowScroll from '../../hooks/useFollowScroll';
-
-export type LayoutFilterBarSize = 'default' | 'large';
-
-const HEADER_PADDING_BOTTOM = 24;
-const HEADER_PADDING = 32 + HEADER_PADDING_BOTTOM; //32 padding top and 24 padding bottom
-
-interface Props {
- className?: string;
- content: React.ReactNode;
- contentClassName?: string;
- filterbar: React.ReactNode;
- filterbarContentClassName?: string;
- filterbarHeader?: React.ReactNode;
- filterbarHeaderClassName?: string;
- filterbarRef?: React.RefObject<HTMLDivElement>;
- header?: React.ReactNode;
- headerHeight?: number;
- id?: string;
- size?: LayoutFilterBarSize;
- withBorderLeft?: boolean;
-}
-
-export default function FilterBarTemplate(props: Readonly<Props>) {
- const {
- className,
- content,
- contentClassName,
- header,
- headerHeight = 0,
- id,
- filterbarRef,
- filterbar,
- filterbarHeader,
- filterbarHeaderClassName,
- filterbarContentClassName,
- size = 'default',
- withBorderLeft = false,
- } = props;
-
- const headerHeightWithPadding = headerHeight ? headerHeight + HEADER_PADDING : 0;
- const { top: topScroll, scrolledOnce } = useFollowScroll();
- const distanceFromBottom = topScroll + window.innerHeight - document.body.scrollHeight;
- const footerVisibleHeight =
- (scrolledOnce &&
- (distanceFromBottom > -LAYOUT_FOOTER_HEIGHT
- ? LAYOUT_FOOTER_HEIGHT + distanceFromBottom
- : 0)) ||
- 0;
-
- return (
- <>
- {header && (
- <div
- className="sw-flex sw-pb-6 sw-box-border"
- style={{
- height: `${headerHeight + HEADER_PADDING_BOTTOM}px`,
- }}
- >
- {header}
- </div>
- )}
- <div
- className={classNames(
- 'sw-grid sw-grid-cols-12 sw-w-full sw-px-14 sw-box-border',
- className,
- )}
- id={id}
- >
- <Filterbar
- className={classNames('sw-z-filterbar', {
- 'sw-col-span-3': size === 'default',
- 'sw-col-span-4': size === 'large',
- bordered: Boolean(header),
- 'sw-mt-0': Boolean(header),
- 'sw-rounded-t-1': Boolean(header),
- 'border-left': withBorderLeft,
- })}
- ref={filterbarRef}
- style={{
- height: `calc(100vh - ${
- LAYOUT_GLOBAL_NAV_HEIGHT + LAYOUT_PROJECT_NAV_HEIGHT
- }px - ${footerVisibleHeight}px)`,
- top: LAYOUT_GLOBAL_NAV_HEIGHT + LAYOUT_PROJECT_NAV_HEIGHT + headerHeightWithPadding,
- }}
- >
- {filterbarHeader && (
- <FilterbarHeader
- className={classNames(
- 'sw-w-full sw-top-0 sw-px-4 sw-py-2 sw-z-filterbar-header',
- filterbarHeaderClassName,
- )}
- >
- {filterbarHeader}
- </FilterbarHeader>
- )}
- <FilterbarContent
- aria-label={translate('secondary')}
- className={classNames('sw-p-4 js-page-filter', filterbarContentClassName)}
- >
- {filterbar}
- </FilterbarContent>
- </Filterbar>
- <Main
- className={classNames(
- 'sw-relative sw-pl-12',
- {
- 'sw-col-span-9': size === 'default',
- 'sw-col-span-8': size === 'large',
- },
- 'js-page-main',
- contentClassName,
- )}
- >
- {content}
- </Main>
- </div>
- </>
- );
-}
-
-const Filterbar = styled.div`
- position: sticky;
- box-sizing: border-box;
- overflow-x: hidden;
- overflow-y: auto;
- background-color: ${themeColor('filterbar')};
- border-right: ${themeBorder('default', 'filterbarBorder')};
-
- &.border-left {
- border-left: ${themeBorder('default', 'filterbarBorder')};
- }
-
- &.bordered {
- border: ${themeBorder('default', 'filterbarBorder')};
- }
-`;
-
-const FilterbarContent = styled.nav`
- position: relative;
- box-sizing: border-box;
- width: 100%;
-`;
-
-const FilterbarHeader = styled.div`
- position: sticky;
- box-sizing: border-box;
- height: ${LAYOUT_FILTERBAR_HEADER}px;
- background-color: inherit;
- border-bottom: ${themeBorder('default')};
-`;
-
-const Main = styled.div`
- flex-grow: 1;
-`;
diff --git a/server/sonar-web/src/main/js/components/templates/__tests__/FilterBarTemplate-test.tsx b/server/sonar-web/src/main/js/components/templates/__tests__/FilterBarTemplate-test.tsx
deleted file mode 100644
index d20d9838d51..00000000000
--- a/server/sonar-web/src/main/js/components/templates/__tests__/FilterBarTemplate-test.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { FCProps } from '../../../types/misc';
-import FilterBarTemplate from '../FilterBarTemplate';
-
-it('should render with filter header', () => {
- setupWithProps({ header: <span data-testid="filter-header">header</span>, headerHeight: 16 });
-
- expect(screen.getByTestId('filter-header')).toHaveTextContent('header');
-});
-
-function setupWithProps(props: Partial<FCProps<typeof FilterBarTemplate>> = {}) {
- return renderComponent(
- <FilterBarTemplate
- className="custom-class"
- content={<div data-testid="content" />}
- filterbar={<div data-testid="side" />}
- filterbarHeader={<div data-testid="side-header" />}
- size="large"
- {...props}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx b/server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx
deleted file mode 100644
index 704f236c9ab..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { withRouter } from '~sonar-aligned/components/hoc/withRouter';
-import { Location } from '~sonar-aligned/types/router';
-import { getAlmSettingsNoCatch } from '../../api/alm-settings';
-import { getScannableProjects } from '../../api/components';
-import { getValue } from '../../api/settings';
-import { getHostUrl } from '../../helpers/urls';
-import { hasGlobalPermission } from '../../helpers/users';
-import { useProjectBindingQuery } from '../../queries/devops-integration';
-import { AlmSettingsInstance } from '../../types/alm-settings';
-import { Permissions } from '../../types/permissions';
-import { SettingsKey } from '../../types/settings';
-import { Component } from '../../types/types';
-import { LoggedInUser } from '../../types/users';
-import TutorialSelectionRenderer from './TutorialSelectionRenderer';
-import { TutorialModes } from './types';
-
-export interface TutorialSelectionProps {
- component: Component;
- currentUser: LoggedInUser;
- location: Location;
- willRefreshAutomatically?: boolean;
-}
-
-export function TutorialSelection(props: Readonly<TutorialSelectionProps>) {
- const { component, currentUser, location, willRefreshAutomatically } = props;
- const [currentUserCanScanProject, setCurrentUserCanScanProject] = React.useState(false);
- const [baseUrl, setBaseUrl] = React.useState(getHostUrl());
- const [loading, setLoading] = React.useState(true);
- const [loadingAlm, setLoadingAlm] = React.useState(false);
- const [almBinding, setAlmBinding] = React.useState<AlmSettingsInstance | undefined>(undefined);
- const { data: projectBinding } = useProjectBindingQuery(component.key);
-
- React.useEffect(() => {
- const checkUserPermissions = async () => {
- if (hasGlobalPermission(currentUser, Permissions.Scan)) {
- setCurrentUserCanScanProject(true);
- return Promise.resolve();
- }
-
- const { projects } = await getScannableProjects();
- setCurrentUserCanScanProject(projects.find((p) => p.key === component.key) !== undefined);
-
- return Promise.resolve();
- };
-
- const fetchBaseUrl = async () => {
- const setting = await getValue({ key: SettingsKey.ServerBaseUrl }).catch(() => undefined);
- const baseUrl = setting?.value;
- if (baseUrl && baseUrl.length > 0) {
- setBaseUrl(baseUrl);
- }
- };
-
- Promise.all([fetchBaseUrl(), checkUserPermissions()])
- .then(() => {
- setLoading(false);
- })
- .catch(() => {});
- }, [component.key, currentUser]);
-
- React.useEffect(() => {
- const fetchAlmBindings = async () => {
- if (projectBinding != null) {
- setLoadingAlm(true);
- const almSettings = await getAlmSettingsNoCatch(component.key).catch(() => undefined);
- let almBinding;
- if (almSettings !== undefined) {
- almBinding = almSettings.find((d) => d.key === projectBinding.key);
- }
- setAlmBinding(almBinding);
- setLoadingAlm(false);
- }
- };
-
- fetchAlmBindings().catch(() => {});
- }, [component.key, projectBinding]);
-
- const selectedTutorial: TutorialModes | undefined = location.query?.selectedTutorial;
-
- return (
- <TutorialSelectionRenderer
- almBinding={almBinding}
- baseUrl={baseUrl}
- component={component}
- currentUser={currentUser}
- currentUserCanScanProject={currentUserCanScanProject}
- loading={loading || loadingAlm}
- projectBinding={projectBinding}
- selectedTutorial={selectedTutorial}
- willRefreshAutomatically={willRefreshAutomatically}
- />
- );
-}
-
-export default withRouter(TutorialSelection);
diff --git a/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx b/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx
deleted file mode 100644
index 9e37fe68868..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkHighlight, LinkStandalone, Spinner } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import {
- Breadcrumbs,
- FlagMessage,
- GreyCard,
- LightLabel,
- LightPrimary,
- SubTitle,
- Title,
-} from '~design-system';
-import { Image } from '~sonar-aligned/components/common/Image';
-import { isMainBranch } from '~sonar-aligned/helpers/branch-like';
-import { AnalysisStatus } from '../../apps/overview/components/AnalysisStatus';
-import { translate } from '../../helpers/l10n';
-import { getProjectTutorialLocation } from '../../helpers/urls';
-import { useBranchesQuery } from '../../queries/branch';
-import { AlmKeys, AlmSettingsInstance, ProjectAlmBindingResponse } from '../../types/alm-settings';
-import { MainBranch } from '../../types/branch-like';
-import { Component } from '../../types/types';
-import { LoggedInUser } from '../../types/users';
-import AzurePipelinesTutorial from './azure-pipelines/AzurePipelinesTutorial';
-import BitbucketPipelinesTutorial from './bitbucket-pipelines/BitbucketPipelinesTutorial';
-import GitHubActionTutorial from './github-action/GitHubActionTutorial';
-import GitLabCITutorial from './gitlabci/GitLabCITutorial';
-import JenkinsTutorial from './jenkins/JenkinsTutorial';
-import OtherTutorial from './other/OtherTutorial';
-import { TutorialModes } from './types';
-
-const DEFAULT_MAIN_BRANCH_NAME = 'main';
-
-export interface TutorialSelectionRendererProps {
- almBinding?: AlmSettingsInstance;
- baseUrl: string;
- component: Component;
- currentUser: LoggedInUser;
- currentUserCanScanProject: boolean;
- loading: boolean;
- projectBinding?: ProjectAlmBindingResponse | null;
- selectedTutorial?: TutorialModes;
- willRefreshAutomatically?: boolean;
-}
-
-function renderAlm(mode: TutorialModes, project: string, icon?: React.ReactNode) {
- return (
- <GreyCard className="sw-col-span-4 sw-p-4">
- <LinkStandalone iconLeft={icon} to={getProjectTutorialLocation(project, mode)}>
- <span className={icon ? 'sw-ml-2' : ''}>
- {translate('onboarding.tutorial.choose_method', mode)}
- </span>
- </LinkStandalone>
-
- {mode === TutorialModes.Local && (
- <LightLabel as="p" className="sw-mt-3">
- {translate('onboarding.mode.help.manual')}
- </LightLabel>
- )}
-
- {mode === TutorialModes.OtherCI && (
- <LightLabel as="p" className="sw-mt-3">
- {translate('onboarding.mode.help.otherci')}
- </LightLabel>
- )}
- </GreyCard>
- );
-}
-
-export default function TutorialSelectionRenderer(props: TutorialSelectionRendererProps) {
- const {
- almBinding,
- baseUrl,
- component,
- currentUser,
- currentUserCanScanProject,
- loading,
- projectBinding,
- selectedTutorial,
- willRefreshAutomatically,
- } = props;
-
- const { data: branchLikes = [] } = useBranchesQuery(component);
-
- const mainBranchName =
- (branchLikes.find((b) => isMainBranch(b)) as MainBranch | undefined)?.name ||
- DEFAULT_MAIN_BRANCH_NAME;
-
- if (loading) {
- return <Spinner />;
- }
-
- if (!currentUserCanScanProject) {
- return (
- <FlagMessage className="sw-w-full" variant="warning">
- {translate('onboarding.tutorial.no_scan_rights')}
- </FlagMessage>
- );
- }
-
- let showGitHubActions = true;
- let showGitLabCICD = true;
- let showBitbucketPipelines = true;
- let showAzurePipelines = true;
- let showJenkins = true;
-
- if (projectBinding != null) {
- showGitHubActions = projectBinding.alm === AlmKeys.GitHub;
- showGitLabCICD = projectBinding.alm === AlmKeys.GitLab;
- showBitbucketPipelines = projectBinding.alm === AlmKeys.BitbucketCloud;
- showAzurePipelines = [AlmKeys.Azure, AlmKeys.GitHub].includes(projectBinding.alm);
-
- showJenkins = [
- AlmKeys.BitbucketCloud,
- AlmKeys.BitbucketServer,
- AlmKeys.GitHub,
- AlmKeys.GitLab,
- ].includes(projectBinding.alm);
- }
-
- return (
- <div className="sw-typo-default">
- <AnalysisStatus component={component} className="sw-mb-4 sw-w-max" />
-
- {selectedTutorial === undefined && (
- <div className="sw-flex sw-flex-col">
- <Title className="sw-mb-6 sw-heading-xl">
- {translate('onboarding.tutorial.page.title')}
- </Title>
-
- <LightPrimary>{translate('onboarding.tutorial.page.description')}</LightPrimary>
-
- <SubTitle className="sw-mt-12 sw-mb-4 sw-heading-lg">
- {translate('onboarding.tutorial.choose_method')}
- </SubTitle>
-
- <div className="it__tutorial-selection sw-grid sw-gap-6 sw-grid-cols-12">
- {showJenkins &&
- renderAlm(
- TutorialModes.Jenkins,
- component.key,
- <Image
- alt="" // Should be ignored by screen readers
- className="sw-h-4 sw-w-4"
- src="/images/tutorials/jenkins.svg"
- />,
- )}
-
- {showGitHubActions &&
- renderAlm(
- TutorialModes.GitHubActions,
- component.key,
- <Image
- alt="" // Should be ignored by screen readers
- className="sw-h-4 sw-w-4"
- src="/images/tutorials/github-actions.svg"
- />,
- )}
-
- {showBitbucketPipelines &&
- renderAlm(
- TutorialModes.BitbucketPipelines,
- component.key,
- <Image
- alt="" // Should be ignored by screen readers
- className="sw-h-4 sw-w-4"
- src="/images/alm/bitbucket.svg"
- />,
- )}
-
- {showGitLabCICD &&
- renderAlm(
- TutorialModes.GitLabCI,
- component.key,
- <Image
- alt="" // Should be ignored by screen readers
- className="sw-h-4 sw-w-4"
- src="/images/alm/gitlab.svg"
- />,
- )}
-
- {showAzurePipelines &&
- renderAlm(
- TutorialModes.AzurePipelines,
- component.key,
- <Image
- alt="" // Should be ignored by screen readers
- className="sw-h-4 sw-w-4"
- src="/images/tutorials/azure-pipelines.svg"
- />,
- )}
-
- {renderAlm(TutorialModes.OtherCI, component.key)}
-
- {renderAlm(TutorialModes.Local, component.key)}
- </div>
- </div>
- )}
-
- {selectedTutorial && (
- <Breadcrumbs className="sw-mb-3">
- <LinkStandalone
- highlight={LinkHighlight.CurrentColor}
- to={getProjectTutorialLocation(component.key)}
- >
- {translate('onboarding.tutorial.breadcrumbs.home')}
- </LinkStandalone>
-
- <LinkStandalone
- highlight={LinkHighlight.CurrentColor}
- to={getProjectTutorialLocation(component.key, selectedTutorial)}
- >
- {translate('onboarding.tutorial.breadcrumbs', selectedTutorial)}
- </LinkStandalone>
- </Breadcrumbs>
- )}
-
- {selectedTutorial === TutorialModes.Local && (
- <OtherTutorial component={component} baseUrl={baseUrl} isLocal currentUser={currentUser} />
- )}
-
- {selectedTutorial === TutorialModes.OtherCI && (
- <OtherTutorial component={component} baseUrl={baseUrl} currentUser={currentUser} />
- )}
-
- {selectedTutorial === TutorialModes.BitbucketPipelines && (
- <BitbucketPipelinesTutorial
- almBinding={almBinding}
- baseUrl={baseUrl}
- component={component}
- currentUser={currentUser}
- mainBranchName={mainBranchName}
- willRefreshAutomatically={willRefreshAutomatically}
- />
- )}
-
- {selectedTutorial === TutorialModes.GitHubActions && (
- <GitHubActionTutorial
- almBinding={almBinding}
- baseUrl={baseUrl}
- component={component}
- currentUser={currentUser}
- monorepo={projectBinding?.monorepo}
- mainBranchName={mainBranchName}
- willRefreshAutomatically={willRefreshAutomatically}
- />
- )}
-
- {selectedTutorial === TutorialModes.Jenkins && (
- <JenkinsTutorial
- almBinding={almBinding}
- baseUrl={baseUrl}
- component={component}
- willRefreshAutomatically={willRefreshAutomatically}
- />
- )}
-
- {selectedTutorial === TutorialModes.GitLabCI && (
- <GitLabCITutorial
- baseUrl={baseUrl}
- component={component}
- currentUser={currentUser}
- willRefreshAutomatically={willRefreshAutomatically}
- />
- )}
-
- {selectedTutorial === TutorialModes.AzurePipelines && (
- <AzurePipelinesTutorial
- alm={projectBinding?.alm}
- baseUrl={baseUrl}
- component={component}
- currentUser={currentUser}
- willRefreshAutomatically={willRefreshAutomatically}
- />
- )}
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-it.tsx b/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-it.tsx
deleted file mode 100644
index b9c978add87..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-it.tsx
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen, waitFor } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { getScannableProjects } from '../../../api/components';
-import AlmSettingsServiceMock from '../../../api/mocks/AlmSettingsServiceMock';
-import SettingsServiceMock from '../../../api/mocks/SettingsServiceMock';
-import UserTokensMock from '../../../api/mocks/UserTokensMock';
-import { mockComponent } from '../../../helpers/mocks/component';
-import { mockLoggedInUser } from '../../../helpers/testMocks';
-import { renderApp } from '../../../helpers/testReactTestingUtils';
-import { AlmKeys } from '../../../types/alm-settings';
-import { Feature } from '../../../types/features';
-import { Permissions } from '../../../types/permissions';
-import { SettingsKey } from '../../../types/settings';
-import TutorialSelection, { TutorialSelectionProps } from '../TutorialSelection';
-import { TutorialModes } from '../types';
-
-jest.mock('../../../api/branches');
-
-jest.mock('../../../helpers/urls', () => ({
- ...jest.requireActual('../../../helpers/urls'),
- getHostUrl: jest.fn().mockReturnValue('http://host.url'),
-}));
-
-jest.mock('../../../api/components', () => ({
- getScannableProjects: jest.fn().mockResolvedValue({ projects: [] }),
-}));
-
-let settingsMock: SettingsServiceMock;
-let tokenMock: UserTokensMock;
-let almMock: AlmSettingsServiceMock;
-
-beforeAll(() => {
- settingsMock = new SettingsServiceMock();
- tokenMock = new UserTokensMock();
- almMock = new AlmSettingsServiceMock();
-});
-
-afterEach(() => {
- tokenMock.reset();
- settingsMock.reset();
- almMock.reset();
-});
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
-
-const ui = {
- loading: byText('loading'),
- noScanRights: byText('onboarding.tutorial.no_scan_rights'),
- monoRepoSecretInfo: byText(
- 'onboarding.tutorial.with.github_action.create_secret.monorepo_project_level_token_info.link',
- ),
- monoRepoYamlDocLink: byRole('link', {
- name: /^onboarding\.tutorial\.with\.github_action\.monorepo\.see_yaml_instructions\b/,
- }),
- chooseTutorialLink: (mode: TutorialModes) =>
- byRole('link', { name: `onboarding.tutorial.choose_method.${mode}` }),
- chooseBootstrapper: (bootstrapper: string) =>
- byRole('radio', { name: `onboarding.build.${bootstrapper}` }),
-};
-
-it.each([
- [TutorialModes.Jenkins, 'onboarding.tutorial.with.jenkins.title'],
- [TutorialModes.AzurePipelines, 'onboarding.tutorial.with.azure_pipelines.title'],
- [
- TutorialModes.BitbucketPipelines,
- 'onboarding.tutorial.with.bitbucket_pipelines.variables.title',
- ],
- [TutorialModes.GitHubActions, 'onboarding.tutorial.with.github_action.create_secret.title'],
- [TutorialModes.GitLabCI, 'onboarding.tutorial.with.gitlab_ci.title'],
- [TutorialModes.Local, 'onboarding.project_analysis.header'],
- [TutorialModes.OtherCI, 'onboarding.project_analysis.header'],
-])('should properly click link for %s', async (mode, title) => {
- const user = userEvent.setup();
- const breadcrumbs = `onboarding.tutorial.breadcrumbs.${mode}`;
- renderTutorialSelection({});
- await waitOnDataLoaded();
-
- expect(screen.getByText('onboarding.tutorial.choose_method')).toBeInTheDocument();
-
- expect(screen.queryByText(breadcrumbs)).not.toBeInTheDocument();
- await user.click(ui.chooseTutorialLink(mode).get());
- expect(screen.getByText(title)).toBeInTheDocument();
- expect(screen.getByText(breadcrumbs)).toBeInTheDocument();
-});
-
-it('should properly detect and render GitHub monorepo-specific instructions for GitHub Actions', async () => {
- almMock.handleSetProjectBinding(AlmKeys.GitHub, {
- project: 'foo',
- almSetting: 'foo',
- repository: 'repo',
- monorepo: true,
- });
- const user = userEvent.setup();
- renderTutorialSelection({});
- await waitOnDataLoaded();
-
- await user.click(ui.chooseTutorialLink(TutorialModes.GitHubActions).get());
-
- expect(ui.monoRepoSecretInfo.get()).toBeInTheDocument();
-
- expect(ui.monoRepoYamlDocLink.query()).not.toBeInTheDocument();
- await user.click(ui.chooseBootstrapper('maven').get());
- expect(ui.monoRepoYamlDocLink.get()).toBeInTheDocument();
-
- await user.click(ui.chooseBootstrapper('gradle').get());
- expect(ui.monoRepoYamlDocLink.get()).toBeInTheDocument();
-
- await user.click(ui.chooseBootstrapper('dotnet').get());
- expect(ui.monoRepoYamlDocLink.get()).toBeInTheDocument();
-
- await user.click(ui.chooseBootstrapper('other').get());
- expect(ui.monoRepoYamlDocLink.get()).toBeInTheDocument();
-});
-
-it('should properly render GitHub project tutorials for GitHub Actions', async () => {
- almMock.handleSetProjectBinding(AlmKeys.GitHub, {
- project: 'foo',
- almSetting: 'foo',
- repository: 'repo',
- monorepo: false,
- });
- const user = userEvent.setup();
- renderTutorialSelection({});
- await waitOnDataLoaded();
-
- await user.click(ui.chooseTutorialLink(TutorialModes.GitHubActions).get());
-
- expect(ui.monoRepoSecretInfo.query()).not.toBeInTheDocument();
-
- await user.click(ui.chooseBootstrapper('maven').get());
- expect(ui.monoRepoYamlDocLink.query()).not.toBeInTheDocument();
-});
-
-it.each([
- [
- AlmKeys.GitHub,
- [TutorialModes.GitHubActions, TutorialModes.Jenkins, TutorialModes.AzurePipelines],
- ],
- [AlmKeys.GitLab, [TutorialModes.GitLabCI, TutorialModes.Jenkins]],
- [AlmKeys.Azure, [TutorialModes.AzurePipelines]],
- [AlmKeys.BitbucketServer, [TutorialModes.Jenkins]],
- [AlmKeys.BitbucketCloud, [TutorialModes.BitbucketPipelines, TutorialModes.Jenkins]],
-])('should show correct buttons if project is bound to %s', async (alm, modes) => {
- almMock.handleSetProjectBinding(alm, {
- project: 'foo',
- almSetting: 'foo',
- repository: 'repo',
- monorepo: false,
- });
- renderTutorialSelection();
- await waitOnDataLoaded();
-
- modes.forEach((mode) => expect(ui.chooseTutorialLink(mode).get()).toBeInTheDocument());
-});
-
-it('should correctly fetch the corresponding ALM setting', async () => {
- almMock.handleSetProjectBinding(AlmKeys.GitHub, {
- project: 'foo',
- almSetting: 'conf-github-1',
- repository: 'repo',
- monorepo: false,
- });
- renderTutorialSelection({}, `tutorials?selectedTutorial=${TutorialModes.Jenkins}&id=foo`);
- await waitOnDataLoaded();
-
- expect(await screen.findByText('http://url', { exact: false })).toBeInTheDocument();
-});
-
-it('should correctly fetch the instance URL', async () => {
- settingsMock.set(SettingsKey.ServerBaseUrl, 'http://sq.example.com');
- const user = userEvent.setup();
- renderTutorialSelection();
- await waitOnDataLoaded();
-
- await startLocalTutorial(user);
- expect(
- screen.getByText('-Dsonar.host.url=http://sq.example.com', { exact: false }),
- ).toBeInTheDocument();
-});
-
-it('should fallback on the host URL', async () => {
- const user = userEvent.setup();
- renderTutorialSelection();
- await waitOnDataLoaded();
-
- await startLocalTutorial(user);
- expect(
- screen.getByText('-Dsonar.host.url=http://host.url', { exact: false }),
- ).toBeInTheDocument();
-});
-
-it('should not display a warning if the user has no global scan permission, but can scan the project', async () => {
- jest
- .mocked(getScannableProjects)
- .mockResolvedValueOnce({ projects: [{ key: 'foo', name: 'foo' }] });
- renderTutorialSelection({ currentUser: mockLoggedInUser() });
- await waitOnDataLoaded();
-
- expect(ui.noScanRights.query()).not.toBeInTheDocument();
-});
-
-it('should correctly display a warning if the user has no scan permissions', async () => {
- renderTutorialSelection({ currentUser: mockLoggedInUser() });
- await waitOnDataLoaded();
-
- expect(ui.noScanRights.query()).toBeInTheDocument();
-});
-
-async function waitOnDataLoaded() {
- await waitFor(() => {
- expect(ui.loading.query()).not.toBeInTheDocument();
- });
-}
-
-async function startLocalTutorial(user: UserEvent) {
- await user.click(ui.chooseTutorialLink(TutorialModes.Local).get());
- await user.click(screen.getByRole('button', { name: 'onboarding.token.generate' }));
- await user.click(screen.getByRole('button', { name: 'continue' }));
- await user.click(screen.getByRole('radio', { name: 'onboarding.build.maven' }));
-}
-
-function renderTutorialSelection(
- props: Partial<TutorialSelectionProps> = {},
- navigateTo: string = 'tutorials?id=bar',
-) {
- return renderApp(
- '/tutorials',
- <TutorialSelection
- component={mockComponent({ key: 'foo' })}
- currentUser={mockLoggedInUser({ permissions: { global: [Permissions.Scan] } })}
- {...props}
- />,
- { featureList: [Feature.BranchSupport], navigateTo },
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/__tests__/utils-test.ts b/server/sonar-web/src/main/js/components/tutorials/__tests__/utils-test.ts
deleted file mode 100644
index fb52b838d07..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/__tests__/utils-test.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- mockAlmSettingsInstance,
- mockProjectBitbucketCloudBindingResponse,
- mockProjectGithubBindingResponse,
-} from '../../../helpers/mocks/alm-settings';
-import { mockUserToken } from '../../../helpers/mocks/token';
-import { UserToken } from '../../../types/token';
-import { buildBitbucketCloudLink, buildGithubLink, getUniqueTokenName } from '../utils';
-
-describe('getUniqueTokenName', () => {
- const initialTokenName = 'Analyze "lightsaber"';
-
- it('should return the given name when the user has no token', () => {
- const userTokens: UserToken[] = [];
-
- expect(getUniqueTokenName(userTokens, initialTokenName)).toBe(initialTokenName);
- });
-
- it('should generate a token with the given name', () => {
- expect(
- getUniqueTokenName([mockUserToken({ name: initialTokenName })], 'Analyze "project"'),
- ).toBe('Analyze "project"');
- });
-
- it('should generate a unique token when the name already exists', () => {
- const userTokens = [
- mockUserToken({ name: initialTokenName }),
- mockUserToken({ name: `${initialTokenName} 1` }),
- ];
-
- expect(getUniqueTokenName(userTokens, initialTokenName)).toBe('Analyze "lightsaber" 2');
- });
-});
-
-describe('buildGithubLink', () => {
- const projectBinding = mockProjectGithubBindingResponse({ repository: 'owner/reponame' });
-
- it('should work for GitHub Enterprise', () => {
- expect(
- buildGithubLink(
- mockAlmSettingsInstance({ url: 'https://github.company.com/api/v3' }),
- projectBinding,
- ),
- ).toBe('https://github.company.com/owner/reponame');
- });
-
- it('should work for github.com', () => {
- expect(
- buildGithubLink(mockAlmSettingsInstance({ url: 'http://api.github.com/' }), projectBinding),
- ).toBe('https://github.com/owner/reponame');
- });
-
- it('should return null if there is no url defined', () => {
- expect(buildGithubLink(mockAlmSettingsInstance({ url: undefined }), projectBinding)).toBeNull();
- });
-});
-
-describe('buildBitbucketCloudLink', () => {
- const projectBinding = mockProjectBitbucketCloudBindingResponse({ repository: 'reponame' });
-
- it('should work', () => {
- expect(
- buildBitbucketCloudLink(
- mockAlmSettingsInstance({ url: 'http://bitbucket.org/workspace/' }),
- projectBinding,
- ),
- ).toBe('http://bitbucket.org/workspace/reponame');
- });
-
- it('should return null if there is no url defined', () => {
- expect(
- buildBitbucketCloudLink(mockAlmSettingsInstance({ url: undefined }), projectBinding),
- ).toBeNull();
- expect(
- buildBitbucketCloudLink(
- mockAlmSettingsInstance(),
- mockProjectBitbucketCloudBindingResponse({ repository: undefined }),
- ),
- ).toBeNull();
- });
-});
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/AzurePipelinesTutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/AzurePipelinesTutorial.tsx
deleted file mode 100644
index 612a436a74c..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/AzurePipelinesTutorial.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { BasicSeparator, Title, TutorialStep, TutorialStepList } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { AlmKeys } from '../../../types/alm-settings';
-import { Component } from '../../../types/types';
-import { LoggedInUser } from '../../../types/users';
-import AllSet from '../components/AllSet';
-import { TutorialConfig } from '../types';
-import BranchAnalysisStepContent from './BranchAnalysisStepContent';
-import ExtensionInstallationStepContent from './ExtensionInstallationStepContent';
-import ServiceEndpointStepContent from './ServiceEndpointStepContent';
-
-export interface AzurePipelinesTutorialProps {
- alm?: AlmKeys;
- baseUrl: string;
- component: Component;
- currentUser: LoggedInUser;
- willRefreshAutomatically?: boolean;
-}
-
-export enum Steps {
- ExtensionInstallation = 'ExtensionInstallation',
- ServiceEndpoint = 'ServiceEndpoint',
- BranchAnalysis = 'BranchAnalysis',
-}
-
-export default function AzurePipelinesTutorial(props: AzurePipelinesTutorialProps) {
- const { alm, baseUrl, component, currentUser, willRefreshAutomatically } = props;
-
- const [config, setConfig] = React.useState<TutorialConfig>({});
- const [done, setDone] = React.useState<boolean>(false);
-
- React.useEffect(() => {
- setDone(Boolean(config.buildTool));
- }, [config.buildTool]);
-
- return (
- <>
- <Title>{translate('onboarding.tutorial.with.azure_pipelines.title')}</Title>
-
- <TutorialStepList className="sw-mb-10">
- <TutorialStep
- title={translate(
- `onboarding.tutorial.with.azure_pipelines.${Steps.ExtensionInstallation}.title`,
- )}
- >
- <ExtensionInstallationStepContent />
- </TutorialStep>
-
- <TutorialStep
- title={translate(
- `onboarding.tutorial.with.azure_pipelines.${Steps.ServiceEndpoint}.title`,
- )}
- >
- <ServiceEndpointStepContent
- baseUrl={baseUrl}
- component={component}
- currentUser={currentUser}
- />
- </TutorialStep>
-
- <TutorialStep
- title={translate(
- `onboarding.tutorial.with.azure_pipelines.${Steps.BranchAnalysis}.title`,
- )}
- >
- <BranchAnalysisStepContent config={config} setConfig={setConfig} component={component} />
- </TutorialStep>
-
- {done && (
- <>
- <BasicSeparator className="sw-my-10" />
- <AllSet
- alm={alm ?? AlmKeys.Azure}
- willRefreshAutomatically={willRefreshAutomatically}
- />
- </>
- )}
- </TutorialStepList>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/BranchAnalysisStepContent.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/BranchAnalysisStepContent.tsx
deleted file mode 100644
index 793fabb44e3..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/BranchAnalysisStepContent.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import withLanguagesContext from '../../../app/components/languages/withLanguagesContext';
-import { Languages } from '../../../types/languages';
-import { Component } from '../../../types/types';
-import BuildConfigSelection from '../components/BuildConfigSelection';
-import { TutorialConfig, TutorialModes } from '../types';
-import AnalysisCommand from './commands/AnalysisCommand';
-
-export interface BranchesAnalysisStepProps {
- component: Component;
- config: TutorialConfig;
- languages: Languages;
- setConfig: (config: TutorialConfig) => void;
-}
-
-export function BranchAnalysisStepContent(props: BranchesAnalysisStepProps) {
- const { config, setConfig, component, languages } = props;
-
- return (
- <>
- <BuildConfigSelection
- ci={TutorialModes.AzurePipelines}
- config={config}
- supportCFamily={Boolean(languages['c'])}
- onSetConfig={setConfig}
- />
-
- <AnalysisCommand config={config} projectKey={component.key} projectName={component.name} />
- </>
- );
-}
-
-export default withLanguagesContext(BranchAnalysisStepContent);
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ExtensionInstallationStepContent.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ExtensionInstallationStepContent.tsx
deleted file mode 100644
index 414a24bc59e..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ExtensionInstallationStepContent.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { Link } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-
-export default function ExtensionInstallationStepContent() {
- return (
- <span>
- <FormattedMessage
- defaultMessage={translate(
- 'onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.sentence',
- )}
- id="onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.sentence"
- values={{
- link: (
- <Link to="https://marketplace.visualstudio.com/items?itemName=SonarSource.sonarqube">
- {translate(
- 'onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.sentence.link',
- )}
- </Link>
- ),
- button: (
- <strong>
- {translate(
- 'onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.sentence.button',
- )}
- </strong>
- ),
- }}
- />
- </span>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/JavaToolInstallation.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/JavaToolInstallation.tsx
deleted file mode 100644
index 9c0094faa01..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/JavaToolInstallation.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { ListItem, NumberedListItem, UnorderedList } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-
-function renderSentenceWithFieldAndValue(props: {
- field: React.ReactNode;
- value: React.ReactNode;
-}) {
- const { field, value } = props;
- return (
- <FormattedMessage
- id="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java_installer.sentence"
- defaultMessage={translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java_installer.sentence',
- )}
- values={{
- field: <b className="sw-font-semibold">{field}</b>,
- value: <b className="sw-font-semibold">{value}</b>,
- }}
- />
- );
-}
-
-export default function JavaToolInstallation() {
- return (
- <NumberedListItem>
- {translate('onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java_installer.title')}
- <UnorderedList ticks className="sw-ml-12">
- <ListItem>
- {renderSentenceWithFieldAndValue({
- field: translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java_installer.java_version',
- ),
- value: '17',
- })}
- {' ' /* explicit space between the two strings */}
- {translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java_installer.or_higher',
- )}
- </ListItem>
- <ListItem>
- {renderSentenceWithFieldAndValue({
- field: translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java_installer.java_architecture',
- ),
- value: 'x64',
- })}
- </ListItem>
- <ListItem>
- {renderSentenceWithFieldAndValue({
- field: translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java_installer.java_source',
- ),
- value: translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java_installer.pre-installed',
- ),
- })}
- </ListItem>
- </UnorderedList>
- </NumberedListItem>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ServiceEndpointStepContent.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ServiceEndpointStepContent.tsx
deleted file mode 100644
index 98fd3ac400d..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ServiceEndpointStepContent.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import {
- ButtonSecondary,
- ClipboardIconButton,
- NumberedList,
- NumberedListItem,
-} from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { TokenType } from '../../../types/token';
-import { Component } from '../../../types/types';
-import { LoggedInUser } from '../../../types/users';
-import EditTokenModal from '../components/EditTokenModal';
-import { InlineSnippet } from '../components/InlineSnippet';
-import SentenceWithHighlights from '../components/SentenceWithHighlights';
-
-export interface ServiceEndpointStepProps {
- baseUrl: string;
- component: Component;
- currentUser: LoggedInUser;
-}
-
-export default function ServiceEndpointStepContent(props: ServiceEndpointStepProps) {
- const { baseUrl, component, currentUser } = props;
-
- const [isModalVisible, toggleModal] = React.useState(false);
-
- return (
- <>
- <NumberedList>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step1"
- highlightKeys={['menu']}
- />
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step2"
- highlightKeys={['type']}
- />
- </NumberedListItem>
- <NumberedListItem className="sw-flex sw-items-center">
- <FormattedMessage
- defaultMessage={translate(
- 'onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step3.sentence',
- )}
- id="onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step3.sentence"
- values={{
- url: (
- <span className="sw-ml-1">
- <InlineSnippet snippet={baseUrl} />
- </span>
- ),
- button: <ClipboardIconButton className="sw-ml-2" copyValue={baseUrl} />,
- }}
- />
- </NumberedListItem>
- <NumberedListItem>
- <span>
- {translate('onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step4.sentence')}:
- </span>
- <ButtonSecondary className="sw-ml-2" onClick={() => toggleModal(true)}>
- {translate('onboarding.token.generate.long')}
- </ButtonSecondary>
- </NumberedListItem>
- <NumberedListItem>
- {translate('onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step5.sentence')}
- </NumberedListItem>
- <NumberedListItem>
- {translate('onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.step6.sentence')}
- </NumberedListItem>
- </NumberedList>
-
- {isModalVisible && (
- <EditTokenModal
- component={component}
- currentUser={currentUser}
- onClose={() => toggleModal(false)}
- preferredTokenType={TokenType.Global}
- />
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/AzurePipelinesTutorial-it.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/AzurePipelinesTutorial-it.tsx
deleted file mode 100644
index acf7367d681..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/AzurePipelinesTutorial-it.tsx
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen, within } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup';
-import UserTokensMock from '../../../../api/mocks/UserTokensMock';
-import { mockComponent } from '../../../../helpers/mocks/component';
-import { mockLanguage, mockLoggedInUser } from '../../../../helpers/testMocks';
-import { RenderContext, renderApp } from '../../../../helpers/testReactTestingUtils';
-import { Permissions } from '../../../../types/permissions';
-import { TokenType } from '../../../../types/token';
-import { getCopyToClipboardValue, getTutorialBuildButtons } from '../../test-utils';
-import { OSs } from '../../types';
-import AzurePipelinesTutorial, { AzurePipelinesTutorialProps } from '../AzurePipelinesTutorial';
-
-jest.mock('../../../../api/settings', () => ({
- getAllValues: jest.fn().mockResolvedValue([]),
-}));
-
-let tokenMock: UserTokensMock;
-
-beforeAll(() => {
- tokenMock = new UserTokensMock();
-});
-
-afterEach(() => {
- tokenMock.reset();
-});
-
-it('should render correctly and allow token generation', async () => {
- renderAzurePipelinesTutorial();
- const user = userEvent.setup();
-
- expect(
- screen.getByRole('heading', { name: 'onboarding.tutorial.with.azure_pipelines.title' }),
- ).toBeInTheDocument();
-
- // Default step.
- assertDefaultStepIsCorrectlyRendered();
-
- // Token step.
- assertServiceEndpointStepIsCorrectlyRendered();
-
- // Generate a token.
- await clickButton(user, 'onboarding.token.generate.long');
- const modal = screen.getByRole('dialog');
- await clickButton(user, 'onboarding.token.generate', modal);
- const lastToken = tokenMock.getLastToken();
-
- expect(lastToken).toBeDefined();
-
- expect(lastToken!.type).toBe(TokenType.Global);
- expect(
- within(modal).getByText(`users.tokens.new_token_created.${lastToken!.token}`),
- ).toBeInTheDocument();
- await clickButton(user, 'continue', modal);
-
- // Analysis step: .NET
- await user.click(getTutorialBuildButtons().dotnetBuildButton.get());
- assertDotNetStepIsCorrectlyRendered();
-
- // Analysis step: Maven
- await user.click(getTutorialBuildButtons().mavenBuildButton.get());
- assertMavenStepIsCorrectlyRendered();
-
- // Analysis step: Gradle
- await user.click(getTutorialBuildButtons().gradleBuildButton.get());
- assertGradleStepIsCorrectlyRendered();
-
- // Analysis step: C Family
- await user.click(getTutorialBuildButtons().cppBuildButton.get());
- // Default: Automatic configuration
- // expect linux/win/macos buttons not to be present
- expect(getTutorialBuildButtons().linuxButton.query()).not.toBeInTheDocument();
- expect(getTutorialBuildButtons().windowsButton.query()).not.toBeInTheDocument();
- expect(getTutorialBuildButtons().macosButton.query()).not.toBeInTheDocument();
- assertAutomaticCppStepIsCorrectlyRendered();
-
- // Switch to manual configuration
- await user.click(getTutorialBuildButtons().autoConfigManual.get());
- await user.click(getTutorialBuildButtons().linuxButton.get());
- assertManualCppStepIsCorrectlyRendered(OSs.Linux);
- await user.click(getTutorialBuildButtons().arm64Button.get());
- assertManualCppStepIsCorrectlyRendered(OSs.Linux, 'arm64');
- await user.click(getTutorialBuildButtons().windowsButton.get());
- assertObjCStepIsCorrectlyRendered(OSs.Windows);
- await user.click(getTutorialBuildButtons().macosButton.get());
- assertObjCStepIsCorrectlyRendered(OSs.MacOS);
-
- // Analysis step: C Family
- await user.click(getTutorialBuildButtons().objCBuildButton.get());
- await user.click(getTutorialBuildButtons().linuxButton.get());
- await user.click(getTutorialBuildButtons().x86_64Button.get());
- assertObjCStepIsCorrectlyRendered(OSs.Linux);
- await user.click(getTutorialBuildButtons().arm64Button.get());
- assertObjCStepIsCorrectlyRendered(OSs.Linux, 'arm64');
- await user.click(getTutorialBuildButtons().windowsButton.get());
- assertObjCStepIsCorrectlyRendered(OSs.Windows);
- await user.click(getTutorialBuildButtons().macosButton.get());
- assertObjCStepIsCorrectlyRendered(OSs.MacOS);
-
- // Analysis step: Dart
- await user.click(getTutorialBuildButtons().dartBuildButton.get());
- assertOtherStepIsCorrectlyRendered();
-
- // Analysis step: Other
- await user.click(getTutorialBuildButtons().otherBuildButton.get());
- assertOtherStepIsCorrectlyRendered();
-
- // Finish tutorial
- assertFinishStepIsCorrectlyRendered();
-});
-
-it('should not offer CFamily analysis if the language is not available', () => {
- renderAzurePipelinesTutorial(undefined, { languages: {} });
-
- expect(getTutorialBuildButtons().dotnetBuildButton.get()).toBeInTheDocument();
- expect(getTutorialBuildButtons().cppBuildButton.query()).not.toBeInTheDocument();
-});
-
-function assertDefaultStepIsCorrectlyRendered() {
- expect(
- screen.getByRole('heading', {
- name: 'onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title',
- }),
- ).toBeInTheDocument();
-}
-
-function assertServiceEndpointStepIsCorrectlyRendered() {
- expect(
- screen.getByRole('heading', {
- name: 'onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.title',
- }),
- ).toBeInTheDocument();
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy to clipboard', inlineSnippet: true })).toBe(
- 'https://sonarqube.example.com/',
- );
- expect(
- screen.getByRole('button', { name: 'onboarding.token.generate.long' }),
- ).toBeInTheDocument();
-}
-
-function assertDotNetStepIsCorrectlyRendered() {
- expect(
- screen.getByRole('heading', {
- name: 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.title',
- }),
- ).toBeInTheDocument();
-
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy to clipboard', inlineSnippet: true })).toBe(
- 'foo',
- );
-}
-
-function assertMavenStepIsCorrectlyRendered() {
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'maven, copy additional properties',
- );
-}
-
-function assertGradleStepIsCorrectlyRendered() {
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'gradle, copy additional properties',
- );
-}
-
-function assertObjCStepIsCorrectlyRendered(os: string, arch: string = 'x86_64') {
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- `objectivec ${os} ${arch}, copy shell script`,
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy to clipboard', inlineSnippet: true })).toBe(
- 'foo',
- );
- expect(
- getCopyToClipboardValue({ i: 2, name: 'Copy to clipboard', inlineSnippet: true }),
- ).toMatchSnapshot(`objectivec ${os} ${arch}, copy additional properties`);
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- `objectivec ${os} ${arch}, copy build-wrapper command`,
- );
-}
-
-function assertAutomaticCppStepIsCorrectlyRendered() {
- assertOtherStepIsCorrectlyRendered();
-}
-
-function assertManualCppStepIsCorrectlyRendered(os: string, arch: string = 'x86_64') {
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- `manual-cpp ${os} ${arch}, copy shell script`,
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy to clipboard', inlineSnippet: true })).toBe(
- 'foo',
- );
- expect(
- getCopyToClipboardValue({ i: 2, name: 'Copy to clipboard', inlineSnippet: true }),
- ).toMatchSnapshot(`manual-cpp ${os} ${arch}, copy additional properties`);
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- `manual-cpp ${os} ${arch}, copy build-wrapper command`,
- );
-}
-
-function assertOtherStepIsCorrectlyRendered() {
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy to clipboard', inlineSnippet: true })).toBe(
- 'foo',
- );
-}
-
-function assertFinishStepIsCorrectlyRendered() {
- expect(
- screen.getByRole('heading', {
- name: 'onboarding.tutorial.ci_outro.done',
- }),
- ).toBeInTheDocument();
-}
-
-function renderAzurePipelinesTutorial(
- props: Partial<AzurePipelinesTutorialProps> = {},
- { languages = { c: mockLanguage({ key: 'c' }) } }: RenderContext = {},
-) {
- return renderApp(
- '/',
- <AzurePipelinesTutorial
- baseUrl="https://sonarqube.example.com/"
- component={mockComponent({ key: 'foo' })}
- currentUser={mockLoggedInUser({ permissions: { global: [Permissions.Scan] } })}
- willRefreshAutomatically
- {...props}
- />,
- { languages },
- );
-}
-
-async function clickButton(user: UserEvent, name: string, context?: HTMLElement) {
- if (context) {
- await user.click(within(context).getByRole('button', { name }));
- } else {
- await user.click(screen.getByRole('button', { name }));
- }
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/AzurePipelinesTutorial-it.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/AzurePipelinesTutorial-it.tsx.snap
deleted file mode 100644
index e68cb7998ee..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/__tests__/__snapshots__/AzurePipelinesTutorial-it.tsx.snap
+++ /dev/null
@@ -1,91 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly and allow token generation: gradle, copy additional properties 1`] = `
-"# Additional properties that will be passed to the scanner,
-# Put one key=value per line, example:
-# sonar.exclusions=**/*.bin
-sonar.projectKey=foo
-sonar.projectName=MyProject
-"
-`;
-
-exports[`should render correctly and allow token generation: manual-cpp linux arm64, copy additional properties 1`] = `"sonar.cfamily.compile-commands=bw-output/compile_commands.json"`;
-
-exports[`should render correctly and allow token generation: manual-cpp linux arm64, copy build-wrapper command 1`] = `"./build-wrapper-linux-aarch64/build-wrapper-linux-aarch64 --out-dir bw-output <your build command here>"`;
-
-exports[`should render correctly and allow token generation: manual-cpp linux arm64, copy shell script 1`] = `
-"curl 'http://localhost/static/cpp/build-wrapper-linux-aarch64.zip' --output build-wrapper.zip
-unzip build-wrapper.zip"
-`;
-
-exports[`should render correctly and allow token generation: manual-cpp linux x86_64, copy additional properties 1`] = `"sonar.cfamily.compile-commands=bw-output/compile_commands.json"`;
-
-exports[`should render correctly and allow token generation: manual-cpp linux x86_64, copy build-wrapper command 1`] = `"./build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw-output <your build command here>"`;
-
-exports[`should render correctly and allow token generation: manual-cpp linux x86_64, copy shell script 1`] = `
-"curl 'http://localhost/static/cpp/build-wrapper-linux-x86.zip' --output build-wrapper.zip
-unzip build-wrapper.zip"
-`;
-
-exports[`should render correctly and allow token generation: maven, copy additional properties 1`] = `
-"# Additional properties that will be passed to the scanner,
-# Put one key=value per line, example:
-# sonar.exclusions=**/*.bin
-sonar.projectKey=foo
-sonar.projectName=MyProject
-"
-`;
-
-exports[`should render correctly and allow token generation: objectivec linux arm64, copy additional properties 1`] = `"sonar.cfamily.compile-commands=bw-output/compile_commands.json"`;
-
-exports[`should render correctly and allow token generation: objectivec linux arm64, copy build-wrapper command 1`] = `"./build-wrapper-linux-aarch64/build-wrapper-linux-aarch64 --out-dir bw-output <your build command here>"`;
-
-exports[`should render correctly and allow token generation: objectivec linux arm64, copy shell script 1`] = `
-"curl 'http://localhost/static/cpp/build-wrapper-linux-aarch64.zip' --output build-wrapper.zip
-unzip build-wrapper.zip"
-`;
-
-exports[`should render correctly and allow token generation: objectivec linux x86_64, copy additional properties 1`] = `"sonar.cfamily.compile-commands=bw-output/compile_commands.json"`;
-
-exports[`should render correctly and allow token generation: objectivec linux x86_64, copy build-wrapper command 1`] = `"./build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw-output <your build command here>"`;
-
-exports[`should render correctly and allow token generation: objectivec linux x86_64, copy shell script 1`] = `
-"curl 'http://localhost/static/cpp/build-wrapper-linux-x86.zip' --output build-wrapper.zip
-unzip build-wrapper.zip"
-`;
-
-exports[`should render correctly and allow token generation: objectivec mac x86_64, copy additional properties 1`] = `"sonar.cfamily.compile-commands=bw-output/compile_commands.json"`;
-
-exports[`should render correctly and allow token generation: objectivec mac x86_64, copy additional properties 2`] = `"sonar.cfamily.compile-commands=bw-output/compile_commands.json"`;
-
-exports[`should render correctly and allow token generation: objectivec mac x86_64, copy build-wrapper command 1`] = `"./build-wrapper-macosx-x86/build-wrapper-macosx-x86 --out-dir bw-output <your build command here>"`;
-
-exports[`should render correctly and allow token generation: objectivec mac x86_64, copy build-wrapper command 2`] = `"./build-wrapper-macosx-x86/build-wrapper-macosx-x86 --out-dir bw-output <your build command here>"`;
-
-exports[`should render correctly and allow token generation: objectivec mac x86_64, copy shell script 1`] = `
-"curl 'http://localhost/static/cpp/build-wrapper-macosx-x86.zip' --output build-wrapper.zip
-unzip build-wrapper.zip"
-`;
-
-exports[`should render correctly and allow token generation: objectivec mac x86_64, copy shell script 2`] = `
-"curl 'http://localhost/static/cpp/build-wrapper-macosx-x86.zip' --output build-wrapper.zip
-unzip build-wrapper.zip"
-`;
-
-exports[`should render correctly and allow token generation: objectivec win x86_64, copy additional properties 1`] = `"sonar.cfamily.compile-commands=bw-output/compile_commands.json"`;
-
-exports[`should render correctly and allow token generation: objectivec win x86_64, copy additional properties 2`] = `"sonar.cfamily.compile-commands=bw-output/compile_commands.json"`;
-
-exports[`should render correctly and allow token generation: objectivec win x86_64, copy build-wrapper command 1`] = `"build-wrapper-win-x86/build-wrapper-win-x86-64.exe --out-dir bw-output <your build command here>"`;
-
-exports[`should render correctly and allow token generation: objectivec win x86_64, copy build-wrapper command 2`] = `"build-wrapper-win-x86/build-wrapper-win-x86-64.exe --out-dir bw-output <your build command here>"`;
-
-exports[`should render correctly and allow token generation: objectivec win x86_64, copy shell script 1`] = `
-"Invoke-WebRequest -Uri 'http://localhost/static/cpp/build-wrapper-win-x86.zip' -OutFile 'build-wrapper.zip'
-Expand-Archive -Path 'build-wrapper.zip' -DestinationPath '.'"
-`;
-
-exports[`should render correctly and allow token generation: objectivec win x86_64, copy shell script 2`] = `
-"Invoke-WebRequest -Uri 'http://localhost/static/cpp/build-wrapper-win-x86.zip' -OutFile 'build-wrapper.zip'
-Expand-Archive -Path 'build-wrapper.zip' -DestinationPath '.'"
-`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/AlertClassicEditor.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/AlertClassicEditor.tsx
deleted file mode 100644
index ef02074c701..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/AlertClassicEditor.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { FlagMessage, Link } from '~design-system';
-import { DocLink } from '../../../../helpers/doc-links';
-import { useDocUrl } from '../../../../helpers/docs';
-import { translate } from '../../../../helpers/l10n';
-
-export default function AlertClassicEditor() {
- const docUrl = useDocUrl(DocLink.AlmAzureIntegration);
-
- return (
- <FlagMessage variant="info" className="sw-mt-4">
- <span>
- <FormattedMessage
- id="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.info"
- defaultMessage={translate('onboarding.tutorial.with.azure_pipelines.BranchAnalysis.info')}
- values={{
- doc_link: (
- <Link to={docUrl}>
- {translate('onboarding.tutorial.with.azure_pipelines.BranchAnalysis.info.doc_link')}
- </Link>
- ),
- }}
- />
- </span>
- </FlagMessage>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/AnalysisCommand.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/AnalysisCommand.tsx
deleted file mode 100644
index 863c3f6b0cb..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/AnalysisCommand.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { BuildTools, TutorialConfig } from '../../types';
-import ClangGCC from './ClangGCC';
-import DotNet from './DotNet';
-import JavaGradle from './JavaGradle';
-import JavaMaven from './JavaMaven';
-import Other from './Other';
-
-export interface AnalysisCommandProps {
- config: TutorialConfig;
- projectKey: string;
- projectName: string;
-}
-
-export default function AnalysisCommand(props: AnalysisCommandProps) {
- const { config, projectKey, projectName } = props;
- const { buildTool } = config;
-
- if (!buildTool) {
- return null;
- }
-
- switch (buildTool) {
- case BuildTools.Maven:
- return <JavaMaven projectKey={projectKey} projectName={projectName} />;
-
- case BuildTools.Gradle:
- return <JavaGradle projectKey={projectKey} projectName={projectName} />;
-
- case BuildTools.DotNet:
- return <DotNet projectKey={projectKey} />;
-
- case BuildTools.Cpp:
- case BuildTools.ObjectiveC:
- return <ClangGCC config={config} projectKey={projectKey} />;
-
- case BuildTools.Dart:
- case BuildTools.Other:
- return <Other projectKey={projectKey} />;
-
- default:
- return null;
- }
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/ClangGCC.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/ClangGCC.tsx
deleted file mode 100644
index d5de1ada394..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/ClangGCC.tsx
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import {
- CodeSnippet,
- ListItem,
- NumberedList,
- NumberedListItem,
- UnorderedList,
-} from '~design-system';
-import { translate } from '../../../../helpers/l10n';
-import { getHostUrl } from '../../../../helpers/urls';
-import { CompilationInfo } from '../../components/CompilationInfo';
-import GithubCFamilyExampleRepositories from '../../components/GithubCFamilyExampleRepositories';
-import RenderOptions from '../../components/RenderOptions';
-import SentenceWithHighlights from '../../components/SentenceWithHighlights';
-import { Arch, AutoConfig, BuildTools, OSs, TutorialConfig, TutorialModes } from '../../types';
-import { getBuildWrapperExecutableLinux, getBuildWrapperFolderLinux } from '../../utils';
-import AlertClassicEditor from './AlertClassicEditor';
-import Other from './Other';
-import PrepareAnalysisCommand, { PrepareType } from './PrepareAnalysisCommand';
-import PublishSteps from './PublishSteps';
-
-export interface ClangGCCProps {
- config: TutorialConfig;
- projectKey: string;
-}
-
-type OsConstant = {
- [key in OSs]: {
- highlightScriptKey: string;
- script: string;
- scriptBuild: string;
- };
-};
-
-export default function ClangGCC(props: ClangGCCProps) {
- const { config, projectKey } = props;
- const [os, setOs] = React.useState<OSs>(OSs.Linux);
- const [arch, setArch] = React.useState<Arch>(Arch.X86_64);
- const host = getHostUrl();
-
- const codeSnippetDownload: OsConstant = {
- [OSs.Linux]: {
- script: `curl '${host}/static/cpp/${getBuildWrapperFolderLinux(arch)}.zip' --output build-wrapper.zip
-unzip build-wrapper.zip`,
- highlightScriptKey:
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.build_wrapper.ccpp.nix',
- scriptBuild: `./${getBuildWrapperFolderLinux(arch)}/${getBuildWrapperExecutableLinux(arch)} --out-dir bw-output <your build command here>`,
- },
- [OSs.Windows]: {
- script: `Invoke-WebRequest -Uri '${host}/static/cpp/build-wrapper-win-x86.zip' -OutFile 'build-wrapper.zip'
-Expand-Archive -Path 'build-wrapper.zip' -DestinationPath '.'`,
- highlightScriptKey:
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.build_wrapper.ccpp.win',
- scriptBuild:
- 'build-wrapper-win-x86/build-wrapper-win-x86-64.exe --out-dir bw-output <your build command here>',
- },
- [OSs.MacOS]: {
- script: `curl '${host}/static/cpp/build-wrapper-macosx-x86.zip' --output build-wrapper.zip
-unzip build-wrapper.zip`,
- highlightScriptKey:
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.build_wrapper.ccpp.nix',
- scriptBuild:
- './build-wrapper-macosx-x86/build-wrapper-macosx-x86 --out-dir bw-output <your build command here>',
- },
- };
-
- if (config.buildTool === BuildTools.Cpp && config.autoConfig === AutoConfig.Automatic) {
- return <Other projectKey={projectKey} />;
- }
-
- return (
- <>
- <div className="sw-mt-4">{translate('onboarding.tutorial.with.azure_pipelines.os')}</div>
- <RenderOptions
- label={translate('onboarding.tutorial.with.azure_pipelines.os')}
- checked={os}
- onCheck={(value: OSs) => setOs(value)}
- optionLabelKey="onboarding.build.other.os"
- options={Object.values(OSs)}
- />
- {os === OSs.Linux && (
- <>
- <div className="sw-mt-4">
- {translate('onboarding.tutorial.with.azure_pipelines.architecture')}
- </div>
- <RenderOptions
- label={translate('onboarding.tutorial.with.azure_pipelines.architecture')}
- checked={arch}
- onCheck={(value: Arch) => setArch(value)}
- optionLabelKey="onboarding.build.other.architecture"
- options={[Arch.X86_64, Arch.Arm64]}
- />
- </>
- )}
-
- <GithubCFamilyExampleRepositories
- className="sw-mt-4 sw-w-abs-600"
- os={os}
- ci={TutorialModes.AzurePipelines}
- />
- <AlertClassicEditor />
- <NumberedList className="sw-mt-4">
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.build_wrapper.ccpp"
- highlightPrefixKeys="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare"
- highlightKeys={['pipeline']}
- />
- <UnorderedList ticks className="sw-ml-12 sw-mt-2">
- <ListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.build_wrapper.ccpp.script"
- highlightPrefixKeys={codeSnippetDownload[os].highlightScriptKey}
- highlightKeys={['task', 'inline']}
- />
- <CodeSnippet className="sw-p-6" snippet={codeSnippetDownload[os].script} />
- </ListItem>
- </UnorderedList>
- </NumberedListItem>
-
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.ccpp"
- highlightPrefixKeys="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare"
- highlightKeys={['task', 'before']}
- />
- <PrepareAnalysisCommand
- buildTool={BuildTools.Cpp}
- kind={PrepareType.StandAlone}
- projectKey={projectKey}
- />
- </NumberedListItem>
-
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.build.ccpp"
- highlightKeys={['task']}
- />
- <UnorderedList className="sw-mt-2">
- <ListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.build_script.ccpp"
- highlightKeys={['build_wrapper']}
- />
- <CodeSnippet
- className="sw-p-6"
- isOneLine
- snippet={codeSnippetDownload[os].scriptBuild}
- />
- <CompilationInfo />
- </ListItem>
- </UnorderedList>
- </NumberedListItem>
-
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.run.ccpp"
- highlightPrefixKeys="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.run"
- highlightKeys={['task', 'after']}
- />
- </NumberedListItem>
-
- <PublishSteps />
- </NumberedList>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/DotNet.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/DotNet.tsx
deleted file mode 100644
index 697f1aef98c..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/DotNet.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { NumberedList, NumberedListItem } from '~design-system';
-import SentenceWithHighlights from '../../components/SentenceWithHighlights';
-import { BuildTools } from '../../types';
-import AlertClassicEditor from './AlertClassicEditor';
-import PrepareAnalysisCommand, { PrepareType } from './PrepareAnalysisCommand';
-import PublishSteps from './PublishSteps';
-
-export interface DotNetProps {
- projectKey: string;
-}
-
-export default function DotNet(props: DotNetProps): JSX.Element {
- const { projectKey } = props;
- return (
- <>
- <AlertClassicEditor />
- <NumberedList className="sw-mt-4">
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare"
- highlightKeys={['pipeline', 'task', 'before']}
- />
- <PrepareAnalysisCommand
- buildTool={BuildTools.DotNet}
- kind={PrepareType.MSBuild}
- projectKey={projectKey}
- />
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.run"
- highlightKeys={['task', 'after']}
- />
- </NumberedListItem>
-
- <PublishSteps />
- </NumberedList>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/JavaGradle.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/JavaGradle.tsx
deleted file mode 100644
index 3672bebd092..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/JavaGradle.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ListItem, NumberedList, NumberedListItem, UnorderedList } from '~design-system';
-import { translate, translateWithParameters } from '../../../../helpers/l10n';
-import SentenceWithHighlights from '../../components/SentenceWithHighlights';
-import { BuildTools } from '../../types';
-import JavaToolInstallation from '../JavaToolInstallation';
-import AlertClassicEditor from './AlertClassicEditor';
-import PrepareAnalysisCommand, { PrepareType } from './PrepareAnalysisCommand';
-import PublishSteps from './PublishSteps';
-
-export interface JavaGradleProps {
- projectKey: string;
- projectName: string;
-}
-
-export default function JavaGradle(props: JavaGradleProps) {
- const { projectKey, projectName } = props;
-
- return (
- <>
- <AlertClassicEditor />
- <NumberedList className="sw-mt-4">
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare"
- highlightKeys={['pipeline', 'task', 'before']}
- />
- <PrepareAnalysisCommand
- buildTool={BuildTools.Gradle}
- kind={PrepareType.JavaMavenGradle}
- projectKey={projectKey}
- projectName={projectName}
- />
- </NumberedListItem>
-
- <JavaToolInstallation />
-
- <NumberedListItem>
- {translateWithParameters(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java',
- translate('onboarding.build', BuildTools.Gradle),
- )}
- <UnorderedList ticks className="sw-ml-12 sw-mb-4">
- <ListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java.settings"
- highlightKeys={['section', 'option']}
- />
- </ListItem>
- </UnorderedList>
- </NumberedListItem>
-
- <PublishSteps />
- </NumberedList>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/JavaMaven.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/JavaMaven.tsx
deleted file mode 100644
index b23a3d9dc62..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/JavaMaven.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ListItem, NumberedList, NumberedListItem, UnorderedList } from '~design-system';
-import { translate, translateWithParameters } from '../../../../helpers/l10n';
-import SentenceWithHighlights from '../../components/SentenceWithHighlights';
-import { BuildTools } from '../../types';
-import JavaToolInstallation from '../JavaToolInstallation';
-import AlertClassicEditor from './AlertClassicEditor';
-import PrepareAnalysisCommand, { PrepareType } from './PrepareAnalysisCommand';
-import PublishSteps from './PublishSteps';
-
-export interface JavaMavenProps {
- projectKey: string;
- projectName: string;
-}
-
-export default function JavaMaven(props: JavaMavenProps) {
- const { projectKey, projectName } = props;
- return (
- <>
- <AlertClassicEditor />
- <NumberedList className="sw-mt-4">
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare"
- highlightKeys={['pipeline', 'task', 'before']}
- />
- <PrepareAnalysisCommand
- buildTool={BuildTools.Gradle}
- kind={PrepareType.JavaMavenGradle}
- projectKey={projectKey}
- projectName={projectName}
- />
- </NumberedListItem>
-
- <JavaToolInstallation />
-
- <NumberedListItem>
- {translateWithParameters(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java',
- translate('onboarding.build', BuildTools.Maven),
- )}
- <UnorderedList ticks className="sw-ml-12 sw-mb-4">
- <ListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.java.settings"
- highlightKeys={['section', 'option']}
- />
- </ListItem>
- </UnorderedList>
- </NumberedListItem>
-
- <PublishSteps />
- </NumberedList>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/Other.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/Other.tsx
deleted file mode 100644
index 1ce9d0275c5..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/Other.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { NumberedList, NumberedListItem } from '~design-system';
-import SentenceWithHighlights from '../../components/SentenceWithHighlights';
-import { BuildTools } from '../../types';
-import AlertClassicEditor from './AlertClassicEditor';
-import PrepareAnalysisCommand, { PrepareType } from './PrepareAnalysisCommand';
-import PublishSteps from './PublishSteps';
-
-export interface OtherProps {
- projectKey: string;
-}
-
-export default function Other(props: OtherProps) {
- const { projectKey } = props;
- return (
- <>
- <AlertClassicEditor />
- <NumberedList className="sw-mt-4">
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare"
- highlightKeys={['pipeline', 'task', 'before']}
- />
- <PrepareAnalysisCommand
- buildTool={BuildTools.Other}
- kind={PrepareType.StandAlone}
- projectKey={projectKey}
- />
- </NumberedListItem>
-
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.run"
- highlightKeys={['task', 'after']}
- />
- </NumberedListItem>
-
- <PublishSteps />
- </NumberedList>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/PrepareAnalysisCommand.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/PrepareAnalysisCommand.tsx
deleted file mode 100644
index 195d747c382..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/PrepareAnalysisCommand.tsx
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { ClipboardIconButton, CodeSnippet, ListItem, UnorderedList } from '~design-system';
-import { translate } from '../../../../helpers/l10n';
-import { InlineSnippet } from '../../components/InlineSnippet';
-import SentenceWithHighlights from '../../components/SentenceWithHighlights';
-import { BuildTools } from '../../types';
-import { isCFamily } from '../../utils';
-
-export enum PrepareType {
- JavaMavenGradle,
- StandAlone,
- MSBuild,
-}
-
-export interface PrepareAnalysisCommandProps {
- buildTool: BuildTools;
- kind: PrepareType;
- projectKey: string;
- projectName?: string;
-}
-
-export default function PrepareAnalysisCommand(props: PrepareAnalysisCommandProps) {
- const { buildTool, kind, projectKey, projectName } = props;
-
- const ADDITIONAL_PROPERTY = 'sonar.cfamily.compile-commands=bw-output/compile_commands.json';
-
- const MAVEN_GRADLE_PROPS_SNIPPET = `# Additional properties that will be passed to the scanner,
-# Put one key=value per line, example:
-# sonar.exclusions=**/*.bin
-sonar.projectKey=${projectKey}
-sonar.projectName=${projectName}
-`;
-
- return (
- <UnorderedList ticks className="sw-ml-12 sw-my-2">
- <ListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.endpoint"
- highlightKeys={['endpoint']}
- />
- </ListItem>
- <ListItem>
- <FormattedMessage
- id="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis"
- defaultMessage={translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis',
- )}
- values={{
- section: (
- <b className="sw-font-semibold">
- {translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.section',
- )}
- </b>
- ),
- run_analysis_value: (
- <b className="sw-font-semibold">
- {translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare.run_analysis.values',
- buildTool,
- )}
- </b>
- ),
- }}
- />
- </ListItem>
-
- {kind === PrepareType.StandAlone && (
- <>
- <ListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.manual"
- highlightKeys={['mode']}
- />
- </ListItem>
-
- <ListItem>
- <span className="sw-flex sw-items-center">
- <FormattedMessage
- id="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.run.key.sentence"
- defaultMessage={translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.run.key.sentence',
- )}
- values={{
- project_key: (
- <b className="sw-font-semibold sw-mx-1">
- {translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.run.key.sentence.project_key',
- )}
- </b>
- ),
- key: (
- <span className="sw-ml-1">
- <InlineSnippet snippet={projectKey} />
- </span>
- ),
- button: <ClipboardIconButton className="sw-ml-2" copyValue={projectKey} />,
- }}
- />
- </span>
- </ListItem>
- {isCFamily(buildTool) && (
- <ListItem>
- <span className="sw-flex sw-items-center sw-flex-wrap">
- <FormattedMessage
- id="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare_additional.ccpp"
- defaultMessage={translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare_additional.ccpp',
- )}
- values={{
- advanced: (
- <b className="sw-font-semibold sw-mx-1">
- {translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare_additional.ccpp.advanced',
- )}
- </b>
- ),
- additional: (
- <b className="sw-font-semibold sw-mx-1">
- {translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.prepare_additional.ccpp.additional',
- )}
- </b>
- ),
- property: (
- <span className="sw-ml-1">
- <InlineSnippet snippet={ADDITIONAL_PROPERTY} />
- </span>
- ),
- button: (
- <ClipboardIconButton className="sw-ml-2" copyValue={ADDITIONAL_PROPERTY} />
- ),
- }}
- />
- </span>
- </ListItem>
- )}
- </>
- )}
-
- {kind === PrepareType.JavaMavenGradle && (
- <ListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.advanced_properties"
- highlightKeys={['section', 'properties']}
- />
- :
- <CodeSnippet
- className="sw-p-6"
- language="properties"
- snippet={MAVEN_GRADLE_PROPS_SNIPPET}
- />
- </ListItem>
- )}
- {kind === PrepareType.MSBuild && (
- <ListItem>
- <span className="sw-flex sw-items-center">
- <FormattedMessage
- id="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.run.key.sentence"
- defaultMessage={translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.run.key.sentence',
- )}
- values={{
- project_key: (
- <b className="sw-font-semibold sw-mx-1">
- {translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.run.key.sentence.project_key',
- )}
- </b>
- ),
- key: (
- <span className="sw-ml-1">
- <InlineSnippet snippet={projectKey} />
- </span>
- ),
- button: <ClipboardIconButton className="sw-ml-2" copyValue={projectKey} />,
- }}
- />
- </span>
- </ListItem>
- )}
- </UnorderedList>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/PublishSteps.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/PublishSteps.tsx
deleted file mode 100644
index 3c4651a026c..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/PublishSteps.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { BasicSeparator, FlagMessage, Link, NumberedListItem } from '~design-system';
-import withAvailableFeatures, {
- WithAvailableFeaturesProps,
-} from '../../../../app/components/available-features/withAvailableFeatures';
-import { DocLink } from '../../../../helpers/doc-links';
-import { useDocUrl } from '../../../../helpers/docs';
-import { translate } from '../../../../helpers/l10n';
-import { Feature } from '../../../../types/features';
-import SentenceWithHighlights from '../../components/SentenceWithHighlights';
-
-export interface PublishStepsProps extends WithAvailableFeaturesProps {}
-
-export function PublishSteps(props: PublishStepsProps) {
- const branchSupportEnabled = props.hasFeature(Feature.BranchSupport);
-
- const docUrl = useDocUrl(DocLink.AlmAzureIntegration);
-
- return (
- <>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.publish_qg"
- highlightKeys={['task']}
- />
- <FlagMessage variant="info" className="sw-mt-2">
- {translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.publish_qg.info.sentence1',
- )}
- </FlagMessage>
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey={
- branchSupportEnabled
- ? 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.continous_integration'
- : 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.continous_integration.no_branches'
- }
- highlightKeys={['tab', 'continuous_integration']}
- />
- </NumberedListItem>
- {branchSupportEnabled && (
- <>
- <BasicSeparator className="sw-my-4" />
- <div>
- <FormattedMessage
- id="onboarding.tutorial.with.azure_pipelines.BranchAnalysis.branch_protection"
- defaultMessage={translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.branch_protection',
- )}
- values={{
- link: (
- <Link to={docUrl}>
- {translate(
- 'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.branch_protection.link',
- )}
- </Link>
- ),
- }}
- />
- </div>
- </>
- )}
- </>
- );
-}
-
-export default withAvailableFeatures(PublishSteps);
diff --git a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/AnalysisCommand.tsx b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/AnalysisCommand.tsx
deleted file mode 100644
index f5d58781e3b..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/AnalysisCommand.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Dictionary } from 'lodash';
-import withAvailableFeatures, {
- WithAvailableFeaturesProps,
-} from '../../../app/components/available-features/withAvailableFeatures';
-import { Feature } from '../../../types/features';
-import { Component } from '../../../types/types';
-import { CompilationInfo } from '../components/CompilationInfo';
-import CreateYmlFile from '../components/CreateYmlFile';
-import { Arch, BuildTools, TutorialConfig } from '../types';
-import { isCFamily } from '../utils';
-import { PreambuleYaml } from './PreambuleYaml';
-import cFamilyExample from './commands/CFamily';
-import dartExample from './commands/Dart';
-import dotNetExample from './commands/DotNet';
-import gradleExample from './commands/Gradle';
-import mavenExample from './commands/Maven';
-import othersExample from './commands/Others';
-
-export interface AnalysisCommandProps extends WithAvailableFeaturesProps {
- arch: Arch;
- component: Component;
- config: TutorialConfig;
- mainBranchName: string;
-}
-
-export type BuildToolExampleBuilder = (data: {
- arch?: Arch;
- branchesEnabled?: boolean;
- config: TutorialConfig;
- mainBranchName?: string;
- projectKey?: string;
- projectName?: string;
-}) => string;
-
-const YamlTemplate: Dictionary<BuildToolExampleBuilder> = {
- [BuildTools.Gradle]: gradleExample,
- [BuildTools.Maven]: mavenExample,
- [BuildTools.DotNet]: dotNetExample,
- [BuildTools.Cpp]: cFamilyExample,
- [BuildTools.ObjectiveC]: cFamilyExample,
- [BuildTools.Dart]: dartExample,
- [BuildTools.Other]: othersExample,
-};
-
-export function AnalysisCommand(props: Readonly<AnalysisCommandProps>) {
- const { config, arch, mainBranchName, component } = props;
- const branchesEnabled = props.hasFeature(Feature.BranchSupport);
-
- if (!config.buildTool) {
- return null;
- }
-
- const yamlTemplate = YamlTemplate[config.buildTool]({
- arch,
- config,
- branchesEnabled,
- mainBranchName,
- projectKey: component.key,
- projectName: component.name,
- });
-
- return (
- <>
- <PreambuleYaml buildTool={config.buildTool} component={component} />
- <CreateYmlFile yamlFileName="bitbucket-pipelines.yml" yamlTemplate={yamlTemplate} />
- {isCFamily(config.buildTool) && <CompilationInfo />}
- </>
- );
-}
-
-export default withAvailableFeatures(AnalysisCommand);
diff --git a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/BitbucketPipelinesTutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/BitbucketPipelinesTutorial.tsx
deleted file mode 100644
index 57dff1f9aeb..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/BitbucketPipelinesTutorial.tsx
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { BasicSeparator, Title, TutorialStep, TutorialStepList } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings';
-import { Component } from '../../../types/types';
-import { LoggedInUser } from '../../../types/users';
-import AllSet from '../components/AllSet';
-import GithubCFamilyExampleRepositories from '../components/GithubCFamilyExampleRepositories';
-import RenderOptions from '../components/RenderOptions';
-import YamlFileStep from '../components/YamlFileStep';
-import { Arch, OSs, TutorialConfig, TutorialModes } from '../types';
-import { shouldShowArchSelector, shouldShowGithubCFamilyExampleRepositories } from '../utils';
-import AnalysisCommand from './AnalysisCommand';
-import RepositoryVariables from './RepositoryVariables';
-
-export enum Steps {
- REPOSITORY_VARIABLES = 1,
- YAML = 2,
- ALL_SET = 3,
-}
-
-export interface BitbucketPipelinesTutorialProps {
- almBinding?: AlmSettingsInstance;
- baseUrl: string;
- component: Component;
- currentUser: LoggedInUser;
- mainBranchName: string;
- willRefreshAutomatically?: boolean;
-}
-
-export default function BitbucketPipelinesTutorial(
- props: Readonly<BitbucketPipelinesTutorialProps>,
-) {
- const { almBinding, baseUrl, currentUser, component, willRefreshAutomatically, mainBranchName } =
- props;
-
- const [config, setConfig] = React.useState<TutorialConfig>({});
- const [done, setDone] = React.useState(false);
- const [arch, setArch] = React.useState<Arch>(Arch.X86_64);
-
- React.useEffect(() => {
- setDone(Boolean(config.buildTool));
- }, [config.buildTool]);
-
- return (
- <>
- <Title>{translate('onboarding.tutorial.with.bitbucket_ci.title')}</Title>
-
- <TutorialStepList className="sw-mb-8">
- <TutorialStep
- title={translate('onboarding.tutorial.with.bitbucket_pipelines.variables.title')}
- >
- <RepositoryVariables
- almBinding={almBinding}
- baseUrl={baseUrl}
- component={component}
- currentUser={currentUser}
- />
- </TutorialStep>
- <TutorialStep title={translate('onboarding.tutorial.with.bitbucket_pipelines.yaml.title')}>
- <YamlFileStep config={config} setConfig={setConfig} ci={TutorialModes.BitbucketPipelines}>
- {(config) => (
- <>
- {shouldShowGithubCFamilyExampleRepositories(config) && (
- <GithubCFamilyExampleRepositories
- className="sw-my-4 sw-w-abs-600"
- ci={TutorialModes.BitbucketPipelines}
- />
- )}
- {shouldShowArchSelector(OSs.Linux, config) && (
- <div className="sw-my-4">
- <RenderOptions
- label={translate('onboarding.build.other.architecture')}
- checked={arch}
- onCheck={(value: Arch) => setArch(value)}
- optionLabelKey="onboarding.build.other.architecture"
- options={[Arch.X86_64, Arch.Arm64]}
- titleLabelKey="onboarding.build.other.architecture"
- />
- </div>
- )}
- <AnalysisCommand
- config={config}
- arch={arch}
- component={component}
- mainBranchName={mainBranchName}
- />
- </>
- )}
- </YamlFileStep>
- </TutorialStep>
-
- {done && (
- <>
- <BasicSeparator className="sw-my-10" />
- <AllSet
- alm={AlmKeys.BitbucketCloud}
- willRefreshAutomatically={willRefreshAutomatically}
- />
- </>
- )}
- </TutorialStepList>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/PreambuleYaml.tsx b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/PreambuleYaml.tsx
deleted file mode 100644
index 45ca2f48852..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/PreambuleYaml.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Component } from '../../../types/types';
-import DefaultProjectKey from '../components/DefaultProjectKey';
-import GradleBuild from '../components/GradleBuild';
-import { BuildTools } from '../types';
-
-export interface PreambuleYamlProps {
- buildTool: BuildTools;
- component: Component;
-}
-
-export function PreambuleYaml(props: PreambuleYamlProps) {
- const { buildTool, component } = props;
- switch (buildTool) {
- case BuildTools.Gradle:
- return <GradleBuild component={component} />;
- case BuildTools.Cpp:
- case BuildTools.ObjectiveC:
- case BuildTools.Dart:
- case BuildTools.Other:
- return <DefaultProjectKey component={component} />;
- default:
- return null;
- }
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/RepositoryVariables.tsx b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/RepositoryVariables.tsx
deleted file mode 100644
index 75e3731f4cf..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/RepositoryVariables.tsx
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkStandalone } from '@sonarsource/echoes-react';
-import { FormattedMessage } from 'react-intl';
-import {
- BasicSeparator,
- ClipboardIconButton,
- NumberedList,
- NumberedListItem,
-} from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { useProjectBindingQuery } from '../../../queries/devops-integration';
-import { AlmSettingsInstance } from '../../../types/alm-settings';
-import { Component } from '../../../types/types';
-import { LoggedInUser } from '../../../types/users';
-import { InlineSnippet } from '../components/InlineSnippet';
-import SentenceWithHighlights from '../components/SentenceWithHighlights';
-import TokenStepGenerator from '../components/TokenStepGenerator';
-import { buildBitbucketCloudLink } from '../utils';
-
-export interface RepositoryVariablesProps {
- almBinding?: AlmSettingsInstance;
- baseUrl: string;
- component: Component;
- currentUser: LoggedInUser;
-}
-
-export default function RepositoryVariables(props: RepositoryVariablesProps) {
- const { almBinding, baseUrl, component, currentUser } = props;
- const { data: projectBinding } = useProjectBindingQuery(component.key);
- return (
- <>
- <FormattedMessage
- defaultMessage={translate('onboarding.tutorial.with.bitbucket_pipelines.variables.intro')}
- id="onboarding.tutorial.with.bitbucket_pipelines.variables.intro"
- values={{
- repository_variables:
- almBinding?.url && projectBinding?.repository ? (
- <LinkStandalone
- to={`${buildBitbucketCloudLink(
- almBinding,
- projectBinding,
- )}/admin/addon/admin/pipelines/repository-variables`}
- shouldOpenInNewTab
- >
- {translate('onboarding.tutorial.with.bitbucket_pipelines.variables.intro.link')}
- </LinkStandalone>
- ) : (
- <span className="sw-typo-semibold">
- {translate('onboarding.tutorial.with.bitbucket_pipelines.variables.intro.link')}
- </span>
- ),
- }}
- />
- <NumberedList>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.bitbucket_pipelines.variables.name"
- highlightKeys={['name']}
- />
- <InlineSnippet snippet="SONAR_TOKEN" className="sw-ml-1" />
- <ClipboardIconButton copyValue="SONAR_TOKEN" className="sw-ml-2 sw-align-sub" />
- </NumberedListItem>
- <NumberedListItem>
- <TokenStepGenerator component={component} currentUser={currentUser} />
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.bitbucket_pipelines.variables.secured"
- highlightKeys={['secured']}
- />
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.bitbucket_pipelines.variables.add"
- highlightKeys={['add']}
- />
- </NumberedListItem>
- </NumberedList>
-
- <BasicSeparator className="sw-my-6" />
-
- <NumberedList>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.bitbucket_pipelines.variables.name"
- highlightKeys={['name']}
- />
- <InlineSnippet snippet="SONAR_HOST_URL" className="sw-ml-1" />
- <ClipboardIconButton copyValue="SONAR_HOST_URL" className="sw-ml-2 sw-align-sub" />
- </NumberedListItem>
- <NumberedListItem>
- <FormattedMessage
- defaultMessage={translate('onboarding.tutorial.env_variables')}
- id="onboarding.tutorial.env_variables"
- values={{
- extra: <ClipboardIconButton copyValue={baseUrl} className="sw-ml-1 sw-align-sub" />,
- field: (
- <span className="sw-typo-semibold">
- {translate('onboarding.tutorial.env_variables.field')}
- </span>
- ),
- value: <InlineSnippet snippet={baseUrl} className="sw-ml-1" />,
- }}
- />
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.bitbucket_pipelines.variables.add"
- highlightKeys={['add']}
- />
- </NumberedListItem>
- </NumberedList>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/__tests__/BitbucketPipelinesTutorial-it.tsx b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/__tests__/BitbucketPipelinesTutorial-it.tsx
deleted file mode 100644
index 8989652009d..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/__tests__/BitbucketPipelinesTutorial-it.tsx
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import AlmSettingsServiceMock from '../../../../api/mocks/AlmSettingsServiceMock';
-import UserTokensMock from '../../../../api/mocks/UserTokensMock';
-import { mockAlmSettingsInstance } from '../../../../helpers/mocks/alm-settings';
-import { mockComponent } from '../../../../helpers/mocks/component';
-import { mockLanguage, mockLoggedInUser } from '../../../../helpers/testMocks';
-import { RenderContext, renderApp } from '../../../../helpers/testReactTestingUtils';
-import { byRole } from '../../../../sonar-aligned/helpers/testSelector';
-import { AlmKeys } from '../../../../types/alm-settings';
-import { Feature } from '../../../../types/features';
-import {
- getCommonNodes,
- getCopyToClipboardHostURLValue,
- getCopyToClipboardValue,
- getTutorialActionButtons,
- getTutorialBuildButtons,
-} from '../../test-utils';
-import { GradleBuildDSL, TutorialModes } from '../../types';
-import BitbucketPipelinesTutorial, {
- BitbucketPipelinesTutorialProps,
-} from '../BitbucketPipelinesTutorial';
-
-jest.mock('../../../../api/settings', () => ({
- getAllValues: jest.fn().mockResolvedValue([]),
-}));
-
-const tokenMock = new UserTokensMock();
-const almMock = new AlmSettingsServiceMock();
-
-afterEach(() => {
- tokenMock.reset();
- almMock.reset();
-});
-
-const ui = {
- ...getCommonNodes(TutorialModes.BitbucketPipelines),
- ...getTutorialActionButtons(),
- ...getTutorialBuildButtons(),
-};
-
-it('should follow and complete all steps', async () => {
- const user = userEvent.setup();
- renderBitbucketPipelinesTutorial();
-
- expect(await ui.secretsStepTitle.find()).toBeInTheDocument();
-
- // Env variables step
- expect(
- getCopyToClipboardValue({ i: 0, name: 'Copy to clipboard', inlineSnippet: true }),
- ).toMatchSnapshot('sonar token key');
- expect(
- getCopyToClipboardValue({ i: 1, name: 'Copy to clipboard', inlineSnippet: true }),
- ).toMatchSnapshot('sonarqube host url key');
- expect(getCopyToClipboardHostURLValue({ i: 2, name: 'Copy to clipboard' })).toMatchSnapshot(
- 'sonarqube host url value',
- );
-
- // Create/update configuration file step
- // Maven
- await user.click(ui.mavenBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'Maven: bitbucket-pipelines.yml',
- );
-
- // Gradle
- await user.click(ui.gradleBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot('Groovy: build.gradle');
- await user.click(ui.gradleDSLButton(GradleBuildDSL.Kotlin).get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'Kotlin: build.gradle.kts',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'Gradle: bitbucket-pipelines.yml',
- );
-
- // .NET
- await user.click(ui.dotnetBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- '.NET: bitbucket-pipelines.yml',
- );
-
- // Cpp
- await user.click(ui.cppBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'C++ (automatic) and other: sonar-project.properties',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'C++ (automatic) and other: bitbucket-pipelines.yml',
- );
-
- // Cpp (manual)
- await user.click(ui.autoConfigManual.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'C++ (manual) and Objective-C: sonar-project.properties',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'C++ (manual) and Objective-C: bitbucket-pipelines.yml',
- );
- await user.click(ui.arm64Button.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'C++ (manual arm64) and Objective-C: sonar-project.properties',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'C++ (manual arm64) and Objective-C: bitbucket-pipelines.yml',
- );
-
- // Objective-C
- await user.click(ui.objCBuildButton.get());
- await user.click(ui.x86_64Button.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'C++ (manual) and Objective-C: bitbucket-pipelines.yml',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'C++ (manual) and Objective-C: sonar-project.properties',
- );
- await user.click(ui.arm64Button.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'C++ (manual arm64) and Objective-C: bitbucket-pipelines.yml',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'C++ (manual arm64) and Objective-C: sonar-project.properties',
- );
-
- // Dart
- await user.click(ui.dartBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'Dart: sonar-project.properties',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'Dart: bitbucket-pipelines.yml',
- );
-
- // Other
- await user.click(ui.otherBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'C++ (automatic) and other: sonar-project.properties',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'C++ (automatic) and other: .github/workflows/build.yml',
- );
-
- expect(ui.allSetSentence.get()).toBeInTheDocument();
-});
-
-it('should generate/delete a new token or use existing one', async () => {
- const user = userEvent.setup();
- renderBitbucketPipelinesTutorial();
-
- expect(await ui.secretsStepTitle.find()).toBeInTheDocument();
-
- // Generate token
- await user.click(ui.genTokenDialogButton.get());
- await user.click(ui.generateTokenButton.get());
- expect(getCopyToClipboardValue({ inlineSnippet: true })).toEqual('generatedtoken2');
-
- // Revoke current token and create new one
- await user.click(ui.deleteTokenButton.get());
- await user.type(ui.tokenNameInput.get(), 'newtoken');
-
- await user.click(ui.expiresInSelect.get());
- await user.click(byRole('option', { name: 'users.tokens.expiration.365' }).get());
-
- await user.click(ui.generateTokenButton.get());
- expect(ui.tokenValue.get()).toBeInTheDocument();
- await user.click(ui.continueButton.getAll()[0]);
- expect(ui.tokenValue.query()).not.toBeInTheDocument();
-});
-
-it('navigates between steps', async () => {
- const user = userEvent.setup();
- almMock.handleSetProjectBinding(AlmKeys.GitHub, {
- almSetting: 'my-project',
- project: 'my-project',
- repository: 'my-project',
- monorepo: true,
- });
- renderBitbucketPipelinesTutorial({
- almBinding: mockAlmSettingsInstance({
- alm: AlmKeys.BitbucketCloud,
- url: 'http://localhost/qube',
- }),
- });
-
- // If project is bound, link to repo is visible
- expect(await ui.linkToRepo.find()).toBeInTheDocument();
-
- await user.click(ui.mavenBuildButton.get());
- expect(ui.allSetSentence.get()).toBeInTheDocument();
-
- await user.click(ui.ymlFileStepTitle.get());
- expect(ui.mavenBuildButton.get()).toBeInTheDocument();
- await user.click(ui.secretsStepTitle.get());
- expect(ui.genTokenDialogButton.get()).toBeInTheDocument();
-});
-
-function renderBitbucketPipelinesTutorial(
- overrides: Partial<BitbucketPipelinesTutorialProps> = {},
- { languages = { c: mockLanguage({ key: 'c' }) } }: RenderContext = {},
-) {
- return renderApp(
- '/',
- <BitbucketPipelinesTutorial
- baseUrl="http://localhost:9000"
- mainBranchName="main"
- component={mockComponent()}
- currentUser={mockLoggedInUser()}
- {...overrides}
- />,
- { languages, featureList: [Feature.BranchSupport] },
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/__tests__/__snapshots__/BitbucketPipelinesTutorial-it.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/__tests__/__snapshots__/BitbucketPipelinesTutorial-it.tsx.snap
deleted file mode 100644
index 7438c3f7613..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/__tests__/__snapshots__/BitbucketPipelinesTutorial-it.tsx.snap
+++ /dev/null
@@ -1,353 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should follow and complete all steps: .NET: bitbucket-pipelines.yml 1`] = `
-"image: mcr.microsoft.com/dotnet/sdk:7.0
-
-definitions:
- steps:
- - step: &build-step
- name: SonarQube analysis
- caches:
- - dotnetcore
- - sonar
- script:
- - dotnet tool install --global dotnet-sonarscanner
- - export PATH="$PATH:/root/.dotnet/tools"
- - dotnet sonarscanner begin /k:"my-project" /d:"sonar.token=\${SONAR_TOKEN}" /d:"sonar.host.url=\${SONAR_HOST_URL}"
- - dotnet build
- - dotnet sonarscanner end /d:"sonar.token=\${SONAR_TOKEN}"
- caches:
- sonar: ~/.sonar
-
-pipelines:
- branches:
- '{main}':
- - step: *build-step
-
- pull-requests:
- '**':
- - step: *build-step"
-`;
-
-exports[`should follow and complete all steps: C++ (automatic) and other: .github/workflows/build.yml 1`] = `
-"definitions:
- steps:
- - step: &build-step
- name: SonarQube analysis
- script:
- - pipe: sonarsource/sonarqube-scan:3.0.2
- variables:
- SONAR_HOST_URL: \${SONAR_HOST_URL} # Get the value from the repository/workspace variable.
- SONAR_TOKEN: \${SONAR_TOKEN} # Get the value from the repository/workspace variable. You shouldn't set secret in clear text here.
- caches:
- sonar: ~/.sonar
-
-clone:
- depth: full
-
-pipelines:
- branches:
- '{main}':
- - step: *build-step
-
- pull-requests:
- '**':
- - step: *build-step
-"
-`;
-
-exports[`should follow and complete all steps: C++ (automatic) and other: bitbucket-pipelines.yml 1`] = `
-"definitions:
- steps:
- - step: &build-step
- name: SonarQube analysis
- script:
- - pipe: sonarsource/sonarqube-scan:3.0.2
- variables:
- SONAR_HOST_URL: \${SONAR_HOST_URL} # Get the value from the repository/workspace variable.
- SONAR_TOKEN: \${SONAR_TOKEN} # Get the value from the repository/workspace variable. You shouldn't set secret in clear text here.
- caches:
- sonar: ~/.sonar
-
-clone:
- depth: full
-
-pipelines:
- branches:
- '{main}':
- - step: *build-step
-
- pull-requests:
- '**':
- - step: *build-step
-"
-`;
-
-exports[`should follow and complete all steps: C++ (automatic) and other: sonar-project.properties 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`should follow and complete all steps: C++ (automatic) and other: sonar-project.properties 2`] = `"sonar.projectKey=my-project"`;
-
-exports[`should follow and complete all steps: C++ (manual arm64) and Objective-C: bitbucket-pipelines.yml 1`] = `
-"image: <image ready for your build toolchain>
-
-definitions:
- steps:
- - step: &build-step
- name: Build the project, and run the SonarQube analysis
- script:
- - export SONAR_SCANNER_VERSION=6.2.0.4584
- - mkdir $HOME/.sonar
- - curl -sSLo $HOME/.sonar/build-wrapper-linux-aarch64.zip \${SONAR_HOST_URL}/static/cpp/build-wrapper-linux-aarch64.zip
- - unzip -o $HOME/.sonar/build-wrapper-linux-aarch64.zip -d $HOME/.sonar/
- - curl -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-\${SONAR_SCANNER_VERSION}-linux-aarch64.zip
- - unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
- - export PATH="$PATH:$HOME/.sonar/sonar-scanner-\${SONAR_SCANNER_VERSION}-linux-aarch64/bin"
- - <any step required before running your build, like ./configure>
- - $HOME/.sonar/build-wrapper-linux-aarch64/build-wrapper-linux-aarch64 --out-dir bw-output <your clean build command>
- - sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json
- caches:
- sonar: ~/.sonar
-
-clone:
- depth: full
-
-pipelines:
- branches:
- '{main}':
- - step: *build-step
-
- pull-requests:
- '**':
- - step: *build-step"
-`;
-
-exports[`should follow and complete all steps: C++ (manual arm64) and Objective-C: bitbucket-pipelines.yml 2`] = `"sonar.projectKey=my-project"`;
-
-exports[`should follow and complete all steps: C++ (manual arm64) and Objective-C: sonar-project.properties 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`should follow and complete all steps: C++ (manual arm64) and Objective-C: sonar-project.properties 2`] = `
-"image: <image ready for your build toolchain>
-
-definitions:
- steps:
- - step: &build-step
- name: Build the project, and run the SonarQube analysis
- script:
- - export SONAR_SCANNER_VERSION=6.2.0.4584
- - mkdir $HOME/.sonar
- - curl -sSLo $HOME/.sonar/build-wrapper-linux-aarch64.zip \${SONAR_HOST_URL}/static/cpp/build-wrapper-linux-aarch64.zip
- - unzip -o $HOME/.sonar/build-wrapper-linux-aarch64.zip -d $HOME/.sonar/
- - curl -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-\${SONAR_SCANNER_VERSION}-linux-aarch64.zip
- - unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
- - export PATH="$PATH:$HOME/.sonar/sonar-scanner-\${SONAR_SCANNER_VERSION}-linux-aarch64/bin"
- - <any step required before running your build, like ./configure>
- - $HOME/.sonar/build-wrapper-linux-aarch64/build-wrapper-linux-aarch64 --out-dir bw-output <your clean build command>
- - sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json
- caches:
- sonar: ~/.sonar
-
-clone:
- depth: full
-
-pipelines:
- branches:
- '{main}':
- - step: *build-step
-
- pull-requests:
- '**':
- - step: *build-step"
-`;
-
-exports[`should follow and complete all steps: C++ (manual) and Objective-C: bitbucket-pipelines.yml 1`] = `
-"image: <image ready for your build toolchain>
-
-definitions:
- steps:
- - step: &build-step
- name: Build the project, and run the SonarQube analysis
- script:
- - export SONAR_SCANNER_VERSION=6.2.0.4584
- - mkdir $HOME/.sonar
- - curl -sSLo $HOME/.sonar/build-wrapper-linux-x86.zip \${SONAR_HOST_URL}/static/cpp/build-wrapper-linux-x86.zip
- - unzip -o $HOME/.sonar/build-wrapper-linux-x86.zip -d $HOME/.sonar/
- - curl -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-\${SONAR_SCANNER_VERSION}-linux-x64.zip
- - unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
- - export PATH="$PATH:$HOME/.sonar/sonar-scanner-\${SONAR_SCANNER_VERSION}-linux-x64/bin"
- - <any step required before running your build, like ./configure>
- - $HOME/.sonar/build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw-output <your clean build command>
- - sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json
- caches:
- sonar: ~/.sonar
-
-clone:
- depth: full
-
-pipelines:
- branches:
- '{main}':
- - step: *build-step
-
- pull-requests:
- '**':
- - step: *build-step"
-`;
-
-exports[`should follow and complete all steps: C++ (manual) and Objective-C: bitbucket-pipelines.yml 2`] = `"sonar.projectKey=my-project"`;
-
-exports[`should follow and complete all steps: C++ (manual) and Objective-C: sonar-project.properties 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`should follow and complete all steps: C++ (manual) and Objective-C: sonar-project.properties 2`] = `
-"image: <image ready for your build toolchain>
-
-definitions:
- steps:
- - step: &build-step
- name: Build the project, and run the SonarQube analysis
- script:
- - export SONAR_SCANNER_VERSION=6.2.0.4584
- - mkdir $HOME/.sonar
- - curl -sSLo $HOME/.sonar/build-wrapper-linux-x86.zip \${SONAR_HOST_URL}/static/cpp/build-wrapper-linux-x86.zip
- - unzip -o $HOME/.sonar/build-wrapper-linux-x86.zip -d $HOME/.sonar/
- - curl -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-\${SONAR_SCANNER_VERSION}-linux-x64.zip
- - unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
- - export PATH="$PATH:$HOME/.sonar/sonar-scanner-\${SONAR_SCANNER_VERSION}-linux-x64/bin"
- - <any step required before running your build, like ./configure>
- - $HOME/.sonar/build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw-output <your clean build command>
- - sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json
- caches:
- sonar: ~/.sonar
-
-clone:
- depth: full
-
-pipelines:
- branches:
- '{main}':
- - step: *build-step
-
- pull-requests:
- '**':
- - step: *build-step"
-`;
-
-exports[`should follow and complete all steps: Dart: bitbucket-pipelines.yml 1`] = `
-"image: ghcr.io/cirruslabs/flutter:stable
-
-definitions:
- steps:
- - step: &build-step
- name: Build the project, and run the SonarQube analysis
- script:
- - <commands to build your project>
- - export SONAR_SCANNER_VERSION=6.2.0.4584
- - mkdir $HOME/.sonar
- - curl -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-\${SONAR_SCANNER_VERSION}-linux-x64.zip
- - unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
- - export PATH="$PATH:$HOME/.sonar/sonar-scanner-\${SONAR_SCANNER_VERSION}-linux-x64/bin"
- - sonar-scanner
- caches:
- sonar: ~/.sonar
-
-clone:
- depth: full
-
-pipelines:
- branches:
- '{main}':
- - step: *build-step
-
- pull-requests:
- '**':
- - step: *build-step"
-`;
-
-exports[`should follow and complete all steps: Dart: sonar-project.properties 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`should follow and complete all steps: Gradle: bitbucket-pipelines.yml 1`] = `
-"image: eclipse-temurin:17
-
-definitions:
- steps:
- - step: &build-step
- name: SonarQube analysis
- caches:
- - gradle
- - sonar
- script:
- - bash ./gradlew sonar
- caches:
- sonar: ~/.sonar
-
-clone:
- depth: full
-
-pipelines:
- branches:
- '{main}':
- - step: *build-step
-
- pull-requests:
- '**':
- - step: *build-step"
-`;
-
-exports[`should follow and complete all steps: Groovy: build.gradle 1`] = `
-"plugins {
- id "org.sonarqube" version "6.0.1.5171"
-}
-
-sonar {
- properties {
- property "sonar.projectKey", "my-project"
- property "sonar.projectName", "MyProject"
- }
-}"
-`;
-
-exports[`should follow and complete all steps: Kotlin: build.gradle.kts 1`] = `
-"plugins {
- id("org.sonarqube") version "6.0.1.5171"
-}
-
-sonar {
- properties {
- property("sonar.projectKey", "my-project")
- property("sonar.projectName", "MyProject")
- }
-}"
-`;
-
-exports[`should follow and complete all steps: Maven: bitbucket-pipelines.yml 1`] = `
-"image: maven:3-eclipse-temurin-17
-
-definitions:
- steps:
- - step: &build-step
- name: SonarQube analysis
- caches:
- - maven
- - sonar
- script:
- - mvn verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=my-project -Dsonar.projectName='MyProject'
- caches:
- sonar: ~/.sonar
-
-clone:
- depth: full
-
-pipelines:
- branches:
- '{main}':
- - step: *build-step
-
- pull-requests:
- '**':
- - step: *build-step"
-`;
-
-exports[`should follow and complete all steps: sonar token key 1`] = `"SONAR_TOKEN"`;
-
-exports[`should follow and complete all steps: sonarqube host url key 1`] = `"SONAR_HOST_URL"`;
-
-exports[`should follow and complete all steps: sonarqube host url value 1`] = `"http://localhost:9000"`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/CFamily.ts b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/CFamily.ts
deleted file mode 100644
index 3d6c82d4e88..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/CFamily.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { AutoConfig, BuildTools, OSs } from '../../types';
-import {
- SONAR_SCANNER_CLI_LATEST_VERSION,
- getBuildWrapperExecutableLinux,
- getBuildWrapperFolderLinux,
- getScannerUrlSuffix,
-} from '../../utils';
-import { BuildToolExampleBuilder } from '../AnalysisCommand';
-import othersExample from './Others';
-
-const cFamilyExample: BuildToolExampleBuilder = ({
- config,
- arch,
- branchesEnabled,
- mainBranchName,
-}) => {
- if (config.buildTool === BuildTools.Cpp && config.autoConfig === AutoConfig.Automatic) {
- return othersExample({ config, branchesEnabled, mainBranchName });
- }
- const buildWrapperExecutable = getBuildWrapperExecutableLinux(arch);
- const buildWrapperFolder = getBuildWrapperFolderLinux(arch);
- const scannerSuffix = getScannerUrlSuffix(OSs.Linux, arch);
- return `image: <image ready for your build toolchain>
-
-definitions:
- steps:
- - step: &build-step
- name: Build the project, and run the SonarQube analysis
- script:
- - export SONAR_SCANNER_VERSION=${SONAR_SCANNER_CLI_LATEST_VERSION}
- - mkdir $HOME/.sonar
- - curl -sSLo $HOME/.sonar/${buildWrapperFolder}.zip \${SONAR_HOST_URL}/static/cpp/${buildWrapperFolder}.zip
- - unzip -o $HOME/.sonar/${buildWrapperFolder}.zip -d $HOME/.sonar/
- - curl -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-\${SONAR_SCANNER_VERSION}${scannerSuffix}.zip
- - unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
- - export PATH="$PATH:$HOME/.sonar/sonar-scanner-\${SONAR_SCANNER_VERSION}${scannerSuffix}/bin"
- - <any step required before running your build, like ./configure>
- - $HOME/.sonar/${buildWrapperFolder}/${buildWrapperExecutable} --out-dir bw-output <your clean build command>
- - sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json
- caches:
- sonar: ~/.sonar
-
-clone:
- depth: full
-
-pipelines:
- branches:
- '{${mainBranchName}}':
- - step: *build-step
-${
- branchesEnabled
- ? `
- pull-requests:
- '**':
- - step: *build-step`
- : ''
-}`;
-};
-
-export default cFamilyExample;
diff --git a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Dart.ts b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Dart.ts
deleted file mode 100644
index 493bf3d2e79..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Dart.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Arch, OSs } from '../../types';
-import { SONAR_SCANNER_CLI_LATEST_VERSION, getScannerUrlSuffix } from '../../utils';
-import { BuildToolExampleBuilder } from '../AnalysisCommand';
-
-const dartExample: BuildToolExampleBuilder = ({ branchesEnabled, mainBranchName }) => {
- const scannerSuffix = getScannerUrlSuffix(OSs.Linux, Arch.X86_64);
- return `image: ghcr.io/cirruslabs/flutter:stable
-
-definitions:
- steps:
- - step: &build-step
- name: Build the project, and run the SonarQube analysis
- script:
- - <commands to build your project>
- - export SONAR_SCANNER_VERSION=${SONAR_SCANNER_CLI_LATEST_VERSION}
- - mkdir $HOME/.sonar
- - curl -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-\${SONAR_SCANNER_VERSION}${scannerSuffix}.zip
- - unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
- - export PATH="$PATH:$HOME/.sonar/sonar-scanner-\${SONAR_SCANNER_VERSION}${scannerSuffix}/bin"
- - sonar-scanner
- caches:
- sonar: ~/.sonar
-
-clone:
- depth: full
-
-pipelines:
- branches:
- '{${mainBranchName}}':
- - step: *build-step
-${
- branchesEnabled
- ? `
- pull-requests:
- '**':
- - step: *build-step`
- : ''
-}`;
-};
-
-export default dartExample;
diff --git a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/DotNet.ts b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/DotNet.ts
deleted file mode 100644
index 011c5a33909..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/DotNet.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { BuildToolExampleBuilder } from '../AnalysisCommand';
-
-const dotNetExample: BuildToolExampleBuilder = ({
- branchesEnabled,
- mainBranchName,
- projectKey,
-}) => {
- return `image: mcr.microsoft.com/dotnet/sdk:7.0
-
-definitions:
- steps:
- - step: &build-step
- name: SonarQube analysis
- caches:
- - dotnetcore
- - sonar
- script:
- - dotnet tool install --global dotnet-sonarscanner
- - export PATH="$PATH:/root/.dotnet/tools"
- - dotnet sonarscanner begin /k:"${projectKey}" /d:"sonar.token=\${SONAR_TOKEN}" /d:"sonar.host.url=\${SONAR_HOST_URL}"
- - dotnet build
- - dotnet sonarscanner end /d:"sonar.token=\${SONAR_TOKEN}"
- caches:
- sonar: ~/.sonar
-
-pipelines:
- branches:
- '{${mainBranchName}}':
- - step: *build-step
-${
- branchesEnabled
- ? `
- pull-requests:
- '**':
- - step: *build-step`
- : ''
-}`;
-};
-
-export default dotNetExample;
diff --git a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Gradle.ts b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Gradle.ts
deleted file mode 100644
index e07016ab260..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Gradle.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { BuildToolExampleBuilder } from '../AnalysisCommand';
-
-const gradleExample: BuildToolExampleBuilder = ({ branchesEnabled, mainBranchName }) => {
- return `image: eclipse-temurin:17
-
-definitions:
- steps:
- - step: &build-step
- name: SonarQube analysis
- caches:
- - gradle
- - sonar
- script:
- - bash ./gradlew sonar
- caches:
- sonar: ~/.sonar
-
-clone:
- depth: full
-
-pipelines:
- branches:
- '{${mainBranchName}}':
- - step: *build-step
-${
- branchesEnabled
- ? `
- pull-requests:
- '**':
- - step: *build-step`
- : ''
-}`;
-};
-
-export default gradleExample;
diff --git a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Maven.ts b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Maven.ts
deleted file mode 100644
index 007649713f0..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Maven.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { BuildToolExampleBuilder } from '../AnalysisCommand';
-
-const mavenExample: BuildToolExampleBuilder = ({
- branchesEnabled,
- mainBranchName,
- projectKey,
- projectName,
-}) => {
- return `image: maven:3-eclipse-temurin-17
-
-definitions:
- steps:
- - step: &build-step
- name: SonarQube analysis
- caches:
- - maven
- - sonar
- script:
- - mvn verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=${projectKey} -Dsonar.projectName='${projectName}'
- caches:
- sonar: ~/.sonar
-
-clone:
- depth: full
-
-pipelines:
- branches:
- '{${mainBranchName}}':
- - step: *build-step
-${
- branchesEnabled
- ? `
- pull-requests:
- '**':
- - step: *build-step`
- : ''
-}`;
-};
-
-export default mavenExample;
diff --git a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Others.ts b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Others.ts
deleted file mode 100644
index b24d85780aa..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/commands/Others.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { BuildToolExampleBuilder } from '../AnalysisCommand';
-
-const othersExample: BuildToolExampleBuilder = ({ branchesEnabled, mainBranchName }) => {
- return `
-definitions:
- steps:
- - step: &build-step
- name: SonarQube analysis
- script:
- - pipe: sonarsource/sonarqube-scan:3.0.2
- variables:
- SONAR_HOST_URL: \${SONAR_HOST_URL} # Get the value from the repository/workspace variable.
- SONAR_TOKEN: \${SONAR_TOKEN} # Get the value from the repository/workspace variable. You shouldn't set secret in clear text here.
- caches:
- sonar: ~/.sonar
-
-clone:
- depth: full
-
-pipelines:
- branches:
- '{${mainBranchName}}':
- - step: *build-step
-${
- branchesEnabled
- ? `
- pull-requests:
- '**':
- - step: *build-step
-`
- : ''
-}`;
-};
-
-export default othersExample;
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/AllSet.tsx b/server/sonar-web/src/main/js/components/tutorials/components/AllSet.tsx
deleted file mode 100644
index 4c7c3bf8354..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/AllSet.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { animated, config, useSpring } from '@react-spring/web';
-import * as React from 'react';
-import { CheckIcon, FlagVisual, SubTitle } from '~design-system';
-import withAvailableFeatures, {
- WithAvailableFeaturesProps,
-} from '../../../app/components/available-features/withAvailableFeatures';
-import { translate } from '../../../helpers/l10n';
-import useIntersectionObserver from '../../../hooks/useIntersectionObserver';
-import { AlmKeys } from '../../../types/alm-settings';
-import { Feature } from '../../../types/features';
-
-export interface AllSetProps extends WithAvailableFeaturesProps {
- alm: AlmKeys;
- willRefreshAutomatically?: boolean;
-}
-
-export function AllSet(props: AllSetProps) {
- const outroRef = React.useRef<HTMLDivElement>(null);
- const { alm, willRefreshAutomatically } = props;
- const branchSupportEnabled = props.hasFeature(Feature.BranchSupport);
-
- const intersectionEntry = useIntersectionObserver(outroRef, { freezeOnceVisible: true });
-
- const outroAnimation = useSpring({
- from: { top: '200px' },
- to: intersectionEntry?.isIntersecting ? { top: '0px' } : { top: '200px' },
- config: config.wobbly,
- });
-
- return (
- <animated.div
- className="sw-flex sw-flex-col sw-items-center sw-relative"
- ref={outroRef}
- style={outroAnimation}
- >
- <FlagVisual />
- <SubTitle className="sw-mt-3 sw-mb-12">
- {translate('onboarding.tutorial.ci_outro.done')}
- </SubTitle>
- <MessageContainer>
- <p className="sw-typo-default sw-mb-4">
- {translate('onboarding.tutorial.ci_outro.refresh_text')}
- </p>
- <ul className="sw-mb-6">
- <li className="sw-mb-4 sw-flex">
- <CheckIcon className="sw-mr-2 sw-pt-1/2" />
- {branchSupportEnabled
- ? translate('onboarding.tutorial.ci_outro.commit.why', alm)
- : translate('onboarding.tutorial.ci_outro.commit.why.no_branches')}
- </li>
- {willRefreshAutomatically && (
- <li className="sw-mb-4 sw-flex">
- <CheckIcon className="sw-mr-2 sw-pt-1/2" />
- {translate('onboarding.tutorial.ci_outro.refresh.why')}
- </li>
- )}
- </ul>
- </MessageContainer>
- </animated.div>
- );
-}
-
-const MessageContainer = styled.div`
- width: 840px;
-`;
-
-export default withAvailableFeatures(AllSet);
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/BuildConfigSelection.tsx b/server/sonar-web/src/main/js/components/tutorials/components/BuildConfigSelection.tsx
deleted file mode 100644
index bc40231bde1..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/BuildConfigSelection.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FlagMessage } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { AutoConfig, BuildTools, TutorialConfig, TutorialModes } from '../types';
-import { getBuildToolOptions, isCFamily, supportsAutoConfig } from '../utils';
-import RenderOptions from './RenderOptions';
-
-export interface BuildConfigSelectionProps {
- ci: TutorialModes;
- config: TutorialConfig;
- hideAutoConfig?: boolean;
- onSetConfig(config: TutorialConfig): void;
- supportCFamily: boolean;
-}
-
-export default function BuildConfigSelection(props: Readonly<BuildConfigSelectionProps>) {
- const { ci, config, hideAutoConfig, supportCFamily, onSetConfig } = props;
-
- function onSelectBuildTool(buildTool: BuildTools) {
- const autoConfig = buildTool === BuildTools.Cpp ? AutoConfig.Automatic : undefined;
- onSetConfig({ ...config, buildTool, autoConfig });
- }
-
- function onSelectAutoConfig(autoConfig: AutoConfig) {
- onSetConfig({ ...config, autoConfig });
- }
-
- return (
- <>
- {translate('onboarding.build')}
- <RenderOptions
- label={translate('onboarding.build')}
- checked={config.buildTool}
- onCheck={onSelectBuildTool}
- optionLabelKey="onboarding.build"
- options={getBuildToolOptions(supportCFamily)}
- />
-
- {ci === TutorialModes.Jenkins && isCFamily(config.buildTool) && (
- <FlagMessage variant="info" className="sw-mt-2 sw-w-abs-600">
- {translate('onboarding.tutorial.with.jenkins.jenkinsfile.cfamilly.agent_setup')}
- </FlagMessage>
- )}
-
- {!hideAutoConfig &&
- config.buildTool &&
- supportsAutoConfig(config.buildTool) &&
- onSelectAutoConfig && (
- <>
- <div className="sw-mt-4">{translate('onboarding.build.cpp.autoconfig')}</div>
- <RenderOptions
- label="onboarding.build.cpp.autoconfig"
- checked={config.autoConfig}
- onCheck={onSelectAutoConfig}
- optionLabelKey="onboarding.build.cpp.autoconfig"
- options={[AutoConfig.Automatic, AutoConfig.Manual]}
- />
- <FlagMessage className="sw-mt-2 sw-w-abs-600" variant="info">
- {translate(`onboarding.build.cpp.autoconfig.${config.autoConfig}.description`)}
- </FlagMessage>
- </>
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/CompilationInfo.tsx b/server/sonar-web/src/main/js/components/tutorials/components/CompilationInfo.tsx
deleted file mode 100644
index 2572a61c009..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/CompilationInfo.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkStandalone as Link } from '@sonarsource/echoes-react';
-import { FormattedMessage } from 'react-intl';
-import { FlagMessage } from '~design-system';
-import { DocLink } from '../../../helpers/doc-links';
-import { useDocUrl } from '../../../helpers/docs';
-import { translate } from '../../../helpers/l10n';
-
-export interface CompilationInfoProps {
- className?: string;
-}
-
-export function CompilationInfo({ className = 'sw-my-2' }: CompilationInfoProps) {
- const docUrl = useDocUrl();
-
- return (
- <FlagMessage className={className} variant="info">
- <div>
- <p className="sw-mb-2">
- <FormattedMessage
- id="onboarding.tutorial.cfamilly.compilation_database_info"
- defaultMessage={translate('onboarding.tutorial.cfamilly.compilation_database_info')}
- values={{
- link: (
- <Link to={docUrl(DocLink.CFamilyCompilationDatabase)}>
- {translate('onboarding.tutorial.cfamilly.compilation_database_info.link')}
- </Link>
- ),
- }}
- />
- </p>
- </div>
- </FlagMessage>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/CreateYmlFile.tsx b/server/sonar-web/src/main/js/components/tutorials/components/CreateYmlFile.tsx
deleted file mode 100644
index 6502720b7af..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/CreateYmlFile.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { ClipboardIconButton, CodeSnippet, NumberedListItem } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { InlineSnippet } from './InlineSnippet';
-
-export interface CreateYmlFileProps {
- warning?: React.ReactNode;
- yamlFileName: string;
- yamlTemplate: string;
-}
-
-export default function CreateYmlFile(props: Readonly<CreateYmlFileProps>) {
- const { yamlTemplate, yamlFileName, warning } = props;
- return (
- <NumberedListItem>
- <FormattedMessage
- defaultMessage={translate('onboarding.tutorial.with.github_action.yaml.create_yml')}
- id="onboarding.tutorial.with.github_action.yaml.create_yml"
- values={{
- file: (
- <>
- <InlineSnippet snippet={yamlFileName} />
- <ClipboardIconButton copyValue={yamlFileName} className="sw-ml-2 sw-align-sub" />
- </>
- ),
- }}
- />
- {warning}
- <CodeSnippet className="sw-p-6 sw-overflow-auto" snippet={yamlTemplate} language="yml" />
- </NumberedListItem>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/DefaultProjectKey.tsx b/server/sonar-web/src/main/js/components/tutorials/components/DefaultProjectKey.tsx
deleted file mode 100644
index 3aa5e421cc0..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/DefaultProjectKey.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { CodeSnippet, FlagMessage, NumberedListItem } from '~design-system';
-import { Component } from '../../../types/types';
-import SentenceWithFilename from './SentenceWithFilename';
-
-export interface DefaultProjectKeyProps {
- component: Component;
- monorepo?: boolean;
-}
-
-const sonarProjectSnippet = (key: string) => `sonar.projectKey=${key}`;
-
-export default function DefaultProjectKey(props: DefaultProjectKeyProps) {
- const { component, monorepo } = props;
-
- return (
- <NumberedListItem className="sw-mb-6">
- <SentenceWithFilename
- filename="sonar-project.properties"
- translationKey={`onboarding.tutorial.other.project_key${monorepo ? '.monorepo' : ''}`}
- />
- <CodeSnippet snippet={sonarProjectSnippet(component.key)} isOneLine className="sw-p-6" />
- <div>
- <FlagMessage variant="info">
- <FormattedMessage id="onboarding.tutorial.other.project_key.monorepo.info" />
- </FlagMessage>
- </div>
- </NumberedListItem>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/EditTokenModal.tsx b/server/sonar-web/src/main/js/components/tutorials/components/EditTokenModal.tsx
deleted file mode 100644
index 876ae1689f9..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/EditTokenModal.tsx
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import {
- ButtonSecondary,
- ClipboardIconButton,
- DestructiveIcon,
- FlagMessage,
- InputField,
- InputSelect,
- LabelValueSelectOption,
- Link,
- Modal,
- Spinner,
- TrashIcon,
-} from '~design-system';
-import { generateToken, getTokens, revokeToken } from '../../../api/user-tokens';
-
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-import {
- EXPIRATION_OPTIONS,
- computeTokenExpirationDate,
- getAvailableExpirationOptions,
-} from '../../../helpers/tokens';
-import { hasGlobalPermission } from '../../../helpers/users';
-import { Permissions } from '../../../types/permissions';
-import { TokenExpiration, TokenType } from '../../../types/token';
-import { Component } from '../../../types/types';
-import { LoggedInUser } from '../../../types/users';
-import { getUniqueTokenName } from '../utils';
-import { InlineSnippet } from './InlineSnippet';
-import ProjectTokenScopeInfo from './ProjectTokenScopeInfo';
-
-interface State {
- loading: boolean;
- token?: string;
- tokenExpiration: TokenExpiration;
- tokenExpirationOptions: { label: string; value: TokenExpiration }[];
- tokenName: string;
-}
-
-interface Props {
- component: Component;
- currentUser: LoggedInUser;
- onClose: (token?: string) => void;
- preferredTokenType?: TokenType.Global | TokenType.Project;
-}
-
-export default class EditTokenModal extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {
- loading: true,
- tokenName: '',
- tokenExpiration: TokenExpiration.OneMonth,
- tokenExpirationOptions: EXPIRATION_OPTIONS,
- };
-
- componentDidMount() {
- this.mounted = true;
- this.getTokensAndName();
- this.getTokenExpirationOptions();
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- getTokensAndName = async () => {
- const { component, currentUser } = this.props;
-
- const tokens = await getTokens(currentUser.login);
-
- if (this.mounted) {
- this.setState({
- loading: false,
- tokenName: getUniqueTokenName(tokens, `Analyze "${component.name}"`),
- });
- }
- };
-
- getTokenExpirationOptions = async () => {
- const tokenExpirationOptions = await getAvailableExpirationOptions();
- if (tokenExpirationOptions && this.mounted) {
- this.setState({ tokenExpirationOptions });
- }
- };
-
- getNewToken = async () => {
- const {
- component: { key },
- } = this.props;
- const { tokenName, tokenExpiration } = this.state;
-
- const type = this.getTokenType();
-
- const { token } = await generateToken({
- name: tokenName,
- type,
- projectKey: key,
- ...(tokenExpiration !== TokenExpiration.NoExpiration && {
- expirationDate: computeTokenExpirationDate(tokenExpiration),
- }),
- });
-
- if (this.mounted) {
- this.setState({
- token,
- tokenName,
- });
- }
- };
-
- getTokenType = () => {
- const { currentUser, preferredTokenType } = this.props;
-
- return preferredTokenType === TokenType.Global &&
- hasGlobalPermission(currentUser, Permissions.Scan)
- ? TokenType.Global
- : TokenType.Project;
- };
-
- handleTokenNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- this.setState({ tokenName: event.currentTarget.value });
- };
-
- handleTokenExpirationChange = (value: TokenExpiration) => {
- this.setState({ tokenExpiration: value });
- };
-
- handleTokenRevoke = async () => {
- const { tokenName } = this.state;
-
- if (tokenName) {
- await revokeToken({ name: tokenName });
-
- if (this.mounted) {
- this.setState({
- token: '',
- tokenName: '',
- });
- }
- }
- };
-
- renderForm(type: TokenType) {
- const { loading, token, tokenName, tokenExpiration, tokenExpirationOptions } = this.state;
- const intro = translate('onboarding.token.text', type);
-
- return (
- <div className="sw-typo-default">
- <FormattedMessage
- defaultMessage={intro}
- id={intro}
- values={{
- link: (
- <Link target="_blank" to="/account/security">
- {translate('onboarding.token.text.user_account')}
- </Link>
- ),
- }}
- />
-
- {token ? (
- <>
- <span>
- {tokenName}
- {': '}
- </span>
- <div>
- <InlineSnippet snippet={token} />
- <ClipboardIconButton
- copyLabel={translate('copy_to_clipboard')}
- className="sw-ml-2"
- copyValue={token}
- />
- <DestructiveIcon
- className="sw-ml-1"
- Icon={TrashIcon}
- aria-label={translate('onboarding.token.delete')}
- onClick={this.handleTokenRevoke}
- />
- </div>
- <FlagMessage className="sw-mt-2" variant="warning">
- {translateWithParameters('users.tokens.new_token_created', token)}
- </FlagMessage>
- </>
- ) : (
- <>
- <div className="sw-flex sw-pt-4">
- <Spinner loading={loading}>
- <div className="sw-flex-col sw-mr-2">
- <label className="sw-block" htmlFor="token-name">
- {translate('onboarding.token.name.label')}
- </label>
- <InputField
- aria-label={translate('onboarding.token.name.label')}
- onChange={this.handleTokenNameChange}
- id="token-name"
- placeholder={translate('onboarding.token.name.placeholder')}
- value={tokenName}
- type="text"
- />
- </div>
- <div className="sw-flex-col">
- <label htmlFor="token-expiration">{translate('users.tokens.expires_in')}</label>
- <div className="sw-flex">
- <InputSelect
- size="medium"
- id="token-expiration"
- isSearchable={false}
- onChange={(data: LabelValueSelectOption<TokenExpiration>) =>
- this.handleTokenExpirationChange(data.value)
- }
- options={tokenExpirationOptions}
- value={tokenExpirationOptions.find(
- (option) => option.value === tokenExpiration,
- )}
- />
- <ButtonSecondary
- className="sw-ml-2"
- disabled={!tokenName}
- onClick={this.getNewToken}
- >
- {translate('onboarding.token.generate')}
- </ButtonSecondary>
- </div>
- </div>
- </Spinner>
- </div>
- {type === TokenType.Project && <ProjectTokenScopeInfo />}
- </>
- )}
- </div>
- );
- }
-
- render() {
- const { loading } = this.state;
- const type = this.getTokenType();
- const header = translate('onboarding.token.generate', type);
-
- return (
- <Modal
- onClose={this.props.onClose}
- headerTitle={header}
- isOverflowVisible
- loading={loading}
- body={this.renderForm(type)}
- secondaryButtonLabel={translate('continue')}
- />
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/GithubCFamilyExampleRepositories.tsx b/server/sonar-web/src/main/js/components/tutorials/components/GithubCFamilyExampleRepositories.tsx
deleted file mode 100644
index a4606e48efd..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/GithubCFamilyExampleRepositories.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkStandalone } from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import { Card, LightLabel } from '~design-system';
-import { Image } from '~sonar-aligned/components/common/Image';
-import { translate } from '../../../helpers/l10n';
-import { OSs, TutorialModes } from '../types';
-
-export interface GithubCFamilyExampleRepositoriesProps {
- ci?: TutorialModes;
- className?: string;
- os?: OSs;
-}
-
-const OS_SEARCH_MAP = {
- [OSs.Linux]: 'linux',
- [OSs.Windows]: 'windows',
- [OSs.MacOS]: 'macos',
-};
-
-const CI_SEARCH_MAP = {
- [TutorialModes.Jenkins]: 'jenkins',
- [TutorialModes.AzurePipelines]: 'azure',
- [TutorialModes.GitHubActions]: 'gh-actions',
- [TutorialModes.GitLabCI]: 'gitlab',
- [TutorialModes.BitbucketPipelines]: 'bitbucket',
- [TutorialModes.Local]: 'otherci',
- [TutorialModes.OtherCI]: 'otherci',
-};
-
-export default function GithubCFamilyExampleRepositories(
- props: Readonly<GithubCFamilyExampleRepositoriesProps>,
-) {
- const { className, os, ci } = props;
- const queryParams = ['sq', os ? OS_SEARCH_MAP[os] : undefined, ci ? CI_SEARCH_MAP[ci] : undefined]
- .filter((s) => !!s)
- .join('+');
- const link = `https://github.com/orgs/sonarsource-cfamily-examples/repositories?q=${queryParams}`;
-
- return (
- <Card className={classNames('sw-p-4 sw-bg-inherit', className)}>
- <div>
- <Image
- alt="" // Should be ignored by screen readers
- className="sw-mr-2"
- height={20}
- src="/images/alm/github.svg"
- />
- <LinkStandalone shouldOpenInNewTab to={link}>
- sonarsource-cfamily-examples
- </LinkStandalone>
- </div>
- <LightLabel as="p" className="sw-mt-4">
- {translate('onboarding.tutorial.cfamily.examples_repositories_description')}
- </LightLabel>
- </Card>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/GradleBuild.tsx b/server/sonar-web/src/main/js/components/tutorials/components/GradleBuild.tsx
deleted file mode 100644
index 66e0e908767..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/GradleBuild.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { ClipboardIconButton, CodeSnippet, NumberedListItem } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { Component } from '../../../types/types';
-import { GradleBuildDSL } from '../types';
-import { buildGradleSnippet } from '../utils';
-import GradleBuildSelection from './GradleBuildSelection';
-import { InlineSnippet } from './InlineSnippet';
-
-interface Props {
- component: Component;
-}
-
-export default function GradleBuild({ component }: Props) {
- return (
- <NumberedListItem>
- <FormattedMessage
- defaultMessage={translate('onboarding.tutorial.with.yaml.gradle')}
- id="onboarding.tutorial.with.yaml.gradle"
- values={{
- groovy: (
- <>
- <InlineSnippet snippet={GradleBuildDSL.Groovy} />
- <ClipboardIconButton
- copyValue={GradleBuildDSL.Groovy}
- className="sw-ml-2 sw-align-sub"
- />
- </>
- ),
- kotlin: (
- <>
- <InlineSnippet snippet={GradleBuildDSL.Kotlin} />
- <ClipboardIconButton
- copyValue={GradleBuildDSL.Kotlin}
- className="sw-ml-2 sw-align-sub"
- />
- </>
- ),
- sq: <InlineSnippet snippet="org.sonarqube" />,
- }}
- />
- <GradleBuildSelection className="sw-my-4">
- {(build) => (
- <CodeSnippet
- language={build === GradleBuildDSL.Groovy ? 'groovy' : 'kotlin'}
- className="sw-p-6"
- snippet={buildGradleSnippet(component.key, component.name, build)}
- />
- )}
- </GradleBuildSelection>
- </NumberedListItem>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/GradleBuildSelection.tsx b/server/sonar-web/src/main/js/components/tutorials/components/GradleBuildSelection.tsx
deleted file mode 100644
index 87b6ca36aef..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/GradleBuildSelection.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React from 'react';
-import { ToggleButton } from '~design-system';
-import { GradleBuildDSL } from '../types';
-
-interface Props {
- children: (build: GradleBuildDSL) => React.ReactNode;
- className?: string;
-}
-
-export default function GradleBuildSelection({ children, className }: Props) {
- const [build, setBuild] = React.useState<GradleBuildDSL>(GradleBuildDSL.Groovy);
-
- const buildOptions = Object.values(GradleBuildDSL).map((v: GradleBuildDSL) => ({
- label: v,
- value: v,
- }));
-
- return (
- <>
- <div className={className}>
- <ToggleButton
- options={buildOptions}
- value={build}
- onChange={(value: GradleBuildDSL) => setBuild(value)}
- />
- </div>
- {children(build)}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/InlineSnippet.tsx b/server/sonar-web/src/main/js/components/tutorials/components/InlineSnippet.tsx
deleted file mode 100644
index 5d180a47ef7..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/InlineSnippet.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { CodeSnippet } from '~design-system';
-import { FCProps } from '../../../types/misc';
-
-export function InlineSnippet({
- snippet,
- className,
-}: Pick<FCProps<typeof CodeSnippet>, 'snippet'> & { className?: string }) {
- return (
- <CodeSnippet
- className={classNames('sw-code sw-inline-block sw-px-1', className)}
- noCopy
- isOneLine
- snippet={snippet}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/LabelActionPair.tsx b/server/sonar-web/src/main/js/components/tutorials/components/LabelActionPair.tsx
deleted file mode 100644
index a06d2146260..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/LabelActionPair.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { translate } from '../../../helpers/l10n';
-
-export interface LabelActionPairProps {
- translationKey: string;
-}
-
-export default function LabelActionPair({ translationKey }: LabelActionPairProps) {
- return (
- <>
- <strong>{translate(translationKey, 'label')}:</strong> {translate(translationKey, 'action')}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/LabelValuePair.tsx b/server/sonar-web/src/main/js/components/tutorials/components/LabelValuePair.tsx
deleted file mode 100644
index 852fa803932..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/LabelValuePair.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ClipboardIconButton } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-
-export interface LabelValuePairProps {
- translationKey: string;
- value: string;
-}
-
-export default function LabelValuePair({ translationKey, value }: LabelValuePairProps) {
- return (
- <div className="sw-flex sw-items-center">
- <b className="sw-mr-1 sw-font-semibold">{translate(translationKey, 'label')}:</b> {value}
- <ClipboardIconButton className="sw-ml-1" copyValue={value} />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/ProjectTokenScopeInfo.tsx b/server/sonar-web/src/main/js/components/tutorials/components/ProjectTokenScopeInfo.tsx
deleted file mode 100644
index a4c3b7f1ac8..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/ProjectTokenScopeInfo.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { FormattedMessage } from 'react-intl';
-import { FlagMessage, Link } from '~design-system';
-import { DocLink } from '../../../helpers/doc-links';
-import { useDocUrl } from '../../../helpers/docs';
-import { translate } from '../../../helpers/l10n';
-
-export interface ProjectTokenScopeInfoProps {
- className?: string;
-}
-
-export default function ProjectTokenScopeInfo({ className }: ProjectTokenScopeInfoProps) {
- const docUrl = useDocUrl(DocLink.AccountTokens);
-
- return (
- <FlagMessage variant="info" className={classNames('sw-mt-2', className)}>
- <FormattedMessage
- tagName="span"
- defaultMessage={translate('onboarding.token.warning_project_token_scope')}
- id="onboarding.token.warning_project_token_scope"
- values={{
- link: (
- <Link target="_blank" to="/account/security">
- {translate('onboarding.token.text.user_account')}
- </Link>
- ),
- doc_link: <Link to={docUrl}>{translate('documentation')}</Link>,
- }}
- />
- </FlagMessage>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/RenderOptions.tsx b/server/sonar-web/src/main/js/components/tutorials/components/RenderOptions.tsx
deleted file mode 100644
index 25d29b0b143..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/RenderOptions.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ToggleButton } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-
-export interface RenderOptionsProps {
- checked: string | undefined;
- label?: string;
- onCheck: (checked: string) => void;
- optionLabelKey: string;
- options: string[];
- titleLabelKey?: string;
-}
-
-export default function RenderOptions({
- checked,
- label,
- onCheck,
- optionLabelKey,
- options,
- titleLabelKey,
-}: RenderOptionsProps) {
- const onChange = (checked: string) => {
- onCheck(checked);
- };
-
- return (
- <div className="sw-mt-4">
- {titleLabelKey && <label className="sw-block sw-mb-1">{translate(titleLabelKey)}</label>}
-
- <ToggleButton
- label={label}
- onChange={onChange}
- options={options.map((build) => ({
- label: translate(optionLabelKey, build),
- value: build,
- }))}
- value={checked}
- />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/SentenceWithFilename.tsx b/server/sonar-web/src/main/js/components/tutorials/components/SentenceWithFilename.tsx
deleted file mode 100644
index c49a06c58cb..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/SentenceWithFilename.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { translate } from '../../../helpers/l10n';
-import { InlineSnippet } from './InlineSnippet';
-
-export interface SentenceWithFilenameProps {
- filename: string;
- translationKey: string;
-}
-
-export default function SentenceWithFilename({
- filename,
- translationKey,
-}: SentenceWithFilenameProps) {
- return (
- <span>
- <FormattedMessage
- defaultMessage={translate(translationKey, 'sentence')}
- id={`${translationKey}.sentence`}
- values={{
- file: <InlineSnippet snippet={filename} />,
- }}
- />
- </span>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/SentenceWithHighlights.tsx b/server/sonar-web/src/main/js/components/tutorials/components/SentenceWithHighlights.tsx
deleted file mode 100644
index 0a6c4f0f1c9..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/SentenceWithHighlights.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { translate } from '../../../helpers/l10n';
-import { Dict } from '../../../types/types';
-
-export interface SentenceWithHighlightsProps {
- highlightKeys: string[];
- highlightPrefixKeys?: string;
- translationKey: string;
-}
-
-export default function SentenceWithHighlights({
- highlightKeys,
- translationKey,
- highlightPrefixKeys,
-}: SentenceWithHighlightsProps) {
- const values: Dict<JSX.Element> = {};
-
- const transhighlightPrefixKeys = highlightPrefixKeys || translationKey;
- highlightKeys.forEach((key) => {
- values[key] = (
- <strong className="sw-font-semibold">
- {translate(transhighlightPrefixKeys, 'sentence', key)}
- </strong>
- );
- });
- return (
- <FormattedMessage
- defaultMessage={translate(translationKey, 'sentence')}
- id={`${translationKey}.sentence`}
- values={values}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/Step.tsx b/server/sonar-web/src/main/js/components/tutorials/components/Step.tsx
deleted file mode 100644
index 0984f00490f..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/Step.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/no-noninteractive-tabindex */
-import styled from '@emotion/styled';
-import * as React from 'react';
-import { Card, TutorialStep, TutorialStepList, themeBorder, themeColor } from '~design-system';
-
-interface Props {
- finished?: boolean;
- onOpen?: VoidFunction;
- open: boolean;
- renderForm: () => React.ReactNode;
- renderResult?: () => React.ReactNode;
- stepNumber?: number;
- stepTitle: React.ReactNode;
-}
-
-const CLOSED_STEP_OPACITY = 0.4;
-
-export default function Step(props: Props) {
- const { finished, open, stepNumber, stepTitle } = props;
-
- const clickable = !open && finished && props.onOpen !== undefined;
-
- const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
- event.preventDefault();
- if (props.onOpen !== undefined) {
- props.onOpen();
- }
- };
-
- return (
- <StyledCard
- clickable={Boolean(clickable)}
- className="sw-mb-2 sw-p-0"
- onClick={clickable ? handleClick : undefined}
- role={clickable ? 'button' : undefined}
- tabIndex={clickable ? 0 : undefined}
- >
- <div
- style={{ opacity: !open && !finished ? CLOSED_STEP_OPACITY : undefined }}
- className="sw-flex sw-items-center sw-justify-between sw-px-6"
- >
- <TutorialStepList className="sw-flex-1">
- <TutorialStep title={stepTitle} stepNumber={stepNumber}>
- {open ? <div>{props.renderForm()}</div> : <div className="sw-px-5 sw-pb-4" />}
- </TutorialStep>
- </TutorialStepList>
- {!open && props.renderResult && props.renderResult()}
- </div>
- </StyledCard>
- );
-}
-
-const StyledCard = styled(Card)<{ clickable: boolean }>`
- --focus: ${themeColor('buttonSecondaryBorder')};
-
- ${({ clickable, theme }) =>
- clickable &&
- `
- cursor: pointer;
-
-
- &:focus,
- &:active {
- outline: ${themeBorder('focus', 'var(--focus)')({ theme })}
- }
-`};
-`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/TokenStepGenerator.tsx b/server/sonar-web/src/main/js/components/tutorials/components/TokenStepGenerator.tsx
deleted file mode 100644
index c1640000c96..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/TokenStepGenerator.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { ButtonSecondary } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { Component } from '../../../types/types';
-import { LoggedInUser } from '../../../types/users';
-import EditTokenModal from './EditTokenModal';
-
-export interface TokenStepGeneratorProps {
- component: Component;
- currentUser: LoggedInUser;
-}
-
-export default function TokenStepGenerator(props: TokenStepGeneratorProps) {
- const { component, currentUser } = props;
- const [isModalVisible, toggleModal] = React.useState(false);
-
- const toggleTokenModal = () => toggleModal((visible) => !visible);
- const closeTokenModal = () => toggleModal(false);
-
- return (
- <>
- <FormattedMessage
- defaultMessage={translate('onboarding.tutorial.env_variables')}
- id="onboarding.tutorial.env_variables"
- values={{
- extra: (
- <ButtonSecondary className="sw-ml-2" onClick={toggleTokenModal}>
- {translate('onboarding.token.generate.long')}
- </ButtonSecondary>
- ),
- field: (
- <span className="sw-typo-semibold">
- {translate('onboarding.tutorial.env_variables.field')}
- </span>
- ),
- value: translate('onboarding.tutorial.env_variables.token_generator.value'),
- }}
- />
- {isModalVisible && (
- <EditTokenModal component={component} currentUser={currentUser} onClose={closeTokenModal} />
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/YamlFileStep.tsx b/server/sonar-web/src/main/js/components/tutorials/components/YamlFileStep.tsx
deleted file mode 100644
index ab5897c1217..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/YamlFileStep.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { NumberedList, NumberedListItem } from '~design-system';
-import { withCLanguageFeature } from '../../hoc/withCLanguageFeature';
-import { TutorialConfig, TutorialModes } from '../types';
-import BuildConfigSelection from './BuildConfigSelection';
-
-export interface YamlFileStepProps {
- children?: (config: TutorialConfig) => React.ReactElement<{}>;
- ci: TutorialModes;
- config: TutorialConfig;
- hasCLanguageFeature: boolean;
- setConfig: (config: TutorialConfig) => void;
-}
-
-export function YamlFileStep(props: YamlFileStepProps) {
- const { ci, config, setConfig, children, hasCLanguageFeature } = props;
-
- return (
- <NumberedList>
- <NumberedListItem>
- <BuildConfigSelection
- ci={ci}
- config={config}
- onSetConfig={setConfig}
- supportCFamily={hasCLanguageFeature}
- />
- </NumberedListItem>
-
- {children && config && children(config)}
- </NumberedList>
- );
-}
-
-export default withCLanguageFeature(YamlFileStep);
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/__tests__/EditTokenModal-test.tsx b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/EditTokenModal-test.tsx
deleted file mode 100644
index 36b13c13432..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/__tests__/EditTokenModal-test.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup';
-import UserTokensMock from '../../../../api/mocks/UserTokensMock';
-import { mockComponent } from '../../../../helpers/mocks/component';
-import { mockUserToken } from '../../../../helpers/mocks/token';
-import { mockLoggedInUser } from '../../../../helpers/testMocks';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { computeTokenExpirationDate } from '../../../../helpers/tokens';
-import { Permissions } from '../../../../types/permissions';
-import { TokenType } from '../../../../types/token';
-import EditTokenModal from '../EditTokenModal';
-
-jest.mock('../../../../api/settings', () => ({
- getAllValues: jest.fn().mockResolvedValue([]),
-}));
-
-let tokenMock: UserTokensMock;
-
-beforeAll(() => {
- tokenMock = new UserTokensMock();
- tokenMock.tokens.push(mockUserToken({ name: 'Analyze "Foo"' }));
-});
-
-afterEach(() => {
- tokenMock.reset();
-});
-
-it('should behave correctly', async () => {
- renderEditTokenModal();
- const user = userEvent.setup();
-
- expect(
- screen.getByRole('heading', { name: 'onboarding.token.generate.PROJECT_ANALYSIS_TOKEN' }),
- ).toBeInTheDocument();
- expect(screen.getByText('onboarding.token.text.PROJECT_ANALYSIS_TOKEN')).toBeInTheDocument();
-
- // Renders form correctly.
- await screen.findByLabelText('onboarding.token.name.label');
- // Should be getByLabelText(), but this is due to a limitation with React Select.
- expect(screen.getByText('users.tokens.expires_in')).toBeInTheDocument();
- expect(screen.getByRole('button', { name: 'continue' })).toBeInTheDocument();
-
- // Sets a default token name.
- const tokenNameInput = screen.getByLabelText('onboarding.token.name.label');
- expect(tokenNameInput).toHaveValue('Analyze "Foo" 1');
-
- // Change name and expiration date.
- await typeInField(user, tokenNameInput, 'new token name');
- await user.click(screen.getByText('users.tokens.expiration.30'));
- await user.click(screen.getByText('users.tokens.expiration.365'));
-
- // Generate token.
- await clickButton(user, 'onboarding.token.generate');
- let lastToken = tokenMock.getLastToken();
- if (lastToken === undefined) {
- throw new Error("Couldn't find the latest generated token.");
- }
-
- expect(lastToken.type).toBe(TokenType.Project);
- expect(lastToken.expirationDate).toBe(computeTokenExpirationDate(365));
- expect(screen.getByText(`users.tokens.new_token_created.${lastToken.token}`)).toBeInTheDocument();
- expect(screen.getByRole('button', { name: 'copy_to_clipboard' })).toBeInTheDocument();
-
- // Revoke token.
- await clickButton(user, 'onboarding.token.delete');
- expect(tokenMock.tokens.map((t) => t.name)).not.toContain(lastToken.name);
-
- // Generate a new token.
- await typeInField(
- user,
- screen.getByLabelText('onboarding.token.name.label'),
- 'another token name',
- );
- await clickButton(user, 'onboarding.token.generate');
-
- lastToken = tokenMock.getLastToken();
- if (lastToken === undefined) {
- throw new Error("Couldn't find the latest generated token.");
- }
- expect(lastToken.type).toBe(TokenType.Project);
- expect(lastToken.expirationDate).toBe(computeTokenExpirationDate(365));
- expect(screen.getByText(`users.tokens.new_token_created.${lastToken.token}`)).toBeInTheDocument();
-});
-
-it('should allow setting a preferred token type', async () => {
- renderEditTokenModal({
- preferredTokenType: TokenType.Global,
- currentUser: mockLoggedInUser({ permissions: { global: [Permissions.Scan] } }),
- });
- const user = userEvent.setup();
-
- await screen.findByLabelText('onboarding.token.name.label');
-
- await clickButton(user, 'onboarding.token.generate');
- const lastToken = tokenMock.getLastToken();
- if (lastToken === undefined) {
- throw new Error("Couldn't find the latest generated token.");
- }
- expect(lastToken.type).toBe(TokenType.Global);
-});
-
-it('should fallback to project tokens if the user cannot generate global tokens', async () => {
- renderEditTokenModal({
- preferredTokenType: TokenType.Global,
- });
- const user = userEvent.setup();
-
- await screen.findByLabelText('onboarding.token.name.label');
-
- await clickButton(user, 'onboarding.token.generate');
- const lastToken = tokenMock.getLastToken();
- if (lastToken === undefined) {
- throw new Error("Couldn't find the latest generated token.");
- }
- expect(lastToken.type).toBe(TokenType.Project);
-});
-
-function renderEditTokenModal(props: Partial<EditTokenModal['props']> = {}) {
- return renderComponent(
- <EditTokenModal
- component={mockComponent({ name: 'Foo' })}
- currentUser={mockLoggedInUser()}
- onClose={jest.fn()}
- {...props}
- />,
- );
-}
-
-async function clickButton(user: UserEvent, name: string) {
- await user.click(screen.getByRole('button', { name }));
-}
-
-async function typeInField(user: UserEvent, input: HTMLElement, value: string) {
- await user.clear(input);
- await user.type(input, value);
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/__tests__/GithubCFamilyExampleRepositories-test.tsx b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/GithubCFamilyExampleRepositories-test.tsx
deleted file mode 100644
index 6751c8a44b8..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/components/__tests__/GithubCFamilyExampleRepositories-test.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { byRole } from '~sonar-aligned/helpers/testSelector';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { OSs, TutorialModes } from '../../types';
-import GithubCFamilyExampleRepositories, {
- GithubCFamilyExampleRepositoriesProps,
-} from '../GithubCFamilyExampleRepositories';
-
-const ui = {
- cfamilyExamplesLink: byRole('link', { name: /sonarsource-cfamily-examples/ }),
-};
-
-it.each([
- [OSs.Linux, TutorialModes.Jenkins, 'linux', 'jenkins'],
- [OSs.MacOS, TutorialModes.AzurePipelines, 'macos', 'azure'],
-])(
- 'should set correct value for CFamily examples link for %s and %ss',
- async (os: OSs, ci: TutorialModes, formattedOS: string, formattedCI: string) => {
- renderGithubCFamilyExampleRepositories({ os, ci });
- expect(await ui.cfamilyExamplesLink.find()).toHaveAttribute(
- 'href',
- `https://github.com/orgs/sonarsource-cfamily-examples/repositories?q=sq+${formattedOS}+${formattedCI}`,
- );
- },
-);
-
-function renderGithubCFamilyExampleRepositories(
- overrides: Partial<GithubCFamilyExampleRepositoriesProps> = {},
-) {
- return renderComponent(
- <GithubCFamilyExampleRepositories className="test-class" {...overrides} />,
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/AnalysisCommand.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/AnalysisCommand.tsx
deleted file mode 100644
index 28e1230014a..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/github-action/AnalysisCommand.tsx
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import withAvailableFeatures, {
- WithAvailableFeaturesProps,
-} from '../../../app/components/available-features/withAvailableFeatures';
-import { Feature } from '../../../types/features';
-import { Component } from '../../../types/types';
-import { BuildTools, TutorialConfig } from '../types';
-import CFamily from './commands/CFamily';
-import DotNet from './commands/DotNet';
-import Gradle from './commands/Gradle';
-import JavaMaven from './commands/JavaMaven';
-import Others from './commands/Others';
-
-export interface AnalysisCommandProps extends WithAvailableFeaturesProps {
- component: Component;
- config: TutorialConfig;
- mainBranchName: string;
- monorepo?: boolean;
-}
-
-export function AnalysisCommand(props: Readonly<AnalysisCommandProps>) {
- const { config, component, mainBranchName, monorepo } = props;
- const branchSupportEnabled = props.hasFeature(Feature.BranchSupport);
-
- switch (config.buildTool) {
- case BuildTools.Maven:
- return (
- <JavaMaven
- branchesEnabled={branchSupportEnabled}
- mainBranchName={mainBranchName}
- monorepo={monorepo}
- component={component}
- />
- );
- case BuildTools.Gradle:
- return (
- <Gradle
- branchesEnabled={branchSupportEnabled}
- mainBranchName={mainBranchName}
- monorepo={monorepo}
- component={component}
- />
- );
- case BuildTools.DotNet:
- return (
- <DotNet
- branchesEnabled={branchSupportEnabled}
- mainBranchName={mainBranchName}
- monorepo={monorepo}
- component={component}
- />
- );
- case BuildTools.Cpp:
- case BuildTools.ObjectiveC:
- return (
- <CFamily
- config={config}
- branchesEnabled={branchSupportEnabled}
- mainBranchName={mainBranchName}
- monorepo={monorepo}
- component={component}
- />
- );
- case BuildTools.Dart:
- return (
- <Others
- branchesEnabled={branchSupportEnabled}
- buildSteps={`
- # The analysis requires to retrieve dependencies and build successfully
- - name: Build project
- run: <commands to build your project>`}
- mainBranchName={mainBranchName}
- monorepo={monorepo}
- component={component}
- />
- );
- case BuildTools.Other:
- return (
- <Others
- branchesEnabled={branchSupportEnabled}
- buildSteps=""
- mainBranchName={mainBranchName}
- monorepo={monorepo}
- component={component}
- />
- );
- default:
- return undefined;
- }
-}
-
-export default withAvailableFeatures(AnalysisCommand);
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/GitHubActionTutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/GitHubActionTutorial.tsx
deleted file mode 100644
index 06dbe899891..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/github-action/GitHubActionTutorial.tsx
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { BasicSeparator, Title, TutorialStep, TutorialStepList } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings';
-import { Component } from '../../../types/types';
-import { LoggedInUser } from '../../../types/users';
-import AllSet from '../components/AllSet';
-import YamlFileStep from '../components/YamlFileStep';
-import { TutorialConfig, TutorialModes } from '../types';
-import AnalysisCommand from './AnalysisCommand';
-import SecretStep from './SecretStep';
-
-export interface GitHubActionTutorialProps {
- almBinding?: AlmSettingsInstance;
- baseUrl: string;
- component: Component;
- currentUser: LoggedInUser;
- mainBranchName: string;
- monorepo?: boolean;
- willRefreshAutomatically?: boolean;
-}
-
-export default function GitHubActionTutorial(props: GitHubActionTutorialProps) {
- const {
- almBinding,
- baseUrl,
- currentUser,
- component,
- monorepo,
- mainBranchName,
- willRefreshAutomatically,
- } = props;
-
- const [config, setConfig] = React.useState<TutorialConfig>({});
- const [done, setDone] = React.useState<boolean>(false);
-
- React.useEffect(() => {
- setDone(Boolean(config.buildTool));
- }, [config.buildTool]);
-
- return (
- <>
- <Title>{translate('onboarding.tutorial.with.github_ci.title')}</Title>
- <TutorialStepList className="sw-mb-8">
- <TutorialStep
- title={translate('onboarding.tutorial.with.github_action.create_secret.title')}
- >
- <SecretStep
- almBinding={almBinding}
- baseUrl={baseUrl}
- component={component}
- currentUser={currentUser}
- monorepo={monorepo}
- />
- </TutorialStep>
- <TutorialStep title={translate('onboarding.tutorial.with.github_action.yaml.title')}>
- <YamlFileStep config={config} setConfig={setConfig} ci={TutorialModes.GitHubActions}>
- {(config) => (
- <AnalysisCommand
- config={config}
- mainBranchName={mainBranchName}
- component={component}
- monorepo={monorepo}
- />
- )}
- </YamlFileStep>
- </TutorialStep>
- {done && (
- <>
- <BasicSeparator className="sw-my-10" />
- <AllSet
- alm={almBinding?.alm || AlmKeys.GitHub}
- willRefreshAutomatically={willRefreshAutomatically}
- />
- </>
- )}
- </TutorialStepList>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/SecretStep.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/SecretStep.tsx
deleted file mode 100644
index 38f0f198ee8..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/github-action/SecretStep.tsx
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Link, LinkStandalone } from '@sonarsource/echoes-react';
-import { FormattedMessage } from 'react-intl';
-import {
- BasicSeparator,
- ClipboardIconButton,
- FlagMessage,
- NumberedList,
- NumberedListItem,
-} from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { useProjectBindingQuery } from '../../../queries/devops-integration';
-import { AlmSettingsInstance } from '../../../types/alm-settings';
-import { Component } from '../../../types/types';
-import { LoggedInUser } from '../../../types/users';
-import { InlineSnippet } from '../components/InlineSnippet';
-import SentenceWithHighlights from '../components/SentenceWithHighlights';
-import TokenStepGenerator from '../components/TokenStepGenerator';
-import { buildGithubLink } from '../utils';
-
-export interface SecretStepProps {
- almBinding?: AlmSettingsInstance;
- baseUrl: string;
- component: Component;
- currentUser: LoggedInUser;
- monorepo?: boolean;
-}
-
-export default function SecretStep(props: SecretStepProps) {
- const { almBinding, baseUrl, component, currentUser, monorepo } = props;
- const { data: projectBinding } = useProjectBindingQuery(component.key);
-
- return (
- <>
- <FormattedMessage
- defaultMessage={translate('onboarding.tutorial.with.github_action.secret.intro')}
- id="onboarding.tutorial.with.github_action.secret.intro"
- values={{
- settings_secret:
- almBinding && projectBinding ? (
- <LinkStandalone
- to={`${buildGithubLink(almBinding, projectBinding)}/settings/secrets`}
- shouldOpenInNewTab
- >
- {translate('onboarding.tutorial.with.github_action.secret.intro.link')}
- </LinkStandalone>
- ) : (
- <span className="sw-typo-semibold">
- {translate('onboarding.tutorial.with.github_action.secret.intro.link')}
- </span>
- ),
- }}
- />
- <NumberedList>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.github_action.secret.new"
- highlightKeys={['new_secret']}
- />
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.github_action.secret.name"
- highlightKeys={['name']}
- />
- <InlineSnippet snippet="SONAR_TOKEN" className="sw-ml-1" />
- <ClipboardIconButton copyValue="SONAR_TOKEN" className="sw-ml-2 sw-align-sub" />
- </NumberedListItem>
- <NumberedListItem>
- <TokenStepGenerator component={component} currentUser={currentUser} />
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.github_action.secret.add"
- highlightKeys={['add_secret']}
- />
- {monorepo && (
- <FlagMessage variant="info" className="sw-block sw-w-fit sw-mt-4">
- <div>
- <div>
- <FormattedMessage
- id="onboarding.tutorial.with.github_action.create_secret.monorepo_project_level_token_info"
- values={{
- link: (
- <Link to="/account/security">
- <FormattedMessage id="onboarding.tutorial.with.github_action.create_secret.monorepo_project_level_token_info.link" />
- </Link>
- ),
- }}
- />
- </div>
- <div className="sw-mt-2">
- <FormattedMessage id="onboarding.tutorial.with.github_action.create_secret.monorepo_global_token_info" />
- </div>
- </div>
- </FlagMessage>
- )}
- </NumberedListItem>
- </NumberedList>
- <BasicSeparator className="sw-my-6" />
- <NumberedList>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.github_action.secret.new"
- highlightKeys={['new_secret']}
- />
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.github_action.secret.name"
- highlightKeys={['name']}
- />
- <InlineSnippet snippet="SONAR_HOST_URL" className="sw-ml-1" />
- <ClipboardIconButton copyValue="SONAR_HOST_URL" className="sw-ml-2 sw-align-sub" />
- </NumberedListItem>
- <NumberedListItem>
- <FormattedMessage
- defaultMessage={translate('onboarding.tutorial.env_variables')}
- id="onboarding.tutorial.env_variables"
- values={{
- extra: <ClipboardIconButton copyValue={baseUrl} className="sw-ml-1 sw-align-sub" />,
- field: (
- <span className="sw-typo-semibold">
- {translate('onboarding.tutorial.env_variables.field')}
- </span>
- ),
- value: <InlineSnippet snippet={baseUrl} className="sw-ml-1" />,
- }}
- />
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- translationKey="onboarding.tutorial.with.github_action.secret.add"
- highlightKeys={['add_secret']}
- />
- </NumberedListItem>
- </NumberedList>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/GithubActionTutorial-it.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/GithubActionTutorial-it.tsx
deleted file mode 100644
index 84859f187fa..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/GithubActionTutorial-it.tsx
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import AlmSettingsServiceMock from '../../../../api/mocks/AlmSettingsServiceMock';
-import UserTokensMock from '../../../../api/mocks/UserTokensMock';
-import { mockAlmSettingsInstance } from '../../../../helpers/mocks/alm-settings';
-import { mockComponent } from '../../../../helpers/mocks/component';
-import { mockLanguage, mockLoggedInUser } from '../../../../helpers/testMocks';
-import { RenderContext, renderApp } from '../../../../helpers/testReactTestingUtils';
-import { byRole } from '../../../../sonar-aligned/helpers/testSelector';
-import { AlmKeys } from '../../../../types/alm-settings';
-import { Feature } from '../../../../types/features';
-import {
- getCommonNodes,
- getCopyToClipboardHostURLValue,
- getCopyToClipboardValue,
- getTutorialActionButtons,
- getTutorialBuildButtons,
-} from '../../test-utils';
-import { GradleBuildDSL, TutorialModes } from '../../types';
-import GitHubActionTutorial, { GitHubActionTutorialProps } from '../GitHubActionTutorial';
-
-jest.mock('../../../../api/settings', () => ({
- getAllValues: jest.fn().mockResolvedValue([]),
-}));
-
-const tokenMock = new UserTokensMock();
-const almMock = new AlmSettingsServiceMock();
-
-afterEach(() => {
- tokenMock.reset();
- almMock.reset();
-});
-
-const ui = {
- ...getCommonNodes(TutorialModes.GitHubActions),
- ...getTutorialActionButtons(),
- ...getTutorialBuildButtons(),
-};
-
-it('should follow and complete all steps', async () => {
- const user = userEvent.setup();
- renderGithubActionTutorial();
-
- expect(await ui.secretsStepTitle.find()).toBeInTheDocument();
-
- // Env variables step
- expect(
- getCopyToClipboardValue({ i: 0, name: 'Copy to clipboard', inlineSnippet: true }),
- ).toMatchSnapshot('sonar token key');
- expect(
- getCopyToClipboardValue({ i: 1, name: 'Copy to clipboard', inlineSnippet: true }),
- ).toMatchSnapshot('sonarqube host url key');
- expect(getCopyToClipboardHostURLValue({ i: 2, name: 'Copy to clipboard' })).toMatchSnapshot(
- 'sonarqube host url value',
- );
-
- // Create/update configuration file step
- // Maven
- await user.click(ui.mavenBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'Maven: .github/workflows/build.yml',
- );
-
- // Gradle
- await user.click(ui.gradleBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot('Groovy: build.gradle');
- await user.click(ui.gradleDSLButton(GradleBuildDSL.Kotlin).get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'Kotlin: build.gradle.kts',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'Gradle: .github/workflows/build.yml',
- );
-
- // .NET
- await user.click(ui.dotnetBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- '.NET: .github/workflows/build.yml',
- );
-
- // Cpp
- await user.click(ui.cppBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'C++ (automatic) and other: sonar-project.properties',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'C++ (automatic) and other: .github/workflows/build.yml',
- );
-
- await user.click(ui.autoConfigManual.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'C++: sonar-project.properties',
- );
- await user.click(ui.linuxButton.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'C++ Linux: .github/workflows/build.yml',
- );
- await user.click(ui.arm64Button.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'C++ Linux arm64: .github/workflows/build.yml',
- );
- await user.click(ui.windowsButton.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'C++ Windows: .github/workflows/build.yml',
- );
- await user.click(ui.macosButton.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'C++ MacOS: .github/workflows/build.yml',
- );
-
- // Objective-C
- await user.click(ui.objCBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'Objective-C: sonar-project.properties',
- );
-
- await user.click(ui.linuxButton.get());
- await user.click(ui.x86_64Button.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'Objective-C Linux: .github/workflows/build.yml',
- );
- await user.click(ui.arm64Button.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'Objective-C Linux arm64: .github/workflows/build.yml',
- );
- await user.click(ui.windowsButton.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'Objective-C Windows: .github/workflows/build.yml',
- );
- await user.click(ui.macosButton.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'Objective-C MacOS: .github/workflows/build.yml',
- );
-
- // Dart
- await user.click(ui.dartBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'Dart: sonar-project.properties',
- );
-
- await user.click(ui.linuxButton.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'Dart Linux: .github/workflows/build.yml',
- );
- await user.click(ui.windowsButton.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'Dart Windows: .github/workflows/build.yml',
- );
- await user.click(ui.macosButton.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'Dart MacOS: .github/workflows/build.yml',
- );
-
- // Other
- await user.click(ui.otherBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'C++ (automatic) and other: sonar-project.properties',
- );
-
- await user.click(ui.linuxButton.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'C++ (automatic) and other Linux: .github/workflows/build.yml',
- );
- await user.click(ui.windowsButton.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'C++ (automatic) and other Windows: .github/workflows/build.yml',
- );
- await user.click(ui.macosButton.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'C++ (automatic) and other MacOS: .github/workflows/build.yml',
- );
-
- expect(ui.allSetSentence.get()).toBeInTheDocument();
-});
-
-it('should generate/delete a new token or use existing one', async () => {
- const user = userEvent.setup();
- renderGithubActionTutorial();
-
- expect(await ui.secretsStepTitle.find()).toBeInTheDocument();
-
- // Generate token
- await user.click(ui.genTokenDialogButton.get());
- await user.click(ui.generateTokenButton.get());
- expect(getCopyToClipboardValue({ inlineSnippet: true })).toEqual('generatedtoken2');
-
- // Revoke current token and create new one
- await user.click(ui.deleteTokenButton.get());
- await user.type(ui.tokenNameInput.get(), 'newtoken');
-
- await user.click(ui.expiresInSelect.get());
- await user.click(byRole('option', { name: 'users.tokens.expiration.365' }).get());
-
- await user.click(ui.generateTokenButton.get());
- expect(ui.tokenValue.get()).toBeInTheDocument();
- await user.click(ui.continueButton.getAll()[0]);
- expect(ui.tokenValue.query()).not.toBeInTheDocument();
-});
-
-it('navigates between steps', async () => {
- const user = userEvent.setup();
- almMock.handleSetProjectBinding(AlmKeys.GitHub, {
- almSetting: 'my-project',
- project: 'my-project',
- repository: 'my-project',
- monorepo: true,
- });
- renderGithubActionTutorial({
- almBinding: mockAlmSettingsInstance({
- alm: AlmKeys.GitHub,
- url: 'http://localhost/qube',
- }),
- });
-
- // If project is bound, link to repo is visible
- expect(await ui.linkToRepo.find()).toBeInTheDocument();
-
- await user.click(ui.mavenBuildButton.get());
- expect(ui.allSetSentence.get()).toBeInTheDocument();
-
- await user.click(ui.ymlFileStepTitle.get());
- expect(ui.mavenBuildButton.get()).toBeInTheDocument();
- await user.click(ui.secretsStepTitle.get());
- expect(ui.genTokenDialogButton.get()).toBeInTheDocument();
-});
-
-function renderGithubActionTutorial(
- overrides: Partial<GitHubActionTutorialProps> = {},
- { languages = { c: mockLanguage({ key: 'c' }) } }: RenderContext = {},
-) {
- return renderApp(
- '/',
- <GitHubActionTutorial
- baseUrl="http://localhost:9000"
- mainBranchName="main"
- component={mockComponent()}
- currentUser={mockLoggedInUser()}
- {...overrides}
- />,
- { languages, featureList: [Feature.BranchSupport] },
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/GithubActionTutorial-it.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/GithubActionTutorial-it.tsx.snap
deleted file mode 100644
index eee03b96041..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/__snapshots__/GithubActionTutorial-it.tsx.snap
+++ /dev/null
@@ -1,708 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should follow and complete all steps: .NET: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: windows-latest
-
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Set up JDK 17
- uses: actions/setup-java@v4
- with:
- java-version: 17
- distribution: 'zulu' # Alternative distribution options are available.
- - name: Cache SonarQube packages
- uses: actions/cache@v4
- with:
- path: ~\\.sonar\\cache
- key: \${{ runner.os }}-sonar
- restore-keys: \${{ runner.os }}-sonar
- - name: Cache SonarQube scanner
- id: cache-sonar-scanner
- uses: actions/cache@v4
- with:
- path: .\\.sonar\\scanner
- key: \${{ runner.os }}-sonar-scanner
- restore-keys: \${{ runner.os }}-sonar-scanner
- - name: Install SonarQube scanner
- if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
- shell: powershell
- run: |
- New-Item -Path .\\.sonar\\scanner -ItemType Directory
- dotnet tool update dotnet-sonarscanner --tool-path .\\.sonar\\scanner
- - name: Build and analyze
- shell: powershell
- run: |
- .\\.sonar\\scanner\\dotnet-sonarscanner begin /k:"my-project" /d:sonar.token="\${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="\${{ secrets.SONAR_HOST_URL }}"
- dotnet build
- .\\.sonar\\scanner\\dotnet-sonarscanner end /d:sonar.token="\${{ secrets.SONAR_TOKEN }}""
-`;
-
-exports[`should follow and complete all steps: C++ (automatic) and other Linux: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - uses: sonarsource/sonarqube-scan-action@v4
- env:
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
- # If you wish to fail your job when the Quality Gate is red, uncomment the
- # following lines. This would typically be used to fail a deployment.
- # We do not recommend to use this in a pull request. Prefer using pull request
- # decoration instead.
- # - uses: sonarsource/sonarqube-quality-gate-action@v1
- # timeout-minutes: 5
- # env:
- # SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}"
-`;
-
-exports[`should follow and complete all steps: C++ (automatic) and other MacOS: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: macos-latest
-
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - uses: sonarsource/sonarqube-scan-action@v4
- env:
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
- # If you wish to fail your job when the Quality Gate is red, uncomment the
- # following lines. This would typically be used to fail a deployment.
- # We do not recommend to use this in a pull request. Prefer using pull request
- # decoration instead.
- # - uses: sonarsource/sonarqube-quality-gate-action@v1
- # timeout-minutes: 5
- # env:
- # SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}"
-`;
-
-exports[`should follow and complete all steps: C++ (automatic) and other Windows: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: windows-latest
-
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - uses: sonarsource/sonarqube-scan-action@v4
- env:
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
- # If you wish to fail your job when the Quality Gate is red, uncomment the
- # following lines. This would typically be used to fail a deployment.
- # We do not recommend to use this in a pull request. Prefer using pull request
- # decoration instead.
- # - uses: sonarsource/sonarqube-quality-gate-action@v1
- # timeout-minutes: 5
- # env:
- # SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}"
-`;
-
-exports[`should follow and complete all steps: C++ (automatic) and other: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - uses: sonarsource/sonarqube-scan-action@v4
- env:
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
- # If you wish to fail your job when the Quality Gate is red, uncomment the
- # following lines. This would typically be used to fail a deployment.
- # We do not recommend to use this in a pull request. Prefer using pull request
- # decoration instead.
- # - uses: sonarsource/sonarqube-quality-gate-action@v1
- # timeout-minutes: 5
- # env:
- # SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}"
-`;
-
-exports[`should follow and complete all steps: C++ (automatic) and other: sonar-project.properties 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`should follow and complete all steps: C++ (automatic) and other: sonar-project.properties 2`] = `"sonar.projectKey=my-project"`;
-
-exports[`should follow and complete all steps: C++ Linux arm64: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: ubuntu-latest
- env:
- BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Install sonar-scanner and build-wrapper
- env:
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- uses: SonarSource/sonarqube-github-c-cpp@v2
- - name: Run build-wrapper
- run: |
- build-wrapper-linux-aarch64 --out-dir \${{ env.BUILD_WRAPPER_OUT_DIR }} <insert_your_clean_build_command>
- - name: Run sonar-scanner
- env:
- GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- run: |
- sonar-scanner -Dsonar.cfamily.compile-commands="\${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json""
-`;
-
-exports[`should follow and complete all steps: C++ Linux: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: ubuntu-latest
- env:
- BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Install sonar-scanner and build-wrapper
- env:
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- uses: SonarSource/sonarqube-github-c-cpp@v2
- - name: Run build-wrapper
- run: |
- build-wrapper-linux-x86-64 --out-dir \${{ env.BUILD_WRAPPER_OUT_DIR }} <insert_your_clean_build_command>
- - name: Run sonar-scanner
- env:
- GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- run: |
- sonar-scanner -Dsonar.cfamily.compile-commands="\${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json""
-`;
-
-exports[`should follow and complete all steps: C++ MacOS: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: macos-latest
- env:
- BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Install sonar-scanner and build-wrapper
- env:
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- uses: SonarSource/sonarqube-github-c-cpp@v2
- - name: Run build-wrapper
- run: |
- build-wrapper-macosx-x86 --out-dir \${{ env.BUILD_WRAPPER_OUT_DIR }} <insert_your_clean_build_command>
- - name: Run sonar-scanner
- env:
- GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- run: |
- sonar-scanner -Dsonar.cfamily.compile-commands="\${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json""
-`;
-
-exports[`should follow and complete all steps: C++ Windows: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: windows-latest
- env:
- BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Install sonar-scanner and build-wrapper
- env:
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- uses: SonarSource/sonarqube-github-c-cpp@v2
- - name: Run build-wrapper
- run: |
- build-wrapper-win-x86-64 --out-dir \${{ env.BUILD_WRAPPER_OUT_DIR }} <insert_your_clean_build_command>
- - name: Run sonar-scanner
- env:
- GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- run: |
- sonar-scanner -Dsonar.cfamily.compile-commands="\${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json""
-`;
-
-exports[`should follow and complete all steps: C++: sonar-project.properties 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`should follow and complete all steps: Dart Linux: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- # The analysis requires to retrieve dependencies and build successfully
- - name: Build project
- run: <commands to build your project>
- - uses: sonarsource/sonarqube-scan-action@v4
- env:
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
- # If you wish to fail your job when the Quality Gate is red, uncomment the
- # following lines. This would typically be used to fail a deployment.
- # We do not recommend to use this in a pull request. Prefer using pull request
- # decoration instead.
- # - uses: sonarsource/sonarqube-quality-gate-action@v1
- # timeout-minutes: 5
- # env:
- # SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}"
-`;
-
-exports[`should follow and complete all steps: Dart MacOS: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: macos-latest
-
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- # The analysis requires to retrieve dependencies and build successfully
- - name: Build project
- run: <commands to build your project>
- - uses: sonarsource/sonarqube-scan-action@v4
- env:
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
- # If you wish to fail your job when the Quality Gate is red, uncomment the
- # following lines. This would typically be used to fail a deployment.
- # We do not recommend to use this in a pull request. Prefer using pull request
- # decoration instead.
- # - uses: sonarsource/sonarqube-quality-gate-action@v1
- # timeout-minutes: 5
- # env:
- # SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}"
-`;
-
-exports[`should follow and complete all steps: Dart Windows: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: windows-latest
-
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- # The analysis requires to retrieve dependencies and build successfully
- - name: Build project
- run: <commands to build your project>
- - uses: sonarsource/sonarqube-scan-action@v4
- env:
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
- # If you wish to fail your job when the Quality Gate is red, uncomment the
- # following lines. This would typically be used to fail a deployment.
- # We do not recommend to use this in a pull request. Prefer using pull request
- # decoration instead.
- # - uses: sonarsource/sonarqube-quality-gate-action@v1
- # timeout-minutes: 5
- # env:
- # SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}"
-`;
-
-exports[`should follow and complete all steps: Dart: sonar-project.properties 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`should follow and complete all steps: Gradle: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Set up JDK 17
- uses: actions/setup-java@v4
- with:
- java-version: 17
- distribution: 'zulu' # Alternative distribution options are available.
- - name: Cache SonarQube packages
- uses: actions/cache@v4
- with:
- path: ~/.sonar/cache
- key: \${{ runner.os }}-sonar
- restore-keys: \${{ runner.os }}-sonar
- - name: Cache Gradle packages
- uses: actions/cache@v4
- with:
- path: ~/.gradle/caches
- key: \${{ runner.os }}-gradle-\${{ hashFiles('**/*.gradle') }}
- restore-keys: \${{ runner.os }}-gradle
- - name: Build and analyze
- env:
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
- run: ./gradlew build sonar --info"
-`;
-
-exports[`should follow and complete all steps: Groovy: build.gradle 1`] = `
-"plugins {
- id "org.sonarqube" version "6.0.1.5171"
-}
-
-sonar {
- properties {
- property "sonar.projectKey", "my-project"
- property "sonar.projectName", "MyProject"
- }
-}"
-`;
-
-exports[`should follow and complete all steps: Kotlin: build.gradle.kts 1`] = `
-"plugins {
- id("org.sonarqube") version "6.0.1.5171"
-}
-
-sonar {
- properties {
- property("sonar.projectKey", "my-project")
- property("sonar.projectName", "MyProject")
- }
-}"
-`;
-
-exports[`should follow and complete all steps: Maven: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Set up JDK 17
- uses: actions/setup-java@v4
- with:
- java-version: 17
- distribution: 'zulu' # Alternative distribution options are available.
- - name: Cache SonarQube packages
- uses: actions/cache@v4
- with:
- path: ~/.sonar/cache
- key: \${{ runner.os }}-sonar
- restore-keys: \${{ runner.os }}-sonar
- - name: Cache Maven packages
- uses: actions/cache@v4
- with:
- path: ~/.m2
- key: \${{ runner.os }}-m2-\${{ hashFiles('**/pom.xml') }}
- restore-keys: \${{ runner.os }}-m2
- - name: Build and analyze
- env:
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
- run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=my-project -Dsonar.projectName='MyProject'"
-`;
-
-exports[`should follow and complete all steps: Objective-C Linux arm64: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: ubuntu-latest
- env:
- BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Install sonar-scanner and build-wrapper
- env:
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- uses: SonarSource/sonarqube-github-c-cpp@v2
- - name: Run build-wrapper
- run: |
- build-wrapper-linux-aarch64 --out-dir \${{ env.BUILD_WRAPPER_OUT_DIR }} <insert_your_clean_build_command>
- - name: Run sonar-scanner
- env:
- GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- run: |
- sonar-scanner -Dsonar.cfamily.compile-commands="\${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json""
-`;
-
-exports[`should follow and complete all steps: Objective-C Linux: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: ubuntu-latest
- env:
- BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Install sonar-scanner and build-wrapper
- env:
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- uses: SonarSource/sonarqube-github-c-cpp@v2
- - name: Run build-wrapper
- run: |
- build-wrapper-linux-x86-64 --out-dir \${{ env.BUILD_WRAPPER_OUT_DIR }} <insert_your_clean_build_command>
- - name: Run sonar-scanner
- env:
- GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- run: |
- sonar-scanner -Dsonar.cfamily.compile-commands="\${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json""
-`;
-
-exports[`should follow and complete all steps: Objective-C MacOS: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: macos-latest
- env:
- BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Install sonar-scanner and build-wrapper
- env:
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- uses: SonarSource/sonarqube-github-c-cpp@v2
- - name: Run build-wrapper
- run: |
- build-wrapper-macosx-x86 --out-dir \${{ env.BUILD_WRAPPER_OUT_DIR }} <insert_your_clean_build_command>
- - name: Run sonar-scanner
- env:
- GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- run: |
- sonar-scanner -Dsonar.cfamily.compile-commands="\${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json""
-`;
-
-exports[`should follow and complete all steps: Objective-C Windows: .github/workflows/build.yml 1`] = `
-"name: Build
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened]
-
-jobs:
- build:
- name: Build and analyze
- runs-on: windows-latest
- env:
- BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Install sonar-scanner and build-wrapper
- env:
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- uses: SonarSource/sonarqube-github-c-cpp@v2
- - name: Run build-wrapper
- run: |
- build-wrapper-win-x86-64 --out-dir \${{ env.BUILD_WRAPPER_OUT_DIR }} <insert_your_clean_build_command>
- - name: Run sonar-scanner
- env:
- GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- run: |
- sonar-scanner -Dsonar.cfamily.compile-commands="\${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json""
-`;
-
-exports[`should follow and complete all steps: Objective-C: sonar-project.properties 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`should follow and complete all steps: sonar token key 1`] = `"SONAR_TOKEN"`;
-
-exports[`should follow and complete all steps: sonarqube host url key 1`] = `"SONAR_HOST_URL"`;
-
-exports[`should follow and complete all steps: sonarqube host url value 1`] = `"http://localhost:9000"`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/CFamily.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/CFamily.tsx
deleted file mode 100644
index 4f6159eba74..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/CFamily.tsx
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { NumberedListItem } from '~design-system';
-import { translate } from '../../../../helpers/l10n';
-import { Component } from '../../../../types/types';
-import { CompilationInfo } from '../../components/CompilationInfo';
-import CreateYmlFile from '../../components/CreateYmlFile';
-import DefaultProjectKey from '../../components/DefaultProjectKey';
-import GithubCFamilyExampleRepositories from '../../components/GithubCFamilyExampleRepositories';
-import RenderOptions from '../../components/RenderOptions';
-import { Arch, AutoConfig, BuildTools, OSs, TutorialConfig, TutorialModes } from '../../types';
-import { getBuildWrapperExecutableLinux } from '../../utils';
-import { generateGitHubActionsYaml } from '../utils';
-import MonorepoDocLinkFallback from './MonorepoDocLinkFallback';
-import Others from './Others';
-
-export interface CFamilyProps {
- branchesEnabled?: boolean;
- component: Component;
- config: TutorialConfig;
- mainBranchName: string;
- monorepo?: boolean;
-}
-
-const STEPS = (os?: OSs, arch?: Arch) => {
- if (OSs.Linux === os) {
- return `
- - name: Install sonar-scanner and build-wrapper
- env:
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- uses: SonarSource/sonarqube-github-c-cpp@v2
- - name: Run build-wrapper
- run: |
- ${getBuildWrapperExecutableLinux(arch)} --out-dir \${{ env.BUILD_WRAPPER_OUT_DIR }} <insert_your_clean_build_command>
- - name: Run sonar-scanner
- env:
- GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- run: |
- sonar-scanner -Dsonar.cfamily.compile-commands="\${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json"`;
- } else if (OSs.MacOS === os) {
- return `
- - name: Install sonar-scanner and build-wrapper
- env:
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- uses: SonarSource/sonarqube-github-c-cpp@v2
- - name: Run build-wrapper
- run: |
- build-wrapper-macosx-x86 --out-dir \${{ env.BUILD_WRAPPER_OUT_DIR }} <insert_your_clean_build_command>
- - name: Run sonar-scanner
- env:
- GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- run: |
- sonar-scanner -Dsonar.cfamily.compile-commands="\${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json"`;
- } else if (OSs.Windows === os) {
- return `
- - name: Install sonar-scanner and build-wrapper
- env:
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- uses: SonarSource/sonarqube-github-c-cpp@v2
- - name: Run build-wrapper
- run: |
- build-wrapper-win-x86-64 --out-dir \${{ env.BUILD_WRAPPER_OUT_DIR }} <insert_your_clean_build_command>
- - name: Run sonar-scanner
- env:
- GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{secrets.SONAR_HOST_URL}}
- run: |
- sonar-scanner -Dsonar.cfamily.compile-commands="\${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json"`;
- }
-
- return '';
-};
-
-export default function CFamily(props: Readonly<CFamilyProps>) {
- const { config, component, branchesEnabled, mainBranchName, monorepo } = props;
- const [os, setOs] = React.useState<OSs>(OSs.Linux);
- const [arch, setArch] = React.useState<Arch>(Arch.X86_64);
-
- if (config.buildTool === BuildTools.Cpp && config.autoConfig === AutoConfig.Automatic) {
- return <Others buildSteps="" {...props} />;
- }
-
- const runsOn = {
- [OSs.Linux]: 'ubuntu-latest',
- [OSs.MacOS]: 'macos-latest',
- [OSs.Windows]: 'windows-latest',
- };
- return (
- <>
- <DefaultProjectKey component={component} monorepo={monorepo} />
- <NumberedListItem>
- <span>{translate('onboarding.build.other.os')}</span>
- <RenderOptions
- label={translate('onboarding.build.other.os')}
- checked={os}
- onCheck={(value: OSs) => setOs(value)}
- optionLabelKey="onboarding.build.other.os"
- options={Object.values(OSs)}
- />
- {os === OSs.Linux && (
- <>
- <div className="sw-mt-4">{translate('onboarding.build.other.architecture')}</div>
- <RenderOptions
- label={translate('onboarding.build.other.architecture')}
- checked={arch}
- onCheck={(value: Arch) => setArch(value)}
- optionLabelKey="onboarding.build.other.architecture"
- options={[Arch.X86_64, Arch.Arm64]}
- />
- </>
- )}
- <GithubCFamilyExampleRepositories
- className="sw-mt-4 sw-w-abs-600"
- os={os}
- ci={TutorialModes.GitHubActions}
- />
- </NumberedListItem>
- {monorepo ? (
- <MonorepoDocLinkFallback />
- ) : (
- <>
- <CreateYmlFile
- yamlFileName=".github/workflows/build.yml"
- yamlTemplate={generateGitHubActionsYaml(
- mainBranchName,
- !!branchesEnabled,
- runsOn[os],
- STEPS(os, arch),
- `env:
- BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed`,
- )}
- />
- <CompilationInfo />
- </>
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/DotNet.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/DotNet.tsx
deleted file mode 100644
index baa22814624..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/DotNet.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Component } from '../../../../types/types';
-import CreateYmlFile from '../../components/CreateYmlFile';
-import { GITHUB_ACTIONS_RUNS_ON_WINDOWS } from '../constants';
-import { generateGitHubActionsYaml } from '../utils';
-import MonorepoDocLinkFallback from './MonorepoDocLinkFallback';
-
-export interface DotNetProps {
- branchesEnabled?: boolean;
- component: Component;
- mainBranchName: string;
- monorepo?: boolean;
-}
-
-function dotnetYamlSteps(projectKey: string) {
- return `
- - name: Set up JDK 17
- uses: actions/setup-java@v4
- with:
- java-version: 17
- distribution: 'zulu' # Alternative distribution options are available.
- - name: Cache SonarQube packages
- uses: actions/cache@v4
- with:
- path: ~\\.sonar\\cache
- key: \${{ runner.os }}-sonar
- restore-keys: \${{ runner.os }}-sonar
- - name: Cache SonarQube scanner
- id: cache-sonar-scanner
- uses: actions/cache@v4
- with:
- path: .\\.sonar\\scanner
- key: \${{ runner.os }}-sonar-scanner
- restore-keys: \${{ runner.os }}-sonar-scanner
- - name: Install SonarQube scanner
- if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
- shell: powershell
- run: |
- New-Item -Path .\\.sonar\\scanner -ItemType Directory
- dotnet tool update dotnet-sonarscanner --tool-path .\\.sonar\\scanner
- - name: Build and analyze
- shell: powershell
- run: |
- .\\.sonar\\scanner\\dotnet-sonarscanner begin /k:"${projectKey}" /d:sonar.token="\${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="\${{ secrets.SONAR_HOST_URL }}"
- dotnet build
- .\\.sonar\\scanner\\dotnet-sonarscanner end /d:sonar.token="\${{ secrets.SONAR_TOKEN }}"`;
-}
-
-export default function DotNet(props: DotNetProps) {
- const { component, branchesEnabled, mainBranchName, monorepo } = props;
-
- if (monorepo) {
- return <MonorepoDocLinkFallback />;
- }
-
- return (
- <CreateYmlFile
- yamlFileName=".github/workflows/build.yml"
- yamlTemplate={generateGitHubActionsYaml(
- mainBranchName,
- !!branchesEnabled,
- GITHUB_ACTIONS_RUNS_ON_WINDOWS,
- dotnetYamlSteps(component.key),
- )}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/Gradle.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/Gradle.tsx
deleted file mode 100644
index 971a27728cc..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/Gradle.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Component } from '../../../../types/types';
-import CreateYmlFile from '../../components/CreateYmlFile';
-import GradleBuild from '../../components/GradleBuild';
-import { GITHUB_ACTIONS_RUNS_ON_LINUX } from '../constants';
-import { generateGitHubActionsYaml } from '../utils';
-import MonorepoDocLinkFallback from './MonorepoDocLinkFallback';
-
-export interface GradleProps {
- branchesEnabled?: boolean;
- component: Component;
- mainBranchName: string;
- monorepo?: boolean;
-}
-
-const GRADLE_YAML_STEPS = `
- - name: Set up JDK 17
- uses: actions/setup-java@v4
- with:
- java-version: 17
- distribution: 'zulu' # Alternative distribution options are available.
- - name: Cache SonarQube packages
- uses: actions/cache@v4
- with:
- path: ~/.sonar/cache
- key: \${{ runner.os }}-sonar
- restore-keys: \${{ runner.os }}-sonar
- - name: Cache Gradle packages
- uses: actions/cache@v4
- with:
- path: ~/.gradle/caches
- key: \${{ runner.os }}-gradle-\${{ hashFiles('**/*.gradle') }}
- restore-keys: \${{ runner.os }}-gradle
- - name: Build and analyze
- env:
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
- run: ./gradlew build sonar --info`;
-
-export default function Gradle(props: GradleProps) {
- const { component, branchesEnabled, mainBranchName, monorepo } = props;
-
- return (
- <>
- <GradleBuild component={component} />
-
- {monorepo ? (
- <MonorepoDocLinkFallback />
- ) : (
- <CreateYmlFile
- yamlFileName=".github/workflows/build.yml"
- yamlTemplate={generateGitHubActionsYaml(
- mainBranchName,
- !!branchesEnabled,
- GITHUB_ACTIONS_RUNS_ON_LINUX,
- GRADLE_YAML_STEPS,
- )}
- />
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/JavaMaven.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/JavaMaven.tsx
deleted file mode 100644
index db8713ed716..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/JavaMaven.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Component } from '../../../../types/types';
-import CreateYmlFile from '../../components/CreateYmlFile';
-import { GITHUB_ACTIONS_RUNS_ON_LINUX } from '../constants';
-import { generateGitHubActionsYaml } from '../utils';
-import MonorepoDocLinkFallback from './MonorepoDocLinkFallback';
-
-export interface JavaMavenProps {
- branchesEnabled?: boolean;
- component: Component;
- mainBranchName: string;
- monorepo?: boolean;
-}
-
-function mavenYamlSteps(projectKey: string, projectName: string) {
- return `
- - name: Set up JDK 17
- uses: actions/setup-java@v4
- with:
- java-version: 17
- distribution: 'zulu' # Alternative distribution options are available.
- - name: Cache SonarQube packages
- uses: actions/cache@v4
- with:
- path: ~/.sonar/cache
- key: \${{ runner.os }}-sonar
- restore-keys: \${{ runner.os }}-sonar
- - name: Cache Maven packages
- uses: actions/cache@v4
- with:
- path: ~/.m2
- key: \${{ runner.os }}-m2-\${{ hashFiles('**/pom.xml') }}
- restore-keys: \${{ runner.os }}-m2
- - name: Build and analyze
- env:
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
- run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=${projectKey} -Dsonar.projectName='${projectName}'`;
-}
-
-export default function JavaMaven(props: JavaMavenProps) {
- const { component, branchesEnabled, mainBranchName, monorepo } = props;
-
- if (monorepo) {
- return <MonorepoDocLinkFallback />;
- }
-
- return (
- <CreateYmlFile
- yamlFileName=".github/workflows/build.yml"
- yamlTemplate={generateGitHubActionsYaml(
- mainBranchName,
- !!branchesEnabled,
- GITHUB_ACTIONS_RUNS_ON_LINUX,
- mavenYamlSteps(component.key, component.name),
- )}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/MonorepoDocLinkFallback.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/MonorepoDocLinkFallback.tsx
deleted file mode 100644
index b1b73a8d452..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/MonorepoDocLinkFallback.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { NumberedListItem } from '~design-system';
-import { DocLink } from '../../../../helpers/doc-links';
-import { translate } from '../../../../helpers/l10n';
-import DocumentationLink from '../../../common/DocumentationLink';
-
-export default function MonorepoDocLinkFallback() {
- return (
- <NumberedListItem>
- <DocumentationLink className="sw-mt-4" to={DocLink.AlmGitHubMonorepoWorkfileExample}>
- {translate('onboarding.tutorial.with.github_action.monorepo.see_yaml_instructions')}
- </DocumentationLink>
- </NumberedListItem>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/Others.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/commands/Others.tsx
deleted file mode 100644
index f74a2da0f41..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/github-action/commands/Others.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { NumberedListItem } from '~design-system';
-import { translate } from '../../../../helpers/l10n';
-import { Component } from '../../../../types/types';
-import CreateYmlFile from '../../components/CreateYmlFile';
-import DefaultProjectKey from '../../components/DefaultProjectKey';
-import RenderOptions from '../../components/RenderOptions';
-import { OSs } from '../../types';
-import { generateGitHubActionsYaml } from '../utils';
-import MonorepoDocLinkFallback from './MonorepoDocLinkFallback';
-
-export interface OthersProps {
- branchesEnabled?: boolean;
- buildSteps: string;
- component: Component;
- mainBranchName: string;
- monorepo?: boolean;
-}
-
-function otherYamlSteps(buildSteps: string, branchesEnabled: boolean) {
- let output =
- buildSteps +
- `
- - uses: sonarsource/sonarqube-scan-action@v4
- env:
- SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: \${{ secrets.SONAR_HOST_URL }}
- # If you wish to fail your job when the Quality Gate is red, uncomment the
- # following lines. This would typically be used to fail a deployment.`;
-
- if (branchesEnabled) {
- output += `
- # We do not recommend to use this in a pull request. Prefer using pull request
- # decoration instead.`;
- }
-
- output += `
- # - uses: sonarsource/sonarqube-quality-gate-action@v1
- # timeout-minutes: 5
- # env:
- # SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}`;
-
- return output;
-}
-
-export default function Others(props: OthersProps) {
- const runsOn = {
- [OSs.Linux]: 'ubuntu-latest',
- [OSs.MacOS]: 'macos-latest',
- [OSs.Windows]: 'windows-latest',
- };
-
- const { component, branchesEnabled, mainBranchName, monorepo, buildSteps } = props;
- const [os, setOs] = React.useState<OSs>(OSs.Linux);
-
- return (
- <>
- <DefaultProjectKey component={component} monorepo={monorepo} />
- <NumberedListItem>
- <span>{translate('onboarding.build.other.os')}</span>
- <RenderOptions
- label={translate('onboarding.build.other.os')}
- checked={os}
- onCheck={(value: OSs) => setOs(value)}
- optionLabelKey="onboarding.build.other.os"
- options={Object.values(OSs)}
- />
- </NumberedListItem>
- {monorepo ? (
- <MonorepoDocLinkFallback />
- ) : (
- <CreateYmlFile
- yamlFileName=".github/workflows/build.yml"
- yamlTemplate={generateGitHubActionsYaml(
- mainBranchName,
- !!branchesEnabled,
- runsOn[os],
- otherYamlSteps(buildSteps, !!branchesEnabled),
- )}
- />
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/constants.ts b/server/sonar-web/src/main/js/components/tutorials/github-action/constants.ts
deleted file mode 100644
index b8dd07dddd7..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/github-action/constants.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export const GITHUB_ACTIONS_RUNS_ON_LINUX = 'ubuntu-latest';
-export const GITHUB_ACTIONS_RUNS_ON_WINDOWS = 'windows-latest';
diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/utils.ts b/server/sonar-web/src/main/js/components/tutorials/github-action/utils.ts
deleted file mode 100644
index 191a45f5101..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/github-action/utils.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export function generateGitHubActionsYaml(
- mainBranchName: string,
- branchesEnabled: boolean,
- runsOn: string,
- steps: string,
- additionalConfig?: string,
-) {
- return `name: Build
-
-on:
- push:
- branches:
- - ${mainBranchName}
-${branchesEnabled ? ' pull_request:\n types: [opened, synchronize, reopened]' : ''}
-
-jobs:
- build:
- name: Build and analyze
- runs-on: ${runsOn}
- ${additionalConfig ?? ''}
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis${steps}`;
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx
deleted file mode 100644
index 103b2c85690..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import {
- BasicSeparator,
- ClipboardIconButton,
- ListItem,
- NumberedList,
- NumberedListItem,
- TutorialStep,
- UnorderedList,
-} from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { Component } from '../../../types/types';
-import { LoggedInUser } from '../../../types/users';
-import { InlineSnippet } from '../components/InlineSnippet';
-import TokenStepGenerator from '../components/TokenStepGenerator';
-
-export interface EnvironmentVariablesStepProps {
- baseUrl: string;
- component: Component;
- currentUser: LoggedInUser;
-}
-
-const pipelineDescriptionLinkLabel = translate(
- 'onboarding.tutorial.with.gitlab_ci.variables.description.link',
-);
-
-export default function EnvironmentVariablesStep(props: EnvironmentVariablesStepProps) {
- const { baseUrl, component, currentUser } = props;
-
- const fieldValueTranslation = translate('onboarding.tutorial.env_variables');
-
- const renderForm = () => (
- <NumberedList>
- <NumberedListItem>
- {translate('onboarding.tutorial.with.gitlab_ci.variables.section.title')}
-
- <FormattedMessage
- defaultMessage={translate(
- 'onboarding.tutorial.with.gitlab_ci.variables.section.description',
- )}
- id="onboarding.tutorial.with.gitlab_ci.variables.section.description"
- values={{
- /* This link will be added when the backend provides the project URL */
- link: <span className="sw-typo-semibold">{pipelineDescriptionLinkLabel}</span>,
- }}
- />
-
- <UnorderedList ticks className="sw-ml-10">
- <ListItem>
- <FormattedMessage
- id="onboarding.tutorial.with.gitlab_ci.variables.step1"
- values={{
- extra: (
- <ClipboardIconButton copyValue="SONAR_TOKEN" className="sw-ml-1 sw-align-sub" />
- ),
-
- value: <InlineSnippet snippet="SONAR_TOKEN" />,
- }}
- />
- </ListItem>
- <ListItem>
- <TokenStepGenerator component={component} currentUser={currentUser} />
- </ListItem>
- <ListItem>
- <FormattedMessage
- defaultMessage={translate('onboarding.tutorial.with.gitlab_ci.variables.step3')}
- id="onboarding.tutorial.with.gitlab_ci.variables.step3"
- values={{
- value: (
- <span className="sw-typo-semibold">
- {translate('onboarding.tutorial.with.gitlab_ci.variables.step3.value')}
- </span>
- ),
- }}
- />
- </ListItem>
- <ListItem>
- <FormattedMessage
- defaultMessage={translate(
- 'onboarding.tutorial.with.gitlab_ci.variables.section.step4',
- )}
- id="onboarding.tutorial.with.gitlab_ci.variables.section.step4"
- values={{
- value: (
- <span className="sw-typo-semibold">
- {translate('onboarding.tutorial.with.gitlab_ci.variables.section.step4.value')}
- </span>
- ),
- }}
- />
- </ListItem>
- </UnorderedList>
- <BasicSeparator className="sw-my-6" />
- </NumberedListItem>
- <NumberedListItem>
- {translate('onboarding.tutorial.with.gitlab_ci.variables.section2.title')}
-
- <FormattedMessage
- defaultMessage={translate(
- 'onboarding.tutorial.with.gitlab_ci.variables.section2.description',
- )}
- id="onboarding.tutorial.with.gitlab_ci.variables.section2.description"
- values={{
- /* This link will be added when the backend provides the project URL */
- link: <span className="sw-typo-semibold">{pipelineDescriptionLinkLabel}</span>,
- }}
- />
-
- <UnorderedList ticks className="sw-ml-10">
- <ListItem>
- <FormattedMessage
- defaultMessage={fieldValueTranslation}
- id="onboarding.tutorial.with.gitlab_ci.variables.step1"
- values={{
- extra: (
- <ClipboardIconButton
- copyValue="SONAR_HOST_URL"
- className="sw-ml-1 sw-align-sub"
- />
- ),
- value: <InlineSnippet snippet="SONAR_HOST_URL" />,
- }}
- />
- </ListItem>
- <ListItem>
- <FormattedMessage
- defaultMessage={fieldValueTranslation}
- id="onboarding.tutorial.with.gitlab_ci.variables.step2"
- values={{
- extra: <ClipboardIconButton copyValue={baseUrl} className="sw-ml-1 sw-align-sub" />,
- field: (
- <span className="sw-typo-semibold">
- {translate('onboarding.tutorial.env_variables.field')}
- </span>
- ),
- value: <InlineSnippet snippet={baseUrl} />,
- }}
- />
- </ListItem>
- <ListItem>
- <FormattedMessage
- defaultMessage={translate('onboarding.tutorial.with.gitlab_ci.variables.step3')}
- id="onboarding.tutorial.with.gitlab_ci.variables.step3"
- values={{
- value: (
- <span className="sw-typo-semibold">
- {translate('onboarding.tutorial.with.gitlab_ci.variables.step3.value')}
- </span>
- ),
- }}
- />
- </ListItem>
- <ListItem>
- <FormattedMessage
- defaultMessage={translate(
- 'onboarding.tutorial.with.gitlab_ci.variables.section2.step4',
- )}
- id="onboarding.tutorial.with.gitlab_ci.variables.section2.step4"
- values={{
- value: (
- <span className="sw-typo-semibold">
- {translate('onboarding.tutorial.with.gitlab_ci.variables.section.step4.value')}
- </span>
- ),
- }}
- />
- </ListItem>
- </UnorderedList>
- </NumberedListItem>
- </NumberedList>
- );
-
- return (
- <TutorialStep title={translate('onboarding.tutorial.with.gitlab_ci.variables.title')}>
- {renderForm()}
- </TutorialStep>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx
deleted file mode 100644
index 0869bc56b0a..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { BasicSeparator, Title, TutorialStepList } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { AlmKeys } from '../../../types/alm-settings';
-import { Component } from '../../../types/types';
-import { LoggedInUser } from '../../../types/users';
-import AllSet from '../components/AllSet';
-import EnvironmentVariablesStep from './EnvironmentVariablesStep';
-import YmlFileStep from './YmlFileStep';
-
-export enum Steps {
- ENV_VARIABLES,
- YML,
- ALL_SET,
-}
-
-export interface GitLabCITutorialProps {
- baseUrl: string;
- component: Component;
- currentUser: LoggedInUser;
- willRefreshAutomatically?: boolean;
-}
-
-export default function GitLabCITutorial(props: GitLabCITutorialProps) {
- const { baseUrl, component, currentUser, willRefreshAutomatically } = props;
-
- const [done, setDone] = React.useState<boolean>(false);
-
- return (
- <>
- <Title>{translate('onboarding.tutorial.with.gitlab_ci.title')}</Title>
-
- <TutorialStepList className="sw-mb-8">
- <EnvironmentVariablesStep
- baseUrl={baseUrl}
- component={component}
- currentUser={currentUser}
- />
-
- <YmlFileStep component={component} setDone={setDone} />
- </TutorialStepList>
-
- {done && (
- <>
- <BasicSeparator className="sw-my-10" />
- <AllSet alm={AlmKeys.GitLab} willRefreshAutomatically={willRefreshAutomatically} />
- </>
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/YmlFileStep.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/YmlFileStep.tsx
deleted file mode 100644
index 699a1a89747..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/gitlabci/YmlFileStep.tsx
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import {
- ClipboardIconButton,
- CodeSnippet,
- FlagMessage,
- NumberedList,
- NumberedListItem,
- TutorialStep,
-} from '~design-system';
-import withAvailableFeatures, {
- WithAvailableFeaturesProps,
-} from '../../../app/components/available-features/withAvailableFeatures';
-import { GRADLE_SCANNER_VERSION } from '../../../helpers/constants';
-import { translate } from '../../../helpers/l10n';
-import { Component } from '../../../types/types';
-import { withCLanguageFeature } from '../../hoc/withCLanguageFeature';
-import BuildConfigSelection from '../components/BuildConfigSelection';
-import GithubCFamilyExampleRepositories from '../components/GithubCFamilyExampleRepositories';
-import GradleBuildSelection from '../components/GradleBuildSelection';
-import { InlineSnippet } from '../components/InlineSnippet';
-import RenderOptions from '../components/RenderOptions';
-import { Arch, BuildTools, GradleBuildDSL, OSs, TutorialConfig, TutorialModes } from '../types';
-import { shouldShowArchSelector, shouldShowGithubCFamilyExampleRepositories } from '../utils';
-import PipeCommand from './commands/PipeCommand';
-
-export interface YmlFileStepProps extends WithAvailableFeaturesProps {
- component: Component;
- hasCLanguageFeature: boolean;
- setDone: (done: boolean) => void;
-}
-
-const mavenSnippet = (key: string, name: string) => `<properties>
- <sonar.projectKey>${key}</sonar.projectKey>
- <sonar.projectName>${name}</sonar.projectName>
- <sonar.qualitygate.wait>true</sonar.qualitygate.wait>
-</properties>`;
-
-const gradleSnippet = (key: string, name: string, build: GradleBuildDSL) => {
- const map = {
- [GradleBuildDSL.Groovy]: `plugins {
- id "org.sonarqube" version "${GRADLE_SCANNER_VERSION}"
-}
-
-sonar {
- properties {
- property "sonar.projectKey", "${key}"
- property "sonar.projectName", "${name}"
- property "sonar.qualitygate.wait", true
- }
-}`,
- [GradleBuildDSL.Kotlin]: `plugins {
- id ("org.sonarqube") version "${GRADLE_SCANNER_VERSION}"
-}
-
-sonar {
- properties {
- property("sonar.projectKey", "${key}")
- property("sonar.projectName", "${name}")
- property("sonar.qualitygate.wait", true)
- }
-}`,
- };
- return map[build];
-};
-
-const otherSnippet = (key: string) => `sonar.projectKey=${key}
-sonar.qualitygate.wait=true
-`;
-
-const snippetForBuildTool = {
- [BuildTools.Cpp]: otherSnippet,
- [BuildTools.ObjectiveC]: otherSnippet,
- [BuildTools.Gradle]: gradleSnippet,
- [BuildTools.Maven]: mavenSnippet,
- [BuildTools.Dart]: otherSnippet,
- [BuildTools.Other]: otherSnippet,
-};
-
-const filenameForBuildTool = {
- [BuildTools.Cpp]: 'sonar-project.properties',
- [BuildTools.ObjectiveC]: 'sonar-project.properties',
- [BuildTools.Gradle]: GradleBuildDSL.Groovy,
- [BuildTools.Maven]: 'pom.xml',
- [BuildTools.Dart]: 'sonar-project.properties',
- [BuildTools.Other]: 'sonar-project.properties',
-};
-
-const snippetLanguageForBuildTool = {
- [BuildTools.Cpp]: undefined,
- [BuildTools.ObjectiveC]: undefined,
- [BuildTools.Gradle]: undefined,
- [BuildTools.Maven]: 'xml',
- [BuildTools.Dart]: undefined,
- [BuildTools.Other]: undefined,
-};
-
-export function YmlFileStep(props: Readonly<YmlFileStepProps>) {
- const { component, hasCLanguageFeature, setDone } = props;
- const [arch, setArch] = React.useState<Arch>(Arch.X86_64);
-
- const [config, setConfig] = React.useState<TutorialConfig>({});
- const { buildTool } = config;
-
- function onSetConfig(config: TutorialConfig) {
- setConfig(config);
- }
-
- React.useEffect(() => {
- setDone(Boolean(config.buildTool));
- }, [config.buildTool, setDone]);
-
- const renderForm = () => (
- <NumberedList>
- <NumberedListItem>
- <BuildConfigSelection
- ci={TutorialModes.GitLabCI}
- config={config}
- supportCFamily={hasCLanguageFeature}
- onSetConfig={onSetConfig}
- />
- {shouldShowArchSelector(OSs.Linux, config) && (
- <RenderOptions
- label={translate('onboarding.build.other.architecture')}
- checked={arch}
- onCheck={(value: Arch) => setArch(value)}
- optionLabelKey="onboarding.build.other.architecture"
- options={[Arch.X86_64, Arch.Arm64]}
- titleLabelKey="onboarding.build.other.architecture"
- />
- )}
-
- {shouldShowGithubCFamilyExampleRepositories(config) && (
- <GithubCFamilyExampleRepositories
- ci={TutorialModes.GitLabCI}
- className="sw-my-4 sw-w-abs-600"
- />
- )}
- </NumberedListItem>
-
- {/* Step 2 */}
- {buildTool !== undefined && buildTool !== BuildTools.DotNet && (
- <NumberedListItem>
- <FormattedMessage
- defaultMessage={translate(
- `onboarding.tutorial.with.gitlab_ci.project_key.${buildTool}.step2`,
- )}
- id={`onboarding.tutorial.with.gitlab_ci.project_key.${buildTool}.step2`}
- values={Object.assign(
- {
- file: (
- <>
- <InlineSnippet snippet={filenameForBuildTool[buildTool]} />
-
- <ClipboardIconButton
- className="sw-ml-2 sw-align-sub"
- copyValue={filenameForBuildTool[buildTool]}
- />
- </>
- ),
- },
- buildTool === BuildTools.Gradle
- ? {
- file2: (
- <>
- <InlineSnippet snippet={GradleBuildDSL.Kotlin} />
-
- <ClipboardIconButton
- className="sw-ml-2 sw-align-sub"
- copyValue={GradleBuildDSL.Kotlin}
- />
- </>
- ),
- }
- : {},
- )}
- />
- {buildTool === BuildTools.Gradle ? (
- <GradleBuildSelection className="sw-mb-4 sw-mt-2">
- {(build) => (
- <CodeSnippet
- className="sw-p-6"
- language="gradle"
- snippet={snippetForBuildTool[buildTool](component.key, component.name, build)}
- />
- )}
- </GradleBuildSelection>
- ) : (
- <CodeSnippet
- className="sw-p-6"
- language={snippetLanguageForBuildTool[buildTool]}
- snippet={snippetForBuildTool[buildTool](component.key, component.name)}
- />
- )}
- </NumberedListItem>
- )}
-
- {/* Step 3 */}
- {buildTool && (
- <NumberedListItem>
- <FormattedMessage
- defaultMessage={translate('onboarding.tutorial.with.gitlab_ci.yaml.description')}
- id="onboarding.tutorial.with.gitlab_ci.yaml.description"
- values={{
- filename: (
- <>
- <InlineSnippet
- snippet={translate('onboarding.tutorial.with.gitlab_ci.yaml.filename')}
- />
-
- <ClipboardIconButton
- className="sw-ml-2 sw-align-sub"
- copyValue={translate('onboarding.tutorial.with.gitlab_ci.yaml.filename')}
- />
- </>
- ),
- }}
- />
-
- <PipeCommand
- buildTool={buildTool}
- projectKey={component.key}
- arch={shouldShowArchSelector(OSs.Linux, config) ? arch : Arch.X86_64}
- config={config}
- />
-
- <FlagMessage className="sw-mb-4 sw-mt-2" variant="warning">
- {translate('onboarding.tutorial.with.gitlab_ci.yaml.premium')}
- </FlagMessage>
-
- <p className="sw-mb-1">
- {translate('onboarding.tutorial.with.gitlab_ci.yaml.baseconfig')}
- </p>
-
- <p>{translate('onboarding.tutorial.with.gitlab_ci.yaml.existing')}</p>
- </NumberedListItem>
- )}
- </NumberedList>
- );
-
- return (
- <TutorialStep title={translate('onboarding.tutorial.with.gitlab_ci.yaml.title')}>
- {renderForm()}
- </TutorialStep>
- );
-}
-
-export default withCLanguageFeature(withAvailableFeatures(YmlFileStep));
diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/GitLabCITutorial-it.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/GitLabCITutorial-it.tsx
deleted file mode 100644
index d657785904b..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/GitLabCITutorial-it.tsx
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import UserTokensMock from '../../../../api/mocks/UserTokensMock';
-import { mockComponent } from '../../../../helpers/mocks/component';
-import { mockLanguage, mockLoggedInUser } from '../../../../helpers/testMocks';
-import { RenderContext, renderApp } from '../../../../helpers/testReactTestingUtils';
-import { byRole } from '../../../../sonar-aligned/helpers/testSelector';
-import {
- getCommonNodes,
- getCopyToClipboardHostURLValue,
- getCopyToClipboardValue,
- getTutorialActionButtons,
- getTutorialBuildButtons,
-} from '../../test-utils';
-import { GradleBuildDSL, TutorialModes } from '../../types';
-import GitLabCITutorial, { GitLabCITutorialProps } from '../GitLabCITutorial';
-
-jest.mock('../../../../api/settings', () => ({
- getAllValues: jest.fn().mockResolvedValue([]),
-}));
-
-const tokenMock = new UserTokensMock();
-
-afterEach(() => {
- tokenMock.reset();
-});
-
-const ui = {
- ...getCommonNodes(TutorialModes.GitLabCI),
- ...getTutorialActionButtons(),
- ...getTutorialBuildButtons(),
-};
-
-it('should follow and complete all steps', async () => {
- const user = userEvent.setup();
- renderGitLabTutorial();
-
- expect(await ui.secretsStepTitle.find()).toBeInTheDocument();
-
- // Env variables step
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy to clipboard' })).toMatchSnapshot(
- 'sonar token key',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy to clipboard' })).toMatchSnapshot(
- 'sonarqube host url key',
- );
- expect(getCopyToClipboardHostURLValue({ i: 2, name: 'Copy to clipboard' })).toMatchSnapshot(
- 'sonarqube host url value',
- );
-
- // Create/update configuration file step
- // Maven
- await user.click(ui.mavenBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot('Maven: pom.xml');
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot('Maven: gitlab-ci.yml');
-
- // Gradle
- await user.click(ui.gradleBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot('Groovy: build.gradle');
- await user.click(ui.gradleDSLButton(GradleBuildDSL.Kotlin).get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'Kotlin: build.gradle.kts',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot('Gradle: gitlab-ci.yml');
-
- // .NET
- await user.click(ui.dotnetBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot('.NET: gitlab-ci.yml');
-
- // C++/Objective-C
- await user.click(ui.cppBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'CPP: sonar-project.properties',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot('CPP: gitlab-ci.yml');
-
- // c++ manual config
- await user.click(ui.autoConfigManual.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'CPP - manual: gitlab-ci.yml',
- );
-
- // Dart
- await user.click(ui.dartBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'Dart: sonar-project.properties',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot('Dart: gitlab-ci.yml');
-
- // Other
- await user.click(ui.otherBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'Other: sonar-project.properties',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot('Other: gitlab-ci.yml');
-
- expect(ui.allSetSentence.get()).toBeInTheDocument();
-});
-
-it('should generate/delete a new token or use existing one', async () => {
- const user = userEvent.setup();
- renderGitLabTutorial();
-
- expect(await ui.secretsStepTitle.find()).toBeInTheDocument();
-
- // Generate token
- await user.click(ui.genTokenDialogButton.get());
- await user.click(ui.generateTokenButton.get());
- expect(getCopyToClipboardValue({ inlineSnippet: true })).toEqual('generatedtoken2');
-
- // Revoke current token and create new one
- await user.click(ui.deleteTokenButton.get());
- await user.type(ui.tokenNameInput.get(), 'newtoken');
- await user.click(ui.expiresInSelect.get());
- await user.click(byRole('option', { name: 'users.tokens.expiration.365' }).get());
-
- await user.click(ui.generateTokenButton.get());
- expect(ui.tokenValue.get()).toBeInTheDocument();
- await user.click(ui.continueButton.getAll()[0]);
- expect(ui.tokenValue.query()).not.toBeInTheDocument();
-});
-
-function renderGitLabTutorial(
- overrides: Partial<GitLabCITutorialProps> = {},
- { languages = { c: mockLanguage({ key: 'c' }) } }: RenderContext = {},
-) {
- return renderApp(
- '/',
- <GitLabCITutorial
- baseUrl="http://localhost:9000"
- component={mockComponent()}
- currentUser={mockLoggedInUser()}
- {...overrides}
- />,
- { languages },
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/GitLabCITutorial-it.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/GitLabCITutorial-it.tsx.snap
deleted file mode 100644
index c506e31e910..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/__snapshots__/GitLabCITutorial-it.tsx.snap
+++ /dev/null
@@ -1,368 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should follow and complete all steps: .NET: gitlab-ci.yml 1`] = `
-"image: mcr.microsoft.com/dotnet/sdk:7.0
-
-variables:
- SONAR_USER_HOME: "\${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
- GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
-
-stages:
- - build-sonar
-
-
-build-sonar:
- stage: build-sonar
-
-
- cache:
- policy: pull-push
- key: "sonar-cache-$CI_COMMIT_REF_SLUG"
- paths:
- - "\${SONAR_USER_HOME}/cache"
- - sonar-scanner/
-
- script:
- - "dotnet tool install --global dotnet-sonarscanner"
- - "export PATH=\\"$PATH:$HOME/.dotnet/tools\\""
- - "dotnet sonarscanner begin /k:\\"my-project\\" /d:sonar.token=\\"$SONAR_TOKEN\\" /d:\\"sonar.host.url=$SONAR_HOST_URL\\" "
- - "dotnet build"
- - "dotnet sonarscanner end /d:sonar.token=\\"$SONAR_TOKEN\\""
- allow_failure: true
- rules:
- - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- - if: $CI_COMMIT_BRANCH == 'master'
- - if: $CI_COMMIT_BRANCH == 'main'
- - if: $CI_COMMIT_BRANCH == 'develop'"
-`;
-
-exports[`should follow and complete all steps: CPP - manual: gitlab-ci.yml 1`] = `
-"image: gcc
-
-variables:
- SONAR_USER_HOME: "\${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
- GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
- BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
-
-stages:
- - get-binaries
- - build-sonar
-
-get-binaries:
- stage: get-binaries
-
- cache:
- policy: pull-push
- key: "sonar-cache-$CI_COMMIT_REF_SLUG"
- paths:
- - "\${SONAR_USER_HOME}/cache"
- - sonar-scanner/
- - build-wrapper/
- script:
- # Download sonar-scanner
- - if [ ! -d sonar-scanner ]; then
- curl -sSLo ./sonar-scanner.zip 'https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-6.2.0.4584-linux-x64.zip' &&
- unzip -o sonar-scanner.zip &&
- mv sonar-scanner-6.2.0.4584-linux-x64 sonar-scanner;
- fi
-
- # Download build wrapper
- - if [ ! -d build-wrapper ]; then
- curl -sSLo ./build-wrapper-linux-x86.zip "$SONAR_HOST_URL/static/cpp/build-wrapper-linux-x86.zip" &&
- unzip -o build-wrapper-linux-x86.zip &&
- mv build-wrapper-linux-x86 build-wrapper;
- fi
-
- rules:
- - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- - if: $CI_COMMIT_BRANCH == 'master'
- - if: $CI_COMMIT_BRANCH == 'main'
- - if: $CI_COMMIT_BRANCH == 'develop'
-
-build-sonar:
- stage: build-sonar
- script:
- - build-wrapper/build-wrapper-linux-x86-64 --out-dir "\${BUILD_WRAPPER_OUT_DIR}" <your clean build command>
- - sonar-scanner/bin/sonar-scanner -Dsonar.host.url="\${SONAR_HOST_URL}" -Dsonar.cfamily.compile-commands="\${BUILD_WRAPPER_OUT_DIR}/compile_commands.json"
-
- cache:
- policy: pull-push
- key: "sonar-cache-$CI_COMMIT_REF_SLUG"
- paths:
- - "\${SONAR_USER_HOME}/cache"
- - sonar-scanner/
- - build-wrapper/
-"
-`;
-
-exports[`should follow and complete all steps: CPP: gitlab-ci.yml 1`] = `
-"image: gcc
-
-variables:
- SONAR_USER_HOME: "\${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
- GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
-
-
-stages:
- - get-binaries
- - build-sonar
-
-get-binaries:
- stage: get-binaries
-
- cache:
- policy: pull-push
- key: "sonar-cache-$CI_COMMIT_REF_SLUG"
- paths:
- - "\${SONAR_USER_HOME}/cache"
- - sonar-scanner/
-
- script:
- # Download sonar-scanner
- - if [ ! -d sonar-scanner ]; then
- curl -sSLo ./sonar-scanner.zip 'https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-6.2.0.4584-linux-x64.zip' &&
- unzip -o sonar-scanner.zip &&
- mv sonar-scanner-6.2.0.4584-linux-x64 sonar-scanner;
- fi
-
- rules:
- - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- - if: $CI_COMMIT_BRANCH == 'master'
- - if: $CI_COMMIT_BRANCH == 'main'
- - if: $CI_COMMIT_BRANCH == 'develop'
-
-build-sonar:
- stage: build-sonar
- dependencies:
- - get-binaries
-
-
- cache:
- policy: pull-push
- key: "sonar-cache-$CI_COMMIT_REF_SLUG"
- paths:
- - "\${SONAR_USER_HOME}/cache"
- - sonar-scanner/
-
- script: sonar-scanner/bin/sonar-scanner -Dsonar.host.url="\${SONAR_HOST_URL}"
- allow_failure: true
- rules:
- - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- - if: $CI_COMMIT_BRANCH == 'master'
- - if: $CI_COMMIT_BRANCH == 'main'
- - if: $CI_COMMIT_BRANCH == 'develop'"
-`;
-
-exports[`should follow and complete all steps: CPP: sonar-project.properties 1`] = `
-"sonar.projectKey=my-project
-sonar.qualitygate.wait=true
-"
-`;
-
-exports[`should follow and complete all steps: Dart: gitlab-ci.yml 1`] = `
-"image: ghcr.io/cirruslabs/flutter:stable
-
-variables:
- SONAR_USER_HOME: "\${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
- GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
-
-stages:
- - get-binaries
- - build-sonar
-
-get-binaries:
- stage: get-binaries
-
- cache:
- policy: pull-push
- key: "sonar-cache-$CI_COMMIT_REF_SLUG"
- paths:
- - "\${SONAR_USER_HOME}/cache"
- - sonar-scanner/
-
- script:
- # Download sonar-scanner
- - if [ ! -d sonar-scanner ]; then
- curl -sSLo ./sonar-scanner.zip 'https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-6.2.0.4584-linux-x64.zip' &&
- unzip -o sonar-scanner.zip &&
- mv sonar-scanner-6.2.0.4584-linux-x64 sonar-scanner;
- fi
-
- rules:
- - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- - if: $CI_COMMIT_BRANCH == 'master'
- - if: $CI_COMMIT_BRANCH == 'main'
- - if: $CI_COMMIT_BRANCH == 'develop'
-
-build-sonar:
- stage: build-sonar
-
-
- cache:
- policy: pull-push
- key: "sonar-cache-$CI_COMMIT_REF_SLUG"
- paths:
- - "\${SONAR_USER_HOME}/cache"
- - sonar-scanner/
-
- script:
- - <commands to build your project>
- - sonar-scanner/bin/sonar-scanner --define sonar.host.url="\${SONAR_HOST_URL}"
- allow_failure: true
- rules:
- - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- - if: $CI_COMMIT_BRANCH == 'master'
- - if: $CI_COMMIT_BRANCH == 'main'
- - if: $CI_COMMIT_BRANCH == 'develop'"
-`;
-
-exports[`should follow and complete all steps: Dart: sonar-project.properties 1`] = `
-"sonar.projectKey=my-project
-sonar.qualitygate.wait=true
-"
-`;
-
-exports[`should follow and complete all steps: Gradle: gitlab-ci.yml 1`] = `
-"image: gradle:8.2.0-jdk17-jammy
-
-variables:
- SONAR_USER_HOME: "\${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
- GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
-
-stages:
- - build-sonar
-
-
-build-sonar:
- stage: build-sonar
-
-
- cache:
- policy: pull-push
- key: "sonar-cache-$CI_COMMIT_REF_SLUG"
- paths:
- - "\${SONAR_USER_HOME}/cache"
- - sonar-scanner/
-
- script: gradle sonar
- allow_failure: true
- rules:
- - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- - if: $CI_COMMIT_BRANCH == 'master'
- - if: $CI_COMMIT_BRANCH == 'main'
- - if: $CI_COMMIT_BRANCH == 'develop'"
-`;
-
-exports[`should follow and complete all steps: Groovy: build.gradle 1`] = `
-"plugins {
- id "org.sonarqube" version "6.0.1.5171"
-}
-
-sonar {
- properties {
- property "sonar.projectKey", "my-project"
- property "sonar.projectName", "MyProject"
- property "sonar.qualitygate.wait", true
- }
-}"
-`;
-
-exports[`should follow and complete all steps: Kotlin: build.gradle.kts 1`] = `
-"plugins {
- id ("org.sonarqube") version "6.0.1.5171"
-}
-
-sonar {
- properties {
- property("sonar.projectKey", "my-project")
- property("sonar.projectName", "MyProject")
- property("sonar.qualitygate.wait", true)
- }
-}"
-`;
-
-exports[`should follow and complete all steps: Maven: gitlab-ci.yml 1`] = `
-"image: maven:3-eclipse-temurin-17
-
-variables:
- SONAR_USER_HOME: "\${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
- GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
-
-stages:
- - build-sonar
-
-
-build-sonar:
- stage: build-sonar
-
-
- cache:
- policy: pull-push
- key: "sonar-cache-$CI_COMMIT_REF_SLUG"
- paths:
- - "\${SONAR_USER_HOME}/cache"
- - sonar-scanner/
-
- script:
- - mvn verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
- allow_failure: true
- rules:
- - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- - if: $CI_COMMIT_BRANCH == 'master'
- - if: $CI_COMMIT_BRANCH == 'main'
- - if: $CI_COMMIT_BRANCH == 'develop'"
-`;
-
-exports[`should follow and complete all steps: Maven: pom.xml 1`] = `
-"<properties>
- <sonar.projectKey>my-project</sonar.projectKey>
- <sonar.projectName>MyProject</sonar.projectName>
- <sonar.qualitygate.wait>true</sonar.qualitygate.wait>
-</properties>"
-`;
-
-exports[`should follow and complete all steps: Other: gitlab-ci.yml 1`] = `
-"image:
- name: sonarsource/sonar-scanner-cli:11
- entrypoint: [""]
-
-variables:
- SONAR_USER_HOME: "\${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
- GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
-
-stages:
- - build-sonar
-
-
-build-sonar:
- stage: build-sonar
-
-
- cache:
- policy: pull-push
- key: "sonar-cache-$CI_COMMIT_REF_SLUG"
- paths:
- - "\${SONAR_USER_HOME}/cache"
- - sonar-scanner/
-
- script:
- - sonar-scanner -Dsonar.host.url="\${SONAR_HOST_URL}"
- allow_failure: true
- rules:
- - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- - if: $CI_COMMIT_BRANCH == 'master'
- - if: $CI_COMMIT_BRANCH == 'main'
- - if: $CI_COMMIT_BRANCH == 'develop'"
-`;
-
-exports[`should follow and complete all steps: Other: sonar-project.properties 1`] = `
-"sonar.projectKey=my-project
-sonar.qualitygate.wait=true
-"
-`;
-
-exports[`should follow and complete all steps: sonar token key 1`] = `"SONAR_TOKEN"`;
-
-exports[`should follow and complete all steps: sonarqube host url key 1`] = `"SONAR_HOST_URL"`;
-
-exports[`should follow and complete all steps: sonarqube host url value 1`] = `"http://localhost:9000"`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommand.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommand.tsx
deleted file mode 100644
index 38bb0fc2354..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/gitlabci/commands/PipeCommand.tsx
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CodeSnippet } from '~design-system';
-import { useAppState } from '../../../../app/components/app-state/withAppStateContext';
-import { EditionKey } from '../../../../types/editions';
-import { CompilationInfo } from '../../components/CompilationInfo';
-import { Arch, AutoConfig, BuildTools, OSs, TutorialConfig } from '../../types';
-import {
- SONAR_SCANNER_CLI_LATEST_VERSION,
- getBuildWrapperExecutableLinux,
- getBuildWrapperFolderLinux,
- getScannerUrlSuffix,
- isCFamily,
- shouldFetchBuildWrapper,
- shouldFetchScanner,
-} from '../../utils';
-
-export interface PipeCommandProps {
- arch: Arch;
- buildTool: BuildTools;
- config: TutorialConfig;
- projectKey: string;
-}
-
-type ScriptFunction = (projectKey?: string, autoConfig?: AutoConfig) => string;
-
-const BUILD_TOOL_SPECIFIC: {
- [key in BuildTools]: {
- image: string;
- script: ScriptFunction;
- };
-} = {
- [BuildTools.Gradle]: {
- image: 'gradle:8.2.0-jdk17-jammy',
- script: () => 'gradle sonar',
- },
- [BuildTools.Maven]: {
- image: 'maven:3-eclipse-temurin-17',
- script: () => `
- - mvn verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar`,
- },
- [BuildTools.DotNet]: {
- image: 'mcr.microsoft.com/dotnet/sdk:7.0',
- script: (projectKey: string) => `
- - "dotnet tool install --global dotnet-sonarscanner"
- - "export PATH=\\"$PATH:$HOME/.dotnet/tools\\""
- - "dotnet sonarscanner begin /k:\\"${projectKey}\\" /d:sonar.token=\\"$SONAR_TOKEN\\" /d:\\"sonar.host.url=$SONAR_HOST_URL\\" "
- - "dotnet build"
- - "dotnet sonarscanner end /d:sonar.token=\\"$SONAR_TOKEN\\""`,
- },
- [BuildTools.Cpp]: {
- image: 'gcc',
- script: (_, autoConfig?: AutoConfig) =>
- `sonar-scanner/bin/sonar-scanner -Dsonar.host.url="\${SONAR_HOST_URL}" ` +
- (autoConfig === AutoConfig.Manual
- ? `-Dsonar.cfamily.compile-commands="\${BUILD_WRAPPER_OUT_DIR}/compile_commands.json"`
- : ''),
- },
- [BuildTools.ObjectiveC]: {
- image: 'gcc',
- script: (_) =>
- `sonar-scanner/bin/sonar-scanner -Dsonar.host.url="\${SONAR_HOST_URL}" ` +
- `-Dsonar.cfamily.compile-commands="\${BUILD_WRAPPER_OUT_DIR}/compile_commands.json"`,
- },
- [BuildTools.Dart]: {
- image: 'ghcr.io/cirruslabs/flutter:stable',
- script: () => `
- - <commands to build your project>
- - sonar-scanner/bin/sonar-scanner --define sonar.host.url="\${SONAR_HOST_URL}"`,
- },
- [BuildTools.Other]: {
- image: `
- name: sonarsource/sonar-scanner-cli:11
- entrypoint: [""]`,
- script: () => `
- - sonar-scanner -Dsonar.host.url="\${SONAR_HOST_URL}"`,
- },
-};
-
-export default function PipeCommand(props: Readonly<PipeCommandProps>) {
- const appState = useAppState();
-
- const { projectKey, buildTool, config, arch } = props;
- const { autoConfig } = config;
- const { image, script } = BUILD_TOOL_SPECIFIC[buildTool];
-
- const isCommunityBuildRunning = appState.edition === EditionKey.community;
-
- const suffix = getScannerUrlSuffix(OSs.Linux, arch);
- const buildWrapperFolder = getBuildWrapperFolderLinux(arch);
-
- const cacheDefinition = `
- cache:
- policy: pull-push
- key: "sonar-cache-$CI_COMMIT_REF_SLUG"
- paths:
- - "\${SONAR_USER_HOME}/cache"
- - sonar-scanner/
- ${shouldFetchBuildWrapper(buildTool, autoConfig) ? '- build-wrapper/' : ''}`;
-
- const getBinariesStage = `get-binaries:
- stage: get-binaries
- ${cacheDefinition}
- script:
- # Download sonar-scanner
- - if [ ! -d sonar-scanner ]; then
- curl -sSLo ./sonar-scanner.zip 'https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_SCANNER_CLI_LATEST_VERSION}${suffix}.zip' &&
- unzip -o sonar-scanner.zip &&
- mv sonar-scanner-${SONAR_SCANNER_CLI_LATEST_VERSION}${suffix} sonar-scanner;
- fi
- ${
- shouldFetchBuildWrapper(buildTool, autoConfig)
- ? `
- # Download build wrapper
- - if [ ! -d build-wrapper ]; then
- curl -sSLo ./${buildWrapperFolder}.zip "$SONAR_HOST_URL/static/cpp/${buildWrapperFolder}.zip" &&
- unzip -o ${buildWrapperFolder}.zip &&
- mv ${buildWrapperFolder} build-wrapper;
- fi
-`
- : ''
- }
- rules:
- - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- - if: $CI_COMMIT_BRANCH == 'master'
- - if: $CI_COMMIT_BRANCH == 'main'
- - if: $CI_COMMIT_BRANCH == 'develop'`;
-
- const sonarWithBuildWrapperStage = `build-sonar:
- stage: build-sonar
- script:
- - build-wrapper/${getBuildWrapperExecutableLinux(arch)} --out-dir "\${BUILD_WRAPPER_OUT_DIR}" <your clean build command>
- - ${script(projectKey, autoConfig)}
- ${cacheDefinition}
-`;
-
- const sonarStage = `build-sonar:
- stage: build-sonar
- ${
- isCFamily(buildTool)
- ? `dependencies:
- - get-binaries
-`
- : ''
- }
- ${cacheDefinition}
- script: ${script(projectKey, autoConfig)}
- allow_failure: true
- rules:
- - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- - if: $CI_COMMIT_BRANCH == 'master'
- - if: $CI_COMMIT_BRANCH == 'main'
- - if: $CI_COMMIT_BRANCH == 'develop'`;
-
- const vulnerabilityReportStage = `sonarqube-vulnerability-report:
- stage: sonarqube-vulnerability-report
- script:
- - 'curl -u "\${SONAR_TOKEN}:" "\${SONAR_HOST_URL}/api/issues/gitlab_sast_export?projectKey=${projectKey}&branch=\${CI_COMMIT_BRANCH}&pullRequest=\${CI_MERGE_REQUEST_IID}" -o gl-sast-sonar-report.json'
- allow_failure: true
- rules:
- - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- - if: $CI_COMMIT_BRANCH == 'master'
- - if: $CI_COMMIT_BRANCH == 'main'
- - if: $CI_COMMIT_BRANCH == 'develop'
- artifacts:
- expire_in: 1 day
- reports:
- sast: gl-sast-sonar-report.json
-`;
-
- let stageDeclaration: string[] = [];
- let stages: string[] = [];
-
- if (shouldFetchBuildWrapper(buildTool, autoConfig)) {
- // only for c-family languages on manual configuration
- stages = [getBinariesStage, sonarWithBuildWrapperStage];
- stageDeclaration = ['get-binaries', 'build-sonar'];
- } else if (shouldFetchScanner(buildTool)) {
- stages = [getBinariesStage, sonarStage];
- stageDeclaration = ['get-binaries', 'build-sonar'];
- } else {
- stages = [sonarStage];
- stageDeclaration = ['build-sonar'];
- }
-
- if (!isCommunityBuildRunning) {
- stages.push(vulnerabilityReportStage);
- stageDeclaration.push('sonarqube-vulnerability-report');
- }
-
- const stageDefinition =
- stageDeclaration.length > 0
- ? `- ${stageDeclaration[0]}\n${stageDeclaration
- .slice(1)
- .map((stage) => ` - ${stage}`)
- .join('\n')}`
- : '';
-
- const variables = isCFamily(buildTool)
- ? `SONAR_USER_HOME: "\${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
- GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
- ${autoConfig === AutoConfig.Manual ? `BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed` : ''}`
- : `SONAR_USER_HOME: "\${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
- GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task`;
-
- const command = `image: ${image}
-
-variables:
- ${variables}
-
-stages:
- ${stageDefinition}
-
-${stages.join('\n\n')}`;
-
- return (
- <>
- <CodeSnippet className="sw-p-6" snippet={command} language="yml" />
- {buildTool === (BuildTools.Cpp || BuildTools.ObjectiveC) &&
- autoConfig === AutoConfig.Manual && <CompilationInfo />}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsStep.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsStep.tsx
deleted file mode 100644
index 6d4bd85c4a7..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsStep.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { NumberedList, NumberedListItem, TutorialStep } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { Component } from '../../../types/types';
-import { withCLanguageFeature } from '../../hoc/withCLanguageFeature';
-import BuildConfigSelection from '../components/BuildConfigSelection';
-import { BuildTools, TutorialConfig, TutorialModes } from '../types';
-import CFamily from './buildtool-steps/CFamily';
-import DotNet from './buildtool-steps/DotNet';
-import Gradle from './buildtool-steps/Gradle';
-import Maven from './buildtool-steps/Maven';
-import Other from './buildtool-steps/Other';
-
-const BUILDTOOL_COMPONENT_MAP: {
- [x in BuildTools]: React.ComponentType<React.PropsWithChildren<LanguageProps>>;
-} = {
- [BuildTools.Maven]: Maven,
- [BuildTools.Gradle]: Gradle,
- [BuildTools.DotNet]: DotNet,
- [BuildTools.Cpp]: CFamily,
- [BuildTools.ObjectiveC]: CFamily,
- [BuildTools.Dart]: Other,
- [BuildTools.Other]: Other,
-};
-
-export interface LanguageProps {
- baseUrl: string;
- component: Component;
- config: TutorialConfig;
-}
-
-export interface JenkinsfileStepProps {
- baseUrl: string;
- component: Component;
- hasCLanguageFeature: boolean;
- setDone: (done: boolean) => void;
-}
-
-export function JenkinsStep(props: Readonly<JenkinsfileStepProps>) {
- const { component, hasCLanguageFeature, baseUrl, setDone } = props;
-
- const [config, setConfig] = React.useState<TutorialConfig>({});
-
- React.useEffect(() => {
- setDone(Boolean(config.buildTool));
- }, [config.buildTool, setDone]);
-
- const BuildToolComponent = config.buildTool && BUILDTOOL_COMPONENT_MAP[config.buildTool];
-
- return (
- <TutorialStep title={translate('onboarding.tutorial.with.jenkins.jenkinsfile.title')}>
- <NumberedList>
- <NumberedListItem>
- <BuildConfigSelection
- ci={TutorialModes.Jenkins}
- config={config}
- supportCFamily={hasCLanguageFeature}
- onSetConfig={setConfig}
- />
- </NumberedListItem>
- {BuildToolComponent && (
- <BuildToolComponent config={config} component={component} baseUrl={baseUrl} />
- )}
- </NumberedList>
- </TutorialStep>
- );
-}
-
-export default withCLanguageFeature(JenkinsStep);
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx
deleted file mode 100644
index b92c7bae787..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { BasicSeparator, Title, TutorialStepList } from '~design-system';
-import withAvailableFeatures, {
- WithAvailableFeaturesProps,
-} from '../../../app/components/available-features/withAvailableFeatures';
-import { translate } from '../../../helpers/l10n';
-import { useProjectBindingQuery } from '../../../queries/devops-integration';
-import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings';
-import { Feature } from '../../../types/features';
-import { Component } from '../../../types/types';
-import AllSet from '../components/AllSet';
-import JenkinsStep from './JenkinsStep';
-import MultiBranchPipelineStep from './MultiBranchPipelineStep';
-import PipelineStep from './PipelineStep';
-import PreRequisitesStep from './PreRequisitesStep';
-import SelectAlmStep from './SelectAlmStep';
-import WebhookStep from './WebhookStep';
-
-export interface JenkinsTutorialProps extends WithAvailableFeaturesProps {
- almBinding?: AlmSettingsInstance;
- baseUrl: string;
- component: Component;
- willRefreshAutomatically?: boolean;
-}
-
-export function JenkinsTutorial(props: JenkinsTutorialProps) {
- const { almBinding, baseUrl, component, willRefreshAutomatically } = props;
- const { data: projectBinding } = useProjectBindingQuery(component.key);
- const hasSelectAlmStep = projectBinding?.alm === undefined;
- const branchSupportEnabled = props.hasFeature(Feature.BranchSupport);
- const [alm, setAlm] = React.useState<AlmKeys | undefined>(projectBinding?.alm);
- const [done, setDone] = React.useState(false);
-
- React.useEffect(() => {
- setAlm(projectBinding?.alm);
- }, [projectBinding]);
-
- return (
- <>
- <Title>{translate('onboarding.tutorial.with.jenkins.title')}</Title>
-
- {hasSelectAlmStep && <SelectAlmStep alm={alm} onChange={setAlm} />}
- {alm && (
- <>
- <TutorialStepList className="sw-mb-10">
- <PreRequisitesStep alm={alm} branchesEnabled={branchSupportEnabled} />
-
- {branchSupportEnabled ? (
- <MultiBranchPipelineStep
- alm={alm}
- almBinding={almBinding}
- projectBinding={projectBinding}
- />
- ) : (
- <PipelineStep alm={alm} />
- )}
-
- <WebhookStep
- alm={alm}
- almBinding={almBinding}
- branchesEnabled={branchSupportEnabled}
- projectBinding={projectBinding}
- />
-
- <JenkinsStep component={component} baseUrl={baseUrl} setDone={setDone} />
- </TutorialStepList>
- {done && (
- <>
- <BasicSeparator className="sw-my-10" />
- <AllSet alm={alm} willRefreshAutomatically={willRefreshAutomatically} />
- </>
- )}
- </>
- )}
- </>
- );
-}
-
-export default withAvailableFeatures(JenkinsTutorial);
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/MultiBranchPipelineStep.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/MultiBranchPipelineStep.tsx
deleted file mode 100644
index 804587d6462..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/MultiBranchPipelineStep.tsx
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- CodeSnippet,
- ListItem,
- NumberedList,
- NumberedListItem,
- TutorialStep,
- UnorderedList,
-} from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import {
- AlmKeys,
- AlmSettingsInstance,
- ProjectAlmBindingResponse,
-} from '../../../types/alm-settings';
-import LabelActionPair from '../components/LabelActionPair';
-import LabelValuePair from '../components/LabelValuePair';
-import SentenceWithHighlights from '../components/SentenceWithHighlights';
-import { buildGithubLink } from '../utils';
-
-export interface MultiBranchPipelineStepProps {
- alm: AlmKeys;
- almBinding?: AlmSettingsInstance;
-
- projectBinding?: ProjectAlmBindingResponse | null;
-}
-
-/* Capture [workspaceID] from this pattern: https://bitbucket.org/[workspaceId]/ */
-const bitbucketcloudUrlRegex = /https:\/\/bitbucket.org\/(.+)\//;
-
-function extractBitbucketCloudWorkspaceId(almBinding?: AlmSettingsInstance): string | undefined {
- if (almBinding?.url) {
- const result = bitbucketcloudUrlRegex.exec(almBinding.url);
-
- return result ? result[1] : undefined;
- }
-}
-
-export default function MultiBranchPipelineStep(props: MultiBranchPipelineStepProps) {
- const { alm, almBinding, projectBinding } = props;
-
- const workspaceId = extractBitbucketCloudWorkspaceId(almBinding);
- const isGitLab = alm === AlmKeys.GitLab;
- const isBitbucketServer = alm === AlmKeys.BitbucketServer;
- const isBitbucketCloud = alm === AlmKeys.BitbucketCloud;
- const isGitHub = alm === AlmKeys.GitHub;
-
- return (
- <TutorialStep title={translate('onboarding.tutorial.with.jenkins.multi_branch_pipeline.title')}>
- <p className="sw-mb-4">
- {translate('onboarding.tutorial.with.jenkins.multi_branch_pipeline.intro')}
- </p>
- <NumberedList>
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['new_item', 'type']}
- translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step1"
- />
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['tab', 'source']}
- translationKey={`onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.${alm}`}
- />
- <UnorderedList ticks className="sw-ml-12">
- {isBitbucketServer && (
- <>
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.server" />
- </ListItem>
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.creds" />
- </ListItem>
- <ListItem>
- {projectBinding?.repository ? (
- <LabelValuePair
- translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.owner"
- value={projectBinding.repository}
- />
- ) : (
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.owner" />
- )}
- </ListItem>
- <ListItem>
- {projectBinding?.slug ? (
- <LabelValuePair
- translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.repo"
- value={projectBinding.slug}
- />
- ) : (
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucket.repo" />
- )}
- </ListItem>
- </>
- )}
- {isBitbucketCloud && (
- <>
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucketcloud.server" />
- </ListItem>
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucketcloud.creds" />
- </ListItem>
- <ListItem>
- {workspaceId ? (
- <LabelValuePair
- translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucketcloud.owner"
- value={workspaceId}
- />
- ) : (
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucketcloud.owner" />
- )}
- </ListItem>
- <ListItem>
- {projectBinding?.repository ? (
- <LabelValuePair
- translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucketcloud.repo"
- value={projectBinding.repository}
- />
- ) : (
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.bitbucketcloud.repo" />
- )}
- </ListItem>
- </>
- )}
- {isGitHub && (
- <>
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github.creds" />
- </ListItem>
- <ListItem>
- {almBinding !== undefined &&
- projectBinding != null &&
- buildGithubLink(almBinding, projectBinding) !== null ? (
- <LabelValuePair
- translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github.repo_url"
- value={buildGithubLink(almBinding, projectBinding) as string}
- />
- ) : (
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.github.repo_url" />
- )}
- </ListItem>
- </>
- )}
- {isGitLab && (
- <>
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.gitlab.creds" />
- </ListItem>
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.gitlab.owner" />
- </ListItem>
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.gitlab.repo" />
- </ListItem>
- </>
- )}
- <ListItem>
- <strong>
- {translate(
- 'onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviors.label',
- )}
- :
- </strong>
- <UnorderedList ticks className="sw-ml-4 sw-mt-1">
- <ListItem>
- <LabelActionPair
- translationKey={`onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviors.${
- isGitLab ? 'branches_mrs' : 'branches_prs'
- }`}
- />
- </ListItem>
- <ListItem>
- <LabelActionPair
- translationKey={`onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviors.${
- isGitLab ? 'discover_mrs' : 'discover_prs'
- }`}
- />
- </ListItem>
- <ListItem>
- <strong>
- {translate(
- 'onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviors.ref_specs.label',
- )}
- :
- </strong>
- <UnorderedList className="sw-ml-4 sw-mt-1">
- <ListItem>
- <SentenceWithHighlights
- highlightKeys={['add', 'ref_spec']}
- translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviors.ref_specs.add_behaviour"
- />
- </ListItem>
- <ListItem>
- <SentenceWithHighlights
- highlightKeys={['ref_spec']}
- translationKey={`onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.behaviors.ref_specs.${
- isGitLab ? 'set_mr_ref_specs' : 'set_pr_ref_specs'
- }`}
- />
- <CodeSnippet
- className="sw-p-4"
- isOneLine
- snippet="+refs/heads/*:refs/remotes/@{remote}/*"
- />
- </ListItem>
- </UnorderedList>
- </ListItem>
- </UnorderedList>
- </ListItem>
- </UnorderedList>
- <p className="sw-ml-12">
- {translate(
- 'onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.leave_defaults',
- )}
- </p>
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['tab']}
- translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3"
- />
- <UnorderedList ticks className="sw-ml-12">
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3.mode" />
- </ListItem>
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step3.script_path" />
- </ListItem>
- </UnorderedList>
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['save']}
- translationKey="onboarding.tutorial.with.jenkins.multi_branch_pipeline.step4"
- />
- </NumberedListItem>
- </NumberedList>
- </TutorialStep>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/PipelineStep.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/PipelineStep.tsx
deleted file mode 100644
index 933f0526002..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/PipelineStep.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- ListItem,
- NumberedList,
- NumberedListItem,
- TutorialStep,
- UnorderedList,
-} from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { AlmKeys } from '../../../types/alm-settings';
-import LabelActionPair from '../components/LabelActionPair';
-import SentenceWithHighlights from '../components/SentenceWithHighlights';
-
-export interface PipelineStepProps {
- alm: AlmKeys;
-}
-
-export default function PipelineStep(props: PipelineStepProps) {
- const { alm } = props;
- return (
- <TutorialStep title={translate('onboarding.tutorial.with.jenkins.pipeline.title')}>
- <p className="sw-mb-4">{translate('onboarding.tutorial.with.jenkins.pipeline.intro')}</p>
- <NumberedList>
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['new_item', 'type']}
- translationKey="onboarding.tutorial.with.jenkins.pipeline.step1"
- />
- </NumberedListItem>
- <NumberedListItem>
- {alm === AlmKeys.GitLab ? (
- <>
- <SentenceWithHighlights
- highlightKeys={['tab', 'option']}
- translationKey="onboarding.tutorial.with.jenkins.pipeline.gitlab.step2.trigger"
- />
- <UnorderedList className="sw-ml-12">
- <ListItem>
- <SentenceWithHighlights
- highlightKeys={['triggers', 'push_events']}
- translationKey="onboarding.tutorial.with.jenkins.pipeline.gitlab.step2.pick_triggers"
- />
- </ListItem>
- <ListItem>
- <SentenceWithHighlights
- highlightKeys={['advanced']}
- translationKey="onboarding.tutorial.with.jenkins.pipeline.gitlab.step2.click_advanced"
- />
- </ListItem>
- <ListItem>
- <SentenceWithHighlights
- highlightKeys={['secret_token', 'generate']}
- translationKey="onboarding.tutorial.with.jenkins.pipeline.gitlab.step2.secret_token"
- />
- </ListItem>
- </UnorderedList>
- </>
- ) : (
- <SentenceWithHighlights
- highlightKeys={['tab', 'option']}
- translationKey="onboarding.tutorial.with.jenkins.pipeline.step2"
- />
- )}
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['tab']}
- translationKey="onboarding.tutorial.with.jenkins.pipeline.step3"
- />
- <UnorderedList className="sw-ml-12">
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.pipeline.step3.definition" />
- </ListItem>
- <ListItem>
- <SentenceWithHighlights
- highlightKeys={['label', 'branches_to_build']}
- translationKey="onboarding.tutorial.with.jenkins.pipeline.step3.scm"
- />
- </ListItem>
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.pipeline.step3.script_path" />
- </ListItem>
- </UnorderedList>
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['save']}
- translationKey="onboarding.tutorial.with.jenkins.pipeline.step4"
- />
- </NumberedListItem>
- </NumberedList>
- </TutorialStep>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx
deleted file mode 100644
index 0db0e390f7a..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Text } from '@sonarsource/echoes-react';
-import { FormattedMessage } from 'react-intl';
-import { FlagMessage, Link, TutorialStep } from '~design-system';
-import { DocLink } from '../../../helpers/doc-links';
-import { useDocUrl } from '../../../helpers/docs';
-import { translate } from '../../../helpers/l10n';
-import { AlmKeys } from '../../../types/alm-settings';
-import SentenceWithHighlights from '../components/SentenceWithHighlights';
-
-export interface PreRequisitesStepProps {
- alm: AlmKeys;
- branchesEnabled: boolean;
-}
-
-export default function PreRequisitesStep(props: PreRequisitesStepProps) {
- const { alm, branchesEnabled } = props;
-
- const docUrl = useDocUrl(DocLink.CIJenkins);
-
- return (
- <TutorialStep title={translate('onboarding.tutorial.with.jenkins.prereqs.title')}>
- <FlagMessage className="sw-mb-4" variant="warning">
- <span>
- <SentenceWithHighlights
- highlightKeys={['installed', 'configured']}
- translationKey="onboarding.tutorial.with.jenkins.prereqs.intro"
- />
- </span>
- </FlagMessage>
- <Text as="div">
- <ul className="sw-mb-4">
- {branchesEnabled && (
- <li>
- {translate('onboarding.tutorial.with.jenkins.prereqs.plugins.branch_source', alm)}
- </li>
- )}
- {!branchesEnabled && alm === AlmKeys.GitLab && (
- <li>{translate('onboarding.tutorial.with.jenkins.prereqs.plugins.gitlab_plugin')}</li>
- )}
- <li>{translate('onboarding.tutorial.with.jenkins.prereqs.plugins.sonar_scanner')}</li>
- </ul>
- <p className="sw-mb-4">
- <FormattedMessage
- defaultMessage={translate(
- 'onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide',
- )}
- id="onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide"
- values={{
- link: (
- <Link to={docUrl}>
- {translate('onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide.link')}
- </Link>
- ),
- }}
- />
- </p>
- <p className="sw-mb-4">
- {translate('onboarding.tutorial.with.jenkins.prereqs.following_are_recommendations')}
- </p>
- </Text>
- </TutorialStep>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/SelectAlmStep.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/SelectAlmStep.tsx
deleted file mode 100644
index 61a8f8e2141..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/SelectAlmStep.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ToggleButton, TutorialStep } from '~design-system';
-import { hasMessage, translate } from '../../../helpers/l10n';
-import { AlmKeys } from '../../../types/alm-settings';
-
-export interface SelectAlmStepProps {
- alm?: AlmKeys;
- onChange: (value: AlmKeys) => void;
-}
-
-function getAlmLongName(alm: AlmKeys) {
- return hasMessage('alm', alm, 'long') ? translate('alm', alm, 'long') : translate('alm', alm);
-}
-
-export default function SelectAlmStep(props: SelectAlmStepProps) {
- const { alm } = props;
- return (
- <TutorialStep title={translate('onboarding.tutorial.with.jenkins.alm_selection.title')}>
- <ToggleButton
- label={translate('onboarding.tutorial.with.jenkins.alm_selection.title')}
- onChange={props.onChange}
- options={[
- AlmKeys.BitbucketCloud,
- AlmKeys.BitbucketServer,
- AlmKeys.GitHub,
- AlmKeys.GitLab,
- ].map((almKey) => ({
- label: getAlmLongName(almKey),
- value: almKey,
- }))}
- value={alm}
- />
- </TutorialStep>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx
deleted file mode 100644
index d1c6307f582..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStep.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable react/no-unused-prop-types */
-
-import { NumberedList, TutorialStep } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import {
- AlmKeys,
- AlmSettingsInstance,
- ProjectAlmBindingResponse,
-} from '../../../types/alm-settings';
-import WebhookStepBitbucket from './WebhookStepBitbucket';
-import WebhookStepGitLab from './WebhookStepGitLab';
-import WebhookStepGithub from './WebhookStepGithub';
-
-export interface WebhookStepProps {
- alm: AlmKeys;
- almBinding?: AlmSettingsInstance;
- branchesEnabled: boolean;
- projectBinding?: ProjectAlmBindingResponse | null;
-}
-
-function renderAlmSpecificInstructions(props: WebhookStepProps) {
- const { alm, almBinding, branchesEnabled, projectBinding } = props;
-
- switch (alm) {
- case AlmKeys.BitbucketCloud:
- case AlmKeys.BitbucketServer:
- return (
- <WebhookStepBitbucket
- alm={alm}
- almBinding={almBinding}
- branchesEnabled={branchesEnabled}
- projectBinding={projectBinding}
- />
- );
-
- case AlmKeys.GitHub:
- return (
- <WebhookStepGithub
- almBinding={almBinding}
- branchesEnabled={branchesEnabled}
- projectBinding={projectBinding}
- />
- );
-
- case AlmKeys.GitLab:
- return <WebhookStepGitLab branchesEnabled={branchesEnabled} />;
-
- default:
- return null;
- }
-}
-
-export default function WebhookStep(props: WebhookStepProps) {
- const { alm } = props;
-
- return (
- <TutorialStep title={translate('onboarding.tutorial.with.jenkins.webhook', alm, 'title')}>
- <p className="sw-mb-4">
- {translate('onboarding.tutorial.with.jenkins.webhook.intro.sentence')}
- </p>
- <NumberedList>{renderAlmSpecificInstructions(props)}</NumberedList>
- </TutorialStep>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepBitbucket.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepBitbucket.tsx
deleted file mode 100644
index ac2b039f586..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepBitbucket.tsx
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import {
- CodeSnippet,
- FlagMessage,
- ListItem,
- NumberedListItem,
- UnorderedList,
-} from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { stripTrailingSlash } from '../../../helpers/urls';
-import {
- AlmKeys,
- AlmSettingsInstance,
- ProjectAlmBindingResponse,
-} from '../../../types/alm-settings';
-import Link from '../../common/Link';
-import LabelActionPair from '../components/LabelActionPair';
-import SentenceWithHighlights from '../components/SentenceWithHighlights';
-import { buildBitbucketCloudLink } from '../utils';
-
-export interface WebhookStepBitbucketProps {
- alm: AlmKeys;
- almBinding?: AlmSettingsInstance;
- branchesEnabled: boolean;
- projectBinding?: ProjectAlmBindingResponse | null;
-}
-
-function buildUrlSnippet(
- branchesEnabled: boolean,
- isBitbucketcloud: boolean,
- ownUrl = '***BITBUCKET_URL***',
-) {
- if (!branchesEnabled) {
- return '***JENKINS_SERVER_URL***/job/***JENKINS_JOB_NAME***/build?token=***JENKINS_BUILD_TRIGGER_TOKEN***';
- }
- return isBitbucketcloud
- ? '***JENKINS_SERVER_URL***/bitbucket-scmsource-hook/notify'
- : `***JENKINS_SERVER_URL***/bitbucket-scmsource-hook/notify?server_url=${ownUrl}`;
-}
-
-export default function WebhookStepBitbucket(props: WebhookStepBitbucketProps) {
- const { alm, almBinding, branchesEnabled, projectBinding } = props;
-
- const isBitbucketCloud = alm === AlmKeys.BitbucketCloud;
-
- let linkUrl;
- if (almBinding?.url && projectBinding) {
- if (isBitbucketCloud && projectBinding?.repository) {
- linkUrl = `${buildBitbucketCloudLink(
- almBinding,
- projectBinding,
- )}/admin/addon/admin/bitbucket-webhooks/bb-webhooks-repo-admin`;
- } else if (projectBinding.slug) {
- linkUrl = `${stripTrailingSlash(almBinding.url)}/plugins/servlet/webhooks/projects/${
- projectBinding.repository
- }/repos/${projectBinding.slug}/create`;
- }
- }
-
- return (
- <>
- <NumberedListItem>
- <FormattedMessage
- defaultMessage={translate('onboarding.tutorial.with.jenkins.webhook.step1.sentence')}
- id="onboarding.tutorial.with.jenkins.webhook.step1.sentence"
- values={{
- link: linkUrl ? (
- <Link to={linkUrl} target="_blank">
- {translate('onboarding.tutorial.with.jenkins.webhook', alm, 'step1.link')}
- </Link>
- ) : (
- <strong>
- {translate('onboarding.tutorial.with.jenkins.webhook', alm, 'step1.link')}
- </strong>
- ),
- }}
- />
- <UnorderedList ticks className="sw-ml-12">
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.step1.name" />
- </ListItem>
- <ListItem>
- <p>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.url" />
- </p>
- <CodeSnippet
- className="sw-p-4"
- isOneLine
- snippet={buildUrlSnippet(branchesEnabled, isBitbucketCloud, almBinding?.url)}
- />
- {branchesEnabled && !isBitbucketCloud && (
- <FlagMessage variant="info">
- {translate('onboarding.tutorial.with.jenkins.webhook.bitbucket.step1.url.warning')}
- </FlagMessage>
- )}
- </ListItem>
- </UnorderedList>
- </NumberedListItem>
- {isBitbucketCloud ? (
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['triggers', 'option']}
- translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucketcloud.step2"
- />
- <UnorderedList ticks className="sw-ml-12">
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucketcloud.step2.repo" />
- </ListItem>
- {branchesEnabled && (
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucketcloud.step2.pr" />
- </ListItem>
- )}
- </UnorderedList>
- </NumberedListItem>
- ) : (
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['events']}
- translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step2"
- />
- <UnorderedList ticks className="sw-ml-12">
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step2.repo" />
- </ListItem>
- {branchesEnabled && (
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step2.pr" />
- </ListItem>
- )}
- </UnorderedList>
- </NumberedListItem>
- )}
- <NumberedListItem>
- {isBitbucketCloud ? (
- <SentenceWithHighlights
- highlightKeys={['save']}
- translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucketcloud.step3"
- />
- ) : (
- <SentenceWithHighlights
- highlightKeys={['create']}
- translationKey="onboarding.tutorial.with.jenkins.webhook.bitbucket.step3"
- />
- )}
- </NumberedListItem>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepGitLab.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepGitLab.tsx
deleted file mode 100644
index fb83ddf7d3b..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepGitLab.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { CodeSnippet, ListItem, NumberedListItem, UnorderedList } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import LabelActionPair from '../components/LabelActionPair';
-import SentenceWithHighlights from '../components/SentenceWithHighlights';
-
-export interface WebhookStepGitLabProps {
- branchesEnabled: boolean;
-}
-
-export default function WebhookStepGitLab({ branchesEnabled }: WebhookStepGitLabProps) {
- return (
- <>
- <NumberedListItem>
- <FormattedMessage
- defaultMessage={translate('onboarding.tutorial.with.jenkins.webhook.step1.sentence')}
- id="onboarding.tutorial.with.jenkins.webhook.step1.sentence"
- values={{
- link: translate('onboarding.tutorial.with.jenkins.webhook.gitlab.step1.link'),
- }}
- />
- <UnorderedList ticks className="sw-ml-12">
- {branchesEnabled ? (
- <ListItem>
- <p>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.gitlab.step1.url_with_branches" />
- </p>
- <CodeSnippet
- className="sw-p-4"
- isOneLine
- snippet="***JENKINS_SERVER_URL***/gitlab-webhook/post"
- />
- </ListItem>
- ) : (
- <>
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.gitlab.step1.url_no_branches" />
- </ListItem>
- <ListItem>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.gitlab.step1.secret_token" />
- </ListItem>
- </>
- )}
- </UnorderedList>
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['trigger']}
- translationKey="onboarding.tutorial.with.jenkins.webhook.gitlab.step2"
- />
- <UnorderedList ticks className="sw-ml-12">
- <ListItem>
- <strong className="sw-font-semibold">
- {translate('onboarding.tutorial.with.jenkins.webhook.gitlab.step2.repo')}
- </strong>
- </ListItem>
- {branchesEnabled && (
- <ListItem>
- <strong className="sw-font-semibold">
- {translate('onboarding.tutorial.with.jenkins.webhook.gitlab.step2.mr')}
- </strong>
- </ListItem>
- )}
- </UnorderedList>
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['add_webhook']}
- translationKey="onboarding.tutorial.with.jenkins.webhook.gitlab.step3"
- />
- </NumberedListItem>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepGithub.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepGithub.tsx
deleted file mode 100644
index 0a163efc7fb..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/WebhookStepGithub.tsx
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { CodeSnippet, Link, ListItem, NumberedListItem, UnorderedList } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { AlmSettingsInstance, ProjectAlmBindingResponse } from '../../../types/alm-settings';
-import LabelActionPair from '../components/LabelActionPair';
-import SentenceWithHighlights from '../components/SentenceWithHighlights';
-import { buildGithubLink } from '../utils';
-
-export interface WebhookStepGithubProps {
- almBinding?: AlmSettingsInstance;
- branchesEnabled: boolean;
- projectBinding?: ProjectAlmBindingResponse | null;
-}
-
-export default function WebhookStepGithub(props: WebhookStepGithubProps) {
- const { almBinding, branchesEnabled, projectBinding } = props;
-
- const linkUrl =
- almBinding && projectBinding && `${buildGithubLink(almBinding, projectBinding)}/settings/hooks`;
-
- const webhookUrl = branchesEnabled
- ? '***JENKINS_SERVER_URL***/github-webhook/'
- : '***JENKINS_SERVER_URL***/job/***JENKINS_JOB_NAME***/build?token=***JENKINS_BUILD_TRIGGER_TOKEN***';
-
- return (
- <>
- <NumberedListItem>
- <FormattedMessage
- defaultMessage={translate('onboarding.tutorial.with.jenkins.webhook.step1.sentence')}
- id="onboarding.tutorial.with.jenkins.webhook.step1.sentence"
- values={{
- link: linkUrl ? (
- <Link to={linkUrl}>
- {translate('onboarding.tutorial.with.jenkins.webhook.github.step1.link')}
- </Link>
- ) : (
- <strong className="sw-font-semibold">
- {translate('onboarding.tutorial.with.jenkins.webhook.github.step1.link')}
- </strong>
- ),
- }}
- />
- <UnorderedList ticks className="sw-ml-12">
- <ListItem>
- <p>
- <LabelActionPair translationKey="onboarding.tutorial.with.jenkins.webhook.github.step1.url" />
- </p>
- <CodeSnippet className="sw-p-4" isOneLine snippet={webhookUrl} />
- </ListItem>
- </UnorderedList>
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['events', 'option']}
- translationKey="onboarding.tutorial.with.jenkins.webhook.github.step2"
- />
- <UnorderedList ticks className="sw-ml-12">
- <ListItem>
- <strong className="sw-font-semibold">
- {translate('onboarding.tutorial.with.jenkins.webhook.github.step2.repo')}
- </strong>
- </ListItem>
- {branchesEnabled && (
- <ListItem>
- <strong className="sw-font-semibold">
- {translate('onboarding.tutorial.with.jenkins.webhook.github.step2.pr')}
- </strong>
- </ListItem>
- )}
- </UnorderedList>
- </NumberedListItem>
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['add_webhook']}
- translationKey="onboarding.tutorial.with.jenkins.webhook.github.step3"
- />
- </NumberedListItem>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsTutorial-it.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsTutorial-it.tsx
deleted file mode 100644
index 643c6a3688d..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsTutorial-it.tsx
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { waitFor } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import AlmSettingsServiceMock from '../../../../api/mocks/AlmSettingsServiceMock';
-import UserTokensMock from '../../../../api/mocks/UserTokensMock';
-import { mockComponent } from '../../../../helpers/mocks/component';
-import { mockLanguage } from '../../../../helpers/testMocks';
-import { RenderContext, renderApp } from '../../../../helpers/testReactTestingUtils';
-import { AlmKeys } from '../../../../types/alm-settings';
-import { Feature } from '../../../../types/features';
-import {
- getCopyToClipboardValue,
- getTutorialActionButtons,
- getTutorialBuildButtons,
-} from '../../test-utils';
-import { GradleBuildDSL } from '../../types';
-import JenkinsTutorial, { JenkinsTutorialProps } from '../JenkinsTutorial';
-
-jest.mock('../../../../api/settings', () => ({
- getAllValues: jest.fn().mockResolvedValue([]),
-}));
-
-const tokenMock = new UserTokensMock();
-const almMock = new AlmSettingsServiceMock();
-
-afterEach(() => {
- tokenMock.reset();
- almMock.reset();
-});
-
-const ui = {
- devopsPlatformTitle: byRole('heading', {
- name: 'onboarding.tutorial.with.jenkins.alm_selection.title',
- }),
- devopsPlatformButton: (alm: AlmKeys) => byRole('radio', { name: `alm.${alm}.long` }),
- prerequisitesTitle: byRole('heading', { name: 'onboarding.tutorial.with.jenkins.prereqs.title' }),
- branchSourcePluginBulletPoint: (alm: AlmKeys) =>
- byText(`onboarding.tutorial.with.jenkins.prereqs.plugins.branch_source.${alm}`),
- multiBranchStepTitle: byRole('heading', {
- name: 'onboarding.tutorial.with.jenkins.multi_branch_pipeline.title',
- }),
- multiBranchPipelineSecondListItem: (alm: AlmKeys) =>
- byText(`onboarding.tutorial.with.jenkins.multi_branch_pipeline.step2.${alm}.sentence`),
- pipelineStepTitle: byRole('heading', { name: 'onboarding.tutorial.with.jenkins.pipeline.title' }),
- pipelineIntroText: byText('onboarding.tutorial.with.jenkins.pipeline.intro'),
- webhookStepTitle: (alm: AlmKeys) =>
- byRole('heading', {
- name: `onboarding.tutorial.with.jenkins.webhook.${alm}.title`,
- }),
- webhookStepIntroSentence: byText('onboarding.tutorial.with.jenkins.webhook.intro.sentence'),
- webhookGHLink: byRole('link', {
- name: 'onboarding.tutorial.with.jenkins.webhook.github.step1.link',
- }),
- webhookAlmLink: (alm: AlmKeys) =>
- byRole('link', {
- name: new RegExp(`onboarding.tutorial.with.jenkins.webhook.${alm}.step1.link`),
- }),
- jenkinsStepTitle: byRole('heading', {
- name: 'onboarding.tutorial.with.jenkins.jenkinsfile.title',
- }),
- allSetSentence: byText('onboarding.tutorial.ci_outro.done'),
- ...getTutorialActionButtons(),
- ...getTutorialBuildButtons(),
-};
-
-it.each([AlmKeys.BitbucketCloud, AlmKeys.BitbucketServer, AlmKeys.GitHub, AlmKeys.GitLab])(
- '%s: can select devops platform and complete all the steps with copying code snippets',
- async (alm: AlmKeys) => {
- const user = userEvent.setup();
- renderJenkinsTutorial();
-
- expect(await ui.devopsPlatformTitle.find()).toBeInTheDocument();
-
- // 1. Select platform and go to prerequisites step
- await user.click(ui.devopsPlatformButton(alm).get());
-
- // 2. Prerequisites
- expect(ui.branchSourcePluginBulletPoint(alm).get()).toBeInTheDocument();
-
- // 3. Multibranch Pipeline Job
- expect(ui.multiBranchPipelineSecondListItem(alm).get()).toBeInTheDocument();
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(`ref spec`);
-
- // 4. Create DevOps platform webhook
- expect(ui.webhookStepTitle(alm).get()).toBeInTheDocument();
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(`jenkins url`);
-
- // 5. Create jenkinsfile
- // Maven
- await user.click(ui.mavenBuildButton.get());
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(`maven jenkinsfile`);
-
- // Gradle (Groovy)
- await user.click(ui.gradleBuildButton.get());
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- `Groovy: build.gradle file`,
- );
- // Gradle(Kotlin)
- await user.click(ui.gradleDSLButton(GradleBuildDSL.Kotlin).get());
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- `Kotlin: build.gradle.kts file`,
- );
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(`gradle jenkinsfile`);
-
- // .NET
- await user.click(ui.dotnetBuildButton.get());
- await user.click(ui.windowsDotnetCoreButton.get());
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- `windows dotnet core jenkinsfile`,
- );
-
- await user.click(ui.windowsDotnetFrameworkButton.get());
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- `windows dotnet framework jenkinsfile`,
- );
-
- await user.click(ui.linuxDotnetCoreButton.get());
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- `linux dotnet core jenkinsfile`,
- );
-
- // C++ (automatic)
- await user.click(ui.cppBuildButton.get());
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- `c++ (automatic and other): build tools sonar-project.properties code`,
- );
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- `c++ (automatic and other): build tools jenkinsfile`,
- );
-
- // C++ (manual)
- await user.click(ui.autoConfigManual.get());
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- `sonar-project.properties code`,
- );
-
- await user.click(ui.linuxButton.get());
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- `c++ (manual) and objectivec: linux jenkinsfile`,
- );
-
- await user.click(ui.arm64Button.get());
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- `c++ (manual) and objectivec: linux arm64 jenkinsfile`,
- );
-
- await user.click(ui.windowsButton.get());
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- `c++ (manual) and objectivec: windows jenkinsfile`,
- );
-
- await user.click(ui.macosButton.get());
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- `c++ (manual) and objectivec: macos jenkinsfile`,
- );
-
- // Objective-C
- await user.click(ui.objCBuildButton.get());
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- `sonar-project.properties code`,
- );
-
- await user.click(ui.linuxButton.get());
- await user.click(ui.x86_64Button.get());
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- `objectivec: linux jenkinsfile`,
- );
-
- await user.click(ui.arm64Button.get());
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- `objectivec: linux arm64 jenkinsfile`,
- );
-
- await user.click(ui.windowsButton.get());
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- `objectivec: windows jenkinsfile`,
- );
-
- await user.click(ui.macosButton.get());
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- `objectivec: macos jenkinsfile`,
- );
-
- // Dart
- await user.click(ui.dartBuildButton.get());
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- `Dart: sonar-project.properties`,
- );
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(`Dart: jenkinsfile`);
-
- // Other
- await user.click(ui.otherBuildButton.get());
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- `c++ (automatic and other): build tools sonar-project.properties code`,
- );
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- `c++ (automatic and other): build tools jenkinsfile`,
- );
-
- expect(ui.allSetSentence.get()).toBeInTheDocument();
- },
-);
-
-it.each([AlmKeys.GitHub, AlmKeys.GitLab, AlmKeys.BitbucketCloud])(
- '%s: has Pipeline step instead of MultiBranchPipeline step if branchSupport is not enabled',
- async (alm: AlmKeys) => {
- const user = userEvent.setup();
- renderJenkinsTutorial({}, { featureList: [] });
-
- expect(await ui.devopsPlatformTitle.find()).toBeInTheDocument();
- await user.click(ui.devopsPlatformButton(alm).get());
- expect(ui.pipelineIntroText.get()).toBeInTheDocument();
- },
-);
-
-it.each([AlmKeys.GitHub, AlmKeys.BitbucketCloud])(
- '%s: completes tutorial with bound alm and project',
- async (alm: AlmKeys) => {
- const user = userEvent.setup();
- await almMock.handleSetProjectBinding(alm, {
- almSetting: 'my-project',
- project: 'my-project',
- repository: 'my-project',
- monorepo: true,
- });
- renderJenkinsTutorial({
- almBinding: {
- alm,
- url: 'http://localhost/qube',
- key: 'my-project',
- },
- });
-
- await waitFor(() => expect(ui.devopsPlatformTitle.query()).not.toBeInTheDocument());
-
- expect(ui.webhookAlmLink(alm).get()).toBeInTheDocument();
- await user.click(ui.mavenBuildButton.get());
- expect(ui.allSetSentence.get()).toBeInTheDocument();
- },
-);
-
-it('navigates between steps', async () => {
- const user = userEvent.setup();
- renderJenkinsTutorial();
-
- await user.click(ui.devopsPlatformButton(AlmKeys.GitHub).get());
- await user.click(ui.mavenBuildButton.get());
- expect(ui.allSetSentence.get()).toBeInTheDocument();
-
- // Navigate back
- await user.click(ui.jenkinsStepTitle.get());
- expect(ui.mavenBuildButton.get()).toBeInTheDocument();
-
- await user.click(ui.webhookStepTitle(AlmKeys.GitHub).get());
- expect(ui.webhookStepIntroSentence.get()).toBeInTheDocument();
-
- await user.click(ui.multiBranchStepTitle.get());
- expect(ui.multiBranchPipelineSecondListItem(AlmKeys.GitHub).get()).toBeInTheDocument();
-
- await user.click(ui.prerequisitesTitle.get());
-
- await user.click(ui.devopsPlatformTitle.get());
- expect(ui.devopsPlatformButton(AlmKeys.BitbucketCloud).get()).toBeInTheDocument();
-});
-
-function renderJenkinsTutorial(
- overrides: Partial<JenkinsTutorialProps> = {},
- {
- featureList = [Feature.BranchSupport],
- languages = { c: mockLanguage({ key: 'c' }) },
- }: RenderContext = {},
-) {
- return renderApp(
- '/',
- <JenkinsTutorial baseUrl="http://localhost:9000" component={mockComponent()} {...overrides} />,
- { featureList, languages },
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-it.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-it.tsx.snap
deleted file mode 100644
index 67f83ff1ffc..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-it.tsx.snap
+++ /dev/null
@@ -1,1461 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: Dart: jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner"
- }
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: Dart: sonar-project.properties 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: Groovy: build.gradle file 1`] = `
-"plugins {
- id "org.sonarqube" version "6.0.1.5171"
-}
-
-sonar {
- properties {
- property "sonar.projectKey", "my-project"
- property "sonar.projectName", "MyProject"
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: Kotlin: build.gradle.kts file 1`] = `
-"plugins {
- id("org.sonarqube") version "6.0.1.5171"
-}
-
-sonar {
- properties {
- property("sonar.projectKey", "my-project")
- property("sonar.projectName", "MyProject")
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner"
- }
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools jenkinsfile 2`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner"
- }
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools sonar-project.properties code 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools sonar-project.properties code 2`] = `"sonar.projectKey=my-project"`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: linux arm64 jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-aarch64.zip http://localhost:9000/static/cpp/build-wrapper-linux-aarch64.zip"
- sh "unzip -o build-wrapper-linux-aarch64.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-aarch64/build-wrapper-linux-aarch64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: linux jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-x86.zip http://localhost:9000/static/cpp/build-wrapper-linux-x86.zip"
- sh "unzip -o build-wrapper-linux-x86.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: macos jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh '''
- mkdir -p .sonar
- curl -sSLo build-wrapper-macosx-x86.zip http://localhost:9000/static/cpp/build-wrapper-macosx-x86.zip
- unzip -o build-wrapper-macosx-x86.zip -d .sonar
- '''
- }
- stage('Build') {
- sh '''
- .sonar/build-wrapper-macosx-x86/build-wrapper-macosx-x86 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: windows jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- powershell '''
- $path = "$HOME/.sonar/build-wrapper-win-x86.zip"
- rm build-wrapper-win-x86 -Recurse -Force -ErrorAction SilentlyContinue
- rm $path -Force -ErrorAction SilentlyContinue
- mkdir $HOME/.sonar
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
- (New-Object System.Net.WebClient).DownloadFile(http://localhost:9000/static/cpp/build-wrapper-win-x86.zip", $path)
- Add-Type -AssemblyName System.IO.Compression.FileSystem
- [System.IO.Compression.ZipFile]::ExtractToDirectory($path, "$HOME/.sonar")
- '''
- }
- stage('Build') {
- powershell '''
- $env:Path += ";$HOME/.sonar/build-wrapper-win-x86"
- build-wrapper-win-x86-64 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- powershell "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: gradle jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- withSonarQubeEnv() {
- sh "./gradlew sonar"
- }
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: jenkins url 1`] = `"***JENKINS_SERVER_URL***/bitbucket-scmsource-hook/notify?server_url=***BITBUCKET_URL***"`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: linux dotnet core jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner for .NET'
- withSonarQubeEnv() {
- sh "dotnet \${scannerHome}/SonarScanner.MSBuild.dll begin /k:\\"my-project\\""
- sh "dotnet build"
- sh "dotnet \${scannerHome}/SonarScanner.MSBuild.dll end"
- }
- }
-}
-"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: maven jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def mvn = tool 'Default Maven';
- withSonarQubeEnv() {
- sh "\${mvn}/bin/mvn clean verify sonar:sonar -Dsonar.projectKey=my-project -Dsonar.projectName='MyProject'"
- }
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: objectivec: linux arm64 jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-aarch64.zip http://localhost:9000/static/cpp/build-wrapper-linux-aarch64.zip"
- sh "unzip -o build-wrapper-linux-aarch64.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-aarch64/build-wrapper-linux-aarch64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: objectivec: linux jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-x86.zip http://localhost:9000/static/cpp/build-wrapper-linux-x86.zip"
- sh "unzip -o build-wrapper-linux-x86.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: objectivec: macos jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh '''
- mkdir -p .sonar
- curl -sSLo build-wrapper-macosx-x86.zip http://localhost:9000/static/cpp/build-wrapper-macosx-x86.zip
- unzip -o build-wrapper-macosx-x86.zip -d .sonar
- '''
- }
- stage('Build') {
- sh '''
- .sonar/build-wrapper-macosx-x86/build-wrapper-macosx-x86 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: objectivec: windows jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- powershell '''
- $path = "$HOME/.sonar/build-wrapper-win-x86.zip"
- rm build-wrapper-win-x86 -Recurse -Force -ErrorAction SilentlyContinue
- rm $path -Force -ErrorAction SilentlyContinue
- mkdir $HOME/.sonar
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
- (New-Object System.Net.WebClient).DownloadFile(http://localhost:9000/static/cpp/build-wrapper-win-x86.zip", $path)
- Add-Type -AssemblyName System.IO.Compression.FileSystem
- [System.IO.Compression.ZipFile]::ExtractToDirectory($path, "$HOME/.sonar")
- '''
- }
- stage('Build') {
- powershell '''
- $env:Path += ";$HOME/.sonar/build-wrapper-win-x86"
- build-wrapper-win-x86-64 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- powershell "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: ref spec 1`] = `"+refs/heads/*:refs/remotes/@{remote}/*"`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: sonar-project.properties code 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: sonar-project.properties code 2`] = `"sonar.projectKey=my-project"`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: windows dotnet core jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner for .NET'
- withSonarQubeEnv() {
- bat "dotnet \${scannerHome}\\\\SonarScanner.MSBuild.dll begin /k:\\"my-project\\""
- bat "dotnet build"
- bat "dotnet \${scannerHome}\\\\SonarScanner.MSBuild.dll end"
- }
- }
-}
-"
-`;
-
-exports[`bitbucket: can select devops platform and complete all the steps with copying code snippets: windows dotnet framework jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def msbuildHome = tool 'Default MSBuild'
- def scannerHome = tool 'SonarScanner for .NET'
- withSonarQubeEnv() {
- bat "\\"\${scannerHome}\\\\SonarScanner.MSBuild.exe\\" begin /k:\\"my-project\\""
- bat "\\"\${msbuildHome}\\\\MSBuild.exe\\" /t:Rebuild"
- bat "\\"\${scannerHome}\\\\SonarScanner.MSBuild.exe\\" end"
- }
- }
-}
-"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: Dart: jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner"
- }
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: Dart: sonar-project.properties 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: Groovy: build.gradle file 1`] = `
-"plugins {
- id "org.sonarqube" version "6.0.1.5171"
-}
-
-sonar {
- properties {
- property "sonar.projectKey", "my-project"
- property "sonar.projectName", "MyProject"
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: Kotlin: build.gradle.kts file 1`] = `
-"plugins {
- id("org.sonarqube") version "6.0.1.5171"
-}
-
-sonar {
- properties {
- property("sonar.projectKey", "my-project")
- property("sonar.projectName", "MyProject")
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner"
- }
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools jenkinsfile 2`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner"
- }
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools sonar-project.properties code 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools sonar-project.properties code 2`] = `"sonar.projectKey=my-project"`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: linux arm64 jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-aarch64.zip http://localhost:9000/static/cpp/build-wrapper-linux-aarch64.zip"
- sh "unzip -o build-wrapper-linux-aarch64.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-aarch64/build-wrapper-linux-aarch64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: linux jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-x86.zip http://localhost:9000/static/cpp/build-wrapper-linux-x86.zip"
- sh "unzip -o build-wrapper-linux-x86.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: macos jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh '''
- mkdir -p .sonar
- curl -sSLo build-wrapper-macosx-x86.zip http://localhost:9000/static/cpp/build-wrapper-macosx-x86.zip
- unzip -o build-wrapper-macosx-x86.zip -d .sonar
- '''
- }
- stage('Build') {
- sh '''
- .sonar/build-wrapper-macosx-x86/build-wrapper-macosx-x86 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: windows jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- powershell '''
- $path = "$HOME/.sonar/build-wrapper-win-x86.zip"
- rm build-wrapper-win-x86 -Recurse -Force -ErrorAction SilentlyContinue
- rm $path -Force -ErrorAction SilentlyContinue
- mkdir $HOME/.sonar
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
- (New-Object System.Net.WebClient).DownloadFile(http://localhost:9000/static/cpp/build-wrapper-win-x86.zip", $path)
- Add-Type -AssemblyName System.IO.Compression.FileSystem
- [System.IO.Compression.ZipFile]::ExtractToDirectory($path, "$HOME/.sonar")
- '''
- }
- stage('Build') {
- powershell '''
- $env:Path += ";$HOME/.sonar/build-wrapper-win-x86"
- build-wrapper-win-x86-64 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- powershell "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: gradle jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- withSonarQubeEnv() {
- sh "./gradlew sonar"
- }
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: jenkins url 1`] = `"***JENKINS_SERVER_URL***/bitbucket-scmsource-hook/notify"`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: linux dotnet core jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner for .NET'
- withSonarQubeEnv() {
- sh "dotnet \${scannerHome}/SonarScanner.MSBuild.dll begin /k:\\"my-project\\""
- sh "dotnet build"
- sh "dotnet \${scannerHome}/SonarScanner.MSBuild.dll end"
- }
- }
-}
-"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: maven jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def mvn = tool 'Default Maven';
- withSonarQubeEnv() {
- sh "\${mvn}/bin/mvn clean verify sonar:sonar -Dsonar.projectKey=my-project -Dsonar.projectName='MyProject'"
- }
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: objectivec: linux arm64 jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-aarch64.zip http://localhost:9000/static/cpp/build-wrapper-linux-aarch64.zip"
- sh "unzip -o build-wrapper-linux-aarch64.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-aarch64/build-wrapper-linux-aarch64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: objectivec: linux jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-x86.zip http://localhost:9000/static/cpp/build-wrapper-linux-x86.zip"
- sh "unzip -o build-wrapper-linux-x86.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: objectivec: macos jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh '''
- mkdir -p .sonar
- curl -sSLo build-wrapper-macosx-x86.zip http://localhost:9000/static/cpp/build-wrapper-macosx-x86.zip
- unzip -o build-wrapper-macosx-x86.zip -d .sonar
- '''
- }
- stage('Build') {
- sh '''
- .sonar/build-wrapper-macosx-x86/build-wrapper-macosx-x86 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: objectivec: windows jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- powershell '''
- $path = "$HOME/.sonar/build-wrapper-win-x86.zip"
- rm build-wrapper-win-x86 -Recurse -Force -ErrorAction SilentlyContinue
- rm $path -Force -ErrorAction SilentlyContinue
- mkdir $HOME/.sonar
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
- (New-Object System.Net.WebClient).DownloadFile(http://localhost:9000/static/cpp/build-wrapper-win-x86.zip", $path)
- Add-Type -AssemblyName System.IO.Compression.FileSystem
- [System.IO.Compression.ZipFile]::ExtractToDirectory($path, "$HOME/.sonar")
- '''
- }
- stage('Build') {
- powershell '''
- $env:Path += ";$HOME/.sonar/build-wrapper-win-x86"
- build-wrapper-win-x86-64 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- powershell "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: ref spec 1`] = `"+refs/heads/*:refs/remotes/@{remote}/*"`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: sonar-project.properties code 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: sonar-project.properties code 2`] = `"sonar.projectKey=my-project"`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: windows dotnet core jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner for .NET'
- withSonarQubeEnv() {
- bat "dotnet \${scannerHome}\\\\SonarScanner.MSBuild.dll begin /k:\\"my-project\\""
- bat "dotnet build"
- bat "dotnet \${scannerHome}\\\\SonarScanner.MSBuild.dll end"
- }
- }
-}
-"
-`;
-
-exports[`bitbucketcloud: can select devops platform and complete all the steps with copying code snippets: windows dotnet framework jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def msbuildHome = tool 'Default MSBuild'
- def scannerHome = tool 'SonarScanner for .NET'
- withSonarQubeEnv() {
- bat "\\"\${scannerHome}\\\\SonarScanner.MSBuild.exe\\" begin /k:\\"my-project\\""
- bat "\\"\${msbuildHome}\\\\MSBuild.exe\\" /t:Rebuild"
- bat "\\"\${scannerHome}\\\\SonarScanner.MSBuild.exe\\" end"
- }
- }
-}
-"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: Dart: jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner"
- }
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: Dart: sonar-project.properties 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: Groovy: build.gradle file 1`] = `
-"plugins {
- id "org.sonarqube" version "6.0.1.5171"
-}
-
-sonar {
- properties {
- property "sonar.projectKey", "my-project"
- property "sonar.projectName", "MyProject"
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: Kotlin: build.gradle.kts file 1`] = `
-"plugins {
- id("org.sonarqube") version "6.0.1.5171"
-}
-
-sonar {
- properties {
- property("sonar.projectKey", "my-project")
- property("sonar.projectName", "MyProject")
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner"
- }
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools jenkinsfile 2`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner"
- }
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools sonar-project.properties code 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools sonar-project.properties code 2`] = `"sonar.projectKey=my-project"`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: linux arm64 jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-aarch64.zip http://localhost:9000/static/cpp/build-wrapper-linux-aarch64.zip"
- sh "unzip -o build-wrapper-linux-aarch64.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-aarch64/build-wrapper-linux-aarch64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: linux jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-x86.zip http://localhost:9000/static/cpp/build-wrapper-linux-x86.zip"
- sh "unzip -o build-wrapper-linux-x86.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: macos jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh '''
- mkdir -p .sonar
- curl -sSLo build-wrapper-macosx-x86.zip http://localhost:9000/static/cpp/build-wrapper-macosx-x86.zip
- unzip -o build-wrapper-macosx-x86.zip -d .sonar
- '''
- }
- stage('Build') {
- sh '''
- .sonar/build-wrapper-macosx-x86/build-wrapper-macosx-x86 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: windows jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- powershell '''
- $path = "$HOME/.sonar/build-wrapper-win-x86.zip"
- rm build-wrapper-win-x86 -Recurse -Force -ErrorAction SilentlyContinue
- rm $path -Force -ErrorAction SilentlyContinue
- mkdir $HOME/.sonar
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
- (New-Object System.Net.WebClient).DownloadFile(http://localhost:9000/static/cpp/build-wrapper-win-x86.zip", $path)
- Add-Type -AssemblyName System.IO.Compression.FileSystem
- [System.IO.Compression.ZipFile]::ExtractToDirectory($path, "$HOME/.sonar")
- '''
- }
- stage('Build') {
- powershell '''
- $env:Path += ";$HOME/.sonar/build-wrapper-win-x86"
- build-wrapper-win-x86-64 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- powershell "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: gradle jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- withSonarQubeEnv() {
- sh "./gradlew sonar"
- }
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: jenkins url 1`] = `"***JENKINS_SERVER_URL***/github-webhook/"`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: linux dotnet core jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner for .NET'
- withSonarQubeEnv() {
- sh "dotnet \${scannerHome}/SonarScanner.MSBuild.dll begin /k:\\"my-project\\""
- sh "dotnet build"
- sh "dotnet \${scannerHome}/SonarScanner.MSBuild.dll end"
- }
- }
-}
-"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: maven jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def mvn = tool 'Default Maven';
- withSonarQubeEnv() {
- sh "\${mvn}/bin/mvn clean verify sonar:sonar -Dsonar.projectKey=my-project -Dsonar.projectName='MyProject'"
- }
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: objectivec: linux arm64 jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-aarch64.zip http://localhost:9000/static/cpp/build-wrapper-linux-aarch64.zip"
- sh "unzip -o build-wrapper-linux-aarch64.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-aarch64/build-wrapper-linux-aarch64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: objectivec: linux jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-x86.zip http://localhost:9000/static/cpp/build-wrapper-linux-x86.zip"
- sh "unzip -o build-wrapper-linux-x86.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: objectivec: macos jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh '''
- mkdir -p .sonar
- curl -sSLo build-wrapper-macosx-x86.zip http://localhost:9000/static/cpp/build-wrapper-macosx-x86.zip
- unzip -o build-wrapper-macosx-x86.zip -d .sonar
- '''
- }
- stage('Build') {
- sh '''
- .sonar/build-wrapper-macosx-x86/build-wrapper-macosx-x86 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: objectivec: windows jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- powershell '''
- $path = "$HOME/.sonar/build-wrapper-win-x86.zip"
- rm build-wrapper-win-x86 -Recurse -Force -ErrorAction SilentlyContinue
- rm $path -Force -ErrorAction SilentlyContinue
- mkdir $HOME/.sonar
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
- (New-Object System.Net.WebClient).DownloadFile(http://localhost:9000/static/cpp/build-wrapper-win-x86.zip", $path)
- Add-Type -AssemblyName System.IO.Compression.FileSystem
- [System.IO.Compression.ZipFile]::ExtractToDirectory($path, "$HOME/.sonar")
- '''
- }
- stage('Build') {
- powershell '''
- $env:Path += ";$HOME/.sonar/build-wrapper-win-x86"
- build-wrapper-win-x86-64 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- powershell "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: ref spec 1`] = `"+refs/heads/*:refs/remotes/@{remote}/*"`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: sonar-project.properties code 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: sonar-project.properties code 2`] = `"sonar.projectKey=my-project"`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: windows dotnet core jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner for .NET'
- withSonarQubeEnv() {
- bat "dotnet \${scannerHome}\\\\SonarScanner.MSBuild.dll begin /k:\\"my-project\\""
- bat "dotnet build"
- bat "dotnet \${scannerHome}\\\\SonarScanner.MSBuild.dll end"
- }
- }
-}
-"
-`;
-
-exports[`github: can select devops platform and complete all the steps with copying code snippets: windows dotnet framework jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def msbuildHome = tool 'Default MSBuild'
- def scannerHome = tool 'SonarScanner for .NET'
- withSonarQubeEnv() {
- bat "\\"\${scannerHome}\\\\SonarScanner.MSBuild.exe\\" begin /k:\\"my-project\\""
- bat "\\"\${msbuildHome}\\\\MSBuild.exe\\" /t:Rebuild"
- bat "\\"\${scannerHome}\\\\SonarScanner.MSBuild.exe\\" end"
- }
- }
-}
-"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: Dart: jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner"
- }
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: Dart: sonar-project.properties 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: Groovy: build.gradle file 1`] = `
-"plugins {
- id "org.sonarqube" version "6.0.1.5171"
-}
-
-sonar {
- properties {
- property "sonar.projectKey", "my-project"
- property "sonar.projectName", "MyProject"
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: Kotlin: build.gradle.kts file 1`] = `
-"plugins {
- id("org.sonarqube") version "6.0.1.5171"
-}
-
-sonar {
- properties {
- property("sonar.projectKey", "my-project")
- property("sonar.projectName", "MyProject")
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner"
- }
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools jenkinsfile 2`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner"
- }
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools sonar-project.properties code 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: c++ (automatic and other): build tools sonar-project.properties code 2`] = `"sonar.projectKey=my-project"`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: linux arm64 jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-aarch64.zip http://localhost:9000/static/cpp/build-wrapper-linux-aarch64.zip"
- sh "unzip -o build-wrapper-linux-aarch64.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-aarch64/build-wrapper-linux-aarch64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: linux jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-x86.zip http://localhost:9000/static/cpp/build-wrapper-linux-x86.zip"
- sh "unzip -o build-wrapper-linux-x86.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: macos jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh '''
- mkdir -p .sonar
- curl -sSLo build-wrapper-macosx-x86.zip http://localhost:9000/static/cpp/build-wrapper-macosx-x86.zip
- unzip -o build-wrapper-macosx-x86.zip -d .sonar
- '''
- }
- stage('Build') {
- sh '''
- .sonar/build-wrapper-macosx-x86/build-wrapper-macosx-x86 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: c++ (manual) and objectivec: windows jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- powershell '''
- $path = "$HOME/.sonar/build-wrapper-win-x86.zip"
- rm build-wrapper-win-x86 -Recurse -Force -ErrorAction SilentlyContinue
- rm $path -Force -ErrorAction SilentlyContinue
- mkdir $HOME/.sonar
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
- (New-Object System.Net.WebClient).DownloadFile(http://localhost:9000/static/cpp/build-wrapper-win-x86.zip", $path)
- Add-Type -AssemblyName System.IO.Compression.FileSystem
- [System.IO.Compression.ZipFile]::ExtractToDirectory($path, "$HOME/.sonar")
- '''
- }
- stage('Build') {
- powershell '''
- $env:Path += ";$HOME/.sonar/build-wrapper-win-x86"
- build-wrapper-win-x86-64 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- powershell "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: gradle jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- withSonarQubeEnv() {
- sh "./gradlew sonar"
- }
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: jenkins url 1`] = `"***JENKINS_SERVER_URL***/gitlab-webhook/post"`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: linux dotnet core jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner for .NET'
- withSonarQubeEnv() {
- sh "dotnet \${scannerHome}/SonarScanner.MSBuild.dll begin /k:\\"my-project\\""
- sh "dotnet build"
- sh "dotnet \${scannerHome}/SonarScanner.MSBuild.dll end"
- }
- }
-}
-"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: maven jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def mvn = tool 'Default Maven';
- withSonarQubeEnv() {
- sh "\${mvn}/bin/mvn clean verify sonar:sonar -Dsonar.projectKey=my-project -Dsonar.projectName='MyProject'"
- }
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: objectivec: linux arm64 jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-aarch64.zip http://localhost:9000/static/cpp/build-wrapper-linux-aarch64.zip"
- sh "unzip -o build-wrapper-linux-aarch64.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-aarch64/build-wrapper-linux-aarch64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: objectivec: linux jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo build-wrapper-linux-x86.zip http://localhost:9000/static/cpp/build-wrapper-linux-x86.zip"
- sh "unzip -o build-wrapper-linux-x86.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: objectivec: macos jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh '''
- mkdir -p .sonar
- curl -sSLo build-wrapper-macosx-x86.zip http://localhost:9000/static/cpp/build-wrapper-macosx-x86.zip
- unzip -o build-wrapper-macosx-x86.zip -d .sonar
- '''
- }
- stage('Build') {
- sh '''
- .sonar/build-wrapper-macosx-x86/build-wrapper-macosx-x86 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: objectivec: windows jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- powershell '''
- $path = "$HOME/.sonar/build-wrapper-win-x86.zip"
- rm build-wrapper-win-x86 -Recurse -Force -ErrorAction SilentlyContinue
- rm $path -Force -ErrorAction SilentlyContinue
- mkdir $HOME/.sonar
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
- (New-Object System.Net.WebClient).DownloadFile(http://localhost:9000/static/cpp/build-wrapper-win-x86.zip", $path)
- Add-Type -AssemblyName System.IO.Compression.FileSystem
- [System.IO.Compression.ZipFile]::ExtractToDirectory($path, "$HOME/.sonar")
- '''
- }
- stage('Build') {
- powershell '''
- $env:Path += ";$HOME/.sonar/build-wrapper-win-x86"
- build-wrapper-win-x86-64 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- powershell "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: ref spec 1`] = `"+refs/heads/*:refs/remotes/@{remote}/*"`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: sonar-project.properties code 1`] = `"sonar.projectKey=my-project"`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: sonar-project.properties code 2`] = `"sonar.projectKey=my-project"`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: windows dotnet core jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner for .NET'
- withSonarQubeEnv() {
- bat "dotnet \${scannerHome}\\\\SonarScanner.MSBuild.dll begin /k:\\"my-project\\""
- bat "dotnet build"
- bat "dotnet \${scannerHome}\\\\SonarScanner.MSBuild.dll end"
- }
- }
-}
-"
-`;
-
-exports[`gitlab: can select devops platform and complete all the steps with copying code snippets: windows dotnet framework jenkinsfile 1`] = `
-"node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def msbuildHome = tool 'Default MSBuild'
- def scannerHome = tool 'SonarScanner for .NET'
- withSonarQubeEnv() {
- bat "\\"\${scannerHome}\\\\SonarScanner.MSBuild.exe\\" begin /k:\\"my-project\\""
- bat "\\"\${msbuildHome}\\\\MSBuild.exe\\" /t:Rebuild"
- bat "\\"\${scannerHome}\\\\SonarScanner.MSBuild.exe\\" end"
- }
- }
-}
-"
-`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/CFamily.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/CFamily.tsx
deleted file mode 100644
index 9ad4da48260..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/CFamily.tsx
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { NumberedListItem } from '~design-system';
-import { translate } from '../../../../helpers/l10n';
-import { CompilationInfo } from '../../components/CompilationInfo';
-import DefaultProjectKey from '../../components/DefaultProjectKey';
-import GithubCFamilyExampleRepositories from '../../components/GithubCFamilyExampleRepositories';
-import RenderOptions from '../../components/RenderOptions';
-import { Arch, AutoConfig, BuildTools, OSs, TutorialModes } from '../../types';
-import { getBuildWrapperExecutableLinux, getBuildWrapperFolderLinux } from '../../utils';
-import { LanguageProps } from '../JenkinsStep';
-import CreateJenkinsfileBulletPoint from './CreateJenkinsfileBulletPoint';
-import Other from './Other';
-
-const YAML_MAP: Record<OSs, (baseUrl: string, arch: Arch) => string> = {
- [OSs.Linux]: (baseUrl, arch) => {
- const buildWrapperFolder = getBuildWrapperFolderLinux(arch);
- const buildWrapperExecutable = getBuildWrapperExecutableLinux(arch);
- return `node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh "mkdir -p .sonar"
- sh "curl -sSLo ${buildWrapperFolder}.zip ${baseUrl}/static/cpp/${buildWrapperFolder}.zip"
- sh "unzip -o ${buildWrapperFolder}.zip -d .sonar"
- }
- stage('Build') {
- sh ".sonar/${buildWrapperFolder}/${buildWrapperExecutable} --out-dir bw-output <your clean build command>"
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}`;
- },
- [OSs.MacOS]: (baseUrl, _) => `node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- sh '''
- mkdir -p .sonar
- curl -sSLo build-wrapper-macosx-x86.zip ${baseUrl}/static/cpp/build-wrapper-macosx-x86.zip
- unzip -o build-wrapper-macosx-x86.zip -d .sonar
- '''
- }
- stage('Build') {
- sh '''
- .sonar/build-wrapper-macosx-x86/build-wrapper-macosx-x86 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}`,
- [OSs.Windows]: (baseUrl, _) => `node {
- stage('SCM') {
- checkout scm
- }
- stage('Download Build Wrapper') {
- powershell '''
- $path = "$HOME/.sonar/build-wrapper-win-x86.zip"
- rm build-wrapper-win-x86 -Recurse -Force -ErrorAction SilentlyContinue
- rm $path -Force -ErrorAction SilentlyContinue
- mkdir $HOME/.sonar
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
- (New-Object System.Net.WebClient).DownloadFile(${baseUrl}/static/cpp/build-wrapper-win-x86.zip", $path)
- Add-Type -AssemblyName System.IO.Compression.FileSystem
- [System.IO.Compression.ZipFile]::ExtractToDirectory($path, "$HOME/.sonar")
- '''
- }
- stage('Build') {
- powershell '''
- $env:Path += ";$HOME/.sonar/build-wrapper-win-x86"
- build-wrapper-win-x86-64 --out-dir bw-output <your clean build command>
- '''
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- powershell "\${scannerHome}/bin/sonar-scanner -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json"
- }
- }
-}`,
-};
-
-export default function CFamily(props: Readonly<LanguageProps>) {
- const { baseUrl, config, component } = props;
- const [os, setOs] = React.useState<OSs>(OSs.Linux);
- const [arch, setArch] = React.useState<Arch>(Arch.X86_64);
-
- if (config.buildTool === BuildTools.Cpp && config.autoConfig === AutoConfig.Automatic) {
- return <Other {...props} />;
- }
-
- return (
- <>
- <DefaultProjectKey component={component} />
- <NumberedListItem>
- {translate('onboarding.build.other.os')}
- <RenderOptions
- label={translate('onboarding.build.other.os')}
- checked={os}
- optionLabelKey="onboarding.build.other.os"
- onCheck={(value: OSs) => setOs(value)}
- options={Object.values(OSs)}
- />
- {
- <GithubCFamilyExampleRepositories
- ci={TutorialModes.Jenkins}
- os={os}
- className="sw-my-4 sw-w-abs-600"
- />
- }
- {os === OSs.Linux && (
- <>
- <div className="sw-mt-4">
- {translate('onboarding.tutorial.with.azure_pipelines.architecture')}
- </div>
- <RenderOptions
- label={translate('onboarding.tutorial.with.azure_pipelines.architecture')}
- checked={arch}
- onCheck={(value: Arch) => setArch(value)}
- optionLabelKey="onboarding.build.other.architecture"
- options={[Arch.X86_64, Arch.Arm64]}
- />
- </>
- )}
- </NumberedListItem>
- {
- <CreateJenkinsfileBulletPoint
- alertTranslationKeyPart="onboarding.tutorial.with.jenkins.jenkinsfile.other.step3"
- snippet={YAML_MAP[os](baseUrl, arch)}
- >
- <CompilationInfo />
- </CreateJenkinsfileBulletPoint>
- }
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/CreateJenkinsfileBulletPoint.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/CreateJenkinsfileBulletPoint.tsx
deleted file mode 100644
index 03dfea255c8..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/CreateJenkinsfileBulletPoint.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { CodeSnippet, FlagMessage, HelperHintIcon, NumberedListItem } from '~design-system';
-import HelpTooltip from '~sonar-aligned/components/controls/HelpTooltip';
-import SentenceWithFilename from '../../components/SentenceWithFilename';
-import SentenceWithHighlights from '../../components/SentenceWithHighlights';
-
-export interface CreateJenkinsfileBulletPointProps {
- alertTranslationKeyPart?: string;
- children?: React.ReactNode;
- snippet: string;
-}
-
-export default function CreateJenkinsfileBulletPoint(props: CreateJenkinsfileBulletPointProps) {
- const { children, snippet, alertTranslationKeyPart } = props;
-
- return (
- <NumberedListItem>
- <SentenceWithFilename
- filename="Jenkinsfile"
- translationKey="onboarding.tutorial.with.jenkins.jenkinsfile.jenkinsfile_step"
- />
- <br />
- {alertTranslationKeyPart && (
- <FlagMessage className="sw-mt-2" variant="info">
- <div>
- <SentenceWithHighlights
- highlightKeys={['default', 'in_jenkins']}
- translationKey={`${alertTranslationKeyPart}.replace`}
- />
- <HelpTooltip
- className="sw-ml-1"
- overlay={
- <>
- <p className="sw-mb-2">
- <SentenceWithHighlights
- highlightKeys={['path']}
- translationKey={`${alertTranslationKeyPart}.help1`}
- />
- </p>
- <p>
- <SentenceWithHighlights
- highlightKeys={['path', 'name']}
- translationKey={`${alertTranslationKeyPart}.help2`}
- />
- </p>
- </>
- }
- >
- <HelperHintIcon />
- </HelpTooltip>
- </div>
- </FlagMessage>
- )}
- <CodeSnippet className="sw-p-6" language="groovy" snippet={snippet} />
- {children}
- </NumberedListItem>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNet.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNet.tsx
deleted file mode 100644
index f98236c303c..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNet.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { NumberedListItem } from '~design-system';
-import { translate } from '../../../../helpers/l10n';
-import { Component } from '../../../../types/types';
-import RenderOptions from '../../components/RenderOptions';
-import { OSs } from '../../types';
-import { LanguageProps } from '../JenkinsStep';
-import DotNetCore from './DotNetCore';
-import DotNetFramework from './DotNetFramework';
-
-export interface DotNetCoreFrameworkProps {
- component: Component;
- os: OSDotNet;
-}
-
-export type OSDotNet = OSs.Linux | OSs.Windows;
-
-const DotNetFlavor = { win_core: DotNetCore, win_msbuild: DotNetFramework, linux_core: DotNetCore };
-const DotOS: { [key in keyof typeof DotNetFlavor]: OSDotNet } = {
- win_core: OSs.Windows,
- win_msbuild: OSs.Windows,
- linux_core: OSs.Linux,
-};
-
-export default function DotNet(props: LanguageProps) {
- const { component } = props;
- const [flavorComponent, setFlavorComponent] =
- React.useState<keyof typeof DotNetFlavor>('win_core');
- const DotNetTutorial = flavorComponent && DotNetFlavor[flavorComponent];
-
- return (
- <>
- <NumberedListItem>
- {translate('onboarding.tutorial.with.jenkins.jenkinsfile.dotnet.build_agent')}
- <RenderOptions
- label={translate('onboarding.tutorial.with.jenkins.jenkinsfile.dotnet.build_agent')}
- checked={flavorComponent}
- optionLabelKey="onboarding.build.dotnet"
- onCheck={(value) => setFlavorComponent(value as keyof typeof DotNetFlavor)}
- options={Object.keys(DotNetFlavor)}
- />
- </NumberedListItem>
- {DotNetTutorial && flavorComponent && (
- <DotNetTutorial component={component} os={DotOS[flavorComponent]} />
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetCore.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetCore.tsx
deleted file mode 100644
index e43ad85a7e0..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetCore.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CodeSnippet, NumberedListItem } from '~design-system';
-import SentenceWithFilename from '../../components/SentenceWithFilename';
-import { OSs } from '../../types';
-import { DotNetCoreFrameworkProps, OSDotNet } from './DotNet';
-import DotNetPrereqsScanner from './DotNetPrereqsScanner';
-
-const OSS_DEP: { [key in OSDotNet]: { pathSeparator: string; shell: string } } = {
- [OSs.Linux]: { shell: 'sh', pathSeparator: '/' },
- [OSs.Windows]: { shell: 'bat', pathSeparator: '\\\\' },
-};
-
-const jenkinsfileSnippet = (key: string, shell: OSDotNet) => `node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner for .NET'
- withSonarQubeEnv() {
- ${OSS_DEP[shell].shell} "dotnet \${scannerHome}${OSS_DEP[shell].pathSeparator}SonarScanner.MSBuild.dll begin /k:\\"${key}\\""
- ${OSS_DEP[shell].shell} "dotnet build"
- ${OSS_DEP[shell].shell} "dotnet \${scannerHome}${OSS_DEP[shell].pathSeparator}SonarScanner.MSBuild.dll end"
- }
- }
-}
-`;
-
-export default function DotNetCore({ component, os }: DotNetCoreFrameworkProps) {
- return (
- <>
- <DotNetPrereqsScanner />
- <NumberedListItem>
- <SentenceWithFilename
- filename="Jenkinsfile"
- translationKey="onboarding.tutorial.with.jenkins.jenkinsfile.jenkinsfile_step"
- />
- <CodeSnippet
- className="sw-p-6"
- language="groovy"
- snippet={jenkinsfileSnippet(component.key, os)}
- />
- </NumberedListItem>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetFramework.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetFramework.tsx
deleted file mode 100644
index 8aa437ef78e..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetFramework.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CodeSnippet, NumberedListItem } from '~design-system';
-import SentenceWithFilename from '../../components/SentenceWithFilename';
-import { DotNetCoreFrameworkProps } from './DotNet';
-import DotNetPrereqsMSBuild from './DotNetPrereqsMSBuild';
-import DotNetPrereqsScanner from './DotNetPrereqsScanner';
-
-const jenkinsfileSnippet = (key: string) => `node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def msbuildHome = tool 'Default MSBuild'
- def scannerHome = tool 'SonarScanner for .NET'
- withSonarQubeEnv() {
- bat "\\"\${scannerHome}\\\\SonarScanner.MSBuild.exe\\" begin /k:\\"${key}\\""
- bat "\\"\${msbuildHome}\\\\MSBuild.exe\\" /t:Rebuild"
- bat "\\"\${scannerHome}\\\\SonarScanner.MSBuild.exe\\" end"
- }
- }
-}
-`;
-
-export default function DotNetFramework({ component }: DotNetCoreFrameworkProps) {
- return (
- <>
- <DotNetPrereqsScanner />
- <DotNetPrereqsMSBuild />
- <NumberedListItem>
- <SentenceWithFilename
- filename="Jenkinsfile"
- translationKey="onboarding.tutorial.with.jenkins.jenkinsfile.jenkinsfile_step"
- />
- <CodeSnippet
- className="sw-ml-8 sw-p-6"
- language="groovy"
- snippet={jenkinsfileSnippet(component.key)}
- />
- </NumberedListItem>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetPrereqsMSBuild.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetPrereqsMSBuild.tsx
deleted file mode 100644
index bfd2e07f37b..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetPrereqsMSBuild.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- ClipboardIconButton,
- FlagMessage,
- ListItem,
- NumberedListItem,
- OrderedList,
-} from '~design-system';
-import { translate } from '../../../../helpers/l10n';
-import { InlineSnippet } from '../../components/InlineSnippet';
-import SentenceWithHighlights from '../../components/SentenceWithHighlights';
-
-export default function DotNetPrereqsMSBuild() {
- return (
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['default_msbuild']}
- translationKey="onboarding.tutorial.with.jenkins.dotnet.msbuild.prereqs.title"
- />
- <div className="sw-ml-8 sw-mt-2">
- <FlagMessage variant="info">
- {translate('onboarding.tutorial.with.jenkins.dotnet.msbuild.prereqs.info')}
- </FlagMessage>
- </div>
- <OrderedList tickStyle="ALPHA" className="sw-ml-12">
- <ListItem>
- <SentenceWithHighlights
- highlightKeys={['msbuild']}
- translationKey="onboarding.tutorial.with.jenkins.dotnet.msbuild.prereqs.step1"
- />
- </ListItem>
- <ListItem>
- <SentenceWithHighlights
- highlightKeys={['path']}
- translationKey="onboarding.tutorial.with.jenkins.dotnet.msbuild.prereqs.step2"
- />
- </ListItem>
- <ListItem>
- <SentenceWithHighlights
- highlightKeys={['msbuild', 'add_msbuild', 'name', 'msbuild_plugin']}
- translationKey="onboarding.tutorial.with.jenkins.dotnet.msbuild.prereqs.step3"
- />
- <InlineSnippet className="sw-ml-1" snippet="Default MSBuild" />
- <ClipboardIconButton className="sw-ml-2 sw-align-sub" copyValue="Default MSBuild" />
- </ListItem>
- </OrderedList>
- </NumberedListItem>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetPrereqsScanner.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetPrereqsScanner.tsx
deleted file mode 100644
index 8d7e160a05f..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/DotNetPrereqsScanner.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- ClipboardIconButton,
- FlagMessage,
- ListItem,
- NumberedListItem,
- OrderedList,
-} from '~design-system';
-import { translate } from '../../../../helpers/l10n';
-import { InlineSnippet } from '../../components/InlineSnippet';
-import SentenceWithHighlights from '../../components/SentenceWithHighlights';
-
-export default function DotNetPrereqsScanner() {
- return (
- <NumberedListItem>
- <SentenceWithHighlights
- highlightKeys={['default_scanner']}
- translationKey="onboarding.tutorial.with.jenkins.dotnet.scanner.prereqs.title"
- />
- <br />
- <FlagMessage className="sw-mt-2" variant="info">
- {translate('onboarding.tutorial.with.jenkins.dotnet.scanner.prereqs.info')}
- </FlagMessage>
- <OrderedList tickStyle="ALPHA" className="sw-ml-12">
- <ListItem>
- <SentenceWithHighlights
- highlightKeys={['path']}
- translationKey="onboarding.tutorial.with.jenkins.dotnet.scanner.prereqs.step1"
- />
- </ListItem>
- <ListItem>
- <SentenceWithHighlights
- highlightKeys={['default_scanner', 'add_scanner_for_msbuild']}
- translationKey="onboarding.tutorial.with.jenkins.dotnet.scanner.prereqs.step2"
- />
- </ListItem>
- <ListItem>
- <SentenceWithHighlights
- highlightKeys={['name']}
- translationKey="onboarding.tutorial.with.jenkins.dotnet.scanner.prereqs.step3"
- />
- <InlineSnippet className="sw-ml-1" snippet="SonarScanner for .NET" />
- <ClipboardIconButton className="sw-ml-2 sw-align-sub" copyValue="SonarScanner for .NET" />
- </ListItem>
- <ListItem>
- <SentenceWithHighlights
- highlightKeys={['install_from']}
- translationKey="onboarding.tutorial.with.jenkins.dotnet.scanner.prereqs.step5"
- />
- </ListItem>
- </OrderedList>
- </NumberedListItem>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Gradle.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Gradle.tsx
deleted file mode 100644
index a711e1fe81d..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Gradle.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { CodeSnippet, NumberedListItem } from '~design-system';
-import { translate } from '../../../../helpers/l10n';
-import GradleBuildSelection from '../../components/GradleBuildSelection';
-import { InlineSnippet } from '../../components/InlineSnippet';
-import { GradleBuildDSL } from '../../types';
-import { buildGradleSnippet } from '../../utils';
-import { LanguageProps } from '../JenkinsStep';
-import CreateJenkinsfileBulletPoint from './CreateJenkinsfileBulletPoint';
-
-const JENKINSFILE_SNIPPET = `node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- withSonarQubeEnv() {
- sh "./gradlew sonar"
- }
- }
-}`;
-
-export default function Gradle(props: LanguageProps) {
- const { component } = props;
-
- return (
- <>
- <NumberedListItem>
- <span>
- <FormattedMessage
- defaultMessage={translate(
- 'onboarding.tutorial.with.jenkins.jenkinsfile.gradle.step2',
- 'sentence',
- )}
- id="onboarding.tutorial.with.jenkins.jenkinsfile.gradle.step2.sentence"
- values={{
- groovy: <InlineSnippet snippet={GradleBuildDSL.Groovy} />,
- kotlin: <InlineSnippet snippet={GradleBuildDSL.Kotlin} />,
- }}
- />
- </span>
- <GradleBuildSelection className="sw-my-4">
- {(build) => (
- <CodeSnippet
- className="sw-p-6"
- language={build === GradleBuildDSL.Groovy ? 'groovy' : 'kotlin'}
- snippet={buildGradleSnippet(component.key, component.name, build)}
- />
- )}
- </GradleBuildSelection>
- </NumberedListItem>
- <CreateJenkinsfileBulletPoint snippet={JENKINSFILE_SNIPPET} />
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Maven.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Maven.tsx
deleted file mode 100644
index 987c53e7f88..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Maven.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LanguageProps } from '../JenkinsStep';
-import CreateJenkinsfileBulletPoint from './CreateJenkinsfileBulletPoint';
-
-function jenkinsfileSnippet(projectKey: string, projectName: string) {
- return `node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def mvn = tool 'Default Maven';
- withSonarQubeEnv() {
- sh "\${mvn}/bin/mvn clean verify sonar:sonar -Dsonar.projectKey=${projectKey} -Dsonar.projectName='${projectName}'"
- }
- }
-}`;
-}
-
-export default function Maven({ component }: LanguageProps) {
- return (
- <CreateJenkinsfileBulletPoint
- alertTranslationKeyPart="onboarding.tutorial.with.jenkins.jenkinsfile.maven.step3"
- snippet={jenkinsfileSnippet(component.key, component.name)}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Other.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Other.tsx
deleted file mode 100644
index 5709af9026d..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/buildtool-steps/Other.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import DefaultProjectKey from '../../components/DefaultProjectKey';
-import { LanguageProps } from '../JenkinsStep';
-import CreateJenkinsfileBulletPoint from './CreateJenkinsfileBulletPoint';
-
-const JENKINSFILE_SNIPPET = `node {
- stage('SCM') {
- checkout scm
- }
- stage('SonarQube Analysis') {
- def scannerHome = tool 'SonarScanner';
- withSonarQubeEnv() {
- sh "\${scannerHome}/bin/sonar-scanner"
- }
- }
-}`;
-
-export default function Other(props: LanguageProps) {
- const { component } = props;
- return (
- <>
- <DefaultProjectKey component={component} />
- <CreateJenkinsfileBulletPoint
- alertTranslationKeyPart="onboarding.tutorial.with.jenkins.jenkinsfile.other.step3"
- snippet={JENKINSFILE_SNIPPET}
- />
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/BuildToolForm.tsx b/server/sonar-web/src/main/js/components/tutorials/other/BuildToolForm.tsx
deleted file mode 100644
index 2750f5258f7..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/BuildToolForm.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { translate } from '../../../helpers/l10n';
-import { withCLanguageFeature } from '../../hoc/withCLanguageFeature';
-import BuildConfigSelection from '../components/BuildConfigSelection';
-import GithubCFamilyExampleRepositories from '../components/GithubCFamilyExampleRepositories';
-import RenderOptions from '../components/RenderOptions';
-import { Arch, OSs, TutorialConfig, TutorialModes } from '../types';
-import {
- shouldShowArchSelector,
- shouldShowGithubCFamilyExampleRepositories,
- shouldShowOsSelector,
-} from '../utils';
-
-interface Props {
- arch?: Arch;
- config: TutorialConfig;
- hasCLanguageFeature: boolean;
- isLocal: boolean;
- os?: OSs;
- setArch: (arch: Arch) => void;
- setConfig: (config: TutorialConfig) => void;
- setOs: (os: OSs) => void;
-}
-
-export function BuildToolForm(props: Readonly<Props>) {
- const { config, setConfig, os, setOs, arch, setArch, isLocal, hasCLanguageFeature } = props;
-
- function handleConfigChange(newConfig: TutorialConfig) {
- setConfig({
- ...config,
- ...newConfig,
- });
- }
-
- return (
- <>
- {config && (
- <BuildConfigSelection
- ci={TutorialModes.OtherCI}
- config={config}
- supportCFamily={hasCLanguageFeature}
- onSetConfig={handleConfigChange}
- />
- )}
- {shouldShowOsSelector(config) && (
- <RenderOptions
- label={translate('onboarding.build.other.os')}
- checked={os}
- onCheck={(value: OSs) => setOs(value)}
- optionLabelKey="onboarding.build.other.os"
- options={[OSs.Linux, OSs.Windows, OSs.MacOS]}
- titleLabelKey="onboarding.build.other.os"
- />
- )}
- {shouldShowArchSelector(os, config, !isLocal) && (
- <RenderOptions
- label={translate('onboarding.build.other.architecture')}
- checked={arch}
- onCheck={(value: Arch) => setArch(value)}
- optionLabelKey="onboarding.build.other.architecture"
- options={[Arch.X86_64, Arch.Arm64]}
- titleLabelKey="onboarding.build.other.architecture"
- />
- )}
- {shouldShowGithubCFamilyExampleRepositories(config) && (
- <GithubCFamilyExampleRepositories
- ci={TutorialModes.OtherCI}
- className="sw-my-4 sw-w-abs-600"
- />
- )}
- </>
- );
-}
-
-export default withCLanguageFeature(BuildToolForm);
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/DoneNextSteps.tsx b/server/sonar-web/src/main/js/components/tutorials/other/DoneNextSteps.tsx
deleted file mode 100644
index 3112e280764..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/DoneNextSteps.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { animated, config, useSpring } from '@react-spring/web';
-import { LinkStandalone as Link } from '@sonarsource/echoes-react';
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { BasicSeparator, FlagVisual } from '~design-system';
-import withAppStateContext from '../../../app/components/app-state/withAppStateContext';
-import { DocLink } from '../../../helpers/doc-links';
-import { useDocUrl } from '../../../helpers/docs';
-import { translate } from '../../../helpers/l10n';
-import useIntersectionObserver from '../../../hooks/useIntersectionObserver';
-import { AppState } from '../../../types/appstate';
-import { EditionKey } from '../../../types/editions';
-
-export interface Props {
- appState: AppState;
-}
-
-function DoneNextSteps({ appState }: Readonly<Props>) {
- const outroRef = React.useRef<HTMLDivElement>(null);
- const hasLicensedEdition = appState.edition && appState.edition !== EditionKey.community;
- const intersectionEntry = useIntersectionObserver(outroRef, { freezeOnceVisible: true });
-
- const outroAnimation = useSpring({
- from: { top: '200px' },
- to: intersectionEntry?.isIntersecting ? { top: '0px' } : { top: '200px' },
- config: config.wobbly,
- });
-
- const docUrl = useDocUrl();
-
- return (
- <animated.div
- className="sw-flex sw-flex-col sw-items-center sw-relative"
- ref={outroRef}
- style={outroAnimation}
- >
- <BasicSeparator className="sw-my-8" />
- <StyledDiv>
- <div className="sw-flex sw-justify-center sw-mb-12">
- <FlagVisual />
- </div>
-
- <p>
- <strong className="sw-font-semibold sw-mr-1">
- {translate('onboarding.analysis.auto_refresh_after_analysis.done')}
- </strong>
- {translate('onboarding.analysis.auto_refresh_after_analysis.auto_refresh')}
- </p>
- <div className="sw-mt-4">
- {hasLicensedEdition ? (
- <>
- <span>
- {translate('onboarding.analysis.auto_refresh_after_analysis.check_these_links')}
- </span>
- <ul className="sw-flex sw-flex-col sw-gap-2 sw-mt-2">
- <li>
- <Link to={docUrl(DocLink.BranchAnalysis)}>
- {translate(
- 'onboarding.analysis.auto_refresh_after_analysis.check_these_links.branches',
- )}
- </Link>
- </li>
-
- <li>
- <Link to={docUrl(DocLink.PullRequestAnalysis)}>
- {translate(
- 'onboarding.analysis.auto_refresh_after_analysis.check_these_links.pr_analysis',
- )}
- </Link>
- </li>
- </ul>
- </>
- ) : (
- <FormattedMessage
- defaultMessage={translate(
- 'onboarding.analysis.auto_refresh_after_analysis.community.check_these_links',
- )}
- id="onboarding.analysis.auto_refresh_after_analysis.community.check_these_links"
- values={{
- edition: (
- <Link to="https://www.sonarsource.com/plans-and-pricing/developer/">
- {translate(
- 'onboarding.analysis.auto_refresh_after_analysis.community.check_these_links.edition',
- )}
- </Link>
- ),
- branches: (
- <Link to={docUrl(DocLink.BranchAnalysis)}>
- {translate(
- 'onboarding.analysis.auto_refresh_after_analysis.check_these_links.branches',
- )}
- </Link>
- ),
- pull_requests: (
- <Link to={docUrl(DocLink.PullRequestAnalysis)}>
- {translate(
- 'onboarding.analysis.auto_refresh_after_analysis.check_these_links.pr_analysis',
- )}
- </Link>
- ),
- }}
- />
- )}
- </div>
- </StyledDiv>
- </animated.div>
- );
-}
-
-export default withAppStateContext(DoneNextSteps);
-
-const StyledDiv = styled.div`
- width: 840px;
- margin: auto;
-`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/OtherTutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/other/OtherTutorial.tsx
deleted file mode 100644
index a67daca8fc4..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/OtherTutorial.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { LightLabel, PageContentFontWrapper, Title } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { Component } from '../../../types/types';
-import { LoggedInUser } from '../../../types/users';
-import ProjectAnalysisStep from './ProjectAnalysisStep';
-import TokenStep from './TokenStep';
-
-export enum Steps {
- ANALYSIS,
- TOKEN,
-}
-
-interface Props {
- baseUrl: string;
- component: Component;
- currentUser: LoggedInUser;
- isLocal?: boolean;
-}
-
-interface State {
- step: Steps;
- token?: string;
-}
-
-export default class OtherTutorial extends React.PureComponent<Props, State> {
- state: State = { step: Steps.TOKEN };
-
- handleTokenDone = (token: string) => {
- this.setState({ step: Steps.ANALYSIS, token });
- };
-
- handleTokenOpen = () => {
- this.setState({ step: Steps.TOKEN });
- };
-
- render() {
- const { component, baseUrl, currentUser, isLocal = false } = this.props;
- const { step, token } = this.state;
-
- return (
- <PageContentFontWrapper className="sw-typo-default">
- <div className="sw-mb-4">
- <Title>{translate('onboarding.project_analysis.header')} </Title>
- <LightLabel>{translate('onboarding.project_analysis.description')}</LightLabel>
- </div>
-
- <TokenStep
- currentUser={currentUser}
- projectKey={component.key}
- finished={Boolean(this.state.token)}
- initialTokenName={`Analyze "${component.name}"`}
- onContinue={this.handleTokenDone}
- onOpen={this.handleTokenOpen}
- open={step === Steps.TOKEN}
- stepNumber={1}
- />
-
- <ProjectAnalysisStep
- component={component}
- baseUrl={baseUrl}
- isLocal={isLocal}
- open={step === Steps.ANALYSIS}
- token={token}
- stepNumber={2}
- />
- </PageContentFontWrapper>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/ProjectAnalysisStep.tsx b/server/sonar-web/src/main/js/components/tutorials/other/ProjectAnalysisStep.tsx
deleted file mode 100644
index 2359bb76f52..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/ProjectAnalysisStep.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { noop } from 'lodash';
-import * as React from 'react';
-import { translate } from '../../../helpers/l10n';
-import { Component } from '../../../types/types';
-import Step from '../components/Step';
-import { Arch, OSs, TutorialConfig } from '../types';
-import BuildToolForm from './BuildToolForm';
-import AnalysisCommand from './commands/AnalysisCommand';
-
-interface Props {
- baseUrl: string;
- component: Component;
- isLocal: boolean;
- open: boolean;
- stepNumber: number;
- token?: string;
-}
-
-export default function ProjectAnalysisStep(props: Readonly<Props>) {
- const { component, open, stepNumber, baseUrl, isLocal, token } = props;
-
- const [config, setConfig] = React.useState<TutorialConfig>({});
- const [os, setOs] = React.useState<OSs>(OSs.Linux);
- const [arch, setArch] = React.useState<Arch>(Arch.X86_64);
-
- function renderForm() {
- return (
- <div className="sw-pb-4">
- <BuildToolForm
- config={config}
- isLocal={isLocal}
- setConfig={setConfig}
- os={os}
- setOs={setOs}
- arch={arch}
- setArch={setArch}
- />
-
- {config && (
- <div className="sw-mt-4">
- <AnalysisCommand
- config={config}
- os={os}
- arch={arch}
- component={component}
- baseUrl={baseUrl}
- isLocal={isLocal}
- token={token}
- />
- </div>
- )}
- </div>
- );
- }
-
- return (
- <Step
- finished={false}
- onOpen={noop}
- open={open}
- renderForm={renderForm}
- stepNumber={stepNumber}
- stepTitle={translate('onboarding.analysis.header')}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/TokenStep.tsx b/server/sonar-web/src/main/js/components/tutorials/other/TokenStep.tsx
deleted file mode 100644
index 8d33c3a7b4b..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/TokenStep.tsx
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { keyframes } from '@emotion/react';
-import styled from '@emotion/styled';
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { SingleValue } from 'react-select';
-import {
- ButtonPrimary,
- ButtonSecondary,
- DestructiveIcon,
- FlagMessage,
- FlagSuccessIcon,
- HelperHintIcon,
- Highlight,
- InputField,
- InputSelect,
- LabelValueSelectOption,
- Link,
- Note,
- Spinner,
- ToggleButton,
- ToggleButtonsOption,
- TrashIcon,
-} from '~design-system';
-import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
-import { generateToken, getTokens, revokeToken } from '../../../api/user-tokens';
-import { DocLink } from '../../../helpers/doc-links';
-import { translate } from '../../../helpers/l10n';
-import {
- EXPIRATION_OPTIONS,
- computeTokenExpirationDate,
- getAvailableExpirationOptions,
-} from '../../../helpers/tokens';
-import { TokenExpiration, TokenType, UserToken } from '../../../types/token';
-import { LoggedInUser } from '../../../types/users';
-import ProjectTokenScopeInfo from '../components/ProjectTokenScopeInfo';
-import Step from '../components/Step';
-import { getUniqueTokenName } from '../utils';
-
-interface Props {
- currentUser: Pick<LoggedInUser, 'login'>;
- finished: boolean;
- initialTokenName?: string;
- onContinue: (token: string) => void;
- onOpen: VoidFunction;
- open: boolean;
- projectKey: string;
- stepNumber: number;
-}
-
-interface State {
- existingToken: string;
- loading: boolean;
- selection: string;
- token?: string;
- tokenExpiration: TokenExpiration;
- tokenExpirationOptions: { label: string; value: TokenExpiration }[];
- tokenName?: string;
- tokens?: UserToken[];
-}
-
-const TOKEN_FORMAT_REGEX = /^[_a-z0-9]+$/;
-
-enum TokenUse {
- GENERATE = 'generate',
- EXISTING = 'use-existing',
-}
-
-export default class TokenStep extends React.PureComponent<Props, State> {
- mounted = false;
-
- constructor(props: Props) {
- super(props);
- this.state = {
- existingToken: '',
- loading: false,
- selection: TokenUse.GENERATE,
- tokenName: props.initialTokenName,
- tokenExpiration: TokenExpiration.OneMonth,
- tokenExpirationOptions: EXPIRATION_OPTIONS,
- };
- }
-
- async componentDidMount() {
- this.mounted = true;
- const { currentUser, initialTokenName } = this.props;
- const { tokenName } = this.state;
-
- const tokenExpirationOptions = await getAvailableExpirationOptions();
- if (tokenExpirationOptions && this.mounted) {
- this.setState({ tokenExpirationOptions });
- }
-
- const tokens = await getTokens(currentUser.login).catch(() => {
- /* noop */
- });
-
- if (tokens && this.mounted) {
- this.setState({ tokens });
- if (initialTokenName !== undefined && initialTokenName === tokenName) {
- this.setState({ tokenName: getUniqueTokenName(tokens, initialTokenName) });
- }
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- getToken = () =>
- this.state.selection === TokenUse.GENERATE ? this.state.token : this.state.existingToken;
-
- canContinue = () => {
- const { existingToken, selection, token } = this.state;
- const validExistingToken = TOKEN_FORMAT_REGEX.exec(existingToken) != null;
- return (
- (selection === TokenUse.GENERATE && token != null) ||
- (selection === TokenUse.EXISTING && existingToken && validExistingToken)
- );
- };
-
- handleTokenNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- this.setState({ tokenName: event.target.value });
- };
-
- handleTokenExpirationChange = (option: SingleValue<LabelValueSelectOption<TokenExpiration>>) => {
- if (option) {
- this.setState({ tokenExpiration: option.value });
- }
- };
-
- handleTokenGenerate = async (event: React.FormEvent<HTMLFormElement>) => {
- event.preventDefault();
- const { tokenName, tokenExpiration } = this.state;
- const { projectKey } = this.props;
-
- if (tokenName) {
- this.setState({ loading: true });
- try {
- const { token } = await generateToken({
- name: tokenName,
- type: TokenType.Project,
- projectKey,
- ...(tokenExpiration !== TokenExpiration.NoExpiration && {
- expirationDate: computeTokenExpirationDate(tokenExpiration),
- }),
- });
- if (this.mounted) {
- this.setState({ loading: false, token });
- }
- } catch (e) {
- this.stopLoading();
- }
- }
- };
-
- handleTokenRevoke = () => {
- const { tokenName } = this.state;
- if (tokenName) {
- this.setState({ loading: true });
- revokeToken({ name: tokenName }).then(() => {
- if (this.mounted) {
- this.setState({ loading: false, token: undefined, tokenName: undefined });
- }
- }, this.stopLoading);
- }
- };
-
- handleContinueClick = () => {
- const token = this.getToken();
- if (token) {
- this.props.onContinue(token);
- }
- };
-
- handleModeChange = (mode: string) => {
- this.setState({ selection: mode });
- };
-
- handleExisingTokenChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- this.setState({ existingToken: event.currentTarget.value });
- };
-
- stopLoading = () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- };
-
- renderGenerateOption = () => {
- const { loading, tokenName, tokenExpiration, tokenExpirationOptions } = this.state;
- return (
- <DivAnimated className="sw-mt-4">
- <form className="sw-flex sw-items-center" onSubmit={this.handleTokenGenerate}>
- <div className="sw-flex sw-flex-col">
- <HighlightLabel className="sw-mb-2" htmlFor="generate-token-input">
- {translate('onboarding.token.name.label')}
- <DocHelpTooltip
- className="sw-ml-2"
- content={translate('onboarding.token.name.help')}
- links={[
- {
- href: DocLink.AccountTokens,
- label: translate('learn_more'),
- },
- ]}
- >
- <HelperHintIcon />
- </DocHelpTooltip>
- </HighlightLabel>
- <InputField
- id="generate-token-input"
- autoFocus
- onChange={this.handleTokenNameChange}
- required
- size="large"
- type="text"
- value={tokenName ?? ''}
- />
- </div>
- <div className="sw-flex sw-flex-col sw-ml-4">
- <HighlightLabel className="sw-mb-2" htmlFor="token-select-expiration">
- {translate('users.tokens.expires_in')}
- </HighlightLabel>
- <div className="sw-flex sw-items-center">
- <InputSelect
- id="token-select-expiration"
- className="sw-w-abs-150 sw-mr-4"
- isSearchable={false}
- onChange={this.handleTokenExpirationChange}
- options={tokenExpirationOptions}
- size="full"
- value={tokenExpirationOptions.find((option) => option.value === tokenExpiration)}
- />
-
- <ButtonSecondary
- type="submit"
- disabled={!tokenName || loading}
- icon={<Spinner className="sw-mr-1" loading={loading} />}
- >
- {translate('onboarding.token.generate')}
- </ButtonSecondary>
- </div>
- </div>
- </form>
- <ProjectTokenScopeInfo className="sw-mt-6 sw-w-1/2" />
- </DivAnimated>
- );
- };
-
- renderUseExistingOption = () => {
- const { existingToken } = this.state;
- const validInput = !existingToken || TOKEN_FORMAT_REGEX.exec(existingToken) != null;
-
- return (
- <DivAnimated className="sw-mt-4">
- {this.state.selection === TokenUse.EXISTING && (
- <div className="sw-flex sw-flex-col sw-mt-4">
- <HighlightLabel className="sw-mb-2" htmlFor="existing-token-input">
- {translate('onboarding.token.use_existing_token.label')}
- <DocHelpTooltip
- className="sw-ml-2"
- content={translate('onboarding.token.use_existing_token.help')}
- links={[
- {
- href: DocLink.AccountTokens,
- label: translate('learn_more'),
- },
- ]}
- >
- <HelperHintIcon />
- </DocHelpTooltip>
- </HighlightLabel>
- <InputField
- id="existing-token-input"
- autoFocus
- onChange={this.handleExisingTokenChange}
- required
- isInvalid={!validInput}
- size="large"
- type="text"
- value={this.state.existingToken}
- />
- {!validInput && (
- <FlagMessage className="sw-mt-2 sw-w-fit" variant="error">
- {translate('onboarding.token.invalid_format')}
- </FlagMessage>
- )}
- </div>
- )}
- </DivAnimated>
- );
- };
-
- renderForm = () => {
- const { loading, selection, token, tokenName, tokens } = this.state;
- const canUseExisting = tokens !== undefined && tokens.length > 0;
-
- const modeOptions: Array<ToggleButtonsOption<string>> = [
- {
- label: translate('onboarding.token.generate', TokenType.Project),
- value: TokenUse.GENERATE,
- },
- {
- label: translate('onboarding.token.use_existing_token'),
- value: TokenUse.EXISTING,
- disabled: !canUseExisting,
- },
- ];
-
- return (
- <div className="sw-p-4">
- {token != null ? (
- <form className="sw-flex sw-items-center" onSubmit={this.handleTokenRevoke}>
- <span>
- {tokenName}
- {': '}
- <strong className="sw-font-semibold">{token}</strong>
- </span>
-
- <Spinner className="sw-ml-3 sw-my-2" loading={loading}>
- <DestructiveIcon
- className="sw-ml-1"
- Icon={TrashIcon}
- aria-label={translate('onboarding.token.delete')}
- onClick={this.handleTokenRevoke}
- />
- </Spinner>
- </form>
- ) : (
- <div>
- <ToggleButton
- onChange={this.handleModeChange}
- options={modeOptions}
- value={selection}
- />
- <div className="sw-ml-4">
- {selection === TokenUse.GENERATE && this.renderGenerateOption()}
- {selection === TokenUse.EXISTING && this.renderUseExistingOption()}
- </div>
- </div>
- )}
-
- <Note as="div" className="sw-mt-6 sw-w-1/2">
- <FormattedMessage
- defaultMessage={translate('onboarding.token.text')}
- id="onboarding.token.text"
- values={{
- link: (
- <Link target="_blank" to="/account/security">
- {translate('onboarding.token.text.user_account')}
- </Link>
- ),
- }}
- />
- </Note>
-
- {this.canContinue() && (
- <div className="sw-mt-4">
- <ButtonPrimary onClick={this.handleContinueClick}>
- {translate('continue')}
- </ButtonPrimary>
- </div>
- )}
- </div>
- );
- };
-
- renderResult = () => {
- const { selection, tokenName } = this.state;
- const token = this.getToken();
-
- if (!token) {
- return null;
- }
-
- return (
- <div className="sw-flex sw-items-center">
- <FlagSuccessIcon className="sw-mr-2" />
- <span>
- {selection === TokenUse.GENERATE && tokenName && `${tokenName}: `}
- <strong className="sw-ml-1">{token}</strong>
- </span>
- </div>
- );
- };
-
- render() {
- return (
- <Step
- finished={this.props.finished}
- onOpen={this.props.onOpen}
- open={this.props.open}
- renderForm={this.renderForm}
- renderResult={this.renderResult}
- stepNumber={this.props.stepNumber}
- stepTitle={translate('onboarding.token.header')}
- />
- );
- }
-}
-
-// We need to pass 'htmlFor' to the label, but
-// using 'as' doesn't dynamically change the allowed props
-// https://github.com/emotion-js/emotion/issues/2266
-const HighlightLabel = Highlight.withComponent('label');
-
-const appearAnimation = keyframes`
- from {
- opacity: 0;
- }
-
- to {
- opacity: 1;
- }
-`;
-
-const DivAnimated = styled.div`
- animation: 0.3s ease-out ${appearAnimation};
-`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/__tests__/DoneNextSteps-it.tsx b/server/sonar-web/src/main/js/components/tutorials/other/__tests__/DoneNextSteps-it.tsx
deleted file mode 100644
index 9993b87a169..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/__tests__/DoneNextSteps-it.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { getEdition } from '../../../../helpers/editions';
-import { mockAppState } from '../../../../helpers/testMocks';
-import { renderApp } from '../../../../helpers/testReactTestingUtils';
-import { EditionKey } from '../../../../types/editions';
-import DoneNextSteps from '../DoneNextSteps';
-
-const ui = {
- analysisDone: byText('onboarding.analysis.auto_refresh_after_analysis.done'),
- autoRefresh: byText('onboarding.analysis.auto_refresh_after_analysis.auto_refresh'),
- licensedNextStep: byText('onboarding.analysis.auto_refresh_after_analysis.check_these_links'),
- communityNextStep: byText(
- 'onboarding.analysis.auto_refresh_after_analysis.community.check_these_links',
- ),
- nextStepLinks: byRole('link'),
-};
-
-describe(`${getEdition(EditionKey.community).name}`, () => {
- it('should inform the user about available next steps', async () => {
- renderDoneNextSteps();
-
- expect(await ui.analysisDone.find()).toBeInTheDocument();
- expect(await ui.autoRefresh.find()).toBeInTheDocument();
- expect(await ui.communityNextStep.find()).toBeInTheDocument();
- expect(await ui.nextStepLinks.findAll()).toHaveLength(3);
- });
-});
-
-describe('Licensed Edition', () => {
- it('should inform the user about available next steps', async () => {
- renderDoneNextSteps(mockAppState({ edition: EditionKey.enterprise }));
-
- expect(await ui.analysisDone.find()).toBeInTheDocument();
- expect(await ui.autoRefresh.find()).toBeInTheDocument();
- expect(await ui.licensedNextStep.find()).toBeInTheDocument();
- expect(await ui.nextStepLinks.findAll()).toHaveLength(2);
- });
-});
-
-function renderDoneNextSteps(appState = mockAppState()) {
- return renderApp('/', <DoneNextSteps />, { appState });
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/__tests__/OtherTutorial-it.tsx b/server/sonar-web/src/main/js/components/tutorials/other/__tests__/OtherTutorial-it.tsx
deleted file mode 100644
index 54ed99f2475..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/__tests__/OtherTutorial-it.tsx
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import UserTokensMock from '../../../../api/mocks/UserTokensMock';
-import { mockComponent } from '../../../../helpers/mocks/component';
-import { mockLanguage, mockLoggedInUser } from '../../../../helpers/testMocks';
-import { RenderContext, renderApp } from '../../../../helpers/testReactTestingUtils';
-import {
- getCopyToClipboardValue,
- getTutorialActionButtons,
- getTutorialBuildButtons,
-} from '../../test-utils';
-import OtherTutorial from '../OtherTutorial';
-
-jest.mock('../../../../api/settings', () => ({
- getAllValues: jest.fn().mockResolvedValue([]),
-}));
-
-jest.mock('clipboard', () => ({
- copy: jest.fn(),
-}));
-
-const tokenMock = new UserTokensMock();
-
-afterEach(() => {
- tokenMock.reset();
-});
-
-const ui = {
- provideTokenTitle: byRole('heading', { name: 'onboarding.token.header' }),
- runAnalysisTitle: byRole('heading', { name: 'onboarding.analysis.header' }),
- generateTokenRadio: byRole('radio', { name: 'onboarding.token.generate.PROJECT_ANALYSIS_TOKEN' }),
- existingTokenRadio: byRole('radio', { name: 'onboarding.token.use_existing_token' }),
- tokenNameInput: byRole('textbox', { name: /onboarding.token.name.label/ }),
- expiresInSelect: byRole('combobox', { name: '' }),
- tokenValueInput: byRole('textbox', { name: /onboarding.token.use_existing_token.label/ }),
- invalidTokenValueMessage: byText('onboarding.token.invalid_format'),
- ...getTutorialActionButtons(),
- ...getTutorialBuildButtons(),
-};
-
-it('should generate/delete a new token or use existing one', async () => {
- const user = userEvent.setup();
- renderOtherTutorial();
-
- // Verify that pages is rendered and includes 2 steps
- expect(await ui.provideTokenTitle.find()).toBeInTheDocument();
- expect(ui.runAnalysisTitle.get()).toBeInTheDocument();
-
- // Generating token
- await user.type(ui.tokenNameInput.get(), 'Testing token');
- await user.click(ui.expiresInSelect.get());
- await user.click(byRole('option', { name: 'users.tokens.expiration.365' }).get());
-
- await user.click(ui.generateTokenButton.get());
-
- expect(ui.continueButton.get()).toBeEnabled();
-
- // Deleting generated token & switchning to existing one
- await user.click(ui.deleteTokenButton.get());
-
- await user.click(ui.existingTokenRadio.get());
- await user.type(ui.tokenValueInput.get(), 'INVALID TOKEN VALUE');
- expect(ui.invalidTokenValueMessage.get()).toBeInTheDocument();
-
- await user.clear(ui.tokenValueInput.get());
- await user.type(ui.tokenValueInput.get(), 'validtokenvalue');
- expect(ui.continueButton.get()).toBeEnabled();
-
- // navigate to 'Run analysis' step
- await user.click(ui.continueButton.get());
- expect(ui.describeBuildTitle.get()).toBeInTheDocument();
-
- // navigate to previous step
- await user.click(ui.provideTokenTitle.get());
- expect(ui.continueButton.get()).toBeEnabled();
-});
-
-it('can choose build tools and copy provided settings', async () => {
- const user = userEvent.setup();
- renderOtherTutorial();
-
- await user.click(ui.generateTokenButton.get());
- await user.click(ui.continueButton.get());
-
- // Maven
- await user.click(ui.mavenBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot('maven: execute scanner');
-
- // Gradle
- await user.click(ui.gradleBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'gradle: sonarqube plugin',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'gradle: execute scanner',
- );
-
- // Dotnet - Core
- await user.click(ui.dotnetBuildButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'dotnet core: install scanner globally',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'dotnet core: execute command 1',
- );
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- 'dotnet core: execute command 2',
- );
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- 'dotnet core: execute command 3',
- );
-
- // Dotnet - Framework
- await user.click(ui.dotnetFrameworkButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'dotnet framework: execute command 1',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'dotnet framework: execute command 2',
- );
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- 'dotnet framework: execute command 3',
- );
-
- // C++ - Automatic
- await user.click(ui.cppBuildButton.get());
- await user.click(ui.linuxButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'c++ (automatic) and other linux: download scanner',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'c++ (automatic) and other linux: execute scanner',
- );
- await user.click(ui.arm64Button.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'c++ (automatic) and other linux arm64: download scanner',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'c++ (automatic) and other linux arm64: execute scanner',
- );
- await user.click(ui.windowsButton.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'c++ (automatic) and other windows: execute scanner',
- );
- await user.click(ui.macosButton.get());
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'c++ (automatic) and other macos: execute scanner',
- );
-
- // C++ - Linux (x86_64)
- await user.click(ui.autoConfigManual.get());
- await user.click(ui.linuxButton.get());
- await user.click(ui.x86_64Button.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) linux: download build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) linux: download scanner',
- );
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) linux: execute build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) linux: execute scanner',
- );
-
- // C++ - Linux (ARM64)
- await user.click(ui.arm64Button.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) linux arm64: download build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) linux arm64: download scanner',
- );
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) linux arm64: execute build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) linux arm64: execute scanner',
- );
-
- // C++ - Windows
- await user.click(ui.windowsButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) windows: download build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) windows: download scanner',
- );
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) windows: execute build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) windows: execute scanner',
- );
-
- // C++ - MacOS
- await user.click(ui.macosButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) macos: download build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) macos: download scanner',
- );
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) macos: execute build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- 'c++ (manual) macos: execute scanner',
- );
-
- // Objective-C - Linux (x86_64)
- await user.click(ui.objCBuildButton.get());
- await user.click(ui.linuxButton.get());
- await user.click(ui.x86_64Button.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'objective-c linux: download build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'objective-c linux: download scanner',
- );
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- 'objective-c linux: execute build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- 'objective-c linux: execute scanner',
- );
-
- // Objective-C - Linux (ARM64)
- await user.click(ui.arm64Button.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'objective-c linux arm64: download build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'objective-c linux arm64: download scanner',
- );
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- 'objective-c linux arm64: execute build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- 'objective-c linux arm64: execute scanner',
- );
-
- // Objective-C - Windows
- await user.click(ui.windowsButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'objective-c windows: download build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'objective-c windows: download scanner',
- );
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- 'objective-c windows: execute build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- 'objective-c windows: execute scanner',
- );
-
- // Objective-C - MacOS
- await user.click(ui.macosButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'objective-c macos: download build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'objective-c macos: download scanner',
- );
- expect(getCopyToClipboardValue({ i: 2, name: 'Copy' })).toMatchSnapshot(
- 'objective-c macos: execute build wrapper',
- );
- expect(getCopyToClipboardValue({ i: 3, name: 'Copy' })).toMatchSnapshot(
- 'objective-c macos: execute scanner',
- );
-
- // Dart - Linux
- await user.click(ui.dartBuildButton.get());
- await user.click(ui.linuxButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'Dart linux: download scanner',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'Dart linux: execute scanner',
- );
-
- // Dart - Windows
- await user.click(ui.windowsButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'Dart windows: download scanner',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'Dart windows: execute scanner',
- );
-
- // Dart - MacOS
- await user.click(ui.macosButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'Dart macos: download scanner',
- );
- expect(getCopyToClipboardValue({ i: 1, name: 'Copy' })).toMatchSnapshot(
- 'Dart macos: execute scanner',
- );
-
- // Other - Linux
- await user.click(ui.otherBuildButton.get());
- await user.click(ui.linuxButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'c++ (automatic) and other linux: execute scanner',
- );
-
- // Other - Windows
- await user.click(ui.windowsButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'c++ (automatic) and other windows: execute scanner',
- );
-
- // Other - MacOS
- await user.click(ui.macosButton.get());
- expect(getCopyToClipboardValue({ i: 0, name: 'Copy' })).toMatchSnapshot(
- 'c++ (automatic) and other macos: execute scanner',
- );
-});
-
-function renderOtherTutorial({
- languages = { c: mockLanguage({ key: 'c' }) },
-}: RenderContext = {}) {
- return renderApp(
- '/',
- <OtherTutorial
- baseUrl="http://localhost:9000"
- component={mockComponent()}
- currentUser={mockLoggedInUser()}
- />,
- { languages },
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/__tests__/__snapshots__/OtherTutorial-it.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/other/__tests__/__snapshots__/OtherTutorial-it.tsx.snap
deleted file mode 100644
index 9e7bc3d9703..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/__tests__/__snapshots__/OtherTutorial-it.tsx.snap
+++ /dev/null
@@ -1,372 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`can choose build tools and copy provided settings: Dart linux: download scanner 1`] = `
-"export SONAR_SCANNER_VERSION=6.2.0.4584
-export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux-aarch64
-curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux-aarch64.zip
-unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
-export PATH=$SONAR_SCANNER_HOME/bin:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: Dart linux: execute scanner 1`] = `
-"sonar-scanner \\
- -Dsonar.projectKey=my-project \\
- -Dsonar.sources=. \\
- -Dsonar.host.url=http://localhost:9000"
-`;
-
-exports[`can choose build tools and copy provided settings: Dart macos: download scanner 1`] = `
-"export SONAR_SCANNER_VERSION=6.2.0.4584
-export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-macosx-aarch64
-curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-macosx-aarch64.zip
-unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
-export PATH=$SONAR_SCANNER_HOME/bin:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: Dart macos: execute scanner 1`] = `
-"sonar-scanner \\
- -Dsonar.projectKey=my-project \\
- -Dsonar.sources=. \\
- -Dsonar.host.url=http://localhost:9000"
-`;
-
-exports[`can choose build tools and copy provided settings: Dart windows: download scanner 1`] = `
-"$env:SONAR_SCANNER_VERSION = "6.2.0.4584"
-$env:SONAR_DIRECTORY = [System.IO.Path]::Combine($(get-location).Path,".sonar")
-$env:SONAR_SCANNER_HOME = "$env:SONAR_DIRECTORY/sonar-scanner-$env:SONAR_SCANNER_VERSION-windows-x64"
-rm $env:SONAR_SCANNER_HOME -Force -Recurse -ErrorAction SilentlyContinue
-New-Item -path $env:SONAR_SCANNER_HOME -type directory
-(New-Object System.Net.WebClient).DownloadFile("https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$env:SONAR_SCANNER_VERSION-windows-x64.zip", "$env:SONAR_DIRECTORY/sonar-scanner.zip")
-Add-Type -AssemblyName System.IO.Compression.FileSystem
-[System.IO.Compression.ZipFile]::ExtractToDirectory("$env:SONAR_DIRECTORY/sonar-scanner.zip", "$env:SONAR_DIRECTORY")
-rm ./.sonar/sonar-scanner.zip -Force -ErrorAction SilentlyContinue
-$env:Path += ";$env:SONAR_SCANNER_HOME/bin"
-"
-`;
-
-exports[`can choose build tools and copy provided settings: Dart windows: execute scanner 1`] = `"sonar-scanner.bat -D"sonar.projectKey=my-project" -D"sonar.sources=." -D"sonar.host.url=http://localhost:9000""`;
-
-exports[`can choose build tools and copy provided settings: c++ (automatic) and other linux arm64: download scanner 1`] = `
-"export SONAR_SCANNER_VERSION=6.2.0.4584
-export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux-aarch64
-curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux-aarch64.zip
-unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
-export PATH=$SONAR_SCANNER_HOME/bin:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (automatic) and other linux arm64: execute scanner 1`] = `
-"sonar-scanner \\
- -Dsonar.projectKey=my-project \\
- -Dsonar.sources=. \\
- -Dsonar.host.url=http://localhost:9000"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (automatic) and other linux: download scanner 1`] = `
-"export SONAR_SCANNER_VERSION=6.2.0.4584
-export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux-x64
-curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux-x64.zip
-unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
-export PATH=$SONAR_SCANNER_HOME/bin:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (automatic) and other linux: execute scanner 1`] = `
-"sonar-scanner \\
- -Dsonar.projectKey=my-project \\
- -Dsonar.sources=. \\
- -Dsonar.host.url=http://localhost:9000"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (automatic) and other linux: execute scanner 2`] = `
-"export SONAR_SCANNER_VERSION=6.2.0.4584
-export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux-aarch64
-curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux-aarch64.zip
-unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
-export PATH=$SONAR_SCANNER_HOME/bin:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (automatic) and other macos: execute scanner 1`] = `
-"sonar-scanner \\
- -Dsonar.projectKey=my-project \\
- -Dsonar.sources=. \\
- -Dsonar.host.url=http://localhost:9000"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (automatic) and other macos: execute scanner 2`] = `
-"export SONAR_SCANNER_VERSION=6.2.0.4584
-export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-macosx-aarch64
-curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-macosx-aarch64.zip
-unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
-export PATH=$SONAR_SCANNER_HOME/bin:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (automatic) and other windows: execute scanner 1`] = `"sonar-scanner.bat -D"sonar.projectKey=my-project" -D"sonar.sources=." -D"sonar.host.url=http://localhost:9000""`;
-
-exports[`can choose build tools and copy provided settings: c++ (automatic) and other windows: execute scanner 2`] = `
-"$env:SONAR_SCANNER_VERSION = "6.2.0.4584"
-$env:SONAR_DIRECTORY = [System.IO.Path]::Combine($(get-location).Path,".sonar")
-$env:SONAR_SCANNER_HOME = "$env:SONAR_DIRECTORY/sonar-scanner-$env:SONAR_SCANNER_VERSION-windows-x64"
-rm $env:SONAR_SCANNER_HOME -Force -Recurse -ErrorAction SilentlyContinue
-New-Item -path $env:SONAR_SCANNER_HOME -type directory
-(New-Object System.Net.WebClient).DownloadFile("https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$env:SONAR_SCANNER_VERSION-windows-x64.zip", "$env:SONAR_DIRECTORY/sonar-scanner.zip")
-Add-Type -AssemblyName System.IO.Compression.FileSystem
-[System.IO.Compression.ZipFile]::ExtractToDirectory("$env:SONAR_DIRECTORY/sonar-scanner.zip", "$env:SONAR_DIRECTORY")
-rm ./.sonar/sonar-scanner.zip -Force -ErrorAction SilentlyContinue
-$env:Path += ";$env:SONAR_SCANNER_HOME/bin"
-"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) linux arm64: download build wrapper 1`] = `
-"curl --create-dirs -sSLo $HOME/.sonar/build-wrapper-linux-aarch64.zip http://localhost:9000/static/cpp/build-wrapper-linux-aarch64.zip
-unzip -o $HOME/.sonar/build-wrapper-linux-aarch64.zip -d $HOME/.sonar/
-export PATH=$HOME/.sonar/build-wrapper-linux-aarch64:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) linux arm64: download scanner 1`] = `
-"export SONAR_SCANNER_VERSION=6.2.0.4584
-export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux-aarch64
-curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux-aarch64.zip
-unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
-export PATH=$SONAR_SCANNER_HOME/bin:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) linux arm64: execute build wrapper 1`] = `"build-wrapper-linux-aarch64 --out-dir bw-output onboarding.analysis.build_wrapper.execute_build_command"`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) linux arm64: execute scanner 1`] = `
-"sonar-scanner \\
- -Dsonar.projectKey=my-project \\
- -Dsonar.sources=. \\
- -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json \\
- -Dsonar.host.url=http://localhost:9000"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) linux: download build wrapper 1`] = `
-"curl --create-dirs -sSLo $HOME/.sonar/build-wrapper-linux-x86.zip http://localhost:9000/static/cpp/build-wrapper-linux-x86.zip
-unzip -o $HOME/.sonar/build-wrapper-linux-x86.zip -d $HOME/.sonar/
-export PATH=$HOME/.sonar/build-wrapper-linux-x86:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) linux: download scanner 1`] = `
-"export SONAR_SCANNER_VERSION=6.2.0.4584
-export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux-x64
-curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux-x64.zip
-unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
-export PATH=$SONAR_SCANNER_HOME/bin:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) linux: execute build wrapper 1`] = `"build-wrapper-linux-x86-64 --out-dir bw-output onboarding.analysis.build_wrapper.execute_build_command"`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) linux: execute scanner 1`] = `
-"sonar-scanner \\
- -Dsonar.projectKey=my-project \\
- -Dsonar.sources=. \\
- -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json \\
- -Dsonar.host.url=http://localhost:9000"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) macos: download build wrapper 1`] = `
-"curl --create-dirs -sSLo $HOME/.sonar/build-wrapper-macosx-x86.zip http://localhost:9000/static/cpp/build-wrapper-macosx-x86.zip
-unzip -o $HOME/.sonar/build-wrapper-macosx-x86.zip -d $HOME/.sonar/
-export PATH=$HOME/.sonar/build-wrapper-macosx-x86:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) macos: download scanner 1`] = `
-"export SONAR_SCANNER_VERSION=6.2.0.4584
-export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-macosx-aarch64
-curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-macosx-aarch64.zip
-unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
-export PATH=$SONAR_SCANNER_HOME/bin:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) macos: execute build wrapper 1`] = `"build-wrapper-macosx-x86 --out-dir bw-output onboarding.analysis.build_wrapper.execute_build_command"`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) macos: execute scanner 1`] = `
-"sonar-scanner \\
- -Dsonar.projectKey=my-project \\
- -Dsonar.sources=. \\
- -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json \\
- -Dsonar.host.url=http://localhost:9000"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) windows: download build wrapper 1`] = `
-"$env:SONAR_DIRECTORY = [System.IO.Path]::Combine($(get-location).Path,".sonar")
-rm "$env:SONAR_DIRECTORY/build-wrapper-win-x86" -Force -Recurse -ErrorAction SilentlyContinue
-New-Item -path $env:SONAR_DIRECTORY/build-wrapper-win-x86 -type directory
-(New-Object System.Net.WebClient).DownloadFile("http://localhost:9000/static/cpp/build-wrapper-win-x86.zip", "$env:SONAR_DIRECTORY/build-wrapper-win-x86.zip")
-Add-Type -AssemblyName System.IO.Compression.FileSystem
-[System.IO.Compression.ZipFile]::ExtractToDirectory("$env:SONAR_DIRECTORY/build-wrapper-win-x86.zip", "$env:SONAR_DIRECTORY")
-$env:Path += ";$env:SONAR_DIRECTORY/build-wrapper-win-x86"
-"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) windows: download scanner 1`] = `
-"$env:SONAR_SCANNER_VERSION = "6.2.0.4584"
-$env:SONAR_DIRECTORY = [System.IO.Path]::Combine($(get-location).Path,".sonar")
-$env:SONAR_SCANNER_HOME = "$env:SONAR_DIRECTORY/sonar-scanner-$env:SONAR_SCANNER_VERSION-windows-x64"
-rm $env:SONAR_SCANNER_HOME -Force -Recurse -ErrorAction SilentlyContinue
-New-Item -path $env:SONAR_SCANNER_HOME -type directory
-(New-Object System.Net.WebClient).DownloadFile("https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$env:SONAR_SCANNER_VERSION-windows-x64.zip", "$env:SONAR_DIRECTORY/sonar-scanner.zip")
-Add-Type -AssemblyName System.IO.Compression.FileSystem
-[System.IO.Compression.ZipFile]::ExtractToDirectory("$env:SONAR_DIRECTORY/sonar-scanner.zip", "$env:SONAR_DIRECTORY")
-rm ./.sonar/sonar-scanner.zip -Force -ErrorAction SilentlyContinue
-$env:Path += ";$env:SONAR_SCANNER_HOME/bin"
-"
-`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) windows: execute build wrapper 1`] = `"build-wrapper-win-x86-64.exe --out-dir bw-output onboarding.analysis.build_wrapper.execute_build_command"`;
-
-exports[`can choose build tools and copy provided settings: c++ (manual) windows: execute scanner 1`] = `"sonar-scanner.bat -D"sonar.projectKey=my-project" -D"sonar.sources=." -D"sonar.cfamily.compile-commands=bw-output/compile_commands.json" -D"sonar.host.url=http://localhost:9000""`;
-
-exports[`can choose build tools and copy provided settings: dotnet core: execute command 1 1`] = `"dotnet sonarscanner begin /k:"my-project" /d:sonar.host.url="http://localhost:9000" /d:sonar.token="generatedtoken2""`;
-
-exports[`can choose build tools and copy provided settings: dotnet core: execute command 2 1`] = `"dotnet build"`;
-
-exports[`can choose build tools and copy provided settings: dotnet core: execute command 3 1`] = `"dotnet sonarscanner end /d:sonar.token="generatedtoken2""`;
-
-exports[`can choose build tools and copy provided settings: dotnet core: install scanner globally 1`] = `"dotnet tool install --global dotnet-sonarscanner"`;
-
-exports[`can choose build tools and copy provided settings: dotnet framework: execute command 1 1`] = `"SonarScanner.MSBuild.exe begin /k:"my-project" /d:sonar.host.url="http://localhost:9000" /d:sonar.token="generatedtoken2""`;
-
-exports[`can choose build tools and copy provided settings: dotnet framework: execute command 2 1`] = `"MsBuild.exe /t:Rebuild"`;
-
-exports[`can choose build tools and copy provided settings: dotnet framework: execute command 3 1`] = `"SonarScanner.MSBuild.exe end /d:sonar.token="generatedtoken2""`;
-
-exports[`can choose build tools and copy provided settings: gradle: execute scanner 1`] = `
-"./gradlew sonar \\
- -Dsonar.projectKey=my-project \\
- -Dsonar.projectName='MyProject' \\
- -Dsonar.host.url=http://localhost:9000 \\
- -Dsonar.token=generatedtoken2"
-`;
-
-exports[`can choose build tools and copy provided settings: gradle: sonarqube plugin 1`] = `
-"plugins {
- id "org.sonarqube" version "6.0.1.5171"
-}"
-`;
-
-exports[`can choose build tools and copy provided settings: maven: execute scanner 1`] = `
-"mvn clean verify sonar:sonar \\
- -Dsonar.projectKey=my-project \\
- -Dsonar.projectName='MyProject' \\
- -Dsonar.host.url=http://localhost:9000 \\
- -Dsonar.token=generatedtoken2"
-`;
-
-exports[`can choose build tools and copy provided settings: objective-c linux arm64: download build wrapper 1`] = `
-"curl --create-dirs -sSLo $HOME/.sonar/build-wrapper-linux-aarch64.zip http://localhost:9000/static/cpp/build-wrapper-linux-aarch64.zip
-unzip -o $HOME/.sonar/build-wrapper-linux-aarch64.zip -d $HOME/.sonar/
-export PATH=$HOME/.sonar/build-wrapper-linux-aarch64:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: objective-c linux arm64: download scanner 1`] = `
-"export SONAR_SCANNER_VERSION=6.2.0.4584
-export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux-aarch64
-curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux-aarch64.zip
-unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
-export PATH=$SONAR_SCANNER_HOME/bin:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: objective-c linux arm64: execute build wrapper 1`] = `"build-wrapper-linux-aarch64 --out-dir bw-output onboarding.analysis.build_wrapper.execute_build_command"`;
-
-exports[`can choose build tools and copy provided settings: objective-c linux arm64: execute scanner 1`] = `
-"sonar-scanner \\
- -Dsonar.projectKey=my-project \\
- -Dsonar.sources=. \\
- -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json \\
- -Dsonar.host.url=http://localhost:9000"
-`;
-
-exports[`can choose build tools and copy provided settings: objective-c linux: download build wrapper 1`] = `
-"curl --create-dirs -sSLo $HOME/.sonar/build-wrapper-linux-x86.zip http://localhost:9000/static/cpp/build-wrapper-linux-x86.zip
-unzip -o $HOME/.sonar/build-wrapper-linux-x86.zip -d $HOME/.sonar/
-export PATH=$HOME/.sonar/build-wrapper-linux-x86:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: objective-c linux: download scanner 1`] = `
-"export SONAR_SCANNER_VERSION=6.2.0.4584
-export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux-x64
-curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux-x64.zip
-unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
-export PATH=$SONAR_SCANNER_HOME/bin:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: objective-c linux: execute build wrapper 1`] = `"build-wrapper-linux-x86-64 --out-dir bw-output onboarding.analysis.build_wrapper.execute_build_command"`;
-
-exports[`can choose build tools and copy provided settings: objective-c linux: execute scanner 1`] = `
-"sonar-scanner \\
- -Dsonar.projectKey=my-project \\
- -Dsonar.sources=. \\
- -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json \\
- -Dsonar.host.url=http://localhost:9000"
-`;
-
-exports[`can choose build tools and copy provided settings: objective-c macos: download build wrapper 1`] = `
-"curl --create-dirs -sSLo $HOME/.sonar/build-wrapper-macosx-x86.zip http://localhost:9000/static/cpp/build-wrapper-macosx-x86.zip
-unzip -o $HOME/.sonar/build-wrapper-macosx-x86.zip -d $HOME/.sonar/
-export PATH=$HOME/.sonar/build-wrapper-macosx-x86:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: objective-c macos: download scanner 1`] = `
-"export SONAR_SCANNER_VERSION=6.2.0.4584
-export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-macosx-aarch64
-curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-macosx-aarch64.zip
-unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
-export PATH=$SONAR_SCANNER_HOME/bin:$PATH
-"
-`;
-
-exports[`can choose build tools and copy provided settings: objective-c macos: execute build wrapper 1`] = `"build-wrapper-macosx-x86 --out-dir bw-output onboarding.analysis.build_wrapper.execute_build_command"`;
-
-exports[`can choose build tools and copy provided settings: objective-c macos: execute scanner 1`] = `
-"sonar-scanner \\
- -Dsonar.projectKey=my-project \\
- -Dsonar.sources=. \\
- -Dsonar.cfamily.compile-commands=bw-output/compile_commands.json \\
- -Dsonar.host.url=http://localhost:9000"
-`;
-
-exports[`can choose build tools and copy provided settings: objective-c windows: download build wrapper 1`] = `
-"$env:SONAR_DIRECTORY = [System.IO.Path]::Combine($(get-location).Path,".sonar")
-rm "$env:SONAR_DIRECTORY/build-wrapper-win-x86" -Force -Recurse -ErrorAction SilentlyContinue
-New-Item -path $env:SONAR_DIRECTORY/build-wrapper-win-x86 -type directory
-(New-Object System.Net.WebClient).DownloadFile("http://localhost:9000/static/cpp/build-wrapper-win-x86.zip", "$env:SONAR_DIRECTORY/build-wrapper-win-x86.zip")
-Add-Type -AssemblyName System.IO.Compression.FileSystem
-[System.IO.Compression.ZipFile]::ExtractToDirectory("$env:SONAR_DIRECTORY/build-wrapper-win-x86.zip", "$env:SONAR_DIRECTORY")
-$env:Path += ";$env:SONAR_DIRECTORY/build-wrapper-win-x86"
-"
-`;
-
-exports[`can choose build tools and copy provided settings: objective-c windows: download scanner 1`] = `
-"$env:SONAR_SCANNER_VERSION = "6.2.0.4584"
-$env:SONAR_DIRECTORY = [System.IO.Path]::Combine($(get-location).Path,".sonar")
-$env:SONAR_SCANNER_HOME = "$env:SONAR_DIRECTORY/sonar-scanner-$env:SONAR_SCANNER_VERSION-windows-x64"
-rm $env:SONAR_SCANNER_HOME -Force -Recurse -ErrorAction SilentlyContinue
-New-Item -path $env:SONAR_SCANNER_HOME -type directory
-(New-Object System.Net.WebClient).DownloadFile("https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$env:SONAR_SCANNER_VERSION-windows-x64.zip", "$env:SONAR_DIRECTORY/sonar-scanner.zip")
-Add-Type -AssemblyName System.IO.Compression.FileSystem
-[System.IO.Compression.ZipFile]::ExtractToDirectory("$env:SONAR_DIRECTORY/sonar-scanner.zip", "$env:SONAR_DIRECTORY")
-rm ./.sonar/sonar-scanner.zip -Force -ErrorAction SilentlyContinue
-$env:Path += ";$env:SONAR_SCANNER_HOME/bin"
-"
-`;
-
-exports[`can choose build tools and copy provided settings: objective-c windows: execute build wrapper 1`] = `"build-wrapper-win-x86-64.exe --out-dir bw-output onboarding.analysis.build_wrapper.execute_build_command"`;
-
-exports[`can choose build tools and copy provided settings: objective-c windows: execute scanner 1`] = `"sonar-scanner.bat -D"sonar.projectKey=my-project" -D"sonar.sources=." -D"sonar.cfamily.compile-commands=bw-output/compile_commands.json" -D"sonar.host.url=http://localhost:9000""`;
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/AnalysisCommand.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/AnalysisCommand.tsx
deleted file mode 100644
index cbaabc71a3a..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/AnalysisCommand.tsx
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Component } from '../../../../types/types';
-import { Arch, AutoConfig, BuildTools, OSs, TutorialConfig } from '../../types';
-import ClangGCCCustom from './ClangGCCCommand';
-import DotNet from './DotNet';
-import JavaGradle from './JavaGradle';
-import JavaMaven from './JavaMaven';
-import Other from './Other';
-
-export interface AnalysisCommandProps {
- arch: Arch;
- baseUrl: string;
- component: Component;
- config: TutorialConfig;
- isLocal: boolean;
- os: OSs;
- token?: string;
-}
-
-export default function AnalysisCommand(props: Readonly<AnalysisCommandProps>) {
- const { config, os, arch, component, baseUrl, isLocal, token } = props;
-
- if (typeof token === 'undefined') {
- return null;
- }
-
- switch (config.buildTool) {
- case BuildTools.Maven:
- return <JavaMaven baseUrl={baseUrl} component={component} token={token} />;
-
- case BuildTools.Gradle:
- return <JavaGradle baseUrl={baseUrl} component={component} token={token} />;
-
- case BuildTools.DotNet:
- return <DotNet baseUrl={baseUrl} component={component} token={token} />;
-
- case BuildTools.Dart:
- case BuildTools.Other:
- return (
- <Other
- arch={arch}
- baseUrl={baseUrl}
- os={os}
- component={component}
- isLocal={isLocal}
- token={token}
- />
- );
-
- case BuildTools.Cpp:
- case BuildTools.ObjectiveC:
- if (config.buildTool === BuildTools.Cpp && config.autoConfig === AutoConfig.Automatic) {
- return (
- <Other
- arch={arch}
- os={os}
- baseUrl={baseUrl}
- component={component}
- isLocal={isLocal}
- token={token}
- />
- );
- }
- return (
- <ClangGCCCustom
- os={os}
- arch={arch}
- baseUrl={baseUrl}
- component={component}
- isLocal={isLocal}
- token={token}
- />
- );
-
- default:
- return null;
- }
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/ClangGCCCommand.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/ClangGCCCommand.tsx
deleted file mode 100644
index 07c995fc8eb..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/ClangGCCCommand.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Component } from '../../../../types/types';
-import { CompilationInfo } from '../../components/CompilationInfo';
-import { Arch, OSs } from '../../types';
-import DownloadBuildWrapper from './DownloadBuildWrapper';
-import DownloadScanner from './DownloadScanner';
-import ExecBuildWrapper from './ExecBuildWrapper';
-import ExecScanner from './ExecScanner';
-
-export interface ClangGCCCustomProps {
- arch: Arch;
- baseUrl: string;
- component: Component;
- isLocal: boolean;
- os: OSs;
- token: string;
-}
-
-export default function ClangGCCCustom(props: Readonly<ClangGCCCustomProps>) {
- const { os, arch, baseUrl, component, isLocal, token } = props;
-
- return (
- <div>
- <DownloadBuildWrapper isLocal={isLocal} baseUrl={baseUrl} os={os} arch={arch} />
- <DownloadScanner arch={arch} isLocal={isLocal} os={os} token={token} />
- <ExecBuildWrapper os={os} arch={arch} />
- <CompilationInfo />
- <ExecScanner
- baseUrl={baseUrl}
- isLocal={isLocal}
- component={component}
- os={os}
- token={token}
- cfamily
- />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNet.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNet.tsx
deleted file mode 100644
index 4f57980ae56..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNet.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { translate } from '../../../../helpers/l10n';
-import { Component } from '../../../../types/types';
-import RenderOptions from '../../components/RenderOptions';
-import DotNetCore from './DotNetCore';
-import DotNetFramework from './DotNetFramework';
-
-export interface DotNetProps {
- baseUrl: string;
- component: Component;
- token: string;
-}
-
-enum Variant {
- DotNetCoreVariant = 'dotnet_core',
- DotNetFrameworkVariant = 'dotnet_framework',
-}
-
-export default function DotNet(props: DotNetProps) {
- const [variant, setVariant] = React.useState<Variant>(Variant.DotNetCoreVariant);
- const DotNetTuto = variant === 'dotnet_core' ? DotNetCore : DotNetFramework;
-
- return (
- <>
- <RenderOptions
- label={translate('onboarding.build.other.os')}
- checked={variant}
- onCheck={(value) => setVariant(value as Variant)}
- optionLabelKey="onboarding.build.dotnet.variant"
- options={['dotnet_core', 'dotnet_framework']}
- titleLabelKey="onboarding.build.dotnet.variant"
- />
- <DotNetTuto {...props} />
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetCore.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetCore.tsx
deleted file mode 100644
index 4790ade6f7e..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetCore.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CodeSnippet, FlagMessage, SubHeading } from '~design-system';
-import { translate } from '../../../../helpers/l10n';
-import { DotNetProps } from './DotNet';
-import DotNetExecute from './DotNetExecute';
-
-export default function DotNetCore(props: DotNetProps) {
- const { baseUrl, component, token } = props;
-
- const commands = [
- `dotnet sonarscanner begin /k:"${component.key}" /d:sonar.host.url="${baseUrl}" /d:sonar.token="${token}"`,
- 'dotnet build',
- `dotnet sonarscanner end /d:sonar.token="${token}"`,
- ];
-
- return (
- <div>
- <SubHeading className="sw-mt-8 sw-mb-2">
- {translate('onboarding.analysis.dotnetcore.global')}
- </SubHeading>
- <p className="sw-mt-4">{translate('onboarding.analysis.dotnetcore.global.text')}</p>
- <CodeSnippet
- className="sw-px-4"
- isOneLine
- snippet="dotnet tool install --global dotnet-sonarscanner"
- />
- <FlagMessage className="sw-mt-2" variant="info">
- {translate('onboarding.analysis.dotnetcore.global.text.path')}
- </FlagMessage>
- <DotNetExecute commands={commands} />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetExecute.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetExecute.tsx
deleted file mode 100644
index 84261fe4a57..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetExecute.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkStandalone as Link } from '@sonarsource/echoes-react';
-import { FormattedMessage } from 'react-intl';
-import { CodeSnippet, SubHeading } from '~design-system';
-import { DocLink } from '../../../../helpers/doc-links';
-import { useDocUrl } from '../../../../helpers/docs';
-import { translate } from '../../../../helpers/l10n';
-import InstanceMessage from '../../../common/InstanceMessage';
-import DoneNextSteps from '../DoneNextSteps';
-
-export interface DotNetExecuteProps {
- commands: string[];
-}
-
-export default function DotNetExecute({ commands }: Readonly<DotNetExecuteProps>) {
- const docUrl = useDocUrl(DocLink.SonarScannerDotNet);
-
- return (
- <>
- <SubHeading className="sw-mt-8 sw-mb-2">
- {translate('onboarding.analysis.sq_scanner.execute')}
- </SubHeading>
-
- <InstanceMessage message={translate('onboarding.analysis.msbuild.execute.text')}>
- {(transformedMessage) => <p className="sw-mb-2">{transformedMessage}</p>}
- </InstanceMessage>
- {commands.map((command) => (
- <CodeSnippet
- className="sw-px-4"
- key={command}
- language="bash"
- isOneLine
- wrap
- snippet={command}
- />
- ))}
- <p className="sw-mt-4">
- <FormattedMessage
- defaultMessage={translate('onboarding.analysis.docs')}
- id="onboarding.analysis.docs"
- values={{
- link: <Link to={docUrl}>{translate('onboarding.analysis.msbuild.docs_link')}</Link>,
- }}
- />
- </p>
- <DoneNextSteps />
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetFramework.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetFramework.tsx
deleted file mode 100644
index e2be7f35f8b..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetFramework.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkStandalone as Link } from '@sonarsource/echoes-react';
-import { FormattedMessage } from 'react-intl';
-import { SubHeading } from '~design-system';
-import { DocLink } from '../../../../helpers/doc-links';
-import { useDocUrl } from '../../../../helpers/docs';
-import { translate } from '../../../../helpers/l10n';
-import { InlineSnippet } from '../../components/InlineSnippet';
-import { DotNetProps } from './DotNet';
-import DotNetExecute from './DotNetExecute';
-
-export default function DotNetFramework(props: DotNetProps) {
- const { baseUrl, component, token } = props;
-
- const docUrl = useDocUrl(DocLink.SonarScannerDotNet);
-
- const commands = [
- `SonarScanner.MSBuild.exe begin /k:"${component.key}" /d:sonar.host.url="${baseUrl}" /d:sonar.token="${token}"`,
- 'MsBuild.exe /t:Rebuild',
- `SonarScanner.MSBuild.exe end /d:sonar.token="${token}"`,
- ];
-
- return (
- <div>
- <div>
- <SubHeading className=" sw-mb-2 sw-mt-8">
- {translate('onboarding.analysis.msbuild.header')}
- </SubHeading>
- <p>
- <FormattedMessage
- defaultMessage={translate('onboarding.analysis.msbuild.text')}
- id="onboarding.analysis.msbuild.text"
- values={{
- code: <InlineSnippet snippet="SonarScanner.MSBuild.exe" />,
- path: <InlineSnippet snippet="%PATH%" />,
- link: <Link to={docUrl}>{translate('onboarding.analysis.msbuild.docs_link')}</Link>,
- }}
- />
- </p>
- </div>
-
- <DotNetExecute commands={commands} />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/DownloadBuildWrapper.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/DownloadBuildWrapper.tsx
deleted file mode 100644
index f369e91d457..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/DownloadBuildWrapper.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { CodeSnippet, DownloadButton, SubHeading } from '~design-system';
-import { translate } from '../../../../helpers/l10n';
-import { getBaseUrl } from '../../../../helpers/system';
-import { InlineSnippet } from '../../components/InlineSnippet';
-import { Arch, OSs } from '../../types';
-import { getBuildWrapperFolder } from '../../utils';
-
-export interface DownloadBuildWrapperProps {
- arch: Arch;
- baseUrl: string;
- isLocal: boolean;
- os: OSs;
-}
-
-export default function DownloadBuildWrapper(props: Readonly<DownloadBuildWrapperProps>) {
- const { os, arch, isLocal, baseUrl } = props;
- return (
- <div className="sw-mb-4">
- <SubHeading className="sw-mb-2">
- {translate('onboarding.analysis.build_wrapper.header', os)}
- </SubHeading>
- {isLocal ? (
- <>
- <p className="sw-mb-2">
- <FormattedMessage
- defaultMessage={translate('onboarding.analysis.build_wrapper.text')}
- id="onboarding.analysis.build_wrapper.text"
- values={{
- env_var: <InlineSnippet snippet={os === 'win' ? '%PATH%' : 'PATH'} />,
- }}
- />
- </p>
- <p className="sw-mb-2">
- <DownloadButton
- download={`${getBuildWrapperFolder(os, arch)}.zip`}
- href={`${getBaseUrl()}/static/cpp/${getBuildWrapperFolder(os, arch)}.zip`}
- rel="noopener noreferrer"
- target="_blank"
- >
- {translate('download_verb')}
- </DownloadButton>
- </p>
- </>
- ) : (
- <CodeSnippet
- className="sw-p-4"
- language={os === OSs.Windows ? 'powershell' : 'bash'}
- snippet={getRemoteDownloadSnippet(os, arch, baseUrl)}
- />
- )}
- </div>
- );
-}
-
-function getRemoteDownloadSnippet(os: OSs, arch: Arch, baseUrl: string) {
- if (os === OSs.Windows) {
- return `$env:SONAR_DIRECTORY = [System.IO.Path]::Combine($(get-location).Path,".sonar")
-rm "$env:SONAR_DIRECTORY/build-wrapper-win-x86" -Force -Recurse -ErrorAction SilentlyContinue
-New-Item -path $env:SONAR_DIRECTORY/build-wrapper-win-x86 -type directory
-(New-Object System.Net.WebClient).DownloadFile("${baseUrl}/static/cpp/build-wrapper-win-x86.zip", "$env:SONAR_DIRECTORY/build-wrapper-win-x86.zip")
-Add-Type -AssemblyName System.IO.Compression.FileSystem
-[System.IO.Compression.ZipFile]::ExtractToDirectory("$env:SONAR_DIRECTORY/build-wrapper-win-x86.zip", "$env:SONAR_DIRECTORY")
-$env:Path += ";$env:SONAR_DIRECTORY/build-wrapper-win-x86"
-`;
- }
- const folder = getBuildWrapperFolder(os, arch);
- return `curl --create-dirs -sSLo $HOME/.sonar/${folder}.zip ${baseUrl}/static/cpp/${folder}.zip
-unzip -o $HOME/.sonar/${folder}.zip -d $HOME/.sonar/
-export PATH=$HOME/.sonar/${folder}:$PATH
-`;
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/DownloadScanner.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/DownloadScanner.tsx
deleted file mode 100644
index 1b00d642687..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/DownloadScanner.tsx
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Link } from '@sonarsource/echoes-react';
-import { FormattedMessage } from 'react-intl';
-import {
- ClipboardIconButton,
- CodeSnippet,
- NumberedList,
- NumberedListItem,
- SubHeading,
-} from '~design-system';
-import { DocLink } from '../../../../helpers/doc-links';
-import { useDocUrl } from '../../../../helpers/docs';
-import { translate } from '../../../../helpers/l10n';
-import { InlineSnippet } from '../../components/InlineSnippet';
-import { Arch, OSs } from '../../types';
-import { SONAR_SCANNER_CLI_LATEST_VERSION, getScannerUrlSuffix } from '../../utils';
-
-export interface DownloadScannerProps {
- arch: Arch;
- isLocal: boolean;
- os: OSs;
- token: string;
-}
-
-export default function DownloadScanner(props: Readonly<DownloadScannerProps>) {
- const { arch, os, isLocal, token } = props;
-
- const docUrl = useDocUrl(DocLink.SonarScanner);
-
- return (
- <div className="sw-mb-4">
- <SubHeading className="sw-mb-2">
- {translate('onboarding.analysis.sq_scanner.header', os)}
- </SubHeading>
- {isLocal ? (
- <p className="sw-mb-2">
- <FormattedMessage
- defaultMessage={translate('onboarding.analysis.sq_scanner.text')}
- id="onboarding.analysis.sq_scanner.text"
- values={{
- dir: <InlineSnippet snippet="bin" />,
- env_var: <InlineSnippet snippet={os === OSs.Windows ? '%PATH%' : 'PATH'} />,
- link: (
- <Link to={docUrl}>{translate('onboarding.analysis.sq_scanner.docs_link')}</Link>
- ),
- }}
- />
- </p>
- ) : (
- <>
- <CodeSnippet
- className="sw-p-4"
- wrap
- language={os === OSs.Windows ? 'powershell' : 'bash'}
- snippet={getRemoteDownloadSnippet(os, arch)}
- render={`<code>${getRemoteDownloadSnippet(os, arch)}</code>`}
- />
- <SubHeading className="sw-mb-2 sw-mt-4">
- {translate('onboarding.analysis.sq_scanner.sonar_token_env.header')}
- </SubHeading>
- <NumberedList>
- <NumberedListItem className="sw-flex sw-items-center">
- <span className="sw-mr-1">
- {translate('onboarding.analysis.sq_scanner.sonar_token_env.var_name')}:
- </span>
- <InlineSnippet snippet="SONAR_TOKEN" />
- <ClipboardIconButton className="sw-ml-2" copyValue="SONAR_TOKEN" />
- </NumberedListItem>
- <NumberedListItem className="sw-flex sw-items-center">
- <span className="sw-mr-1">
- {translate('onboarding.analysis.sq_scanner.sonar_token_env.var_value')}:
- </span>
- <InlineSnippet snippet={token} />
- <ClipboardIconButton className="sw-ml-2" copyValue={token} />
- </NumberedListItem>
- </NumberedList>
- </>
- )}
- </div>
- );
-}
-
-function getRemoteDownloadSnippet(os: OSs, arch: Arch) {
- const suffix = getScannerUrlSuffix(os, arch);
- if (os === OSs.Windows) {
- return `$env:SONAR_SCANNER_VERSION = "${SONAR_SCANNER_CLI_LATEST_VERSION}"
-$env:SONAR_DIRECTORY = [System.IO.Path]::Combine($(get-location).Path,".sonar")
-$env:SONAR_SCANNER_HOME = "$env:SONAR_DIRECTORY/sonar-scanner-$env:SONAR_SCANNER_VERSION${suffix}"
-rm $env:SONAR_SCANNER_HOME -Force -Recurse -ErrorAction SilentlyContinue
-New-Item -path $env:SONAR_SCANNER_HOME -type directory
-(New-Object System.Net.WebClient).DownloadFile("https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$env:SONAR_SCANNER_VERSION${suffix}.zip", "$env:SONAR_DIRECTORY/sonar-scanner.zip")
-Add-Type -AssemblyName System.IO.Compression.FileSystem
-[System.IO.Compression.ZipFile]::ExtractToDirectory("$env:SONAR_DIRECTORY/sonar-scanner.zip", "$env:SONAR_DIRECTORY")
-rm ./.sonar/sonar-scanner.zip -Force -ErrorAction SilentlyContinue
-$env:Path += ";$env:SONAR_SCANNER_HOME/bin"
-`;
- }
- return `export SONAR_SCANNER_VERSION=${SONAR_SCANNER_CLI_LATEST_VERSION}
-export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION${suffix}
-curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION${suffix}.zip
-unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
-export PATH=$SONAR_SCANNER_HOME/bin:$PATH
-`;
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/ExecBuildWrapper.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/ExecBuildWrapper.tsx
deleted file mode 100644
index 0646f9c26ac..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/ExecBuildWrapper.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { CodeSnippet, Link, SubHeading } from '~design-system';
-import { DocLink } from '../../../../helpers/doc-links';
-import { useDocUrl } from '../../../../helpers/docs';
-import { translate } from '../../../../helpers/l10n';
-import { Arch, OSs } from '../../types';
-import { getBuildWrapperExecutable } from '../../utils';
-
-export interface ExecBuildWrapperProps {
- arch: Arch;
- os: OSs;
-}
-
-export default function ExecBuildWrapper(props: ExecBuildWrapperProps) {
- const { os, arch } = props;
-
- const docUrl = useDocUrl(DocLink.CFamilyBuildWrapper);
-
- return (
- <>
- <SubHeading className="sw-mt-8 sw-mb-2">
- {translate('onboarding.analysis.build_wrapper.execute')}
- </SubHeading>
- <p className="sw-mb-2">{translate('onboarding.analysis.build_wrapper.execute_text')}</p>
- <CodeSnippet
- className="sw-px-4"
- isOneLine
- snippet={`${getBuildWrapperExecutable(os, arch)} --out-dir bw-output ${translate(
- 'onboarding.analysis.build_wrapper.execute_build_command',
- )}`}
- />
- <p className="sw-mt-4">
- <FormattedMessage
- defaultMessage={translate('onboarding.analysis.build_wrapper.docs')}
- id="onboarding.analysis.build_wrapper.docs"
- values={{
- link: (
- <Link to={docUrl}>{translate('onboarding.analysis.build_wrapper.docs_link')}</Link>
- ),
- }}
- />
- </p>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/ExecScanner.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/ExecScanner.tsx
deleted file mode 100644
index 84f2c4262b9..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/ExecScanner.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { CodeSnippet, Link, SubHeading } from '~design-system';
-import { DocLink } from '../../../../helpers/doc-links';
-import { useDocUrl } from '../../../../helpers/docs';
-import { translate } from '../../../../helpers/l10n';
-import { Component } from '../../../../types/types';
-import InstanceMessage from '../../../common/InstanceMessage';
-import { OSs } from '../../types';
-import { quote } from '../../utils';
-import DoneNextSteps from '../DoneNextSteps';
-
-export interface ExecScannerProps {
- baseUrl: string;
- cfamily?: boolean;
- component: Component;
- isLocal: boolean;
- os: OSs;
- token: string;
-}
-
-export default function ExecScanner(props: ExecScannerProps) {
- const { baseUrl, os, isLocal, component, token, cfamily } = props;
-
- const docUrl = useDocUrl(DocLink.SonarScanner);
-
- const q = quote(os);
- const command = [
- os === OSs.Windows ? 'sonar-scanner.bat' : 'sonar-scanner',
- '-D' + q(`sonar.projectKey=${component.key}`),
- '-D' + q('sonar.sources=.'),
- cfamily
- ? '-D' + q('sonar.cfamily.compile-commands=bw-output/compile_commands.json')
- : undefined,
- '-D' + q(`sonar.host.url=${baseUrl}`),
- isLocal ? '-D' + q(`sonar.token=${token}`) : undefined,
- ];
-
- return (
- <div>
- <SubHeading className="sw-mt-4 sw-mb-2">
- {translate('onboarding.analysis.sq_scanner.execute')}
- </SubHeading>
- <InstanceMessage message={translate('onboarding.analysis.sq_scanner.execute.text')}>
- {(transformedMessage) => <p className="sw-mb-2">{transformedMessage}</p>}
- </InstanceMessage>
- <CodeSnippet className="sw-p-4" isOneLine={os === OSs.Windows} snippet={command} />
- <p className="sw-mt-4">
- <FormattedMessage
- defaultMessage={translate('onboarding.analysis.sq_scanner.docs')}
- id="onboarding.analysis.sq_scanner.docs"
- values={{
- link: <Link to={docUrl}>{translate('onboarding.analysis.sq_scanner.docs_link')}</Link>,
- }}
- />
- </p>
- <DoneNextSteps />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/JavaGradle.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/JavaGradle.tsx
deleted file mode 100644
index 6328925b383..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/JavaGradle.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { CodeSnippet, Link, Note, SubHeading } from '~design-system';
-import { GRADLE_SCANNER_VERSION } from '../../../../helpers/constants';
-import { DocLink } from '../../../../helpers/doc-links';
-import { useDocUrl } from '../../../../helpers/docs';
-import { translate } from '../../../../helpers/l10n';
-import { Component } from '../../../../types/types';
-import InstanceMessage from '../../../common/InstanceMessage';
-import GradleBuildSelection from '../../components/GradleBuildSelection';
-import { InlineSnippet } from '../../components/InlineSnippet';
-import { GradleBuildDSL } from '../../types';
-import DoneNextSteps from '../DoneNextSteps';
-
-export interface JavaGradleProps {
- baseUrl: string;
- component: Component;
- token: string;
-}
-
-const config = {
- [GradleBuildDSL.Groovy]: {
- lang: 'groovy',
- snippet: `plugins {
- id "org.sonarqube" version "${GRADLE_SCANNER_VERSION}"
-}`,
- },
- [GradleBuildDSL.Kotlin]: {
- lang: 'kts',
- snippet: `plugins {
- id("org.sonarqube") version "${GRADLE_SCANNER_VERSION}"
-}`,
- },
-};
-
-export default function JavaGradle(props: JavaGradleProps) {
- const { baseUrl, component, token } = props;
-
- const docUrl = useDocUrl(DocLink.SonarScannerGradle);
-
- const command = [
- './gradlew sonar',
- `-Dsonar.projectKey=${component.key}`,
- `-Dsonar.projectName='${component.name}'`,
- `-Dsonar.host.url=${baseUrl}`,
- `-Dsonar.token=${token}`,
- ];
-
- return (
- <div>
- <SubHeading className="sw-mb-2">
- {translate('onboarding.analysis.java.gradle.header')}
- </SubHeading>
- <InstanceMessage message={translate('onboarding.analysis.java.gradle.text.1')}>
- {(transformedMessage) => (
- <p className="sw-mb-2">
- <FormattedMessage
- defaultMessage={transformedMessage}
- id="onboarding.analysis.java.gradle.text.1"
- values={{
- plugin_code: <InlineSnippet snippet="org.sonarqube" />,
- groovy: <InlineSnippet snippet={GradleBuildDSL.Groovy} />,
- kotlin: <InlineSnippet snippet={GradleBuildDSL.Kotlin} />,
- }}
- />
- </p>
- )}
- </InstanceMessage>
- <GradleBuildSelection className="sw-mt-4 sw-mb-4">
- {(build) => (
- <CodeSnippet
- language={config[build].lang}
- className="sw-p-4"
- snippet={config[build].snippet}
- />
- )}
- </GradleBuildSelection>
- <p className="sw-mb-4">
- <Note as="em">
- <FormattedMessage
- defaultMessage={translate('onboarding.analysis.java.gradle.latest_version')}
- id="onboarding.analysis.java.gradle.latest_version"
- values={{
- link: <Link to={docUrl}>{translate('here')}</Link>,
- }}
- />
- </Note>
- </p>
- <p className="sw-mt-2 sw-mb-2">{translate('onboarding.analysis.java.gradle.text.2')}</p>
- <CodeSnippet className="sw-p-4" snippet={command} />
- <p className="sw-mt-4">
- <FormattedMessage
- defaultMessage={translate('onboarding.analysis.docs')}
- id="onboarding.analysis.docs"
- values={{
- link: <Link to={docUrl}>{translate('onboarding.analysis.java.gradle.docs_link')}</Link>,
- }}
- />
- </p>
- <DoneNextSteps />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/JavaMaven.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/JavaMaven.tsx
deleted file mode 100644
index 6942f7a479e..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/JavaMaven.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { CodeSnippet, Link, SubHeading } from '~design-system';
-import { DocLink } from '../../../../helpers/doc-links';
-import { useDocUrl } from '../../../../helpers/docs';
-import { translate } from '../../../../helpers/l10n';
-import { Component } from '../../../../types/types';
-import InstanceMessage from '../../../common/InstanceMessage';
-import DoneNextSteps from '../DoneNextSteps';
-
-export interface JavaMavenProps {
- baseUrl: string;
- component: Component;
- token: string;
-}
-
-export default function JavaMaven(props: JavaMavenProps) {
- const { baseUrl, component, token } = props;
- const command = [
- 'mvn clean verify sonar:sonar',
- `-Dsonar.projectKey=${component.key}`,
- `-Dsonar.projectName='${component.name}'`,
- `-Dsonar.host.url=${baseUrl}`,
- `-Dsonar.token=${token}`,
- ];
-
- const docUrl = useDocUrl(DocLink.SonarScannerMaven);
-
- return (
- <div>
- <SubHeading className="sw-mb-2">
- {translate('onboarding.analysis.java.maven.header')}
- </SubHeading>
- <p className="sw-mb-2">
- <InstanceMessage message={translate('onboarding.analysis.java.maven.text')} />
- </p>
- <CodeSnippet className="sw-p-4" snippet={command} />
- <p className="sw-mt-4">
- <FormattedMessage
- defaultMessage={translate('onboarding.analysis.docs')}
- id="onboarding.analysis.docs"
- values={{
- link: <Link to={docUrl}>{translate('onboarding.analysis.java.maven.docs_link')}</Link>,
- }}
- />
- </p>
- <DoneNextSteps />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/Other.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/Other.tsx
deleted file mode 100644
index 646283c0008..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/Other.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Component } from '../../../../types/types';
-import { Arch, OSs } from '../../types';
-import DownloadScanner from './DownloadScanner';
-import ExecScanner from './ExecScanner';
-
-export interface OtherProps {
- arch: Arch;
- baseUrl: string;
- component: Component;
- isLocal: boolean;
- os: OSs;
- token: string;
-}
-
-export default function Other(props: Readonly<OtherProps>) {
- const { arch, baseUrl, os, component, isLocal, token } = props;
-
- return (
- <div>
- <DownloadScanner arch={arch} isLocal={isLocal} os={os} token={token} />
- <ExecScanner
- baseUrl={baseUrl}
- isLocal={isLocal}
- os={os}
- component={component}
- token={token}
- />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/test-utils.ts b/server/sonar-web/src/main/js/components/tutorials/test-utils.ts
deleted file mode 100644
index f46255e766c..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/test-utils.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { byLabelText, byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { BuildTools, GradleBuildDSL, OSs, TutorialModes } from './types';
-
-const CI_TRANSLATE_MAP: Partial<Record<TutorialModes, string>> = {
- [TutorialModes.BitbucketPipelines]: 'bitbucket_pipelines',
- [TutorialModes.GitHubActions]: 'github_action',
- [TutorialModes.GitLabCI]: 'gitlab_ci',
-};
-
-interface GetCopyToClipboardValueArgs {
- i?: number;
- inlineSnippet?: boolean;
- name?: string;
-}
-
-export function getCopyToClipboardValue({
- i = 0,
- inlineSnippet = false,
- name = 'copy_to_clipboard',
-}: GetCopyToClipboardValueArgs = {}) {
- const button = screen.getAllByRole('button', { name })[i];
-
- return inlineSnippet
- ? button.previousSibling?.firstChild?.textContent
- : button.nextSibling?.firstChild?.textContent;
-}
-
-export function getCopyToClipboardHostURLValue({
- i = 0,
- name = 'copy_to_clipboard',
-}: Omit<GetCopyToClipboardValueArgs, 'inlineSnippet'> = {}) {
- return screen.getAllByRole('button', { name })[i].nextSibling?.nextSibling?.firstChild
- ?.textContent;
-}
-
-export function getCommonNodes(ci: TutorialModes) {
- return {
- secretsStepTitle: byRole('heading', {
- name: `onboarding.tutorial.with.${CI_TRANSLATE_MAP[ci]}.${
- ci === TutorialModes.GitHubActions ? 'create_secret' : 'variables'
- }.title`,
- }),
- ymlFileStepTitle: byRole('heading', {
- name: `onboarding.tutorial.with.${CI_TRANSLATE_MAP[ci]}.yaml.title`,
- }),
- genTokenDialogButton: byRole('button', {
- name: 'onboarding.token.generate.long',
- }),
- tokenNameInput: byRole('textbox', { name: 'onboarding.token.name.label' }),
- expiresInSelect: byRole('combobox', { name: '' }),
- tokenValue: byText('generatedtoken2'),
- linkToRepo: byRole('link', {
- name: new RegExp(
- `onboarding.tutorial.with.${CI_TRANSLATE_MAP[ci]}.${
- ci === TutorialModes.GitHubActions ? 'secret' : 'variables'
- }.intro.link`,
- ),
- }),
- allSetSentence: byText('onboarding.tutorial.ci_outro.done'),
- };
-}
-
-export function getTutorialActionButtons() {
- return {
- continueButton: byRole('button', { name: 'continue' }),
- generateTokenButton: byRole('button', { name: 'onboarding.token.generate' }),
- deleteTokenButton: byRole('button', { name: 'onboarding.token.delete' }),
- finishTutorialButton: byRole('button', { name: 'tutorials.finish' }),
- };
-}
-
-export function getTutorialBuildButtons() {
- return {
- describeBuildTitle: byLabelText('onboarding.build'),
- mavenBuildButton: byRole('radio', { name: `onboarding.build.${BuildTools.Maven}` }),
- gradleBuildButton: byRole('radio', { name: `onboarding.build.${BuildTools.Gradle}` }),
- gradleDSLButton: (name: GradleBuildDSL) => byRole('radio', { name }),
- dotnetBuildButton: byRole('radio', { name: `onboarding.build.${BuildTools.DotNet}` }),
- cppBuildButton: byRole('radio', { name: `onboarding.build.${BuildTools.Cpp}` }),
- objCBuildButton: byRole('radio', { name: `onboarding.build.${BuildTools.ObjectiveC}` }),
- dartBuildButton: byRole('radio', { name: `onboarding.build.${BuildTools.Dart}` }),
- otherBuildButton: byRole('radio', { name: `onboarding.build.${BuildTools.Other}` }),
- windowsDotnetCoreButton: byRole('radio', {
- name: `onboarding.build.${BuildTools.DotNet}.win_core`,
- }),
- windowsDotnetFrameworkButton: byRole('radio', {
- name: `onboarding.build.${BuildTools.DotNet}.win_msbuild`,
- }),
- linuxDotnetCoreButton: byRole('radio', {
- name: `onboarding.build.${BuildTools.DotNet}.linux_core`,
- }),
- dotnetCoreButton: byRole('radio', {
- name: `onboarding.build.${BuildTools.DotNet}.variant.dotnet_core`,
- }),
- dotnetFrameworkButton: byRole('radio', {
- name: `onboarding.build.${BuildTools.DotNet}.variant.dotnet_framework`,
- }),
- linuxButton: byRole('radio', { name: `onboarding.build.other.os.${OSs.Linux}` }),
- windowsButton: byRole('radio', { name: `onboarding.build.other.os.${OSs.Windows}` }),
- macosButton: byRole('radio', { name: `onboarding.build.other.os.${OSs.MacOS}` }),
- arm64Button: byRole('radio', { name: `onboarding.build.other.architecture.arm64` }),
- x86_64Button: byRole('radio', { name: `onboarding.build.other.architecture.x86_64` }),
- autoConfigAutomatic: byRole('radio', { name: 'onboarding.build.cpp.autoconfig.automatic' }),
- autoConfigManual: byRole('radio', { name: 'onboarding.build.cpp.autoconfig.manual' }),
- };
-}
diff --git a/server/sonar-web/src/main/js/components/tutorials/types.ts b/server/sonar-web/src/main/js/components/tutorials/types.ts
deleted file mode 100644
index 77eb740a45f..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/types.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum TutorialModes {
- Local = 'local',
- Jenkins = 'jenkins',
- BitbucketPipelines = 'bitbucket-pipelines',
- GitLabCI = 'gitlab-ci',
- GitHubActions = 'github-actions',
- AzurePipelines = 'azure-pipelines',
- OtherCI = 'other-ci',
-}
-
-export enum BuildTools {
- Maven = 'maven',
- Gradle = 'gradle',
- Cpp = 'cpp',
- ObjectiveC = 'objectivec',
- DotNet = 'dotnet',
- Dart = 'dart',
- Other = 'other',
-}
-
-export enum GradleBuildDSL {
- Groovy = 'build.gradle',
- Kotlin = 'build.gradle.kts',
-}
-
-export enum OSs {
- Linux = 'linux',
- Windows = 'win',
- MacOS = 'mac',
-}
-
-export enum Arch {
- X86_64 = 'x86_64',
- Arm64 = 'arm64',
-}
-
-export enum AutoConfig {
- Automatic = 'automatic',
- Manual = 'manual',
-}
-
-export type TutorialConfig = {
- autoConfig?: AutoConfig;
- buildTool?: BuildTools;
-};
diff --git a/server/sonar-web/src/main/js/components/tutorials/utils.ts b/server/sonar-web/src/main/js/components/tutorials/utils.ts
deleted file mode 100644
index 12425ea5998..00000000000
--- a/server/sonar-web/src/main/js/components/tutorials/utils.ts
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { GRADLE_SCANNER_VERSION } from '../../helpers/constants';
-import { convertGithubApiUrlToLink, stripTrailingSlash } from '../../helpers/urls';
-import { AlmSettingsInstance, ProjectAlmBindingResponse } from '../../types/alm-settings';
-import { UserToken } from '../../types/token';
-import { Arch, AutoConfig, BuildTools, GradleBuildDSL, OSs, TutorialConfig } from './types';
-
-export const SONAR_SCANNER_CLI_LATEST_VERSION = '6.2.0.4584';
-
-export function quote(os: string): (s: string) => string {
- return os === 'win' ? (s: string) => `"${s}"` : (s: string) => s;
-}
-
-export function buildGradleSnippet(key: string, name: string, build: GradleBuildDSL) {
- const map = {
- [GradleBuildDSL.Groovy]: `plugins {
- id "org.sonarqube" version "${GRADLE_SCANNER_VERSION}"
-}
-
-sonar {
- properties {
- property "sonar.projectKey", "${key}"
- property "sonar.projectName", "${name}"
- }
-}`,
- [GradleBuildDSL.Kotlin]: `plugins {
- id("org.sonarqube") version "${GRADLE_SCANNER_VERSION}"
-}
-
-sonar {
- properties {
- property("sonar.projectKey", "${key}")
- property("sonar.projectName", "${name}")
- }
-}`,
- };
- return map[build];
-}
-
-export function getUniqueTokenName(tokens: UserToken[], initialTokenName: string) {
- const hasToken = (name: string) => tokens.find((token) => token.name === name) !== undefined;
-
- if (!hasToken(initialTokenName)) {
- return initialTokenName;
- }
-
- let i = 1;
- while (hasToken(`${initialTokenName} ${i}`)) {
- i++;
- }
- return `${initialTokenName} ${i}`;
-}
-
-export function buildGithubLink(
- almBinding: AlmSettingsInstance,
- projectBinding: ProjectAlmBindingResponse,
-) {
- if (almBinding.url === undefined) {
- return null;
- }
-
- // strip the api path:
- const urlRoot = convertGithubApiUrlToLink(almBinding.url);
-
- return `${stripTrailingSlash(urlRoot)}/${projectBinding.repository}`;
-}
-
-export function buildBitbucketCloudLink(
- almBinding: AlmSettingsInstance,
- projectBinding: ProjectAlmBindingResponse,
-) {
- if (almBinding.url === undefined || projectBinding.repository === undefined) {
- return null;
- }
-
- return `${stripTrailingSlash(almBinding.url)}/${projectBinding.repository}`;
-}
-
-export function supportsAutoConfig(buildTool: BuildTools) {
- return buildTool === BuildTools.Cpp;
-}
-
-export function getBuildToolOptions(supportCFamily: boolean) {
- const list = [BuildTools.Maven, BuildTools.Gradle, BuildTools.DotNet];
- if (supportCFamily) {
- list.push(BuildTools.Cpp);
- list.push(BuildTools.ObjectiveC);
- // Both Dart and CFamily are available in Developer Edition and above
- list.push(BuildTools.Dart);
- }
- list.push(BuildTools.Other);
- return list;
-}
-
-export function isCFamily(buildTool?: BuildTools) {
- return buildTool === BuildTools.Cpp || buildTool === BuildTools.ObjectiveC;
-}
-
-export function shouldShowGithubCFamilyExampleRepositories(config: TutorialConfig) {
- if (config.buildTool === BuildTools.Cpp && config.autoConfig === AutoConfig.Manual) {
- return true;
- }
- if (config.buildTool === BuildTools.ObjectiveC) {
- return true;
- }
- return false;
-}
-
-export function shouldShowOsSelector(config: TutorialConfig) {
- return (
- config.buildTool === BuildTools.Cpp ||
- config.buildTool === BuildTools.ObjectiveC ||
- config.buildTool === BuildTools.Dart ||
- config.buildTool === BuildTools.Other
- );
-}
-
-export function shouldShowArchSelector(
- os: OSs | undefined,
- config: TutorialConfig,
- scannerDownloadExplicit = false,
-) {
- if (!shouldShowOsSelector(config)) {
- return false;
- }
- if (os !== OSs.Linux && os !== OSs.MacOS) {
- return false;
- }
- if (scannerDownloadExplicit) {
- return true;
- }
- if (!isCFamily(config.buildTool)) {
- return false;
- }
- if (config.buildTool === BuildTools.Cpp && config.autoConfig === AutoConfig.Automatic) {
- return false;
- }
- return true;
-}
-
-export function getBuildWrapperFolder(os: OSs, arch?: Arch) {
- if (os === OSs.Linux) {
- return arch === Arch.X86_64 ? 'build-wrapper-linux-x86' : 'build-wrapper-linux-aarch64';
- }
- if (os === OSs.MacOS) {
- return 'build-wrapper-macosx-x86';
- }
- if (os === OSs.Windows) {
- return 'build-wrapper-win-x86';
- }
- throw new Error(`Unsupported OS: ${os}`);
-}
-
-export function getBuildWrapperExecutable(os: OSs, arch?: Arch) {
- if (os === OSs.Linux) {
- return arch === Arch.X86_64 ? 'build-wrapper-linux-x86-64' : 'build-wrapper-linux-aarch64';
- }
- if (os === OSs.MacOS) {
- return 'build-wrapper-macosx-x86';
- }
- if (os === OSs.Windows) {
- return 'build-wrapper-win-x86-64.exe';
- }
- throw new Error(`Unsupported OS: ${os}`);
-}
-
-export function getBuildWrapperFolderLinux(arch?: Arch) {
- return getBuildWrapperFolder(OSs.Linux, arch);
-}
-export function getBuildWrapperExecutableLinux(arch?: Arch) {
- return getBuildWrapperExecutable(OSs.Linux, arch);
-}
-
-export function getScannerUrlSuffix(os: OSs, arch?: Arch) {
- if (os === OSs.Windows) {
- return '-windows-x64';
- }
- if (os === OSs.MacOS) {
- return '-macosx-' + (arch === Arch.Arm64 ? 'aarch64' : 'x64');
- }
- if (os === OSs.Linux) {
- return '-linux-' + (arch === Arch.Arm64 ? 'aarch64' : 'x64');
- }
- return '';
-}
-
-export function shouldFetchBuildWrapper(buildTool: BuildTools, autoConfig?: AutoConfig) {
- return (
- (buildTool === BuildTools.Cpp && autoConfig === AutoConfig.Manual) ||
- buildTool === BuildTools.ObjectiveC
- );
-}
-
-export function shouldFetchScanner(buildTool: BuildTools) {
- if (isCFamily(buildTool)) {
- return true;
- }
- return [BuildTools.Dart].includes(buildTool);
-}
diff --git a/server/sonar-web/src/main/js/components/ui/AdminPageHeader.tsx b/server/sonar-web/src/main/js/components/ui/AdminPageHeader.tsx
deleted file mode 100644
index 1b3463c8c32..00000000000
--- a/server/sonar-web/src/main/js/components/ui/AdminPageHeader.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { withTheme } from '@emotion/react';
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { ReactNode } from 'react';
-import { themeColor } from '~design-system';
-
-interface Props {
- children?: ReactNode;
- className?: string;
- description?: ReactNode;
- title: ReactNode;
-}
-
-export function AdminPageHeader({ children, className, description, title }: Readonly<Props>) {
- return (
- <div className={classNames('sw-flex sw-justify-between', className)}>
- <header className="sw-flex-1">
- <AdminPageTitle className="sw-heading-xl">{title}</AdminPageTitle>
- {description && (
- <AdminPageDescription className="sw-typo-default sw-pt-4 sw-max-w-9/12">
- {description}
- </AdminPageDescription>
- )}
- </header>
- {children && <div className="sw-flex sw-gap-2">{children}</div>}
- </div>
- );
-}
-export const AdminPageTitle = withTheme(styled.h1`
- color: ${themeColor('pageTitle')};
-`);
-
-export const AdminPageDescription = withTheme(styled.div`
- color: ${themeColor('pageContent')};
-`);
diff --git a/server/sonar-web/src/main/js/components/ui/AiCodeAssuranceBanner.tsx b/server/sonar-web/src/main/js/components/ui/AiCodeAssuranceBanner.tsx
deleted file mode 100644
index 45ecd690fc0..00000000000
--- a/server/sonar-web/src/main/js/components/ui/AiCodeAssuranceBanner.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { Heading } from '@sonarsource/echoes-react';
-import AIAssuredIllustration, { AiIconVariant } from '../illustrations/AiAssuredIllustration';
-
-interface AiCodeAssuranceBannerProps {
- className?: string;
- description: React.ReactNode;
- iconVariant: AiIconVariant;
- title: React.ReactNode;
-}
-
-export default function AiCodeAssuranceBanner({
- className,
- iconVariant,
- title,
- description,
-}: Readonly<AiCodeAssuranceBannerProps>) {
- return (
- <StyledWrapper className={className}>
- <MessageContainer>
- <LeftContent>
- <AIAssuredIllustration variant={iconVariant} width={84} height={84} />
- <TextWrapper>
- <PromotedHeading as="h3">{title}</PromotedHeading>
- {description}
- </TextWrapper>
- </LeftContent>
- </MessageContainer>
- </StyledWrapper>
- );
-}
-
-const StyledWrapper = styled.div`
- background-color: var(--echoes-color-background-accent-weak-default);
- border: 1px solid var(--echoes-color-border-weak);
- padding-left: var(--echoes-dimension-space-300);
- border-radius: var(--echoes-border-radius-400);
-`;
-
-const MessageContainer = styled.div`
- padding-top: var(--echoes-dimension-space-100);
- padding-bottom: var(--echoes-dimension-space-100);
-`;
-
-const LeftContent = styled.div`
- display: flex;
- align-items: center;
- gap: var(--echoes-border-radius-400);
-`;
-
-const TextWrapper = styled.div`
- display: flex;
- flex-direction: column;
- padding-top: var(--echoes-dimension-space-100);
- padding-bottom: var(--echoes-dimension-space-100);
- gap: var(--echoes-border-radius-400);
-`;
-
-const PromotedHeading = styled(Heading)`
- color: var(--echoes-color-text-accent-bold);
-`;
diff --git a/server/sonar-web/src/main/js/components/ui/Avatar.tsx b/server/sonar-web/src/main/js/components/ui/Avatar.tsx
deleted file mode 100644
index b8d6d67d0ab..00000000000
--- a/server/sonar-web/src/main/js/components/ui/Avatar.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Avatar as BaseAvatar } from '~design-system';
-import { AppStateContext } from '../../app/components/app-state/AppStateContext';
-import { FCProps } from '../../types/misc';
-import { GlobalSettingKeys } from '../../types/settings';
-
-type ExcludedProps =
- | 'enableGravatar'
- | 'gravatarServerUrl'
- | 'organizationAvatar'
- | 'organizationName';
-
-type Props = Omit<FCProps<typeof BaseAvatar>, ExcludedProps>;
-
-export default function Avatar(props: Props) {
- const { settings } = React.useContext(AppStateContext);
-
- const enableGravatar = settings[GlobalSettingKeys.EnableGravatar] === 'true';
- const gravatarServerUrl = settings[GlobalSettingKeys.GravatarServerUrl] ?? '';
-
- return (
- <BaseAvatar enableGravatar={enableGravatar} gravatarServerUrl={gravatarServerUrl} {...props} />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/ui/DismissableAlert.tsx b/server/sonar-web/src/main/js/components/ui/DismissableAlert.tsx
deleted file mode 100644
index 98a6bb91a17..00000000000
--- a/server/sonar-web/src/main/js/components/ui/DismissableAlert.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import * as React from 'react';
-import { Banner, Variant } from '~design-system';
-import { get, save } from '../../helpers/storage';
-
-export interface DismissableAlertProps {
- alertKey: string;
- children?: React.ReactNode;
- className?: string;
- variant: Variant;
-}
-
-export const DISMISSED_ALERT_STORAGE_KEY = 'sonarqube.dismissed_alert';
-
-export function DismissableAlert(props: DismissableAlertProps) {
- const { alertKey, children, className, variant } = props;
- const [show, setShow] = React.useState(false);
-
- React.useEffect(() => {
- if (get(DISMISSED_ALERT_STORAGE_KEY, alertKey) !== 'true') {
- setShow(true);
- } else {
- setShow(false);
- }
- }, [alertKey]);
-
- const hideAlert = () => {
- window.dispatchEvent(new Event('resize'));
- save(DISMISSED_ALERT_STORAGE_KEY, 'true', alertKey);
- };
-
- return !show ? null : (
- <Banner
- onDismiss={() => {
- hideAlert();
- setShow(false);
- }}
- className={classNames('sw-w-full', className)}
- variant={variant}
- >
- {children}
- </Banner>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/ui/FilesCounter.tsx b/server/sonar-web/src/main/js/components/ui/FilesCounter.tsx
deleted file mode 100644
index 08d43dda6b2..00000000000
--- a/server/sonar-web/src/main/js/components/ui/FilesCounter.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { Note, themeColor } from '~design-system';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import { translate } from '../../helpers/l10n';
-import { isDefined } from '../../helpers/types';
-
-interface Props {
- className?: string;
- current?: number;
- total: number;
-}
-
-export default function FilesCounter({ className, current, total }: Props) {
- return (
- <Note className={classNames('sw-whitespace-nowrap', className)}>
- <Counter className="sw-typo-semibold">
- {isDefined(current) && formatMeasure(current, MetricType.Integer) + '/'}
- {formatMeasure(total, MetricType.Integer)}
- </Counter>{' '}
- {translate('component_measures.files')}
- </Note>
- );
-}
-
-FilesCounter.displayName = 'FilesCounter';
-
-const Counter = styled.strong`
- color: ${themeColor('pageContent')};
-`;
diff --git a/server/sonar-web/src/main/js/components/ui/MandatoryFieldsExplanation.tsx b/server/sonar-web/src/main/js/components/ui/MandatoryFieldsExplanation.tsx
deleted file mode 100644
index 197d11b84f0..00000000000
--- a/server/sonar-web/src/main/js/components/ui/MandatoryFieldsExplanation.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FormattedMessage } from 'react-intl';
-import { LightLabel, RequiredIcon } from '~design-system';
-import { translate } from '../../helpers/l10n';
-
-export interface MandatoryFieldsExplanationProps {
- className?: string;
-}
-
-export default function MandatoryFieldsExplanation({ className }: MandatoryFieldsExplanationProps) {
- return (
- <LightLabel aria-hidden className={className}>
- <FormattedMessage
- id="fields_marked_with_x_required"
- defaultMessage={translate('fields_marked_with_x_required')}
- values={{ star: <RequiredIcon className="sw-m-0" /> }}
- />
- </LightLabel>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/ui/Rating.css b/server/sonar-web/src/main/js/components/ui/Rating.css
deleted file mode 100644
index ebe095917c5..00000000000
--- a/server/sonar-web/src/main/js/components/ui/Rating.css
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-.rating {
- display: inline-flex;
- width: 24px;
- height: 24px;
- border-radius: 24px;
- box-sizing: border-box;
- font-size: 16px;
- font-weight: 400;
- align-items: center;
- justify-content: center;
-}
-
-.rating-muted {
- background-color: #b4b4b4 !important;
- color: #ffffff !important;
-}
-
-a > .rating-A,
-.rating-A {
- color: rgba(0, 0, 0, 0.75);
- background-color: #6cd46c;
-}
-
-a > .rating-B,
-.rating-B {
- color: rgba(0, 0, 0, 0.75);
- background-color: #c6e056;
-}
-
-a > .rating-C,
-.rating-C {
- color: rgba(0, 0, 0, 0.75);
- background-color: #f4d348;
-}
-
-a > .rating-D,
-.rating-D {
- color: rgba(0, 0, 0, 0.75);
- background-color: #f69d53;
-}
-
-a > .rating-E,
-.rating-E {
- color: rgba(0, 0, 0, 0.75);
- background-color: #f0878e;
-}
diff --git a/server/sonar-web/src/main/js/components/ui/Rating.tsx b/server/sonar-web/src/main/js/components/ui/Rating.tsx
deleted file mode 100644
index 03111cbe6c4..00000000000
--- a/server/sonar-web/src/main/js/components/ui/Rating.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import * as React from 'react';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import './Rating.css';
-
-interface Props extends React.AriaAttributes {
- className?: string;
- muted?: boolean;
- small?: boolean;
- value: string | number | undefined;
-}
-
-export default function Rating({ className, muted = false, value, ...ariaAttrs }: Props) {
- if (value === undefined) {
- return (
- <span
- className={classNames('no-rating', { 'rating-muted': muted }, className)}
- aria-label={translate('metric.no_rating')}
- {...ariaAttrs}
- >
- –
- </span>
- );
- }
-
- const formatted = formatMeasure(value, MetricType.Rating);
-
- return (
- <span
- aria-label={translateWithParameters('metric.has_rating_X', formatted)}
- className={classNames('rating', `rating-${formatted}`, { 'rating-muted': muted }, className)}
- {...ariaAttrs}
- >
- {formatted}
- </span>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/ui/__tests__/AdminPageHeader-test.tsx b/server/sonar-web/src/main/js/components/ui/__tests__/AdminPageHeader-test.tsx
deleted file mode 100644
index 85f551df6b9..00000000000
--- a/server/sonar-web/src/main/js/components/ui/__tests__/AdminPageHeader-test.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { AdminPageHeader } from '../AdminPageHeader';
-
-it('render correctly', () => {
- renderAdminPageHeader();
-
- expect(screen.getByRole('heading', { name: 'Page title' })).toBeInTheDocument();
- expect(screen.getByText('Page description')).toBeInTheDocument();
- expect(screen.getByText('Actions')).toBeInTheDocument();
-});
-
-function renderAdminPageHeader() {
- return renderComponent(
- <AdminPageHeader description="Page description" title="Page title">
- Actions
- </AdminPageHeader>,
- );
-}
diff --git a/server/sonar-web/src/main/js/components/ui/__tests__/Avatar-test.tsx b/server/sonar-web/src/main/js/components/ui/__tests__/Avatar-test.tsx
deleted file mode 100644
index 9177d69cfde..00000000000
--- a/server/sonar-web/src/main/js/components/ui/__tests__/Avatar-test.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { mockAppState } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import Avatar from '../Avatar';
-
-const gravatarServerUrl = 'http://example.com/{EMAIL_MD5}.jpg?s={SIZE}';
-
-it('renders correctly', () => {
- renderComponent(<Avatar name="John Doe" hash="johndoe" />, '', {
- appState: mockAppState({
- settings: {
- 'sonar.lf.enableGravatar': 'true',
- 'sonar.lf.gravatarServerUrl': gravatarServerUrl,
- },
- }),
- });
- const image = screen.getByAltText('John Doe');
- expect(image).toBeInTheDocument();
- expect(image).toHaveAttribute('src', 'http://example.com/johndoe.jpg?s=48');
-});
diff --git a/server/sonar-web/src/main/js/components/ui/icon/SheildCheckIcon.tsx b/server/sonar-web/src/main/js/components/ui/icon/SheildCheckIcon.tsx
deleted file mode 100644
index 1ce14fa0670..00000000000
--- a/server/sonar-web/src/main/js/components/ui/icon/SheildCheckIcon.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CustomIcon, IconProps } from '~design-system';
-
-/*
- * Temporary Icon. To remove when echoes gets the proper icon.
- */
-export function SheildCheckIcon({ fill, ...iconProps }: Readonly<IconProps>) {
- return (
- <CustomIcon viewBox="0 0 36 36" width={20} height={20} {...iconProps}>
- <g>
- <path
- d="M12.6427 29.0627C9.55385 28.2849 7.00385 26.5127 4.99274 23.746C2.98163 20.9793 1.97607 17.9071 1.97607 14.5293V6.396L12.6427 2.396L23.3094 6.396V15.1293C23.3094 15.3293 23.2983 15.5404 23.2761 15.7627H20.5761C20.5983 15.5404 20.615 15.3293 20.6261 15.1293C20.6372 14.9293 20.6427 14.7293 20.6427 14.5293V8.22933L12.6427 5.22933L4.64274 8.22933V14.5293C4.64274 17.2182 5.3983 19.6627 6.90941 21.8627C8.42052 24.0627 10.3316 25.5293 12.6427 26.2627V29.0627Z"
- fill={fill}
- />
- <path
- fillRule="evenodd"
- clipRule="evenodd"
- d="M9.10304 14.4089C8.97046 14.5067 8.83547 14.6015 8.69818 14.6931C8.08185 15.1045 7.41893 15.4528 6.71826 15.7292C7.41893 16.0055 8.08185 16.3538 8.69817 16.7652C8.83547 16.8568 8.97046 16.9516 9.10303 17.0494C9.9496 17.674 10.6979 18.4223 11.3225 19.2689C11.4203 19.4015 11.5151 19.5364 11.6067 19.6737C12.0181 20.2901 12.3664 20.953 12.6427 21.6536C12.9191 20.953 13.2674 20.2901 13.6788 19.6737C13.7704 19.5364 13.8652 19.4015 13.963 19.2689C14.5876 18.4223 15.3359 17.674 16.1824 17.0494C16.315 16.9516 16.45 16.8568 16.5873 16.7652C17.2036 16.3538 17.8665 16.0055 18.5672 15.7292C17.8665 15.4528 17.2036 15.1045 16.5873 14.6931C16.45 14.6015 16.315 14.5067 16.1824 14.4089C15.3359 13.7843 14.5876 13.036 13.963 12.1895C13.8652 12.0569 13.7704 11.9219 13.6788 11.7846C13.2674 11.1683 12.9191 10.5054 12.6427 9.80469C12.3664 10.5054 12.0181 11.1683 11.6067 11.7846C11.5151 11.9219 11.4203 12.0569 11.3225 12.1895C10.6979 13.036 9.9496 13.7843 9.10304 14.4089ZM11.0178 15.7292C11.6072 16.2208 12.1512 16.7647 12.6427 17.3541C13.1343 16.7647 13.6782 16.2208 14.2677 15.7292C13.6782 15.2376 13.1343 14.6937 12.6427 14.1042C12.1512 14.6937 11.6072 15.2376 11.0178 15.7292Z"
- fill={fill}
- />
- <path
- d="M19.9266 29.0846L14.5933 23.7513L16.4599 21.8846L19.9266 25.3513L28.7266 16.5513L30.5933 18.4179L19.9266 29.0846Z"
- fill={fill}
- />
- </g>
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/ui/icon/SheildCrossIcon.tsx b/server/sonar-web/src/main/js/components/ui/icon/SheildCrossIcon.tsx
deleted file mode 100644
index c33710de8f4..00000000000
--- a/server/sonar-web/src/main/js/components/ui/icon/SheildCrossIcon.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CustomIcon, IconProps } from '~design-system';
-
-/*
- * Temporary Icon. To remove when echoes gets the proper icon.
- */
-export function SheildCrossIcon({ fill, ...iconProps }: Readonly<IconProps>) {
- return (
- <CustomIcon viewBox="0 0 36 36" width={20} height={20} {...iconProps}>
- <g>
- <path
- d="M12.6427 29.0627C9.55385 28.2849 7.00385 26.5127 4.99274 23.746C2.98163 20.9793 1.97607 17.9071 1.97607 14.5293V6.396L12.6427 2.396L23.3094 6.396V15.1293C23.3094 15.3293 23.2983 15.5404 23.2761 15.7627H20.5761C20.5983 15.5404 20.615 15.3293 20.6261 15.1293C20.6372 14.9293 20.6427 14.7293 20.6427 14.5293V8.22933L12.6427 5.22933L4.64274 8.22933V14.5293C4.64274 17.2182 5.3983 19.6627 6.90941 21.8627C8.42052 24.0627 10.3316 25.5293 12.6427 26.2627V29.0627Z"
- fill={fill}
- />
- <path
- fillRule="evenodd"
- clipRule="evenodd"
- d="M9.10304 14.4089C8.97046 14.5067 8.83547 14.6015 8.69818 14.6931C8.08185 15.1045 7.41893 15.4528 6.71826 15.7292C7.41893 16.0055 8.08185 16.3538 8.69817 16.7652C8.83547 16.8568 8.97046 16.9516 9.10303 17.0494C9.9496 17.674 10.6979 18.4223 11.3225 19.2689C11.4203 19.4015 11.5151 19.5364 11.6067 19.6737C12.0181 20.2901 12.3664 20.953 12.6427 21.6536C12.9191 20.953 13.2674 20.2901 13.6788 19.6737C13.7704 19.5364 13.8652 19.4015 13.963 19.2689C14.5876 18.4223 15.3359 17.674 16.1824 17.0494C16.315 16.9516 16.45 16.8568 16.5873 16.7652C17.2036 16.3538 17.8665 16.0055 18.5672 15.7292C17.8665 15.4528 17.2036 15.1045 16.5873 14.6931C16.45 14.6015 16.315 14.5067 16.1824 14.4089C15.3359 13.7843 14.5876 13.036 13.963 12.1895C13.8652 12.0569 13.7704 11.9219 13.6788 11.7846C13.2674 11.1683 12.9191 10.5054 12.6427 9.80469C12.3664 10.5054 12.0181 11.1683 11.6067 11.7846C11.5151 11.9219 11.4203 12.0569 11.3225 12.1895C10.6979 13.036 9.9496 13.7843 9.10304 14.4089ZM11.0178 15.7292C11.6072 16.2208 12.1512 16.7647 12.6427 17.3541C13.1343 16.7647 13.6782 16.2208 14.2677 15.7292C13.6782 15.2376 13.1343 14.6937 12.6427 14.1042C12.1512 14.6937 11.6072 15.2376 11.0178 15.7292Z"
- fill={fill}
- />
- <path
- d="M25.7129 19.1533L27.3316 20.7721L17.619 30.4848L16.0002 28.866L25.7129 19.1533Z"
- fill={fill}
- />
- <path
- d="M27.3315 28.8663L25.7127 30.485L16 20.7724L17.6188 19.1536L27.3315 28.8663Z"
- fill={fill}
- />
- </g>
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/ui/icon/ShieldIcon.tsx b/server/sonar-web/src/main/js/components/ui/icon/ShieldIcon.tsx
deleted file mode 100644
index 1e574830efa..00000000000
--- a/server/sonar-web/src/main/js/components/ui/icon/ShieldIcon.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CustomIcon, IconProps } from '~design-system';
-
-/*
- * Temporary Icon. To remove when echoes gets the proper icon.
- */
-export function ShieldIcon({ fill, ...iconProps }: Readonly<IconProps>) {
- return (
- <CustomIcon viewBox="0 0 20 20" {...iconProps}>
- <g fill={fill}>
- <path
- fillRule="evenodd"
- clipRule="evenodd"
- d="M7.78736 9.00555C7.7045 9.06668 7.62013 9.12592 7.53432 9.1832C7.14912 9.44032 6.7348 9.658 6.29688 9.83071C6.7348 10.0034 7.14912 10.2211 7.53432 10.4782C7.62013 10.5355 7.7045 10.5947 7.78736 10.6559C8.31646 11.0462 8.78415 11.5139 9.17451 12.043C9.23564 12.1259 9.29488 12.2102 9.35216 12.2961C9.60928 12.6813 9.82696 13.0956 9.99967 13.5335C10.1724 13.0956 10.3901 12.6813 10.6472 12.2961C10.7045 12.2102 10.7637 12.1259 10.8248 12.043C11.2152 11.5139 11.6829 11.0462 12.212 10.6559C12.2949 10.5947 12.3792 10.5355 12.465 10.4782C12.8502 10.2211 13.2646 10.0034 13.7025 9.83071C13.2646 9.658 12.8502 9.44032 12.465 9.1832C12.3792 9.12592 12.2949 9.06668 12.212 9.00555C11.6829 8.61519 11.2152 8.14751 10.8248 7.6184C10.7637 7.53555 10.7045 7.45118 10.6472 7.36537C10.3901 6.98017 10.1724 6.56585 9.99967 6.12793C9.82696 6.56585 9.60928 6.98017 9.35216 7.36537C9.29488 7.45118 9.23564 7.53555 9.17451 7.61841C8.78415 8.14751 8.31646 8.61519 7.78736 9.00555ZM8.98407 9.83071C9.35249 10.1379 9.69243 10.4779 9.99968 10.8463C10.3069 10.4779 10.6469 10.1379 11.0153 9.83071C10.6469 9.52347 10.3069 9.18353 9.99967 8.81511C9.69243 9.18353 9.35249 9.52347 8.98407 9.83071Z"
- fill={fill}
- />
- <path
- d="M9.99973 18.1777C8.06916 17.6916 6.47539 16.5839 5.21844 14.8548C3.96148 13.1256 3.33301 11.2055 3.33301 9.09434V4.01099L9.99973 1.51099L16.6664 4.01099V9.09434C16.6664 11.2055 16.038 13.1256 14.781 14.8548C13.5241 16.5839 11.9303 17.6916 9.99973 18.1777ZM9.99973 16.4277C11.4442 15.9694 12.6386 15.0527 13.5831 13.6777C14.5275 12.3027 14.9998 10.7749 14.9998 9.09434V5.15683L9.99973 3.28182L4.99969 5.15683V9.09434C4.99969 10.7749 5.47191 12.3027 6.41636 13.6777C7.36082 15.0527 8.55527 15.9694 9.99973 16.4277Z"
- fill={fill}
- />
- </g>
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/ui/popups.css b/server/sonar-web/src/main/js/components/ui/popups.css
deleted file mode 100644
index 5bbb3496c5e..00000000000
--- a/server/sonar-web/src/main/js/components/ui/popups.css
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-.popup {
- position: absolute;
- z-index: 5000;
- margin-top: -16px;
- margin-left: 8px;
- padding: 8px;
- border: 1px solid var(--echoes-color-border-weak);
- border-radius: 3px;
- box-sizing: border-box;
- background-color: #ffffff;
- box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
- cursor: default;
-}
-
-.popup.no-padding {
- padding: 0;
-}
-
-/* #region .popup-arrow */
-.popup-arrow,
-.popup-arrow:after {
- position: absolute;
- display: block;
- width: 0;
- height: 0;
- border: 6px solid transparent;
-}
-
-.popup-arrow {
- top: 15px;
- left: -6px;
- border-left-width: 0;
- border-right-color: #e6e6e6;
-}
-
-.popup-arrow:after {
- content: ' ';
- left: 1px;
- bottom: -6px;
- border-left-width: 0;
- border-right-color: #ffffff;
-}
-/* #endregion */
-
-/* #region .popup.is-bottom */
-.popup.is-bottom {
- top: 100%;
- left: 0;
- margin: 0;
- margin-left: 50%;
- transform: translate(-50%, 6px);
-}
-
-.popup.is-bottom .popup-arrow {
- top: -6px;
- left: calc(50% - 6px);
- border-left-width: 6px;
- border-top-width: 0;
- border-right-color: transparent;
- border-bottom-color: #e6e6e6;
-}
-
-.popup.is-bottom .popup-arrow.is-left {
- left: 8px;
-}
-
-.popup.is-bottom .popup-arrow:after {
- left: -6px;
- bottom: -7px;
- border-left-width: 6px;
- border-top-width: 0;
- border-right-color: transparent;
- border-bottom-color: #ffffff;
-}
-/* #endregion */
-
-/* #region .popup.is-bottom-right */
-.popup.is-bottom-right {
- top: 100%;
- right: 0;
- margin: 0;
-
- /* TODO Update like .is-bottom-left, currently it's */
- transform: translateY(6px);
-}
-
-.popup.is-bottom-right .popup-arrow {
- top: -6px;
- left: auto;
- right: 8px;
- border-left-width: 6px;
- border-top-width: 0;
- border-right-color: transparent;
- border-bottom-color: #e6e6e6;
-}
-
-.popup.is-bottom-right .popup-arrow:after {
- left: -6px;
- bottom: -7px;
- border-left-width: 6px;
- border-top-width: 0;
- border-right-color: transparent;
- border-bottom-color: #ffffff;
-}
-/* #endregion */
-
-/* #region .popup.is-bottom-left */
-.popup.is-bottom-left {
- top: 100%;
- left: 0;
- margin: 0;
- transform: translate(-8px, 6px);
-}
-
-.popup.is-bottom-left .popup-arrow {
- top: -6px;
- right: auto;
- left: 8px;
- border-left-width: 6px;
- border-top-width: 0;
- border-right-color: transparent;
- border-bottom-color: #e6e6e6;
-}
-
-.popup.is-bottom-left .popup-arrow:after {
- left: -6px;
- bottom: -7px;
- border-left-width: 6px;
- border-top-width: 0;
- border-right-color: transparent;
- border-bottom-color: #ffffff;
-}
-/* #endregion */
-
-/* #region .popup.is-left-top */
-.popup.is-left-top {
- top: -4px;
- right: 100%;
- margin: 0;
- transform: translateX(-6px);
-}
-
-.popup.is-left-top .popup-arrow {
- right: -6px;
- left: auto;
- top: 8px;
- border-right-width: 0;
- border-left-width: 6px;
- border-left-color: #e6e6e6;
- border-right-color: transparent;
-}
-
-.popup.is-left-top .popup-arrow:after {
- top: -6px;
- left: -7px;
- border-right-width: 0;
- border-left-width: 6px;
- border-left-color: #ffffff;
- border-right-color: transparent;
-}
-/* #endregion */
-
-/* #region .popup.is-right-top */
-.popup.is-right-top {
- top: -4px;
- left: 100%;
- margin: 0;
- transform: translateX(6px);
-}
-
-.popup.is-right-top .popup-arrow {
- left: -6px;
- right: auto;
- top: 8px;
- border-left-width: 0;
- border-right-width: 6px;
- border-right-color: #e6e6e6;
- border-left-color: transparent;
-}
-
-.popup.is-right-top .popup-arrow:after {
- top: -6px;
- right: -7px;
- border-left-width: 0;
- border-right-width: 6px;
- border-right-color: #ffffff;
- border-left-color: transparent;
-}
-/* #endregion */
-
-/* #region .popup.is-right-bottom */
-.popup.is-right-bottom {
- bottom: 4px;
- left: 100%;
- margin: 0;
- transform: translateX(6px);
-}
-
-.popup.is-right-bottom .popup-arrow {
- left: -6px;
- right: auto;
- top: calc(100% - 15px);
- border-left-width: 0;
- border-right-width: 6px;
- border-right-color: #e6e6e6;
- border-left-color: transparent;
-}
-
-.popup.is-right-bottom .popup-arrow:after {
- top: -6px;
- right: -7px;
- border-left-width: 0;
- border-right-width: 6px;
- border-right-color: #ffffff;
- border-left-color: transparent;
-}
-/* #endregion */
-
-/* #region .popup.is-top-left */
-.popup.is-top-left {
- bottom: calc(100% + 8px);
- left: 0;
- margin: 0;
- transform: translateX(-8px);
-}
-
-.popup.is-top-left .popup-arrow {
- bottom: -6px;
- top: auto;
- left: 8px;
- border-color: #e6e6e6 transparent transparent;
- border-width: 6px 6px 0 6px;
-}
-
-.popup.is-top-left .popup-arrow:after {
- left: -6px;
- top: -7px;
- border-width: 6px 6px 0 6px;
- border-color: #fff transparent transparent;
-}
-/* #endregion */
-
-/* #region .popup & .menu or .multi-select */
-.popup:not(.no-padding) > .menu,
-.popup:not(.no-padding) > .multi-select {
- margin: calc(-1 * 8px);
-}
-/* #endregion */
-
-/* #region .popup-portal override css placement */
-.popup-portal .popup.is-bottom {
- top: unset;
- left: unset;
- transform: unset;
- margin: 0;
-}
-
-.popup-portal .popup.is-bottom-left,
-.popup-portal .popup.is-bottom-right,
-.popup-portal .popup.is-top-left,
-.popup-portal .popup.is-left-top,
-.popup-portal .popup.is-right-top,
-.popup-portal .popup.is-right-bottom {
- top: unset;
- right: unset;
- bottom: unset;
- left: unset;
-}
-/* #endregion */
diff --git a/server/sonar-web/src/main/js/components/ui/popups.tsx b/server/sonar-web/src/main/js/components/ui/popups.tsx
deleted file mode 100644
index f381c6854c0..00000000000
--- a/server/sonar-web/src/main/js/components/ui/popups.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable prefer-destructuring */
-
-import classNames from 'classnames';
-import * as React from 'react';
-import ClickEventBoundary from '../controls/ClickEventBoundary';
-import './popups.css';
-
-/**
- * Positioning rules:
- * - Bottom = below the block, horizontally centered
- * - BottomLeft = below the block, horizontally left-aligned
- * - BottomRight = below the block, horizontally right-aligned
- * - LeftTop = on the left-side of the block, vertically top-aligned
- * - RightTop = on the right-side of the block, vertically top-aligned
- * - RightBottom = on the right-side of the block, vetically bottom-aligned
- * - TopLeft = above the block, horizontally left-aligned
- */
-export enum PopupPlacement {
- Bottom = 'bottom',
- BottomLeft = 'bottom-left',
- BottomRight = 'bottom-right',
- LeftTop = 'left-top',
- RightTop = 'right-top',
- RightBottom = 'right-bottom',
- TopLeft = 'top-left',
-}
-
-interface PopupProps {
- arrowStyle?: React.CSSProperties;
- children?: React.ReactNode;
- className?: string;
- noArrow?: boolean;
- noPadding?: boolean;
- placement?: PopupPlacement;
- style?: React.CSSProperties;
- useEventBoundary?: boolean;
-}
-
-function PopupBase(props: PopupProps, ref: React.Ref<HTMLDivElement>) {
- const { useEventBoundary = true, noArrow = false, placement = PopupPlacement.Bottom } = props;
- const inner = (
- <div
- className={classNames(
- 'popup',
- `is-${placement}`,
- { 'no-padding': props.noPadding },
- props.className,
- )}
- ref={ref || React.createRef()}
- style={props.style}
- >
- {props.children}
- {!noArrow && <PopupArrow style={props.arrowStyle} />}
- </div>
- );
- if (useEventBoundary) {
- return <ClickEventBoundary>{inner}</ClickEventBoundary>;
- }
- return inner;
-}
-
-interface PopupArrowProps {
- style?: React.CSSProperties;
-}
-
-function PopupArrow(props: PopupArrowProps) {
- return <div className="popup-arrow" style={props.style} />;
-}
-
-const PopupWithRef = React.forwardRef(PopupBase);
-PopupWithRef.displayName = 'Popup';
-export const Popup = PopupWithRef;
diff --git a/server/sonar-web/src/main/js/components/upgrade/SystemUpgradeButton.tsx b/server/sonar-web/src/main/js/components/upgrade/SystemUpgradeButton.tsx
deleted file mode 100644
index f29ce936bf0..00000000000
--- a/server/sonar-web/src/main/js/components/upgrade/SystemUpgradeButton.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, Link } from '@sonarsource/echoes-react';
-import React from 'react';
-import { translate } from '../../helpers/l10n';
-import { SystemUpgrade } from '../../types/system';
-import { SystemUpgradeForm } from './SystemUpgradeForm';
-import { groupUpgrades, sortUpgrades, UpdateUseCase } from './utils';
-
-interface Props {
- latestLTA?: string;
- systemUpgrades: SystemUpgrade[];
- updateUseCase: UpdateUseCase;
-}
-
-export function SystemUpgradeButton(props: Readonly<Props>) {
- const { latestLTA, systemUpgrades, updateUseCase } = props;
-
- const [isSystemUpgradeFormOpen, setIsSystemUpgradeFormOpen] = React.useState(false);
-
- const openSystemUpgradeForm = React.useCallback(() => {
- setIsSystemUpgradeFormOpen(true);
- }, [setIsSystemUpgradeFormOpen]);
-
- const closeSystemUpgradeForm = React.useCallback(() => {
- setIsSystemUpgradeFormOpen(false);
- }, [setIsSystemUpgradeFormOpen]);
-
- if (systemUpgrades.length === 0) {
- return (
- <Link
- className="sw-ml-2"
- to="https://www.sonarsource.com/products/sonarqube/downloads/?referrer=sonarqube"
- shouldOpenInNewTab
- >
- {translate('learn_more')}
- </Link>
- );
- }
-
- return (
- <>
- <Button className="sw-ml-2" onClick={openSystemUpgradeForm}>
- {translate('learn_more')}
- </Button>
-
- {isSystemUpgradeFormOpen && (
- <SystemUpgradeForm
- onClose={closeSystemUpgradeForm}
- systemUpgrades={groupUpgrades(sortUpgrades(systemUpgrades))}
- latestLTA={latestLTA}
- updateUseCase={updateUseCase}
- />
- )}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/upgrade/SystemUpgradeForm.tsx b/server/sonar-web/src/main/js/components/upgrade/SystemUpgradeForm.tsx
deleted file mode 100644
index f6f9dafa673..00000000000
--- a/server/sonar-web/src/main/js/components/upgrade/SystemUpgradeForm.tsx
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, ButtonVariety, LinkStandalone, Modal } from '@sonarsource/echoes-react';
-import { filter, flatMap, isEmpty, negate } from 'lodash';
-import { FlagMessage } from '~design-system';
-import { useAppState } from '../../app/components/app-state/withAppStateContext';
-import { BANNER_VARIANT } from '../../app/components/update-notification/helpers';
-import { translate } from '../../helpers/l10n';
-import { EditionKey } from '../../types/editions';
-import { SystemUpgrade } from '../../types/system';
-import { SystemUpgradeItem } from './SystemUpgradeItem';
-import { SYSTEM_VERSION_REGEXP, UpdateUseCase } from './utils';
-
-interface Props {
- latestLTA?: string;
- onClose: () => void;
- systemUpgrades: SystemUpgrade[][];
- updateUseCase: UpdateUseCase;
-}
-
-export function SystemUpgradeForm(props: Readonly<Props>) {
- const appState = useAppState();
-
- const { latestLTA, onClose, updateUseCase, systemUpgrades } = props;
-
- const isCommunityBuildRunning = appState.edition === EditionKey.community;
-
- let systemUpgradesWithPatch: SystemUpgrade[][] = [];
-
- const alertVariant =
- updateUseCase !== UpdateUseCase.NewVersion ? BANNER_VARIANT[updateUseCase] : undefined;
-
- const parsedVersion = SYSTEM_VERSION_REGEXP.exec(appState.version);
-
- let patches: SystemUpgrade[] = [];
-
- if (updateUseCase === UpdateUseCase.NewPatch && parsedVersion !== null) {
- const [, major, minor] = parsedVersion;
- const majoMinorVersion = `${major}.${minor}`;
-
- patches = flatMap(systemUpgrades, (upgrades) =>
- filter(upgrades, (upgrade) => upgrade.version.startsWith(majoMinorVersion)),
- );
-
- systemUpgradesWithPatch = systemUpgrades
- .map((upgrades) =>
- upgrades.filter((upgrade) => !upgrade.version.startsWith(majoMinorVersion)),
- )
- .filter(negate(isEmpty));
-
- systemUpgradesWithPatch.push(patches);
- } else {
- let untilLTA = false;
-
- for (const upgrades of systemUpgrades) {
- if (untilLTA === false) {
- systemUpgradesWithPatch.push(upgrades);
-
- untilLTA = upgrades.some(
- (upgrade) => latestLTA !== undefined && upgrade.version.startsWith(latestLTA),
- );
- }
- }
- }
-
- return (
- <Modal
- content={
- <div className="sw-mt-4">
- {alertVariant && (
- <FlagMessage variant={alertVariant} className={`it__upgrade-alert-${updateUseCase}`}>
- {translate('admin_notification.update', updateUseCase)}
- </FlagMessage>
- )}
-
- {systemUpgradesWithPatch.map((upgrades) => (
- <SystemUpgradeItem
- edition={appState.edition}
- key={upgrades[upgrades.length - 1].version}
- systemUpgrades={upgrades}
- isPatch={upgrades === patches}
- isLTAVersion={upgrades.some(
- (upgrade) => latestLTA !== undefined && upgrade.version.startsWith(latestLTA),
- )}
- />
- ))}
- </div>
- }
- {...(isCommunityBuildRunning && {
- description: translate(
- 'admin_notification.update.new_sqs_version_when_running_sqcb.upgrade',
- ),
- })}
- isOpen
- onOpenChange={(isOpen) => {
- if (!isOpen) {
- onClose();
- }
- }}
- primaryButton={
- !isCommunityBuildRunning && (
- <LinkStandalone
- className="sw-mr-8"
- to="https://www.sonarsource.com/products/sonarqube/downloads/?referrer=sonarqube"
- >
- {translate('system.see_sonarqube_downloads')}
- </LinkStandalone>
- )
- }
- secondaryButton={
- <Button onClick={onClose} variety={ButtonVariety.Default}>
- {translate('cancel')}
- </Button>
- }
- title={translate(
- isCommunityBuildRunning
- ? 'admin_notification.update.new_sqs_version_when_running_sqcb.modal'
- : 'system.system_upgrade',
- )}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/components/upgrade/SystemUpgradeIntermediate.tsx b/server/sonar-web/src/main/js/components/upgrade/SystemUpgradeIntermediate.tsx
deleted file mode 100644
index 448506a56d7..00000000000
--- a/server/sonar-web/src/main/js/components/upgrade/SystemUpgradeIntermediate.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { Accordion, BasicSeparator, Link, Note } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { SystemUpgrade } from '../../types/system';
-import DateFormatter from '../intl/DateFormatter';
-
-interface Props {
- className?: string;
- upgrades: SystemUpgrade[];
-}
-
-interface State {
- showMore: boolean;
-}
-
-export default class SystemUpgradeIntermediate extends React.PureComponent<Props, State> {
- state: State = { showMore: false };
-
- toggleIntermediatVersions = () => {
- this.setState((state) => ({ showMore: !state.showMore }));
- };
-
- render() {
- const { showMore } = this.state;
- const { upgrades } = this.props;
- if (upgrades.length <= 0) {
- return null;
- }
-
- return (
- <div className={this.props.className}>
- <Accordion
- header={
- showMore
- ? translate('system.hide_intermediate_versions')
- : translate('system.show_intermediate_versions')
- }
- open={showMore}
- onClick={this.toggleIntermediatVersions}
- >
- {upgrades.map((upgrade, index) => (
- <Note className="sw-block sw-mb-4" key={upgrade.version}>
- {upgrade.releaseDate && (
- <DateFormatter date={upgrade.releaseDate} long>
- {(formattedDate) => (
- <p>
- <b className="sw-mr-1">SonarQube {upgrade.version}</b>
- {formattedDate}
- {upgrade.changeLogUrl && (
- <Link className="sw-ml-2" to={upgrade.changeLogUrl}>
- {translate('system.release_notes')}
- </Link>
- )}
- </p>
- )}
- </DateFormatter>
- )}
- {upgrade.description && <p className="sw-mt-2">{upgrade.description}</p>}
-
- {index !== upgrades.length - 1 && <BasicSeparator />}
- </Note>
- ))}
- </Accordion>
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/upgrade/SystemUpgradeItem.tsx b/server/sonar-web/src/main/js/components/upgrade/SystemUpgradeItem.tsx
deleted file mode 100644
index 566a8177b6c..00000000000
--- a/server/sonar-web/src/main/js/components/upgrade/SystemUpgradeItem.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Button, ButtonVariety, LinkStandalone } from '@sonarsource/echoes-react';
-import { FormattedMessage } from 'react-intl';
-import { DownloadButton, SubHeading } from '~design-system';
-import { useAppState } from '../../app/components/app-state/withAppStateContext';
-import { DocLink } from '../../helpers/doc-links';
-import {
- getEdition,
- getEditionDownloadFilename,
- getEditionDownloadUrl,
-} from '../../helpers/editions';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { EditionKey } from '../../types/editions';
-import { ProductName, SystemUpgrade } from '../../types/system';
-import DocumentationLink from '../common/DocumentationLink';
-import DateFormatter from '../intl/DateFormatter';
-import SystemUpgradeIntermediate from './SystemUpgradeIntermediate';
-
-export interface SystemUpgradeItemProps {
- edition: EditionKey | undefined;
- isLTAVersion: boolean;
- isPatch: boolean;
- systemUpgrades: SystemUpgrade[];
-}
-
-export function SystemUpgradeItem(props: Readonly<SystemUpgradeItemProps>) {
- const appState = useAppState();
-
- const { edition, isPatch, isLTAVersion, systemUpgrades } = props;
-
- const isCommunityBuildRunning = appState.edition === EditionKey.community;
-
- const lastUpgrade = systemUpgrades[0];
-
- const downloadUrl =
- getEditionDownloadUrl(getEdition(edition ?? EditionKey.community), lastUpgrade) ?? '';
-
- let header = translate('system.latest_version');
-
- if (isLTAVersion) {
- header = translate('system.lta_version');
- } else if (isPatch) {
- header = translate('system.latest_patch');
- }
-
- return (
- <div className="system-upgrade-version it__upgrade-list-item">
- <SubHeading as="h3">
- <strong>{header}</strong>
-
- {!isPatch && (
- <LinkStandalone
- className="sw-ml-2"
- to="https://www.sonarsource.com/products/sonarqube/whats-new/?referrer=sonarqube"
- >
- {translate('system.see_whats_new')}
- </LinkStandalone>
- )}
- </SubHeading>
-
- <p>
- <FormattedMessage
- id="system.version_is_availble"
- values={{
- version: (
- <b>
- {`${ProductName.SonarQubeServer} ${
- isCommunityBuildRunning
- ? lastUpgrade.version.split('.').join(' Release ')
- : lastUpgrade.version
- }`}
- </b>
- ),
- }}
- />
- </p>
-
- <p className="sw-mt-2">{lastUpgrade.description}</p>
-
- <div className="sw-mt-4">
- {lastUpgrade.releaseDate !== undefined && (
- <DateFormatter date={lastUpgrade.releaseDate} long>
- {(formattedDate) => (
- <span>{translateWithParameters('system.released_x', formattedDate)}</span>
- )}
- </DateFormatter>
- )}
-
- {lastUpgrade.changeLogUrl !== undefined && (
- <LinkStandalone className="sw-ml-2" to={lastUpgrade.changeLogUrl}>
- {translate('system.release_notes')}
- </LinkStandalone>
- )}
- </div>
-
- <SystemUpgradeIntermediate className="sw-mt-2" upgrades={systemUpgrades.slice(1)} />
-
- <div className="sw-mt-4">
- {isCommunityBuildRunning ? (
- <Button
- // WARNING! A button acting as a link is bad a11y. We should replace this with a
- // Call To Action (CTA) component from Echoes once it becomes available.
- onClick={() => {
- window.location.href = 'https://www.sonarsource.com/plans-and-pricing/sonarqube/';
- }}
- //
- variety={ButtonVariety.Primary}
- >
- {translate('learn_more')}
- </Button>
- ) : (
- <>
- <DownloadButton download={getEditionDownloadFilename(downloadUrl)} href={downloadUrl}>
- {translateWithParameters('system.download_x', lastUpgrade.version)}
- </DownloadButton>
-
- <DocumentationLink className="sw-ml-4" to={DocLink.ServerUpgradeRoadmap}>
- {translate('system.how_to_upgrade')}
- </DocumentationLink>
- </>
- )}
- </div>
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/upgrade/__tests__/SystemUpgrade-test.tsx b/server/sonar-web/src/main/js/components/upgrade/__tests__/SystemUpgrade-test.tsx
deleted file mode 100644
index cd8e8d52ada..00000000000
--- a/server/sonar-web/src/main/js/components/upgrade/__tests__/SystemUpgrade-test.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import React from 'react';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { mockAppState } from '../../../helpers/testMocks';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { EditionKey } from '../../../types/editions';
-import { SystemUpgradeButton } from '../SystemUpgradeButton';
-import { UpdateUseCase } from '../utils';
-
-const ui = {
- learnMoreButton: byRole('button', { name: 'learn_more' }),
-
- header: byRole('heading', { name: 'system.system_upgrade' }),
- downloadLink: byRole('link', { name: /system.see_sonarqube_downloads/ }),
-
- ltaVersionHeader: byRole('heading', { name: /system.lta_version/ }),
-
- newPatchWarning: byText(/admin_notification.update/),
-};
-
-it('should render properly', async () => {
- const user = userEvent.setup();
-
- renderSystemUpgradeButton();
-
- await user.click(ui.learnMoreButton.get());
-
- expect(ui.header.get()).toBeInTheDocument();
- expect(ui.ltaVersionHeader.get()).toBeInTheDocument();
- expect(ui.downloadLink.get()).toBeInTheDocument();
-});
-
-it('should render properly for new patch', async () => {
- const user = userEvent.setup();
-
- renderSystemUpgradeButton(
- {
- updateUseCase: UpdateUseCase.NewPatch,
- latestLTA: '9.9',
- systemUpgrades: [{ downloadUrl: '', version: '9.9.1' }],
- },
- '9.9',
- );
-
- await user.click(ui.learnMoreButton.get());
-
- expect(ui.header.get()).toBeInTheDocument();
- expect(ui.newPatchWarning.get()).toBeInTheDocument();
- expect(ui.ltaVersionHeader.get()).toBeInTheDocument();
- expect(ui.downloadLink.get()).toBeInTheDocument();
-});
-
-function renderSystemUpgradeButton(
- props: Partial<React.ComponentPropsWithoutRef<typeof SystemUpgradeButton>> = {},
- version = '9.7',
-) {
- renderComponent(
- <SystemUpgradeButton
- updateUseCase={UpdateUseCase.NewVersion}
- latestLTA="9.9"
- systemUpgrades={[
- { downloadUrl: 'eight', version: '9.8' },
- { downloadUrl: 'lts', version: '9.9' },
- { downloadUrl: 'patch', version: '9.9.1' },
- ]}
- {...props}
- />,
- '',
- { appState: mockAppState({ edition: EditionKey.developer, version }) },
- );
-}
diff --git a/server/sonar-web/src/main/js/components/upgrade/__tests__/utils-test.ts b/server/sonar-web/src/main/js/components/upgrade/__tests__/utils-test.ts
deleted file mode 100644
index dacc523ab36..00000000000
--- a/server/sonar-web/src/main/js/components/upgrade/__tests__/utils-test.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { SystemUpgrade } from '../../../types/system';
-import * as u from '../utils';
-
-describe('sortUpgrades', () => {
- it('should sort correctly versions', () => {
- expect(
- u.sortUpgrades([
- { version: '5.4.2' },
- { version: '5.10' },
- { version: '5.1' },
- { version: '5.4' },
- ] as SystemUpgrade[]),
- ).toEqual([{ version: '5.10' }, { version: '5.4.2' }, { version: '5.4' }, { version: '5.1' }]);
- expect(
- u.sortUpgrades([
- { version: '5.10' },
- { version: '5.1.2' },
- { version: '6.0' },
- { version: '6.9' },
- ] as SystemUpgrade[]),
- ).toEqual([{ version: '6.9' }, { version: '6.0' }, { version: '5.10' }, { version: '5.1.2' }]);
- });
-});
-
-describe('groupUpgrades', () => {
- it('should group correctly', () => {
- expect(
- u.groupUpgrades([
- { version: '5.10' },
- { version: '5.4.2' },
- { version: '5.4' },
- { version: '5.1' },
- ] as SystemUpgrade[]),
- ).toEqual([
- [{ version: '5.10' }, { version: '5.4.2' }, { version: '5.4' }, { version: '5.1' }],
- ]);
- expect(
- u.groupUpgrades([
- { version: '6.9' },
- { version: '6.7' },
- { version: '6.0' },
- { version: '5.10' },
- { version: '5.4.2' },
- ] as SystemUpgrade[]),
- ).toEqual([
- [{ version: '6.9' }, { version: '6.7' }, { version: '6.0' }],
- [{ version: '5.10' }, { version: '5.4.2' }],
- ]);
- });
-});
diff --git a/server/sonar-web/src/main/js/components/upgrade/utils.ts b/server/sonar-web/src/main/js/components/upgrade/utils.ts
deleted file mode 100644
index 42a0df22bc2..00000000000
--- a/server/sonar-web/src/main/js/components/upgrade/utils.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { groupBy, sortBy } from 'lodash';
-import { SystemUpgrade } from '../../types/system';
-
-export enum UpdateUseCase {
- NewVersion = 'new_version',
- CurrentVersionInactive = 'current_version_inactive',
- NewPatch = 'new_patch',
-}
-
-export const SYSTEM_VERSION_REGEXP = /^(\d+)\.(\d+)(\.(\d+))?/;
-
-export function sortUpgrades(upgrades: SystemUpgrade[]): SystemUpgrade[] {
- return sortBy(upgrades, [
- (upgrade: SystemUpgrade) => -Number(upgrade.version.split('.')[0]),
- (upgrade: SystemUpgrade) => -Number(upgrade.version.split('.')[1] || 0),
- (upgrade: SystemUpgrade) => -Number(upgrade.version.split('.')[2] || 0),
- ]);
-}
-
-export function groupUpgrades(upgrades: SystemUpgrade[]): SystemUpgrade[][] {
- const groupedVersions = groupBy(upgrades, (upgrade) => upgrade.version.split('.')[0]);
- const sortedMajor = sortBy(Object.keys(groupedVersions), (key) => -Number(key));
- return sortedMajor.map((key) => groupedVersions[key]);
-}
diff --git a/server/sonar-web/src/main/js/components/workspace/Workspace.tsx b/server/sonar-web/src/main/js/components/workspace/Workspace.tsx
deleted file mode 100644
index b91ce7f4239..00000000000
--- a/server/sonar-web/src/main/js/components/workspace/Workspace.tsx
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { omit, uniqBy } from 'lodash';
-import * as React from 'react';
-import { getRulesApp } from '../../api/rules';
-import { get, save } from '../../helpers/storage';
-import { Dict } from '../../types/types';
-import WorkspaceComponentViewer from './WorkspaceComponentViewer';
-import WorkspaceNav from './WorkspaceNav';
-import WorkspacePortal from './WorkspacePortal';
-import { ComponentDescriptor, WorkspaceContext } from './context';
-import './styles.css';
-
-const WORKSPACE = 'sonarqube-workspace';
-interface State {
- components: ComponentDescriptor[];
- externalRulesRepoNames: Dict<string>;
- height: number;
- maximized?: boolean;
- open: { component?: string };
-}
-
-export const MIN_HEIGHT = 0.05;
-export const MAX_HEIGHT = 0.85;
-export const INITIAL_HEIGHT = 300;
-
-export const TYPE_KEY = '__type__';
-export enum WorkspaceTypes {
- Component = 'component',
-}
-
-export default class Workspace extends React.PureComponent<React.PropsWithChildren, State> {
- mounted = false;
-
- constructor(props: {}) {
- super(props);
- this.state = {
- externalRulesRepoNames: {},
- height: INITIAL_HEIGHT,
- open: {},
- ...this.loadWorkspace(),
- };
- }
-
- componentDidMount() {
- this.mounted = true;
- this.fetchRuleNames();
- }
-
- componentDidUpdate(_: {}, prevState: State) {
- if (prevState.components !== this.state.components) {
- this.saveWorkspace();
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchRuleNames = async () => {
- const { repositories } = await getRulesApp();
- const externalRulesRepoNames: Dict<string> = {};
- repositories
- .filter(({ key }) => key.startsWith('external_'))
- .forEach(({ key, name }) => {
- externalRulesRepoNames[key.replace('external_', '')] = name;
- });
- this.setState({ externalRulesRepoNames });
- };
-
- loadWorkspace = () => {
- try {
- const data: any[] = JSON.parse(get(WORKSPACE) || '');
- const components: ComponentDescriptor[] = data.filter(
- (x) => x[TYPE_KEY] === WorkspaceTypes.Component,
- );
- return { components };
- } catch {
- // Fail silently.
- return { components: [] };
- }
- };
-
- saveWorkspace = () => {
- const data = [
- // Do not save line number, next time the file is open, it should be open
- // on the first line.
- ...this.state.components.map((x) =>
- omit({ ...x, [TYPE_KEY]: WorkspaceTypes.Component }, 'line'),
- ),
- ];
- save(WORKSPACE, JSON.stringify(data));
- };
-
- handleOpenComponent = (component: ComponentDescriptor) => {
- this.setState((state: State) => ({
- components: uniqBy([...state.components, component], (c) => c.key),
- open: { component: component.key },
- }));
- };
-
- handleComponentReopen = (componentKey: string) => {
- this.setState({ open: { component: componentKey } });
- };
-
- handleComponentClose = (componentKey: string) => {
- this.setState((state: State) => ({
- components: state.components.filter((x) => x.key !== componentKey),
- open: {
- ...state.open,
- component: state.open.component === componentKey ? undefined : state.open.component,
- },
- }));
- };
-
- handleComponentLoad = (details: { key: string; name: string; qualifier: string }) => {
- if (this.mounted) {
- const { key, name, qualifier } = details;
- this.setState((state: State) => ({
- components: state.components.map((component) =>
- component.key === key ? { ...component, name, qualifier } : component,
- ),
- }));
- }
- };
-
- handleCollapse = () => {
- this.setState({ open: {} });
- };
-
- handleMaximize = () => {
- this.setState({ maximized: true });
- };
-
- handleMinimize = () => {
- this.setState({ maximized: false });
- };
-
- handleResize = (deltaY: number) => {
- const minHeight = window.innerHeight * MIN_HEIGHT;
- const maxHeight = window.innerHeight * MAX_HEIGHT;
- this.setState((state: State) => ({
- height: Math.min(maxHeight, Math.max(minHeight, state.height - deltaY)),
- }));
- };
-
- render() {
- const { components, externalRulesRepoNames, height, maximized, open } = this.state;
-
- const openComponent = open.component && components.find((x) => x.key === open.component);
-
- const actualHeight = maximized ? window.innerHeight * MAX_HEIGHT : height;
-
- return (
- <WorkspaceContext.Provider
- value={{
- externalRulesRepoNames,
- openComponent: this.handleOpenComponent,
- }}
- >
- {this.props.children}
- <WorkspacePortal>
- {components.length > 0 && (
- <WorkspaceNav
- components={components}
- onComponentClose={this.handleComponentClose}
- onComponentOpen={this.handleComponentReopen}
- open={open}
- />
- )}
- {openComponent && (
- <WorkspaceComponentViewer
- component={openComponent}
- height={actualHeight}
- maximized={maximized}
- onClose={this.handleComponentClose}
- onCollapse={this.handleCollapse}
- onLoad={this.handleComponentLoad}
- onMaximize={this.handleMaximize}
- onMinimize={this.handleMinimize}
- onResize={this.handleResize}
- />
- )}
- </WorkspacePortal>
- </WorkspaceContext.Provider>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/workspace/WorkspaceComponentTitle.tsx b/server/sonar-web/src/main/js/components/workspace/WorkspaceComponentTitle.tsx
deleted file mode 100644
index af605d075b0..00000000000
--- a/server/sonar-web/src/main/js/components/workspace/WorkspaceComponentTitle.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { QualifierIcon } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { collapsePath } from '../../helpers/path';
-import { isDefined } from '../../helpers/types';
-import { ComponentDescriptor } from './context';
-
-interface Props {
- component: ComponentDescriptor;
- limited?: boolean;
-}
-
-export default function WorkspaceComponentTitle({ component, limited }: Props) {
- const { name = '—' } = component;
- return (
- <>
- {isDefined(component.qualifier) && (
- <QualifierIcon
- aria-label={translate('qualifier', component.qualifier)}
- className="sw-mr-1"
- qualifier={component.qualifier}
- />
- )}
- {limited ? collapsePath(name, 15) : name}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/workspace/WorkspaceComponentViewer.tsx b/server/sonar-web/src/main/js/components/workspace/WorkspaceComponentViewer.tsx
deleted file mode 100644
index df2172d1348..00000000000
--- a/server/sonar-web/src/main/js/components/workspace/WorkspaceComponentViewer.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { SourceViewerFile } from '../../types/types';
-import SourceViewer from '../SourceViewer/SourceViewer';
-import WorkspaceComponentTitle from './WorkspaceComponentTitle';
-import WorkspaceHeader, { Props as WorkspaceHeaderProps } from './WorkspaceHeader';
-import { ComponentDescriptor } from './context';
-
-export interface Props extends Omit<WorkspaceHeaderProps, 'children' | 'onClose'> {
- component: ComponentDescriptor;
- height: number;
- onClose: (componentKey: string) => void;
- onLoad: (details: { key: string; name: string; qualifier: string }) => void;
-}
-
-export default class WorkspaceComponentViewer extends React.PureComponent<Props> {
- container?: HTMLElement | null;
-
- componentDidMount() {
- if (document.documentElement) {
- document.documentElement.classList.add('with-workspace');
- }
- }
-
- componentWillUnmount() {
- if (document.documentElement) {
- document.documentElement.classList.remove('with-workspace');
- }
- }
-
- handleClose = () => {
- this.props.onClose(this.props.component.key);
- };
-
- handleLoaded = (component: SourceViewerFile) => {
- this.props.onLoad({
- key: this.props.component.key,
- name: component.path,
- qualifier: component.q,
- });
-
- if (this.container && this.props.component.line) {
- const row = this.container.querySelector(
- `.it__source-line[data-line-number="${this.props.component.line}"]`,
- );
- if (row) {
- row.scrollIntoView({ block: 'center' });
- }
- }
- };
-
- render() {
- const { component } = this.props;
-
- return (
- <div className="workspace-viewer">
- <WorkspaceHeader
- maximized={this.props.maximized}
- onClose={this.handleClose}
- onCollapse={this.props.onCollapse}
- onMaximize={this.props.onMaximize}
- onMinimize={this.props.onMinimize}
- onResize={this.props.onResize}
- >
- <WorkspaceComponentTitle component={component} />
- </WorkspaceHeader>
-
- <div
- className="workspace-viewer-container"
- role="complementary"
- ref={(node) => (this.container = node)}
- style={{ height: this.props.height }}
- >
- <SourceViewer
- aroundLine={component.line}
- branchLike={component.branchLike}
- component={component.key}
- hidePinOption
- highlightedLine={component.line}
- onLoaded={this.handleLoaded}
- />
- </div>
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/workspace/WorkspaceHeader.tsx b/server/sonar-web/src/main/js/components/workspace/WorkspaceHeader.tsx
deleted file mode 100644
index 3cc7b6f2bcc..00000000000
--- a/server/sonar-web/src/main/js/components/workspace/WorkspaceHeader.tsx
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import * as React from 'react';
-import { DraggableCore, DraggableData } from 'react-draggable';
-import {
- CloseIcon,
- CollapseIcon,
- ExpandIcon,
- IconProps,
- InteractiveIcon,
- MinimizeIcon,
- themeColor,
-} from '~design-system';
-import { translate } from '../../helpers/l10n';
-import Tooltip from '../controls/Tooltip';
-
-export interface Props {
- children: React.ReactNode;
- maximized?: boolean;
- onClose: () => void;
- onCollapse: () => void;
- onMaximize: () => void;
- onMinimize: () => void;
- onResize: (deltaY: number) => void;
-}
-
-export default class WorkspaceHeader extends React.PureComponent<Props> {
- handleDrag = (_event: MouseEvent, data: DraggableData) => {
- this.props.onResize(data.deltaY);
- };
-
- render() {
- return (
- <StyledWorkSpaceHeader>
- <StyledWorkspaceName className="sw-typo-default sw-inline-flex sw-items-center">
- {this.props.children}
- </StyledWorkspaceName>
-
- <DraggableCore offsetParent={document.body} onDrag={this.handleDrag}>
- <StyledWorkspaceResizer />
- </DraggableCore>
-
- <div className="it__workspace-viewer-actions sw-flex sw-gap-1">
- <WorkspaceHeaderButton
- icon={MinimizeIcon}
- onClick={this.props.onCollapse}
- tooltipContent="workspace.minimize"
- />
-
- {this.props.maximized ? (
- <WorkspaceHeaderButton
- icon={CollapseIcon}
- onClick={this.props.onMinimize}
- tooltipContent="workspace.normal_size"
- />
- ) : (
- <WorkspaceHeaderButton
- icon={ExpandIcon}
- onClick={this.props.onMaximize}
- tooltipContent="workspace.full_window"
- />
- )}
-
- <WorkspaceHeaderButton
- icon={CloseIcon}
- onClick={this.props.onClose}
- tooltipContent="workspace.close"
- />
- </div>
- </StyledWorkSpaceHeader>
- );
- }
-}
-
-const StyledWorkSpaceHeader = styled.header`
- display: flex;
- align-items: center;
- justify-content: space-between;
- box-sizing: border-box;
- height: 1.875rem;
- padding: 3px 10px;
- font-weight: 300;
- background-color: ${themeColor('workSpaceNavItemBackground')};
- color: ${themeColor('workSpaceNavItem')};
-`;
-
-const StyledWorkspaceName = styled.h6`
- color: ${themeColor('workSpaceNavItem')};
-`;
-
-const StyledWorkspaceResizer = styled.div`
- position: absolute;
- top: 3px;
- left: 50%;
- width: 30px;
- height: 5px;
- margin-left: -15px;
- background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzBweCIgaGVpZ2h0PSI1cHgiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgc3R5bGU9ImZpbGwtcnVsZTpldmVub2RkO2NsaXAtcnVsZTpldmVub2RkO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxLjQxNDIxOyI+PGc+PGcgaWQ9IkxheWVyMSI+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSwwLDApIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsNCwwKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDgsMCkiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSwxMiwwKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDE2LDApIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMjAsMCkiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSwyNCwwKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDI4LDApIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMCwzKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDQsMykiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSw4LDMpIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMTIsMykiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSwxNiwzKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDIwLDMpIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMjQsMykiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSwyOCwzKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDAsMCkiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSw0LDApIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsOCwwKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDEyLDApIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMTYsMCkiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSwyMCwwKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDI0LDApIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMjgsMCkiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PC9nPjwvZz48L3N2Zz4=);
- cursor: ns-resize;
-`;
-
-interface WorkspaceHeaderButtonProps {
- icon: React.ComponentType<React.PropsWithChildren<IconProps>>;
- onClick: () => void;
- tooltipContent: string;
-}
-
-function WorkspaceHeaderButton({
- icon,
- onClick,
- tooltipContent,
-}: Readonly<WorkspaceHeaderButtonProps>) {
- return (
- <Tooltip content={translate(tooltipContent)}>
- <InteractiveIcon
- aria-label={translate(tooltipContent)}
- Icon={icon}
- currentColor
- onClick={onClick}
- size="small"
- />
- </Tooltip>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/workspace/WorkspaceNav.tsx b/server/sonar-web/src/main/js/components/workspace/WorkspaceNav.tsx
deleted file mode 100644
index 6192662e3c1..00000000000
--- a/server/sonar-web/src/main/js/components/workspace/WorkspaceNav.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import WorkspaceNavComponent from './WorkspaceNavComponent';
-import { ComponentDescriptor } from './context';
-
-export interface Props {
- components: ComponentDescriptor[];
- onComponentClose: (componentKey: string) => void;
- onComponentOpen: (componentKey: string) => void;
- open: { component?: string; rule?: string };
-}
-
-export default function WorkspaceNav(props: Props) {
- // do not show a tab for the currently open component/rule
- const components = props.components.filter((x) => x.key !== props.open.component);
-
- return (
- <WorkspaceNavStyled>
- <ul className="sw-float-right">
- {components.map((component) => (
- <WorkspaceNavComponent
- component={component}
- key={`component-${component.key}`}
- onClose={props.onComponentClose}
- onOpen={props.onComponentOpen}
- />
- ))}
- </ul>
- </WorkspaceNavStyled>
- );
-}
-
-const WorkspaceNavStyled = styled.nav`
- position: fixed;
- z-index: 451;
- bottom: 0;
- right: 0;
- height: 1.75rem;
-`;
diff --git a/server/sonar-web/src/main/js/components/workspace/WorkspaceNavComponent.tsx b/server/sonar-web/src/main/js/components/workspace/WorkspaceNavComponent.tsx
deleted file mode 100644
index f62cf96ffa3..00000000000
--- a/server/sonar-web/src/main/js/components/workspace/WorkspaceNavComponent.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import WorkspaceComponentTitle from './WorkspaceComponentTitle';
-import WorkspaceNavItem from './WorkspaceNavItem';
-import { ComponentDescriptor } from './context';
-
-export interface Props {
- component: ComponentDescriptor;
- onClose: (componentKey: string) => void;
- onOpen: (componentKey: string) => void;
-}
-
-export default class WorkspaceNavComponent extends React.PureComponent<Props> {
- handleClose = () => {
- this.props.onClose(this.props.component.key);
- };
-
- handleOpen = () => {
- this.props.onOpen(this.props.component.key);
- };
-
- render() {
- return (
- <WorkspaceNavItem onClose={this.handleClose} onOpen={this.handleOpen}>
- <WorkspaceComponentTitle component={this.props.component} limited />
- </WorkspaceNavItem>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/workspace/WorkspaceNavItem.tsx b/server/sonar-web/src/main/js/components/workspace/WorkspaceNavItem.tsx
deleted file mode 100644
index 5eeb5d5a419..00000000000
--- a/server/sonar-web/src/main/js/components/workspace/WorkspaceNavItem.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import * as React from 'react';
-import { CloseIcon, InteractiveIcon, themeColor } from '~design-system';
-import { translate } from '../../helpers/l10n';
-
-export interface Props {
- children: React.ReactNode;
- onClose: () => void;
- onOpen: () => void;
-}
-
-export default class WorkspaceNavItem extends React.PureComponent<Props> {
- handleNameClick = (event: React.MouseEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
- this.props.onOpen();
- };
-
- render() {
- return (
- <StyledWorkspaceNavItem className="sw-mr-2">
- <StyledWorkSpaceNavItemButton
- className="sw-typo-default sw-pr-8 sw-pl-2"
- onClick={this.handleNameClick}
- >
- {this.props.children}
- </StyledWorkSpaceNavItemButton>
- <InteractiveIcon
- aria-label={translate('workspace.close')}
- className="js-close sw-absolute sw-top-0 sw-right-0 sw-m-1/2"
- currentColor
- Icon={CloseIcon}
- onClick={this.props.onClose}
- size="small"
- />
- </StyledWorkspaceNavItem>
- );
- }
-}
-
-const StyledWorkspaceNavItem = styled.li`
- display: inline-flex;
- align-items: center;
- position: relative;
- color: ${themeColor('workSpaceNavItem')};
-`;
-
-const StyledWorkSpaceNavItemButton = styled.button`
- display: inline-flex;
- align-items: center;
- border: none;
- height: 1.75rem;
- background-color: ${themeColor('workSpaceNavItemBackground')};
- color: ${themeColor('workSpaceNavItem')};
-
- &:hover,
- &:focus {
- color: ${themeColor('workSpaceNavItem')};
- opacity: 0.9;
- }
-`;
diff --git a/server/sonar-web/src/main/js/components/workspace/WorkspacePortal.tsx b/server/sonar-web/src/main/js/components/workspace/WorkspacePortal.tsx
deleted file mode 100644
index 3078f108bdf..00000000000
--- a/server/sonar-web/src/main/js/components/workspace/WorkspacePortal.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { createPortal } from 'react-dom';
-
-export default class WorkspacePortal extends React.PureComponent<React.PropsWithChildren> {
- el: HTMLElement;
-
- constructor(props: {}) {
- super(props);
- this.el = document.createElement('div');
- this.el.classList.add('workspace');
- }
-
- componentDidMount() {
- document.body.appendChild(this.el);
- }
-
- componentWillUnmount() {
- document.body.removeChild(this.el);
- }
-
- render() {
- return createPortal(this.props.children, this.el);
- }
-}
diff --git a/server/sonar-web/src/main/js/components/workspace/__tests__/Workspace-test.tsx b/server/sonar-web/src/main/js/components/workspace/__tests__/Workspace-test.tsx
deleted file mode 100644
index a259d958b6e..00000000000
--- a/server/sonar-web/src/main/js/components/workspace/__tests__/Workspace-test.tsx
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import * as React from 'react';
-import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { mockBranch } from '../../../helpers/mocks/branch-like';
-import { get, save } from '../../../helpers/storage';
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import { BranchLike } from '../../../types/branch-like';
-import Workspace, { TYPE_KEY, WorkspaceTypes } from '../Workspace';
-import { WorkspaceContext } from '../context';
-
-jest.mock('../../../helpers/storage', () => {
- return {
- get: jest.fn(() => {
- throw Error('no local storage');
- }),
- save: jest.fn(),
- };
-});
-
-jest.mock('../../../api/rules', () => ({
- getRulesApp: jest.fn().mockResolvedValue({
- repositories: [{ key: 'repo', language: 'xoo', name: 'Xoo Repository' }],
- }),
-}));
-
-// Simplify the SourceViewer
-jest.mock('../../SourceViewer/SourceViewer', () => {
- const { useEffect } = jest.requireActual('react');
- const { ComponentQualifier } = jest.requireActual('~sonar-aligned/types/component');
-
- function SourceViewer({
- component,
- onLoaded,
- }: {
- component: string;
- onLoaded: (component: { path: string; q: string }) => void;
- }) {
- // Trigger the "loadComponent" to update the name of the component
- useEffect(() => {
- onLoaded({ path: `path/to/component/${component}`, q: ComponentQualifier.File });
- }, [component, onLoaded]);
-
- return <div />;
- }
-
- return {
- __esModule: true,
- default: SourceViewer,
- };
-});
-
-const WINDOW_HEIGHT = 1000;
-const originalHeight = window.innerHeight;
-
-beforeAll(() => {
- Object.defineProperty(window, 'innerHeight', {
- writable: true,
- configurable: true,
- value: WINDOW_HEIGHT,
- });
-});
-
-afterAll(() => {
- Object.defineProperty(window, 'innerHeight', {
- writable: true,
- configurable: true,
- value: originalHeight,
- });
-});
-
-beforeEach(jest.clearAllMocks);
-
-it('should load data from local storage and allow to open another component', async () => {
- const user = userEvent.setup();
- const component = {
- [TYPE_KEY]: WorkspaceTypes.Component,
- branchLike: mockBranch(),
- key: 'foo',
- name: 'previously opened file',
- };
- jest.mocked(get).mockReturnValueOnce(JSON.stringify([component]));
-
- renderWorkspace();
-
- expect(byText('previously opened file').get()).toBeInTheDocument();
- expect(
- byRole('heading', { name: 'qualifier.FIL path/to/component/k1' }).query(),
- ).not.toBeInTheDocument();
-
- await user.click(ui.componentOpenButton.get());
-
- expect(
- byRole('heading', { name: 'qualifier.FIL path/to/component/k1' }).get(),
- ).toBeInTheDocument();
- expect(save).toHaveBeenCalled();
-});
-
-it('should be resizable', async () => {
- const user = userEvent.setup();
-
- renderWorkspace();
-
- await user.click(ui.componentOpenButton.get());
-
- expect(ui.workspaceViewerContainer.get()).toHaveStyle({ height: '300px' });
-
- await user.click(ui.fullWindowButton.get());
-
- // 85% of window height, forced at 1000 in the test (WINDOW_HEIGHT)
- expect(ui.workspaceViewerContainer.get()).toHaveStyle({ height: '850px' });
-
- expect(ui.normalWindowButton.get()).toBeInTheDocument();
- expect(ui.fullWindowButton.query()).not.toBeInTheDocument();
- await user.click(ui.normalWindowButton.get());
-
- expect(ui.workspaceViewerContainer.get()).toHaveStyle({ height: '300px' });
-
- await user.click(ui.collapseButton.get());
-
- expect(ui.workspaceViewerContainer.query()).not.toBeInTheDocument();
-
- const fileButton = byRole('button', { name: 'qualifier.FIL path/to/component/k1' });
- expect(fileButton.get()).toBeInTheDocument();
- await user.click(fileButton.get());
-
- await user.click(ui.closeButton.get());
- expect(fileButton.query()).not.toBeInTheDocument();
-});
-
-function renderWorkspace(componentKey = 'k1', branchLike?: BranchLike) {
- return renderComponent(
- <Workspace>
- <TestComponent componentKey={componentKey} branchLike={branchLike} />
- </Workspace>,
- );
-}
-
-function TestComponent({
- componentKey,
- branchLike,
-}: {
- branchLike?: BranchLike;
- componentKey: string;
-}) {
- const { openComponent } = React.useContext(WorkspaceContext);
-
- const clickHandler = React.useCallback(() => {
- openComponent({
- key: componentKey,
- branchLike,
- name: componentKey,
- qualifier: ComponentQualifier.File,
- });
- }, [openComponent, componentKey, branchLike]);
-
- return (
- <button type="button" onClick={clickHandler}>
- open component
- </button>
- );
-}
-
-const ui = {
- componentOpenButton: byRole('button', { name: 'open component' }),
- collapseButton: byRole('button', { name: 'workspace.minimize' }),
- normalWindowButton: byRole('button', { name: 'workspace.normal_size' }),
- fullWindowButton: byRole('button', { name: 'workspace.full_window' }),
- closeButton: byRole('button', { name: 'workspace.close' }),
- workspaceViewerContainer: byRole('complementary'),
-};
diff --git a/server/sonar-web/src/main/js/components/workspace/context.ts b/server/sonar-web/src/main/js/components/workspace/context.ts
deleted file mode 100644
index 615e53213d3..00000000000
--- a/server/sonar-web/src/main/js/components/workspace/context.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { createContext } from 'react';
-import { BranchLike } from '../../types/branch-like';
-import { Dict } from '../../types/types';
-
-export interface ComponentDescriptor {
- branchLike: BranchLike | undefined;
- key: string;
- line?: number;
- name?: string;
- qualifier?: string;
-}
-
-export interface RuleDescriptor {
- key: string;
- name?: string;
-}
-
-export interface WorkspaceContextShape {
- externalRulesRepoNames: Dict<string>;
- openComponent: (component: ComponentDescriptor) => void;
-}
-
-export const WorkspaceContext = createContext<WorkspaceContextShape>({
- externalRulesRepoNames: {},
- openComponent: () => {},
-});
diff --git a/server/sonar-web/src/main/js/components/workspace/styles.css b/server/sonar-web/src/main/js/components/workspace/styles.css
deleted file mode 100644
index 5b8a02ddf83..00000000000
--- a/server/sonar-web/src/main/js/components/workspace/styles.css
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-.workspace-viewer {
- position: fixed;
- z-index: 450;
- bottom: 0;
- left: 0;
- right: 0;
- box-sizing: border-box;
- background-color: #fff;
- box-shadow: 0 -6px 12px rgba(0, 0, 0, 0.175);
-}
-
-.workspace-viewer-resize {
- position: absolute;
- top: 3px;
- left: 50%;
- width: 30px;
- height: 5px;
- margin-left: -15px;
- background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzBweCIgaGVpZ2h0PSI1cHgiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgc3R5bGU9ImZpbGwtcnVsZTpldmVub2RkO2NsaXAtcnVsZTpldmVub2RkO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxLjQxNDIxOyI+PGc+PGcgaWQ9IkxheWVyMSI+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSwwLDApIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsNCwwKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDgsMCkiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSwxMiwwKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDE2LDApIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMjAsMCkiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSwyNCwwKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDI4LDApIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMCwzKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDQsMykiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSw4LDMpIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMTIsMykiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSwxNiwzKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDIwLDMpIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMjQsMykiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSwyOCwzKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDAsMCkiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSw0LDApIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsOCwwKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDEyLDApIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMTYsMCkiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSwyMCwwKSI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIiIGhlaWdodD0iMiIgc3R5bGU9ImZpbGw6Izc3NztmaWxsLW9wYWNpdHk6MC41OyIvPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwxLDI0LDApIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMiIgaGVpZ2h0PSIyIiBzdHlsZT0iZmlsbDojNzc3O2ZpbGwtb3BhY2l0eTowLjU7Ii8+PC9nPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMjgsMCkiPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHN0eWxlPSJmaWxsOiM3Nzc7ZmlsbC1vcGFjaXR5OjAuNTsiLz48L2c+PC9nPjwvZz48L3N2Zz4=);
- cursor: ns-resize;
-}
-
-.workspace-viewer-container {
- height: calc(40vh - 30px);
- min-height: 100px;
- max-height: calc(95vh - 30px);
- padding: 5px 10px;
- overflow-y: scroll;
- overflow-x: auto;
- box-sizing: border-box;
-}
-
-.with-workspace .source-viewer {
- padding-bottom: 40vh;
-}
-
-.with-workspace .workspace-viewer .source-viewer {
- padding-bottom: 0;
-}
diff --git a/server/sonar-web/src/main/js/design-system/README.md b/server/sonar-web/src/main/js/design-system/README.md
deleted file mode 100644
index c85e257d539..00000000000
--- a/server/sonar-web/src/main/js/design-system/README.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Design System
-This module is a Component Library for SonarQube. Despite being an internal module, it should be thought of as an external library.
-
-
-
-## Components
-
-Components implemented here should be generic components, mostly agnostic of the business domains.
-There are some grey areas, like the Quality Gate Indicator which is obviously tied to the states a QG can have.
-
-
-## L10n, i18n, translations
-
-Translation helpers (`translate`/`translateWithParameters`) cannot be used in the component library. Most text should be expected as a prop anyway.
-Generic (read "context-independent") labels will soon be translated using react-intl.
-
-Date/time formatting should use react-intl, to benefit from the user's locale.
-
-
-## Helpers and utilities
-
-Only helpers necessary for Components should be implemented in this module. Business logic utilities, or application-specific methods (e.g. `getComponentUrl`), should be kept in the core. \ No newline at end of file
diff --git a/server/sonar-web/src/main/js/design-system/components/Accordion.tsx b/server/sonar-web/src/main/js/design-system/components/Accordion.tsx
deleted file mode 100644
index 024a4eb8774..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Accordion.tsx
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { css } from '@emotion/react';
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { uniqueId } from 'lodash';
-import React from 'react';
-import tw from 'twin.macro';
-import { themeBorder, themeColor, themeContrast } from '../helpers';
-import { BareButton } from '../sonar-aligned/components/buttons';
-import { ThemedProps } from '../types';
-import { OpenCloseIndicator } from './icons/OpenCloseIndicator';
-
-interface AccordionProps {
- ariaLabel?: string;
- children: React.ReactNode;
- className?: string;
- data?: string;
- header: React.ReactNode;
- onClick: (data?: string) => void;
- open: boolean;
-}
-
-export function Accordion(props: AccordionProps) {
- const { ariaLabel, className, open, header, data, onClick } = props;
-
- const id = React.useMemo(() => uniqueId('accordion-'), []);
- const handleClick = React.useCallback(() => {
- onClick(data);
- }, [onClick, data]);
-
- return (
- <Container
- className={classNames(className, {
- open,
- })}
- role="listitem"
- >
- <BareButton
- aria-controls={`${id}-panel`}
- aria-expanded={open}
- aria-label={ariaLabel}
- className="sw-flex sw-items-center sw-justify-between sw-p-4 sw-box-border sw-w-full"
- id={`${id}-header`}
- onClick={handleClick}
- >
- {header}
- <OpenCloseIndicator aria-hidden className="sw-ml-2" open={open} />
- </BareButton>
- <div aria-labelledby={`${id}-header`} id={`${id}-panel`} role="region">
- {open && <div className="sw-p-4">{props.children}</div>}
- </div>
- </Container>
- );
-}
-
-const accordionStyle = (props: ThemedProps) => css`
- box-sizing: border-box;
- text-decoration: none;
- outline: none;
- border: ${themeBorder('default', 'buttonSecondaryBorder')(props)};
- color: ${themeContrast('buttonSecondary')(props)};
- background-color: ${themeColor('buttonSecondary')(props)};
- transition:
- background-color 0.2s ease,
- outline 0.2s ease;
-
- & > button {
- ${tw`sw-typo-semibold`}
- }
- ${tw`sw-rounded-2`}
- ${tw`sw-overflow-hidden`}
-
- & > button:hover, & > button:active {
- color: ${themeContrast('buttonSecondary')(props)};
- background-color: ${themeColor('buttonSecondaryHover')(props)};
- }
-
- & > button:focus,
- & > button:active {
- color: ${themeContrast('buttonSecondary')(props)};
- outline: ${themeBorder('focus', 'var(--focus)')(props)};
- }
-
- & > button:disabled,
- & > button:disabled:hover {
- color: var(--echoes-color-text-disabled);
- background-color: ${themeColor('buttonDisabled')(props)};
- border: ${themeBorder('default', 'buttonDisabledBorder')(props)};
-
- ${tw`sw-cursor-not-allowed`}
- }
-
- & > svg {
- ${tw`sw-mr-1`}
- }
-`;
-
-const Container = styled.div`
- ${accordionStyle}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/Badge.tsx b/server/sonar-web/src/main/js/design-system/components/Badge.tsx
deleted file mode 100644
index 90268436259..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Badge.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeBorder, themeColor, themeContrast } from '../helpers/theme';
-import { ThemeColors } from '../types/theme';
-
-type BadgeVariant = 'default' | 'new' | 'deleted' | 'counter' | 'counterFailed';
-
-const variantList: Record<BadgeVariant, ThemeColors> = {
- default: 'badgeDefault',
- new: 'badgeNew',
- deleted: 'badgeDeleted',
- counter: 'badgeCounter',
- counterFailed: 'badgeCounterFailed',
-};
-
-interface BadgeProps extends React.PropsWithChildren {
- className?: string;
- title?: string;
- variant?: BadgeVariant;
-}
-
-function getColor(variantInfo: ThemeColors) {
- if (variantInfo === 'badgeCounterFailed') {
- return 'var(--echoes-color-text-danger-bold)';
- }
-
- return themeContrast(variantInfo);
-}
-
-export function Badge({ className, children, title, variant = 'default' }: BadgeProps) {
- const commonProps = {
- 'aria-label': title,
- className,
- role: title ? 'img' : 'presentation',
- title,
- };
-
- const Component = ['counter', 'counterFailed'].includes(variant) ? StyledCounter : StyledBadge;
-
- return (
- <Component variantInfo={variantList[variant]} {...commonProps}>
- {children}
- </Component>
- );
-}
-
-const StyledBadge = styled.span<{
- variantInfo: ThemeColors;
-}>`
- ${tw`sw-text-[0.75rem]`};
- ${tw`sw-leading-[0.938rem]`};
- ${tw`sw-font-semibold`};
- ${tw`sw-inline-block`};
- ${tw`sw-whitespace-nowrap`};
- ${tw`sw-px-[0.125rem] sw-py-[0.03125rem]`};
- ${tw`sw-rounded-1/2`};
-
- color: ${({ variantInfo }) => themeContrast(variantInfo)};
- background-color: ${({ variantInfo }) => themeColor(variantInfo)};
- text-transform: uppercase;
-
- &:empty {
- ${tw`sw-hidden`}
- }
-`;
-
-const StyledCounter = styled.span<{
- variantInfo: ThemeColors;
-}>`
- ${tw`sw-min-w-5 sw-min-h-5`};
- ${tw`sw-text-[0.75rem]`};
- ${tw`sw-font-regular`};
- ${tw`sw-box-border sw-px-[5px]`};
- ${tw`sw-inline-flex`};
- ${tw`sw-leading-[1.125rem]`};
- ${tw`sw-items-center sw-justify-center`};
- ${tw`sw-rounded-pill`};
-
- color: ${({ variantInfo }) => getColor(variantInfo)};
- background-color: ${({ variantInfo }) => themeColor(variantInfo)};
- border: ${({ variantInfo }) =>
- themeBorder(
- 'default',
- variantInfo === 'badgeCounterFailed' ? 'badgeCounterFailedBorder' : 'transparent',
- )};
-
- &:empty {
- ${tw`sw-hidden`}
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/Banner.tsx b/server/sonar-web/src/main/js/design-system/components/Banner.tsx
deleted file mode 100644
index 8500ce7273a..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Banner.tsx
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { ReactNode } from 'react';
-import { useIntl } from 'react-intl';
-import tw from 'twin.macro';
-import { LAYOUT_BANNER_HEIGHT, LAYOUT_VIEWPORT_MIN_WIDTH, themeColor } from '../helpers';
-import { ThemeColors } from '../types';
-import { InteractiveIconBase } from './InteractiveIcon';
-import { CloseIcon, FlagErrorIcon, FlagInfoIcon, FlagSuccessIcon, FlagWarningIcon } from './icons';
-
-export type Variant = 'error' | 'warning' | 'success' | 'info';
-
-interface Props {
- children: ReactNode;
- className?: string;
- onDismiss?: VoidFunction;
- variant: Variant;
-}
-
-function getVariantInfo(variant: Variant) {
- const variantList = {
- error: {
- icon: <FlagErrorIcon />,
- fontColor: 'errorText',
- backGroundColor: 'errorBackground',
- },
- warning: {
- icon: <FlagWarningIcon />,
- fontColor: 'warningText',
- backGroundColor: 'warningBackground',
- },
- success: {
- icon: <FlagSuccessIcon />,
- fontColor: 'successText',
- backGroundColor: 'successBackground',
- },
- info: {
- icon: <FlagInfoIcon />,
- fontColor: 'infoText',
- backGroundColor: 'infoBackground',
- },
- } as const;
-
- return variantList[variant];
-}
-
-export function Banner({ children, className, onDismiss, variant }: Props) {
- const variantInfo = getVariantInfo(variant);
-
- const intl = useIntl();
-
- return (
- <div className={className} role="alert" style={{ height: LAYOUT_BANNER_HEIGHT }}>
- <BannerWrapper
- backGroundColor={variantInfo.backGroundColor}
- fontColor={variantInfo.fontColor}
- >
- <BannerInner>
- <div className="sw-flex sw-items-center">
- <div className="sw-mr-3">{variantInfo.icon}</div>
- {children}
- </div>
-
- {onDismiss && (
- <BannerCloseIcon
- Icon={CloseIcon}
- aria-label={intl.formatMessage({ id: 'dismiss' })}
- backGroundColor={variantInfo.backGroundColor}
- fontColor={variantInfo.fontColor}
- onClick={onDismiss}
- size="small"
- />
- )}
- </BannerInner>
- </BannerWrapper>
- </div>
- );
-}
-
-const BannerWrapper = styled.div<{
- backGroundColor: ThemeColors;
- fontColor: ThemeColors;
-}>`
- min-width: ${LAYOUT_VIEWPORT_MIN_WIDTH}px;
- max-width: 100%;
- height: inherit;
- background-color: ${({ backGroundColor }) => themeColor(backGroundColor)};
- color: ${({ fontColor }) => themeColor(fontColor)};
- ${tw`sw-z-popup sw-fixed sw-w-full`}
- ${tw`sw-sticky sw-top-0`}
-`;
-
-const BannerInner = styled.div`
- width: 100%;
- height: inherit;
- ${tw`sw-box-border`}
- ${tw`sw-flex sw-items-center sw-justify-between sw-gap-3`}
- ${tw`sw-px-4`}
- ${tw`sw-typo-default`}
-`;
-
-const BannerCloseIcon = styled(InteractiveIconBase)<{
- backGroundColor: ThemeColors;
- fontColor: ThemeColors;
-}>`
- --background: ${({ backGroundColor }) => themeColor(backGroundColor)};
- --backgroundHover: ${({ fontColor }) => themeColor(fontColor)};
- --color: ${({ fontColor }) => themeColor(fontColor)};
- --colorHover: ${({ backGroundColor }) => themeColor(backGroundColor)};
- --focus: ${themeColor('bannerIconFocus', 0.2)};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/BarChart.tsx b/server/sonar-web/src/main/js/design-system/components/BarChart.tsx
deleted file mode 100644
index ad149cee618..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/BarChart.tsx
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { max } from 'd3-array';
-import { ScaleBand, ScaleLinear, scaleBand, scaleLinear } from 'd3-scale';
-import { themeColor } from '../helpers';
-
-interface DataPoint {
- description: string;
- tooltip?: string;
- x: number;
- y: number;
-}
-
-interface Props<T> {
- barsWidth: number;
- data: Array<DataPoint & T>;
- height: number;
- onBarClick: (point: DataPoint & T) => void;
- padding?: [number, number, number, number];
- width: number;
- xValues?: string[];
-}
-
-export function BarChart<T>(props: Props<T>) {
- const { barsWidth, data, width, height, padding = [10, 10, 10, 10], xValues } = props;
-
- const availableWidth = width - padding[1] - padding[3];
- const availableHeight = height - padding[0] - padding[2];
-
- const innerPadding = (availableWidth - barsWidth * data.length) / (data.length - 1);
- const relativeInnerPadding = innerPadding / (innerPadding + barsWidth);
-
- const maxY = max(data, (d) => d.y) as number;
- const xScale = scaleBand<number>()
- .domain(data.map((d) => d.x))
- .range([0, availableWidth])
- .paddingInner(relativeInnerPadding);
- const yScale = scaleLinear().domain([0, maxY]).range([availableHeight, 0]);
-
- return (
- <svg className="bar-chart" height={height} width={width}>
- <g transform={`translate(${padding[3]}, ${padding[0]})`}>
- <Xvalues
- data={data}
- onBarClick={props.onBarClick}
- xScale={xScale}
- xValues={xValues}
- yScale={yScale}
- />
- <Bars
- barsWidth={barsWidth}
- data={data}
- onBarClick={props.onBarClick}
- xScale={xScale}
- yScale={yScale}
- />
- </g>
- </svg>
- );
-}
-
-function Xvalues<T>(
- props: {
- xScale: ScaleBand<number>;
- yScale: ScaleLinear<number, number>;
- } & Pick<Props<T>, 'data' | 'xValues' | 'onBarClick'>,
-) {
- const { data, xValues = [], xScale, yScale } = props;
-
- if (!xValues.length) {
- return null;
- }
-
- const ticks = xValues.map((value, index) => {
- const point = data[index];
- const x = Math.round((xScale(point.x) as number) + xScale.bandwidth() / 2);
- const y = yScale(point.y);
-
- return (
- <BarChartTick
- className="sw-typo-default sw-cursor-pointer"
- dy="-0.5em"
- // eslint-disable-next-line react/no-array-index-key
- key={index}
- onClick={() => {
- props.onBarClick(point);
- }}
- x={x}
- y={y}
- >
- {point.tooltip && <title>{point.tooltip}</title>}
- {value}
- </BarChartTick>
- );
- });
- return <g>{ticks}</g>;
-}
-
-function Bars<T>(
- props: {
- xScale: ScaleBand<number>;
- yScale: ScaleLinear<number, number>;
- } & Pick<Props<T>, 'data' | 'barsWidth' | 'onBarClick'>,
-) {
- const { barsWidth, data, xScale, yScale } = props;
-
- const bars = data.map((point, index) => {
- const x = Math.round(xScale(point.x) as number);
- const maxY = yScale.range()[0];
- const y = Math.round(yScale(point.y)) - /* minimum bar height */ 1;
- const height = maxY - y;
- const rect = (
- <BarChartBar
- aria-label={point.description}
- className="sw-cursor-pointer"
- height={height}
- // eslint-disable-next-line react/no-array-index-key
- key={index}
- onClick={() => {
- props.onBarClick(point);
- }}
- width={barsWidth}
- x={x}
- y={y}
- >
- <title>{point.tooltip}</title>
- </BarChartBar>
- );
- return rect;
- });
- return <g>{bars}</g>;
-}
-
-const BarChartTick = styled.text`
- fill: var(--echoes-color-text-subdued);
- text-anchor: middle;
-`;
-
-const BarChartBar = styled.rect`
- fill: ${themeColor('primary')};
-
- &:hover {
- fill: ${themeColor('primaryDark')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/BorderlessAccordion.tsx b/server/sonar-web/src/main/js/design-system/components/BorderlessAccordion.tsx
deleted file mode 100644
index cad39d617ca..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/BorderlessAccordion.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { uniqueId } from 'lodash';
-import * as React from 'react';
-import { BareButton } from '../sonar-aligned/components/buttons';
-import { OpenCloseIndicator } from './icons/OpenCloseIndicator';
-
-interface AccordionProps {
- ariaLabel?: string;
- children: React.ReactNode;
- className?: string;
- data?: string;
- header: React.ReactNode;
- onClick: (data?: string) => void;
- open: boolean;
-}
-
-export function BorderlessAccordion(props: AccordionProps) {
- const { ariaLabel, className, open, header, data, onClick } = props;
-
- const id = React.useMemo(() => uniqueId('accordion-'), []);
- const handleClick = React.useCallback(() => {
- onClick(data);
- }, [onClick, data]);
-
- return (
- <div
- className={classNames('sw-cursor-pointer', className, {
- open,
- })}
- role="listitem"
- >
- <BareButton
- aria-controls={`${id}-panel`}
- aria-expanded={open}
- aria-label={ariaLabel}
- className="sw-flex sw-items-center sw-justify-between sw-px-2 sw-py-2 sw-box-border sw-w-full"
- id={`${id}-header`}
- onClick={handleClick}
- >
- {header}
- <OpenCloseIndicator aria-hidden className="sw-ml-2" open={open} />
- </BareButton>
- <div aria-labelledby={`${id}-header`} id={`${id}-panel`} role="region">
- {open && <div>{props.children}</div>}
- </div>
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/Breadcrumbs.tsx b/server/sonar-web/src/main/js/design-system/components/Breadcrumbs.tsx
deleted file mode 100644
index 47fa0c0b686..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Breadcrumbs.tsx
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import React from 'react';
-import { useIntl } from 'react-intl';
-import tw from 'twin.macro';
-import {
- LAYOUT_VIEWPORT_MAX_WIDTH_LARGE,
- PopupPlacement,
- PopupZLevel,
- themeColor,
-} from '../helpers';
-import { useResizeObserver } from '../hooks/useResizeObserver';
-import { Dropdown } from './Dropdown';
-import { InteractiveIcon } from './InteractiveIcon';
-import { Tooltip } from './Tooltip';
-import { ChevronDownIcon, ChevronRightIcon } from './icons';
-
-const WIDTH_OF_BREADCRUMB_DROPDOWN = 32;
-
-interface Props {
- actions?: React.ReactNode;
- ariaLabel?: string;
- breadcrumbLimit?: number;
- children: React.ReactNode;
- className?: string;
- expandButtonLabel?: string;
- innerRef?: React.RefObject<HTMLElement>;
- maxWidth?: number;
-}
-
-export function Breadcrumbs(props: Props) {
- const {
- ariaLabel,
- breadcrumbLimit,
- className,
- children,
- expandButtonLabel,
- innerRef,
- actions,
- maxWidth = LAYOUT_VIEWPORT_MAX_WIDTH_LARGE,
- } = props;
- const [lengthOfChildren, setLengthOfChildren] = React.useState<number[]>([]);
-
- const intl = useIntl();
-
- const breadcrumbRef = React.useCallback((node: HTMLLIElement, index: number) => {
- setLengthOfChildren((value) => {
- if (value[index] === node.offsetWidth) {
- return value;
- }
-
- const newValue = [...value];
- newValue[index] = node.offsetWidth;
- return newValue;
- });
- }, []);
-
- let hiddenBreadcrumbsCount = 0;
-
- const modifiedChildren = React.useMemo(() => {
- const childrenArray = React.Children.toArray(children).reverse();
-
- setLengthOfChildren((value) => {
- if (childrenArray.length === value.length) {
- return value;
- }
- return value.slice(0, childrenArray.length);
- });
-
- return React.Children.map(childrenArray, (child, index) => {
- const isLast = index === 0;
- return (
- <li
- ref={(node) => {
- if (node !== null) {
- breadcrumbRef(node, index);
- }
- }}
- >
- {child}
- {!isLast && <ChevronRightIcon data-testid="chevron-right" />}
- </li>
- );
- });
- }, [children, breadcrumbRef]);
-
- const onlyVisibleBreadcrumbs: JSX.Element[] = [];
- const widthOfChildrens = lengthOfChildren.reduce((sum, value) => sum + value, 0);
- if (widthOfChildrens > Math.ceil(maxWidth)) {
- let accumulatedBreadcrumbSize = WIDTH_OF_BREADCRUMB_DROPDOWN;
- lengthOfChildren.forEach((breadcrumbSize, index) => {
- const isBelowExplicitBreadcrumbLimit = breadcrumbLimit ? index + 1 <= breadcrumbLimit : true;
- accumulatedBreadcrumbSize += breadcrumbSize;
-
- const isLastBreadcrumb = index === 0; // always render the last breadcrumb
-
- if (isLastBreadcrumb && breadcrumbSize > maxWidth) {
- onlyVisibleBreadcrumbs.push(
- <Tooltip
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
- content={modifiedChildren[index].props.children as React.ReactNode}
- key={modifiedChildren[index].key}
- >
- {modifiedChildren[index]}
- </Tooltip>,
- );
- } else if (
- isLastBreadcrumb ||
- (accumulatedBreadcrumbSize <= maxWidth && isBelowExplicitBreadcrumbLimit)
- ) {
- onlyVisibleBreadcrumbs.push(modifiedChildren[index]);
- } else {
- hiddenBreadcrumbsCount += 1;
- }
- });
- }
-
- const showDropdownMenu = hiddenBreadcrumbsCount > 0;
- const breadcrumbsToShow = showDropdownMenu ? onlyVisibleBreadcrumbs : modifiedChildren;
-
- return (
- <BreadcrumbWrapper
- aria-label={ariaLabel ?? intl.formatMessage({ id: 'breadcrumbs' })}
- className={classNames('js-breadcrumbs', className)}
- ref={innerRef}
- >
- {showDropdownMenu && (
- <Dropdown
- allowResizing
- className="sw-px-2"
- id="breadcrumb-menu"
- overlay={React.Children.map(children, (child) => (
- <li>{child}</li>
- ))}
- placement={PopupPlacement.BottomLeft}
- zLevel={PopupZLevel.Global}
- >
- <InteractiveIcon
- Icon={ChevronDownIcon}
- aria-label={expandButtonLabel ?? intl.formatMessage({ id: 'expand_breadcrumb' })}
- className="sw-m-1 sw-mr-2"
- size="small"
- />
- </Dropdown>
- )}
- <ul className="sw-truncate sw-leading-6 sw-flex">{[...breadcrumbsToShow].reverse()}</ul>
- {actions && <div className="sw-mx-2">{actions}</div>}
- </BreadcrumbWrapper>
- );
-}
-
-export function BreadcrumbsFullWidth(props: Omit<Props, 'innerRef' | 'maxWidth'>) {
- const containerRef = React.useRef(null);
- const [width = LAYOUT_VIEWPORT_MAX_WIDTH_LARGE] = useResizeObserver(containerRef);
-
- return <Breadcrumbs {...props} innerRef={containerRef} maxWidth={width} />;
-}
-
-const BreadcrumbWrapper = styled.nav`
- ${tw`sw-flex sw-items-center`}
- ${tw`sw-truncate`}
- ${tw`sw-typo-default`}
-
- color: var(--echoes-color-text-subdued);
- background-color: ${themeColor('breadcrumb')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/BubbleChart.tsx b/server/sonar-web/src/main/js/design-system/components/BubbleChart.tsx
deleted file mode 100644
index 68f915f79d0..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/BubbleChart.tsx
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { max, min } from 'd3-array';
-import { ScaleLinear, scaleLinear } from 'd3-scale';
-import { select } from 'd3-selection';
-import { D3ZoomEvent, ZoomBehavior, zoom, zoomIdentity } from 'd3-zoom';
-import { sortBy, uniq } from 'lodash';
-import * as React from 'react';
-import { AutoSizer } from 'react-virtualized/dist/commonjs/AutoSizer';
-import tw from 'twin.macro';
-import { themeColor, themeContrast } from '../helpers';
-import { ButtonSecondary } from '../sonar-aligned/components/buttons';
-import { Note } from '../sonar-aligned/components/typography';
-import { Tooltip } from './Tooltip';
-
-const TICKS_COUNT = 5;
-const DEFAULT_PADDING = [10, 10, 10, 10];
-const DEFAULT_SIZE_RANGE = [5, 45];
-
-interface BubbleItem<T> {
- backgroundColor?: string;
- borderColor?: string;
- data?: T;
- key?: string;
- size: number;
- tooltip?: React.ReactNode;
- x: number;
- y: number;
-}
-
-export interface BubbleChartProps<T> {
- 'data-testid'?: string;
- displayXGrid?: boolean;
- displayXTicks?: boolean;
- displayYGrid?: boolean;
- displayYTicks?: boolean;
- formatXTick?: (tick: number) => string;
- formatYTick?: (tick: number) => string;
- height: number;
- items: Array<BubbleItem<T>>;
- onBubbleClick?: (ref?: T) => void;
- padding: [number, number, number, number];
- sizeDomain?: [number, number];
- sizeRange?: [number, number];
- xDomain?: [number, number];
- yDomain?: [number, number];
- zoomLabel?: string;
- zoomResetLabel?: string;
- zoomTooltipText?: string;
-}
-
-type Scale = ScaleLinear<number, number>;
-
-export function BubbleChart<T>(props: BubbleChartProps<T>) {
- const {
- padding = DEFAULT_PADDING,
- height,
- items,
- xDomain,
- yDomain,
- sizeDomain,
- sizeRange = DEFAULT_SIZE_RANGE,
- zoomResetLabel = 'Reset',
- zoomTooltipText,
- zoomLabel = 'Zoom',
- displayXTicks = true,
- displayYTicks = true,
- displayXGrid = true,
- displayYGrid = true,
- formatXTick = (d: number) => String(d),
- formatYTick = (d: number) => String(d),
- } = props;
-
- const [transform, setTransform] = React.useState({ x: 0, y: 0, k: 1 });
- const nodeRef = React.useRef<SVGSVGElement>();
- const zoomRef = React.useRef<ZoomBehavior<Element, unknown>>();
- const zoomLevelLabel = `${Math.floor(transform.k * 100)}%`;
-
- if (zoomRef.current && nodeRef.current) {
- const rect = nodeRef.current.getBoundingClientRect();
- zoomRef.current.translateExtent([
- [0, 0],
- [rect.width, rect.height],
- ]);
- }
-
- const zoomed = React.useCallback(
- (event: D3ZoomEvent<SVGSVGElement, void>) => {
- const { x, y, k } = event.transform;
- setTransform({
- x: x + padding[3] * (k - 1),
- y: y + padding[0] * (k - 1),
- k,
- });
- },
- [padding],
- );
-
- const boundNode = React.useCallback(
- (node: SVGSVGElement) => {
- nodeRef.current = node;
- zoomRef.current = zoom().scaleExtent([1, 10]).on('zoom', zoomed);
- // @ts-expect-error Type instantiation is excessively deep and possibly infinite.
- select(nodeRef.current).call(zoomRef.current);
- },
- [zoomed],
- );
-
- const resetZoom = React.useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
- e.stopPropagation();
- e.preventDefault();
- if (zoomRef.current && nodeRef.current) {
- select(nodeRef.current).call(zoomRef.current.transform, zoomIdentity);
- }
- }, []);
-
- const getXRange = React.useCallback(
- (xScale: Scale, sizeScale: Scale, availableWidth: number) => {
- const [x1, x2] = xScale.range();
- const minX = min(items, (d) => xScale(d.x) - sizeScale(d.size)) ?? 0;
- const maxX = max(items, (d) => xScale(d.x) + sizeScale(d.size)) ?? 0;
- const dMinX = minX < 0 ? x1 - minX : x1;
- const dMaxX = maxX > x2 ? maxX - x2 : 0;
- return [dMinX, availableWidth - dMaxX];
- },
- [items],
- );
-
- const getYRange = React.useCallback(
- (yScale: Scale, sizeScale: Scale, availableHeight: number) => {
- const [y1, y2] = yScale.range();
- const minY = min(items, (d) => yScale(d.y) - sizeScale(d.size)) ?? 0;
- const maxY = max(items, (d) => yScale(d.y) + sizeScale(d.size)) ?? 0;
- const dMinY = minY < 0 ? y2 - minY : y2;
- const dMaxY = maxY > y1 ? maxY - y1 : 0;
- return [availableHeight - dMaxY, dMinY];
- },
- [items],
- );
-
- const getTicks = React.useCallback(
- (scale: Scale, format: (d: number) => string) => {
- const zoomAmount = Math.ceil(transform.k);
- const ticks = scale.ticks(TICKS_COUNT * zoomAmount).map((tick) => format(tick));
- const uniqueTicksCount = uniq(ticks).length;
- const ticksCount =
- uniqueTicksCount < TICKS_COUNT * zoomAmount
- ? uniqueTicksCount - 1
- : TICKS_COUNT * zoomAmount;
- return scale.ticks(ticksCount);
- },
- [transform],
- );
-
- const renderXGrid = React.useCallback(
- (ticks: number[], xScale: Scale, yScale: Scale) => {
- if (!displayXGrid) {
- return null;
- }
-
- const lines = ticks.map((tick, index) => {
- const x = xScale(tick);
- const [y1, y2] = yScale.range();
- return (
- <BubbleChartGrid
- // eslint-disable-next-line react/no-array-index-key
- key={index}
- x1={x * transform.k + transform.x}
- x2={x * transform.k + transform.x}
- y1={y1 * transform.k}
- y2={transform.k > 1 ? 0 : y2}
- />
- );
- });
-
- return <g>{lines}</g>;
- },
- [transform, displayXGrid],
- );
-
- const renderYGrid = React.useCallback(
- (ticks: number[], xScale: Scale, yScale: Scale) => {
- if (!displayYGrid) {
- return null;
- }
-
- const lines = ticks.map((tick, index) => {
- const y = yScale(tick);
- const [x1, x2] = xScale.range();
- return (
- <BubbleChartGrid
- // eslint-disable-next-line react/no-array-index-key
- key={index}
- x1={transform.k > 1 ? 0 : x1}
- x2={x2 * transform.k}
- y1={y * transform.k + transform.y}
- y2={y * transform.k + transform.y}
- />
- );
- });
-
- return <g>{lines}</g>;
- },
- [displayYGrid, transform],
- );
-
- const renderXTicks = React.useCallback(
- (xTicks: number[], xScale: Scale, yScale: Scale) => {
- if (!displayXTicks) {
- return null;
- }
-
- const ticks = xTicks.map((tick, index) => {
- const x = xScale(tick) * transform.k + transform.x;
- const y = yScale.range()[0];
- const innerText = formatXTick(tick);
- // as we modified the `x` using `transform`, check that it is inside the range again
- return x > 0 && x < xScale.range()[1] ? (
- // eslint-disable-next-line react/no-array-index-key
- <BubbleChartTick dy="1.5em" key={index} style={{ '--align': 'middle' }} x={x} y={y}>
- {innerText}
- </BubbleChartTick>
- ) : null;
- });
-
- return <g>{ticks}</g>;
- },
- [displayXTicks, formatXTick, transform],
- );
-
- const renderYTicks = React.useCallback(
- (yTicks: number[], xScale: Scale, yScale: Scale) => {
- if (!displayYTicks) {
- return null;
- }
-
- const ticks = yTicks.map((tick, index) => {
- const x = xScale.range()[0];
- const y = yScale(tick) * transform.k + transform.y;
- const innerText = formatYTick(tick);
- // as we modified the `y` using `transform`, check that it is inside the range again
- return y > 0 && y < yScale.range()[0] ? (
- <BubbleChartTick
- dx="-0.5em"
- dy="0.3em"
- // eslint-disable-next-line react/no-array-index-key
- key={index}
- style={{ '--align': 'end' }}
- x={x}
- y={y}
- >
- {innerText}
- </BubbleChartTick>
- ) : null;
- });
-
- return <g>{ticks}</g>;
- },
- [displayYTicks, formatYTick, transform],
- );
-
- const renderChart = (width: number) => {
- const availableWidth = width - padding[1] - padding[3];
- const availableHeight = height - padding[0] - padding[2];
-
- const xScale = scaleLinear()
- .domain(xDomain ?? [0, max(items, (d) => d.x) ?? 0])
- .range([0, availableWidth])
- .nice();
- const yScale = scaleLinear()
- .domain(yDomain ?? [0, max(items, (d) => d.y) ?? 0])
- .range([availableHeight, 0])
- .nice();
- const sizeScale = scaleLinear()
- .domain(sizeDomain ?? [0, max(items, (d) => d.size) ?? 0])
- .range(sizeRange ?? []);
-
- const xScaleOriginal = xScale.copy();
- const yScaleOriginal = yScale.copy();
-
- xScale.range(getXRange(xScale, sizeScale, availableWidth));
- yScale.range(getYRange(yScale, sizeScale, availableHeight));
-
- const bubbles = sortBy(items, (b) => -b.size).map((item, index) => {
- return (
- <Bubble
- backgroundColor={item.backgroundColor}
- borderColor={item.borderColor}
- data={item.data}
- key={item.key ?? index}
- onClick={props.onBubbleClick}
- r={sizeScale(item.size)}
- scale={1 / transform.k}
- tooltip={item.tooltip}
- x={xScale(item.x)}
- y={yScale(item.y)}
- />
- );
- });
-
- const xTicks = getTicks(xScale, formatXTick);
- const yTicks = getTicks(yScale, formatYTick);
-
- return (
- <svg
- className={classNames('bubble-chart')}
- data-testid={props['data-testid']}
- height={height}
- ref={boundNode}
- width={width}
- >
- <defs>
- <clipPath id="graph-region">
- <rect
- // Extend clip by 2 pixels: one for clipRect border, and one for Bubble borders
- height={availableHeight + 4}
- width={availableWidth + 4}
- x={-2}
- y={-2}
- />
- </clipPath>
- </defs>
- <g transform={`translate(${padding[3]}, ${padding[0]})`}>
- <g clipPath="url(#graph-region)">
- {renderXGrid(xTicks, xScale, yScale)}
- {renderYGrid(yTicks, xScale, yScale)}
- <g transform={`translate(${transform.x}, ${transform.y}) scale(${transform.k})`}>
- {bubbles}
- </g>
- </g>
- {renderXTicks(xTicks, xScale, yScaleOriginal)}
- {renderYTicks(yTicks, xScaleOriginal, yScale)}
- </g>
- </svg>
- );
- };
-
- return (
- <div>
- <div className="sw-flex sw-items-center sw-justify-end sw-h-control sw-mb-4">
- <Tooltip content={zoomTooltipText}>
- <span>
- <Note className="sw-typo-semibold">{zoomLabel}</Note>
- {': '}
- {zoomLevelLabel}
- </span>
- </Tooltip>
- {zoomLevelLabel !== '100%' && (
- <ButtonSecondary
- className="sw-ml-2"
- disabled={zoomLevelLabel === '100%'}
- onClick={resetZoom}
- >
- {zoomResetLabel}
- </ButtonSecondary>
- )}
- </div>
- <AutoSizer disableHeight>{(size) => renderChart(size.width)}</AutoSizer>
- </div>
- );
-}
-
-interface BubbleProps<T> {
- backgroundColor?: string;
- borderColor?: string;
- data?: T;
- onClick?: (ref?: T) => void;
- r: number;
- scale: number;
- tooltip?: string | React.ReactNode;
- x: number;
- y: number;
-}
-
-function Bubble<T>(props: BubbleProps<T>) {
- const { backgroundColor, borderColor, data, onClick, r, scale, tooltip, x, y } = props;
- const handleClick = React.useCallback(
- (event: React.MouseEvent<HTMLAnchorElement>) => {
- event.stopPropagation();
- event.preventDefault();
- onClick?.(data);
- },
- [data, onClick],
- );
-
- const circle = (
- <a href="#" onClick={handleClick}>
- <BubbleStyled
- r={r}
- style={{
- fill: backgroundColor ?? '',
- stroke: borderColor ?? '',
- }}
- transform={`translate(${x}, ${y}) scale(${scale})`}
- />
- </a>
- );
-
- return <Tooltip content={tooltip}>{circle}</Tooltip>;
-}
-
-const BubbleStyled = styled.circle`
- ${tw`sw-cursor-pointer`}
-
- transition: fill-opacity 0.2s ease;
- fill: ${themeColor('bubbleDefault')};
- stroke: ${themeContrast('bubbleDefault')};
-
- &:hover {
- fill-opacity: 0.8;
- }
-`;
-
-const BubbleChartGrid = styled.line`
- shape-rendering: crispedges;
- stroke: ${themeColor('bubbleChartLine')};
-`;
-
-const BubbleChartTick = styled.text`
- ${tw`sw-typo-default`}
- ${tw`sw-select-none`}
- fill: var(--echoes-color-text-subdued);
- text-anchor: var(--align);
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/ClickEventBoundary.tsx b/server/sonar-web/src/main/js/design-system/components/ClickEventBoundary.tsx
deleted file mode 100644
index 6adbebb915f..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/ClickEventBoundary.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React from 'react';
-
-export interface ClickEventBoundaryProps {
- children: React.ReactElement<{ onClick?: (e: React.SyntheticEvent<MouseEvent>) => void }>;
-}
-
-export default function ClickEventBoundary({ children }: ClickEventBoundaryProps) {
- return React.cloneElement(children, {
- onClick: (e: React.SyntheticEvent<MouseEvent>) => {
- e.stopPropagation();
-
- if (typeof children.props.onClick === 'function') {
- children.props.onClick(e);
- }
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/CodeSnippet.tsx b/server/sonar-web/src/main/js/design-system/components/CodeSnippet.tsx
deleted file mode 100644
index 7adce4394c4..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/CodeSnippet.tsx
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { escape as lodashEscape } from 'lodash';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../helpers/theme';
-import { isDefined } from '../helpers/types';
-import { CodeSyntaxHighlighter } from './CodeSyntaxHighlighter';
-import { ClipboardButton } from './clipboard';
-
-interface Props {
- className?: string;
- copyAriaLabel?: string;
- isOneLine?: boolean;
- join?: string;
- language?: string;
- noCopy?: boolean;
- render?: string;
- snippet: string | Array<string | undefined>;
- wrap?: boolean | 'words';
-}
-
-// keep this "useless" concatenation for the readability reason
-// eslint-disable-next-line no-useless-concat
-const s = ' \\' + '\n ';
-
-export function CodeSnippet(props: Readonly<Props>) {
- const {
- copyAriaLabel,
- className,
- isOneLine,
- join = s,
- language,
- noCopy,
- render,
- snippet,
- wrap = false,
- } = props;
- const snippetArray = Array.isArray(snippet) ? snippet.filter(isDefined) : [snippet];
- const finalSnippet = isOneLine ? snippetArray.join(' ') : snippetArray.join(join);
-
- const isSimpleOneLine = isOneLine && noCopy;
-
- const copyButton = isOneLine ? (
- <StyledSingleLineClipboardButton copyValue={finalSnippet} ariaLabel={copyAriaLabel} />
- ) : (
- <StyledClipboardButton ariaLabel={copyAriaLabel} copyValue={finalSnippet} />
- );
-
- const renderSnippet =
- render ??
- (wrap || isOneLine
- ? `<code>${lodashEscape(finalSnippet)}</code>`
- : `<pre>${lodashEscape(finalSnippet)}</pre>`);
-
- return (
- <Wrapper
- as={isSimpleOneLine ? 'span' : undefined}
- className={classNames(
- 'sw-code',
- {
- 'sw-py-6': isOneLine && !noCopy,
- 'code-snippet-highlighted-oneline': isOneLine,
- 'code-snippet-simple-oneline': isSimpleOneLine,
- },
- className,
- 'fs-mask',
- )}
- >
- {!noCopy && copyButton}
- <CodeSyntaxHighlighter
- className={classNames('sw-overflow-auto', {
- 'sw-pr-24': !noCopy,
- 'sw-flex': !noCopy,
- })}
- htmlAsString={renderSnippet}
- language={language}
- wrap={wrap}
- />
- </Wrapper>
- );
-}
-
-const Wrapper = styled.div`
- background-color: ${themeColor('codeSnippetBackground')};
- border: ${themeBorder('default', 'codeSnippetBorder')};
-
- ${tw`sw-rounded-2`}
- ${tw`sw-relative`}
- ${tw`sw-my-2`}
-
- &.code-snippet-simple-oneline {
- ${tw`sw-my-0`}
- ${tw`sw-rounded-1`}
- }
-`;
-
-const StyledClipboardButton = styled(ClipboardButton)`
- ${tw`sw-select-none`}
- ${tw`sw-typo-default`}
- ${tw`sw-top-6 sw-right-6`}
- ${tw`sw-absolute`}
-
- .code-snippet-highlighted-oneline & {
- ${tw`sw-bottom-2`}
- }
-`;
-
-const StyledSingleLineClipboardButton = styled(StyledClipboardButton)`
- ${tw`sw-top-4 sw-bottom-4`}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/CodeSyntaxHighlighter.tsx b/server/sonar-web/src/main/js/design-system/components/CodeSyntaxHighlighter.tsx
deleted file mode 100644
index 339765de82c..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/CodeSyntaxHighlighter.tsx
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { HighlightResult } from 'highlight.js';
-import hljs from 'highlight.js/lib/core';
-import actionscript from 'highlight.js/lib/languages/actionscript';
-import bash from 'highlight.js/lib/languages/bash';
-import c from 'highlight.js/lib/languages/c';
-import cpp from 'highlight.js/lib/languages/cpp';
-import csharp from 'highlight.js/lib/languages/csharp';
-import css from 'highlight.js/lib/languages/css';
-import dart from 'highlight.js/lib/languages/dart';
-import docker from 'highlight.js/lib/languages/dockerfile';
-import go from 'highlight.js/lib/languages/go';
-import gradle from 'highlight.js/lib/languages/gradle';
-import java from 'highlight.js/lib/languages/java';
-import javascript from 'highlight.js/lib/languages/javascript';
-import json from 'highlight.js/lib/languages/json';
-import kotlin from 'highlight.js/lib/languages/kotlin';
-import objectivec from 'highlight.js/lib/languages/objectivec';
-import pgsql from 'highlight.js/lib/languages/pgsql';
-import php from 'highlight.js/lib/languages/php';
-import plaintext from 'highlight.js/lib/languages/plaintext';
-import powershell from 'highlight.js/lib/languages/powershell';
-import properties from 'highlight.js/lib/languages/properties';
-import python from 'highlight.js/lib/languages/python';
-import ruby from 'highlight.js/lib/languages/ruby';
-import scala from 'highlight.js/lib/languages/scala';
-import shell from 'highlight.js/lib/languages/shell';
-import sql from 'highlight.js/lib/languages/sql';
-import swift from 'highlight.js/lib/languages/swift';
-import typescript from 'highlight.js/lib/languages/typescript';
-import vbnet from 'highlight.js/lib/languages/vbnet';
-import xml from 'highlight.js/lib/languages/xml';
-import yaml from 'highlight.js/lib/languages/yaml';
-import apex from 'highlightjs-apex';
-import cobol from 'highlightjs-cobol';
-import abap from 'highlightjs-sap-abap';
-import tw from 'twin.macro';
-import { themeColor, themeContrast } from '../helpers/theme';
-import { hljsIssueIndicatorPlugin, hljsUnderlinePlugin } from '../sonar-aligned';
-import { SafeHTMLInjection, SanitizeLevel } from '../sonar-aligned/helpers/sanitize';
-
-// Supported Languages: https://highlightjs.readthedocs.io/en/latest/supported-languages.html
-// Registering languages individually reduce the packaged size to ~62kb instead of ~440kb
-// Terraform package is outdated an unmaintained
-hljs.registerLanguage('actionscript', actionscript);
-hljs.registerLanguage('bash', bash);
-hljs.registerLanguage('c', c);
-hljs.registerLanguage('cpp', cpp);
-hljs.registerLanguage('csharp', csharp);
-hljs.registerLanguage('css', css);
-hljs.registerLanguage('docker', docker);
-hljs.registerLanguage('go', go);
-hljs.registerLanguage('gradle', gradle);
-hljs.registerLanguage('java', java);
-hljs.registerLanguage('javascript', javascript);
-hljs.registerLanguage('json', json);
-hljs.registerLanguage('dart', dart);
-hljs.registerLanguage('kotlin', kotlin);
-hljs.registerLanguage('objectivec', objectivec);
-hljs.registerLanguage('pgsql', pgsql);
-hljs.registerLanguage('php', php);
-hljs.registerLanguage('plaintext', plaintext);
-hljs.registerLanguage('powershell', powershell);
-hljs.registerLanguage('properties', properties);
-hljs.registerLanguage('python', python);
-hljs.registerLanguage('ruby', ruby);
-hljs.registerLanguage('scala', scala);
-hljs.registerLanguage('shell', shell);
-hljs.registerLanguage('sql', sql);
-hljs.registerLanguage('swift', swift);
-hljs.registerLanguage('typescript', typescript);
-hljs.registerLanguage('vbnet', vbnet);
-hljs.registerLanguage('xml', xml);
-hljs.registerLanguage('yaml', yaml);
-hljs.registerLanguage('abap', abap);
-hljs.registerLanguage('apex', apex);
-hljs.registerLanguage('cobol', cobol);
-
-// By default, highlight js will treat unknown language as plaintext
-hljs.registerAliases('azureresourcemanager', { languageName: 'json' });
-hljs.registerAliases('flex', { languageName: 'actionscript' });
-hljs.registerAliases('objc', { languageName: 'objectivec' });
-hljs.registerAliases('plsql', { languageName: 'pgsql' });
-hljs.registerAliases('ipynb', { languageName: 'python' });
-// tsql plugin doesn't work with Vite and is ~13kb in size
-hljs.registerAliases('tsql', { languageName: 'sql' });
-hljs.registerAliases('secrets', { languageName: 'markdown' });
-hljs.registerAliases('web', { languageName: 'xml' });
-hljs.registerAliases(['cloudformation', 'kubernetes'], { languageName: 'yaml' });
-
-hljs.addPlugin(hljsIssueIndicatorPlugin);
-hljs.addPlugin(hljsUnderlinePlugin);
-
-interface Props {
- className?: string;
- escapeDom?: boolean;
- htmlAsString: string;
- language?: string;
- sanitizeLevel?: SanitizeLevel;
- wrap?: boolean | 'words';
-}
-
-const CODE_REGEXP = '<(code|pre)\\b([^>]*?)>(.+?)<\\/\\1>';
-const GLOBAL_REGEXP = new RegExp(CODE_REGEXP, 'gs');
-const SINGLE_REGEXP = new RegExp(CODE_REGEXP, 's');
-
-const htmlDecode = (escapedCode: string) => {
- const doc = new DOMParser().parseFromString(escapedCode, 'text/html');
-
- return doc.documentElement.textContent ?? '';
-};
-
-export function CodeSyntaxHighlighter(props: Readonly<Props>) {
- const {
- className,
- escapeDom = true,
- htmlAsString,
- language,
- sanitizeLevel = SanitizeLevel.FORBID_STYLE,
- wrap,
- } = props;
- let highlightedHtmlAsString = htmlAsString;
-
- htmlAsString.match(GLOBAL_REGEXP)?.forEach((codeBlock) => {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const [, tag, attributes, code] = SINGLE_REGEXP.exec(codeBlock)!;
-
- const unescapedCode = escapeDom ? htmlDecode(code) : code;
- let highlightedCode: HighlightResult;
-
- try {
- const actualLanguage =
- language !== undefined && hljs.getLanguage(language) ? language : 'plaintext';
-
- highlightedCode = hljs.highlight(unescapedCode, {
- ignoreIllegals: true,
- language: actualLanguage,
- });
- } catch {
- highlightedCode = hljs.highlight(unescapedCode, {
- ignoreIllegals: true,
- language: 'plaintext',
- });
- }
-
- highlightedHtmlAsString = highlightedHtmlAsString.replace(
- codeBlock,
- // Use a function to avoid triggering special replacement patterns
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_the_replacement
- () => `<${tag}${attributes}>${highlightedCode.value}</${tag}>`,
- );
- });
-
- return (
- <SafeHTMLInjection htmlAsString={highlightedHtmlAsString} sanitizeLevel={sanitizeLevel}>
- <StyledSpan
- className={classNames(
- `hljs ${className ?? ''}`,
- { 'code-wrap': wrap },
- { 'wrap-words': wrap === 'words' },
- )}
- />
- </SafeHTMLInjection>
- );
-}
-
-const StyledSpan = styled.span`
- code {
- ${tw`sw-code`};
-
- background: ${themeColor('codeSnippetBackground')};
- color: ${themeColor('codeSnippetBody')};
-
- &.hljs {
- padding: unset;
- }
- }
-
- .hljs-meta,
- .hljs-variable {
- color: ${themeColor('codeSnippetBody')};
- }
-
- .hljs-doctag,
- .hljs-title,
- .hljs-title.class_,
- .hljs-title.function_ {
- color: ${themeColor('codeSnippetAnnotations')};
- }
-
- .hljs-comment {
- ${tw`sw-code-comment`}
-
- color: ${themeColor('codeSnippetComments')};
- }
-
- .hljs-keyword,
- .hljs-tag,
- .hljs-type {
- color: ${themeColor('codeSnippetKeyword')};
- }
-
- .hljs-literal,
- .hljs-number {
- color: ${themeColor('codeSnippetConstants')};
- }
-
- .hljs-string {
- color: ${themeColor('codeSnippetString')};
- }
-
- .hljs-meta .hljs-keyword {
- color: ${themeColor('codeSnippetPreprocessingDirective')};
- }
-
- .sonar-underline {
- text-decoration: underline ${themeColor('codeLineIssueSquiggle')}; // Fallback
- text-decoration: underline ${themeColor('codeLineIssueSquiggle')} wavy;
- text-decoration-thickness: 2px;
- text-decoration-skip-ink: none;
- }
-
- &.code-wrap {
- ${tw`sw-whitespace-pre-wrap`}
- ${tw`sw-break-all`}
-
- &.wrap-words {
- word-break: normal;
- ${tw`sw-break-words`}
- }
- }
-
- mark {
- ${tw`sw-font-regular`}
- ${tw`sw-p-1`}
- ${tw`sw-rounded-1`}
-
- background-color: ${themeColor('codeSnippetHighlight')};
- color: ${themeContrast('codeSnippetHighlight')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/ColorsLegend.tsx b/server/sonar-web/src/main/js/design-system/components/ColorsLegend.tsx
deleted file mode 100644
index a0ee2c2efc1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/ColorsLegend.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeBorder, themeColor, themeContrast } from '../helpers';
-import { BubbleColorVal } from '../types';
-import { Tooltip } from './Tooltip';
-import { Checkbox } from './input/Checkbox';
-
-export interface ColorFilterOption {
- ariaLabel?: string;
- backgroundColor?: string;
- borderColor?: string;
- label: React.ReactNode;
- overlay?: React.ReactNode;
- selected: boolean;
- value: string | number;
-}
-
-interface ColorLegendProps {
- className?: string;
- colors: ColorFilterOption[];
- onColorClick: (color: ColorFilterOption) => void;
-}
-
-export function ColorsLegend(props: ColorLegendProps) {
- const { className, colors } = props;
- const theme = useTheme();
-
- return (
- <ColorsLegendWrapper className={className}>
- {colors.map((color, idx) => (
- <li className="sw-ml-4" key={color.value}>
- <Tooltip content={color.overlay}>
- <div>
- <Checkbox
- checked={color.selected}
- label={color.ariaLabel}
- onCheck={() => {
- props.onColorClick(color);
- }}
- >
- <ColorRating
- style={
- color.selected
- ? {
- backgroundColor:
- color.backgroundColor ??
- themeColor(`bubble.${(idx + 1) as BubbleColorVal}`)({
- theme,
- }),
- borderColor:
- color.borderColor ??
- themeContrast(`bubble.${(idx + 1) as BubbleColorVal}`)({
- theme,
- }),
- }
- : {}
- }
- >
- {color.label}
- </ColorRating>
- </Checkbox>
- </div>
- </Tooltip>
- </li>
- ))}
- </ColorsLegendWrapper>
- );
-}
-
-const ColorsLegendWrapper = styled.ul`
- ${tw`sw-flex`}
-`;
-
-const ColorRating = styled.div`
- width: 20px;
- height: 20px;
- line-height: 20px;
- border-radius: 50%;
- border: ${themeBorder()};
- ${tw`sw-flex sw-justify-center`}
- ${tw`sw-ml-1`}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/CoverageIndicator.tsx b/server/sonar-web/src/main/js/design-system/components/CoverageIndicator.tsx
deleted file mode 100644
index 90fc23b11df..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/CoverageIndicator.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../helpers/theme';
-import { DonutChart } from './DonutChart';
-import { NoDataIcon } from './icons';
-
-const SIZE_TO_WIDTH_MAPPING = { xs: 16, sm: 24, md: 36 };
-const SIZE_TO_THICKNESS_MAPPING = { xs: 2, sm: 3, md: 4 };
-const FULL_PERCENT = 100;
-const PAD_ANGLE = 0.1;
-
-export interface CoverageIndicatorProps {
- 'aria-hidden'?: boolean | 'true' | 'false';
- 'aria-label'?: string;
- size?: 'xs' | 'sm' | 'md';
- value?: number | string;
-}
-
-export function CoverageIndicator({
- size = 'sm',
- value,
- ...rest
-}: Readonly<CoverageIndicatorProps>) {
- const theme = useTheme();
- const width = SIZE_TO_WIDTH_MAPPING[size];
- const thickness = SIZE_TO_THICKNESS_MAPPING[size];
-
- if (value === undefined) {
- return <NoDataIcon size={size} {...rest} />;
- }
-
- const themeRed = themeColor('coverageRed')({ theme });
- const themeGreen = themeColor('coverageGreen')({ theme });
-
- let padAngle = 0;
- const numberValue = Number(value || 0);
- const data = [
- { value: numberValue, fill: themeGreen },
- {
- value: FULL_PERCENT - numberValue,
- fill: themeRed,
- },
- ];
- if (numberValue !== 0 && numberValue < FULL_PERCENT) {
- padAngle = PAD_ANGLE; // Same for all sizes, because it scales automatically
- }
-
- return (
- <DonutChart
- data={data}
- height={width}
- padAngle={padAngle}
- thickness={thickness}
- width={width}
- {...rest}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/DonutChart.tsx b/server/sonar-web/src/main/js/design-system/components/DonutChart.tsx
deleted file mode 100644
index f4c1554400d..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/DonutChart.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { arc as d3Arc, pie as d3Pie, PieArcDatum } from 'd3-shape';
-
-export interface DataPoint {
- fill: string;
- value: number;
-}
-
-export interface DonutChartProps {
- 'aria-hidden'?: boolean | 'true' | 'false';
- 'aria-label'?: string;
- cornerRadius?: number;
- data: DataPoint[];
- height: number;
- minPercent?: number;
- padAngle?: number;
- padding?: [number, number, number, number];
- thickness: number;
- width: number;
-}
-
-export function DonutChart(props: Readonly<DonutChartProps>) {
- const {
- height,
- cornerRadius,
- minPercent = 0,
- padding = [0, 0, 0, 0],
- width,
- padAngle,
- data,
- thickness,
- ...rest
- } = props;
-
- const availableWidth = width - padding[1] - padding[3];
- const availableHeight = height - padding[0] - padding[2];
-
- const size = Math.min(availableWidth, availableHeight);
- const radius = Math.floor(size / 2);
-
- const total = data.reduce((acc, d) => acc + d.value, 0);
-
- const pie = d3Pie<any, DataPoint>()
- .sort(null)
- .value((d) => Math.max(d.value, (total / 100) * minPercent));
-
- if (padAngle !== undefined) {
- pie.padAngle(padAngle);
- }
-
- const sectors = pie(data).map((d, i) => {
- return (
- <Sector
- cornerRadius={cornerRadius}
- data={d}
- fill={data[i].fill}
- key={i}
- radius={radius}
- thickness={thickness}
- />
- );
- });
-
- return (
- <svg className="donut-chart" height={height} width={width} {...rest}>
- <g transform={`translate(${padding[3]}, ${padding[0]})`}>
- <g transform={`translate(${radius}, ${radius})`}>{sectors}</g>
- </g>
- </svg>
- );
-}
-
-interface SectorProps {
- cornerRadius?: number;
- data: PieArcDatum<DataPoint>;
- fill: string;
- radius: number;
- thickness: number;
-}
-
-function Sector(props: Readonly<SectorProps>) {
- const arc = d3Arc<any, PieArcDatum<DataPoint>>()
- .outerRadius(props.radius)
- .innerRadius(props.radius - props.thickness);
-
- if (props.cornerRadius) {
- arc.cornerRadius(props.cornerRadius);
- }
- const d = arc(props.data) as string;
- return <path d={d} style={{ fill: props.fill }} />;
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/Dropdown.tsx b/server/sonar-web/src/main/js/design-system/components/Dropdown.tsx
deleted file mode 100644
index bdfe49daac6..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Dropdown.tsx
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React from 'react';
-import { PopupPlacement, PopupZLevel } from '../helpers/positioning';
-import { InputSizeKeys } from '../types/theme';
-import { DropdownMenu } from './DropdownMenu';
-import { DropdownToggler } from './DropdownToggler';
-
-type OnClickCallback = (event?: React.MouseEvent<HTMLElement>) => void;
-type A11yAttrs = Pick<React.AriaAttributes, 'aria-controls' | 'aria-expanded' | 'aria-haspopup'> & {
- id: string;
- role: React.AriaRole;
-};
-interface RenderProps {
- a11yAttrs: A11yAttrs;
- closeDropdown: VoidFunction;
- onToggleClick: OnClickCallback;
- open: boolean;
-}
-
-interface Props {
- allowResizing?: boolean;
- children:
- | ((renderProps: Readonly<RenderProps>) => JSX.Element)
- | React.ReactElement<{ onClick: OnClickCallback }>;
- className?: string;
- closeOnClick?: boolean;
- id: string;
- onClose?: VoidFunction;
- onOpen?: VoidFunction;
- openDropdown?: boolean;
- overlay: React.ReactNode;
- placement?: PopupPlacement;
- size?: InputSizeKeys;
- withClickOutHandler?: boolean;
- withFocusOutHandler?: boolean;
- zLevel?: PopupZLevel;
-}
-
-interface State {
- open: boolean;
-}
-
-/** @deprecated Use DropdownMenu.Root and other DropdownMenu.* elements from Echoes instead.
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3354918914/DropdownMenus | Migration Guide}
- */
-export class Dropdown extends React.PureComponent<Readonly<Props>, State> {
- state: State = { open: false };
-
- componentDidUpdate(props: Readonly<Props>, prevState: State) {
- if (!prevState.open && this.state.open && this.props.onOpen) {
- this.props.onOpen();
- }
- if (
- props.openDropdown !== this.props.openDropdown &&
- typeof this.props.openDropdown === 'boolean'
- ) {
- this.setState({ open: this.props.openDropdown });
- }
- }
-
- handleClose = () => {
- this.setState({ open: false });
- if (this.props.onClose) {
- this.props.onClose();
- }
- };
-
- handleToggleClick: OnClickCallback = (event) => {
- if (event) {
- event.preventDefault();
- event.currentTarget.blur();
- }
- this.setState((state) => ({ open: !state.open }));
- };
-
- render() {
- const { open } = this.state;
- const { allowResizing, className, closeOnClick = true, id, size = 'full', zLevel } = this.props;
- const a11yAttrs: A11yAttrs = {
- 'aria-controls': `${id}-dropdown`,
- 'aria-expanded': open,
- 'aria-haspopup': 'menu',
- id: `${id}-trigger`,
- role: 'button',
- };
-
- const children = React.isValidElement(this.props.children)
- ? React.cloneElement(this.props.children, { onClick: this.handleToggleClick, ...a11yAttrs })
- : this.props.children({
- a11yAttrs,
- closeDropdown: this.handleClose,
- onToggleClick: this.handleToggleClick,
- open,
- });
-
- return (
- <DropdownToggler
- allowResizing={allowResizing}
- aria-labelledby={`${id}-trigger`}
- className={className}
- id={`${id}-dropdown`}
- onRequestClose={this.handleClose}
- open={open}
- overlay={
- <DropdownMenu onClick={closeOnClick ? this.handleClose : undefined} size={size}>
- {this.props.overlay}
- </DropdownMenu>
- }
- placement={this.props.placement}
- withClickOutHandler={this.props.withClickOutHandler}
- withFocusOutHandler={this.props.withFocusOutHandler}
- zLevel={zLevel}
- >
- {children}
- </DropdownToggler>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/DropdownMenu.tsx b/server/sonar-web/src/main/js/design-system/components/DropdownMenu.tsx
deleted file mode 100644
index 1251298bfcb..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/DropdownMenu.tsx
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { css } from '@emotion/react';
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import React, { ForwardedRef, forwardRef } from 'react';
-import tw from 'twin.macro';
-import { INPUT_SIZES } from '../helpers/constants';
-import { themeColor, themeContrast } from '../helpers/theme';
-import { InputSizeKeys, ThemedProps } from '../types/theme';
-import { BaseLink, LinkProps } from './Link';
-import NavLink from './NavLink';
-import { Tooltip } from './Tooltip';
-import { useCopyClipboardEffect } from './clipboard';
-import { Checkbox } from './input/Checkbox';
-
-interface Props extends React.HtmlHTMLAttributes<HTMLMenuElement> {
- children?: React.ReactNode;
- className?: string;
- innerRef?: React.Ref<HTMLUListElement>;
- maxHeight?: string;
- size?: InputSizeKeys;
-}
-
-/** @deprecated Use DropdownMenu.Root and other DropdownMenu.* elements from Echoes instead.
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3354918914/DropdownMenus | Migration Guide}
- */
-export function DropdownMenu({
- children,
- className,
- innerRef,
- maxHeight = 'inherit',
- size = 'small',
- ...menuProps
-}: Readonly<Props>) {
- return (
- <DropdownMenuWrapper
- className={classNames('dropdown-menu', className)}
- ref={innerRef}
- role="menu"
- style={{ '--inputSize': INPUT_SIZES[size], maxHeight }}
- {...menuProps}
- >
- {children}
- </DropdownMenuWrapper>
- );
-}
-
-interface ListItemProps {
- children?: React.ReactNode;
- className?: string;
- innerRef?: React.Ref<HTMLLIElement>;
- onFocus?: VoidFunction;
- onPointerEnter?: VoidFunction;
- onPointerLeave?: VoidFunction;
- selected?: boolean;
-}
-
-type ItemLinkProps = Omit<ListItemProps, 'innerRef'> &
- Pick<LinkProps, 'disabled' | 'icon' | 'isExternal' | 'onClick' | 'to'> & {
- innerRef?: React.Ref<HTMLAnchorElement>;
- };
-
-/** @deprecated Use DropdownMenu.Root and other DropdownMenu.* elements from Echoes instead.
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3354918914/DropdownMenus | Migration Guide}
- */
-export function ItemLink(props: ItemLinkProps) {
- const {
- children,
- className,
- disabled,
- icon,
- isExternal,
- onClick,
- selected,
- innerRef,
- to,
- ...liProps
- } = props;
- return (
- <li {...liProps}>
- <ItemLinkStyled
- className={classNames(className, { disabled, selected })}
- disabled={disabled}
- icon={icon}
- isExternal={isExternal}
- onClick={onClick}
- ref={innerRef}
- role="menuitem"
- showExternalIcon={false}
- to={to}
- >
- {children}
- </ItemLinkStyled>
- </li>
- );
-}
-
-interface ItemNavLinkProps extends ItemLinkProps {
- end?: boolean;
-}
-
-/** @deprecated Use DropdownMenu.Root and other DropdownMenu.* elements from Echoes instead.
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3354918914/DropdownMenus | Migration Guide}
- */
-export function ItemNavLink(props: ItemNavLinkProps) {
- const { children, className, disabled, end, icon, onClick, selected, innerRef, to, ...liProps } =
- props;
- return (
- <li {...liProps}>
- <ItemNavLinkStyled
- className={classNames(className, { disabled, selected })}
- disabled={disabled}
- end={end}
- onClick={onClick}
- ref={innerRef}
- role="menuitem"
- to={to}
- >
- {icon}
- {children}
- </ItemNavLinkStyled>
- </li>
- );
-}
-
-interface ItemButtonProps extends ListItemProps {
- disabled?: boolean;
- icon?: React.ReactNode;
- onClick: React.MouseEventHandler<HTMLButtonElement>;
-}
-
-/** @deprecated Use DropdownMenu.Root and other DropdownMenu.* elements from Echoes instead.
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3354918914/DropdownMenus | Migration Guide}
- */
-export const ItemButton = forwardRef(
- (props: ItemButtonProps, ref: ForwardedRef<HTMLButtonElement>) => {
- const { children, className, disabled, icon, innerRef, onClick, selected, ...liProps } = props;
- return (
- <li ref={innerRef} role="none" {...liProps}>
- <ItemButtonStyled
- className={classNames(className, { disabled, selected })}
- disabled={disabled}
- onClick={onClick}
- ref={ref}
- role="menuitem"
- >
- {icon}
- {children}
- </ItemButtonStyled>
- </li>
- );
- },
-);
-ItemButton.displayName = 'ItemButton';
-
-export const ItemDangerButton = styled(ItemButton)`
- --color: ${themeContrast('dropdownMenuDanger')};
-`;
-
-interface ItemCheckboxProps extends ListItemProps {
- checked: boolean;
- disabled?: boolean;
- id?: string;
- label?: string;
- onCheck: (checked: boolean, id?: string) => void;
-}
-
-export function ItemCheckbox(props: ItemCheckboxProps) {
- const {
- checked,
- children,
- className,
- disabled,
- id,
- innerRef,
- label,
- onCheck,
- onFocus,
- ...liProps
- } = props;
- return (
- <li ref={innerRef} role="none" {...liProps}>
- <ItemCheckboxStyled
- checked={checked}
- className={classNames(className, { disabled })}
- disabled={disabled}
- id={id}
- label={label}
- onCheck={onCheck}
- onFocus={onFocus}
- >
- {children}
- </ItemCheckboxStyled>
- </li>
- );
-}
-
-interface ItemCopyProps {
- children?: React.ReactNode;
- className?: string;
- copyValue: string;
- tooltipOverlay: React.ReactNode;
-}
-
-export function ItemCopy(props: ItemCopyProps) {
- const { children, className, copyValue, tooltipOverlay } = props;
-
- const [copySuccess, handleCopy] = useCopyClipboardEffect(copyValue);
-
- return (
- <Tooltip content={tooltipOverlay} visible={copySuccess}>
- <li role="none">
- <ItemButtonStyled className={className} onClick={handleCopy} role="menuitem">
- {children}
- </ItemButtonStyled>
- </li>
- </Tooltip>
- );
-}
-
-interface ItemDownloadProps extends ListItemProps {
- download: string;
- href: string;
-}
-
-export function ItemDownload(props: ItemDownloadProps) {
- const { children, className, download, href, innerRef, ...liProps } = props;
- return (
- <li ref={innerRef} role="none" {...liProps}>
- <ItemDownloadStyled
- className={className}
- download={download}
- href={href}
- rel="noopener noreferrer"
- role="menuitem"
- target="_blank"
- >
- {children}
- </ItemDownloadStyled>
- </li>
- );
-}
-
-export const ItemHeaderHighlight = styled.span`
- color: ${themeContrast('searchHighlight')};
- font-weight: 600;
-`;
-
-/** @deprecated Use DropdownMenu.Root and other DropdownMenu.* elements from Echoes instead.
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3354918914/DropdownMenus | Migration Guide}
- */
-export const ItemHeader = styled(UnstyledItemHeader)`
- background-color: ${themeColor('dropdownMenuHeader')};
- color: var(--echoes-color-text-subdued);
-
- ${tw`sw-py-2 sw-px-3`}
-`;
-
-function UnstyledItemHeader({
- children,
- className = 'dropdown-menu-header',
- role = 'menuitem',
- ...props
-}: Readonly<React.HtmlHTMLAttributes<HTMLLIElement>>) {
- return (
- <li className={className} role={role} {...props}>
- {children}
- </li>
- );
-}
-
-/** @deprecated Use DropdownMenu.Root and other DropdownMenu.* elements from Echoes instead.
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3354918914/DropdownMenus | Migration Guide}
- */
-export const ItemDivider = styled(UnstyledItemDivider)`
- height: 1px;
- background-color: ${themeColor('popupBorder')};
-
- ${tw`sw-my-1 sw--mx-2`}
- ${tw`sw-overflow-hidden`};
-`;
-
-function UnstyledItemDivider({
- children,
- role = 'separator',
- ...props
-}: Readonly<React.HtmlHTMLAttributes<HTMLLIElement>>) {
- return (
- <li role={role} {...props}>
- {children}
- </li>
- );
-}
-
-export const DropdownMenuWrapper = styled.ul`
- background-color: ${themeColor('dropdownMenu')};
- color: ${themeContrast('dropdownMenu')};
- width: var(--inputSize);
- list-style: none;
-
- ${tw`sw-flex sw-flex-col`}
- ${tw`sw-box-border`};
- ${tw`sw-min-w-input-small`}
- ${tw`sw-py-2`}
- ${tw`sw-typo-default`}
-
- &:focus {
- outline: none;
- }
-`;
-
-const itemStyle = (props: ThemedProps) => css`
- color: var(--color);
- background-color: ${themeColor('dropdownMenu')(props)};
- border: none;
- border-bottom: none;
- text-decoration: none;
- transition: none;
-
- ${tw`sw-flex sw-items-center`}
- ${tw`sw-typo-default`}
- ${tw`sw-box-border`}
- ${tw`sw-w-full`}
- ${tw`sw-text-left`}
- ${tw`sw-py-2 sw-px-3`}
- ${tw`sw-truncate`};
- ${tw`sw-cursor-pointer`}
-
- &.active,
- &:active,
- &.active:active,
- &:hover,
- &.active:hover {
- color: var(--color);
- background-color: ${themeColor('dropdownMenuHover')(props)};
- text-decoration: none;
- outline: none;
- border: none;
- border-bottom: none;
- }
-
- &:focus,
- &:focus-within,
- &.active:focus,
- &.active:focus-within {
- color: var(--color);
- background-color: ${themeColor('dropdownMenuFocus')(props)};
- text-decoration: none;
- border: none;
- border-bottom: none;
- }
-
- &:focus-visible {
- borderLeft: '2px solid var(--echoes-color-focus-default)',
- marginLeft: '-2px',
- }
-
- &:disabled,
- &.disabled {
- color: var(--echoes-color-text-disabled);
- background-color: ${themeColor('dropdownMenuDisabled')(props)};
- pointer-events: none !important;
-
- ${tw`sw-cursor-not-allowed`};
- }
-
- &.selected {
- background-color: ${themeColor('selectOptionSelected')(props)};
- }
-
- & > svg {
- ${tw`sw-mr-2`}
- }
-`;
-
-const ItemNavLinkStyled = styled(NavLink)`
- --color: ${themeContrast('dropdownMenu')};
- ${itemStyle};
-`;
-
-const ItemLinkStyled = styled(BaseLink)`
- --color: ${themeContrast('dropdownMenu')};
- ${itemStyle}
-`;
-
-const ItemButtonStyled = styled.button`
- --color: ${themeContrast('dropdownMenu')};
- ${itemStyle}
-`;
-
-const ItemDownloadStyled = styled.a`
- --color: ${themeContrast('dropdownMenu')};
- ${itemStyle}
-`;
-
-const ItemCheckboxStyled = styled(Checkbox)`
- --color: ${themeContrast('dropdownMenu')};
- ${itemStyle}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/DropdownToggler.tsx b/server/sonar-web/src/main/js/design-system/components/DropdownToggler.tsx
deleted file mode 100644
index ead84fb690c..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/DropdownToggler.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import EscKeydownHandler from './EscKeydownHandler';
-import { FocusOutHandler } from './FocusOutHandler';
-import { OutsideClickHandler } from './OutsideClickHandler';
-import { Popup } from './popups';
-
-type PopupProps = Popup['props'];
-
-interface Props extends PopupProps {
- onRequestClose: VoidFunction;
- open: boolean;
- withClickOutHandler?: boolean;
- withFocusOutHandler?: boolean;
-}
-
-/** @deprecated Use DropdownMenu.Root and other DropdownMenu.* elements from Echoes instead.
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3354918914/DropdownMenus | Migration Guide}
- */
-export function DropdownToggler(props: Props) {
- const {
- children,
- open,
- onRequestClose,
- withClickOutHandler = true,
- withFocusOutHandler = true,
- overlay,
- ...popupProps
- } = props;
-
- let finalOverlay = <EscKeydownHandler onKeydown={onRequestClose}>{overlay}</EscKeydownHandler>;
-
- if (withFocusOutHandler) {
- finalOverlay = <FocusOutHandler onFocusOut={onRequestClose}>{finalOverlay}</FocusOutHandler>;
- }
-
- if (withClickOutHandler) {
- finalOverlay = (
- <OutsideClickHandler onClickOutside={onRequestClose}>{finalOverlay}</OutsideClickHandler>
- );
- }
-
- return (
- <Popup overlay={open && finalOverlay} {...popupProps}>
- {children}
- </Popup>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/DuplicationsIndicator.tsx b/server/sonar-web/src/main/js/design-system/components/DuplicationsIndicator.tsx
deleted file mode 100644
index a98399e2e23..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/DuplicationsIndicator.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../helpers/theme';
-import { isDefined } from '../helpers/types';
-import { DuplicationEnum, DuplicationLabel } from '../types/measures';
-import { NoDataIcon } from './icons';
-
-interface Props {
- 'aria-hidden'?: boolean | 'true' | 'false';
- 'aria-label'?: string;
- rating?: DuplicationLabel;
- size?: 'xs' | 'sm' | 'md';
-}
-
-const SIZE_TO_PX_MAPPING = { xs: 16, sm: 24, md: 36 };
-
-export function DuplicationsIndicator({ size = 'sm', rating, ...rest }: Readonly<Props>) {
- const theme = useTheme();
- const sizePX = SIZE_TO_PX_MAPPING[size];
-
- if (rating === undefined) {
- return <NoDataIcon size={size} />;
- }
-
- const primaryColor = themeColor(`duplicationsIndicator.${rating}`)({ theme });
- const secondaryColor = themeColor('duplicationsIndicatorSecondary')({ theme });
-
- return (
- <RatingSVG
- primaryColor={primaryColor}
- rating={rating}
- secondaryColor={secondaryColor}
- size={sizePX}
- {...rest}
- />
- );
-}
-
-interface SVGProps {
- 'aria-hidden'?: boolean | 'true' | 'false';
- 'aria-label'?: string;
- primaryColor: string;
- rating: DuplicationLabel;
- secondaryColor: string;
- size: number;
-}
-
-function RatingSVG({ primaryColor, rating, secondaryColor, size, ...rest }: Readonly<SVGProps>) {
- return (
- <svg height={size} viewBox="0 0 16 16" width={size} {...rest}>
- <circle cx="8" cy="8" fill={primaryColor} r="2" />
- {isDefined(rating) &&
- {
- [DuplicationEnum.A]: (
- <>
- <path
- clipRule="evenodd"
- d="M8 14c3.3137 0 6-2.6863 6-6 0-3.31371-2.6863-6-6-6-3.31371 0-6 2.68629-6 6 0 3.3137 2.68629 6 6 6Zm0 2c4.4183 0 8-3.5817 8-8 0-4.41828-3.5817-8-8-8-4.41828 0-8 3.58172-8 8 0 4.4183 3.58172 8 8 8Z"
- fill={secondaryColor}
- fillRule="evenodd"
- />
- <circle cx="8" cy="8" fill={primaryColor} r="2" />
- </>
- ),
- [DuplicationEnum.B]: (
- <>
- <path
- clipRule="evenodd"
- d="M8 14c3.3137 0 6-2.6863 6-6 0-3.31371-2.6863-6-6-6-3.31371 0-6 2.68629-6 6 0 3.3137 2.68629 6 6 6Zm0 2c4.4183 0 8-3.5817 8-8 0-4.41828-3.5817-8-8-8-4.41828 0-8 3.58172-8 8 0 4.4183 3.58172 8 8 8Z"
- fill={secondaryColor}
- fillRule="evenodd"
- />
- <path
- d="M8 0c.81879 0 1.63272.125698 2.4134.372702L9.81002 2.27953A5.99976 5.99976 0 0 0 8 2V0Z"
- fill={primaryColor}
- />
- </>
- ),
- [DuplicationEnum.C]: (
- <>
- <path
- clipRule="evenodd"
- d="M8 14c3.3137 0 6-2.6863 6-6 0-3.31371-2.6863-6-6-6-3.31371 0-6 2.68629-6 6 0 3.3137 2.68629 6 6 6Zm0 2c4.4183 0 8-3.5817 8-8 0-4.41828-3.5817-8-8-8-4.41828 0-8 3.58172-8 8 0 4.4183 3.58172 8 8 8Z"
- fill={secondaryColor}
- fillRule="evenodd"
- />
- <path
- d="M8 0c1.89071 2e-8 3.7203.669649 5.1643 1.89017l-1.2911 1.52746C10.7902 2.50224 9.41803 2 8 2V0Z"
- fill={primaryColor}
- />
- </>
- ),
- [DuplicationEnum.D]: (
- <>
- <path
- clipRule="evenodd"
- d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z"
- fill={secondaryColor}
- fillRule="evenodd"
- />
- <path
- d="M8 0a7.9999 7.9999 0 0 1 4.5815 1.44181 7.99949 7.99949 0 0 1 2.9301 3.80574l-1.8779.68811A6.00009 6.00009 0 0 0 8 2V0Z"
- fill={primaryColor}
- />
- </>
- ),
- [DuplicationEnum.E]: (
- <>
- <path
- clipRule="evenodd"
- d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z"
- fill={secondaryColor}
- fillRule="evenodd"
- />
- <path
- d="M8 0a8 8 0 0 1 5.0686 1.81054 8.00033 8.00033 0 0 1 2.7744 4.61211l-1.9608.39434a5.99958 5.99958 0 0 0-2.0808-3.45908A5.99972 5.99972 0 0 0 8 2V0Z"
- fill={primaryColor}
- />
- </>
- ),
- [DuplicationEnum.F]: (
- <>
- <path
- clipRule="evenodd"
- d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z"
- fill={secondaryColor}
- fillRule="evenodd"
- />
- <path
- d="M8 0a8.0002 8.0002 0 0 1 5.6569 13.6569l-1.4143-1.4143a5.9993 5.9993 0 0 0 1.3007-6.5387A5.9999 5.9999 0 0 0 8 2V0Z"
- fill={primaryColor}
- />
- </>
- ),
- }[rating]}
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/EscKeydownHandler.tsx b/server/sonar-web/src/main/js/design-system/components/EscKeydownHandler.tsx
deleted file mode 100644
index c2609e72c69..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/EscKeydownHandler.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React from 'react';
-import { Key } from '../helpers/keyboard';
-
-interface Props {
- children: React.ReactNode;
- onKeydown: () => void;
-}
-
-export default class EscKeydownHandler extends React.Component<Props> {
- componentDidMount() {
- setTimeout(() => {
- document.addEventListener('keydown', this.handleKeyDown, false);
- }, 0);
- }
-
- componentWillUnmount() {
- document.removeEventListener('keydown', this.handleKeyDown, false);
- }
-
- handleKeyDown = (event: KeyboardEvent) => {
- if (event.code === Key.Escape) {
- this.props.onKeydown();
- }
- };
-
- render() {
- return this.props.children;
- }
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/ExecutionFlowAccordion.tsx b/server/sonar-web/src/main/js/design-system/components/ExecutionFlowAccordion.tsx
deleted file mode 100644
index 28510140db9..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/ExecutionFlowAccordion.tsx
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { ReactNode } from 'react';
-import tw from 'twin.macro';
-import { themeBorder, themeColor, themeContrast } from '../helpers/theme';
-import { BareButton } from '../sonar-aligned/components/buttons';
-import { OpenCloseIndicator } from './icons/OpenCloseIndicator';
-
-interface Props {
- children: ReactNode;
- expanded?: boolean;
- header: ReactNode;
- hidden?: boolean;
- id: string;
- innerRef?: (node: HTMLDivElement) => void;
- onClick?: () => void;
-}
-
-export function ExecutionFlowAccordion(props: Readonly<Props>) {
- const { children, expanded, header, hidden, id, innerRef, onClick } = props;
-
- return (
- <Accordion className={classNames({ expanded, 'sw-hidden': hidden })} ref={innerRef}>
- <Expander
- aria-controls={`${id}-flow-accordion`}
- aria-expanded={expanded}
- aria-hidden={hidden}
- id={`${id}-flow-accordion-button`}
- onClick={onClick}
- >
- {header}
- <OpenCloseIndicator open={Boolean(expanded)} />
- </Expander>
-
- {expanded && <Body id={`${id}-flow-accordion-body`}>{children}</Body>}
- </Accordion>
- );
-}
-
-const Expander = styled(BareButton)`
- ${tw`sw-flex sw-items-center sw-justify-between`}
- ${tw`sw-box-border`}
- ${tw`sw-p-2`}
- ${tw`sw-w-full`}
- ${tw`sw-cursor-pointer`}
-
- color: ${themeContrast('subnavigationExecutionFlow')};
- background-color: ${themeColor('subnavigationExecutionFlow')};
-`;
-
-const Accordion = styled.div`
- ${tw`sw-flex sw-flex-col`}
- ${tw`sw-rounded-1/2`}
-
- border: ${themeBorder('default', 'subnavigationExecutionFlowBorder')};
-
- &:hover {
- border: ${themeBorder('default', 'subnavigationExecutionFlowActive')};
- }
-
- &.expanded {
- border: ${themeBorder('default', 'subnavigationExecutionFlowActive')};
- outline: ${themeBorder('focus', 'primary')};
-
- ${Expander} {
- border-bottom: ${themeBorder('default', 'subnavigationExecutionFlowBorder')};
- }
- }
-`;
-
-const Body = styled.div`
- ${tw`sw-p-2`}
-
- background-color: ${themeColor('subnavigationExecutionFlow')};
-`;
-
-ExecutionFlowAccordion.displayName = 'ExecutionFlowAccordion';
diff --git a/server/sonar-web/src/main/js/design-system/components/FacetBox.tsx b/server/sonar-web/src/main/js/design-system/components/FacetBox.tsx
deleted file mode 100644
index 898b19d67fc..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/FacetBox.tsx
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { ButtonIcon, ButtonSize, ButtonVariety, IconX, Text } from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import { uniqueId } from 'lodash';
-import * as React from 'react';
-import { useIntl } from 'react-intl';
-import tw from 'twin.macro';
-import { themeColor } from '../helpers';
-import { BareButton } from '../sonar-aligned/components/buttons';
-import { Badge } from './Badge';
-import { Spinner } from './Spinner';
-import { Tooltip as SCTooltip } from './Tooltip';
-import { OpenCloseIndicator } from './icons';
-
-export interface FacetBoxProps {
- ariaLabel?: string;
- children: React.ReactNode;
- className?: string;
- clearIconLabel?: string;
- count?: number;
- countLabel?: string;
- 'data-property'?: string;
- disabled?: boolean;
- disabledHelper?: string;
- hasEmbeddedFacets?: boolean;
- help?: React.ReactNode;
- id?: string;
- inner?: boolean;
- loading?: boolean;
- name: string;
- onClear?: () => void;
- onClick?: (isOpen: boolean) => void;
- open?: boolean;
- secondLine?: string;
- tooltipComponent?: React.ComponentType<React.PropsWithChildren<{ content: React.ReactNode }>>;
-}
-
-export function FacetBox(props: FacetBoxProps) {
- const {
- ariaLabel,
- children,
- className,
- clearIconLabel,
- count,
- countLabel,
- 'data-property': dataProperty,
- disabled = false,
- disabledHelper,
- secondLine,
- hasEmbeddedFacets = false,
- help,
- id: idProp,
- inner = false,
- loading = false,
- name,
- onClear,
- onClick,
- open = false,
- tooltipComponent,
- } = props;
- const intl = useIntl();
-
- const clearable = !disabled && Boolean(onClear) && count !== undefined && count > 0;
- const counter = count ?? 0;
- const expandable = !disabled && Boolean(onClick);
- const id = React.useMemo(() => idProp ?? uniqueId('filter-facet-'), [idProp]);
- const Tooltip = tooltipComponent ?? SCTooltip;
-
- return (
- <Accordion
- className={classNames(className, { open })}
- data-property={dataProperty}
- hasEmbeddedFacets={hasEmbeddedFacets}
- inner={inner}
- >
- <Header>
- <div className="sw-flex sw-items-center">
- <TitleWithHelp>
- <ChevronAndTitle
- aria-controls={`${id}-panel`}
- aria-disabled={!expandable}
- aria-expanded={open}
- aria-label={ariaLabel ?? name}
- expandable={expandable}
- id={`${id}-header`}
- onClick={() => {
- if (!disabled) {
- onClick?.(!open);
- }
- }}
- >
- {expandable && <OpenCloseIndicator aria-hidden open={open} />}
-
- {disabled ? (
- <Tooltip content={disabledHelper}>
- <HeaderTitle
- aria-disabled
- aria-label={`${name}, ${disabledHelper ?? ''}`}
- disabled={disabled}
- >
- {name}
- </HeaderTitle>
- </Tooltip>
- ) : (
- <div>
- <HeaderTitle>{name}</HeaderTitle>
- {secondLine !== undefined && (
- <Text as="div" isSubdued>
- {secondLine}
- </Text>
- )}
- </div>
- )}
- </ChevronAndTitle>
- </TitleWithHelp>
- {help && <span className="sw-ml-1">{help}</span>}
- </div>
-
- {<Spinner loading={loading} />}
-
- {counter > 0 && (
- <BadgeAndIcons>
- <Badge className="sw-px-2" title={countLabel} variant="counter">
- {counter}
- </Badge>
-
- {Boolean(clearable) && (
- <Tooltip content={clearIconLabel}>
- <ButtonIcon
- variety={ButtonVariety.DefaultGhost}
- ariaLabel={
- clearIconLabel ?? intl.formatMessage({ id: 'clear_x_filter' }, { '0': name })
- }
- data-testid={`clear-${name}`}
- onClick={onClear}
- Icon={IconX}
- size={ButtonSize.Medium}
- />
- </Tooltip>
- )}
- </BadgeAndIcons>
- )}
- </Header>
-
- {open && (
- <div aria-labelledby={`${id}-header`} id={`${id}-panel`} role="group">
- {children}
- </div>
- )}
- </Accordion>
- );
-}
-
-FacetBox.displayName = 'FacetBox'; // so that tests don't see the obfuscated production name
-
-const Accordion = styled.div<{
- hasEmbeddedFacets?: boolean;
- inner?: boolean;
-}>`
- ${tw`sw-flex-col`};
- ${tw`sw-flex`};
- ${tw`sw-gap-3`};
-
- ${({ hasEmbeddedFacets }) => (hasEmbeddedFacets ? tw`sw-gap-0` : '')};
-
- ${({ inner }) => (inner ? tw`sw-gap-1 sw-ml-3 sw-mt-1` : '')};
-`;
-
-const BadgeAndIcons = styled.div`
- ${tw`sw-flex`};
- ${tw`sw-items-center`};
- ${tw`sw-gap-2`};
-`;
-
-const TitleWithHelp = styled.div`
- ${tw`sw-flex`};
- ${tw`sw-items-center`};
-`;
-
-const ChevronAndTitle = styled(BareButton)<{
- expandable?: boolean;
-}>`
- ${tw`sw-flex`};
- ${tw`sw-gap-1`};
- ${tw`sw-h-9`};
- ${tw`sw-items-center`};
-
- cursor: ${({ expandable }) => (expandable ? 'pointer' : 'default')};
-
- &:focus-visible {
- background: transparent;
- outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
- outline-offset: 4px;
- border-radius: var(--echoes-border-radius-200);
- }
-`;
-
-const Header = styled.div`
- ${tw`sw-flex`};
- ${tw`sw-gap-3`};
- ${tw`sw-items-center`};
- ${tw`sw-justify-between`};
-`;
-
-const HeaderTitle = styled.span<{
- disabled?: boolean;
-}>`
- ${tw`sw-typo-semibold`};
-
- color: ${({ disabled }) =>
- disabled ? 'var(--echoes-color-text-disabled)' : themeColor('facetHeader')};
-
- cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'inherit')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/FacetItem.tsx b/server/sonar-web/src/main/js/design-system/components/FacetItem.tsx
deleted file mode 100644
index 84ce1aa0920..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/FacetItem.tsx
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import * as React from 'react';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../helpers';
-import { isDefined } from '../helpers/types';
-import { ButtonProps, ButtonSecondary } from '../sonar-aligned/components/buttons';
-
-export type FacetItemProps = Omit<ButtonProps, 'name' | 'onClick'> & {
- active?: boolean;
- /** Disable the item if its value is 0. True by default. */
- disableZero?: boolean;
- name: string | React.ReactNode;
- onClick: (x: string, multiple?: boolean) => void;
- small?: boolean;
- stat?: React.ReactNode;
- statBarPercent?: number;
- /** Textual version of `name` */
- tooltip?: string;
- value: string;
-};
-
-const STATBAR_MAX_WIDTH = 60;
-
-export function BaseFacetItem({
- active = false,
- className,
- disabled: disabledProp = false,
- disableZero = true,
- icon,
- name,
- onClick,
- small,
- stat,
- statBarPercent,
- tooltip,
- value,
-}: FacetItemProps) {
- // alow an active facet to be disabled even if it now has a "0" stat
- // (it was activated when a different value of My issues/All/New code was selected)
- const disabled = disabledProp || (disableZero && !active && stat !== undefined && stat === 0);
-
- const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
- event.preventDefault();
-
- onClick(value, event.ctrlKey || event.metaKey);
- };
-
- return (
- <StyledItem active={active} className={classNames({ active }, className)} role="listitem">
- <StyledButton
- active={active}
- aria-checked={active}
- aria-label={typeof name === 'string' ? name : undefined}
- data-facet={value}
- disabled={disabled}
- icon={icon}
- onClick={handleClick}
- role="checkbox"
- small={small}
- title={tooltip}
- >
- <div className="container">
- <span className="name">{name}</span>
- <div>
- <span className="stat">{stat}</span>
- {isDefined(statBarPercent) && (
- <FacetStatBar>
- <FacetStatBarInner
- style={{ '--statBarWidth': `${statBarPercent * STATBAR_MAX_WIDTH}px` }}
- />
- </FacetStatBar>
- )}
- </div>
- </div>
- </StyledButton>
- </StyledItem>
- );
-}
-
-BaseFacetItem.displayName = 'FacetItem'; // so that tests don't see the obfuscated production name
-
-export const FacetItem = styled(BaseFacetItem)``;
-
-const StyledButton = styled(ButtonSecondary)<{ active?: boolean; small?: boolean }>`
- ${tw`sw-typo-default`};
- ${tw`sw-box-border`};
- ${tw`sw-h-7`};
- ${tw`sw-px-1`};
- ${tw`sw-rounded-1`};
- ${tw`sw-w-full`};
-
- ${({ small }) => (small ? tw`sw-typo-sm sw-pr-0` : '')};
-
- --background: ${({ active }) => (active ? themeColor('facetItemSelected') : 'transparent')};
- --backgroundHover: ${({ active }) => (active ? themeColor('facetItemSelected') : 'transparent')};
-
- --border: none;
-
- & div.container {
- ${tw`sw-container`};
- ${tw`sw-flex`};
- ${tw`sw-items-center`};
- ${tw`sw-justify-between`};
-
- & span.name {
- ${tw`sw-pr-1`};
- ${tw`sw-truncate`};
-
- & mark {
- background-color: ${themeColor('searchHighlight')};
- font-weight: 400;
- }
- }
-
- & span.stat {
- color: var(--echoes-color-text-subdued);
- }
- }
-
- &:disabled {
- background-color: transparent;
- border-color: transparent;
-
- & span.container span.stat {
- color: var(--echoes-color-text-disabled);
- }
-
- &:hover {
- background-color: transparent;
- border-color: transparent;
- }
- }
-`;
-
-/*&:hover {
- --border: ${themeBorder('default', 'facetItemSelectedBorder')};
- }*/
-
-const StyledItem = styled.span<{ active: boolean }>`
- border: ${({ active }) =>
- active
- ? themeBorder('default', 'facetItemSelectedBorder')
- : themeBorder('default', 'transparent')};
-
- border-radius: 0.25rem;
-
- &:hover,
- &:active,
- &:focus {
- border-color: ${themeColor('facetItemSelectedBorder')};
- }
-`;
-
-const FacetStatBar = styled.div`
- ${tw`sw-inline-block`}
- ${tw`sw-ml-2`}
-
- width: ${STATBAR_MAX_WIDTH}px;
-`;
-
-const FacetStatBarInner = styled.div`
- width: var(--statBarWidth);
- min-width: 5px;
- height: 10px;
- background-color: ${themeColor('facetItemGraph')};
- transition: width 0.3s ease;
-`;
-
-export const HighlightedFacetItems = styled.div`
- display: flex;
- flex-direction: column;
- width: 100%;
-
- ${FacetItem} {
- &:is(:hover, .active) {
- border-color: ${themeColor('facetItemSelectedBorder')};
- padding-bottom: 1px;
- border-bottom-width: 0;
- border-bottom-right-radius: 0rem;
- border-bottom-left-radius: 0rem;
-
- &:last-of-type {
- padding-bottom: 0;
- border-bottom-width: 1px;
- border-radius: 0.25rem;
- }
-
- & ~ ${FacetItem} {
- border-color: ${themeColor('facetItemSelectedBorder')};
- padding-bottom: 1px;
- padding-top: 1px;
- border-top-width: 0;
- border-bottom-width: 0;
- border-radius: 0;
- }
-
- & ~ ${FacetItem}:last-of-type {
- padding-bottom: 0;
- border-bottom-width: 1px;
- border-bottom-right-radius: 0.25rem;
- border-bottom-left-radius: 0.25rem;
- }
- }
-
- &.active {
- background-color: ${themeColor('facetItemSelected')};
-
- & ~ ${FacetItem} {
- background-color: ${themeColor('facetItemSelected')};
- }
-
- & ~ ${FacetItem}:hover, & ~ ${FacetItem}:hover ~ ${FacetItem} {
- background-color: ${themeColor('facetItemSelectedHover')};
- }
- }
-
- &.active ~ ${FacetItem}:hover, &:hover ~ ${FacetItem}.active {
- padding-top: 0;
- border-top-width: 1px;
- }
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/FailedQGConditionLink.tsx b/server/sonar-web/src/main/js/design-system/components/FailedQGConditionLink.tsx
deleted file mode 100644
index 31205dd1dd4..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/FailedQGConditionLink.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeColor } from '../helpers/theme';
-import { ButtonProps, DangerButtonSecondary } from '../sonar-aligned/components/buttons';
-import { ChevronRightIcon } from './icons/ChevronRightIcon';
-
-const StyledFailedQGConditionLink = styled(DangerButtonSecondary)`
- ${tw`sw-typo-default`}
- ${tw`sw-h-7`}
- ${tw`sw-pl-2`}
- ${tw`sw-pr-1`}
- ${tw`sw-py-0`}
- ${tw`sw-rounded-1/2`}
-
- &:active,
- &:focus,
- &:focus-visible,
- &:focus-within,
- &:hover,
- &:visited {
- border-bottom-color: ${themeColor('dangerButtonSecondaryBorder')};
- }
-`;
-
-export function FailedQGConditionLink({ children, ...props }: ButtonProps) {
- return (
- <StyledFailedQGConditionLink {...props}>
- {children}
- <ChevronRightIcon className="sw-ml-1 -sw-mr-1" />
- </StyledFailedQGConditionLink>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/FavoriteButton.tsx b/server/sonar-web/src/main/js/design-system/components/FavoriteButton.tsx
deleted file mode 100644
index 12264c9c07f..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/FavoriteButton.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import * as React from 'react';
-import { InteractiveIcon } from './InteractiveIcon';
-import { StarFillIcon, StarIcon } from './icons';
-
-interface Props {
- className?: string;
- favorite: boolean;
- innerRef?: React.Ref<HTMLButtonElement>;
- overlay: string;
- toggleFavorite: VoidFunction;
- tooltip?: React.ComponentType<React.PropsWithChildren<{ content: React.ReactNode }>>;
-}
-
-export function FavoriteButton(props: Props) {
- const { className, favorite, overlay, toggleFavorite, tooltip, innerRef } = props;
- const Tooltip = tooltip ?? React.Fragment;
-
- return (
- <Tooltip content={overlay}>
- <InteractiveIcon
- Icon={favorite ? StarFillIcon : StarIcon}
- aria-label={overlay}
- className={classNames('it__favorite-link', className, {
- 'it__is-filled': favorite,
- })}
- innerRef={innerRef}
- onClick={toggleFavorite}
- size="small"
- />
- </Tooltip>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/FlowStep.tsx b/server/sonar-web/src/main/js/design-system/components/FlowStep.tsx
deleted file mode 100644
index cf9c68832e9..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/FlowStep.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeColor } from '../helpers/theme';
-import { BaseLink } from './Link';
-import { LocationMarker, StyledMarker } from './LocationMarker';
-
-interface Props {
- additionalMarkers?: React.ReactNode;
- className?: string;
- message?: string;
- onClick?: () => void;
- selected: boolean;
- step?: number;
-}
-
-export function FlowStep(props: Props) {
- const { additionalMarkers, className, message, selected, step } = props;
-
- return (
- <StyledLink className={className} onClick={props.onClick} to={{}}>
- <>
- <LocationMarker selected={selected} text={step} />
- {additionalMarkers}
- </>
- <span>{message}</span>
- </StyledLink>
- );
-}
-
-const StyledLink = styled(BaseLink)`
- ${tw`sw-p-1 sw-rounded-1/2`}
- ${tw`sw-flex sw-items-center sw-flex-wrap sw-gap-2`}
- ${tw`sw-typo-default`}
-
- color: ${themeColor('pageContent')};
- border-bottom: none;
-
- &.selected,
- &:hover {
- background-color: ${themeColor('codeLineLocationSelected')};
- }
-
- &:hover ${StyledMarker} {
- background-color: ${themeColor('codeLineLocationMarkerSelected')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/FocusOutHandler.tsx b/server/sonar-web/src/main/js/design-system/components/FocusOutHandler.tsx
deleted file mode 100644
index ba0d7a2182d..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/FocusOutHandler.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-
-interface Props extends React.BaseHTMLAttributes<HTMLDivElement> {
- innerRef?: (instance: HTMLDivElement) => void;
- onFocusOut: () => void;
-}
-
-export class FocusOutHandler extends React.PureComponent<React.PropsWithChildren<Props>> {
- ref?: HTMLDivElement;
-
- componentDidMount() {
- setTimeout(() => {
- document.addEventListener('focusin', this.handleFocusOut);
- }, 0);
- }
-
- componentWillUnmount() {
- document.removeEventListener('focusin', this.handleFocusOut);
- }
-
- nodeRef = (node: HTMLDivElement) => {
- const { innerRef } = this.props;
- this.ref = node;
- innerRef?.(node);
- };
-
- handleFocusOut = () => {
- if (this.ref?.querySelector(':focus') === null) {
- this.props.onFocusOut();
- }
- };
-
- render() {
- const { onFocusOut, innerRef, children, ...props } = this.props;
- return (
- <div ref={this.nodeRef} {...props}>
- {children}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/HighlightRing.tsx b/server/sonar-web/src/main/js/design-system/components/HighlightRing.tsx
deleted file mode 100644
index af090074c86..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/HighlightRing.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeColor } from '../helpers';
-
-export const HighlightRing = styled.div`
- &.active {
- box-shadow: 0 0 4px 0 ${themeColor('primary')};
- background: ${themeColor('highlightRingBackground')};
- z-index: 1;
- ${tw`sw-rounded-1/2`}
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/HighlightedSection.tsx b/server/sonar-web/src/main/js/design-system/components/HighlightedSection.tsx
deleted file mode 100644
index e065c3063f4..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/HighlightedSection.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../helpers';
-
-export const HighlightedSection = styled.div`
- border: ${themeBorder('default', 'highlightedSectionBorder')};
- background: ${themeColor('highlightedSection')};
-
- ${tw`sw-box-border`}
- ${tw`sw-flex sw-flex-col`}
- ${tw`sw-gap-4`}
- ${tw`sw-p-8`}
- ${tw`sw-rounded-2`}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/Histogram.tsx b/server/sonar-web/src/main/js/design-system/components/Histogram.tsx
deleted file mode 100644
index 56e5ed029af..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Histogram.tsx
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable @typescript-eslint/prefer-optional-chain */
-import styled from '@emotion/styled';
-import { max } from 'd3-array';
-import { scaleBand, ScaleBand, scaleLinear, ScaleLinear } from 'd3-scale';
-import React from 'react';
-import tw from 'twin.macro';
-import { themeColor, themeContrast } from '../helpers';
-import { Tooltip, TooltipWrapper } from './Tooltip';
-
-interface Props {
- bars: number[];
- height: number;
- leftAlignTicks?: boolean;
- padding?: [number, number, number, number];
- width: number;
- yTicks?: string[];
- yTooltips?: string[];
- yValues?: string[];
-}
-
-const BAR_HEIGHT = 10;
-const DEFAULT_PADDING = [10, 10, 10, 10];
-
-type XScale = ScaleLinear<number, number>;
-type YScale = ScaleBand<number>;
-
-export class Histogram extends React.PureComponent<Props> {
- renderBar(d: number, index: number, xScale: XScale, yScale: YScale) {
- const { leftAlignTicks, padding = DEFAULT_PADDING } = this.props;
-
- const width = Math.round(xScale(d)) + /* minimum bar width */ 1;
- const x = xScale.range()[0] + (leftAlignTicks ? padding[3] : 0);
- const y = Math.round((yScale(index) ?? 0) + yScale.bandwidth() / 2);
-
- return <HistogramBar height={BAR_HEIGHT} width={width} x={x} y={y} />;
- }
-
- renderValue(d: number, index: number, xScale: XScale, yScale: YScale) {
- const { leftAlignTicks, padding = DEFAULT_PADDING, yValues } = this.props;
-
- const value = yValues && yValues[index];
-
- if (!value) {
- return null;
- }
-
- const x = xScale(d) + (leftAlignTicks ? padding[3] : 0);
- const y = Math.round((yScale(index) ?? 0) + yScale.bandwidth() / 2 + BAR_HEIGHT / 2);
-
- return (
- <Tooltip content={this.props.yTooltips && this.props.yTooltips[index]}>
- <HistogramTick dx="1em" dy="0.3em" textAnchor="start" x={x} y={y}>
- {value}
- </HistogramTick>
- </Tooltip>
- );
- }
-
- renderTick(index: number, xScale: XScale, yScale: YScale) {
- const { leftAlignTicks, yTicks } = this.props;
-
- const tick = yTicks && yTicks[index];
-
- if (!tick) {
- return null;
- }
-
- const x = xScale.range()[0];
- const y = Math.round((yScale(index) ?? 0) + yScale.bandwidth() / 2 + BAR_HEIGHT / 2);
-
- return (
- <HistogramTick
- dx={leftAlignTicks ? 0 : '-1em'}
- dy="0.3em"
- textAnchor={leftAlignTicks ? 'start' : 'end'}
- x={x}
- y={y}
- >
- {tick}
- </HistogramTick>
- );
- }
-
- renderBars(xScale: XScale, yScale: YScale) {
- return (
- <g>
- {this.props.bars.map((d, index) => (
- <g key={index}>
- {this.renderBar(d, index, xScale, yScale)}
- {this.renderValue(d, index, xScale, yScale)}
- {this.renderTick(index, xScale, yScale)}
- </g>
- ))}
- </g>
- );
- }
-
- render() {
- const { bars, height, leftAlignTicks, padding = DEFAULT_PADDING, width } = this.props;
-
- const availableWidth = width - padding[1] - padding[3];
- const xScale: XScale = scaleLinear()
- .domain([0, max(bars) ?? 0])
- .range([0, availableWidth]);
-
- const availableHeight = height - padding[0] - padding[2];
- const yScale: YScale = scaleBand<number>()
- .domain(bars.map((_, index) => index))
- .rangeRound([0, availableHeight]);
-
- return (
- <svg height={this.props.height} width={this.props.width}>
- <g transform={`translate(${leftAlignTicks ? 0 : padding[3]}, ${padding[0]})`}>
- {this.renderBars(xScale, yScale)}
- </g>
- </svg>
- );
- }
-}
-
-const HistogramTick = styled.text`
- ${tw`sw-typo-default`}
- fill: var(--echoes-color-text-subdued);
-
- ${TooltipWrapper} & {
- fill: ${themeContrast('primary')};
- }
-`;
-
-const HistogramBar = styled.rect`
- fill: ${themeColor('primary')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/HotspotRating.tsx b/server/sonar-web/src/main/js/design-system/components/HotspotRating.tsx
deleted file mode 100644
index 9ae63255288..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/HotspotRating.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { HotspotRatingEnum, HotspotRatingLabel } from '../types/measures';
-import { SeverityCriticalIcon, SeverityMajorIcon, SeverityMinorIcon } from './icons';
-
-interface Props extends React.AriaAttributes {
- className?: string;
- rating?: HotspotRatingLabel;
-}
-
-export function HotspotRating({ className, rating = HotspotRatingEnum.LOW, ...rest }: Props) {
- const ratings = {
- [HotspotRatingEnum.HIGH]: HotspotRatingHigh,
- [HotspotRatingEnum.MEDIUM]: HotspotRatingMedium,
- [HotspotRatingEnum.LOW]: HotspotRatingLow,
- };
-
- const Rating = ratings[rating];
-
- return <Rating className={className} {...rest} />;
-}
-
-function HotspotRatingHigh(props: Props) {
- return <SeverityCriticalIcon {...props} fill="rating.E" />;
-}
-
-function HotspotRatingMedium(props: Props) {
- return <SeverityMajorIcon {...props} fill="rating.D" />;
-}
-
-function HotspotRatingLow(props: Props) {
- return <SeverityMinorIcon {...props} fill="rating.C" />;
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/HtmlFormatter.tsx b/server/sonar-web/src/main/js/design-system/components/HtmlFormatter.tsx
deleted file mode 100644
index 85e5984d1e2..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/HtmlFormatter.tsx
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../helpers';
-
-export const HtmlFormatter = styled.div`
- ${tw`sw-typo-default`}
-
- a {
- color: ${themeColor('linkDefault')};
- border-bottom: ${themeBorder('default', 'linkDefault')};
- ${tw`sw-no-underline sw-typo-semibold`};
-
- &:visited {
- color: ${themeColor('linkDefault')};
- }
-
- &:hover,
- &:focus,
- &:active {
- color: ${themeColor('linkActive')};
- border-bottom: ${themeBorder('default', 'linkDefault')};
- }
- }
-
- p,
- ul,
- ol,
- pre,
- blockquote,
- table {
- color: ${themeColor('pageContent')};
- ${tw`sw-mb-4`}
- }
-
- h2,
- h3 {
- color: ${themeColor('pageContentDark')};
- ${tw`sw-typo-lg-semibold`}
- ${tw`sw-my-6`}
- }
-
- h4,
- h5,
- h6 {
- color: ${themeColor('pageContentDark')};
- ${tw`sw-typo-semibold`}
- ${tw`sw-mt-6 sw-mb-2`}
- }
-
- pre,
- code {
- background-color: ${themeColor('codeSnippetBackground')};
- border: ${themeBorder('default', 'codeSnippetBorder')};
- ${tw`sw-code`}
- }
-
- pre {
- ${tw`sw-rounded-2`}
- ${tw`sw-relative`}
- ${tw`sw-my-2`}
-
- ${tw`sw-overflow-x-auto`}
- ${tw`sw-p-6`}
- }
-
- code {
- ${tw`sw-m-0`}
- /* 1px override is needed to prevent overlap of other code "tags" */
- ${tw`sw-py-[1px] sw-px-1`}
- ${tw`sw-rounded-1`}
- ${tw`sw-whitespace-nowrap`}
- }
-
- pre > code {
- ${tw`sw-p-0`}
- ${tw`sw-whitespace-pre`}
- background-color: transparent;
- }
-
- blockquote {
- ${tw`sw-px-4`}
- line-height: 1.5;
- }
-
- ul {
- ${tw`sw-pl-6`}
- ${tw`sw-flex sw-flex-col sw-gap-2`}
- list-style-type: disc;
-
- li::marker {
- color: ${themeColor('listMarker')};
- }
- }
-
- li > ul {
- ${tw`sw-my-2 sw-mx-0`}
- }
-
- ol {
- ${tw`sw-pl-10`};
- list-style-type: decimal;
- }
-
- table {
- ${tw`sw-min-w-[50%]`}
- border: ${themeBorder('default')};
- border-collapse: collapse;
- }
-
- th {
- ${tw`sw-py-1 sw-px-3`}
- ${tw`sw-typo-semibold`}
- ${tw`sw-text-center`}
- background-color: ${themeColor('backgroundPrimary')};
- border: ${themeBorder('default')};
- }
-
- td {
- ${tw`sw-py-1 sw-px-3`}
- border: ${themeBorder('default')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/IlllustredSelectionCard.tsx b/server/sonar-web/src/main/js/design-system/components/IlllustredSelectionCard.tsx
deleted file mode 100644
index b254f97c0b1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/IlllustredSelectionCard.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { ReactNode } from 'react';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../helpers/theme';
-import { Note } from '../sonar-aligned';
-import { BareButton } from '../sonar-aligned/components/buttons';
-
-interface Props {
- className?: string;
- description: ReactNode;
- image: ReactNode;
- onClick: () => void;
- selected: boolean;
-}
-
-export function IllustratedSelectionCard(props: Props) {
- const { className, description, image, onClick, selected } = props;
-
- return (
- <StyledSelectionCard
- className={classNames(className, { selected })}
- aria-pressed={selected}
- onClick={onClick}
- >
- <ImageContainer>{image}</ImageContainer>
- <DescriptionContainer>
- <Note>{description}</Note>
- </DescriptionContainer>
- </StyledSelectionCard>
- );
-}
-
-const ImageContainer = styled.div`
- min-height: 116px;
- flex: 1;
- background: ${themeColor('backgroundPrimary')};
- ${tw`sw-flex`}
- ${tw`sw-justify-center sw-items-center`}
- ${tw`sw-rounded-t-1`}
-`;
-
-const DescriptionContainer = styled.div`
- background: ${themeColor('backgroundSecondary')};
- border-top: ${themeBorder()};
- ${tw`sw-rounded-b-1`}
- ${tw`sw-p-4`}
-`;
-
-export const StyledSelectionCard = styled(BareButton)`
- ${tw`sw-flex`}
- ${tw`sw-flex-col`}
- ${tw`sw-rounded-1`};
-
- min-width: 146px;
- border: ${themeBorder('default')};
- transition: border 0.3s ease;
-
- &:hover,
- &:active {
- border: ${themeBorder('default', 'primary')};
- }
-
- &:focus {
- outline: ${themeBorder('focus', 'primary')};
- }
-
- &.selected {
- border: ${themeBorder('default', 'primary')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/InteractiveIcon.tsx b/server/sonar-web/src/main/js/design-system/components/InteractiveIcon.tsx
deleted file mode 100644
index 292af594cc4..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/InteractiveIcon.tsx
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { css } from '@emotion/react';
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import React, { ForwardedRef, MouseEvent, forwardRef, useCallback } from 'react';
-import tw from 'twin.macro';
-import { OPACITY_20_PERCENT } from '../helpers/constants';
-import { themeBorder, themeColor, themeContrast } from '../helpers/theme';
-import { isDefined } from '../helpers/types';
-import { ThemedProps } from '../types/theme';
-import { IconProps } from './icons/Icon';
-
-export type InteractiveIconSize = 'small' | 'medium';
-
-export interface InteractiveIconProps {
- Icon: React.ComponentType<React.PropsWithChildren<IconProps>>;
- 'aria-label': string;
- children?: React.ReactNode;
- className?: string;
- currentColor?: boolean;
- disabled?: boolean;
- iconProps?: IconProps;
- id?: string;
- innerRef?: React.Ref<HTMLButtonElement>;
- onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
- size?: InteractiveIconSize;
- stopPropagation?: boolean;
-}
-
-export const InteractiveIconBase = forwardRef(
- (props: InteractiveIconProps, ref: ForwardedRef<HTMLButtonElement>) => {
- const {
- Icon,
- children,
- disabled,
- onClick,
- size = 'medium',
- iconProps = {},
- stopPropagation = true,
- ...htmlProps
- } = props;
-
- const handleClick = useCallback(
- (event: React.MouseEvent<HTMLButtonElement>) => {
- if (stopPropagation) {
- event.stopPropagation();
- }
-
- if (onClick && !disabled) {
- onClick(event);
- }
- },
- [disabled, onClick, stopPropagation],
- );
-
- const propsForInteractiveWrapper = {
- ...htmlProps,
- 'aria-disabled': disabled,
- disabled,
- size,
- };
-
- return (
- <IconButton {...propsForInteractiveWrapper} onClick={handleClick} ref={ref} type="button">
- <Icon className={classNames({ 'sw-mr-1': isDefined(children) })} {...iconProps} />
- {children}
- </IconButton>
- );
- },
-);
-
-InteractiveIconBase.displayName = 'InteractiveIconBase';
-
-const buttonIconStyle = (props: ThemedProps & { size: InteractiveIconSize }) => css`
- box-sizing: border-box;
- border: none;
- outline: none;
- text-decoration: none;
- color: var(--color);
- background-color: var(--background);
- transition:
- background-color 0.2s ease,
- outline 0.2s ease,
- color 0.2s ease;
-
- ${tw`sw-inline-flex sw-items-center sw-justify-center`}
- ${tw`sw-cursor-pointer`}
-
- ${{
- small: tw`sw-h-6 sw-px-1 sw-rounded-1/2`,
- medium: tw`sw-h-control sw-px-[0.625rem] sw-rounded-2`,
- }[props.size]}
-
-
- &:hover,
- &:focus,
- &:active {
- color: var(--colorHover);
- background-color: var(--backgroundHover);
- }
-
- &:focus,
- &:active {
- outline: ${themeBorder('focus', 'var(--focus)')(props)};
- }
-
- &:disabled,
- &:disabled:hover {
- color: var(--echoes-color-icon-disabled);
- background-color: var(--background);
-
- ${tw`sw-cursor-not-allowed`}
- }
-`;
-
-const IconButton = styled.button`
- ${buttonIconStyle}
-`;
-
-/**
- * @deprecated Use ButtonIcon from Echoes instead.
- *
- * Use the `variety` prop with the ButtonVariety enum to change the
- * button's look and feel.
- *
- * Some of the props have changed or been renamed:
- * - `disabled` is now `isDisabled`, note that an Echoes Tooltip won't work
- * on a disabled button, use a text notice or ToggleTip next to the disabled button instead.
- * - `Icon` is restricted to Echoes' Icons
- * - `aria-label` is now `ariaLabel`
- * - `size` now requires a value from the ButtonSize enum
- *
- * New props:
- * - `tooltipContent` overrides the content of the tooltip (which defaults to the value of ariaLabel!)
- * - `tooltipProps` allows you to customize the tooltip positioning (`align` and `side`)
- *
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3382706231/Button | Migration Guide} for more information.
- */
-export const InteractiveIcon = styled(InteractiveIconBase)`
- --background: ${themeColor('interactiveIcon')};
- --backgroundHover: ${themeColor('interactiveIconHover')};
- --color: ${({ currentColor, theme }) =>
- currentColor ? 'currentColor' : themeContrast('interactiveIcon')({ theme })};
- --colorHover: ${themeContrast('interactiveIconHover')};
- --focus: ${themeColor('interactiveIconFocus', OPACITY_20_PERCENT)};
-`;
-
-/**
- * @deprecated Use ButtonIcon from Echoes instead, with the ButtonVariety.DefaultGhost variety.
- *
- * Some of the props have changed or been renamed:
- * - `disabled` is now `isDisabled`, note that an Echoes Tooltip won't work
- * on a disabled button, use a text notice or ToggleTip next to the disabled button instead.
- * - `Icon` is restricted to Echoes' Icons
- * - `aria-label` is now `ariaLabel`
- * - `size` now requires a value from the ButtonSize enum
- *
- * New props:
- * - `tooltipContent` overrides the content of the tooltip (which defaults to the value of ariaLabel!)
- * - `tooltipProps` allows you to customize the tooltip positioning (`align` and `side`)
- *
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3382706231/Button | Migration Guide} for more information.
- */
-export const DiscreetInteractiveIcon = styled(InteractiveIcon)`
- --color: var(--echoes-color-icon-subdued);
-`;
-
-/**
- * @deprecated Use ButtonIcon from Echoes instead, with the ButtonVariety.DangerGhost variety.
- *
- * Some of the props have changed or been renamed:
- * - `disabled` is now `isDisabled`, note that an Echoes Tooltip won't work
- * on a disabled button, use a text notice or ToggleTip next to the disabled button instead.
- * - `Icon` is restricted to Echoes' Icons
- * - `aria-label` is now `ariaLabel`
- * - `size` now requires a value from the ButtonSize enum
- *
- * New props:
- * - `tooltipContent` overrides the content of the tooltip (which defaults to the value of ariaLabel!)
- * - `tooltipProps` allows you to customize the tooltip positioning (`align` and `side`)
- *
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3382706231/Button | Migration Guide} for more information.
- */
-export const DestructiveIcon = styled(InteractiveIconBase)`
- --background: ${themeColor('destructiveIcon')};
- --backgroundHover: ${themeColor('destructiveIconHover')};
- --color: ${themeContrast('destructiveIcon')};
- --colorHover: ${themeContrast('destructiveIconHover')};
- --focus: ${themeColor('destructiveIconFocus', OPACITY_20_PERCENT)};
-`;
-
-/**
- * @deprecated Use ButtonIcon from Echoes instead, with the ButtonVariety.DefaultGhost variety.
- *
- * Some of the props have changed or been renamed:
- * - `disabled` is now `isDisabled`, note that an Echoes Tooltip won't work
- * on a disabled button, use a text notice or ToggleTip next to the disabled button instead.
- * - `Icon` is restricted to Echoes' Icons
- * - `aria-label` is now `ariaLabel`
- * - `size` now requires a value from the ButtonSize enum
- *
- * New props:
- * - `tooltipContent` overrides the content of the tooltip (which defaults to the value of ariaLabel!)
- * - `tooltipProps` allows you to customize the tooltip positioning (`align` and `side`)
- *
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3382706231/Button | Migration Guide} for more information.
- */
-export const DismissProductNewsIcon = styled(InteractiveIcon)`
- --background: ${themeColor('productNews')};
- --backgroundHover: ${themeColor('productNewsHover')};
- --color: ${themeContrast('productNews')};
- --colorHover: ${themeContrast('productNewsHover')};
- --focus: ${themeColor('interactiveIconFocus', OPACITY_20_PERCENT)};
-
- height: 28px;
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/IssueMessageHighlighting.tsx b/server/sonar-web/src/main/js/design-system/components/IssueMessageHighlighting.tsx
deleted file mode 100644
index b7cb86bb5ad..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/IssueMessageHighlighting.tsx
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import * as React from 'react';
-import tw from 'twin.macro';
-import { themeColor } from '../helpers';
-
-export interface MessageFormatting {
- end: number;
- start: number;
- type: MessageFormattingType;
-}
-
-export enum MessageFormattingType {
- CODE = 'CODE',
-}
-
-export interface IssueMessageHighlightingProps {
- message?: string;
- messageFormattings?: MessageFormatting[];
-}
-
-export function IssueMessageHighlighting(props: IssueMessageHighlightingProps) {
- const { message, messageFormattings } = props;
-
- if (message === undefined || message === '') {
- return null;
- }
-
- if (!(messageFormattings && messageFormattings.length > 0)) {
- return <>{message}</>;
- }
-
- let previousEnd = 0;
-
- const sanitizedFormattings = [...messageFormattings]
- .sort((a, b) => a.start - b.start)
- .reduce<typeof messageFormattings>((acc, messageFormatting) => {
- const { type } = messageFormatting;
-
- if (type !== MessageFormattingType.CODE) {
- return acc;
- }
-
- const { start } = messageFormatting;
- let { end } = messageFormatting;
-
- end = Math.min(message.length, end);
-
- if (start < 0 || end === start || end < start) {
- return acc;
- }
-
- if (acc.length > 0) {
- const { start: previousStart, end: previousEnd } = acc[acc.length - 1];
-
- if (start <= previousEnd) {
- acc[acc.length - 1] = {
- start: previousStart,
- end: Math.max(previousEnd, end),
- type,
- };
-
- return acc;
- }
- }
-
- acc.push({ start, end, type });
-
- return acc;
- }, []);
-
- return (
- <span>
- {sanitizedFormattings.map(({ start, end, type }) => {
- const beginning = previousEnd;
- previousEnd = end;
-
- return (
- <React.Fragment key={`${message}-${start}-${end}`}>
- {message.slice(beginning, start)}
- {type === MessageFormattingType.CODE ? (
- <SingleLineSnippet className="sw-code sw-rounded-1 sw-px-1 sw-border sw-border-solid">
- {message.slice(start, end)}
- </SingleLineSnippet>
- ) : (
- <span>{message.slice(start, end)}</span>
- )}
- </React.Fragment>
- );
- })}
-
- {message.slice(previousEnd)}
- </span>
- );
-}
-
-const SingleLineSnippet = styled.span`
- background: ${themeColor('codeSnippetBackground')};
- border-color: ${themeColor('codeSnippetBorder')};
- color: ${themeColor('codeSnippetInline')};
- ${tw`sw-py-1/2`}
-
- a & {
- ${tw`sw-pb-0`}
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/KeyboardHint.tsx b/server/sonar-web/src/main/js/design-system/components/KeyboardHint.tsx
deleted file mode 100644
index 2950d93ac24..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/KeyboardHint.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { Key } from '../helpers/keyboard';
-import { KeyboardHintKeys } from './KeyboardHintKeys';
-
-interface Props {
- className?: string;
- command: string;
- title?: string;
-}
-
-export function KeyboardHint({ title, command, className }: Props) {
- const normalizedCommand = command
- .replace(Key.Control, isMacOS() ? 'Command' : 'Control')
- .replace(Key.Alt, isMacOS() ? 'Option' : 'Alt');
-
- return (
- <Body className={className}>
- {title && <span className="sw-truncate">{title}</span>}
- <KeyboardHintKeys command={normalizedCommand} />
- </Body>
- );
-}
-
-const Body = styled.div`
- ${tw`sw-flex sw-gap-2 sw-justify-center`}
- flex-wrap: wrap;
- color: var(--echoes-color-text-subdued);
-`;
-
-function isMacOS() {
- return navigator.userAgent.toLocaleLowerCase().includes('mac os');
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/KeyboardHintKeys.tsx b/server/sonar-web/src/main/js/design-system/components/KeyboardHintKeys.tsx
deleted file mode 100644
index 78afa567e79..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/KeyboardHintKeys.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import tw from 'twin.macro';
-import { themeColor, themeContrast } from '../helpers';
-import { Key } from '../helpers/keyboard';
-import { TriangleDownIcon, TriangleLeftIcon, TriangleRightIcon, TriangleUpIcon } from './icons';
-
-export const mappedKeys = {
- [Key.Alt]: 'Alt',
- [Key.ArrowDown]: <TriangleDownIcon />,
- [Key.ArrowLeft]: <TriangleLeftIcon />,
- [Key.ArrowRight]: <TriangleRightIcon />,
- [Key.ArrowUp]: <TriangleUpIcon />,
- [Key.Command]: '⌘',
- [Key.Control]: 'Ctrl',
- [Key.Option]: '⌥',
- [Key.Click]: 'click',
-};
-
-const NON_KEY_SYMBOLS = ['+', ' '];
-
-export function KeyboardHintKeys({ command }: { command: string }) {
- const keys = command
- .trim()
- .split(' ')
- .map((key, index) => {
- const uniqueKey = `${key}-${index}`;
-
- if (NON_KEY_SYMBOLS.includes(key)) {
- return <span key={uniqueKey}>{key}</span>;
- }
-
- const isNonMappedKey = !(
- Object.keys(mappedKeys).includes(key) || Object.values(mappedKeys).includes(key)
- );
-
- return (
- <KeyBox className={classNames({ 'sw-px-1': isNonMappedKey })} key={uniqueKey}>
- {Object.keys(mappedKeys).includes(key) ? mappedKeys[key as keyof typeof mappedKeys] : key}
- </KeyBox>
- );
- });
-
- return <div className="sw-flex sw-gap-1">{keys}</div>;
-}
-
-export const KeyBox = styled.span`
- ${tw`sw-flex sw-items-center sw-justify-center`}
- ${tw`sw-px-1/2`}
- ${tw`sw-rounded-1/2`}
-
- background-color: ${themeColor('keyboardHintKey')};
- color: ${themeContrast('keyboardHintKey')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/Link.tsx b/server/sonar-web/src/main/js/design-system/components/Link.tsx
deleted file mode 100644
index ed4114e1be3..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Link.tsx
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { css } from '@emotion/react';
-import styled from '@emotion/styled';
-import React, { HTMLAttributeAnchorTarget } from 'react';
-import { Link as RouterLink, LinkProps as RouterLinkProps } from 'react-router-dom';
-import tw, { theme as twTheme } from 'twin.macro';
-import { themeBorder, themeColor } from '../helpers/theme';
-import { TooltipWrapperInner } from './Tooltip';
-import { OpenNewTabIcon } from './icons/OpenNewTabIcon';
-
-/** @deprecated Use LinkProps from Echoes instead.
- *
- * Some of the props have changed or been renamed:
- * - `blurAfterClick` is now `shouldBlurAfterClick`
- * - ~`disabled`~ doesn't exist anymore, a disabled link is just a regular text
- * - `forceExternal` is now `isExternal`
- * - `icon` is now `iconLeft` and can only be used with LinkStandalone
- * - `preventDefault` is now `shouldPreventDefault`
- * - `showExternalIcon` is now `hasExternalIcon`
- * - `stopPropagation` is now `shouldStopPropagation`
- */
-export interface LinkProps extends RouterLinkProps {
- blurAfterClick?: boolean;
- disabled?: boolean;
- forceExternal?: boolean;
- icon?: React.ReactNode;
- isExternal?: boolean;
- onClick?: (event: React.MouseEvent<HTMLAnchorElement>) => void;
- preventDefault?: boolean;
- showExternalIcon?: boolean;
- stopPropagation?: boolean;
- target?: HTMLAttributeAnchorTarget;
-}
-
-function BaseLinkWithRef(props: LinkProps, ref: React.ForwardedRef<HTMLAnchorElement>) {
- const {
- children,
- blurAfterClick,
- disabled,
- icon,
- isExternal: isExternalProp = false,
- onClick,
- preventDefault,
- showExternalIcon = !icon,
- stopPropagation,
- to,
- ...rest
- } = props;
-
- const toAsString =
- typeof to === 'string' ? to : `${to.pathname ?? ''}${to.search ?? ''}${to.hash ?? ''}`;
-
- const isExternal = isExternalProp || toAsString.startsWith('http');
-
- const handleClick = React.useCallback(
- (event: React.MouseEvent<HTMLAnchorElement>) => {
- if (blurAfterClick) {
- event.currentTarget.blur();
- }
-
- if (preventDefault || disabled) {
- event.preventDefault();
- }
-
- if (stopPropagation) {
- event.stopPropagation();
- }
-
- if (onClick && !disabled) {
- onClick(event);
- }
- },
- [onClick, blurAfterClick, preventDefault, stopPropagation, disabled],
- );
-
- if (isExternal) {
- return (
- <a
- rel="noopener noreferrer"
- target="_blank"
- {...rest}
- href={toAsString}
- onClick={handleClick}
- ref={ref}
- >
- {icon}
- {children}
- {showExternalIcon && <ExternalIcon className="sw-ml-1" />}
- </a>
- );
- }
-
- return (
- <RouterLink ref={ref} {...rest} onClick={handleClick} to={to}>
- {icon}
- {children}
- </RouterLink>
- );
-}
-
-const ExternalIcon = styled(OpenNewTabIcon)`
- color: ${themeColor('linkExternalIcon')};
-`;
-
-/** @deprecated Use either Link or LinkStandalone from Echoes, or react-router-dom's Link instead.
- */
-export const BaseLink = React.forwardRef(BaseLinkWithRef);
-
-const StyledBaseLink = styled(BaseLink)`
- color: var(--color);
- border-bottom: ${({ children, icon, theme }) =>
- icon && !children ? themeBorder('default', 'transparent')({ theme }) : 'var(--border)'};
-
- &:visited {
- color: var(--color);
- }
-
- &:hover,
- &:focus,
- &:active {
- color: var(--active);
- border-bottom: ${({ children, icon, theme }) =>
- icon && !children ? themeBorder('default', 'transparent')({ theme }) : 'var(--borderActive)'};
-
- ${ExternalIcon} {
- color: ${themeColor('linkExternalIconActive')};
- }
- }
-
- & > svg {
- ${tw`sw-align-text-bottom!`}
- }
-
- ${({ icon }) =>
- icon &&
- css`
- margin-left: calc(${twTheme('width.icon')} + ${twTheme('spacing.3')});
-
- & > svg,
- & > img {
- ${tw`sw-mr-3`}
-
- margin-left: calc(-1 * (${twTheme('width.icon')} + ${twTheme('spacing.3')}));
- }
- `};
-`;
-
-/** @deprecated Use either Link or LinkStandalone from Echoes instead.
- */
-export const NakedLink = styled(BaseLink)`
- border-bottom: none;
- padding-bottom: 1px;
-
- font-weight: 600;
- color: ${themeColor('linkNaked')};
-
- ${({ disabled, theme }) =>
- disabled
- ? tw`sw-cursor-default`
- : `&:hover,
- &:focus,
- &:active {
- color: ${themeColor('linkActive')({ theme })};
- }`};
-`;
-
-/** @deprecated Use either Link or LinkStandalone from Echoes instead.
- */
-export const DrilldownLink = styled(StyledBaseLink)`
- ${tw`sw-heading-xl`}
- ${tw`sw-tracking-tight`}
- ${tw`sw-whitespace-nowrap`}
-
- ${({ disabled, theme }) =>
- disabled
- ? tw`sw-cursor-default`
- : `--active: ${themeColor('linkActive')({ theme })};
- --border: ${themeBorder('default', 'linkBorder')({ theme })};
- --borderActive: ${themeBorder('default', 'linkBorder')({ theme })};`};
-
- --color: ${themeColor('drilldown')};
-`;
-
-DrilldownLink.displayName = 'DrilldownLink';
-
-/** @deprecated Use either Link or LinkStandalone from Echoes instead.
- */
-export const HoverLink = styled(StyledBaseLink)`
- text-decoration: none;
-
- --color: ${themeColor('linkDiscreet')};
- --active: ${themeColor('linkActive')};
- --border: ${themeBorder('default', 'transparent')};
- --borderActive: ${themeBorder('default', 'linkBorder')};
-
- ${TooltipWrapperInner} & {
- --active: ${themeColor('linkTooltipActive')};
- --borderActive: ${themeBorder('default', 'linkBorder')};
- }
-
- ${ExternalIcon} {
- color: ${themeColor('linkDiscreet')};
- }
-`;
-HoverLink.displayName = 'HoverLink';
-
-/** @deprecated Use either Link or LinkStandalone from Echoes instead.
- */
-export const LinkBox = styled(StyledBaseLink)`
- text-decoration: none;
-
- &:hover,
- &:focus,
- &:active {
- background-color: ${themeColor('dropdownMenuHover')};
- display: block;
- }
-`;
-LinkBox.displayName = 'LinkBox';
-
-/** @deprecated Use either Link or LinkStandalone from Echoes instead.
- */
-export const DiscreetLinkBox = styled(StyledBaseLink)`
- text-decoration: none;
-
- &:hover,
- &:focus,
- &:active {
- background-color: none;
- display: block;
- }
-
- ${({ disabled }) => (disabled ? tw`sw-cursor-default` : '')};
-`;
-LinkBox.displayName = 'DiscreetLinkBox';
-
-/** @deprecated Use either Link or LinkStandalone from Echoes instead.
- */
-export const DiscreetLink = styled(HoverLink)`
- --border: ${themeBorder('default', 'linkDiscreet')};
-`;
-DiscreetLink.displayName = 'DiscreetLink';
-
-/** @deprecated Use either Link or LinkStandalone from Echoes instead.
- */
-export const ContentLink = styled(HoverLink)`
- --color: ${themeColor('pageTitle')};
- --border: ${themeBorder('default', 'contentLinkBorder')};
-
- ${({ disabled }) => (disabled ? tw`sw-cursor-default` : '')};
-
- ${({ disabled, theme }) =>
- disabled
- ? `--active: ${themeColor('pageTitle')({ theme })};
- --border: none;
- --borderActive: none;`
- : ''}
-`;
-ContentLink.displayName = 'ContentLink';
-
-/** @deprecated Use either Link or LinkStandalone from Echoes instead.
- */
-export const StandoutLink = styled(StyledBaseLink)`
- ${tw`sw-font-semibold`}
- ${tw`sw-no-underline`}
-
- --color: ${themeColor('linkDefault')};
- --active: ${themeColor('linkActive')};
- --border: ${themeBorder('default', 'linkBorder')};
- --borderActive: ${themeBorder('default', 'linkBorder')};
-
- ${TooltipWrapperInner} & {
- --color: ${themeColor('linkTooltipDefault')};
- --active: ${themeColor('linkTooltipActive')};
- --border: ${themeBorder('default', 'linkBorder')};
- --borderActive: ${themeBorder('default', 'linkBorder')};
- }
-`;
-StandoutLink.displayName = 'StandoutLink';
-
-/** @deprecated Use either Link or LinkStandalone from Echoes instead.
- */
-export const IssueIndicatorLink = styled(BaseLink)`
- color: var(--echoes-color-text-subdued);
- text-decoration: none;
-
- ${tw`sw-whitespace-nowrap`}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/LocationMarker.tsx b/server/sonar-web/src/main/js/design-system/components/LocationMarker.tsx
deleted file mode 100644
index 083e948d09d..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/LocationMarker.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { forwardRef, LegacyRef } from 'react';
-import tw from 'twin.macro';
-import { themeColor, themeContrast } from '../helpers/theme';
-import { isDefined } from '../helpers/types';
-import { IssueLocationIcon } from './icons/IssueLocationIcon';
-
-interface Props {
- className?: string;
- onClick?: () => void;
- selected: boolean;
- text?: number | string;
-}
-
-function InternalLocationMarker(
- { className, onClick, text, selected }: Props,
- ref: LegacyRef<HTMLDivElement>,
-) {
- return (
- <StyledMarker
- className={classNames(className, {
- selected,
- concealed: !isDefined(text),
- 'sw-cursor-pointer': isDefined(onClick),
- })}
- onClick={onClick}
- ref={ref}
- >
- {isDefined(text) ? text : <IssueLocationIcon />}
- </StyledMarker>
- );
-}
-
-export const LocationMarker = forwardRef<HTMLDivElement, Props>(InternalLocationMarker);
-
-export const StyledMarker = styled.div`
- ${tw`sw-flex sw-grow-0 sw-items-center sw-justify-center`}
- ${tw`sw-typo-semibold`}
- ${tw`sw-rounded-1/2`}
-
- height: 1.125rem;
- color: ${themeContrast('codeLineLocationMarker')};
- background-color: ${themeColor('codeLineLocationMarker')};
-
- &.selected,
- &:hover {
- background-color: ${themeColor('codeLineLocationMarkerSelected')};
- }
-
- &:not(.concealed) {
- ${tw`sw-px-1`}
- ${tw`sw-self-start`}
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/MainAppBar.tsx b/server/sonar-web/src/main/js/design-system/components/MainAppBar.tsx
deleted file mode 100644
index 49f95ce83d9..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/MainAppBar.tsx
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import styled from '@emotion/styled';
-import { throttle } from 'lodash';
-import React from 'react';
-import tw from 'twin.macro';
-import {
- LAYOUT_GLOBAL_NAV_HEIGHT,
- LAYOUT_LOGO_MARGIN_RIGHT,
- LAYOUT_LOGO_MAX_HEIGHT,
- LAYOUT_LOGO_MAX_WIDTH,
- LAYOUT_VIEWPORT_MIN_WIDTH,
- THROTTLE_SCROLL_DELAY,
-} from '../helpers/constants';
-import { themeBorder, themeColor, themeContrast, themeShadow } from '../helpers/theme';
-import { BaseLink } from './Link';
-
-const MainAppBarHeader = styled.header`
- ${tw`sw-flex`};
- ${tw`sw-items-center`};
- ${tw`sw-px-6`};
- ${tw`sw-w-full`};
- ${tw`sw-box-border`};
-
- background: ${themeColor('mainBar')};
- border-bottom: ${themeBorder('default')};
- color: ${themeContrast('mainBar')};
- height: ${LAYOUT_GLOBAL_NAV_HEIGHT}px;
- min-width: ${LAYOUT_VIEWPORT_MIN_WIDTH}px;
-`;
-
-const MainAppBarNavLogoDiv = styled.div`
- margin-right: ${LAYOUT_LOGO_MARGIN_RIGHT}px;
-
- img,
- svg {
- ${tw`sw-object-contain`};
-
- max-height: ${LAYOUT_LOGO_MAX_HEIGHT}px;
- max-width: ${LAYOUT_LOGO_MAX_WIDTH}px;
- }
-`;
-
-const MainAppBarNavLogoLink = styled(BaseLink)`
- border: none;
-`;
-
-const MainAppBarNavRightDiv = styled.div`
- flex-grow: 2;
- height: 100%;
-`;
-
-export function MainAppBar({
- children,
- Logo,
-}: React.PropsWithChildren<{ Logo: React.ElementType }>) {
- const theme = useTheme();
- const [boxShadow, setBoxShadow] = React.useState('none');
-
- React.useEffect(() => {
- const handleScroll = throttle(() => {
- setBoxShadow(document.documentElement?.scrollTop > 0 ? themeShadow('md')({ theme }) : 'none');
- }, THROTTLE_SCROLL_DELAY);
-
- document.addEventListener('scroll', handleScroll);
- return () => {
- document.removeEventListener('scroll', handleScroll);
- };
- }, [theme]);
-
- return (
- <MainAppBarHeader style={{ boxShadow }}>
- <MainAppBarNavLogoDiv>
- <MainAppBarNavLogoLink to="/">
- <Logo />
- </MainAppBarNavLogoLink>
- </MainAppBarNavLogoDiv>
- <MainAppBarNavRightDiv>{children}</MainAppBarNavRightDiv>
- </MainAppBarHeader>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/MainMenu.tsx b/server/sonar-web/src/main/js/design-system/components/MainMenu.tsx
deleted file mode 100644
index f3168936a3f..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/MainMenu.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-
-const MainMenuUl = styled.ul`
- ${tw`sw-flex sw-gap-8 sw-items-center`}
-`;
-
-export function MainMenu({ children }: React.PropsWithChildren<object>) {
- return <MainMenuUl>{children}</MainMenuUl>;
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/MainMenuItem.tsx b/server/sonar-web/src/main/js/design-system/components/MainMenuItem.tsx
deleted file mode 100644
index 9c1b226e21e..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/MainMenuItem.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { LAYOUT_GLOBAL_NAV_HEIGHT } from '../helpers/constants';
-import { themeBorder, themeContrast } from '../helpers/theme';
-
-export const MainMenuItem = styled.li`
- & a {
- ${tw`sw-block sw-box-border`};
- ${tw`sw-text-sm sw-font-semibold`};
- ${tw`sw-whitespace-nowrap`};
- ${tw`sw-no-underline`};
- ${tw`sw-select-none`};
- ${tw`sw-font-sans`};
-
- color: ${themeContrast('mainBar')};
- letter-spacing: 0.03em;
- line-height: calc(${LAYOUT_GLOBAL_NAV_HEIGHT}px - 4px); // - 4px border bottom
- border-bottom: ${themeBorder('active', 'transparent', 1)};
-
- &:visited {
- border-bottom: ${themeBorder('active', 'transparent', 1)};
- color: ${themeContrast('mainBar')};
- }
-
- &:active,
- &.active,
- &:focus {
- border-bottom: ${themeBorder('active', 'menuBorder', 1)};
- color: ${themeContrast('mainBar')};
- }
-
- &:hover,
- &.hover {
- border-bottom: ${themeBorder('active', 'menuBorder', 1)};
- color: ${themeContrast('mainBarHover')};
- }
- }
-
- &[aria-expanded='true'] a {
- border-bottom: ${themeBorder('active', 'menuBorder', 1)};
- color: ${themeContrast('mainBarHover')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/MultiSelector.tsx b/server/sonar-web/src/main/js/design-system/components/MultiSelector.tsx
deleted file mode 100644
index f8509cbbbe9..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/MultiSelector.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { MultiSelectMenu } from './input/MultiSelectMenu';
-
-interface Props {
- allowNewElements?: boolean;
- allowSearch?: boolean;
- createElementLabel: string;
- elements: string[];
- headerLabel: string;
- listSize?: number;
- noResultsLabel: string;
- onSearch?: (query: string) => Promise<void>;
- onSelect: (item: string) => void;
- onUnselect: (item: string) => void;
- renderTooltip?: (item: string, disabled: boolean) => React.ReactNode;
- searchInputAriaLabel: string;
- selectedElements: string[];
- selectedElementsDisabled?: string[];
-}
-
-const LIST_SIZE = 10;
-
-export function MultiSelector(props: Readonly<Props>) {
- const {
- allowNewElements,
- createElementLabel,
- selectedElementsDisabled,
- headerLabel,
- noResultsLabel,
- searchInputAriaLabel,
- selectedElements,
- elements,
- allowSearch = true,
- renderTooltip,
- listSize = LIST_SIZE,
- } = props;
-
- return (
- <MultiSelectMenu
- allowNewElements={allowNewElements}
- allowSearch={allowSearch}
- createElementLabel={createElementLabel}
- elements={elements}
- headerNode={<div className="sw-mt-4 sw-font-semibold">{headerLabel}</div>}
- listSize={listSize}
- noResultsLabel={noResultsLabel}
- onSearch={props.onSearch}
- onSelect={props.onSelect}
- onUnselect={props.onUnselect}
- placeholder={searchInputAriaLabel}
- renderTooltip={renderTooltip}
- searchInputAriaLabel={searchInputAriaLabel}
- selectedElements={selectedElements}
- selectedElementsDisabled={selectedElementsDisabled}
- validateSearchInput={validateElement}
- />
- );
-}
-
-export function validateElement(value: string) {
- // Allow only a-z, 0-9, '+', '-', '#', '.'
- return value.toLowerCase().replace(/[^-a-z0-9+#.]/gi, '');
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/NavBarTabs.tsx b/server/sonar-web/src/main/js/design-system/components/NavBarTabs.tsx
deleted file mode 100644
index 999716d190d..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/NavBarTabs.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { IconChevronDown } from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import React, { forwardRef } from 'react';
-import tw, { theme } from 'twin.macro';
-import { themeBorder, themeColor, themeContrast } from '../helpers/theme';
-import { isDefined } from '../helpers/types';
-import NavLink, { NavLinkProps } from './NavLink';
-import { Tooltip } from './Tooltip';
-
-interface Props extends React.HTMLAttributes<HTMLUListElement> {
- children?: React.ReactNode;
- className?: string;
-}
-
-export function NavBarTabs({ children, className, ...other }: Props) {
- return (
- <ul className={`sw-flex sw-items-end sw-gap-8 ${className ?? ''}`} {...other}>
- {children}
- </ul>
- );
-}
-
-interface NavBarTabLinkProps extends Omit<NavLinkProps, 'children'> {
- active?: boolean;
- children?: React.ReactNode;
- className?: string;
- text: string;
- withChevron?: boolean;
-}
-
-export const NavBarTabLink = forwardRef<HTMLAnchorElement, NavBarTabLinkProps>(
- (props: NavBarTabLinkProps, ref) => {
- const { active, children, className, text, withChevron = false, ...linkProps } = props;
- return (
- <NavBarTabLinkWrapper>
- <NavLink
- className={({ isActive }) =>
- classNames(
- 'sw-flex sw-items-center',
- { active: isDefined(active) ? active : isActive },
- className,
- )
- }
- ref={ref}
- {...linkProps}
- >
- <span className="sw-inline-block sw-text-center" data-text={text}>
- {text}
- </span>
-
- {children}
-
- {withChevron && (
- <span className="sw-ml-1">
- <IconChevronDown />
- </span>
- )}
- </NavLink>
- </NavBarTabLinkWrapper>
- );
- },
-);
-
-NavBarTabLink.displayName = 'NavBarTabLink';
-
-export function DisabledTabLink(props: { label: string; overlay: React.ReactNode }) {
- return (
- <NavBarTabLinkWrapper>
- <Tooltip content={props.overlay}>
- <a aria-disabled="true" className="disabled-link" role="link">
- {props.label}
- </a>
- </Tooltip>
- </NavBarTabLinkWrapper>
- );
-}
-
-// Styling for <NavLink> due to its special className function, it conflicts when styled with Emotion.
-const NavBarTabLinkWrapper = styled.li`
- ${tw`sw-typo-lg`};
- & > a {
- ${tw`sw-pb-3`};
- ${tw`sw-block`};
- ${tw`sw-box-border`};
- ${tw`sw-transition-none`};
-
- color: ${themeContrast('buttonSecondary')};
- text-decoration: none;
- border-bottom: ${themeBorder('xsActive', 'transparent')};
- padding-bottom: calc(${theme('spacing.3')} + 1px); // 12px spacing + 3px border + 1px = 16px
- }
-
- & > a.active,
- & > a:active,
- & > a:hover,
- & > a:focus,
- & > a[aria-expanded='true'] {
- border-bottom-color: ${themeColor('tabBorder')};
- }
-
- & > a.active > span[data-text],
- & > a[aria-expanded='true'] > span[data-text],
- & > a:active > span {
- ${tw`sw-typo-lg-semibold`};
- }
-
- // This is a hack to have a link take the space of the bold font, so when active other ones are not moving
- & > a > span[data-text]::before {
- ${tw`sw-block`};
- ${tw`sw-typo-lg-semibold`};
- ${tw`sw-h-0`};
- ${tw`sw-overflow-hidden`};
- ${tw`sw-invisible`};
- content: attr(data-text);
- }
-
- & > a.disabled-link,
- & > a.disabled-link:hover,
- & > a.disabled-link.hover {
- ${tw`sw-cursor-default`};
- border-bottom: ${themeBorder('xsActive', 'transparent', 1)};
- color: var(--echoes-color-text-disabled);
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/NavLink.tsx b/server/sonar-web/src/main/js/design-system/components/NavLink.tsx
deleted file mode 100644
index cee447b2d5e..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/NavLink.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React from 'react';
-import { NavLink as RouterNavLink, NavLinkProps as RouterNavLinkProps } from 'react-router-dom';
-
-export interface NavLinkProps extends RouterNavLinkProps {
- blurAfterClick?: boolean;
- disabled?: boolean;
- onClick?: (event: React.MouseEvent<HTMLAnchorElement>) => void;
- preventDefault?: boolean;
- stopPropagation?: boolean;
-}
-
-// Styling this component directly with Emotion should be avoided due to conflicts with react-router's classname.
-// Use NavBarTabs as an example of this exception.
-function NavLinkWithRef(props: NavLinkProps, ref: React.ForwardedRef<HTMLAnchorElement>) {
- const {
- blurAfterClick,
- children,
- disabled,
- onClick,
- preventDefault,
- stopPropagation,
- ...otherProps
- } = props;
-
- const handleClick = React.useCallback(
- (event: React.MouseEvent<HTMLAnchorElement>) => {
- if (blurAfterClick) {
- // explicitly lose focus after click
- event.currentTarget.blur();
- }
-
- if (preventDefault || disabled) {
- event.preventDefault();
- }
-
- if (stopPropagation) {
- event.stopPropagation();
- }
-
- if (onClick && !disabled) {
- onClick(event);
- }
- },
- [onClick, blurAfterClick, preventDefault, stopPropagation, disabled],
- );
-
- return (
- <RouterNavLink onClick={handleClick} ref={ref} {...otherProps}>
- {children}
- </RouterNavLink>
- );
-}
-
-const NavLink = React.forwardRef(NavLinkWithRef);
-export default NavLink;
diff --git a/server/sonar-web/src/main/js/design-system/components/NewCodeLegend.tsx b/server/sonar-web/src/main/js/design-system/components/NewCodeLegend.tsx
deleted file mode 100644
index 85a7863d68b..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/NewCodeLegend.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import tw from 'twin.macro';
-import { themeColor } from '../helpers/theme';
-
-export const NewCodeLegendIcon = styled.span`
- ${tw`sw-align-middle`}
- ${tw`sw-box-border`}
- ${tw`sw-h-4`}
- ${tw`sw-inline-block`}
- ${tw`sw-w-4`}
- background-color: ${themeColor('newCodeLegend')};
- border: 1px solid ${themeColor('newCodeLegendBorder')};
-`;
-
-const NewCodeLegendText = styled.span`
- ${tw`sw-align-middle`}
- ${tw`sw-typo-default`}
- ${tw`sw-ml-2`}
- color: var(--echoes-color-text-subdued);
-`;
-
-export function NewCodeLegend(props: Readonly<{ className?: string; text: string }>) {
- const { className, text } = props;
-
- return (
- <span className={classNames(className, 'sw-whitespace-nowrap')}>
- <NewCodeLegendIcon />
- <NewCodeLegendText>{text}</NewCodeLegendText>
- </span>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/OutsideClickHandler.tsx b/server/sonar-web/src/main/js/design-system/components/OutsideClickHandler.tsx
deleted file mode 100644
index 1cefb116eb5..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/OutsideClickHandler.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React from 'react';
-import { findDOMNode } from 'react-dom';
-
-export type MouseEventListener = 'click' | 'mousedown';
-interface Props {
- children: React.ReactNode;
- listenerType?: MouseEventListener;
- onClickOutside: () => void;
-}
-
-export class OutsideClickHandler extends React.Component<Props> {
- mounted = false;
-
- componentDidMount() {
- this.mounted = true;
- setTimeout(() => {
- this.addClickHandler();
- }, 0);
- }
-
- componentWillUnmount() {
- this.mounted = false;
- this.removeClickHandler();
- }
-
- addClickHandler = () => {
- const { listenerType = 'click' } = this.props;
- window.addEventListener(listenerType, this.handleWindowClick);
- };
-
- removeClickHandler = () => {
- const { listenerType = 'click' } = this.props;
- window.removeEventListener(listenerType, this.handleWindowClick);
- };
-
- handleWindowClick = (event: MouseEvent) => {
- if (this.mounted) {
- // eslint-disable-next-line react/no-find-dom-node
- const node = findDOMNode(this);
-
- if (!node?.contains(event.target as Node)) {
- this.props.onClickOutside();
- }
- }
- };
-
- render() {
- return this.props.children;
- }
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/Pill.tsx b/server/sonar-web/src/main/js/design-system/components/Pill.tsx
deleted file mode 100644
index 9b4c18e563f..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Pill.tsx
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { css } from '@emotion/react';
-import styled from '@emotion/styled';
-import { forwardRef, ReactNode } from 'react';
-import tw from 'twin.macro';
-import { themeColor, themeContrast } from '../helpers/theme';
-import { ThemeColors } from '../types/theme';
-
-export enum PillVariant {
- Critical = 'critical',
- Danger = 'danger',
- Warning = 'warning',
- Caution = 'caution',
- Info = 'info',
- Accent = 'accent',
- Success = 'success',
- Neutral = 'neutral',
-}
-
-export enum PillHighlight {
- Medium = 'medium',
- Low = 'low',
-}
-
-const variantThemeColors: Record<PillVariant, ThemeColors> = {
- [PillVariant.Critical]: 'pillCritical',
- [PillVariant.Danger]: 'pillDanger',
- [PillVariant.Warning]: 'pillWarning',
- [PillVariant.Caution]: 'pillCaution',
- [PillVariant.Info]: 'pillInfo',
- [PillVariant.Accent]: 'pillAccent',
- [PillVariant.Success]: 'pillSuccess',
- [PillVariant.Neutral]: 'pillNeutral',
-};
-
-const variantThemeBorderColors: Record<PillVariant, ThemeColors> = {
- [PillVariant.Critical]: 'pillCriticalBorder',
- [PillVariant.Danger]: 'pillDangerBorder',
- [PillVariant.Warning]: 'pillWarningBorder',
- [PillVariant.Caution]: 'pillCautionBorder',
- [PillVariant.Info]: 'pillInfoBorder',
- [PillVariant.Accent]: 'pillAccentBorder',
- [PillVariant.Success]: 'pillSuccessBorder',
- [PillVariant.Neutral]: 'pillNeutralBorder',
-};
-
-const variantThemeHoverColors: Record<PillVariant, ThemeColors> = {
- [PillVariant.Critical]: 'pillCriticalHover',
- [PillVariant.Danger]: 'pillDangerHover',
- [PillVariant.Warning]: 'pillWarningHover',
- [PillVariant.Caution]: 'pillCautionHover',
- [PillVariant.Info]: 'pillInfoHover',
- [PillVariant.Accent]: 'pillAccentHover',
- [PillVariant.Success]: 'pillSuccessHover',
- [PillVariant.Neutral]: 'pillNeutralHover',
-};
-
-interface PillProps {
- ['aria-label']?: string;
- children: ReactNode;
- className?: string;
- highlight?: PillHighlight;
- // If pill is wrapped with Tooltip, it will have onClick prop overriden.
- // So to avoid hover effect, we add additional prop to disable hover effect even with onClick.
- notClickable?: boolean;
- onClick?: () => void;
- variant: PillVariant;
-}
-
-// eslint-disable-next-line react/display-name
-export const Pill = forwardRef<HTMLButtonElement, Readonly<PillProps>>(
- ({ children, variant, highlight = PillHighlight.Low, onClick, notClickable, ...rest }, ref) => {
- return onClick && !notClickable ? (
- <StyledPillButton onClick={onClick} ref={ref} variant={variant} {...rest}>
- {children}
- </StyledPillButton>
- ) : (
- <StyledPill highlight={highlight} ref={ref} variant={variant} {...rest}>
- {children}
- </StyledPill>
- );
- },
-);
-
-const reusedStyles = css`
- ${tw`sw-typo-sm`};
- ${tw`sw-w-fit`};
- ${tw`sw-inline-block`};
- ${tw`sw-whitespace-nowrap`};
- ${tw`sw-px-[8px] sw-py-[2px]`};
- ${tw`sw-rounded-pill`};
- border-width: 1px;
-
- &:empty {
- ${tw`sw-hidden`}
- }
-`;
-
-const StyledPill = styled.span<{
- highlight: PillHighlight;
- variant: PillVariant;
-}>`
- ${reusedStyles};
-
- background-color: ${({ variant, highlight }) =>
- highlight === PillHighlight.Medium && themeColor(variantThemeColors[variant])};
- color: ${({ variant }) => themeContrast(variantThemeColors[variant])};
- border-style: ${({ highlight }) => (highlight === PillHighlight.Medium ? 'hidden' : 'solid')};
- border-color: ${({ variant, highlight }) =>
- highlight === PillHighlight.Low && themeColor(variantThemeBorderColors[variant])};
-`;
-
-const StyledPillButton = styled.button<{
- variant: PillVariant;
-}>`
- ${reusedStyles};
-
- background-color: ${({ variant }) => themeColor(variantThemeColors[variant])};
- color: ${({ variant }) => themeContrast(variantThemeColors[variant])};
- border-style: ${({ variant }) => (variant === PillVariant.Accent ? 'hidden' : 'solid')};
- border-color: ${({ variant }) => themeColor(variantThemeBorderColors[variant])};
-
- cursor: pointer;
-
- &:hover {
- background-color: ${({ variant }) => themeColor(variantThemeHoverColors[variant])};
- }
-
- &:focus {
- outline: var(--echoes-color-focus-default) solid var(--echoes-focus-border-width-default);
- outline-offset: var(--echoes-focus-border-offset-default);
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/QualityGateIndicator.tsx b/server/sonar-web/src/main/js/design-system/components/QualityGateIndicator.tsx
deleted file mode 100644
index ed6ac0258a5..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/QualityGateIndicator.tsx
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import React from 'react';
-import { useIntl } from 'react-intl';
-import { theme as twTheme } from 'twin.macro';
-import { BasePlacement, PopupPlacement } from '../helpers/positioning';
-import { themeColor, themeContrast } from '../helpers/theme';
-import { QGStatus } from '../types/quality-gates';
-
-const SIZE = {
- sm: twTheme('spacing.4'),
- md: twTheme('spacing.6'),
- xl: twTheme('spacing.16'),
-};
-
-interface Props {
- className?: string;
- size?: keyof typeof SIZE;
- status: QGStatus;
- tooltipPlacement?: BasePlacement;
-}
-
-const RX_4 = 4;
-const RX_2 = 2;
-
-export function QualityGateIndicator(props: Props) {
- const { className, size = 'md', status, tooltipPlacement = PopupPlacement.Right } = props;
- const iconProps = {
- className,
- height: SIZE[size],
- rx: size === 'xl' ? RX_4 : RX_2,
- size,
- tooltipPlacement,
- width: SIZE[size],
- };
- let StatusComponent: React.ReactNode;
- switch (status) {
- case 'NONE':
- case 'NOT_COMPUTED':
- StatusComponent = <QGNotComputed {...iconProps} />;
- break;
- case 'OK':
- StatusComponent = <QGPassed {...iconProps} />;
- break;
- case 'ERROR':
- StatusComponent = <QGFailed {...iconProps} />;
- break;
- }
- return <div className="sw-flex sw-justify-center sw-items-center">{StatusComponent}</div>;
-}
-
-const COMMON_PROPS = {
- fill: 'none',
- role: 'img',
- xmlns: 'http://www.w3.org/2000/svg',
-};
-
-interface IconProps {
- className?: string;
- height: string;
- rx: number;
- size: keyof typeof SIZE;
- tooltipPlacement?: BasePlacement;
- width: string;
-}
-
-function QGNotComputed({ className, rx, size, tooltipPlacement, ...sizeProps }: IconProps) {
- const theme = useTheme();
- const contrastColor = themeContrast('qgIndicatorNotComputed')({ theme });
- const intl = useIntl();
- const formatted = intl.formatMessage({ id: 'metric.level.NONE' });
- const title = intl.formatMessage({ id: 'overview.quality_gate_x' }, { '0': formatted });
-
- return (
- <svg className={className} {...COMMON_PROPS} {...sizeProps}>
- <title>{title}</title>
- <rect fill={themeColor('qgIndicatorNotComputed')({ theme })} rx={rx} {...sizeProps} />
- {
- {
- xl: <path d="M42 31v3H22v-3z" fill={contrastColor} />,
- md: <path d="M18 12v1.5H6V12z" fill={contrastColor} />,
- sm: <path d="M12 8v1H4V8z" fill={contrastColor} />,
- }[size]
- }
- </svg>
- );
-}
-
-function QGPassed({ className, rx, size, tooltipPlacement, ...sizeProps }: IconProps) {
- const theme = useTheme();
- const contrastColor = themeContrast('qgIndicatorPassed')({ theme });
- const intl = useIntl();
- const formatted = intl.formatMessage({ id: 'metric.level.OK' });
- const title = intl.formatMessage({ id: 'overview.quality_gate_x' }, { '0': formatted });
-
- return (
- <svg className={className} {...COMMON_PROPS} {...sizeProps}>
- <title>{title}</title>
- <rect fill={themeColor('qgIndicatorPassed')({ theme })} rx={rx} {...sizeProps} />
- {
- {
- xl: (
- <>
- <path d="M38.974 25 41 27.026 28.847 39.178l-2.025-2.025z" fill={contrastColor} />
- <path d="M30.974 37.153 28.95 39.18 22 32.229l2.026-2.025z" fill={contrastColor} />
- </>
- ),
- md: (
- <>
- <path d="m16.95 7.5 1.308 1.307-7.84 7.84-1.308-1.306z" fill={contrastColor} />
- <path d="m11.79 15.34-1.307 1.307-4.484-4.483 1.307-1.306z" fill={contrastColor} />
- </>
- ),
- sm: (
- <>
- <path d="m11.3 5 .871.87-5.227 5.228-.87-.871z" fill={contrastColor} />
- <path d="m7.86 10.227-.872.871L4 8.11l.871-.871z" fill={contrastColor} />
- </>
- ),
- }[size]
- }
- </svg>
- );
-}
-
-function QGFailed({ className, rx, size, tooltipPlacement, ...sizeProps }: IconProps) {
- const theme = useTheme();
- const contrastColor = themeContrast('qgIndicatorFailed')({ theme });
- const intl = useIntl();
- const formatted = intl.formatMessage({ id: 'metric.level.ERROR' });
- const title = intl.formatMessage({ id: 'overview.quality_gate_x' }, { '0': formatted });
-
- return (
- <svg className={className} {...COMMON_PROPS} {...sizeProps}>
- <title>{title}</title>
- <rect fill={themeColor('qgIndicatorFailed')({ theme })} rx={rx} {...sizeProps} />
- {
- {
- xl: (
- <>
- <path d="m37.153 25 2.026 2.026-12.153 12.152L25 37.153z" fill={contrastColor} />
- <path d="m39.178 37.153-2.025 2.026L25 27.026 27.026 25z" fill={contrastColor} />
- </>
- ),
- md: (
- <>
- <path d="m15.34 7.5 1.307 1.307-7.84 7.84L7.5 15.34z" fill={contrastColor} />
- <path d="m16.647 15.34-1.307 1.307-7.84-7.84L8.806 7.5z" fill={contrastColor} />
- </>
- ),
- sm: (
- <>
- <path d="m10.227 5 .871.871-5.227 5.227L5 10.227z" fill={contrastColor} />
- <path d="m11.098 10.227-.871.87L5 5.872 5.87 5z" fill={contrastColor} />
- </>
- ),
- }[size]
- }
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/SearchHighlighter.tsx b/server/sonar-web/src/main/js/design-system/components/SearchHighlighter.tsx
deleted file mode 100644
index 7d82599fc12..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/SearchHighlighter.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { deburr } from 'lodash';
-import * as React from 'react';
-import Highlighter from 'react-highlight-words';
-import { themeColor, themeContrast } from '../helpers/theme';
-
-export const SearchHighlighterContext = React.createContext<string | undefined>(undefined);
-SearchHighlighterContext.displayName = 'SearchHighlighterContext';
-
-interface Props {
- children?: string;
- term?: string;
-}
-
-export function SearchHighlighter({ children = '', term }: Props) {
- const query = React.useContext(SearchHighlighterContext);
-
- const searchTerm = term ?? query;
- if (searchTerm) {
- return (
- <StyledHighlighter
- autoEscape
- sanitize={deburr}
- searchWords={[searchTerm]}
- textToHighlight={children}
- />
- );
- }
- return <>{children}</>;
-}
-
-const StyledHighlighter = styled(Highlighter)`
- mark {
- color: ${themeContrast('searchHighlight')};
- font-weight: inherit;
- background: ${themeColor('searchHighlight')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/SelectionCard.tsx b/server/sonar-web/src/main/js/design-system/components/SelectionCard.tsx
deleted file mode 100644
index fb8db7785f7..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/SelectionCard.tsx
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { useIntl } from 'react-intl';
-import tw from 'twin.macro';
-import { themeBorder, themeColor, themeContrast, themeShadow } from '../helpers/theme';
-import { LightLabel } from './Text';
-import { RecommendedIcon } from './icons/RecommendedIcon';
-import { RadioButtonStyled } from './input/RadioButton';
-
-export interface SelectionCardProps {
- children?: React.ReactNode;
- className?: string;
- disabled?: boolean;
- onClick?: VoidFunction;
- recommended?: boolean;
- recommendedReason?: string;
- selected?: boolean;
- title: string;
- titleInfo?: React.ReactNode;
- vertical?: boolean;
-}
-
-export function SelectionCard(props: SelectionCardProps) {
- const {
- children,
- className,
- disabled,
- onClick,
- recommended,
- recommendedReason,
- selected = false,
- title,
- titleInfo,
- vertical = false,
- } = props;
- const isActionable = Boolean(onClick);
-
- const intl = useIntl();
-
- return (
- <StyledButton
- aria-checked={selected}
- aria-disabled={disabled}
- className={classNames(
- 'js-radio-card',
- {
- 'card-actionable': isActionable && !disabled,
- 'card-vertical': vertical,
- disabled,
- selected,
- },
- className,
- )}
- onClick={isActionable && !disabled && !selected ? onClick : undefined}
- role={isActionable ? 'radio' : 'presentation'}
- tabIndex={disabled ? -1 : 0}
- type="button"
- >
- <StyledContent>
- {isActionable && (
- <div className="sw-items-start sw-mt-1/2 sw-mr-2">
- <RadioButtonStyled
- as="i"
- className={classNames({ 'is-checked': selected, 'is-disabled': disabled })}
- />
- </div>
- )}
- <div>
- <StyledLabel>
- {title}
- <LightLabel>{titleInfo}</LightLabel>
- </StyledLabel>
- <StyledBody>{children}</StyledBody>
- </div>
- </StyledContent>
- {recommended && (
- <StyledRecommended>
- <StyledRecommendedIcon className="sw-mr-1" />
- <span className="sw-align-middle">
- <strong>{intl.formatMessage({ id: 'recommended' })}</strong> {recommendedReason}
- </span>
- </StyledRecommended>
- )}
- </StyledButton>
- );
-}
-
-const StyledButton = styled.button`
- ${tw`sw-relative sw-flex sw-flex-col`}
- ${tw`sw-rounded-2`}
- ${tw`sw-box-border`}
-
- background-color: ${themeColor('backgroundSecondary')};
- border: ${themeBorder('default', 'selectionCardBorder')};
- color: inherit;
-
- &:focus {
- outline: ${themeBorder('focus', 'selectionCardBorderSelected')};
- box-shadow: ${themeShadow('sm')};
- }
-
- &.card-vertical {
- ${tw`sw-w-full`}
- min-height: auto;
- }
-
- &.card-actionable {
- ${tw`sw-cursor-pointer`}
-
- &:hover {
- border: ${themeBorder('default', 'selectionCardBorderHover')};
- box-shadow: ${themeShadow('sm')};
- }
-
- &.selected {
- border: ${themeBorder('default', 'selectionCardBorderSelected')};
- }
- }
-
- &.disabled {
- ${tw`sw-cursor-not-allowed`}
-
- background-color: ${themeColor('selectionCardDisabled')};
- color: var(--echoes-color-text-disabled);
- border: ${themeBorder('default', 'selectionCardBorderDisabled')};
- }
-`;
-
-const StyledContent = styled.div`
- ${tw`sw-my-4 sw-mx-3`}
- ${tw`sw-flex sw-grow`}
- ${tw`sw-text-left`}
-`;
-
-const StyledRecommended = styled.div`
- ${tw`sw-typo-default`}
- ${tw`sw-py-2 sw-px-4`}
- ${tw`sw-box-border`}
- ${tw`sw-rounded-b-2`}
- ${tw`sw-w-full`}
- ${tw`sw-text-left`}
-
- color: ${themeContrast('infoBackground')};
- background-color: ${themeColor('infoBackground')};
-`;
-
-const StyledRecommendedIcon = styled(RecommendedIcon)`
- color: ${themeColor('iconInfo')};
- ${tw`sw-align-middle`}
-`;
-
-const StyledLabel = styled.label`
- ${tw`sw-flex`}
- ${tw`sw-mb-3 sw-gap-2`}
- ${tw`sw-typo-semibold`}
-
- color: ${themeColor('selectionCardHeader')};
- cursor: inherit;
-
- .disabled & {
- color: var(--echoes-color-text-disabled);
- }
-`;
-
-const StyledBody = styled.div`
- ${tw`sw-flex sw-grow`}
- ${tw`sw-flex-col sw-justify-between`}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/Separator.tsx b/server/sonar-web/src/main/js/design-system/components/Separator.tsx
deleted file mode 100644
index 9a1cb89d1a2..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Separator.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeColor } from '../helpers/theme';
-
-export const BasicSeparator = styled.hr`
- height: 1px;
- background-color: ${themeColor('border')};
-
- ${tw`sw-my-1`}
- ${tw`sw-overflow-hidden`};
- ${tw`sw-clear-both`}
-`;
-
-export const BlueGreySeparator = styled(BasicSeparator)`
- background-color: ${themeColor('popupBorder')};
-`;
-
-export const CardSeparator = styled(BasicSeparator)`
- background-color: ${themeColor('projectCardBorder')};
-`;
-
-export const GreySeparator = styled(BasicSeparator)`
- background-color: ${themeColor('subnavigationBorder')};
-`;
-
-export const SubnavigationFlowSeparator = styled(BasicSeparator)`
- background-color: ${themeColor('subnavigationExecutionFlowSeparator')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/SizeIndicator.tsx b/server/sonar-web/src/main/js/design-system/components/SizeIndicator.tsx
deleted file mode 100644
index 4154df9bd09..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/SizeIndicator.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { inRange } from 'lodash';
-import tw from 'twin.macro';
-import { getProp, themeColor, themeContrast } from '../helpers/theme';
-import { SizeLabel } from '../types/measures';
-
-export interface Props {
- size?: 'xs' | 'sm' | 'md';
- value: number;
-}
-
-const SIZE_MAPPING = {
- xs: '1rem',
- sm: '1.5rem',
- md: '2rem',
-};
-
-const SIZE_IN_LOC = {
- xs: 1000,
- sm: 10_000,
- md: 100_000,
- l: 500_000,
-};
-
-export function SizeIndicator({ size = 'sm', value }: Props) {
- let letter: SizeLabel;
- if (inRange(value, 0, SIZE_IN_LOC.xs)) {
- letter = 'XS';
- } else if (inRange(value, SIZE_IN_LOC.xs, SIZE_IN_LOC.sm)) {
- letter = 'S';
- } else if (inRange(value, SIZE_IN_LOC.sm, SIZE_IN_LOC.md)) {
- letter = 'M';
- } else if (inRange(value, SIZE_IN_LOC.md, SIZE_IN_LOC.l)) {
- letter = 'L';
- } else {
- letter = 'XL';
- }
-
- return (
- <StyledContainer aria-hidden="true" size={SIZE_MAPPING[size]}>
- {letter}
- </StyledContainer>
- );
-}
-
-const StyledContainer = styled.div<{ size: string }>`
- width: ${getProp('size')};
- height: ${getProp('size')};
- font-size: ${({ size }) => (size === '2rem' ? '0.875rem' : `calc(${size}/2)`)};
- color: ${themeContrast('sizeIndicator')};
- background-color: ${themeColor('sizeIndicator')};
-
- ${tw`sw-inline-flex sw-items-center sw-justify-center`};
- ${tw`sw-leading-4`};
- ${tw`sw-rounded-pill`};
- ${tw`sw-font-semibold`};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/SonarCodeColorizer.tsx b/server/sonar-web/src/main/js/design-system/components/SonarCodeColorizer.tsx
deleted file mode 100644
index 17c8c6beba5..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/SonarCodeColorizer.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeColor } from '../helpers/theme';
-
-export const SonarCodeColorizer = styled.div`
- & pre {
- ${tw`sw-code`}
-
- color: ${themeColor('codeSyntaxBody')};
- }
-
- /* for example java annotations */
- & .a {
- color: ${themeColor('codeSyntaxAnnotations')};
- }
-
- /* constants */
- & .c {
- ${tw`sw-code-highlight`}
-
- color: ${themeColor('codeSyntaxConstants')};
- }
-
- /* classic comment */
- & .cd {
- ${tw`sw-code-comment`}
-
- color: ${themeColor('codeSyntaxComments')};
- }
-
- /* javadoc */
- & .j {
- ${tw`sw-code-comment`}
-
- color: ${themeColor('codeSyntaxComments')};
- }
-
- /* C++ doc */
- & .cppd {
- ${tw`sw-code-comment`}
-
- color: ${themeColor('codeSyntaxComments')};
- }
-
- /* keyword */
- & .k {
- ${tw`sw-code-highlight`}
-
- color: ${themeColor('codeSyntaxKeyword')};
- }
-
- /* string */
- & .s {
- color: ${themeColor('codeSyntaxString')};
- }
-
- /* keyword light */
- & .h {
- color: ${themeColor('codeSyntaxKeywordLight')};
- }
-
- /* preprocessing directive */
- & .p {
- color: ${themeColor('codeSyntaxPreprocessingDirective')};
- }
-`;
-SonarCodeColorizer.displayName = 'SonarCodeColorizer';
diff --git a/server/sonar-web/src/main/js/design-system/components/SonarQubeLogo.tsx b/server/sonar-web/src/main/js/design-system/components/SonarQubeLogo.tsx
deleted file mode 100644
index e83aed8a988..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/SonarQubeLogo.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-
-const SonarQubeLogoSvg = styled.svg`
- height: 40px;
- width: 132px;
-`;
-
-export function SonarQubeLogo() {
- return (
- <SonarQubeLogoSvg viewBox="0 0 540.33 156.33" xmlns="http://www.w3.org/2000/svg">
- <path
- d="M11.89 101.92a29.92 29.92 0 0 0 13.23 3.74c4.65 0 6.57-1.62 6.57-4.14s-1.51-3.74-7.27-5.66c-10.21-3.44-14.15-9-14-14.85 0-9.2 7.89-16.17 20.11-16.17a33.07 33.07 0 0 1 13.95 2.83l-2.78 10.6A24.24 24.24 0 0 0 31 75.44c-3.74 0-5.87 1.51-5.87 4 0 2.33 1.93 3.54 8 5.66 9.4 3.23 13.34 8 13.44 15.26 0 9.19-7.27 16-21.42 16-6.47 0-12.22-1.42-16-3.44zM100.63 90.09c0 18.09-12.83 26.38-26.08 26.38C60.11 116.48 49 107 49 91s10.5-26.17 26.37-26.17c15.16 0 25.26 10.41 25.26 25.26zm-35.78.51c0 8.49 3.54 14.85 10.11 14.85 6 0 9.8-6 9.8-14.85 0-7.38-2.83-14.87-9.8-14.87-7.37.01-10.11 7.59-10.11 14.87zM106.11 81.71c0-6.16-.2-11.42-.41-15.76H119l.7 6.76h.31a18.08 18.08 0 0 1 15.25-7.88c10.11 0 17.69 6.66 17.69 21.22v29.31h-15.31V88c0-6.37-2.22-10.71-7.78-10.71a8.18 8.18 0 0 0-7.78 5.71 10.41 10.41 0 0 0-.61 3.84v28.51h-15.36zM189.39 115.36l-.91-5h-.3c-3.23 3.95-8.3 6.07-14.15 6.07-10 0-16-7.29-16-15.16 0-12.83 11.52-19 29-18.91v-.7c0-2.63-1.42-6.37-9-6.37a27.8 27.8 0 0 0-13.64 3.73l-2.84-9.9c3.44-1.93 10.21-4.35 19.2-4.35 16.48 0 21.73 9.7 21.73 21.32v17.18a75.92 75.92 0 0 0 .71 12zM187.58 92c-8.08-.1-14.35 1.83-14.35 7.78 0 3.95 2.63 5.87 6.07 5.87a8.39 8.39 0 0 0 8-5.66 10.87 10.87 0 0 0 .31-2.63zM210.63 82.21c0-7.27-.2-12-.41-16.26h13.24L224 75h.4c2.53-7.17 8.59-10.2 13.34-10.2a16.56 16.56 0 0 1 3.26.2v14.48a21.82 21.82 0 0 0-4.14-.41c-5.66 0-9.5 3-10.52 7.78a18.94 18.94 0 0 0-.3 3.44v25.07h-15.41zM342.35 102c0 5 .1 9.5.41 13.34h-7.89l-.51-8h-.19a18.43 18.43 0 0 1-16.17 9.1c-7.68 0-16.89-4.24-16.89-21.42V66.44H310v27.09c0 9.29 2.83 15.57 10.92 15.57a12.88 12.88 0 0 0 11.72-8.1 13.15 13.15 0 0 0 .81-4.55v-30h8.9zM352.67 115.36c.2-3.34.4-8.3.4-12.64V43.6h8.79v30.73h.2c3.13-5.46 8.79-9 16.68-9 12.12 0 20.71 10.11 20.61 25 0 17.49-11 26.18-21.92 26.18-7.08 0-12.73-2.73-16.37-9.2h-.31l-.4 8.09zm9.19-19.61a16.48 16.48 0 0 0 .41 3.23 13.71 13.71 0 0 0 13.33 10.41c9.31 0 14.85-7.58 14.85-18.79 0-9.8-5-18.19-14.55-18.19a14.17 14.17 0 0 0-13.54 10.91 17.47 17.47 0 0 0-.51 3.64zM411.5 92.52c.19 12 7.88 17 16.77 17a32.24 32.24 0 0 0 13.54-2.52l1.52 6.37c-3.13 1.41-8.49 3-16.27 3-15.06 0-24.06-9.9-24.06-24.65s8.69-26.38 22.94-26.38c16 0 20.21 14 20.21 23a33.67 33.67 0 0 1-.3 4.14zm26.07-6.37c.1-5.66-2.31-14.46-12.32-14.46-9 0-12.94 8.3-13.65 14.46z"
- fill="#1b171b"
- />
- <path
- d="M290.55 75.25a26.41 26.41 0 1 0-11.31 39.07l10.22 16.6 8.11-5.51-10.22-16.6a26.42 26.42 0 0 0 3.2-33.56M279.1 105.4a18.5 18.5 0 1 1 4.9-25.7 18.52 18.52 0 0 1-4.9 25.7"
- fill="#1b171b"
- fillRule="evenodd"
- />
- <path
- d="M506.94 115.57h-6.27c0-50.44-41.62-91.48-92.78-91.48v-6.26c54.62 0 99.05 43.84 99.05 97.74z"
- fill="#4e9bcd"
- />
- <path
- d="M511.27 81.93c-7.52-31.65-33.16-58.06-65.27-67.29l1.44-5c33.93 9.74 61 37.65 68.95 71.1zM516.09 52.23a96 96 0 0 0-37.17-41.49l2.17-3.57a100.24 100.24 0 0 1 38.8 43.31z"
- fill="#4e9bcd"
- />
- </SonarQubeLogoSvg>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/Spinner.tsx b/server/sonar-web/src/main/js/design-system/components/Spinner.tsx
deleted file mode 100644
index 5910ae45e0e..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Spinner.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { keyframes } from '@emotion/react';
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import * as React from 'react';
-import { useIntl } from 'react-intl';
-import tw from 'twin.macro';
-import { themeColor } from '../helpers/theme';
-
-interface Props {
- ariaLabel?: string;
- className?: string;
- customSpinner?: JSX.Element;
- loading?: boolean;
- placeholder?: boolean;
-}
-
-/** @deprecated Use Spinner from Echoes instead.
- *
- * Some of the props have changed or been renamed:
- * - ~`customSpinner`~ has been removed
- * - `loading` is now `isLoading`
- * - `placeholder` is now `hasPlaceholder`
- */
-export function Spinner(props: React.PropsWithChildren<Props>) {
- const intl = useIntl();
- const {
- customSpinner,
- className,
- children,
- placeholder,
- ariaLabel = intl.formatMessage({ id: 'loading' }),
- loading = true,
- } = props;
-
- if (customSpinner) {
- return <>{loading ? customSpinner : children}</>;
- }
-
- return (
- // Below: using <></> won't work in extenstions ('React' is not defined). This is because the
- // name 'React' would already have been minified to something else when <> is resolved to
- // React.Fragment
- // eslint-disable-next-line react/jsx-fragments
- <React.Fragment>
- <div className="sw-relative">
- <div
- className={classNames('sw-overflow-hidden', {
- 'sw-sr-only': !loading,
- it__loading: loading,
- })}
- >
- <StyledSpinner aria-live="polite" className={className} role="status">
- {loading && <span className="sw-sr-only">{ariaLabel}</span>}
- </StyledSpinner>
- </div>
- </div>
- {!loading && (children ?? (placeholder && <Placeholder className={className} />) ?? null)}
- </React.Fragment>
- );
-}
-
-const spinAnimation = keyframes`
- from {
- transform: rotate(0deg);
- }
-
- to {
- transform: rotate(-360deg);
- }
-`;
-
-const StyledSpinner = styled.div`
- border: 2px solid transparent;
- background:
- linear-gradient(0deg, ${themeColor('primary')} 50%, transparent 50% 100%) border-box,
- linear-gradient(90deg, ${themeColor('primary')} 25%, transparent 75% 100%) border-box;
- mask:
- linear-gradient(#fff 0 0) padding-box,
- linear-gradient(#fff 0 0);
- -webkit-mask-composite: xor;
- mask-composite: exclude;
- animation: ${spinAnimation} 1s infinite linear;
-
- ${tw`sw-h-4 sw-w-4`};
- ${tw`sw-inline-block`};
- ${tw`sw-box-border`};
- ${tw`sw-rounded-pill`}
-`;
-
-const Placeholder = styled.div`
- position: relative;
- visibility: hidden;
-
- ${tw`sw-inline-flex sw-items-center sw-justify-center`};
- ${tw`sw-h-4 sw-w-4`};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/SpotlightTour.tsx b/server/sonar-web/src/main/js/design-system/components/SpotlightTour.tsx
deleted file mode 100644
index ecfdd774044..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/SpotlightTour.tsx
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { keyframes } from '@emotion/react';
-import styled from '@emotion/styled';
-import {
- Button,
- ButtonIcon,
- ButtonVariety,
- IconX,
- LinkStandalone,
- TooltipProvider,
-} from '@sonarsource/echoes-react';
-import React from 'react';
-import { useIntl } from 'react-intl';
-import ReactJoyride, {
- Props as JoyrideProps,
- Step as JoyrideStep,
- TooltipRenderProps,
-} from 'react-joyride';
-import { LinkProps } from 'react-router-dom';
-import tw from 'twin.macro';
-import { GLOBAL_POPUP_Z_INDEX, PopupZLevel, themeColor } from '../helpers';
-import { findAnchor } from '../helpers/dom';
-import { PopupWrapper } from './popups';
-
-type Placement = 'left' | 'right' | 'top' | 'bottom' | 'center';
-
-export interface SpotlightTourProps extends Omit<JoyrideProps, 'steps'> {
- actionLabel?: string;
- actionPath?: LinkProps['to'];
- backLabel?: string;
- closeLabel?: string;
- nextLabel?: string;
- skipLabel?: string;
- stepXofYLabel?: (x: number, y: number) => string;
- steps: SpotlightTourStep[];
- width?: number;
-}
-
-export type SpotlightTourStep = JoyrideStep & {
- placement?: Placement;
-};
-
-// React Joyride needs a "global" property to be defined on window. It will throw an error if it cannot find it.
-// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
-(window as any).global = (window as any).global ?? {};
-
-const PULSE_SIZE = 8;
-const DEFAULT_PLACEMENT = 'bottom';
-const DEFAULT_WIDTH = 315;
-const defultRect = new DOMRect(0, 0, 0, 0);
-
-function TooltipComponent({
- actionLabel,
- actionPath,
- continuous,
- index,
- step,
- size,
- isLastStep,
- backProps,
- skipProps: { 'aria-label': skipPropsAriaLabel, ...skipProps },
- closeProps,
- primaryProps,
- stepXofYLabel,
- tooltipProps,
- width = DEFAULT_WIDTH,
-}: TooltipRenderProps & {
- actionLabel?: string;
- actionPath?: LinkProps['to'];
- step: SpotlightTourStep;
- stepXofYLabel: SpotlightTourProps['stepXofYLabel'];
- width?: number;
-}) {
- const [timeStamp, setTimeStamp] = React.useState(0);
- const [ref, setRef] = React.useState<HTMLDivElement | null>(null);
-
- const placement = step.placement ?? DEFAULT_PLACEMENT;
- const intl = useIntl();
-
- React.useEffect(() => {
- const target =
- typeof step.target === 'string' ? document.querySelector(step.target) : step.target;
- // To show the highlight, target has to be HighlightRing from design system
- target?.classList.add('active');
-
- return () => {
- target?.classList.remove('active');
- };
- }, [step]);
-
- React.useEffect(() => {
- const updateScroll = (event: Event) => {
- // The spotlight is doint transition that would look strange when we
- // re-render arrow right away.
- setTimeout(() => {
- setTimeStamp(event.timeStamp);
- }, 0);
- };
-
- document.addEventListener('scroll', updateScroll, { capture: true });
-
- return () => {
- document.removeEventListener('scroll', updateScroll, { capture: true });
- };
- }, []);
-
- const rect = ref?.parentElement?.getBoundingClientRect();
- const targetElement =
- typeof step.target === 'string'
- ? document.querySelector<HTMLElement>(step.target)
- : step.target;
- const targetRect = targetElement?.getBoundingClientRect();
-
- /**
- * Preventing click events from bubbling to avoid closing other popups, in cases when the guide
- * is shown simultaneously with other popups.
- */
- function handleClick(e: React.MouseEvent) {
- e.stopPropagation();
- }
-
- const arrowPosition = React.useMemo(
- () => findAnchor(rect ?? defultRect, targetRect ?? defultRect, PULSE_SIZE),
- [rect, targetRect, timeStamp],
- );
-
- return (
- <StyledPopupWrapper
- className="sw-p-3 sw-typo-default sw-relative sw-border-0"
- onClick={handleClick}
- style={{ width }}
- zLevel={PopupZLevel.Absolute}
- {...tooltipProps}
- >
- {placement !== 'center' && (
- <SpotlightArrowWrapper left={arrowPosition.left} top={arrowPosition.top}>
- <SpotlightArrow rotate={arrowPosition.rotate} width={arrowPosition.width} />
- </SpotlightArrowWrapper>
- )}
-
- <div
- className="sw-flex sw-justify-between"
- ref={(r) => {
- setRef(r);
- setTimeout(() => {
- setTimeStamp(1);
- }, 100);
- }}
- >
- <strong className="sw-typo-lg-semibold sw-mb-2">{step.title}</strong>
- <ButtonIcon
- Icon={IconX}
- ariaLabel={skipPropsAriaLabel}
- className="sw--mt-2 sw--mr-2"
- variety={ButtonVariety.DefaultGhost}
- {...skipProps}
- />
- </div>
- <div>{step.content}</div>
-
- {actionLabel && actionPath && (
- <div className="sw-pt-4">
- <LinkStandalone to={actionPath}>{actionLabel}</LinkStandalone>
- </div>
- )}
-
- {!step.hideFooter && (
- <div className="sw-flex sw-justify-between sw-items-center sw-mt-4">
- {(stepXofYLabel || size > 1) && (
- <strong>
- {stepXofYLabel
- ? stepXofYLabel(index + 1, size)
- : intl.formatMessage({ id: 'guiding.step_x_of_y' }, { '0': index + 1, '1': size })}
- </strong>
- )}
- <span />
- <div>
- {index > 0 && (
- <Button className="sw-mr-4" variety={ButtonVariety.DefaultGhost} {...backProps}>
- {backProps.title}
- </Button>
- )}
- {continuous && !isLastStep && (
- <Button variety={ButtonVariety.Primary} {...primaryProps}>
- {primaryProps.title}
- </Button>
- )}
- {(!continuous || isLastStep) && (
- <Button variety={ButtonVariety.Primary} {...closeProps}>
- {closeProps.title}
- </Button>
- )}
- </div>
- </div>
- )}
- </StyledPopupWrapper>
- );
-}
-
-export function SpotlightTour(props: SpotlightTourProps) {
- const {
- actionLabel,
- actionPath,
- steps,
- skipLabel,
- backLabel,
- closeLabel,
- nextLabel,
- stepXofYLabel,
- disableOverlay = true,
- width,
- ...otherProps
- } = props;
-
- const intl = useIntl();
-
- return (
- <ReactJoyride
- disableOverlay={disableOverlay}
- floaterProps={{
- styles: {
- floater: {
- zIndex: GLOBAL_POPUP_Z_INDEX,
- },
- },
- hideArrow: true,
- offset: 0,
- }}
- locale={{
- skip: skipLabel ?? intl.formatMessage({ id: 'skip' }),
- back: backLabel ?? intl.formatMessage({ id: 'go_back' }),
- close: closeLabel ?? intl.formatMessage({ id: 'close' }),
- next: nextLabel ?? intl.formatMessage({ id: 'next' }),
- }}
- scrollDuration={0}
- scrollOffset={250}
- steps={steps.map((s) => ({
- ...s,
- disableScrolling: true,
- disableBeacon: true,
- floaterProps: {
- disableAnimation: true,
- offset: 0,
- },
- }))}
- tooltipComponent={(
- tooltipProps: React.PropsWithChildren<TooltipRenderProps & { step: SpotlightTourStep }>,
- ) => (
- <TooltipProvider>
- <TooltipComponent
- actionLabel={actionLabel}
- actionPath={actionPath}
- stepXofYLabel={stepXofYLabel}
- width={width}
- {...tooltipProps}
- />
- </TooltipProvider>
- )}
- {...otherProps}
- />
- );
-}
-
-const StyledPopupWrapper = styled(PopupWrapper)`
- background-color: ${themeColor('spotlightBackgroundColor')};
- ${tw`sw-overflow-visible`};
- ${tw`sw-rounded-1`};
-`;
-
-const SpotlightArrowWrapper = styled.div<{ left: number; top: number }>`
- ${tw`sw-absolute`}
- ${tw`sw-z-popup`}
-
- width: ${PULSE_SIZE}px;
- height: ${PULSE_SIZE}px;
- left: ${({ left }) => left}px;
- top: ${({ top }) => top}px;
-`;
-
-const pulseKeyFrame = keyframes`
- 0% { transform: scale(.50) }
- 80%, 100% { opacity: 0 }
-`;
-
-const SpotlightArrow = styled.div<{ rotate: string; width: number }>`
- ${tw`sw-w-full sw-h-full`}
- ${tw`sw-rounded-pill`}
- background: ${themeColor('spotlightPulseBackground')};
- opacity: 1;
- transform: rotate(${({ rotate }) => rotate});
-
- &::after {
- ${tw`sw-block sw-absolute`}
- ${tw`sw-rounded-pill`}
-
- top: -100%;
- left: -100%;
- width: 300%;
- height: 300%;
- background-color: ${themeColor('spotlightPulseBackground')};
- animation: ${pulseKeyFrame} 1.25s cubic-bezier(0.215, 0.61, 0.355, 1) infinite;
- content: '';
- }
-
- &::before {
- ${tw`sw-block sw-absolute`}
-
- width: ${({ width }) => width}px;
- height: 0.125rem;
- background-color: ${themeColor('spotlightPulseBackground')};
- left: 100%;
- top: calc(50% - calc(0.125rem / 2));
- transition:
- margin 0.3s,
- left 0.3s;
- content: '';
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/Switch.tsx b/server/sonar-web/src/main/js/design-system/components/Switch.tsx
deleted file mode 100644
index 0c684bd061d..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Switch.tsx
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { ForwardedRef, forwardRef } from 'react';
-import tw from 'twin.macro';
-import { themeColor, themeContrast, themeShadow } from '../helpers';
-import { CheckIcon } from './icons';
-
-interface Props {
- ariaDescribedby?: string;
- ariaLabel?: string;
- disabled?: boolean;
- id?: string;
- name?: string;
- onChange?: (value: boolean) => void;
- value: boolean | string;
-}
-
-const getValue = (value: boolean | string) => {
- return typeof value === 'string' ? value === 'true' : value;
-};
-
-function SwitchWithRef(props: Readonly<Props>, ref: ForwardedRef<HTMLButtonElement>) {
- const { ariaDescribedby, ariaLabel, disabled, name, value: propsValue, onChange, id } = props;
- const value = getValue(propsValue);
-
- const handleClick = () => {
- if (!disabled && onChange) {
- const value = getValue(propsValue);
- onChange(!value);
- }
- };
-
- return (
- <StyledSwitch
- active={value}
- aria-checked={value}
- aria-describedby={ariaDescribedby}
- aria-label={ariaLabel}
- disabled={disabled}
- name={name}
- id={id}
- onClick={handleClick}
- ref={ref}
- role="switch"
- type="button"
- >
- <CheckIconContainer active={value} disabled={disabled}>
- {value && <CheckIcon fill="currentColor" />}
- </CheckIconContainer>
- </StyledSwitch>
- );
-}
-
-interface StyledProps {
- active: boolean;
- disabled?: boolean;
-}
-
-const CheckIconContainer = styled.div<StyledProps>`
- ${tw`sw-rounded-pill`}
- ${tw`sw-flex sw-items-center sw-justify-center`}
- ${tw`sw-w-4 sw-h-4`}
- color: ${({ disabled }) =>
- disabled ? 'var(--echoes-color-icon-disabled)' : themeContrast('switchButton')};
- background: ${({ disabled }) =>
- disabled ? themeColor('switchButtonDisabled') : themeColor('switchButton')};
- border: none;
- box-shadow: ${themeShadow('xs')};
- transform: ${({ active }) => (active ? 'translateX(1rem)' : 'translateX(0)')};
- cursor: inherit;
- transition: transform 0.3s ease;
-`;
-
-const StyledSwitch = styled.button<StyledProps>`
- ${tw`sw-flex sw-flex-row`}
- ${tw`sw-rounded-pill`}
- ${tw`sw-p-1/2`}
- ${tw`sw-cursor-pointer`}
- width: 2.25rem;
- height: 1.25rem;
- background: ${({ active }) => (active ? themeColor('switchActive') : themeColor('switch'))};
- border: none;
- transition: 0.3s ease;
- transition-property: background;
-
- &:hover:not(:disabled),
- &:active:not(:disabled),
- &:focus:not(:disabled) {
- background: ${({ active }) =>
- active ? themeColor('switchHoverActive') : themeColor('switchHover')};
- ${CheckIconContainer} {
- color: ${themeContrast('switchHover')};
- }
- }
-
- &:disabled {
- background: ${themeColor('switchDisabled')};
- }
-
- &:focus:not(:disabled),
- &:active:not(:disabled) {
- outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
- outline-offset: var(--echoes-focus-border-offset-default);
- }
-`;
-
-export const Switch = forwardRef(SwitchWithRef);
diff --git a/server/sonar-web/src/main/js/design-system/components/Tabs.tsx b/server/sonar-web/src/main/js/design-system/components/Tabs.tsx
deleted file mode 100644
index 8bc9dec8b74..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Tabs.tsx
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { PropsWithChildren } from 'react';
-import { FormattedMessage } from 'react-intl';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../helpers';
-import { BareButton } from '../sonar-aligned/components/buttons';
-import { getTabId, getTabPanelId } from '../sonar-aligned/helpers/tabs';
-import { Badge } from './Badge';
-
-type TabValueType = string | number | boolean;
-
-export interface TabOption<T extends TabValueType> {
- counter?: number;
- disabled?: boolean;
- label: string | React.ReactNode;
- value: T;
-}
-
-export interface TabsProps<T extends TabValueType> {
- borderColor?: ReturnType<typeof themeBorder>;
- className?: string;
- disabled?: boolean;
- label?: string;
- large?: boolean;
- onChange: (value: T) => void;
- options: ReadonlyArray<TabOption<T>>;
- value?: T;
-}
-
-export function Tabs<T extends TabValueType>(props: PropsWithChildren<TabsProps<T>>) {
- const {
- disabled = false,
- label,
- options,
- value,
- className,
- children,
- large = false,
- borderColor = themeBorder('default'),
- } = props;
-
- return (
- <TabsContainer borderColor={borderColor} className={className} large={large}>
- <TabList aria-label={label} role="tablist">
- {options.map((option) => (
- <TabButton
- aria-controls={getTabPanelId(String(option.value))}
- aria-current={option.value === value}
- aria-selected={option.value === value}
- borderColor={borderColor}
- data-value={option.value}
- disabled={disabled || option.disabled}
- id={getTabId(String(option.value))}
- key={option.value.toString()}
- large={large}
- onClick={() => {
- if (option.value !== value) {
- props.onChange(option.value);
- }
- }}
- role="tab"
- selected={option.value === value}
- >
- {option.label}
- {option.counter ? (
- <Badge className="sw-ml-2 sw-font-semibold" variant="counterFailed">
- <FormattedMessage id="overview.failed.badge" values={{ counter: option.counter }} />
- </Badge>
- ) : null}
- </TabButton>
- ))}
- </TabList>
- <RightSection>{children}</RightSection>
- </TabsContainer>
- );
-}
-
-const TabsContainer = styled.div<{ borderColor: ReturnType<typeof themeBorder>; large: boolean }>`
- ${tw`sw-w-full`};
- ${(props) => !props.large && tw`sw-pl-4`}
- ${tw`sw-flex sw-justify-between`};
- border-bottom: ${(props) => props.borderColor};
-`;
-
-const TabList = styled.div`
- ${tw`sw-inline-flex`};
-`;
-
-const TabButton = styled(BareButton)<{
- borderColor: ReturnType<typeof themeBorder>;
- large: boolean;
- selected: boolean;
-}>`
- ${tw`sw-relative`};
- ${tw` sw-mb-[-1px]`};
- ${tw`sw-flex sw-items-center`};
- ${(props) => (props.large ? tw`sw-typo-lg sw-px-6 sw-py-4` : tw`sw-typo-default sw-px-3 sw-py-1`)}
- ${tw`sw-font-semibold`};
- ${tw`sw-rounded-t-1`};
-
- height: 34px;
- background: ${(props) => (props.selected ? themeColor('backgroundSecondary') : 'none')};
- color: ${(props) =>
- props.selected ? themeColor('tabSelected') : 'var(--echoes-color-text-subdued)'};
- border: ${(props) =>
- props.selected ? props.borderColor : themeBorder('default', 'transparent')};
- border-bottom: ${(props) =>
- props.selected ? themeBorder('default', 'backgroundSecondary') : props.borderColor};
-
- &:hover {
- background: ${(props) =>
- props.selected ? themeColor('backgroundSecondary') : themeColor('tabHover')};
- }
-
- &:active {
- outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
- z-index: 1;
- }
-
- // Active line
- &::after {
- content: '';
- ${tw`sw-absolute`};
- ${tw`sw-rounded-t-1`};
- top: 0;
- left: 0;
- width: calc(100%);
- height: 2px;
- background: ${(props) => (props.selected ? themeColor('tabSelected') : 'none')};
- }
-`;
-
-const RightSection = styled.div`
- max-height: 43px;
- ${tw`sw-flex sw-items-center`};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/Tags.tsx b/server/sonar-web/src/main/js/design-system/components/Tags.tsx
deleted file mode 100644
index 4b90ac8e5aa..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Tags.tsx
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import * as React from 'react';
-import tw from 'twin.macro';
-import { PopupPlacement, PopupZLevel } from '../helpers';
-import { themeColor, themeContrast } from '../helpers/theme';
-import { Dropdown } from './Dropdown';
-import { LightLabel } from './Text';
-import { WrapperButton } from './buttons';
-
-interface Props {
- allowUpdate?: boolean;
- ariaTagsListLabel: string;
- className?: string;
- emptyText: string;
- menuId?: string;
- onClose?: VoidFunction;
- open?: boolean;
- overlay?: React.ReactNode;
- popupPlacement?: PopupPlacement;
- tags: string[];
- tagsClassName?: string;
- tagsToDisplay?: number;
- tooltip?: React.ComponentType<React.PropsWithChildren<{ content: React.ReactNode }>>;
-}
-
-export function Tags({
- allowUpdate = false,
- ariaTagsListLabel,
- className,
- tagsClassName,
- emptyText,
- menuId = '',
- overlay,
- popupPlacement,
- tags,
- tagsToDisplay = 3,
- tooltip,
- open,
- onClose,
-}: Readonly<Props>) {
- const displayedTags = tags.slice(0, tagsToDisplay);
- const extraTags = tags.slice(tagsToDisplay);
- const Tooltip = tooltip || React.Fragment;
-
- const displayedTagsContent = (open = false) => (
- <Tooltip content={open ? undefined : tags.join(', ')}>
- <span className="sw-inline-flex sw-items-center sw-gap-1">
- {/* Display first 3 (tagsToDisplay) tags */}
- {displayedTags.map((tag) => (
- <TagLabel key={tag}>{tag}</TagLabel>
- ))}
-
- {/* Show ellipsis if there are more tags */}
- {extraTags.length > 0 ? <TagLabel>...</TagLabel> : null}
-
- {/* Handle no tags with its own styling */}
- {tags.length === 0 && <LightLabel>{emptyText}</LightLabel>}
- </span>
- </Tooltip>
- );
-
- return (
- <span
- aria-label={`${ariaTagsListLabel}: ${tags.join(', ')}`}
- className={classNames('sw-cursor-default sw-flex sw-items-center', className)}
- >
- {allowUpdate ? (
- <Dropdown
- allowResizing
- closeOnClick={false}
- id={menuId}
- onClose={onClose}
- openDropdown={open}
- overlay={overlay}
- placement={popupPlacement}
- zLevel={PopupZLevel.Global}
- >
- {({ a11yAttrs, onToggleClick, open }) => (
- <WrapperButton
- className={classNames(
- 'sw-flex sw-items-center sw-gap-1 sw-p-0 sw-h-auto sw-rounded-0',
- tagsClassName,
- )}
- onClick={onToggleClick}
- {...a11yAttrs}
- >
- {displayedTagsContent(open)}
- <TagLabel className="sw-cursor-pointer">+</TagLabel>
- </WrapperButton>
- )}
- </Dropdown>
- ) : (
- <span>{displayedTagsContent()}</span>
- )}
- </span>
- );
-}
-
-const TagLabel = styled.span`
- color: ${themeContrast('tag')};
- background: ${themeColor('tag')};
-
- ${tw`sw-box-border`}
- ${tw`sw-truncate`}
- ${tw`sw-rounded-1/2`}
- ${tw`sw-px-1 sw-py-1/2`}
- ${tw`sw-max-w-32`}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/Text.tsx b/server/sonar-web/src/main/js/design-system/components/Text.tsx
deleted file mode 100644
index 71275eb2237..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Text.tsx
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { ElementType } from 'react';
-import tw from 'twin.macro';
-import { themeColor, themeContrast } from '../helpers/theme';
-import { SafeHTMLInjection } from '../sonar-aligned/helpers/sanitize';
-
-interface TextBoldProps {
- className?: string;
- match?: string;
- name: string;
-}
-
-/** @deprecated Use Text (with `isHighlighted` prop) from Echoes instead.
- */
-export function TextBold({ match, name, className }: TextBoldProps) {
- return match ? (
- <SafeHTMLInjection htmlAsString={match}>
- <StyledText className={className} />
- </SafeHTMLInjection>
- ) : (
- <StyledText className={className} title={name}>
- {name}
- </StyledText>
- );
-}
-
-/** @deprecated Use Text (with `isSubdued` prop) from Echoes instead.
- */
-export function TextMuted({ text, className }: Readonly<{ className?: string; text: string }>) {
- return (
- <StyledMutedText className={className} title={text}>
- {text}
- </StyledMutedText>
- );
-}
-
-/** @deprecated Use Heading from Echoes instead.
- */
-export function PageTitle({
- text,
- className,
- as = 'h1',
-}: {
- as?: ElementType;
- className?: string;
- text: string;
-}) {
- return (
- <StyledPageTitle as={as} className={className} title={text}>
- {text}
- </StyledPageTitle>
- );
-}
-
-/** @deprecated Use Text (with `colorOverride='echoes-color-text-danger'` prop) from Echoes instead.
- */
-export function TextError({
- as,
- text,
- className,
-}: Readonly<{
- as?: React.ElementType;
- className?: string;
- text: string | React.ReactNode;
-}>) {
- if (typeof text === 'string') {
- return (
- <StyledTextError as={as} className={className} title={text}>
- {text}
- </StyledTextError>
- );
- }
- return (
- <StyledTextError as={as} className={className}>
- {text}
- </StyledTextError>
- );
-}
-
-/** @deprecated Use Text (with `colorOverride='echoes-color-text-success'` prop) from Echoes instead.
- */
-export function TextSuccess({ text, className }: Readonly<{ className?: string; text: string }>) {
- return (
- <StyledTextSuccess className={className} title={text}>
- {text}
- </StyledTextSuccess>
- );
-}
-
-const StyledText = styled.span`
- ${tw`sw-inline-block`};
- ${tw`sw-truncate`};
- ${tw`sw-font-semibold`};
- ${tw`sw-max-w-abs-800`}
-
- mark {
- ${tw`sw-inline-block`};
-
- background: ${themeColor('searchHighlight')};
- color: ${themeContrast('searchHighlight')};
- }
-`;
-
-/** @deprecated Use Text (with `isSubdued` prop) from Echoes instead.
- */
-export const StyledMutedText = styled(StyledText)`
- ${tw`sw-font-regular`};
- color: var(--echoes-color-text-subdued);
-`;
-
-/** @deprecated Use Heading from Echoes instead.
- */
-export const StyledPageTitle = styled(StyledText)`
- ${tw`sw-block`};
- ${tw`sw-text-base`}
- color: ${themeColor('facetHeader')};
-`;
-
-const StyledTextError = styled(StyledText)`
- color: ${themeColor('danger')};
-`;
-
-const StyledTextSuccess = styled(StyledText)`
- color: ${themeColor('textSuccess')};
-`;
-
-/** @deprecated Use Text (with `isSubdued` prop) from Echoes instead.
- */
-export const TextSubdued = styled.span`
- ${tw`sw-font-regular`};
- color: var(--echoes-color-text-subdued);
-`;
-
-/** @deprecated Use Text (with `isSubdued` prop) from Echoes instead.
- */
-export const LightLabel = styled.span`
- color: var(--echoes-color-text-subdued);
-`;
-
-/** @deprecated Use Label or Text (with `isHighlighted` prop) from Echoes instead.
- */
-export const DarkLabel = styled.label`
- color: ${themeColor('pageContentDark')};
-
- ${tw`sw-typo-semibold`}
-`;
-
-/** @deprecated Use Text from Echoes instead.
- */
-export const LightPrimary = styled.span`
- color: ${themeContrast('primaryLight')};
-`;
-
-/** @deprecated Use Text (with `isHighlighted` prop) from Echoes instead.
- */
-export const Highlight = styled.strong`
- color: ${themeColor('pageContentDark')};
-
- ${tw`sw-typo-semibold`}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/TextAccordion.tsx b/server/sonar-web/src/main/js/design-system/components/TextAccordion.tsx
deleted file mode 100644
index 897e07fe5fb..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/TextAccordion.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { uniqueId } from 'lodash';
-import React, { ReactNode } from 'react';
-import tw from 'twin.macro';
-import { themeColor } from '../helpers';
-import { BareButton } from '../sonar-aligned/components/buttons';
-import { Note } from '../sonar-aligned/components/typography';
-import { OpenCloseIndicator } from './icons';
-
-interface Props {
- ariaLabel: string;
- children: ReactNode;
- className?: string;
- data?: string;
- onClick: (data?: string) => void;
- open: boolean;
- renderHeader?: () => ReactNode;
- title: ReactNode;
-}
-
-export function TextAccordion(props: Readonly<Props>) {
- const [hoveringInner, setHoveringInner] = React.useState(false);
-
- const { className, open, renderHeader, title, ariaLabel } = props;
-
- const id = React.useMemo(() => uniqueId('accordion-'), []);
-
- function handleClick() {
- props.onClick(props.data);
- }
-
- function onDetailEnter() {
- setHoveringInner(true);
- }
-
- function onDetailLeave() {
- setHoveringInner(false);
- }
-
- return (
- <StyledAccordion
- className={classNames('it__text-accordion', className, {
- 'no-hover': hoveringInner,
- })}
- >
- <Note as="h3">
- <BareButton
- aria-controls={`${id}-panel`}
- aria-expanded={open}
- aria-label={ariaLabel}
- className="sw-flex sw-items-center sw-px-2 sw-py-2 sw-box-border sw-w-full"
- id={`${id}-header`}
- onClick={handleClick}
- >
- <AccordionTitle>
- <OpenCloseIndicator className="sw-mr-1" open={open} />
- {title}
- </AccordionTitle>
- {renderHeader?.()}
- </BareButton>
- </Note>
- {open && (
- <AccordionContent onMouseEnter={onDetailEnter} onMouseLeave={onDetailLeave} role="region">
- {props.children}
- </AccordionContent>
- )}
- </StyledAccordion>
- );
-}
-
-const StyledAccordion = styled.div`
- transition: border-color 0.3s ease;
-`;
-
-const AccordionTitle = styled.span`
- cursor: pointer;
- position: relative;
- display: inline-flex;
- align-items: center;
- font-weight: bold;
- vertical-align: middle;
- transition: color 0.3s ease;
-
- ${tw`sw-select-none`}
- ${tw`sw-pt-4 sw-px-page sw-pb-2`}
-
- &:hover {
- color: ${themeColor('linkDefault')};
- }
-`;
-
-const AccordionContent = styled.div`
- ${tw`sw-pl-10`}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/Tooltip.tsx b/server/sonar-web/src/main/js/design-system/components/Tooltip.tsx
deleted file mode 100644
index 3dba3938bb2..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/Tooltip.tsx
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { keyframes, ThemeContext } from '@emotion/react';
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { throttle, uniqueId } from 'lodash';
-import React from 'react';
-import { createPortal, findDOMNode } from 'react-dom';
-import tw from 'twin.macro';
-import { THROTTLE_SCROLL_DELAY } from '../helpers/constants';
-import {
- BasePlacement,
- PLACEMENT_FLIP_MAP,
- PopupPlacement,
- popupPositioning,
-} from '../helpers/positioning';
-import { themeColor } from '../helpers/theme';
-
-const MILLISECONDS_IN_A_SECOND = 1000;
-
-interface TooltipProps {
- children: React.ReactElement;
- content: React.ReactNode;
- mouseEnterDelay?: number;
- mouseLeaveDelay?: number;
- onHide?: VoidFunction;
- onShow?: VoidFunction;
- placement?: BasePlacement;
- visible?: boolean;
-}
-
-interface Measurements {
- height: number;
- left: number;
- leftFix: number;
- top: number;
- topFix: number;
- width: number;
-}
-
-interface OwnState {
- flipped: boolean;
- placement?: PopupPlacement;
- visible: boolean;
-}
-
-type State = OwnState & Partial<Measurements>;
-
-function isMeasured(state: State): state is OwnState & Measurements {
- return state.height !== undefined;
-}
-
-/**
- * @deprecated Use Tooltip from Echoes instead.
- *
- * Echoes Tooltip component should mainly be used on interactive element and contain very simple text based content.
- * If the content is more complex use a Popover component instead (not available yet).
- *
- * Some of the props have changed or been renamed:
- * - `children` is the trigger for the tooltip, should be an interactive Element. If not an Echoes component, make sure the component forwards the props and the ref to an interactive DOM node, it's needed by the tooltip to position itself.
- * - `overlay` is now `content`, that's the tooltip content. It's a ReactNode for convenience but should render only text based content, no interactivity is allowed inside the tooltip.
- * - ~`mouseEnterDelay`~ doesn't exist anymore, was mostly used in situation that should be replaced by a Popover component.
- * - ~`mouseLeaveDelay`~ doesn't exist anymore, was mostly used in situation that should be replaced by a Popover component.
- * - ~`onHide`~ doesn't exist anymore, was mostly used in situation that should be replaced by a Popover component.
- * - ~`onShow`~ doesn't exist anymore, was mostly used in situation that should be replaced by a Popover component.
- * - `placement` is now `align` and `side`, based on the TooltipAlign and TooltipSide enums.
- * - `visible` is now `isOpen`
- */
-export function Tooltip(props: TooltipProps) {
- // overlay is a ReactNode, so it can be a boolean, `undefined` or `null`
- // this allows to easily render a tooltip conditionally
- // more generaly we avoid rendering empty tooltips
- return props.content ? <TooltipInner {...props}>{props.children}</TooltipInner> : props.children;
-}
-
-export class TooltipInner extends React.Component<TooltipProps, State> {
- throttledPositionTooltip: VoidFunction;
- mouseEnterTimeout?: number;
- mouseLeaveTimeout?: number;
- tooltipNode?: HTMLElement | null;
- mounted = false;
- mouseIn = false;
- id: string;
-
- static defaultProps = {
- mouseEnterDelay: 0.1,
- };
-
- constructor(props: TooltipProps) {
- super(props);
-
- this.state = {
- flipped: false,
- placement: props.placement,
- visible: props.visible !== undefined ? props.visible : false,
- };
- this.id = uniqueId('tooltip-');
- this.throttledPositionTooltip = throttle(this.positionTooltip, THROTTLE_SCROLL_DELAY);
- }
-
- componentDidMount() {
- this.mounted = true;
-
- if (this.props.visible === true) {
- this.positionTooltip();
- this.addEventListeners();
- }
- }
-
- componentDidUpdate(prevProps: TooltipProps, prevState: State) {
- if (this.props.placement !== prevProps.placement) {
- this.setState({ placement: this.props.placement }, () => {
- this.onUpdatePlacement(this.hasVisibleChanged(prevState.visible, prevProps.visible));
- });
- } else if (this.hasVisibleChanged(prevState.visible, prevProps.visible)) {
- this.onUpdateVisible();
- } else if (!this.state.flipped && this.needsFlipping(this.state)) {
- this.setState(
- ({ placement = PopupPlacement.Bottom }) => ({
- flipped: true,
- placement: PLACEMENT_FLIP_MAP[placement],
- }),
- () => {
- if (this.state.visible) {
- // Force a re-positioning, as "only" updating the state doesn't
- // recompute the position, only re-renders with the previous
- // position (which is no longer correct).
- this.positionTooltip();
- }
- },
- );
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- this.removeEventListeners();
- this.clearTimeouts();
- }
-
- static contextType = ThemeContext;
-
- onUpdatePlacement = (visibleHasChanged: boolean) => {
- this.setState({ placement: this.props.placement }, () => {
- if (this.isVisible()) {
- this.positionTooltip();
- if (visibleHasChanged) {
- this.addEventListeners();
- }
- }
- });
- };
-
- onUpdateVisible = () => {
- if (this.isVisible()) {
- this.positionTooltip();
- this.addEventListeners();
- } else {
- this.clearPosition();
- this.removeEventListeners();
- }
- };
-
- addEventListeners = () => {
- window.addEventListener('resize', this.throttledPositionTooltip);
- window.addEventListener('scroll', this.throttledPositionTooltip);
- };
-
- removeEventListeners = () => {
- window.removeEventListener('resize', this.throttledPositionTooltip);
- window.removeEventListener('scroll', this.throttledPositionTooltip);
- };
-
- clearTimeouts = () => {
- window.clearTimeout(this.mouseEnterTimeout);
- window.clearTimeout(this.mouseLeaveTimeout);
- };
-
- hasVisibleChanged = (prevStateVisible: boolean, prevPropsVisible?: boolean) => {
- if (this.props.visible === undefined) {
- return prevPropsVisible ?? this.state.visible !== prevStateVisible;
- }
-
- return this.props.visible !== prevPropsVisible;
- };
-
- isVisible = () => this.props.visible ?? this.state.visible;
-
- getPlacement = (): PopupPlacement => this.state.placement ?? PopupPlacement.Bottom;
-
- tooltipNodeRef = (node: HTMLElement | null) => {
- this.tooltipNode = node;
- };
-
- adjustArrowPosition = (
- placement: PopupPlacement,
- { leftFix, topFix, height, width }: Measurements,
- ) => {
- switch (placement) {
- case PopupPlacement.Left:
- case PopupPlacement.Right:
- return {
- marginTop: Math.max(0, Math.min(-topFix, height / 2 - ARROW_WIDTH * 2)),
- };
- default:
- return {
- marginLeft: Math.max(0, Math.min(-leftFix, width / 2 - ARROW_WIDTH * 2)),
- };
- }
- };
-
- positionTooltip = () => {
- // `findDOMNode(this)` will search for the DOM node for the current component
- // first it will find a React.Fragment (see `render`),
- // so it will get the DOM node of the first child, i.e. DOM node of `this.props.children`
- // docs: https://reactjs.org/docs/refs-and-the-dom.html#exposing-dom-refs-to-parent-components
-
- // eslint-disable-next-line react/no-find-dom-node
- const toggleNode = findDOMNode(this);
-
- if (toggleNode && toggleNode instanceof Element && this.tooltipNode) {
- const { height, left, leftFix, top, topFix, width } = popupPositioning(
- toggleNode,
- this.tooltipNode,
- this.getPlacement(),
- );
-
- // save width and height (and later set in `render`) to avoid resizing the popup element,
- // when it's placed close to the window edge
- this.setState({
- left: window.scrollX + left,
- leftFix,
- top: window.scrollY + top,
- topFix,
- width,
- height,
- });
- }
- };
-
- clearPosition = () => {
- this.setState({
- flipped: false,
- left: undefined,
- leftFix: undefined,
- top: undefined,
- topFix: undefined,
- width: undefined,
- height: undefined,
- placement: this.props.placement,
- });
- };
-
- handlePointerEnter = () => {
- this.mouseEnterTimeout = window.setTimeout(
- () => {
- // for some reason even after the `this.mouseEnterTimeout` is cleared, it still triggers
- // to workaround this issue, check that its value is not `undefined`
- // (if it's `undefined`, it means the timer has been reset)
- if (
- this.mounted &&
- this.props.visible === undefined &&
- this.mouseEnterTimeout !== undefined
- ) {
- this.setState({ visible: true });
- }
- },
- (this.props.mouseEnterDelay ?? 0) * MILLISECONDS_IN_A_SECOND,
- );
-
- if (this.props.onShow) {
- this.props.onShow();
- }
- };
-
- handlePointerLeave = () => {
- if (this.mouseEnterTimeout !== undefined) {
- window.clearTimeout(this.mouseEnterTimeout);
- this.mouseEnterTimeout = undefined;
- }
-
- if (!this.mouseIn) {
- this.mouseLeaveTimeout = window.setTimeout(
- () => {
- if (this.mounted && this.props.visible === undefined && !this.mouseIn) {
- this.setState({ visible: false });
- }
- },
- (this.props.mouseLeaveDelay ?? 0) * MILLISECONDS_IN_A_SECOND,
- );
-
- if (this.props.onHide) {
- this.props.onHide();
- }
- }
- };
-
- handleFocus = () => {
- this.setState({ visible: true });
- if (this.props.onShow) {
- this.props.onShow();
- }
- };
-
- handleBlur = () => {
- this.setState({ visible: false });
- };
-
- handleOverlayPointerEnter = () => {
- this.mouseIn = true;
- };
-
- handleOverlayPointerLeave = () => {
- this.mouseIn = false;
- this.handlePointerLeave();
- };
-
- handleChildPointerEnter = () => {
- this.handlePointerEnter();
-
- const { children } = this.props;
-
- const props = children.props as { onPointerEnter?: VoidFunction };
-
- if (typeof props.onPointerEnter === 'function') {
- props.onPointerEnter();
- }
- };
-
- handleChildPointerLeave = () => {
- this.handlePointerLeave();
-
- const { children } = this.props;
-
- const props = children.props as { onPointerLeave?: VoidFunction };
-
- if (typeof props.onPointerLeave === 'function') {
- props.onPointerLeave();
- }
- };
-
- needsFlipping = ({ leftFix, topFix }: State) => {
- // We can live with a tooltip that's slightly positioned over the toggle
- // node. Only trigger if it really starts overlapping, as the re-positioning
- // is quite expensive, needing 2 re-renders.
- const repositioningThreshold = 8;
- switch (this.getPlacement()) {
- case PopupPlacement.Left:
- case PopupPlacement.Right:
- return Boolean(leftFix && Math.abs(leftFix) > repositioningThreshold);
- case PopupPlacement.Top:
- case PopupPlacement.Bottom:
- return Boolean(topFix && Math.abs(topFix) > repositioningThreshold);
- default:
- return false;
- }
- };
-
- render() {
- const placement = this.getPlacement();
- const style = isMeasured(this.state)
- ? {
- left: this.state.left,
- top: this.state.top,
- width: this.state.width,
- height: this.state.height,
- }
- : undefined;
-
- return (
- <>
- {React.cloneElement(this.props.children, {
- onPointerEnter: this.handleChildPointerEnter,
- onPointerLeave: this.handleChildPointerLeave,
- onFocus: this.handleFocus,
- onBlur: this.handleBlur,
- // aria-describedby is the semantically correct property to use, but it's not
- // always well supported. We sometimes need to handle this differently, depending
- // on the triggering element. We should NOT use aria-labelledby, as this can
- // have unintended effects (e.g., this can mess up buttons that need a tooltip).
- 'aria-describedby': this.id,
- })}
- {this.isVisible() && (
- <TooltipPortal>
- <TooltipWrapper
- className={classNames(placement)}
- onPointerEnter={this.handleOverlayPointerEnter}
- onPointerLeave={this.handleOverlayPointerLeave}
- ref={this.tooltipNodeRef}
- role="tooltip"
- style={style}
- >
- <TooltipWrapperInner>{this.props.content}</TooltipWrapperInner>
- <TooltipWrapperArrow
- style={
- isMeasured(this.state)
- ? this.adjustArrowPosition(placement, this.state)
- : undefined
- }
- />
- </TooltipWrapper>
- </TooltipPortal>
- )}
- </>
- );
- }
-}
-
-class TooltipPortal extends React.Component<React.PropsWithChildren> {
- el: HTMLElement;
-
- constructor(props: object) {
- super(props);
- this.el = document.createElement('div');
- }
-
- componentDidMount() {
- document.body.appendChild(this.el);
- }
-
- componentWillUnmount() {
- document.body.removeChild(this.el);
- }
-
- render() {
- return createPortal(this.props.children, this.el);
- }
-}
-
-const fadeIn = keyframes`
- from {
- opacity: 0;
- }
-
- to {
- opacity: 1;
- }
-`;
-
-const ARROW_WIDTH = 6;
-const ARROW_HEIGHT = 7;
-const ARROW_MARGIN = 3;
-
-export const TooltipWrapper = styled.div`
- animation: ${fadeIn} 0.3s forwards;
-
- ${tw`sw-absolute`}
- ${tw`sw-z-tooltip`};
- ${tw`sw-block`};
- ${tw`sw-box-border`};
- ${tw`sw-h-auto`};
- ${tw`sw-typo-default`};
-
- &.top {
- margin-top: -${ARROW_MARGIN}px;
- padding: ${ARROW_HEIGHT}px 0;
- }
-
- &.right {
- margin-left: ${ARROW_MARGIN}px;
- padding: 0 ${ARROW_HEIGHT}px;
- }
-
- &.bottom {
- margin-top: ${ARROW_MARGIN}px;
- padding: ${ARROW_HEIGHT}px 0;
- }
-
- &.left {
- margin-left: -${ARROW_MARGIN}px;
- padding: 0 ${ARROW_HEIGHT}px;
- }
-`;
-
-const TooltipWrapperArrow = styled.div`
- ${tw`sw-absolute`};
- ${tw`sw-w-0`};
- ${tw`sw-h-0`};
- ${tw`sw-border-solid`};
- border-color: var(--echoes-color-support-transparent);
-
- ${TooltipWrapper}.top & {
- border-width: ${ARROW_HEIGHT}px ${ARROW_WIDTH}px 0;
- border-top-color: ${themeColor('tooltipBackground')};
- transform: translateX(-${ARROW_WIDTH}px);
-
- ${tw`sw-bottom-0`};
- ${tw`sw-left-1/2`};
- }
-
- ${TooltipWrapper}.right & {
- border-width: ${ARROW_WIDTH}px ${ARROW_HEIGHT}px ${ARROW_WIDTH}px 0;
- border-right-color: ${themeColor('tooltipBackground')};
- transform: translateY(-${ARROW_WIDTH}px);
-
- ${tw`sw-top-1/2`};
- ${tw`sw-left-0`};
- }
-
- ${TooltipWrapper}.left & {
- border-width: ${ARROW_WIDTH}px 0 ${ARROW_WIDTH}px ${ARROW_HEIGHT}px;
- border-left-color: ${themeColor('tooltipBackground')};
- transform: translateY(-${ARROW_WIDTH}px);
-
- ${tw`sw-top-1/2`};
- ${tw`sw-right-0`};
- }
-
- ${TooltipWrapper}.bottom & {
- border-width: 0 ${ARROW_WIDTH}px ${ARROW_HEIGHT}px;
- border-bottom-color: ${themeColor('tooltipBackground')};
- transform: translateX(-${ARROW_WIDTH}px);
-
- ${tw`sw-top-0`};
- ${tw`sw-left-1/2`};
- }
-`;
-
-export const TooltipWrapperInner = styled.div`
- font: var(--echoes-typography-paragraph-small-regular);
- padding: var(--echoes-dimension-space-50) var(--echoes-dimension-space-150);
- color: var(--echoes-color-text-on-color);
- background-color: var(--echoes-color-background-inverse);
- border-radius: var(--echoes-border-radius-200);
-
- ${tw`sw-max-w-[22rem]`}
- ${tw`sw-overflow-hidden`};
- ${tw`sw-text-left`};
- ${tw`sw-no-underline`};
- ${tw`sw-break-words`};
-
- hr {
- background-color: var(--echoes-color-text-subdued);
-
- ${tw`sw-mx-4`};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/TopBar.tsx b/server/sonar-web/src/main/js/design-system/components/TopBar.tsx
deleted file mode 100644
index e20691538a9..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/TopBar.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { LAYOUT_VIEWPORT_MIN_WIDTH } from '../helpers';
-import { themeColor, themeContrast, themeShadow } from '../helpers/theme';
-
-export const TopBar = styled.nav`
- ${tw`sw-px-6 sw-pt-4`}
- ${tw`sw-box-border`};
- ${tw`sw-w-full`};
- ${tw`sw-font-sans`}
- ${tw`sw-text-sm`}
-
- min-width: ${LAYOUT_VIEWPORT_MIN_WIDTH}px;
-
- background-color: ${themeColor('navbar')};
- color: ${themeContrast('navbar')};
- box-shadow: ${themeShadow('lg')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/TreeMap.tsx b/server/sonar-web/src/main/js/design-system/components/TreeMap.tsx
deleted file mode 100644
index 43229aae254..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/TreeMap.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { hierarchy as d3Hierarchy, treemap as d3Treemap } from 'd3-hierarchy';
-import { sortBy } from 'lodash';
-import tw from 'twin.macro';
-import { PopupPlacement } from '../helpers/positioning';
-import { TreeMapRect } from './TreeMapRect';
-
-export interface TreeMapItem<T> {
- color?: string;
- gradient?: string;
- icon?: React.ReactNode;
- key: string;
- label: string;
- size: number;
- sourceData?: T;
- tooltip?: React.ReactNode;
-}
-
-interface HierarchicalTreemapItem<T> extends TreeMapItem<T> {
- children?: Array<TreeMapItem<T>>;
-}
-
-export interface TreeMapProps<T> {
- height: number;
- items: Array<TreeMapItem<T>>;
- onRectangleClick?: (item: TreeMapItem<T>) => void;
- width: number;
-}
-
-export function TreeMap<T = unknown>(props: TreeMapProps<T>) {
- function mostCommitPrefix(labels: string[]) {
- const sortedLabels = sortBy(labels.slice(0));
- const firstLabel = sortedLabels[0];
- const firstLabelLength = firstLabel.length;
- const lastLabel = sortedLabels[sortedLabels.length - 1];
- let i = 0;
- while (i < firstLabelLength && firstLabel.charAt(i) === lastLabel.charAt(i)) {
- i++;
- }
- const prefix = firstLabel.substring(0, i);
- const prefixTokens = prefix.split(/[\s\\/]/);
- const lastPrefixPart = prefixTokens[prefixTokens.length - 1];
- return prefix.substring(0, prefix.length - lastPrefixPart.length);
- }
-
- function handleClick(data: TreeMapItem<T>) {
- if (props.onRectangleClick) {
- props.onRectangleClick(data);
- }
- }
-
- const { items, height, width } = props;
- const hierarchy = d3Hierarchy({ children: items } as HierarchicalTreemapItem<T>)
- .sum((d) => d.size)
- .sort((a, b) => (b.value ?? 0) - (a.value ?? 0));
-
- const treemap = d3Treemap<TreeMapItem<T>>().round(true).size([width, height]);
-
- const nodes = treemap(hierarchy).leaves();
- const prefix = mostCommitPrefix(items.map((item) => item.label));
- const halfWidth = width / 2;
- return (
- <StyledContainer style={{ width, height }}>
- {nodes.map(({ data, y0, y1, x0, x1 }) => (
- <TreeMapRect
- fill={data.color}
- gradient={data.gradient}
- height={y1 - y0}
- icon={data.icon}
- itemKey={data.key}
- key={data.key}
- label={data.label}
- onClick={() => {
- handleClick(data);
- }}
- placement={x0 === 0 || x1 < halfWidth ? PopupPlacement.Right : PopupPlacement.Left}
- prefix={prefix}
- tooltip={data.tooltip}
- width={x1 - x0}
- x={x0}
- y={y0}
- />
- ))}
- </StyledContainer>
- );
-}
-
-const StyledContainer = styled.ul`
- ${tw`sw-relative`}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/TreeMapRect.tsx b/server/sonar-web/src/main/js/design-system/components/TreeMapRect.tsx
deleted file mode 100644
index 0bda2755703..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/TreeMapRect.tsx
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { scaleLinear } from 'd3-scale';
-import React from 'react';
-import tw from 'twin.macro';
-import { themeColor } from '../helpers';
-import { BasePlacement, PopupPlacement } from '../helpers/positioning';
-import { Tooltip } from './Tooltip';
-
-const SIZE_SCALE = scaleLinear().domain([3, 15]).range([11, 18]).clamp(true);
-const TEXT_VISIBLE_AT_WIDTH = 40;
-const TEXT_VISIBLE_AT_HEIGHT = 45;
-const ICON_VISIBLE_AT_WIDTH = 24;
-const ICON_VISIBLE_AT_HEIGHT = 26;
-
-interface Props {
- fill?: string;
- gradient?: string;
- height: number;
- icon?: React.ReactNode;
- itemKey: string;
- label: string;
- onClick: (item: string) => void;
- placement?: BasePlacement;
- prefix: string;
- tooltip?: React.ReactNode;
- width: number;
- x: number;
- y: number;
-}
-
-export function TreeMapRect(props: Props) {
- const {
- placement,
- tooltip,
- onClick,
- itemKey,
- x,
- y,
- width,
- height,
- fill,
- gradient,
- label,
- icon,
- prefix,
- } = props;
-
- const handleRectClick = React.useCallback(() => {
- onClick(itemKey);
- return false;
- }, [onClick, itemKey]);
-
- const cellStyles = {
- left: x,
- top: y,
- width,
- height,
- backgroundColor: fill,
- backgroundImage: gradient,
- fontSize: SIZE_SCALE(width / label.length),
- lineHeight: `${height}px`,
- };
- const isTextVisible = width >= TEXT_VISIBLE_AT_WIDTH && height >= TEXT_VISIBLE_AT_HEIGHT;
- const isIconVisible = width >= ICON_VISIBLE_AT_WIDTH && height >= ICON_VISIBLE_AT_HEIGHT;
-
- return (
- <Tooltip content={tooltip} placement={placement ?? PopupPlacement.Left}>
- <StyledCell style={cellStyles}>
- <StyledCellLink href="#" onClick={handleRectClick}>
- <StyledCellLabel width={width}>
- {isIconVisible && <span className="shrink-0">{icon}</span>}
- {isTextVisible &&
- (prefix ? (
- <span className="treemap-text">
- {prefix}
- <br />
- {label.substring(prefix.length)}
- </span>
- ) : (
- <span className="treemap-text">{label}</span>
- ))}
- <StyledA11yHidden>{tooltip}</StyledA11yHidden>
- </StyledCellLabel>
- </StyledCellLink>
- </StyledCell>
- </Tooltip>
- );
-}
-
-const StyledCell = styled.li`
- ${tw`sw-absolute`};
- ${tw`sw-box-border`};
-
- border-right: 1px solid #fff;
- border-bottom: 1px solid #fff;
-`;
-
-const StyledCellLink = styled.a`
- ${tw`sw-w-full sw-h-full`};
- ${tw`sw-border-0`};
- ${tw`sw-flex sw-flex-col sw-items-center sw-justify-center`};
-
- color: ${themeColor('pageContent')};
-
- &:hover,
- &:active,
- &:focus {
- ${tw`sw-border-0`};
- outline: none;
- }
-
- &:focus .treemap-text,
- &:hover .treemap-text {
- ${tw`sw-underline`};
- }
-`;
-
-const StyledCellLabel = styled.div<{ width: number }>`
- ${tw`sw-flex sw-flex-wrap sw-justify-center sw-items-center sw-gap-2`};
-
- line-height: 1.2;
- max-width: ${({ width }) => width}px;
-
- .treemap-text {
- ${tw`sw-shrink sw-overflow-hidden sw-whitespace-nowrap sw-text-left sw-text-ellipsis`};
- }
-`;
-
-const StyledA11yHidden = styled.span`
- position: absolute !important;
- left: -10000px !important;
- top: auto !important;
- width: 1px !important;
- height: 1px !important;
- overflow: hidden !important;
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/TutorialStep.tsx b/server/sonar-web/src/main/js/design-system/components/TutorialStep.tsx
deleted file mode 100644
index f91f90ae80e..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/TutorialStep.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../helpers/theme';
-
-interface Props {
- children: React.ReactNode;
- stepNumber?: number;
- title: React.ReactNode;
-}
-
-export function TutorialStep({ children, title, stepNumber }: Props) {
- return (
- <Step stepNumber={stepNumber}>
- <Title>{title}</Title>
- <StepDetails>{children}</StepDetails>
- </Step>
- );
-}
-
-const StepDetails = styled.div`
- h3 {
- ${tw`sw-typo-semibold`}
- ${tw`sw-my-2`}
-
- color: ${themeColor('pageContent')};
- }
-
- &,
- h4,
- h5 {
- ${tw`sw-typo-default`}
- ${tw`sw-mb-2`}
-
- color: ${themeColor('pageContent')};
- }
-`;
-
-const Title = styled.h2`
- ${tw`sw-typo-lg-semibold`}
- ${tw`sw-inline-block`}
- ${tw`sw-mb-4`}
-
- color: ${themeColor('pageTitle')};
-`;
-
-const Step = styled.li<{ stepNumber?: number }>`
- list-style: none;
- counter-increment: li ${(props) => props.stepNumber};
-
- ${tw`sw-mt-10`}
-
- &::before {
- color: var(--echoes-color-text-subdued);
- content: counter(li);
-
- ${tw`sw-inline-block`}
- ${tw`sw-align-middle`}
- ${tw`sw-heading-lg`}
- ${tw`sw-mr-2 sw--mt-1`}
- }
-
- & + & {
- border-top: ${themeBorder('default')};
-
- ${tw`sw-pt-10`}
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/TutorialStepList.tsx b/server/sonar-web/src/main/js/design-system/components/TutorialStepList.tsx
deleted file mode 100644
index 42fe45b04fe..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/TutorialStepList.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-
-const StyledTutorialStepList = styled.ol`
- list-style: none;
- counter-reset: li;
-`;
-StyledTutorialStepList.displayName = 'TutorialStepList';
-
-export const TutorialStepList = StyledTutorialStepList;
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/Badge-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/Badge-test.tsx
deleted file mode 100644
index 31062bf85e3..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/Badge-test.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../helpers/testUtils';
-import { Badge } from '../Badge';
-
-it('renders badge correctly', () => {
- render(<Badge>foo</Badge>);
- expect(screen.getByText('foo')).toBeInTheDocument();
-});
-
-it('renders counter correctly', () => {
- render(
- <Badge title="This 23" variant="counter">
- 23
- </Badge>,
- );
- expect(screen.getByRole('img')).toHaveAccessibleName('This 23');
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/Banner-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/Banner-test.tsx
deleted file mode 100644
index 0de1f631038..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/Banner-test.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { renderWithContext } from '../../helpers/testUtils';
-import { Note } from '../../sonar-aligned';
-import { FCProps } from '../../types/misc';
-import { Banner } from '../Banner';
-
-it('should render with close button', async () => {
- const onDismiss = jest.fn();
- const { user } = setupWithProps({ onDismiss });
- expect(
- screen.getByRole('button', {
- name: 'dismiss',
- }),
- ).toBeVisible();
-
- await user.click(
- screen.getByRole('button', {
- name: 'dismiss',
- }),
- );
-
- expect(onDismiss).toHaveBeenCalledTimes(1);
-});
-
-function setupWithProps(props: Partial<FCProps<typeof Banner>> = {}) {
- return renderWithContext(
- <Banner {...props} variant="warning">
- <Note className="sw-typo-default">{props.children ?? 'Test Message'}</Note>
- </Banner>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/BarChart-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/BarChart-test.tsx
deleted file mode 100644
index f5a295a1362..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/BarChart-test.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { render } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { BarChart } from '../BarChart';
-
-it('renders chart correctly', async () => {
- const user = userEvent.setup();
- const onBarClick = jest.fn();
- renderChart({ onBarClick });
-
- const p1 = screen.getByLabelText('point 1');
- expect(p1).toBeInTheDocument();
- await user.click(p1);
-
- expect(onBarClick).toHaveBeenCalledWith({ description: 'point 1', x: 1, y: 20 });
-});
-
-it('displays values', () => {
- const xValues = ['hi', '43', 'testing'];
- renderChart({ xValues });
-
- expect(screen.getByText(xValues[0])).toBeInTheDocument();
- expect(screen.getByText(xValues[1])).toBeInTheDocument();
- expect(screen.getByText(xValues[2])).toBeInTheDocument();
-});
-
-function renderChart(overrides: Partial<FCProps<typeof BarChart>> = {}) {
- return render(
- <BarChart
- barsWidth={20}
- data={[
- { x: 1, y: 20, description: 'point 1' },
- { x: 2, y: 40, description: 'apex' },
- { x: 3, y: 31, description: 'point 3' },
- ]}
- height={75}
- onBarClick={jest.fn()}
- width={200}
- {...overrides}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/BorderlessAccordion-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/BorderlessAccordion-test.tsx
deleted file mode 100644
index 82ea71b0776..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/BorderlessAccordion-test.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import * as React from 'react';
-import { render } from '../../helpers/testUtils';
-import { BorderlessAccordion } from '../BorderlessAccordion';
-
-it('should behave correctly', async () => {
- const user = userEvent.setup();
- const children = 'hello';
- renderAccordion(children);
- expect(screen.queryByText(children)).not.toBeInTheDocument();
- await user.click(screen.getByRole('button', { expanded: false }));
- expect(screen.getByText(children)).toBeInTheDocument();
-});
-
-function renderAccordion(children: React.ReactNode) {
- function AccordionTest() {
- const [open, setOpen] = React.useState(false);
-
- return (
- <BorderlessAccordion
- header="test"
- onClick={() => {
- setOpen(!open);
- }}
- open={open}
- >
- <div>{children}</div>
- </BorderlessAccordion>
- );
- }
-
- return render(<AccordionTest />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/Breadcrumbs-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/Breadcrumbs-test.tsx
deleted file mode 100644
index d315261928d..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/Breadcrumbs-test.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { renderWithRouter } from '../../helpers/testUtils';
-import { useResizeObserver } from '../../hooks/useResizeObserver';
-import { BreadcrumbsFullWidth } from '../Breadcrumbs';
-import { HoverLink } from '../Link';
-
-jest.mock('../../hooks/useResizeObserver', () => ({
- useResizeObserver: jest.fn(() => [1000, undefined]),
-}));
-
-it('should display three breadcrumbs correctly', () => {
- renderWithRouter(
- <BreadcrumbsFullWidth>
- <HoverLink to="/first">first</HoverLink>
- <HoverLink to="/second">second</HoverLink>
- <HoverLink to="/third">third</HoverLink>
- </BreadcrumbsFullWidth>,
- );
-
- expect(screen.getAllByRole('link').length).toBe(3);
- expect(screen.getAllByTestId('chevron-right').length).toBe(2);
-});
-
-describe('when the container of the breadcrumbs is small(400px)', () => {
- const originalOffsetWidth = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetWidth');
- beforeAll(() => {
- jest.mocked(useResizeObserver).mockImplementation(() => [400, undefined]);
- Object.defineProperty(HTMLElement.prototype, 'offsetWidth', { configurable: true, value: 110 });
- });
-
- afterAll(() => {
- Object.defineProperty(HTMLElement.prototype, 'offsetWidth', originalOffsetWidth as number);
- });
-
- it('should use the dropdown and hide the first breadcrumb when the width is 400', async () => {
- const content = (
- <BreadcrumbsFullWidth>
- <HoverLink to="/first-link-long">first link long</HoverLink>
- <HoverLink to="/second-link-long">second link long</HoverLink>
- <HoverLink to="/third-link-long">third link long</HoverLink>
- <HoverLink to="/fourth-link-long">fourth link long</HoverLink>
- </BreadcrumbsFullWidth>
- );
-
- const { user, rerender } = renderWithRouter(content);
-
- rerender(content);
-
- expect(screen.getByRole('button')).toBeVisible();
-
- expect(screen.getAllByRole('link').length).toBe(3);
- expect(screen.getAllByTestId('chevron-right').length).toBe(2);
-
- await user.click(screen.getByRole('button'));
-
- // 3 from breadcrumbs, 4 from dropdown
- expect(screen.getAllByRole('link').length).toBe(7);
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/BubbleChart-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/BubbleChart-test.tsx
deleted file mode 100644
index ff3f5850749..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/BubbleChart-test.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { AutoSizerProps } from 'react-virtualized';
-import { renderWithRouter } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { BubbleChart } from '../BubbleChart';
-
-jest.mock('react-virtualized/dist/commonjs/AutoSizer', () => ({
- AutoSizer: ({ children }: AutoSizerProps) => children({ width: 100, height: NaN }),
-}));
-
-jest.mock('d3-zoom', () => ({
- zoom: jest.fn().mockReturnValue({ scaleExtent: jest.fn().mockReturnValue({ on: jest.fn() }) }),
-}));
-
-jest.mock('d3-selection', () => ({
- select: jest.fn().mockReturnValue({ call: jest.fn() }),
-}));
-
-it('should display bubbles with correct chart structure', () => {
- renderBubbleChart();
- expect(screen.getAllByRole('link')).toHaveLength(2);
- expect(screen.getByText('5')).toBeInTheDocument();
-});
-
-it('should allow click on bubbles', async () => {
- const onBubbleClick = jest.fn();
- const { user } = renderBubbleChart({ onBubbleClick });
- await user.click(screen.getAllByRole('link')[0]);
- expect(onBubbleClick).toHaveBeenCalledWith('foo');
-});
-
-it('should navigate between bubbles by tab', async () => {
- const { user } = renderBubbleChart();
- await user.tab();
- expect(screen.getAllByRole('link')[0]).toHaveFocus();
- await user.tab();
- expect(screen.getAllByRole('link')[1]).toHaveFocus();
-});
-
-it('should not display ticks and grid', () => {
- renderBubbleChart({
- displayXGrid: false,
- displayYGrid: false,
- displayXTicks: false,
- displayYTicks: false,
- });
-
- expect(screen.queryByText('5')).not.toBeInTheDocument();
-});
-
-it('renders empty graph', () => {
- renderBubbleChart({
- items: [],
- });
-
- expect(screen.queryByRole('link')).not.toBeInTheDocument();
-});
-
-function renderBubbleChart(props: Partial<FCProps<typeof BubbleChart>> = {}) {
- return renderWithRouter(
- <BubbleChart
- height={100}
- items={[
- { x: 1, y: 10, size: 7, data: 'foo' },
- { x: 2, y: 30, size: 5, data: 'bar' },
- ]}
- padding={[0, 0, 0, 0]}
- {...props}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/CodeSnippet-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/CodeSnippet-test.tsx
deleted file mode 100644
index e2b2015362b..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/CodeSnippet-test.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { HelmetProvider } from 'react-helmet-async';
-import { renderWithContext } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { CodeSnippet } from '../CodeSnippet';
-
-it('should show full size when multiline with no editing', () => {
- const { container } = setupWithProps();
- const copyButton = screen.getByRole('button', { name: 'Copy' });
- expect(copyButton).toHaveStyle('top: 1.5rem');
- expect(container).toMatchSnapshot();
-});
-
-it('should show reduced size when single line with no editing', () => {
- const { container } = setupWithProps({ isOneLine: true, snippet: 'foobar' });
- const copyButton = screen.getByRole('button', { name: 'Copy' });
- expect(copyButton).toHaveStyle('top: 1rem');
- expect(container).toMatchSnapshot();
-});
-
-it('should highlight code content correctly', () => {
- const { container } = setupWithProps({ snippet: '<prop>foobar<prop>' });
- expect(container).toMatchSnapshot();
-});
-
-function setupWithProps(props: Partial<FCProps<typeof CodeSnippet>> = {}) {
- return renderWithContext(
- <HelmetProvider>
- <CodeSnippet snippet={'foo\nbar'} {...props} />
- </HelmetProvider>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/CodeSyntaxHighlighter-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/CodeSyntaxHighlighter-test.tsx
deleted file mode 100644
index db00ff319d8..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/CodeSyntaxHighlighter-test.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render } from '../../helpers/testUtils';
-import { CodeSyntaxHighlighter } from '../CodeSyntaxHighlighter';
-
-it('renders correctly with no code', () => {
- const { container } = render(
- <CodeSyntaxHighlighter
- htmlAsString={`
- <p>Hello there!</p>
-
- <p>There's no code here.</p>
- `}
- />,
- );
-
- // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
- expect(container.getElementsByClassName('hljs-string').length).toBe(0);
-});
-
-it('renders correctly with code', () => {
- const { container } = render(
- <CodeSyntaxHighlighter
- htmlAsString={`
- <p>Hello there!</p>
-
- <p>There's some <code>"code"</code> here.</p>
- `}
- language="typescript"
- />,
- );
-
- // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
- expect(container.getElementsByClassName('hljs-string').length).toBe(1);
-});
-
-/*
- * This test reproduces a breaking case for https://sonarsource.atlassian.net/browse/SONAR-20161
- */
-it('handles html code snippets', () => {
- const { container } = render(
- <CodeSyntaxHighlighter
- htmlAsString={
- '\u003ch4\u003eNoncompliant code example\u003c/h4\u003e\n\u003cpre data-diff-id\u003d"1" data-diff-type\u003d"noncompliant"\u003e\npublic void Method(MyObject myObject)\n{\n if (myObject is null)\n {\n new MyObject(); // Noncompliant\n }\n\n if (myObject.IsCorrupted)\n {\n new ArgumentException($"{nameof(myObject)} is corrupted"); // Noncompliant\n }\n\n // ...\n}\n\u003c/pre\u003e\n\u003ch4\u003eCompliant solution\u003c/h4\u003e\n\u003cpre data-diff-id\u003d"1" data-diff-type\u003d"compliant"\u003e\npublic void Method(MyObject myObject)\n{\n if (myObject is null)\n {\n myObject \u003d new MyObject(); // Compliant\n }\n\n if (myObject.IsCorrupted)\n {\n throw new ArgumentException($"{nameof(myObject)} is corrupted"); // Compliant\n }\n\n // ...\n}\n\u003c/pre\u003e'
- }
- />,
- );
-
- // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
- expect(container.querySelectorAll('pre')).toHaveLength(2);
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/ColorsLegend-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/ColorsLegend-test.tsx
deleted file mode 100644
index 29ec4a864f2..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/ColorsLegend-test.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-
-import { renderWithContext } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { ColorsLegend } from '../ColorsLegend';
-
-const colors = [
- {
- selected: true,
- overlay: 'Overlay A',
- label: 'A',
- value: '1',
- },
- {
- selected: true,
- overlay: 'Overlay B',
- label: 'B',
- value: '2',
- },
-];
-
-it('should render correctly', () => {
- renderColorLegend();
- expect(screen.getByRole('checkbox', { name: 'A' })).toBeInTheDocument();
- expect(screen.getByRole('checkbox', { name: 'B' })).toBeInTheDocument();
-});
-
-it('should react when a rating is clicked', () => {
- const onColorClick = jest.fn();
- renderColorLegend({ onColorClick });
-
- screen.getByRole('checkbox', { name: 'A' }).click();
- expect(onColorClick).toHaveBeenCalledWith(colors[0]);
-});
-
-function renderColorLegend(props: Partial<FCProps<typeof ColorsLegend>> = {}) {
- return renderWithContext(<ColorsLegend colors={colors} onColorClick={jest.fn()} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/CoverageIndicator-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/CoverageIndicator-test.tsx
deleted file mode 100644
index 46223d82e00..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/CoverageIndicator-test.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-
-import { CoverageIndicator } from '../CoverageIndicator';
-
-it('should display CoverageIndicator', () => {
- const wrapper = setupWithProps({ value: 10 });
- expect(wrapper.baseElement).toMatchSnapshot();
-});
-
-it('should display CoverageIndicator without value', () => {
- const wrapper = setupWithProps();
- expect(wrapper.baseElement).toMatchSnapshot();
-});
-
-it('should display CoverageIndicator with correct aria properties', () => {
- const wrapper = setupWithProps({ 'aria-label': 'label', 'aria-hidden': true });
- expect(wrapper.baseElement).toMatchSnapshot();
-});
-
-function setupWithProps(props: Partial<FCProps<typeof CoverageIndicator>> = {}) {
- return render(<CoverageIndicator {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/Dropdown-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/Dropdown-test.tsx
deleted file mode 100644
index bf7e3a51de2..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/Dropdown-test.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { renderWithRouter } from '../../helpers/testUtils';
-import { ButtonSecondary } from '../../sonar-aligned/components/buttons';
-import { Dropdown } from '../Dropdown';
-
-describe('Dropdown', () => {
- it('renders', async () => {
- const { user } = renderDropdown();
- expect(screen.getByRole('button')).toBeInTheDocument();
-
- await user.click(screen.getByRole('button'));
- expect(screen.getByRole('menu')).toBeInTheDocument();
- });
-
- it('toggles with render prop', async () => {
- const { user } = renderDropdown({
- children: ({ onToggleClick }) => <ButtonSecondary onClick={onToggleClick} />,
- });
-
- await user.click(screen.getByRole('button'));
- expect(screen.getByRole('menu')).toBeVisible();
- });
-
- it('closes when clicking outside of menu', async () => {
- const { user } = renderDropdown();
-
- await user.click(screen.getByRole('button'));
- expect(screen.getByRole('menu')).toBeInTheDocument();
-
- await user.click(document.body);
- expect(screen.queryByRole('menu')).not.toBeInTheDocument();
- });
-
- it('does not close when clicking ouside of menu', async () => {
- const { user } = renderDropdown({ withClickOutHandler: false });
-
- await user.click(screen.getByRole('button'));
- expect(screen.getByRole('menu')).toBeInTheDocument();
-
- await user.click(document.body);
- expect(screen.getByRole('menu')).toBeInTheDocument();
- });
-
- it('closes when other target gets focus', async () => {
- const { user } = renderDropdown();
-
- await user.click(screen.getByRole('button'));
- expect(screen.getByRole('menu')).toBeInTheDocument();
-
- await user.tab();
-
- expect(screen.queryByRole('menu')).not.toBeInTheDocument();
- });
-
- it('does not close when other target gets focus', async () => {
- const { user } = renderDropdown({ withFocusOutHandler: false });
-
- await user.click(screen.getByRole('button'));
- expect(screen.getByRole('menu')).toBeInTheDocument();
-
- await user.tab();
- expect(screen.getByRole('menu')).toBeInTheDocument();
- });
-
- function renderDropdown(props: Partial<Dropdown['props']> = {}) {
- const { children, ...rest } = props;
- return renderWithRouter(
- <Dropdown id="test-menu" overlay={<div id="overlay" />} {...rest}>
- {children ?? <ButtonSecondary />}
- </Dropdown>,
- );
- }
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/DropdownMenu-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/DropdownMenu-test.tsx
deleted file mode 100644
index e5eb5b80481..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/DropdownMenu-test.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { noop } from 'lodash';
-import { render, renderWithRouter } from '../../helpers/testUtils';
-import {
- DropdownMenu,
- ItemButton,
- ItemCheckbox,
- ItemCopy,
- ItemDangerButton,
- ItemDivider,
- ItemHeader,
- ItemLink,
- ItemNavLink,
-} from '../DropdownMenu';
-import { Tooltip } from '../Tooltip';
-import { MenuIcon } from '../icons/MenuIcon';
-
-it('should render a full menu correctly', () => {
- renderDropdownMenu();
- expect(screen.getByRole('menuitem', { name: 'My header' })).toBeInTheDocument();
- expect(screen.getByRole('menuitem', { name: 'Test menu item' })).toBeInTheDocument();
- expect(screen.getByRole('menuitem', { name: 'Test disabled item' })).toHaveClass('disabled');
-});
-
-it('menu items should work with tooltips', async () => {
- render(
- <Tooltip content="test tooltip">
- <ItemButton onClick={jest.fn()}>button</ItemButton>
- </Tooltip>,
- {},
- { delay: null },
- );
-
- expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
- await expect(screen.getByRole('menuitem')).toHaveATooltipWithContent('test tooltip');
-});
-
-function renderDropdownMenu() {
- return renderWithRouter(
- <DropdownMenu>
- <ItemHeader>My header</ItemHeader>
- <ItemNavLink to="/test">Test menu item</ItemNavLink>
- <ItemDivider />
- <ItemLink disabled to="/test-disabled">
- Test disabled item
- </ItemLink>
- <ItemButton icon={<MenuIcon />} onClick={noop}>
- Button
- </ItemButton>
- <ItemDangerButton onClick={noop}>DangerButton</ItemDangerButton>
- <ItemCopy copyValue="copy" tooltipOverlay="overlay">
- Copy
- </ItemCopy>
- <ItemCheckbox checked onCheck={noop}>
- Checkbox item
- </ItemCheckbox>
- </DropdownMenu>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/DuplicationsIndicator-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/DuplicationsIndicator-test.tsx
deleted file mode 100644
index 61b5659c4ad..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/DuplicationsIndicator-test.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-
-import { DuplicationLabel } from '../../types/measures';
-import { DuplicationsIndicator } from '../DuplicationsIndicator';
-
-it('should display DuplicationsIndicator without rating', () => {
- const wrapper = setupWithProps();
- expect(wrapper.baseElement).toMatchSnapshot();
-});
-
-it.each(['A', 'B', 'C', 'D', 'E', 'F'])(
- 'should display DuplicationsIndicator with rating',
- (variant: DuplicationLabel) => {
- const wrapper = setupWithProps({ rating: variant });
- expect(wrapper.baseElement).toMatchSnapshot();
- },
-);
-
-function setupWithProps(props: Partial<FCProps<typeof DuplicationsIndicator>> = {}) {
- return render(<DuplicationsIndicator {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/ExecutionFlowAccordion-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/ExecutionFlowAccordion-test.tsx
deleted file mode 100644
index 861322cc032..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/ExecutionFlowAccordion-test.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render, screen } from '@testing-library/react';
-import { FCProps } from '../../types/misc';
-import { ExecutionFlowAccordion } from '../ExecutionFlowAccordion';
-
-it('should render correctly', () => {
- renderExecutionFlowAccordion({}, <div>flow-accordion-children</div>);
- expect(screen.queryByText('flow-accordion-children')).not.toBeInTheDocument();
-});
-
-it('should render correctly expanded', () => {
- renderExecutionFlowAccordion({ expanded: true }, <div>flow-accordion-children</div>);
- expect(screen.getByText('flow-accordion-children')).toBeVisible();
-});
-
-function renderExecutionFlowAccordion(
- props: Partial<FCProps<typeof ExecutionFlowAccordion>> = {},
- children?: React.ReactNode,
-) {
- return render(
- <ExecutionFlowAccordion header="header" id="id" {...props}>
- {children}
- </ExecutionFlowAccordion>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/FacetBox-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/FacetBox-test.tsx
deleted file mode 100644
index ad65879c5b6..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/FacetBox-test.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { TooltipProvider } from '@sonarsource/echoes-react';
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { renderWithContext } from '../../helpers/testUtils';
-import { FacetBox, FacetBoxProps } from '../FacetBox';
-
-it('should render an empty disabled facet box', async () => {
- const user = userEvent.setup();
-
- const onClick = jest.fn();
-
- renderComponent({ disabled: true, hasEmbeddedFacets: true, onClick });
-
- expect(screen.queryByRole('group')).not.toBeInTheDocument();
-
- expect(screen.getByText('Test FacetBox')).toBeInTheDocument();
-
- expect(screen.getByRole('button', { expanded: false })).toHaveAttribute('aria-disabled', 'true');
-
- await user.click(screen.getByRole('button'));
-
- expect(onClick).not.toHaveBeenCalled();
-});
-
-it('should render an inner expanded facet box with count', async () => {
- const user = userEvent.setup();
-
- const onClear = jest.fn();
- const onClick = jest.fn();
-
- renderComponent({
- children: 'The panel',
- count: 3,
- inner: true,
- onClear,
- onClick,
- open: true,
- });
-
- expect(screen.getByRole('group')).toBeInTheDocument();
-
- expect(screen.getByRole('button', { expanded: true })).toBeInTheDocument();
-
- await user.click(screen.getByRole('button', { expanded: true }));
-
- expect(onClick).toHaveBeenCalledWith(false);
-});
-
-function renderComponent({ children, ...props }: Partial<FacetBoxProps> = {}) {
- return renderWithContext(
- <TooltipProvider>
- <FacetBox name="Test FacetBox" {...props}>
- {children}
- </FacetBox>
- </TooltipProvider>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/FacetItem-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/FacetItem-test.tsx
deleted file mode 100644
index 07fe9259687..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/FacetItem-test.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { render } from '../../helpers/testUtils';
-import { BaseFacetItem, FacetItemProps } from '../FacetItem';
-
-it('should render a disabled facet item', async () => {
- const user = userEvent.setup();
-
- const onClick = jest.fn();
-
- renderComponent({ disabled: true, onClick });
-
- expect(screen.getByRole('checkbox')).toHaveAttribute('aria-disabled', 'true');
-
- await user.click(screen.getByRole('checkbox'));
-
- expect(onClick).not.toHaveBeenCalled();
-});
-
-it('should render a non-disabled facet item', async () => {
- const user = userEvent.setup();
-
- const onClick = jest.fn();
-
- renderComponent({ active: true, onClick, stat: 3, value: 'foo' });
-
- expect(screen.getByRole('checkbox')).toHaveAttribute('aria-disabled', 'false');
-
- await user.click(screen.getByRole('checkbox'));
-
- expect(onClick).toHaveBeenCalledWith('foo', false);
-
- await user.keyboard('{Meta>}');
- await user.click(screen.getByRole('checkbox'));
-
- expect(onClick).toHaveBeenLastCalledWith('foo', true);
-});
-
-it('should add an aria label if the name is a string', () => {
- renderComponent({ name: 'Foo' });
-
- expect(screen.getByRole('checkbox')).toHaveAccessibleName('Foo');
-});
-
-it('should not add an aria label if the name is not a string', () => {
- renderComponent({ name: <div>Foo</div>, small: true });
-
- expect(screen.getByRole('checkbox')).not.toHaveAttribute('aria-label');
-});
-
-function renderComponent(props: Partial<FacetItemProps> = {}) {
- return render(
- <BaseFacetItem name="Test facet item" onClick={jest.fn()} value="Value" {...props} />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/FavoriteButton-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/FavoriteButton-test.tsx
deleted file mode 100644
index 002a54a53cb..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/FavoriteButton-test.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { render } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { FavoriteButton } from '../FavoriteButton';
-import { Tooltip } from '../Tooltip';
-
-it('should render favorite filled', () => {
- const { container } = renderFavoriteButton({ favorite: true });
- expect(screen.getByLabelText('label-info')).toBeInTheDocument();
- expect(container).toMatchSnapshot();
-});
-
-it('should render favorite empty', () => {
- const { container } = renderFavoriteButton();
- expect(screen.getByLabelText('label-info')).toBeInTheDocument();
- expect(container).toMatchSnapshot();
-});
-
-it('should toggle favorite', async () => {
- const toggleFavorite = jest.fn();
- renderFavoriteButton({ toggleFavorite });
- await userEvent.click(screen.getByRole('button'));
- expect(toggleFavorite).toHaveBeenCalled();
-});
-
-function renderFavoriteButton(props: Partial<FCProps<typeof FavoriteButton>> = {}) {
- return render(
- <FavoriteButton
- favorite
- overlay="label-info"
- toggleFavorite={jest.fn()}
- tooltip={Tooltip}
- {...props}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/FlowStep-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/FlowStep-test.tsx
deleted file mode 100644
index 5193b20b3b9..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/FlowStep-test.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { renderWithRouter } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { FlowStep } from '../FlowStep';
-
-it('should render correctly', () => {
- renderFlowStep({ step: 3, additionalMarkers: <span>additional</span> });
-
- expect(screen.getByText('3')).toBeInTheDocument();
- expect(screen.getByText('additional')).toBeInTheDocument();
-});
-
-function renderFlowStep(props: Partial<FCProps<typeof FlowStep>> = {}) {
- return renderWithRouter(<FlowStep message="" selected={false} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/HighlightedSection-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/HighlightedSection-test.tsx
deleted file mode 100644
index 97ccc9b8f94..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/HighlightedSection-test.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render, screen } from '@testing-library/react';
-import { HighlightedSection } from '../HighlightedSection';
-
-it('should render as expected', () => {
- render(<HighlightedSection>content</HighlightedSection>);
-
- expect(screen.getByText('content')).toHaveStyle({
- padding: '2rem',
- border: '1px solid rgb(225,230,243)',
- background: 'rgb(252,252,253)',
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/Histogram-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/Histogram-test.tsx
deleted file mode 100644
index 33300fbceee..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/Histogram-test.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render } from '../../helpers/testUtils';
-import { Histogram } from '../Histogram';
-
-it('renders correctly', () => {
- const { container } = renderHistogram();
- expect(container).toMatchSnapshot();
-});
-
-it('renders correctly with yValues', () => {
- const { container } = renderHistogram({ yValues: ['100.0', '75.0', '150.0'] });
- expect(container).toMatchSnapshot();
-});
-
-it('renders correctly with yValues and yTicks', () => {
- const { container } = renderHistogram({
- yValues: ['100.0', '75.0', '150.0'],
- yTicks: ['a', 'b', 'c'],
- });
- expect(container).toMatchSnapshot();
-});
-
-it('renders correctly with yValues, yTicks, and yTooltips', () => {
- const { container } = renderHistogram({
- yValues: ['100.0', '75.0', '150.0'],
- yTicks: ['a', 'b', 'c'],
- yTooltips: ['a - 100', 'b - 75', 'c - 150'],
- });
- expect(container).toMatchSnapshot();
-});
-
-function renderHistogram(props: Partial<Histogram['props']> = {}) {
- return render(<Histogram bars={[100, 75, 150]} height={75} width={100} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/HotspotRating-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/HotspotRating-test.tsx
deleted file mode 100644
index 4f988f7ad70..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/HotspotRating-test.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../helpers/testUtils';
-import { HotspotRatingEnum } from '../../types/measures';
-import { HotspotRating } from '../HotspotRating';
-
-it('should render HotspotRating with default LOW rating', () => {
- renderHotspotRating(undefined, 'label');
- expect(screen.getByLabelText('label')).toMatchSnapshot();
-});
-
-it.each(Object.values(HotspotRatingEnum))(
- 'should render HotspotRating with %s rating',
- (rating) => {
- renderHotspotRating(rating, 'label');
- expect(screen.getByLabelText('label')).toMatchSnapshot();
- },
-);
-
-function renderHotspotRating(rating?: HotspotRatingEnum, label?: string) {
- return render(<HotspotRating aria-label={label} rating={rating} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/IssueMessageHighlighting-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/IssueMessageHighlighting-test.tsx
deleted file mode 100644
index 623a49e2244..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/IssueMessageHighlighting-test.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render } from '@testing-library/react';
-import {
- IssueMessageHighlighting,
- IssueMessageHighlightingProps,
- MessageFormattingType,
-} from '../IssueMessageHighlighting';
-
-it.each([
- [undefined, undefined],
- ['message', undefined],
- ['message', []],
- ['message', [{ start: 1, end: 4, type: 'something else' as MessageFormattingType }]],
- [
- 'message',
- [
- { start: 5, end: 6, type: MessageFormattingType.CODE },
- { start: 1, end: 4, type: MessageFormattingType.CODE },
- ],
- ],
- [
- 'a somewhat longer message with overlapping ranges',
- [{ start: -1, end: 1, type: MessageFormattingType.CODE }],
- ],
- [
- 'a somewhat longer message with overlapping ranges',
- [{ start: 48, end: 70, type: MessageFormattingType.CODE }],
- ],
- [
- 'a somewhat longer message with overlapping ranges',
- [{ start: 0, end: 0, type: MessageFormattingType.CODE }],
- ],
- [
- 'a somewhat longer message with overlapping ranges',
- [
- { start: 11, end: 17, type: MessageFormattingType.CODE },
- { start: 2, end: 25, type: MessageFormattingType.CODE },
- { start: 25, end: 2, type: MessageFormattingType.CODE },
- ],
- ],
- [
- 'a somewhat longer message with overlapping ranges',
- [
- { start: 18, end: 30, type: MessageFormattingType.CODE },
- { start: 2, end: 25, type: MessageFormattingType.CODE },
- ],
- ],
-])('should format the string with highlights', (message, messageFormattings) => {
- const { asFragment } = renderIssueMessageHighlighting({ message, messageFormattings });
- expect(asFragment()).toMatchSnapshot();
-});
-
-function renderIssueMessageHighlighting(props: Partial<IssueMessageHighlightingProps> = {}) {
- return render(<IssueMessageHighlighting {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/KeyboardHint-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/KeyboardHint-test.tsx
deleted file mode 100644
index bb893ab0ef9..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/KeyboardHint-test.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Key } from '../../helpers/keyboard';
-import { render } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { KeyboardHint } from '../KeyboardHint';
-
-afterEach(() => {
- jest.clearAllMocks();
-});
-
-it('renders without title', () => {
- const { container } = setupWithProps();
- expect(container).toMatchSnapshot();
-});
-
-it('renders with title', () => {
- const { container } = setupWithProps({ title: 'title' });
- expect(container).toMatchSnapshot();
-});
-
-it('renders with command', () => {
- const { container } = setupWithProps({ command: 'command' });
- expect(container).toMatchSnapshot();
-});
-
-it('renders on mac', () => {
- Object.defineProperty(navigator, 'userAgent', {
- configurable: true,
- value: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4)',
- });
- const { container } = setupWithProps({ command: `${Key.Control} ${Key.Alt}` });
- expect(container).toMatchSnapshot();
-});
-
-it('renders on windows', () => {
- Object.defineProperty(navigator, 'userAgent', {
- configurable: true,
- value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
- });
- const { container } = setupWithProps({ command: `${Key.Control} ${Key.Alt}` });
- expect(container).toMatchSnapshot();
-});
-
-function setupWithProps(props: Partial<FCProps<typeof KeyboardHint>> = {}) {
- return render(<KeyboardHint command="click" {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/KeyboardHintKeys-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/KeyboardHintKeys-test.tsx
deleted file mode 100644
index 9c4d6763f3b..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/KeyboardHintKeys-test.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Key } from '../../helpers/keyboard';
-import { render } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { KeyboardHintKeys, mappedKeys } from '../KeyboardHintKeys';
-
-it.each(Object.keys(mappedKeys))('should render %s', (key) => {
- const { container } = setupWithProps({ command: key });
- expect(container).toMatchSnapshot();
-});
-
-it('should render multiple keys', () => {
- const { container } = setupWithProps({ command: `Use Ctrl + ${Key.ArrowUp} ${Key.ArrowDown}` });
- expect(container).toMatchSnapshot();
-});
-
-it('should render multiple keys with non-key symbols', () => {
- const { container } = setupWithProps({
- command: `${Key.Control} + ${Key.ArrowDown} ${Key.ArrowUp}`,
- });
- expect(container).toMatchSnapshot();
-});
-
-it('should render a default text if no keys match', () => {
- const { container } = setupWithProps({ command: `${Key.Control} + click` });
- expect(container).toMatchSnapshot();
-});
-
-function setupWithProps(props: Partial<FCProps<typeof KeyboardHintKeys>> = {}) {
- return render(<KeyboardHintKeys command={`${Key.ArrowUp}`} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/LineCoverage-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/LineCoverage-test.tsx
deleted file mode 100644
index 5d9ecd41d5a..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/LineCoverage-test.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { LineCoverage } from '../code-line/LineCoverage';
-
-it('should render correctly when covered', () => {
- expect(setupWithProps().container).toMatchSnapshot();
-});
-
-it('should render correctly when uncovered', () => {
- expect(
- setupWithProps({ lineNumber: 16, coverageStatus: 'uncovered' }).container,
- ).toMatchSnapshot();
-});
-
-it('should render correctly when partially covered without conditions', () => {
- expect(
- setupWithProps({
- lineNumber: 16,
- coverageStatus: 'partially-covered',
- }).container,
- ).toMatchSnapshot();
-});
-
-it('should render correctly when partially covered with 5/10 conditions', () => {
- expect(
- setupWithProps({
- lineNumber: 16,
- coverageStatus: 'partially-covered',
- }).container,
- ).toMatchSnapshot();
-});
-
-it('should render correctly when no data', () => {
- expect(setupWithProps({ lineNumber: 16, coverageStatus: undefined }).container).toMatchSnapshot();
-});
-
-function setupWithProps(props: Partial<FCProps<typeof LineCoverage>> = {}) {
- return render(<LineCoverage coverageStatus="covered" lineNumber={16} status="OK" {...props} />, {
- container: document.createElement('tr'),
- });
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/LineFinding-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/LineFinding-test.tsx
deleted file mode 100644
index f21a1b5fb0b..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/LineFinding-test.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { render } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { LineFinding } from '../code-line/LineFinding';
-
-it('should render correctly as button', async () => {
- const user = userEvent.setup();
- const { container } = setupWithProps();
- await user.click(screen.getByRole('button'));
- expect(container).toMatchSnapshot();
-});
-
-it('should render as non-button', () => {
- setupWithProps({ as: 'div', onIssueSelect: undefined });
- expect(screen.queryByRole('button')).not.toBeInTheDocument();
-});
-
-it('should be clickable when onIssueSelect is provided', async () => {
- const mockClick = jest.fn();
- const user = userEvent.setup();
-
- setupWithProps({ onIssueSelect: mockClick });
- await user.click(screen.getByRole('button'));
- expect(mockClick).toHaveBeenCalled();
-});
-
-function setupWithProps(props?: Partial<FCProps<typeof LineFinding>>) {
- return render(
- <LineFinding issueKey="key" message="message" onIssueSelect={jest.fn()} {...props} />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/LineNumber-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/LineNumber-test.tsx
deleted file mode 100644
index f0f8a6beca9..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/LineNumber-test.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { LineNumber } from '../code-line/LineNumber';
-
-it('should a popup when clicked', async () => {
- const { user } = setupWithProps();
-
- expect(screen.getByRole('button', { name: 'aria-label' })).toBeVisible();
-
- await user.click(screen.getByRole('button', { name: 'aria-label' }));
- expect(screen.getByText('Popup')).toBeVisible();
-});
-
-function setupWithProps(props: Partial<FCProps<typeof LineNumber>> = {}) {
- return render(
- <table>
- <tbody>
- <tr>
- <LineNumber
- ariaLabel="aria-label"
- displayOptions
- firstLineNumber={1}
- lineNumber={16}
- popup={<div>Popup</div>}
- {...props}
- />
- </tr>
- </tbody>
- </table>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/LineToken-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/LineToken-test.tsx
deleted file mode 100644
index b351e7b1431..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/LineToken-test.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ReactNode } from 'react';
-import { render } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { LineToken } from '../code-line/LineToken';
-
-it.each([
- ['isHighlighted', 'highlighted'],
- ['isLocation', 'issue-location'],
- ['isSelected', 'selected'],
- ['isUnderlined', 'issue-underline'],
-])('should have matching class if modifiers are provided', (modifier, className) => {
- const { container } = setupWithProps({ [modifier]: true });
- expect(container.firstChild).toHaveClass(className);
-});
-
-it('should add class when hasMarker is provided', () => {
- const { container } = setupWithProps({ hasMarker: true });
- expect(container.firstChild).toHaveClass('has-marker');
-});
-
-function setupWithProps(props: Partial<FCProps<typeof LineToken>>, children?: ReactNode) {
- return render(<LineToken {...props}>{children}</LineToken>);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/LineWrapper-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/LineWrapper-test.tsx
deleted file mode 100644
index 9dc9f4cf410..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/LineWrapper-test.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { LineWrapper, SuggestedLineWrapper } from '../code-line/LineWrapper';
-
-it('should render with correct styling', () => {
- expect(setupWithProps().container).toMatchSnapshot();
-});
-
-it('should properly setup css grid columns', () => {
- expect(setupWithProps().container.firstChild).toHaveStyle({
- '--columns': '44px 50px 26px repeat(3, 6px) 1fr',
- });
- expect(setupWithProps({ duplicationsCount: 0 }).container.firstChild).toHaveStyle({
- '--columns': '44px 50px 26px repeat(1, 6px) 1fr',
- });
- expect(
- setupWithProps({ displayCoverage: false, displaySCM: false, duplicationsCount: 0 }).container
- .firstChild,
- ).toHaveStyle({ '--columns': '44px 26px 1fr' });
-});
-
-it('should set a highlighted background color in css props', () => {
- const { container } = setupWithProps({ highlighted: true });
- expect(container.firstChild).toHaveStyle({ '--line-background': 'rgb(225,230,243)' });
-});
-
-it('should properly setup css grid columns for Suggested Line', () => {
- const container = render(<SuggestedLineWrapper />, {
- container: document.createElement('div'),
- });
- expect(container.container.firstChild).toHaveStyle({
- '--columns': '44px 26px 1rem 1fr',
- });
-});
-
-function setupWithProps(props: Partial<FCProps<typeof LineWrapper>> = {}) {
- return render(
- <LineWrapper displayCoverage displaySCM duplicationsCount={2} highlighted={false} {...props} />,
- { container: document.createElement('tbody') },
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/Link-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/Link-test.tsx
deleted file mode 100644
index 25f212af11a..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/Link-test.tsx
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import * as React from 'react';
-import { MemoryRouter, Route, Routes, useLocation } from 'react-router-dom';
-import { render } from '../../helpers/testUtils';
-import { ContentLink, DiscreetLink, StandoutLink as Link } from '../Link';
-
-beforeAll(() => {
- const { location } = window;
- delete (window as { location?: Location }).location;
- window.location = { ...location, href: '' };
-});
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
-
-// This functionality won't be needed once we update the breadcrumbs
-it('should remove focus after link is clicked', async () => {
- const { user } = setupWithMemoryRouter(
- <Link blurAfterClick icon={<div>Icon</div>} to="/initial" />,
- );
-
- await user.click(screen.getByRole('link'));
-
- expect(screen.getByRole('link')).not.toHaveFocus();
-});
-
-it('should prevent default when preventDefault is true', async () => {
- const { user } = setupWithMemoryRouter(<Link preventDefault to="/second" />);
-
- expect(screen.getByText('/initial')).toBeVisible();
-
- await user.click(screen.getByRole('link'));
-
- // prevent default behavior of page navigation
- expect(screen.getByText('/initial')).toBeVisible();
- expect(screen.queryByText('/second')).not.toBeInTheDocument();
-});
-
-it('should stop propagation when stopPropagation is true', async () => {
- const buttonOnClick = jest.fn();
-
- const { user } = setupWithMemoryRouter(
- <button onClick={buttonOnClick} type="button">
- <Link stopPropagation to="/second" />
- </button>,
- );
-
- await user.click(screen.getByRole('link'));
-
- expect(buttonOnClick).not.toHaveBeenCalled();
-});
-
-it('should call onClick when one is passed', async () => {
- const onClick = jest.fn();
- const { user } = setupWithMemoryRouter(<Link onClick={onClick} stopPropagation to="/second" />);
-
- await user.click(screen.getByRole('link'));
-
- expect(onClick).toHaveBeenCalled();
-});
-
-it('internal link should be clickable', async () => {
- const { user } = setupWithMemoryRouter(<Link to="/second">internal link</Link>);
- expect(screen.getByRole('link')).toBeVisible();
-
- await user.click(screen.getByRole('link'));
-
- expect(screen.getByText('/second')).toBeVisible();
-});
-
-it('external links are indicated by OpenNewTabIcon', () => {
- setupWithMemoryRouter(<Link to="https://google.com">external link</Link>);
- expect(screen.getByRole('link')).toBeVisible();
-});
-
-it.each([
- ['discreet', DiscreetLink],
- ['content', ContentLink],
-])('%s links also can be external indicated by the OpenNewTabIcon', (_, LinkComponent) => {
- setupWithMemoryRouter(<LinkComponent to="https://google.com">external link</LinkComponent>);
- expect(screen.getByRole('link')).toBeVisible();
-});
-
-function ShowPath() {
- const { pathname } = useLocation();
- return <pre>{pathname}</pre>;
-}
-
-const setupWithMemoryRouter = (component: JSX.Element, initialEntries = ['/initial']) => {
- return render(
- <MemoryRouter initialEntries={initialEntries}>
- <Routes>
- <Route
- element={
- // Below: using <></> won't work in extensions ('React' is not defined). This is because the
- // name 'React' would already have been minified to something else when <> is resolved to
- // React.Fragment
- // eslint-disable-next-line react/jsx-fragments
- <React.Fragment>
- {component}
- <ShowPath />
- </React.Fragment>
- }
- path="/initial"
- />
- <Route element={<ShowPath />} path="/second" />
- </Routes>
- </MemoryRouter>,
- );
-};
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/MainAppBar-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/MainAppBar-test.tsx
deleted file mode 100644
index ed9e09bef5d..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/MainAppBar-test.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable import/no-extraneous-dependencies */
-
-import { fireEvent, screen } from '@testing-library/react';
-import { MemoryRouter, Route, Routes } from 'react-router-dom';
-import { LAYOUT_LOGO_MAX_HEIGHT, LAYOUT_LOGO_MAX_WIDTH } from '../../helpers/constants';
-import { render } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { MainAppBar } from '../MainAppBar';
-import { SonarQubeLogo } from '../SonarQubeLogo';
-
-it('should render the main app bar with max-height and max-width constraints on the logo', () => {
- setupWithProps();
-
- expect(screen.getByRole('img')).toHaveStyle({
- border: 'none',
- 'max-height': `${LAYOUT_LOGO_MAX_HEIGHT}px`,
- 'max-width': `${LAYOUT_LOGO_MAX_WIDTH}px`,
- 'object-fit': 'contain',
- });
-});
-
-it('should render the logo', () => {
- const element = setupWithProps({ Logo: SonarQubeLogo });
-
- // eslint-disable-next-line testing-library/no-node-access
- expect(element.container.querySelector('svg')).toHaveStyle({ height: '40px', width: '132px' });
-});
-
-it('should add shadow when scrolled', () => {
- setupWithProps();
-
- expect(screen.getByRole('banner')).toHaveStyle({
- 'box-shadow': 'none',
- });
-
- document.documentElement.scrollTop = 100;
- fireEvent.scroll(document, { target: { scrollTop: 100 } });
-
- expect(screen.getByRole('banner')).toHaveStyle({
- 'box-shadow': '0px 4px 8px -2px rgba(29,33,47,0.1),0px 2px 15px -2px rgba(29,33,47,0.06)',
- });
-});
-
-function setupWithProps(
- props: FCProps<typeof MainAppBar> = {
- Logo: () => <img alt="logo" src="http://example.com/logo.png" />,
- },
-) {
- return render(
- <MemoryRouter initialEntries={['/']}>
- <Routes>
- <Route element={<MainAppBar {...props} />} path="/" />
- </Routes>
- </MemoryRouter>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/Menu-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/Menu-test.tsx
deleted file mode 100644
index 687f5aad0e1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/Menu-test.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable import/no-extraneous-dependencies */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../helpers/testUtils';
-import { MainMenu } from '../MainMenu';
-
-it('should render MainMenu', () => {
- render(<MainMenu>Children</MainMenu>);
-
- expect(screen.getByText('Children')).toBeInTheDocument();
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/MenuItem-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/MenuItem-test.tsx
deleted file mode 100644
index b303e8a5208..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/MenuItem-test.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable import/no-extraneous-dependencies */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../helpers/testUtils';
-import { MainMenuItem } from '../MainMenuItem';
-
-it('should render default', () => {
- render(
- <MainMenuItem>
- <a>Hi</a>
- </MainMenuItem>,
- );
-
- expect(screen.getByText('Hi')).toHaveStyle({
- color: 'rgb(62, 67, 87)',
- 'border-bottom': '4px solid transparent',
- });
-});
-
-it('should render active link', () => {
- render(
- <MainMenuItem>
- <a className="active">Hi</a>
- </MainMenuItem>,
- );
-
- expect(screen.getByText('Hi')).toHaveStyle({
- color: 'rgb(62, 67, 87)',
- 'border-bottom': '4px solid rgba(123,135,217,1)',
- });
-});
-
-it('should render hovered link', () => {
- render(
- <MainMenuItem>
- <a className="hover">Hi</a>
- </MainMenuItem>,
- );
-
- expect(screen.getByText('Hi')).toHaveStyle({
- color: 'rgb(42, 47, 64)',
- 'border-bottom': '4px solid rgba(123,135,217,1)',
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/NavBarTabs-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/NavBarTabs-test.tsx
deleted file mode 100644
index da4bfd5b87f..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/NavBarTabs-test.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { renderWithRouter } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { DisabledTabLink, NavBarTabLink, NavBarTabs } from '../NavBarTabs';
-
-describe('NewNavBarTabs', () => {
- it('should render correctly', () => {
- setup();
-
- expect(screen.getByRole('list')).toBeInTheDocument();
- expect(screen.getByRole('listitem')).toBeInTheDocument();
- expect(screen.getByRole('link')).toBeInTheDocument();
- expect(screen.getByRole('link')).toHaveTextContent('test');
- });
-
- function setup() {
- return renderWithRouter(
- <NavBarTabs>
- <NavBarTabLink text="test" to="/summary/new_code" />
- </NavBarTabs>,
- );
- }
-});
-
-describe('NewNavBarTabLink', () => {
- it('should not be active when on different url', () => {
- setupWithProps();
-
- expect(screen.getByRole('link')).not.toHaveClass('active');
- });
-
- it('should be active when on same url', () => {
- setupWithProps({ to: '/' });
-
- expect(screen.getByRole('link')).toHaveClass('active');
- });
-
- it('should be active when active prop is set regardless of the url', () => {
- setupWithProps({ active: true, withChevron: true });
-
- expect(screen.getByRole('link')).toHaveClass('active');
- });
-
- it('should not be active when active prop is false regardless of the url', () => {
- setupWithProps({ active: false, to: '/' });
-
- expect(screen.getByRole('link')).not.toHaveClass('active');
- });
-
- function setupWithProps(props: Partial<FCProps<typeof NavBarTabLink>> = {}) {
- return renderWithRouter(<NavBarTabLink text="test" to="/summary/new_code" {...props} />);
- }
-});
-
-describe('DisabledTabLink', () => {
- it('should render correctly', () => {
- renderWithRouter(<DisabledTabLink label="label" overlay={<span>Overlay</span>} />);
- expect(screen.getByRole('link')).toHaveClass('disabled-link');
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/NavLink-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/NavLink-test.tsx
deleted file mode 100644
index 92eaf01d843..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/NavLink-test.tsx
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import * as React from 'react';
-import { MemoryRouter, Route, Routes, useLocation } from 'react-router-dom';
-import { render } from '../../helpers/testUtils';
-import NavLink from '../NavLink';
-
-beforeAll(() => {
- const { location } = window;
- delete (window as { location?: Location }).location;
- window.location = { ...location, href: '' };
-});
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
-
-it('should remove focus after link is clicked', async () => {
- const { user } = setupWithMemoryRouter(<NavLink blurAfterClick to="/initial" />);
-
- await user.click(screen.getByRole('link'));
-
- expect(screen.getByRole('link')).not.toHaveFocus();
-});
-
-it('should prevent default when preventDefault is true', async () => {
- const { user } = setupWithMemoryRouter(<NavLink preventDefault to="/second" />);
-
- expect(screen.getByText('/initial')).toBeVisible();
-
- await user.click(screen.getByRole('link'));
-
- // prevent default behavior of page navigation
- expect(screen.getByText('/initial')).toBeVisible();
- expect(screen.queryByText('/second')).not.toBeInTheDocument();
-});
-
-it('should stop propagation when stopPropagation is true', async () => {
- const buttonOnClick = jest.fn();
-
- const { user } = setupWithMemoryRouter(
- <button onClick={buttonOnClick} type="button">
- <NavLink stopPropagation to="/second" />
- </button>,
- );
-
- await user.click(screen.getByRole('link'));
-
- expect(buttonOnClick).not.toHaveBeenCalled();
-});
-
-it('should call onClick when one is passed', async () => {
- const onClick = jest.fn();
- const { user } = setupWithMemoryRouter(
- <NavLink onClick={onClick} stopPropagation to="/second" />,
- );
-
- await user.click(screen.getByRole('link'));
-
- expect(onClick).toHaveBeenCalled();
-});
-
-it('NavLink should be clickable', async () => {
- const { user } = setupWithMemoryRouter(<NavLink to="/second">internal link</NavLink>);
- expect(screen.getByRole('link')).toBeVisible();
-
- await user.click(screen.getByRole('link'));
-
- expect(screen.getByText('/second')).toBeVisible();
-});
-
-function ShowPath() {
- const { pathname } = useLocation();
- return <pre>{pathname}</pre>;
-}
-
-const setupWithMemoryRouter = (component: JSX.Element, initialEntries = ['/initial']) => {
- return render(
- <MemoryRouter initialEntries={initialEntries}>
- <Routes>
- <Route
- element={
- // Below: using <></> won't work in extensions ('React' is not defined). This is because the
- // name 'React' would already have been minified to something else when <> is resolved to
- // React.Fragment
- // eslint-disable-next-line react/jsx-fragments
- <React.Fragment>
- {component}
- <ShowPath />
- </React.Fragment>
- }
- path="/initial"
- />
- <Route element={<ShowPath />} path="/second" />
- </Routes>
- </MemoryRouter>,
- );
-};
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/NewCodeLegend-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/NewCodeLegend-test.tsx
deleted file mode 100644
index d40edf65e1c..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/NewCodeLegend-test.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import tailwindBaseConfig from '../../../../../../tailwind.base.config';
-import { render } from '../../helpers/testUtils';
-import { NewCodeLegend } from '../NewCodeLegend';
-
-it('should render NewCodeLegend', () => {
- render(<NewCodeLegend text="the text" />);
-
- expect(screen.getByText('the text')).toHaveStyle({
- font: 'var(--echoes-typography-text-default-regular)',
- 'margin-left': tailwindBaseConfig.theme.spacing[2],
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/Pill-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/Pill-test.tsx
deleted file mode 100644
index 5349c24dd61..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/Pill-test.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../helpers/testUtils';
-import { Pill, PillVariant } from '../Pill';
-
-it('should render correctly', () => {
- render(<Pill variant={PillVariant.Accent}>23</Pill>);
- expect(screen.getByText('23')).toBeInTheDocument();
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/QualityGateIndicator-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/QualityGateIndicator-test.tsx
deleted file mode 100644
index 3562e979105..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/QualityGateIndicator-test.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { IntlShape } from 'react-intl';
-import { renderWithContext } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { QualityGateIndicator } from '../QualityGateIndicator';
-
-jest.mock(
- 'react-intl',
- () =>
- ({
- ...jest.requireActual('react-intl'),
- useIntl: () => ({
- formatMessage: ({ id }: { id: string }, values = {}) =>
- [id, ...Object.values(values)].join('.'),
- }),
- }) as IntlShape,
-);
-
-it('should display tooltip', () => {
- const { rerender } = setupWithProps({
- size: 'sm',
- status: 'NONE',
- });
- expect(screen.getByTitle('overview.quality_gate_x.metric.level.NONE')).toBeInTheDocument();
-
- rerender(<QualityGateIndicator size="md" status="OK" />);
- expect(screen.getByTitle('overview.quality_gate_x.metric.level.OK')).toBeInTheDocument();
-
- rerender(<QualityGateIndicator size="xl" status="ERROR" />);
- expect(screen.getByTitle('overview.quality_gate_x.metric.level.ERROR')).toBeInTheDocument();
-});
-
-function setupWithProps(props: Partial<FCProps<typeof QualityGateIndicator>> = {}) {
- return renderWithContext(<QualityGateIndicator status="OK" {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/SelectionCard-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/SelectionCard-test.tsx
deleted file mode 100644
index df1fd540881..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/SelectionCard-test.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { renderWithContext } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { SelectionCard } from '../SelectionCard';
-
-it('should render option and be actionnable', async () => {
- const user = userEvent.setup();
- const onClick = jest.fn();
- renderSelectionCard({
- onClick,
- children: <>The Option</>,
- });
-
- // Click on content
- await user.click(screen.getByText(/The Option/));
- expect(onClick).toHaveBeenCalledTimes(1);
-
- // Click on radio button
- await user.click(screen.getByRole('radio'));
- expect(onClick).toHaveBeenCalledTimes(2);
-});
-
-it('should not be actionnable when disabled', async () => {
- const user = userEvent.setup();
- const onClick = jest.fn();
- renderSelectionCard({
- onClick,
- disabled: true,
- children: <>The Option</>,
- });
-
- // Clicking on content or radio button should not trigger click handler
- await user.click(screen.getByText(/The Option/));
- expect(onClick).not.toHaveBeenCalled();
-
- await user.click(screen.getByRole('radio'));
- expect(onClick).not.toHaveBeenCalled();
-});
-
-it('should not be actionnable when no click handler', () => {
- renderSelectionCard({
- children: <>The Option</>,
- });
-
- // Radio button should not be shown
- expect(screen.queryByRole('radio')).not.toBeInTheDocument();
-});
-
-function renderSelectionCard(props: Partial<FCProps<typeof SelectionCard>> = {}) {
- return renderWithContext(
- <SelectionCard
- recommended
- recommendedReason="Recommended for you"
- title="Selection Card"
- titleInfo="info"
- {...props}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/SizeIndicator-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/SizeIndicator-test.tsx
deleted file mode 100644
index 5f35af84093..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/SizeIndicator-test.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-
-import { SizeLabel } from '../../types/measures';
-import { SizeIndicator } from '../SizeIndicator';
-
-it.each([
- [100, 'XS'],
- [1100, 'S'],
- [20_000, 'M'],
- [200_000, 'L'],
- [1_000_000, 'XL'],
-])('should display SizeIndicator with size', (value: number, letter: SizeLabel) => {
- setupWithProps({ value });
- expect(screen.getByText(letter)).toBeInTheDocument();
-});
-
-function setupWithProps(props: Partial<FCProps<typeof SizeIndicator>> = {}) {
- return render(<SizeIndicator value={0} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/Spinner-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/Spinner-test.tsx
deleted file mode 100644
index 4d5d2595f2a..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/Spinner-test.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render, screen } from '@testing-library/react';
-import { IntlWrapper } from '../../helpers/testUtils';
-import { Spinner } from '../Spinner';
-
-it('allows setting a custom class name', () => {
- renderSpinner({ className: 'foo' });
- expect(screen.getByRole('status')).toHaveClass('foo');
-});
-
-it('can be controlled by the loading prop', () => {
- const { rerender } = renderSpinner({ loading: true });
- expect(screen.getByText('loading')).toBeInTheDocument();
-
- rerender(prepareSpinner({ loading: false }));
- expect(screen.queryByText('loading')).not.toBeInTheDocument();
-});
-
-function renderSpinner(props: Partial<Parameters<typeof Spinner>[0]> = {}) {
- // We don't use our renderComponent() helper here, as we have some tests that
- // require changes in props.
- return render(prepareSpinner(props));
-}
-
-function prepareSpinner(props: Partial<Parameters<typeof Spinner>[0]> = {}) {
- return (
- <IntlWrapper>
- <Spinner {...props} />
- </IntlWrapper>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/SpotlightTour-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/SpotlightTour-test.tsx
deleted file mode 100644
index d015ca429dc..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/SpotlightTour-test.tsx
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { renderWithContext } from '../../helpers/testUtils';
-import { SpotlightTour, SpotlightTourProps } from '../SpotlightTour';
-
-it('should display the spotlight tour', async () => {
- const user = userEvent.setup();
- const callback = jest.fn();
- renderSpotlightTour({ callback });
-
- expect(await screen.findByRole('alertdialog')).toBeInTheDocument();
- let dialog = screen.getByRole('alertdialog');
- expect(dialog).toHaveTextContent('Trust The Foo');
- expect(dialog).toHaveTextContent('Foo bar is baz');
- expect(screen.getByText('step 1 of 5')).toBeInTheDocument();
-
- await user.click(screen.getByRole('button', { name: 'next' }));
-
- dialog = screen.getByRole('alertdialog');
- expect(dialog).toHaveTextContent('Trust The Baz');
- expect(dialog).toHaveTextContent('Baz foo is bar');
- expect(callback).toHaveBeenCalled();
-
- await user.click(screen.getByRole('button', { name: 'next' }));
-
- dialog = screen.getByRole('alertdialog');
- expect(dialog).toHaveTextContent('Trust The Bar');
- expect(dialog).toHaveTextContent('Bar baz is foo');
-
- await user.click(screen.getByRole('button', { name: 'next' }));
-
- dialog = screen.getByRole('alertdialog');
- expect(dialog).toHaveTextContent('Trust The Foo 2');
- expect(dialog).toHaveTextContent('Foo baz is bar');
-
- await user.click(screen.getByRole('button', { name: 'go_back' }));
-
- dialog = screen.getByRole('alertdialog');
- expect(dialog).toHaveTextContent('Trust The Bar');
- expect(dialog).toHaveTextContent('Bar baz is foo');
-
- await user.click(screen.getByRole('button', { name: 'next' }));
- await user.click(screen.getByRole('button', { name: 'next' }));
-
- dialog = screen.getByRole('alertdialog');
- expect(dialog).toHaveTextContent('Trust The Baz 2');
- expect(dialog).toHaveTextContent('Baz bar is foo');
-
- expect(screen.queryByRole('button', { name: 'next' })).not.toBeInTheDocument();
-
- await user.click(screen.getByRole('button', { name: 'close' }));
-
- expect(screen.queryByRole('alertdialog')).not.toBeInTheDocument();
-});
-
-it('should not show the spotlight tour if run is false', () => {
- renderSpotlightTour({ run: false });
- expect(screen.queryByRole('alertdialog')).not.toBeInTheDocument();
-});
-
-it('should allow the customization of button labels', async () => {
- const user = userEvent.setup();
- renderSpotlightTour({
- nextLabel: 'forward',
- backLabel: 'backward',
- closeLabel: 'close_me',
- skipLabel: "just don't",
- showSkipButton: true,
- });
-
- expect(await screen.findByRole('alertdialog')).toBeInTheDocument();
- expect(screen.getByRole('button', { name: 'forward' })).toBeInTheDocument();
- expect(screen.getByRole('button', { name: "just don't" })).toBeInTheDocument();
-
- await user.click(screen.getByRole('button', { name: 'forward' }));
-
- expect(screen.getByRole('button', { name: 'backward' })).toBeInTheDocument();
-
- await user.click(screen.getByRole('button', { name: 'forward' }));
- await user.click(screen.getByRole('button', { name: 'forward' }));
- await user.click(screen.getByRole('button', { name: 'forward' }));
-
- expect(screen.getByRole('button', { name: 'close_me' })).toBeInTheDocument();
-});
-
-it('should not display steps counter when there is only one step and no render method', async () => {
- renderSpotlightTour({
- steps: [
- {
- target: '#step1',
- content: 'Foo bar is baz',
- title: 'Trust The Foo',
- placement: 'top',
- },
- ],
- stepXofYLabel: undefined,
- });
-
- expect(await screen.findByRole('alertdialog')).toBeInTheDocument();
- expect(screen.queryByText('step 1 of 1')).not.toBeInTheDocument();
-});
-
-function renderSpotlightTour(props: Partial<SpotlightTourProps> = {}) {
- return renderWithContext(
- <div>
- <div id="step1">This is step 1</div>
- <div id="step2">This is step 2</div>
- <div id="step3">This is step 3</div>
- <div id="step4">This is step 4</div>
- <div id="step5">This is step 5</div>
-
- <SpotlightTour
- continuous
- run
- stepXofYLabel={(x: number, y: number) => `step ${x} of ${y}`}
- steps={[
- {
- target: '#step1',
- content: 'Foo bar is baz',
- title: 'Trust The Foo',
- placement: 'top',
- },
- {
- target: '#step2',
- content: 'Baz foo is bar',
- title: 'Trust The Baz',
- placement: 'right',
- },
- {
- target: '#step3',
- content: 'Bar baz is foo',
- title: 'Trust The Bar',
- placement: 'bottom',
- },
- {
- target: '#step4',
- content: 'Foo baz is bar',
- title: 'Trust The Foo 2',
- placement: 'left',
- },
- {
- target: '#step5',
- content: 'Baz bar is foo',
- title: 'Trust The Baz 2',
- placement: 'center',
- },
- ]}
- {...props}
- />
- </div>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/Switch-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/Switch-test.tsx
deleted file mode 100644
index e1efe8f5d5a..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/Switch-test.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { render } from '../../helpers/testUtils';
-import { Switch } from '../Switch';
-
-const defaultProps = {
- value: false,
-};
-
-it('renders switch correctly if value is false and change to true on click', async () => {
- const user = userEvent.setup();
- const onChange = jest.fn();
-
- render(<Switch {...defaultProps} onChange={onChange} />);
- const switchContainer = screen.getByRole('switch');
- expect(switchContainer).not.toBeChecked();
-
- await user.click(switchContainer);
-
- expect(onChange).toHaveBeenCalledWith(true);
-});
-
-it('renders switch correctly if value is true and change to false on click', async () => {
- const user = userEvent.setup();
- const onChange = jest.fn();
-
- render(<Switch {...defaultProps} onChange={onChange} value />);
- const switchContainer = screen.getByRole('switch');
- expect(switchContainer).toBeChecked();
-
- await user.click(switchContainer);
-
- expect(onChange).toHaveBeenCalledWith(false);
-});
-
-it('renders switch correctly if value is true and disabled', () => {
- render(<Switch {...defaultProps} disabled value />);
- const switchContainer = screen.getByRole('switch');
- expect(switchContainer).toBeDisabled();
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/Tabs-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/Tabs-test.tsx
deleted file mode 100644
index 32837740b79..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/Tabs-test.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { renderWithContext } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { TabOption, Tabs } from '../Tabs';
-
-it('should render all options', async () => {
- const user = userEvent.setup();
- const onChange = jest.fn();
- const options: Array<TabOption<number>> = [
- { value: 1, label: 'first' },
- { value: 2, label: 'disabled', disabled: true },
- { value: 3, label: 'has counter', counter: 7 },
- ];
- renderToggleButtons({ onChange, options, value: 1 });
-
- expect(screen.getAllByRole('tab')).toHaveLength(3);
-
- await user.click(screen.getByText('first'));
-
- expect(onChange).not.toHaveBeenCalled();
-
- await user.click(screen.getByText('has counter'));
-
- expect(onChange).toHaveBeenCalledWith(3);
-});
-
-function renderToggleButtons(props: Partial<FCProps<typeof Tabs>> = {}) {
- return renderWithContext(<Tabs onChange={jest.fn()} options={[]} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/Tags-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/Tags-test.tsx
deleted file mode 100644
index 581bc3fd3cb..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/Tags-test.tsx
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable import/no-extraneous-dependencies */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { useState } from 'react';
-import { renderWithContext } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { MultiSelector } from '../MultiSelector';
-import { Tags } from '../Tags';
-import { Tooltip } from '../Tooltip';
-
-it('should display "no tags"', () => {
- renderTags({ tags: [] });
-
- expect(screen.getByText('no tags')).toBeInTheDocument();
-});
-
-it('should display tags', () => {
- const tags = ['tag1', 'tag2'];
- renderTags({ tags });
-
- expect(screen.getByText('tag1')).toBeInTheDocument();
- expect(screen.getByText('tag2')).toBeInTheDocument();
-});
-
-it('should handle more tags than the max to display', () => {
- const tags = ['tag1', 'tag2', 'tag3'];
- renderTags({ tags, tagsToDisplay: 2 });
-
- expect(screen.getByText('tag1')).toBeInTheDocument();
- expect(screen.getByText('tag2')).toBeInTheDocument();
- expect(screen.queryByText('tag3')).not.toBeInTheDocument();
- expect(screen.getByText('...')).toBeInTheDocument();
-});
-
-it('should allow editing tags', async () => {
- const user = userEvent.setup();
- renderTags({ allowUpdate: true });
-
- const plusButton = screen.getByText('+');
- expect(plusButton).toBeInTheDocument();
- await user.click(plusButton);
-
- expect(await screen.findByLabelText('search')).toBeInTheDocument();
- await user.click(screen.getByText('tag3'));
- await user.keyboard('{Escape}');
-
- expect(screen.getByText('tag1')).toBeInTheDocument();
- expect(screen.getByText('tag3')).toBeInTheDocument();
-
- await user.click(plusButton);
- await user.click(screen.getByRole('checkbox', { name: 'tag1' }));
- await user.keyboard('{Escape}');
-
- expect(screen.queryByText('tag1')).not.toBeInTheDocument();
- expect(screen.getByText('tag3')).toBeInTheDocument();
-});
-
-function renderTags(overrides: Partial<FCProps<typeof Tags>> = {}) {
- renderWithContext(<Wrapper {...overrides} />);
-}
-
-function Wrapper(overrides: Partial<FCProps<typeof Tags>> = {}) {
- const [selectedTags, setSelectedTags] = useState<string[]>(overrides.tags ?? ['tag1']);
-
- const overlay = (
- <MultiSelector
- createElementLabel="create new tag"
- elements={['tag1', 'tag2', 'tag3']}
- headerLabel="edit tags"
- noResultsLabel="no results"
- onSearch={jest.fn().mockResolvedValue(undefined)}
- onSelect={(tag) => {
- setSelectedTags([...selectedTags, tag]);
- }}
- onUnselect={(tag) => {
- const i = selectedTags.indexOf(tag);
- if (i > -1) {
- setSelectedTags([...selectedTags.slice(0, i), ...selectedTags.slice(i + 1)]);
- }
- }}
- searchInputAriaLabel="search"
- selectedElements={selectedTags}
- />
- );
-
- return (
- <Tags
- ariaTagsListLabel="list"
- emptyText="no tags"
- overlay={overlay}
- tags={selectedTags}
- tooltip={Tooltip}
- {...overrides}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/Text-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/Text-test.tsx
deleted file mode 100644
index 115ea4996a3..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/Text-test.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable import/no-extraneous-dependencies */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../helpers/testUtils';
-import { TextBold, TextMuted } from '../Text';
-
-it('should render SearchText', () => {
- render(<TextBold match="hi" name="hiya" />);
-
- expect(screen.getByText('hi')).toHaveStyle({
- 'font-weight': '600',
- });
-});
-
-it('should render TextMuted', () => {
- render(<TextMuted text="Hi" />);
-
- expect(screen.getByText('Hi')).toHaveStyle({
- color: 'var(--echoes-color-text-subdued)',
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/TextAccordion-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/TextAccordion-test.tsx
deleted file mode 100644
index 8a5919d35e5..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/TextAccordion-test.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import * as React from 'react';
-import { render } from '../../helpers/testUtils';
-import { TextAccordion } from '../TextAccordion';
-
-it('should behave correctly', async () => {
- const user = userEvent.setup();
- const children = 'hello';
- renderAccordion(children);
- expect(screen.queryByText(children)).not.toBeInTheDocument();
- await user.click(screen.getByRole('button', { name: 'test-aria' }));
- expect(screen.getByText(children)).toBeInTheDocument();
-});
-
-function renderAccordion(children: React.ReactNode) {
- function AccordionTest() {
- const [open, setOpen] = React.useState(false);
-
- return (
- <TextAccordion
- ariaLabel="test-aria"
- onClick={() => {
- setOpen(!open);
- }}
- open={open}
- renderHeader={() => 'Expand'}
- title="test"
- >
- <div>{children}</div>
- </TextAccordion>
- );
- }
-
- return render(<AccordionTest />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/Tooltip-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/Tooltip-test.tsx
deleted file mode 100644
index 8971c0ea191..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/Tooltip-test.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../helpers/testUtils';
-import { FCProps } from '../../types/misc';
-import { Tooltip, TooltipInner } from '../Tooltip';
-
-jest.mock('react-dom', () => {
- const reactDom = jest.requireActual('react-dom') as object;
- return { ...reactDom, findDOMNode: jest.fn().mockReturnValue(undefined) };
-});
-
-describe('TooltipInner', () => {
- it('should open & close', async () => {
- const onShow = jest.fn();
- const onHide = jest.fn();
- const { user } = setupWithProps({ onHide, onShow });
-
- await user.hover(screen.getByRole('note'));
- expect(await screen.findByRole('tooltip')).toBeInTheDocument();
- expect(onShow).toHaveBeenCalled();
-
- await user.unhover(screen.getByRole('note'));
- expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
- expect(onHide).toHaveBeenCalled();
- });
-
- it('should not shadow children pointer events', async () => {
- const onShow = jest.fn();
- const onHide = jest.fn();
- const onPointerEnter = jest.fn();
- const onPointerLeave = jest.fn();
- const { user } = setupWithProps(
- { onHide, onShow },
- <div onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave} role="note" />,
- );
-
- await user.hover(screen.getByRole('note'));
- expect(await screen.findByRole('tooltip')).toBeInTheDocument();
- expect(onShow).toHaveBeenCalled();
- expect(onPointerEnter).toHaveBeenCalled();
-
- await user.unhover(screen.getByRole('note'));
- expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
- expect(onHide).toHaveBeenCalled();
- expect(onPointerLeave).toHaveBeenCalled();
- });
-
- it('should not open when mouse goes away quickly', async () => {
- const { user } = setupWithProps();
-
- await user.hover(screen.getByRole('note'));
- await user.unhover(screen.getByRole('note'));
-
- expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
- });
-
- it('should position the tooltip correctly', async () => {
- const onShow = jest.fn();
- const onHide = jest.fn();
- const { user } = setupWithProps({ onHide, onShow });
-
- await user.hover(screen.getByRole('note'));
- expect(await screen.findByRole('tooltip')).toBeInTheDocument();
- expect(screen.getByRole('tooltip')).toHaveClass('bottom');
- });
-
- it('should be opened/hidden using tab navigation', async () => {
- const { user } = setupWithProps({}, <a href="#">Link</a>);
-
- await user.tab();
- expect(await screen.findByRole('tooltip')).toBeInTheDocument();
- await user.tab();
- expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
- });
-
- function setupWithProps(
- props: Partial<TooltipInner['props']> = {},
- children = <div role="note" />,
- ) {
- return render(
- <TooltipInner content={<span id="overlay" />} mouseLeaveDelay={0} {...props}>
- {children}
- </TooltipInner>,
- );
- }
-});
-
-describe('Tooltip', () => {
- it('should not render tooltip without overlay', async () => {
- const { user } = setupWithProps({ content: undefined });
- await user.hover(screen.getByRole('note'));
- expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
- });
-
- it('should not render undefined tooltips', async () => {
- const { user } = setupWithProps({ content: undefined, visible: true });
- await user.hover(screen.getByRole('note'));
- expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
- });
-
- it('should not render empty tooltips', async () => {
- const { user } = setupWithProps({ content: '', visible: true });
- await user.hover(screen.getByRole('note'));
- expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
- });
-
- function setupWithProps(
- props: Partial<FCProps<typeof Tooltip>> = {},
- children = <div role="note" />,
- ) {
- return render(
- <Tooltip content={<span id="overlay" />} {...props}>
- {children}
- </Tooltip>,
- );
- }
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/TreeMap-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/TreeMap-test.tsx
deleted file mode 100644
index 41abad0b4a1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/TreeMap-test.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { render } from '../../helpers/testUtils';
-import { TreeMap, TreeMapProps } from '../TreeMap';
-
-it('should render correctly and forward click event', async () => {
- const user = userEvent.setup();
- const items = [
- {
- key: '1',
- size: 10,
- color: '#777',
- label: 'SonarQube_Server',
- },
- {
- key: '2',
- size: 30,
- color: '#777',
- label: 'SonarQube_Web',
- sourceData: 123,
- },
- {
- key: '3',
- size: 20,
- gradient: '#777',
- label: 'SonarQube_Search',
- },
- ];
- const onRectangleClick = jest.fn();
- const { container } = renderTreeMap({
- items,
- onRectangleClick,
- });
-
- expect(container).toMatchSnapshot();
-
- await user.click(screen.getByRole('link', { name: 'SonarQube_Web' }));
- expect(onRectangleClick).toHaveBeenCalledTimes(1);
- expect(onRectangleClick).toHaveBeenCalledWith(items[1]);
-});
-
-function renderTreeMap(props: Partial<TreeMapProps<unknown>>) {
- return render(
- <TreeMap height={100} items={[]} onRectangleClick={jest.fn()} width={100} {...props} />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/TutorialStep-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/TutorialStep-test.tsx
deleted file mode 100644
index c2f82fbfdf4..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/TutorialStep-test.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../helpers/testUtils';
-import { TutorialStep } from '../TutorialStep';
-import { TutorialStepList } from '../TutorialStepList';
-
-it('renders correctly', () => {
- renderTutorialStep();
- expect(screen.getByRole('heading', { level: 2, name: 'This is title' })).toBeInTheDocument();
- expect(screen.getByText('These are children')).toBeInTheDocument();
-});
-
-function renderTutorialStep() {
- return render(
- <TutorialStepList>
- <TutorialStep title="This is title">These are children</TutorialStep>
- </TutorialStepList>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/CodeSnippet-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/CodeSnippet-test.tsx.snap
deleted file mode 100644
index ac2ea24e199..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/CodeSnippet-test.tsx.snap
+++ /dev/null
@@ -1,691 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should highlight code content correctly 1`] = `
-.emotion-0 {
- background-color: rgb(252,252,253);
- border: 1px solid rgb(225,230,243);
- border-radius: 0.5rem;
- position: relative;
- margin-top: 0.5rem;
- margin-bottom: 0.5rem;
-}
-
-.emotion-0.code-snippet-simple-oneline {
- margin-top: 0;
- margin-bottom: 0;
- border-radius: 0.25rem;
-}
-
-.emotion-3 {
- box-sizing: border-box;
- display: -webkit-inline-box;
- display: -webkit-inline-flex;
- display: -ms-inline-flexbox;
- display: inline-flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- padding: var(--echoes-dimension-space-0) var(--button-padding);
- height: var(--button-height);
- min-height: var(--button-height);
- overflow: hidden;
- font: var(--echoes-typography-others-label);
- color: var(--button-color);
- -webkit-text-decoration: none;
- text-decoration: none;
- background-color: var(--button-background);
- border: var(--button-border);
- border-radius: var(--echoes-border-radius-400);
- outline: none;
- cursor: pointer;
- --button-color: var(--echoes-color-text-default);
- --button-border: var(--echoes-color-border-bold) solid var(--echoes-border-width-default);
- --button-background: var(--echoes-color-background-default);
- --button-background-hover: var(--echoes-color-background-default-hover);
- --button-background-active: var(--echoes-color-background-default-active);
- --button-background-focus: var(--echoes-color-background-default);
- --button-background-disabled: var(--echoes-color-background-disabled);
- --button-padding: var(--echoes-dimension-space-150);
- --button-height: var(--echoes-sizes-buttons-large);
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- font: var(--echoes-typography-text-default-regular);
- right: 1.5rem;
- top: 1.5rem;
- position: absolute;
-}
-
-.emotion-3:focus,
-.emotion-3:focus-visible {
- background-color: var(--button-background-focus);
- outline: var(--echoes-color-focus-default) solid var(--echoes-focus-border-width-default);
- outline-offset: var(--echoes-focus-border-offset-default);
-}
-
-.emotion-3:hover {
- background-color: var(--button-background-hover);
-}
-
-.emotion-3:active {
- background-color: var(--button-background-active);
-}
-
-.emotion-3:disabled,
-.emotion-3:disabled:has(:hover, :active, :focus, :focus-visible) {
- color: var(--echoes-color-text-disabled);
- background-color: var(--button-background-disabled);
- border: none;
- cursor: not-allowed;
- pointer-events: none;
-}
-
-.code-snippet-highlighted-oneline .emotion-3 {
- bottom: 0.5rem;
-}
-
-.emotion-5 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- gap: var(--echoes-dimension-space-75);
- overflow: hidden;
-}
-
-.emotion-7 {
- -moz-osx-font-smoothing: grayscale;
- -webkit-font-smoothing: antialiased;
- display: inline-block;
- font-size: calc(1em + 4px);
- font-style: normal;
- font-weight: normal;
- height: calc(2em - 16px);
- line-height: calc(2em - 16px);
- text-align: center;
- vertical-align: bottom;
- width: calc(2em - 16px);
- font-family: 'Material Symbols Rounded';
-}
-
-.emotion-9 {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.emotion-11 code {
- font: var(--echoes-typography-code-default);
- background: rgb(252,252,253);
- color: rgb(51,53,60);
-}
-
-.emotion-11 code.hljs {
- padding: unset;
-}
-
-.emotion-11 .hljs-meta,
-.emotion-11 .hljs-variable {
- color: rgb(51,53,60);
-}
-
-.emotion-11 .hljs-doctag,
-.emotion-11 .hljs-title,
-.emotion-11 .hljs-title.class_,
-.emotion-11 .hljs-title.function_ {
- color: rgb(34,84,192);
-}
-
-.emotion-11 .hljs-comment {
- font: var(--echoes-typography-code-comment);
- color: rgb(109,111,119);
-}
-
-.emotion-11 .hljs-keyword,
-.emotion-11 .hljs-tag,
-.emotion-11 .hljs-type {
- color: rgb(152,29,150);
-}
-
-.emotion-11 .hljs-literal,
-.emotion-11 .hljs-number {
- color: rgb(126,83,5);
-}
-
-.emotion-11 .hljs-string {
- color: rgb(32,105,31);
-}
-
-.emotion-11 .hljs-meta .hljs-keyword {
- color: rgb(47,103,48);
-}
-
-.emotion-11 .sonar-underline {
- -webkit-text-decoration: underline rgb(253,162,155);
- text-decoration: underline rgb(253,162,155);
- -webkit-text-decoration: underline rgb(253,162,155) wavy;
- text-decoration: underline rgb(253,162,155) wavy;
- text-decoration-thickness: 2px;
- text-decoration-skip-ink: none;
-}
-
-.emotion-11.code-wrap {
- white-space: pre-wrap;
- word-break: break-all;
-}
-
-.emotion-11.code-wrap.wrap-words {
- word-break: normal;
- overflow-wrap: break-word;
-}
-
-.emotion-11 mark {
- font-weight: 400;
- padding: 0.25rem;
- border-radius: 0.25rem;
- background-color: rgb(197,205,223);
- color: rgb(217,45,32);
-}
-
-<div>
- <div
- class="sw-code fs-mask emotion-0 emotion-1"
- >
- <button
- class="sw-select-none emotion-2 emotion-3 emotion-4"
- data-state="closed"
- type="button"
- >
- <span
- class="emotion-5 emotion-6"
- >
- <span
- aria-hidden="true"
- class="emotion-7 emotion-8"
- >
- 
- </span>
- <span
- class="emotion-9 emotion-10"
- >
- Copy
- </span>
- </span>
- </button>
- <span
- class="hljs sw-overflow-auto sw-pr-24 sw-flex emotion-11 emotion-12"
- >
- <pre>
- &lt;prop&gt;foobar&lt;prop&gt;
- </pre>
- </span>
- </div>
-</div>
-`;
-
-exports[`should show full size when multiline with no editing 1`] = `
-.emotion-0 {
- background-color: rgb(252,252,253);
- border: 1px solid rgb(225,230,243);
- border-radius: 0.5rem;
- position: relative;
- margin-top: 0.5rem;
- margin-bottom: 0.5rem;
-}
-
-.emotion-0.code-snippet-simple-oneline {
- margin-top: 0;
- margin-bottom: 0;
- border-radius: 0.25rem;
-}
-
-.emotion-3 {
- box-sizing: border-box;
- display: -webkit-inline-box;
- display: -webkit-inline-flex;
- display: -ms-inline-flexbox;
- display: inline-flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- padding: var(--echoes-dimension-space-0) var(--button-padding);
- height: var(--button-height);
- min-height: var(--button-height);
- overflow: hidden;
- font: var(--echoes-typography-others-label);
- color: var(--button-color);
- -webkit-text-decoration: none;
- text-decoration: none;
- background-color: var(--button-background);
- border: var(--button-border);
- border-radius: var(--echoes-border-radius-400);
- outline: none;
- cursor: pointer;
- --button-color: var(--echoes-color-text-default);
- --button-border: var(--echoes-color-border-bold) solid var(--echoes-border-width-default);
- --button-background: var(--echoes-color-background-default);
- --button-background-hover: var(--echoes-color-background-default-hover);
- --button-background-active: var(--echoes-color-background-default-active);
- --button-background-focus: var(--echoes-color-background-default);
- --button-background-disabled: var(--echoes-color-background-disabled);
- --button-padding: var(--echoes-dimension-space-150);
- --button-height: var(--echoes-sizes-buttons-large);
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- font: var(--echoes-typography-text-default-regular);
- right: 1.5rem;
- top: 1.5rem;
- position: absolute;
-}
-
-.emotion-3:focus,
-.emotion-3:focus-visible {
- background-color: var(--button-background-focus);
- outline: var(--echoes-color-focus-default) solid var(--echoes-focus-border-width-default);
- outline-offset: var(--echoes-focus-border-offset-default);
-}
-
-.emotion-3:hover {
- background-color: var(--button-background-hover);
-}
-
-.emotion-3:active {
- background-color: var(--button-background-active);
-}
-
-.emotion-3:disabled,
-.emotion-3:disabled:has(:hover, :active, :focus, :focus-visible) {
- color: var(--echoes-color-text-disabled);
- background-color: var(--button-background-disabled);
- border: none;
- cursor: not-allowed;
- pointer-events: none;
-}
-
-.code-snippet-highlighted-oneline .emotion-3 {
- bottom: 0.5rem;
-}
-
-.emotion-5 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- gap: var(--echoes-dimension-space-75);
- overflow: hidden;
-}
-
-.emotion-7 {
- -moz-osx-font-smoothing: grayscale;
- -webkit-font-smoothing: antialiased;
- display: inline-block;
- font-size: calc(1em + 4px);
- font-style: normal;
- font-weight: normal;
- height: calc(2em - 16px);
- line-height: calc(2em - 16px);
- text-align: center;
- vertical-align: bottom;
- width: calc(2em - 16px);
- font-family: 'Material Symbols Rounded';
-}
-
-.emotion-9 {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.emotion-11 code {
- font: var(--echoes-typography-code-default);
- background: rgb(252,252,253);
- color: rgb(51,53,60);
-}
-
-.emotion-11 code.hljs {
- padding: unset;
-}
-
-.emotion-11 .hljs-meta,
-.emotion-11 .hljs-variable {
- color: rgb(51,53,60);
-}
-
-.emotion-11 .hljs-doctag,
-.emotion-11 .hljs-title,
-.emotion-11 .hljs-title.class_,
-.emotion-11 .hljs-title.function_ {
- color: rgb(34,84,192);
-}
-
-.emotion-11 .hljs-comment {
- font: var(--echoes-typography-code-comment);
- color: rgb(109,111,119);
-}
-
-.emotion-11 .hljs-keyword,
-.emotion-11 .hljs-tag,
-.emotion-11 .hljs-type {
- color: rgb(152,29,150);
-}
-
-.emotion-11 .hljs-literal,
-.emotion-11 .hljs-number {
- color: rgb(126,83,5);
-}
-
-.emotion-11 .hljs-string {
- color: rgb(32,105,31);
-}
-
-.emotion-11 .hljs-meta .hljs-keyword {
- color: rgb(47,103,48);
-}
-
-.emotion-11 .sonar-underline {
- -webkit-text-decoration: underline rgb(253,162,155);
- text-decoration: underline rgb(253,162,155);
- -webkit-text-decoration: underline rgb(253,162,155) wavy;
- text-decoration: underline rgb(253,162,155) wavy;
- text-decoration-thickness: 2px;
- text-decoration-skip-ink: none;
-}
-
-.emotion-11.code-wrap {
- white-space: pre-wrap;
- word-break: break-all;
-}
-
-.emotion-11.code-wrap.wrap-words {
- word-break: normal;
- overflow-wrap: break-word;
-}
-
-.emotion-11 mark {
- font-weight: 400;
- padding: 0.25rem;
- border-radius: 0.25rem;
- background-color: rgb(197,205,223);
- color: rgb(217,45,32);
-}
-
-<div>
- <div
- class="sw-code fs-mask emotion-0 emotion-1"
- >
- <button
- class="sw-select-none emotion-2 emotion-3 emotion-4"
- data-state="closed"
- type="button"
- >
- <span
- class="emotion-5 emotion-6"
- >
- <span
- aria-hidden="true"
- class="emotion-7 emotion-8"
- >
- 
- </span>
- <span
- class="emotion-9 emotion-10"
- >
- Copy
- </span>
- </span>
- </button>
- <span
- class="hljs sw-overflow-auto sw-pr-24 sw-flex emotion-11 emotion-12"
- >
- <pre>
- foo
-bar
- </pre>
- </span>
- </div>
-</div>
-`;
-
-exports[`should show reduced size when single line with no editing 1`] = `
-.emotion-0 {
- background-color: rgb(252,252,253);
- border: 1px solid rgb(225,230,243);
- border-radius: 0.5rem;
- position: relative;
- margin-top: 0.5rem;
- margin-bottom: 0.5rem;
-}
-
-.emotion-0.code-snippet-simple-oneline {
- margin-top: 0;
- margin-bottom: 0;
- border-radius: 0.25rem;
-}
-
-.emotion-3 {
- box-sizing: border-box;
- display: -webkit-inline-box;
- display: -webkit-inline-flex;
- display: -ms-inline-flexbox;
- display: inline-flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- padding: var(--echoes-dimension-space-0) var(--button-padding);
- height: var(--button-height);
- min-height: var(--button-height);
- overflow: hidden;
- font: var(--echoes-typography-others-label);
- color: var(--button-color);
- -webkit-text-decoration: none;
- text-decoration: none;
- background-color: var(--button-background);
- border: var(--button-border);
- border-radius: var(--echoes-border-radius-400);
- outline: none;
- cursor: pointer;
- --button-color: var(--echoes-color-text-default);
- --button-border: var(--echoes-color-border-bold) solid var(--echoes-border-width-default);
- --button-background: var(--echoes-color-background-default);
- --button-background-hover: var(--echoes-color-background-default-hover);
- --button-background-active: var(--echoes-color-background-default-active);
- --button-background-focus: var(--echoes-color-background-default);
- --button-background-disabled: var(--echoes-color-background-disabled);
- --button-padding: var(--echoes-dimension-space-150);
- --button-height: var(--echoes-sizes-buttons-large);
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- font: var(--echoes-typography-text-default-regular);
- right: 1.5rem;
- top: 1.5rem;
- position: absolute;
- bottom: 1rem;
- top: 1rem;
-}
-
-.emotion-3:focus,
-.emotion-3:focus-visible {
- background-color: var(--button-background-focus);
- outline: var(--echoes-color-focus-default) solid var(--echoes-focus-border-width-default);
- outline-offset: var(--echoes-focus-border-offset-default);
-}
-
-.emotion-3:hover {
- background-color: var(--button-background-hover);
-}
-
-.emotion-3:active {
- background-color: var(--button-background-active);
-}
-
-.emotion-3:disabled,
-.emotion-3:disabled:has(:hover, :active, :focus, :focus-visible) {
- color: var(--echoes-color-text-disabled);
- background-color: var(--button-background-disabled);
- border: none;
- cursor: not-allowed;
- pointer-events: none;
-}
-
-.code-snippet-highlighted-oneline .emotion-3 {
- bottom: 0.5rem;
-}
-
-.emotion-5 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- gap: var(--echoes-dimension-space-75);
- overflow: hidden;
-}
-
-.emotion-7 {
- -moz-osx-font-smoothing: grayscale;
- -webkit-font-smoothing: antialiased;
- display: inline-block;
- font-size: calc(1em + 4px);
- font-style: normal;
- font-weight: normal;
- height: calc(2em - 16px);
- line-height: calc(2em - 16px);
- text-align: center;
- vertical-align: bottom;
- width: calc(2em - 16px);
- font-family: 'Material Symbols Rounded';
-}
-
-.emotion-9 {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.emotion-11 code {
- font: var(--echoes-typography-code-default);
- background: rgb(252,252,253);
- color: rgb(51,53,60);
-}
-
-.emotion-11 code.hljs {
- padding: unset;
-}
-
-.emotion-11 .hljs-meta,
-.emotion-11 .hljs-variable {
- color: rgb(51,53,60);
-}
-
-.emotion-11 .hljs-doctag,
-.emotion-11 .hljs-title,
-.emotion-11 .hljs-title.class_,
-.emotion-11 .hljs-title.function_ {
- color: rgb(34,84,192);
-}
-
-.emotion-11 .hljs-comment {
- font: var(--echoes-typography-code-comment);
- color: rgb(109,111,119);
-}
-
-.emotion-11 .hljs-keyword,
-.emotion-11 .hljs-tag,
-.emotion-11 .hljs-type {
- color: rgb(152,29,150);
-}
-
-.emotion-11 .hljs-literal,
-.emotion-11 .hljs-number {
- color: rgb(126,83,5);
-}
-
-.emotion-11 .hljs-string {
- color: rgb(32,105,31);
-}
-
-.emotion-11 .hljs-meta .hljs-keyword {
- color: rgb(47,103,48);
-}
-
-.emotion-11 .sonar-underline {
- -webkit-text-decoration: underline rgb(253,162,155);
- text-decoration: underline rgb(253,162,155);
- -webkit-text-decoration: underline rgb(253,162,155) wavy;
- text-decoration: underline rgb(253,162,155) wavy;
- text-decoration-thickness: 2px;
- text-decoration-skip-ink: none;
-}
-
-.emotion-11.code-wrap {
- white-space: pre-wrap;
- word-break: break-all;
-}
-
-.emotion-11.code-wrap.wrap-words {
- word-break: normal;
- overflow-wrap: break-word;
-}
-
-.emotion-11 mark {
- font-weight: 400;
- padding: 0.25rem;
- border-radius: 0.25rem;
- background-color: rgb(197,205,223);
- color: rgb(217,45,32);
-}
-
-<div>
- <div
- class="sw-code sw-py-6 code-snippet-highlighted-oneline fs-mask emotion-0 emotion-1"
- >
- <button
- class="sw-select-none emotion-2 emotion-3 emotion-4"
- data-state="closed"
- type="button"
- >
- <span
- class="emotion-5 emotion-6"
- >
- <span
- aria-hidden="true"
- class="emotion-7 emotion-8"
- >
- 
- </span>
- <span
- class="emotion-9 emotion-10"
- >
- Copy
- </span>
- </span>
- </button>
- <span
- class="hljs sw-overflow-auto sw-pr-24 sw-flex emotion-11 emotion-12"
- >
- <code>
- foobar
- </code>
- </span>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/CoverageIndicator-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/CoverageIndicator-test.tsx.snap
deleted file mode 100644
index f04fb70a190..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/CoverageIndicator-test.tsx.snap
+++ /dev/null
@@ -1,83 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should display CoverageIndicator 1`] = `
-<body>
- <div>
- <svg
- class="donut-chart"
- height="24"
- width="24"
- >
- <g
- transform="translate(0, 0)"
- >
- <g
- transform="translate(12, 12)"
- >
- <path
- d="M0.75,-11.977A12,12,0,0,1,7.222,-9.583L5.265,-7.299A9,9,0,0,0,0.75,-8.969Z"
- style="fill: rgb(18,183,106);"
- />
- <path
- d="M8.361,-8.608A12,12,0,1,1,-0.75,-11.977L-0.75,-8.969A9,9,0,1,0,6.404,-6.324Z"
- style="fill: rgb(180,35,24);"
- />
- </g>
- </g>
- </svg>
- </div>
-</body>
-`;
-
-exports[`should display CoverageIndicator with correct aria properties 1`] = `
-<body>
- <div>
- <svg
- aria-hidden="true"
- aria-label="label"
- fill="none"
- height="24"
- role="img"
- style="clip-rule: evenodd; display: inline-block; fill-rule: evenodd; user-select: none; vertical-align: middle; stroke-linejoin: round; stroke-miterlimit: 1.414;"
- version="1.1"
- viewBox="0 0 16 16"
- width="24"
- xml:space="preserve"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- >
- <path
- clip-rule="evenodd"
- d="M16 8C16 12.4183 12.4183 16 8 16C5.5106 16 3.28676 14.863 1.81951 13.0799L15.4913 5.1865C15.8201 6.06172 16 7.00986 16 8ZM14.5574 3.41624L0.750565 11.3876C0.269025 10.3589 0 9.21089 0 8C0 3.58172 3.58172 0 8 0C10.7132 0 13.1109 1.35064 14.5574 3.41624Z"
- fill="#E1E6F3"
- fill-rule="evenodd"
- />
- </svg>
- </div>
-</body>
-`;
-
-exports[`should display CoverageIndicator without value 1`] = `
-<body>
- <div>
- <svg
- aria-hidden="true"
- fill="none"
- height="24"
- role="img"
- style="clip-rule: evenodd; display: inline-block; fill-rule: evenodd; user-select: none; vertical-align: middle; stroke-linejoin: round; stroke-miterlimit: 1.414;"
- version="1.1"
- viewBox="0 0 16 16"
- width="24"
- xml:space="preserve"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- >
- <path
- clip-rule="evenodd"
- d="M16 8C16 12.4183 12.4183 16 8 16C5.5106 16 3.28676 14.863 1.81951 13.0799L15.4913 5.1865C15.8201 6.06172 16 7.00986 16 8ZM14.5574 3.41624L0.750565 11.3876C0.269025 10.3589 0 9.21089 0 8C0 3.58172 3.58172 0 8 0C10.7132 0 13.1109 1.35064 14.5574 3.41624Z"
- fill="#E1E6F3"
- fill-rule="evenodd"
- />
- </svg>
- </div>
-</body>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/DuplicationsIndicator-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/DuplicationsIndicator-test.tsx.snap
deleted file mode 100644
index 677207098fe..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/DuplicationsIndicator-test.tsx.snap
+++ /dev/null
@@ -1,203 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should display DuplicationsIndicator with rating 1`] = `
-<body>
- <div>
- <svg
- height="24"
- viewBox="0 0 16 16"
- width="24"
- >
- <circle
- cx="8"
- cy="8"
- fill="rgb(18,183,106)"
- r="2"
- />
- <path
- clip-rule="evenodd"
- d="M8 14c3.3137 0 6-2.6863 6-6 0-3.31371-2.6863-6-6-6-3.31371 0-6 2.68629-6 6 0 3.3137 2.68629 6 6 6Zm0 2c4.4183 0 8-3.5817 8-8 0-4.41828-3.5817-8-8-8-4.41828 0-8 3.58172-8 8 0 4.4183 3.58172 8 8 8Z"
- fill="rgb(239,242,249)"
- fill-rule="evenodd"
- />
- <circle
- cx="8"
- cy="8"
- fill="rgb(18,183,106)"
- r="2"
- />
- </svg>
- </div>
-</body>
-`;
-
-exports[`should display DuplicationsIndicator with rating 2`] = `
-<body>
- <div>
- <svg
- height="24"
- viewBox="0 0 16 16"
- width="24"
- >
- <circle
- cx="8"
- cy="8"
- fill="rgb(18,183,106)"
- r="2"
- />
- <path
- clip-rule="evenodd"
- d="M8 14c3.3137 0 6-2.6863 6-6 0-3.31371-2.6863-6-6-6-3.31371 0-6 2.68629-6 6 0 3.3137 2.68629 6 6 6Zm0 2c4.4183 0 8-3.5817 8-8 0-4.41828-3.5817-8-8-8-4.41828 0-8 3.58172-8 8 0 4.4183 3.58172 8 8 8Z"
- fill="rgb(239,242,249)"
- fill-rule="evenodd"
- />
- <path
- d="M8 0c.81879 0 1.63272.125698 2.4134.372702L9.81002 2.27953A5.99976 5.99976 0 0 0 8 2V0Z"
- fill="rgb(18,183,106)"
- />
- </svg>
- </div>
-</body>
-`;
-
-exports[`should display DuplicationsIndicator with rating 3`] = `
-<body>
- <div>
- <svg
- height="24"
- viewBox="0 0 16 16"
- width="24"
- >
- <circle
- cx="8"
- cy="8"
- fill="rgb(110,183,18)"
- r="2"
- />
- <path
- clip-rule="evenodd"
- d="M8 14c3.3137 0 6-2.6863 6-6 0-3.31371-2.6863-6-6-6-3.31371 0-6 2.68629-6 6 0 3.3137 2.68629 6 6 6Zm0 2c4.4183 0 8-3.5817 8-8 0-4.41828-3.5817-8-8-8-4.41828 0-8 3.58172-8 8 0 4.4183 3.58172 8 8 8Z"
- fill="rgb(239,242,249)"
- fill-rule="evenodd"
- />
- <path
- d="M8 0c1.89071 2e-8 3.7203.669649 5.1643 1.89017l-1.2911 1.52746C10.7902 2.50224 9.41803 2 8 2V0Z"
- fill="rgb(110,183,18)"
- />
- </svg>
- </div>
-</body>
-`;
-
-exports[`should display DuplicationsIndicator with rating 4`] = `
-<body>
- <div>
- <svg
- height="24"
- viewBox="0 0 16 16"
- width="24"
- >
- <circle
- cx="8"
- cy="8"
- fill="rgb(245,184,64)"
- r="2"
- />
- <path
- clip-rule="evenodd"
- d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z"
- fill="rgb(239,242,249)"
- fill-rule="evenodd"
- />
- <path
- d="M8 0a7.9999 7.9999 0 0 1 4.5815 1.44181 7.99949 7.99949 0 0 1 2.9301 3.80574l-1.8779.68811A6.00009 6.00009 0 0 0 8 2V0Z"
- fill="rgb(245,184,64)"
- />
- </svg>
- </div>
-</body>
-`;
-
-exports[`should display DuplicationsIndicator with rating 5`] = `
-<body>
- <div>
- <svg
- height="24"
- viewBox="0 0 16 16"
- width="24"
- >
- <circle
- cx="8"
- cy="8"
- fill="rgb(247,95,9)"
- r="2"
- />
- <path
- clip-rule="evenodd"
- d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z"
- fill="rgb(239,242,249)"
- fill-rule="evenodd"
- />
- <path
- d="M8 0a8 8 0 0 1 5.0686 1.81054 8.00033 8.00033 0 0 1 2.7744 4.61211l-1.9608.39434a5.99958 5.99958 0 0 0-2.0808-3.45908A5.99972 5.99972 0 0 0 8 2V0Z"
- fill="rgb(247,95,9)"
- />
- </svg>
- </div>
-</body>
-`;
-
-exports[`should display DuplicationsIndicator with rating 6`] = `
-<body>
- <div>
- <svg
- height="24"
- viewBox="0 0 16 16"
- width="24"
- >
- <circle
- cx="8"
- cy="8"
- fill="rgb(240,68,56)"
- r="2"
- />
- <path
- clip-rule="evenodd"
- d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z"
- fill="rgb(239,242,249)"
- fill-rule="evenodd"
- />
- <path
- d="M8 0a8.0002 8.0002 0 0 1 5.6569 13.6569l-1.4143-1.4143a5.9993 5.9993 0 0 0 1.3007-6.5387A5.9999 5.9999 0 0 0 8 2V0Z"
- fill="rgb(240,68,56)"
- />
- </svg>
- </div>
-</body>
-`;
-
-exports[`should display DuplicationsIndicator without rating 1`] = `
-<body>
- <div>
- <svg
- aria-hidden="true"
- fill="none"
- height="24"
- role="img"
- style="clip-rule: evenodd; display: inline-block; fill-rule: evenodd; user-select: none; vertical-align: middle; stroke-linejoin: round; stroke-miterlimit: 1.414;"
- version="1.1"
- viewBox="0 0 16 16"
- width="24"
- xml:space="preserve"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- >
- <path
- clip-rule="evenodd"
- d="M16 8C16 12.4183 12.4183 16 8 16C5.5106 16 3.28676 14.863 1.81951 13.0799L15.4913 5.1865C15.8201 6.06172 16 7.00986 16 8ZM14.5574 3.41624L0.750565 11.3876C0.269025 10.3589 0 9.21089 0 8C0 3.58172 3.58172 0 8 0C10.7132 0 13.1109 1.35064 14.5574 3.41624Z"
- fill="#E1E6F3"
- fill-rule="evenodd"
- />
- </svg>
- </div>
-</body>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/FavoriteButton-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/FavoriteButton-test.tsx.snap
deleted file mode 100644
index ac4eb0e769e..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/FavoriteButton-test.tsx.snap
+++ /dev/null
@@ -1,167 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render favorite empty 1`] = `
-.emotion-1 {
- box-sizing: border-box;
- border: none;
- outline: none;
- -webkit-text-decoration: none;
- text-decoration: none;
- color: var(--color);
- background-color: var(--background);
- -webkit-transition: background-color 0.2s ease,outline 0.2s ease,color 0.2s ease;
- transition: background-color 0.2s ease,outline 0.2s ease,color 0.2s ease;
- display: -webkit-inline-box;
- display: -webkit-inline-flex;
- display: -ms-inline-flexbox;
- display: inline-flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- cursor: pointer;
- height: 1.5rem;
- border-radius: 0.125rem;
- padding-left: 0.25rem;
- padding-right: 0.25rem;
- --background: transparent;
- --backgroundHover: rgb(232,235,255);
- --color: rgb(75,86,187);
- --colorHover: rgb(43,51,104);
- --focus: rgba(93,108,208,0.2);
-}
-
-.emotion-1:hover,
-.emotion-1:focus,
-.emotion-1:active {
- color: var(--colorHover);
- background-color: var(--backgroundHover);
-}
-
-.emotion-1:focus,
-.emotion-1:active {
- outline: 4px solid var(--focus);
-}
-
-.emotion-1:disabled,
-.emotion-1:disabled:hover {
- color: var(--echoes-color-icon-disabled);
- background-color: var(--background);
- cursor: not-allowed;
-}
-
-.emotion-3 {
- fill: rgb(237,148,106);
-}
-
-<div>
- <button
- aria-describedby="tooltip-2"
- aria-label="label-info"
- class="it__favorite-link it__is-filled emotion-0 emotion-1 emotion-2"
- type="button"
- >
- <svg
- aria-hidden="true"
- class=" emotion-3 emotion-4"
- fill="currentColor"
- focusable="false"
- height="16"
- style="display: inline-block; user-select: none; vertical-align: middle; overflow: visible;"
- viewBox="0 0 16 16"
- width="16"
- >
- <path
- d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"
- />
- </svg>
- </button>
-</div>
-`;
-
-exports[`should render favorite filled 1`] = `
-.emotion-1 {
- box-sizing: border-box;
- border: none;
- outline: none;
- -webkit-text-decoration: none;
- text-decoration: none;
- color: var(--color);
- background-color: var(--background);
- -webkit-transition: background-color 0.2s ease,outline 0.2s ease,color 0.2s ease;
- transition: background-color 0.2s ease,outline 0.2s ease,color 0.2s ease;
- display: -webkit-inline-box;
- display: -webkit-inline-flex;
- display: -ms-inline-flexbox;
- display: inline-flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- cursor: pointer;
- height: 1.5rem;
- border-radius: 0.125rem;
- padding-left: 0.25rem;
- padding-right: 0.25rem;
- --background: transparent;
- --backgroundHover: rgb(232,235,255);
- --color: rgb(75,86,187);
- --colorHover: rgb(43,51,104);
- --focus: rgba(93,108,208,0.2);
-}
-
-.emotion-1:hover,
-.emotion-1:focus,
-.emotion-1:active {
- color: var(--colorHover);
- background-color: var(--backgroundHover);
-}
-
-.emotion-1:focus,
-.emotion-1:active {
- outline: 4px solid var(--focus);
-}
-
-.emotion-1:disabled,
-.emotion-1:disabled:hover {
- color: var(--echoes-color-icon-disabled);
- background-color: var(--background);
- cursor: not-allowed;
-}
-
-.emotion-3 {
- fill: rgb(237,148,106);
-}
-
-<div>
- <button
- aria-describedby="tooltip-1"
- aria-label="label-info"
- class="it__favorite-link it__is-filled emotion-0 emotion-1 emotion-2"
- type="button"
- >
- <svg
- aria-hidden="true"
- class=" emotion-3 emotion-4"
- fill="currentColor"
- focusable="false"
- height="16"
- style="display: inline-block; user-select: none; vertical-align: middle; overflow: visible;"
- viewBox="0 0 16 16"
- width="16"
- >
- <path
- d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"
- />
- </svg>
- </button>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/Histogram-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/Histogram-test.tsx.snap
deleted file mode 100644
index 566251156e1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/Histogram-test.tsx.snap
+++ /dev/null
@@ -1,369 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly 1`] = `
-.emotion-0 {
- fill: rgb(93,108,208);
-}
-
-<div>
- <svg
- height="75"
- width="100"
- >
- <g
- transform="translate(10, 10)"
- >
- <g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="54"
- x="0"
- y="10"
- />
- </g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="41"
- x="0"
- y="28"
- />
- </g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="81"
- x="0"
- y="46"
- />
- </g>
- </g>
- </g>
- </svg>
-</div>
-`;
-
-exports[`renders correctly with yValues 1`] = `
-.emotion-0 {
- fill: rgb(93,108,208);
-}
-
-.emotion-2 {
- font: var(--echoes-typography-text-default-regular);
- fill: var(--echoes-color-text-subdued);
-}
-
-.e4r8l5e2 .emotion-2 {
- fill: rgb(255,255,255);
-}
-
-<div>
- <svg
- height="75"
- width="100"
- >
- <g
- transform="translate(10, 10)"
- >
- <g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="54"
- x="0"
- y="10"
- />
- <text
- class="emotion-2 emotion-3"
- dx="1em"
- dy="0.3em"
- text-anchor="start"
- x="53.33333333333333"
- y="15"
- >
- 100.0
- </text>
- </g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="41"
- x="0"
- y="28"
- />
- <text
- class="emotion-2 emotion-3"
- dx="1em"
- dy="0.3em"
- text-anchor="start"
- x="40"
- y="33"
- >
- 75.0
- </text>
- </g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="81"
- x="0"
- y="46"
- />
- <text
- class="emotion-2 emotion-3"
- dx="1em"
- dy="0.3em"
- text-anchor="start"
- x="80"
- y="51"
- >
- 150.0
- </text>
- </g>
- </g>
- </g>
- </svg>
-</div>
-`;
-
-exports[`renders correctly with yValues and yTicks 1`] = `
-.emotion-0 {
- fill: rgb(93,108,208);
-}
-
-.emotion-2 {
- font: var(--echoes-typography-text-default-regular);
- fill: var(--echoes-color-text-subdued);
-}
-
-.e4r8l5e2 .emotion-2 {
- fill: rgb(255,255,255);
-}
-
-<div>
- <svg
- height="75"
- width="100"
- >
- <g
- transform="translate(10, 10)"
- >
- <g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="54"
- x="0"
- y="10"
- />
- <text
- class="emotion-2 emotion-3"
- dx="1em"
- dy="0.3em"
- text-anchor="start"
- x="53.33333333333333"
- y="15"
- >
- 100.0
- </text>
- <text
- class="emotion-2 emotion-3"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="15"
- >
- a
- </text>
- </g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="41"
- x="0"
- y="28"
- />
- <text
- class="emotion-2 emotion-3"
- dx="1em"
- dy="0.3em"
- text-anchor="start"
- x="40"
- y="33"
- >
- 75.0
- </text>
- <text
- class="emotion-2 emotion-3"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="33"
- >
- b
- </text>
- </g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="81"
- x="0"
- y="46"
- />
- <text
- class="emotion-2 emotion-3"
- dx="1em"
- dy="0.3em"
- text-anchor="start"
- x="80"
- y="51"
- >
- 150.0
- </text>
- <text
- class="emotion-2 emotion-3"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="51"
- >
- c
- </text>
- </g>
- </g>
- </g>
- </svg>
-</div>
-`;
-
-exports[`renders correctly with yValues, yTicks, and yTooltips 1`] = `
-.emotion-0 {
- fill: rgb(93,108,208);
-}
-
-.emotion-2 {
- font: var(--echoes-typography-text-default-regular);
- fill: var(--echoes-color-text-subdued);
-}
-
-.e4r8l5e2 .emotion-2 {
- fill: rgb(255,255,255);
-}
-
-<div>
- <svg
- height="75"
- width="100"
- >
- <g
- transform="translate(10, 10)"
- >
- <g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="54"
- x="0"
- y="10"
- />
- <text
- aria-describedby="tooltip-1"
- class="emotion-2 emotion-3"
- dx="1em"
- dy="0.3em"
- text-anchor="start"
- x="53.33333333333333"
- y="15"
- >
- 100.0
- </text>
- <text
- class="emotion-2 emotion-3"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="15"
- >
- a
- </text>
- </g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="41"
- x="0"
- y="28"
- />
- <text
- aria-describedby="tooltip-2"
- class="emotion-2 emotion-3"
- dx="1em"
- dy="0.3em"
- text-anchor="start"
- x="40"
- y="33"
- >
- 75.0
- </text>
- <text
- class="emotion-2 emotion-3"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="33"
- >
- b
- </text>
- </g>
- <g>
- <rect
- class="emotion-0 emotion-1"
- height="10"
- width="81"
- x="0"
- y="46"
- />
- <text
- aria-describedby="tooltip-3"
- class="emotion-2 emotion-3"
- dx="1em"
- dy="0.3em"
- text-anchor="start"
- x="80"
- y="51"
- >
- 150.0
- </text>
- <text
- class="emotion-2 emotion-3"
- dx="-1em"
- dy="0.3em"
- text-anchor="end"
- x="0"
- y="51"
- >
- c
- </text>
- </g>
- </g>
- </g>
- </svg>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/HotspotRating-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/HotspotRating-test.tsx.snap
deleted file mode 100644
index 741beaababd..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/HotspotRating-test.tsx.snap
+++ /dev/null
@@ -1,118 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render HotspotRating with HIGH rating 1`] = `
-<svg
- aria-hidden="false"
- aria-label="label"
- fill="none"
- height="16"
- role="img"
- style="clip-rule: evenodd; display: inline-block; fill-rule: evenodd; user-select: none; vertical-align: middle; stroke-linejoin: round; stroke-miterlimit: 1.414;"
- version="1.1"
- viewBox="0 0 16 16"
- width="16"
- xml:space="preserve"
- xmlns:xlink="http://www.w3.org/1999/xlink"
->
- <circle
- cx="8"
- cy="8"
- fill="rgb(254,205,202)"
- r="7"
- />
- <path
- d="M5 6.67113C5 6.56986 5.05583 6.47727 5.14421 6.43198L7.88334 5.02823C7.95678 4.99059 8.04322 4.99059 8.11666 5.02823L10.8558 6.43198C10.9442 6.47727 11 6.56986 11 6.67113V10.7324C11 10.9191 10.8181 11.0483 10.6475 10.9827L8.0916 10.0003C8.03254 9.97763 7.96746 9.97763 7.9084 10.0003L5.35247 10.9827C5.18192 11.0483 5 10.9191 5 10.7324V6.67113Z"
- fill="rgb(93,29,19)"
- />
-</svg>
-`;
-
-exports[`should render HotspotRating with LOW rating 1`] = `
-<svg
- aria-hidden="false"
- aria-label="label"
- fill="none"
- height="16"
- role="img"
- style="clip-rule: evenodd; display: inline-block; fill-rule: evenodd; user-select: none; vertical-align: middle; stroke-linejoin: round; stroke-miterlimit: 1.414;"
- version="1.1"
- viewBox="0 0 16 16"
- width="16"
- xml:space="preserve"
- xmlns:xlink="http://www.w3.org/1999/xlink"
->
- <circle
- cx="8"
- cy="8"
- fill="rgb(252,233,163)"
- r="7"
- />
- <path
- d="M5.23223 6.93223L8 9.7L10.7678 6.93223"
- stroke="rgb(102,64,15)"
- stroke-linecap="round"
- stroke-linejoin="round"
- stroke-width="1.5"
- />
-</svg>
-`;
-
-exports[`should render HotspotRating with MEDIUM rating 1`] = `
-<svg
- aria-hidden="false"
- aria-label="label"
- fill="none"
- height="16"
- role="img"
- style="clip-rule: evenodd; display: inline-block; fill-rule: evenodd; user-select: none; vertical-align: middle; stroke-linejoin: round; stroke-miterlimit: 1.414;"
- version="1.1"
- viewBox="0 0 16 16"
- width="16"
- xml:space="preserve"
- xmlns:xlink="http://www.w3.org/1999/xlink"
->
- <circle
- cx="8"
- cy="8"
- fill="rgb(255,214,175)"
- r="7"
- />
- <path
- d="M10.7678 9.5 8 6.73223 5.23223 9.5"
- stroke="rgb(122,46,14)"
- stroke-linecap="round"
- stroke-linejoin="round"
- stroke-width="1.5"
- />
-</svg>
-`;
-
-exports[`should render HotspotRating with default LOW rating 1`] = `
-<svg
- aria-hidden="false"
- aria-label="label"
- fill="none"
- height="16"
- role="img"
- style="clip-rule: evenodd; display: inline-block; fill-rule: evenodd; user-select: none; vertical-align: middle; stroke-linejoin: round; stroke-miterlimit: 1.414;"
- version="1.1"
- viewBox="0 0 16 16"
- width="16"
- xml:space="preserve"
- xmlns:xlink="http://www.w3.org/1999/xlink"
->
- <circle
- cx="8"
- cy="8"
- fill="rgb(252,233,163)"
- r="7"
- />
- <path
- d="M5.23223 6.93223L8 9.7L10.7678 6.93223"
- stroke="rgb(102,64,15)"
- stroke-linecap="round"
- stroke-linejoin="round"
- stroke-width="1.5"
- />
-</svg>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/IssueMessageHighlighting-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/IssueMessageHighlighting-test.tsx.snap
deleted file mode 100644
index 932cc06d0f8..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/IssueMessageHighlighting-test.tsx.snap
+++ /dev/null
@@ -1,148 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should format the string with highlights 1`] = `<DocumentFragment />`;
-
-exports[`should format the string with highlights 2`] = `
-<DocumentFragment>
- message
-</DocumentFragment>
-`;
-
-exports[`should format the string with highlights 3`] = `
-<DocumentFragment>
- message
-</DocumentFragment>
-`;
-
-exports[`should format the string with highlights 4`] = `
-<DocumentFragment>
- <span>
- message
- </span>
-</DocumentFragment>
-`;
-
-exports[`should format the string with highlights 5`] = `
-<DocumentFragment>
- .emotion-0 {
- background: rgb(252,252,253);
- border-color: rgb(225,230,243);
- color: rgb(62,67,87);
- padding-top: 0.125rem;
- padding-bottom: 0.125rem;
-}
-
-a .emotion-0 {
- padding-bottom: 0;
-}
-
-<span>
- m
- <span
- class="sw-code sw-rounded-1 sw-px-1 sw-border sw-border-solid emotion-0 emotion-1"
- >
- ess
- </span>
- a
- <span
- class="sw-code sw-rounded-1 sw-px-1 sw-border sw-border-solid emotion-0 emotion-1"
- >
- g
- </span>
- e
- </span>
-</DocumentFragment>
-`;
-
-exports[`should format the string with highlights 6`] = `
-<DocumentFragment>
- <span>
- a somewhat longer message with overlapping ranges
- </span>
-</DocumentFragment>
-`;
-
-exports[`should format the string with highlights 7`] = `
-<DocumentFragment>
- .emotion-0 {
- background: rgb(252,252,253);
- border-color: rgb(225,230,243);
- color: rgb(62,67,87);
- padding-top: 0.125rem;
- padding-bottom: 0.125rem;
-}
-
-a .emotion-0 {
- padding-bottom: 0;
-}
-
-<span>
- a somewhat longer message with overlapping range
- <span
- class="sw-code sw-rounded-1 sw-px-1 sw-border sw-border-solid emotion-0 emotion-1"
- >
- s
- </span>
- </span>
-</DocumentFragment>
-`;
-
-exports[`should format the string with highlights 8`] = `
-<DocumentFragment>
- <span>
- a somewhat longer message with overlapping ranges
- </span>
-</DocumentFragment>
-`;
-
-exports[`should format the string with highlights 9`] = `
-<DocumentFragment>
- .emotion-0 {
- background: rgb(252,252,253);
- border-color: rgb(225,230,243);
- color: rgb(62,67,87);
- padding-top: 0.125rem;
- padding-bottom: 0.125rem;
-}
-
-a .emotion-0 {
- padding-bottom: 0;
-}
-
-<span>
- a
- <span
- class="sw-code sw-rounded-1 sw-px-1 sw-border sw-border-solid emotion-0 emotion-1"
- >
- somewhat longer message
- </span>
- with overlapping ranges
- </span>
-</DocumentFragment>
-`;
-
-exports[`should format the string with highlights 10`] = `
-<DocumentFragment>
- .emotion-0 {
- background: rgb(252,252,253);
- border-color: rgb(225,230,243);
- color: rgb(62,67,87);
- padding-top: 0.125rem;
- padding-bottom: 0.125rem;
-}
-
-a .emotion-0 {
- padding-bottom: 0;
-}
-
-<span>
- a
- <span
- class="sw-code sw-rounded-1 sw-px-1 sw-border sw-border-solid emotion-0 emotion-1"
- >
- somewhat longer message with
- </span>
- overlapping ranges
- </span>
-</DocumentFragment>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/KeyboardHint-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/KeyboardHint-test.tsx.snap
deleted file mode 100644
index bc08e8388ec..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/KeyboardHint-test.tsx.snap
+++ /dev/null
@@ -1,291 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders on mac 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- gap: 0.5rem;
- -webkit-box-flex-wrap: wrap;
- -webkit-flex-wrap: wrap;
- -ms-flex-wrap: wrap;
- flex-wrap: wrap;
- color: var(--echoes-color-text-subdued);
-}
-
-.emotion-2 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="emotion-0 emotion-1"
- >
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-2 emotion-3"
- >
- ⌘
- </span>
- <span
- class=" emotion-2 emotion-3"
- >
- ⌥
- </span>
- </div>
- </div>
-</div>
-`;
-
-exports[`renders on windows 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- gap: 0.5rem;
- -webkit-box-flex-wrap: wrap;
- -webkit-flex-wrap: wrap;
- -ms-flex-wrap: wrap;
- flex-wrap: wrap;
- color: var(--echoes-color-text-subdued);
-}
-
-.emotion-2 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="emotion-0 emotion-1"
- >
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-2 emotion-3"
- >
- Ctrl
- </span>
- <span
- class=" emotion-2 emotion-3"
- >
- Alt
- </span>
- </div>
- </div>
-</div>
-`;
-
-exports[`renders with command 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- gap: 0.5rem;
- -webkit-box-flex-wrap: wrap;
- -webkit-flex-wrap: wrap;
- -ms-flex-wrap: wrap;
- flex-wrap: wrap;
- color: var(--echoes-color-text-subdued);
-}
-
-.emotion-2 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="emotion-0 emotion-1"
- >
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class="sw-px-1 emotion-2 emotion-3"
- >
- command
- </span>
- </div>
- </div>
-</div>
-`;
-
-exports[`renders with title 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- gap: 0.5rem;
- -webkit-box-flex-wrap: wrap;
- -webkit-flex-wrap: wrap;
- -ms-flex-wrap: wrap;
- flex-wrap: wrap;
- color: var(--echoes-color-text-subdued);
-}
-
-.emotion-2 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="emotion-0 emotion-1"
- >
- <span
- class="sw-truncate"
- >
- title
- </span>
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-2 emotion-3"
- >
- click
- </span>
- </div>
- </div>
-</div>
-`;
-
-exports[`renders without title 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- gap: 0.5rem;
- -webkit-box-flex-wrap: wrap;
- -webkit-flex-wrap: wrap;
- -ms-flex-wrap: wrap;
- flex-wrap: wrap;
- color: var(--echoes-color-text-subdued);
-}
-
-.emotion-2 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="emotion-0 emotion-1"
- >
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-2 emotion-3"
- >
- click
- </span>
- </div>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/KeyboardHintKeys-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/KeyboardHintKeys-test.tsx.snap
deleted file mode 100644
index 5817a21adb1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/KeyboardHintKeys-test.tsx.snap
+++ /dev/null
@@ -1,552 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render Alt 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-0 emotion-1"
- >
- Alt
- </span>
- </div>
-</div>
-`;
-
-exports[`should render ArrowDown 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-0 emotion-1"
- >
- <svg
- aria-hidden="true"
- class="octicon octicon-triangle-down"
- fill="currentColor"
- focusable="false"
- height="16"
- style="display: inline-block; user-select: none; vertical-align: middle; overflow: visible;"
- viewBox="0 0 16 16"
- width="16"
- >
- <path
- d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"
- />
- </svg>
- </span>
- </div>
-</div>
-`;
-
-exports[`should render ArrowLeft 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-0 emotion-1"
- >
- <svg
- aria-hidden="true"
- class="octicon octicon-triangle-left"
- fill="currentColor"
- focusable="false"
- height="16"
- style="display: inline-block; user-select: none; vertical-align: middle; overflow: visible;"
- viewBox="0 0 16 16"
- width="16"
- >
- <path
- d="M9.573 4.427 6.177 7.823a.25.25 0 0 0 0 .354l3.396 3.396a.25.25 0 0 0 .427-.177V4.604a.25.25 0 0 0-.427-.177Z"
- />
- </svg>
- </span>
- </div>
-</div>
-`;
-
-exports[`should render ArrowRight 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-0 emotion-1"
- >
- <svg
- aria-hidden="true"
- class="octicon octicon-triangle-right"
- fill="currentColor"
- focusable="false"
- height="16"
- style="display: inline-block; user-select: none; vertical-align: middle; overflow: visible;"
- viewBox="0 0 16 16"
- width="16"
- >
- <path
- d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"
- />
- </svg>
- </span>
- </div>
-</div>
-`;
-
-exports[`should render ArrowUp 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-0 emotion-1"
- >
- <svg
- aria-hidden="true"
- class="octicon octicon-triangle-up"
- fill="currentColor"
- focusable="false"
- height="16"
- style="display: inline-block; user-select: none; vertical-align: middle; overflow: visible;"
- viewBox="0 0 16 16"
- width="16"
- >
- <path
- d="m4.427 9.573 3.396-3.396a.25.25 0 0 1 .354 0l3.396 3.396a.25.25 0 0 1-.177.427H4.604a.25.25 0 0 1-.177-.427Z"
- />
- </svg>
- </span>
- </div>
-</div>
-`;
-
-exports[`should render Click 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-0 emotion-1"
- >
- click
- </span>
- </div>
-</div>
-`;
-
-exports[`should render Command 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-0 emotion-1"
- >
- ⌘
- </span>
- </div>
-</div>
-`;
-
-exports[`should render Control 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-0 emotion-1"
- >
- Ctrl
- </span>
- </div>
-</div>
-`;
-
-exports[`should render Option 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-0 emotion-1"
- >
- ⌥
- </span>
- </div>
-</div>
-`;
-
-exports[`should render a default text if no keys match 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-0 emotion-1"
- >
- Ctrl
- </span>
- <span>
- +
- </span>
- <span
- class=" emotion-0 emotion-1"
- >
- click
- </span>
- </div>
-</div>
-`;
-
-exports[`should render multiple keys 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class="sw-px-1 emotion-0 emotion-1"
- >
- Use
- </span>
- <span
- class=" emotion-0 emotion-1"
- >
- Ctrl
- </span>
- <span>
- +
- </span>
- <span
- class=" emotion-0 emotion-1"
- >
- <svg
- aria-hidden="true"
- class="octicon octicon-triangle-up"
- fill="currentColor"
- focusable="false"
- height="16"
- style="display: inline-block; user-select: none; vertical-align: middle; overflow: visible;"
- viewBox="0 0 16 16"
- width="16"
- >
- <path
- d="m4.427 9.573 3.396-3.396a.25.25 0 0 1 .354 0l3.396 3.396a.25.25 0 0 1-.177.427H4.604a.25.25 0 0 1-.177-.427Z"
- />
- </svg>
- </span>
- <span
- class=" emotion-0 emotion-1"
- >
- <svg
- aria-hidden="true"
- class="octicon octicon-triangle-down"
- fill="currentColor"
- focusable="false"
- height="16"
- style="display: inline-block; user-select: none; vertical-align: middle; overflow: visible;"
- viewBox="0 0 16 16"
- width="16"
- >
- <path
- d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"
- />
- </svg>
- </span>
- </div>
-</div>
-`;
-
-exports[`should render multiple keys with non-key symbols 1`] = `
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding-left: 0.125rem;
- padding-right: 0.125rem;
- border-radius: 0.125rem;
- background-color: rgb(225,230,243);
- color: rgb(62,67,87);
-}
-
-<div>
- <div
- class="sw-flex sw-gap-1"
- >
- <span
- class=" emotion-0 emotion-1"
- >
- Ctrl
- </span>
- <span>
- +
- </span>
- <span
- class=" emotion-0 emotion-1"
- >
- <svg
- aria-hidden="true"
- class="octicon octicon-triangle-down"
- fill="currentColor"
- focusable="false"
- height="16"
- style="display: inline-block; user-select: none; vertical-align: middle; overflow: visible;"
- viewBox="0 0 16 16"
- width="16"
- >
- <path
- d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"
- />
- </svg>
- </span>
- <span
- class=" emotion-0 emotion-1"
- >
- <svg
- aria-hidden="true"
- class="octicon octicon-triangle-up"
- fill="currentColor"
- focusable="false"
- height="16"
- style="display: inline-block; user-select: none; vertical-align: middle; overflow: visible;"
- viewBox="0 0 16 16"
- width="16"
- >
- <path
- d="m4.427 9.573 3.396-3.396a.25.25 0 0 1 .354 0l3.396 3.396a.25.25 0 0 1-.177.427H4.604a.25.25 0 0 1-.177-.427Z"
- />
- </svg>
- </span>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/LineCoverage-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/LineCoverage-test.tsx.snap
deleted file mode 100644
index c21478897f5..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/LineCoverage-test.tsx.snap
+++ /dev/null
@@ -1,237 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly when covered 1`] = `
-.emotion-0 {
- color: var(--echoes-color-text-subdued);
- background-color: var(--line-background);
- outline: none;
- height: 100%;
- width: 100%;
- box-sizing: border-box;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-
-.e19zkvle13:hover .emotion-0 {
- background-color: rgb(239,242,249);
-}
-
-.emotion-2 {
- height: 100%;
- width: 0.25rem;
- margin-left: 0.125rem;
- background-color: rgb(166,244,197);
-}
-
-.emotion-2,
-.emotion-2 svg {
- outline: none;
-}
-
-<tr>
- <td
- aria-describedby="tooltip-1"
- class="emotion-0 emotion-1"
- data-line-number="16"
- >
- <div
- aria-label="OK"
- class="emotion-2 emotion-3"
- />
- </td>
-</tr>
-`;
-
-exports[`should render correctly when no data 1`] = `
-.emotion-0 {
- color: var(--echoes-color-text-subdued);
- background-color: var(--line-background);
- outline: none;
- height: 100%;
- width: 100%;
- box-sizing: border-box;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-
-.e19zkvle13:hover .emotion-0 {
- background-color: rgb(239,242,249);
-}
-
-<tr>
- <td
- class="emotion-0 emotion-1"
- data-line-number="16"
- />
-</tr>
-`;
-
-exports[`should render correctly when partially covered with 5/10 conditions 1`] = `
-.emotion-0 {
- color: var(--echoes-color-text-subdued);
- background-color: var(--line-background);
- outline: none;
- height: 100%;
- width: 100%;
- box-sizing: border-box;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-
-.e19zkvle13:hover .emotion-0 {
- background-color: rgb(239,242,249);
-}
-
-.emotion-2 {
- height: 100%;
- width: 0.25rem;
- margin-left: 0.125rem;
-}
-
-.emotion-2,
-.emotion-2 svg {
- outline: none;
-}
-
-<tr>
- <td
- aria-describedby="tooltip-4"
- class="emotion-0 emotion-1"
- data-line-number="16"
- >
- <div
- aria-label="OK"
- class="emotion-2 emotion-3"
- >
- <svg
- fill="none"
- viewBox="0 0 4 18"
- xmlns="http://www.w3.org/2000/svg"
- >
- <rect
- fill="rgb(217,45,32)"
- height="18"
- width="4"
- />
- <path
- clip-rule="evenodd"
- d="M0 0L4 3V6L0 3V0ZM0 6L4 9V12L0 9V6ZM4 15L0 12V15L4 18V15Z"
- fill="rgb(255,255,255)"
- fill-rule="evenodd"
- />
- </svg>
- </div>
- </td>
-</tr>
-`;
-
-exports[`should render correctly when partially covered without conditions 1`] = `
-.emotion-0 {
- color: var(--echoes-color-text-subdued);
- background-color: var(--line-background);
- outline: none;
- height: 100%;
- width: 100%;
- box-sizing: border-box;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-
-.e19zkvle13:hover .emotion-0 {
- background-color: rgb(239,242,249);
-}
-
-.emotion-2 {
- height: 100%;
- width: 0.25rem;
- margin-left: 0.125rem;
-}
-
-.emotion-2,
-.emotion-2 svg {
- outline: none;
-}
-
-<tr>
- <td
- aria-describedby="tooltip-3"
- class="emotion-0 emotion-1"
- data-line-number="16"
- >
- <div
- aria-label="OK"
- class="emotion-2 emotion-3"
- >
- <svg
- fill="none"
- viewBox="0 0 4 18"
- xmlns="http://www.w3.org/2000/svg"
- >
- <rect
- fill="rgb(217,45,32)"
- height="18"
- width="4"
- />
- <path
- clip-rule="evenodd"
- d="M0 0L4 3V6L0 3V0ZM0 6L4 9V12L0 9V6ZM4 15L0 12V15L4 18V15Z"
- fill="rgb(255,255,255)"
- fill-rule="evenodd"
- />
- </svg>
- </div>
- </td>
-</tr>
-`;
-
-exports[`should render correctly when uncovered 1`] = `
-.emotion-0 {
- color: var(--echoes-color-text-subdued);
- background-color: var(--line-background);
- outline: none;
- height: 100%;
- width: 100%;
- box-sizing: border-box;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-
-.e19zkvle13:hover .emotion-0 {
- background-color: rgb(239,242,249);
-}
-
-.emotion-2 {
- height: 100%;
- width: 0.25rem;
- margin-left: 0.125rem;
- background-color: rgb(217,45,32);
-}
-
-.emotion-2,
-.emotion-2 svg {
- outline: none;
-}
-
-<tr>
- <td
- aria-describedby="tooltip-2"
- class="emotion-0 emotion-1"
- data-line-number="16"
- >
- <div
- aria-label="OK"
- class="emotion-2 emotion-3"
- />
- </td>
-</tr>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/LineFinding-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/LineFinding-test.tsx.snap
deleted file mode 100644
index 7e61c609169..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/LineFinding-test.tsx.snap
+++ /dev/null
@@ -1,64 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly as button 1`] = `
-.emotion-0 {
- all: unset;
- cursor: pointer;
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- gap: 0.5rem;
- margin-left: 0.25rem;
- margin-right: 0.25rem;
- margin-top: 0.75rem;
- margin-bottom: 0.75rem;
- border-radius: 0.25rem;
- padding-left: 0.75rem;
- padding-right: 0.75rem;
- width: 100%;
- box-sizing: border-box;
- padding-top: 0.75rem;
- padding-bottom: 0.75rem;
- font: var(--echoes-typography-text-large-semi-bold);
- cursor: default;
- border: 1px solid rgb(253,162,155);
- color: rgb(62,67,87);
- word-break: break-word;
- background-color: rgb(255,255,255);
-}
-
-.emotion-0:focus-visible {
- background-color: rgb(239,242,249);
-}
-
-.emotion-0:hover {
- box-shadow: 0px 1px 3px 0px rgba(29,33,47,0.05),0px 1px 25px 0px rgba(29,33,47,0.05);
-}
-
-.emotion-2 {
- all: unset;
- cursor: pointer;
-}
-
-.emotion-2:focus-visible {
- background-color: rgb(239,242,249);
-}
-
-<div>
- <div
- class="emotion-0 emotion-1"
- data-issue="key"
- >
- <button
- class="emotion-2 emotion-3"
- >
- message
- </button>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/LineWrapper-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/LineWrapper-test.tsx.snap
deleted file mode 100644
index bb8bcca7efc..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/LineWrapper-test.tsx.snap
+++ /dev/null
@@ -1,21 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render with correct styling 1`] = `
-.emotion-0 {
- display: grid;
- grid-template-rows: auto;
- grid-template-columns: var(--columns);
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- font: var(--echoes-typography-code-default);
-}
-
-<tbody>
- <tr
- class="emotion-0 emotion-1"
- style="--columns: 44px 50px 26px repeat(3, 6px) 1fr; --line-background: rgb(255,255,255);"
- />
-</tbody>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/TreeMap-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/TreeMap-test.tsx.snap
deleted file mode 100644
index f9b2a493f78..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/__snapshots__/TreeMap-test.tsx.snap
+++ /dev/null
@@ -1,194 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly and forward click event 1`] = `
-.emotion-0 {
- position: relative;
-}
-
-.emotion-2 {
- position: absolute;
- box-sizing: border-box;
- border-right: 1px solid #fff;
- border-bottom: 1px solid #fff;
-}
-
-.emotion-4 {
- height: 100%;
- width: 100%;
- border-width: 0px;
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-flex-direction: column;
- -ms-flex-direction: column;
- flex-direction: column;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- color: rgb(62,67,87);
-}
-
-.emotion-4:hover,
-.emotion-4:active,
-.emotion-4:focus {
- border-width: 0px;
- outline: none;
-}
-
-.emotion-4:focus .treemap-text,
-.emotion-4:hover .treemap-text {
- text-decoration-line: underline;
-}
-
-.emotion-6 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-box-flex-wrap: wrap;
- -webkit-flex-wrap: wrap;
- -ms-flex-wrap: wrap;
- flex-wrap: wrap;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- gap: 0.5rem;
- line-height: 1.2;
- max-width: 83px;
-}
-
-.emotion-6 .treemap-text {
- -webkit-flex-shrink: 1;
- -ms-flex-negative: 1;
- flex-shrink: 1;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- text-align: left;
-}
-
-.emotion-8 {
- position: absolute!important;
- left: -10000px!important;
- top: auto!important;
- width: 1px!important;
- height: 1px!important;
- overflow: hidden!important;
-}
-
-.emotion-22 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-box-flex-wrap: wrap;
- -webkit-flex-wrap: wrap;
- -ms-flex-wrap: wrap;
- flex-wrap: wrap;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- gap: 0.5rem;
- line-height: 1.2;
- max-width: 17px;
-}
-
-.emotion-22 .treemap-text {
- -webkit-flex-shrink: 1;
- -ms-flex-negative: 1;
- flex-shrink: 1;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- text-align: left;
-}
-
-<div>
- <ul
- class="emotion-0 emotion-1"
- style="width: 100px; height: 100px;"
- >
- <li
- class="emotion-2 emotion-3"
- style="left: 0px; top: 0px; width: 83px; height: 60px; background-color: rgb(119, 119, 119); font-size: 12.974358974358974px; line-height: 60px;"
- >
- <a
- class="emotion-4 emotion-5"
- href="#"
- >
- <div
- class="emotion-6 emotion-7"
- width="83"
- >
- <span
- class="shrink-0"
- />
- <span
- class="treemap-text"
- >
- SonarQube_Web
- </span>
- <span
- class="emotion-8 emotion-9"
- />
- </div>
- </a>
- </li>
- <li
- class="emotion-2 emotion-3"
- style="left: 0px; top: 60px; width: 83px; height: 40px; font-size: 12.276041666666668px; line-height: 40px;"
- >
- <a
- class="emotion-4 emotion-5"
- href="#"
- >
- <div
- class="emotion-6 emotion-7"
- width="83"
- >
- <span
- class="shrink-0"
- />
- <span
- class="emotion-8 emotion-9"
- />
- </div>
- </a>
- </li>
- <li
- class="emotion-2 emotion-3"
- style="left: 83px; top: 0px; width: 17px; height: 100px; background-color: rgb(119, 119, 119); font-size: 11px; line-height: 100px;"
- >
- <a
- class="emotion-4 emotion-5"
- href="#"
- >
- <div
- class="emotion-22 emotion-7"
- width="17"
- >
- <span
- class="emotion-8 emotion-9"
- />
- </div>
- </a>
- </li>
- </ul>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/clipboard-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/clipboard-test.tsx
deleted file mode 100644
index 9b3d3bb7e52..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/clipboard-test.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen, waitForElementToBeRemoved } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { renderWithContext } from '../../helpers/testUtils';
-import { ClipboardButton, ClipboardIconButton } from '../clipboard';
-
-beforeEach(() => {
- jest.useFakeTimers();
-});
-
-afterEach(() => {
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
-});
-
-describe('ClipboardButton', () => {
- it('should display and function correctly', async () => {
- /* Delay: null is necessary to play well with fake timers
- * https://github.com/testing-library/user-event/issues/833
- */
- const user = userEvent.setup({ delay: null });
- renderClipboardButton();
-
- expect(screen.getByRole('button', { name: 'Copy' })).toBeInTheDocument();
-
- await user.click(screen.getByRole('button', { name: 'Copy' }));
-
- expect(await screen.findByRole('tooltip', { name: 'Copied' })).toBeInTheDocument();
-
- await waitForElementToBeRemoved(() => screen.queryByRole('tooltip', { name: 'Copied' }));
- jest.runAllTimers();
- });
-
- it('should render a custom label if provided', () => {
- renderClipboardButton('Foo Bar');
- expect(screen.getByRole('button', { name: 'Foo Bar' })).toBeInTheDocument();
- });
-
- function renderClipboardButton(children?: React.ReactNode) {
- renderWithContext(<ClipboardButton copyValue="foo">{children}</ClipboardButton>);
- }
-});
-
-describe('ClipboardIconButton', () => {
- it('should display and function correctly', async () => {
- /* Delay: null is necessary to play well with fake timers
- * https://github.com/testing-library/user-event/issues/833
- */
- const user = userEvent.setup({ delay: null });
- renderWithContext(<ClipboardIconButton copyValue="foo" />);
-
- const copyButton = screen.getByRole('button', { name: 'Copy to clipboard' });
- expect(copyButton).toBeInTheDocument();
-
- expect(screen.getByRole('button', { name: 'Copy to clipboard' })).toBeInTheDocument();
-
- await user.click(screen.getByRole('button', { name: 'Copy to clipboard' }));
-
- expect(await screen.findByRole('tooltip', { name: 'Copied' })).toBeInTheDocument();
-
- await waitForElementToBeRemoved(() => screen.queryByRole('tooltip', { name: 'Copied' }));
- jest.runAllTimers();
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/__tests__/layouts-test.tsx b/server/sonar-web/src/main/js/design-system/components/__tests__/layouts-test.tsx
deleted file mode 100644
index 2e5a2d67961..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/__tests__/layouts-test.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render, screen } from '@testing-library/react';
-import { CenteredLayout, LargeCenteredLayout } from '../layouts';
-
-describe('CenteredLayout', () => {
- it('should render as expected', () => {
- render(<CenteredLayout>content</CenteredLayout>);
-
- expect(screen.getByText('content')).toHaveStyle({
- 'min-width': '1280px',
- 'max-width': '1280px',
- });
- });
-});
-
-describe('LargeCenteredLayout', () => {
- it('should render as expected', () => {
- render(<LargeCenteredLayout>content</LargeCenteredLayout>);
-
- expect(screen.getByText('content')).toHaveStyle({
- 'min-width': '1280px',
- 'max-width': '1680px',
- });
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/avatar/Avatar.tsx b/server/sonar-web/src/main/js/design-system/components/avatar/Avatar.tsx
deleted file mode 100644
index 3335bef541a..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/avatar/Avatar.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { ReactEventHandler, useState } from 'react';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../../helpers/theme';
-import { GenericAvatar } from './GenericAvatar';
-import { Size, sizeMap } from './utils';
-
-interface AvatarProps {
- border?: boolean;
- className?: string;
- enableGravatar?: boolean;
- gravatarServerUrl?: string;
- hash?: string;
- name?: string;
- organizationAvatar?: string;
- organizationName?: string;
- size?: Size;
-}
-
-/**
- * (!) Do not use directly. it requires the gravatar settings to properly fetch the avatars.
- * This is injected by the `Avatar` component in `components/ui` in sonar-web
- */
-export function Avatar({
- className,
- enableGravatar,
- gravatarServerUrl,
- hash,
- name,
- organizationAvatar,
- organizationName,
- size = 'sm',
- border,
-}: AvatarProps) {
- const [imgError, setImgError] = useState(false);
- const numberSize = sizeMap[size];
- const resolvedName = organizationName ?? name;
-
- const handleImgError: ReactEventHandler<HTMLImageElement> = () => {
- setImgError(true);
- };
-
- if (!imgError) {
- if (enableGravatar && gravatarServerUrl && hash) {
- const url = gravatarServerUrl
- .replace('{EMAIL_MD5}', hash)
- .replace('{SIZE}', String(numberSize * 2));
-
- return (
- <StyledAvatar
- alt={resolvedName}
- border={border}
- className={className}
- height={numberSize}
- onError={handleImgError}
- role="img"
- src={url}
- width={numberSize}
- />
- );
- }
-
- if (resolvedName && organizationAvatar) {
- return (
- <StyledAvatar
- alt={resolvedName}
- border={border}
- className={className}
- height={numberSize}
- onError={handleImgError}
- role="img"
- src={organizationAvatar}
- width={numberSize}
- />
- );
- }
- }
-
- if (!resolvedName) {
- return <input className="sw-appearance-none" />;
- }
-
- return <GenericAvatar className={className} name={resolvedName} size={size} />;
-}
-
-const StyledAvatar = styled.img<{ border?: boolean }>`
- ${tw`sw-inline-flex`};
- ${tw`sw-items-center`};
- ${tw`sw-justify-center`};
- ${tw`sw-align-top`};
- ${tw`sw-rounded-1`};
- border: ${({ border }) => (border ? themeBorder('default', 'avatarBorder') : '')};
- background: ${themeColor('avatarBackground')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/avatar/GenericAvatar.tsx b/server/sonar-web/src/main/js/design-system/components/avatar/GenericAvatar.tsx
deleted file mode 100644
index 36af2b5bbff..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/avatar/GenericAvatar.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import styled from '@emotion/styled';
-import React from 'react';
-import tw from 'twin.macro';
-import { themeAvatarColor } from '../../helpers/theme';
-import { IconProps } from '../icons/Icon';
-import { Size, iconSizeMap, sizeMap } from './utils';
-
-export interface GenericAvatarProps {
- Icon?: React.ComponentType<React.PropsWithChildren<IconProps>>;
- className?: string;
- name: string;
- size?: Size;
-}
-
-export function GenericAvatar({
- className,
- Icon,
- name,
- size = 'sm',
-}: Readonly<GenericAvatarProps>) {
- const theme = useTheme();
- const text = name.length > 0 ? name[0].toUpperCase() : '';
-
- const iconSize = iconSizeMap[size];
-
- return (
- <StyledGenericAvatar
- aria-label={name}
- className={className}
- name={name}
- role="img"
- size={sizeMap[size]}
- >
- {Icon ? (
- <Icon fill={themeAvatarColor(name, true)({ theme })} height={iconSize} width={iconSize} />
- ) : (
- text
- )}
- </StyledGenericAvatar>
- );
-}
-
-export const StyledGenericAvatar = styled.div<{ name: string; size: number }>`
- ${tw`sw-text-center`};
- ${tw`sw-align-top`};
- ${tw`sw-select-none`};
- ${tw`sw-font-regular`};
- ${tw`sw-rounded-1`};
- ${tw`sw-inline-flex`};
- ${tw`sw-items-center`};
- ${tw`sw-justify-center`};
- height: ${({ size }) => size}px;
- width: ${({ size }) => size}px;
- background-color: ${({ name, theme }) => themeAvatarColor(name)({ theme })};
- color: ${({ name, theme }) => themeAvatarColor(name, true)({ theme })};
- font-size: ${({ size }) => Math.max(Math.floor(size / 2), 8)}px;
- line-height: ${({ size }) => size}px;
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/avatar/__tests__/Avatar-test.tsx b/server/sonar-web/src/main/js/design-system/components/avatar/__tests__/Avatar-test.tsx
deleted file mode 100644
index c3d5143eb2d..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/avatar/__tests__/Avatar-test.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable import/no-extraneous-dependencies */
-
-import { fireEvent, screen } from '@testing-library/react';
-import { render } from '../../../helpers/testUtils';
-import { FCProps } from '../../../types/misc';
-import { Avatar } from '../Avatar';
-
-const gravatarServerUrl = 'http://example.com/{EMAIL_MD5}.jpg?s={SIZE}';
-
-it('should render avatar with border', () => {
- setupWithProps({ border: true, hash: '7daf6c79d4802916d83f6266e24850af' });
- expect(screen.getByRole('img')).toHaveStyle('border: 1px solid rgb(225,230,243)');
-});
-
-it('should be able to render with hash only', () => {
- setupWithProps({ hash: '7daf6c79d4802916d83f6266e24850af' });
- expect(screen.getByRole('img')).toHaveAttribute(
- 'src',
- 'http://example.com/7daf6c79d4802916d83f6266e24850af.jpg?s=48',
- );
-});
-
-it('should fall back to generated on error', () => {
- setupWithProps({ hash: '7daf6c79d4802916d83f6266e24850af' });
- fireEvent(screen.getByRole('img'), new Event('error'));
- expect(screen.getByRole('img')).not.toHaveAttribute('src');
-});
-
-it('should fall back to dummy avatar', () => {
- setupWithProps({ enableGravatar: false });
- expect(screen.getByRole('img')).not.toHaveAttribute('src');
-});
-
-it('should return null if no name is set', () => {
- setupWithProps({ name: undefined });
- expect(screen.queryByRole('img')).not.toBeInTheDocument();
-});
-
-it('should display organization avatar correctly', () => {
- const avatar = 'http://example.com/avatar.png';
- setupWithProps({ organizationAvatar: avatar, organizationName: 'my-org' });
- expect(screen.getByRole('img')).toHaveAttribute('src', avatar);
-});
-
-function setupWithProps(props: Partial<FCProps<typeof Avatar>> = {}) {
- return render(
- <Avatar enableGravatar gravatarServerUrl={gravatarServerUrl} name="foo" {...props} />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/avatar/__tests__/GenericAvatar-test.tsx b/server/sonar-web/src/main/js/design-system/components/avatar/__tests__/GenericAvatar-test.tsx
deleted file mode 100644
index 2780d89ae2a..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/avatar/__tests__/GenericAvatar-test.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../../helpers/testUtils';
-import { CustomIcon, IconProps } from '../../icons/Icon';
-import { GenericAvatar } from '../GenericAvatar';
-
-function TestIcon(props: IconProps) {
- return (
- <CustomIcon {...props}>
- <path d="l10 10" />
- </CustomIcon>
- );
-}
-
-it('should render single word and size', () => {
- render(<GenericAvatar name="foo" size="xs" />);
- const image = screen.getByRole('img');
- expect(image).toHaveAttribute('size', '16');
- expect(screen.getByText('F')).toBeInTheDocument();
-});
-
-it('should render multiple word with default size', () => {
- render(<GenericAvatar name="foo bar" />);
- const image = screen.getByRole('img');
- expect(image).toHaveAttribute('size', '24');
- expect(screen.getByText('F')).toBeInTheDocument();
-});
-
-it('should render without name', () => {
- render(<GenericAvatar Icon={TestIcon} name="" size="md" />);
- const image = screen.getByRole('img');
- expect(image).toHaveAttribute('size', '40');
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/avatar/utils.ts b/server/sonar-web/src/main/js/design-system/components/avatar/utils.ts
deleted file mode 100644
index f3aa0d48527..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/avatar/utils.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export type Size = 'xs' | 'sm' | 'md' | 'lg';
-
-export const sizeMap: Record<Size, number> = {
- xs: 16,
- sm: 24,
- md: 40,
- lg: 64,
-};
-
-export const iconSizeMap: Record<Size, number> = {
- xs: 12,
- sm: 18,
- md: 24,
- lg: 24,
-};
diff --git a/server/sonar-web/src/main/js/design-system/components/buttons/BareButtons.tsx b/server/sonar-web/src/main/js/design-system/components/buttons/BareButtons.tsx
deleted file mode 100644
index 546b71710e7..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/buttons/BareButtons.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../../helpers';
-import { BareButton } from '../../sonar-aligned/components/buttons';
-
-interface CodeViewerExpanderProps {
- direction: 'UP' | 'DOWN';
-}
-
-export const CodeViewerExpander = styled(BareButton)<CodeViewerExpanderProps>`
- ${tw`sw-flex sw-items-center sw-gap-2`}
- ${tw`sw-px-2 sw-py-1`}
- ${tw`sw-code`}
- ${tw`sw-w-full`}
- ${tw`sw-box-border`}
-
- color: var(--echoes-color-text-subdued);
- background-color: ${themeColor('codeLineEllipsis')};
-
- &:hover {
- background-color: ${themeColor('codeLineEllipsisHover')};
- }
-
- border-top: ${(props) =>
- props.direction === 'DOWN' ? themeBorder('default', 'codeLineBorder') : 'none'};
-
- border-bottom: ${(props) =>
- props.direction === 'UP' ? themeBorder('default', 'codeLineBorder') : 'none'};
-`;
-
-export const IssueIndicatorButton = styled(BareButton)`
- color: var(--echoes-color-text-subdued);
- text-decoration: none;
-
- ${tw`sw-whitespace-nowrap`}
-`;
-
-export const DuplicationBlock = styled(BareButton)`
- background-color: ${themeColor('codeLineDuplication')};
- outline: none;
-
- ${tw`sw-block`}
- ${tw`sw-w-1 sw-h-full`}
- ${tw`sw-ml-1/2`}
- ${tw`sw-cursor-pointer`}
-`;
-
-export const LineSCMStyled = styled(BareButton)`
- outline: none;
-
- ${tw`sw-pr-2`}
- ${tw`sw-truncate`}
- ${tw`sw-whitespace-nowrap`}
- ${tw`sw-cursor-pointer`}
- ${tw`sw-w-full sw-h-full`}
-
- &:hover {
- color: var(--echoes-color-text-subdued);
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/buttons/ButtonLink.tsx b/server/sonar-web/src/main/js/design-system/components/buttons/ButtonLink.tsx
deleted file mode 100644
index 7f008c99676..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/buttons/ButtonLink.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../../helpers';
-import { BareButton } from '../../sonar-aligned/components/buttons';
-
-/**
- * @deprecated Use Button from Echoes instead with the `variety` prop set
- * to ButtonVariety.DefaultGhost to have the same look and feel.
- *
- * Some of the props have changed or been renamed:
- * - `blurAfterClick` is now `shouldBlurAfterClick`
- * - `disabled` is now `isDisabled`, note that a Echoes Tooltip won't work
- * on a disabled button, use a text notice or ToggleTip next to the disabled button instead.
- * - `icon` is now replace by `prefix` which works the same way
- * - `preventDefault` is now `shouldPreventDefault`
- * - `stopPropagation` is now `shouldStopPropagation`
- *
- * The button can't be used as a link anymore, and all props related to links have been dropped.
- * Use a real Echoes Link instead.
- *
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3382706231/Button | Migration Guide} for more information.
- */
-export const ButtonLink = styled(BareButton)`
- color: ${themeColor('linkDefault')};
- border-bottom: ${themeBorder('default', 'linkDefault')};
-
- ${tw`sw-font-semibold`}
- ${tw`sw-no-underline`}
-
- &:hover,
- &:focus,
- &:active {
- color: ${themeColor('linkActive')};
- border-bottom: ${themeBorder('default', 'linkDefault')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/buttons/DownloadButton.tsx b/server/sonar-web/src/main/js/design-system/components/buttons/DownloadButton.tsx
deleted file mode 100644
index d1e34b6f0f7..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/buttons/DownloadButton.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { buttonStyle, PrimaryStyle } from '../../sonar-aligned/components/buttons';
-
-export const DownloadButton = styled.a`
- ${buttonStyle}
- ${PrimaryStyle}
- &:hover {
- border-bottom-color: transparent;
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/buttons/WrapperButton.tsx b/server/sonar-web/src/main/js/design-system/components/buttons/WrapperButton.tsx
deleted file mode 100644
index 5485cabe5ac..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/buttons/WrapperButton.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { OPACITY_20_PERCENT, themeColor } from '../../helpers';
-import { Button, ButtonProps } from '../../sonar-aligned/components/buttons';
-
-export const WrapperButton: React.FC<React.PropsWithChildren<ButtonProps>> = styled(Button)`
- --background: none;
- --backgroundHover: none;
- --color: none;
- --focus: ${themeColor('button', OPACITY_20_PERCENT)};
- --border: none;
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/buttons/__tests__/BareButtons-test.tsx b/server/sonar-web/src/main/js/design-system/components/buttons/__tests__/BareButtons-test.tsx
deleted file mode 100644
index 0b1e3647b2e..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/buttons/__tests__/BareButtons-test.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../../helpers/testUtils';
-import { CodeViewerExpander } from '../BareButtons';
-
-it('renders CodeViewerExpander correctly when direction is UP', () => {
- render(<CodeViewerExpander direction="UP">Hello</CodeViewerExpander>);
- const content = screen.getByRole('button', { name: 'Hello' });
- expect(content).toHaveStyle({
- 'border-top': 'none',
- 'border-bottom': '1px solid rgb(221,221,221)',
- });
-});
-
-it('renders CodeViewerExpander correctly when direction is DOWN', () => {
- render(<CodeViewerExpander direction="DOWN">Hello</CodeViewerExpander>);
- const content = screen.getByRole('button', { name: 'Hello' });
- expect(content).toHaveStyle({
- 'border-bottom': 'none',
- 'border-top': '1px solid rgb(221,221,221)',
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/buttons/__tests__/ButtonLink-test.tsx b/server/sonar-web/src/main/js/design-system/components/buttons/__tests__/ButtonLink-test.tsx
deleted file mode 100644
index a36b7633a33..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/buttons/__tests__/ButtonLink-test.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render, screen } from '@testing-library/react';
-import { ButtonLink } from '../ButtonLink';
-
-it('renders ButtonLink correctly', () => {
- render(<ButtonLink>Hello</ButtonLink>);
- const content = screen.getByRole('button', { name: 'Hello' });
- expect(content).toHaveStyle({
- all: 'unset',
- color: 'rgb(93,108,208)',
- 'border-bottom': '1px solid rgb(93,108,208)',
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/buttons/index.ts b/server/sonar-web/src/main/js/design-system/components/buttons/index.ts
deleted file mode 100644
index 72f6032b66d..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/buttons/index.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './BareButtons';
-export * from './ButtonLink';
-export * from './DownloadButton';
-export * from './WrapperButton';
diff --git a/server/sonar-web/src/main/js/design-system/components/clipboard.tsx b/server/sonar-web/src/main/js/design-system/components/clipboard.tsx
deleted file mode 100644
index 45a6b778cd3..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/clipboard.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- Button,
- ButtonIcon,
- ButtonSize,
- ButtonVariety,
- IconCopy,
- Tooltip,
- TooltipProvider,
-} from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import { copy } from 'clipboard';
-import React, { ComponentProps, useCallback, useState } from 'react';
-
-const COPY_SUCCESS_NOTIFICATION_LIFESPAN = 1000;
-
-interface ButtonProps {
- ariaLabel?: string;
- children?: React.ReactNode;
- className?: string;
- copiedLabel?: string;
- copyLabel?: string;
- copyValue: string;
- icon?: React.ReactNode;
-}
-
-export function ClipboardButton(props: ButtonProps) {
- const {
- icon = <IconCopy />,
- className,
- children,
- copyValue,
- ariaLabel,
- copiedLabel = 'Copied',
- copyLabel = 'Copy',
- } = props;
- const [copySuccess, handleCopy] = useCopyClipboardEffect(copyValue);
-
- return (
- <TooltipProvider>
- {/* TODO ^ Remove TooltipProvider after design-system is reintegrated into sonar-web */}
- <Tooltip content={copiedLabel} isOpen={copySuccess}>
- <Button
- aria-label={ariaLabel}
- className={classNames('sw-select-none', className)}
- onClick={handleCopy}
- prefix={icon}
- >
- {children ?? copyLabel}
- </Button>
- </Tooltip>
- </TooltipProvider>
- );
-}
-
-interface IconButtonProps {
- Icon?: ComponentProps<typeof ButtonIcon>['Icon'];
- 'aria-label'?: string;
- className?: string;
- copiedLabel?: string;
- copyLabel?: string;
- copyValue: string;
- discreet?: boolean;
- size?: ButtonSize;
-}
-
-export function ClipboardIconButton(props: IconButtonProps) {
- const {
- className,
- copyValue,
- discreet,
- size = ButtonSize.Medium,
- Icon = IconCopy,
- copiedLabel = 'Copied',
- copyLabel = 'Copy to clipboard',
- } = props;
-
- const [copySuccess, handleCopy] = useCopyClipboardEffect(copyValue);
-
- return (
- <TooltipProvider>
- {/* TODO ^ Remove TooltipProvider after design-system is reintegrated into sonar-web */}
- <ButtonIcon
- Icon={Icon}
- ariaLabel={props['aria-label'] ?? copyLabel}
- className={className}
- onClick={handleCopy}
- size={size}
- tooltipContent={copySuccess ? copiedLabel : copyLabel}
- tooltipOptions={copySuccess ? { isOpen: copySuccess } : undefined}
- variety={discreet ? ButtonVariety.DefaultGhost : ButtonVariety.Default}
- />
- </TooltipProvider>
- );
-}
-
-export function useCopyClipboardEffect(copyValue: string) {
- const [copySuccess, setCopySuccess] = useState(false);
-
- const handleCopy = useCallback(
- ({ currentTarget }: React.MouseEvent<HTMLButtonElement>) => {
- const isSuccess = copy(copyValue) === copyValue;
- setCopySuccess(isSuccess);
-
- if (isSuccess) {
- setTimeout(() => {
- setCopySuccess(false);
- }, COPY_SUCCESS_NOTIFICATION_LIFESPAN);
- }
-
- currentTarget.focus();
- },
- [copyValue],
- );
-
- return [copySuccess, handleCopy] as const;
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/code-line/LineCoverage.tsx b/server/sonar-web/src/main/js/design-system/components/code-line/LineCoverage.tsx
deleted file mode 100644
index 8b7784809f2..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/code-line/LineCoverage.tsx
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import styled from '@emotion/styled';
-import React, { memo } from 'react';
-import tw from 'twin.macro';
-import { PopupPlacement } from '../../helpers/positioning';
-import { themeColor } from '../../helpers/theme';
-import { Tooltip } from '../Tooltip';
-import { LineMeta } from './LineStyles';
-
-interface Props {
- coverageStatus?: 'uncovered' | 'partially-covered' | 'covered';
- lineNumber: number;
- scrollToUncoveredLine?: boolean;
- status: string | undefined;
-}
-
-function LineCoverageFunc({ lineNumber, coverageStatus, status, scrollToUncoveredLine }: Props) {
- const coverageMarker = React.useRef<HTMLTableCellElement>(null);
- React.useEffect(() => {
- if (scrollToUncoveredLine && coverageMarker.current) {
- coverageMarker.current.scrollIntoView({
- behavior: 'smooth',
- block: 'center',
- inline: 'center',
- });
- }
- }, [scrollToUncoveredLine, coverageMarker]);
-
- if (!coverageStatus) {
- return <LineMeta data-line-number={lineNumber} />;
- }
-
- return (
- <Tooltip content={status} placement={PopupPlacement.Bottom}>
- <LineMeta data-line-number={lineNumber} ref={coverageMarker}>
- {coverageStatus === 'covered' && <CoveredBlock aria-label={status} />}
- {coverageStatus === 'uncovered' && <UncoveredBlock aria-label={status} />}
- {coverageStatus === 'partially-covered' && <PartiallyCoveredBlock aria-label={status} />}
- </LineMeta>
- </Tooltip>
- );
-}
-
-export const LineCoverage = memo(LineCoverageFunc);
-
-const CoverageBlock = styled.div`
- ${tw`sw-w-1 sw-h-full`}
- ${tw`sw-ml-1/2`}
-
- &, & svg {
- outline: none;
- }
-`;
-
-const CoveredBlock = styled(CoverageBlock)`
- background-color: ${themeColor('codeLineCovered')};
-`;
-
-const UncoveredBlock = styled(CoverageBlock)`
- background-color: ${themeColor('codeLineUncovered')};
-`;
-
-function PartiallyCoveredBlock(htmlProps: React.HTMLAttributes<HTMLDivElement>) {
- const theme = useTheme();
- return (
- <CoverageBlock {...htmlProps}>
- <svg fill="none" viewBox="0 0 4 18" xmlns="http://www.w3.org/2000/svg">
- <rect fill={themeColor('codeLinePartiallyCoveredA')({ theme })} height="18" width="4" />
- <path
- clipRule="evenodd"
- d="M0 0L4 3V6L0 3V0ZM0 6L4 9V12L0 9V6ZM4 15L0 12V15L4 18V15Z"
- fill={themeColor('codeLinePartiallyCoveredB')({ theme })}
- fillRule="evenodd"
- />
- </svg>
- </CoverageBlock>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/code-line/LineFinding.tsx b/server/sonar-web/src/main/js/design-system/components/code-line/LineFinding.tsx
deleted file mode 100644
index e78688e9abd..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/code-line/LineFinding.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { forwardRef, Ref } from 'react';
-import tw from 'twin.macro';
-import { themeBorder, themeColor, themeContrast, themeShadow } from '../../helpers/theme';
-import { BareButton } from '../../sonar-aligned/components/buttons';
-
-interface Props {
- as?: React.ElementType;
- className?: string;
- getFixButton?: React.ReactNode;
- issueKey: string;
- message: React.ReactNode;
- onIssueSelect?: (issueKey: string) => void;
- selected?: boolean;
-}
-
-function LineFindingFunc(
- { as, getFixButton, message, issueKey, selected = true, className, onIssueSelect }: Props,
- ref: Ref<HTMLButtonElement>,
-) {
- return selected ? (
- <LineFindingStyled
- as="div"
- className={className}
- data-issue={issueKey}
- ref={ref}
- selected={selected}
- >
- {onIssueSelect ? (
- <BareButton
- onClick={() => {
- onIssueSelect(issueKey);
- }}
- >
- {message}
- </BareButton>
- ) : (
- message
- )}
- {getFixButton}
- </LineFindingStyled>
- ) : (
- <LineFindingStyled
- as={as}
- className={className}
- data-issue={issueKey}
- onClick={() => {
- if (onIssueSelect) {
- onIssueSelect(issueKey);
- }
- }}
- ref={ref}
- selected={selected}
- >
- {message}
- </LineFindingStyled>
- );
-}
-
-export const LineFinding = forwardRef<HTMLElement, Props>(LineFindingFunc);
-
-const LineFindingStyled = styled(BareButton)<{ selected: boolean }>`
- ${tw`sw-flex sw-gap-2 sw-items-center`}
- ${tw`sw-my-3 sw-mx-1`}
- ${tw`sw-rounded-1`}
- ${tw`sw-px-3`}
- ${tw`sw-w-full`}
- ${tw`sw-box-border`}
- ${(props) => (props.selected ? tw`sw-py-3` : tw`sw-py-2`)};
- ${(props) => (props.selected ? tw`sw-typo-lg-semibold` : tw`sw-typo-default`)};
- ${(props) => (props.selected ? tw`sw-cursor-default` : tw`sw-cursor-pointer`)};
-
- border: ${(props) =>
- props.selected
- ? themeBorder('default', 'issueBoxSelectedBorder')
- : themeBorder('default', 'issueBoxBorder')};
- color: ${themeContrast('pageBlock')};
- word-break: break-word;
- background-color: ${themeColor('pageBlock')};
-
- :hover {
- box-shadow: ${themeShadow('sm')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/code-line/LineIssuePointer.tsx b/server/sonar-web/src/main/js/design-system/components/code-line/LineIssuePointer.tsx
deleted file mode 100644
index e5eb954c038..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/code-line/LineIssuePointer.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { createRef, RefObject, useEffect, useState } from 'react';
-import tw from 'twin.macro';
-import { themeColor } from '../../helpers/theme';
-
-const POINTER_HANDLE_HEIGHT_OFFSET = 2;
-const POINTER_HANDLE_MAX_HEIGHT = 10;
-
-interface Props {
- issueFindingRef?: RefObject<HTMLDivElement>;
-}
-
-export function LineIssuePointer({ issueFindingRef }: Props) {
- const [distance, setDistance] = useState(0);
- const pointerRef = createRef<HTMLDivElement>();
-
- useEffect(() => {
- if (pointerRef.current && issueFindingRef?.current) {
- setDistance(
- issueFindingRef.current.getBoundingClientRect().top -
- pointerRef.current.getBoundingClientRect().bottom,
- );
- }
- }, [pointerRef, issueFindingRef]);
-
- // Keep only the pointer head as reference for future calculations
- if (distance < POINTER_HANDLE_HEIGHT_OFFSET || distance > POINTER_HANDLE_MAX_HEIGHT) {
- return <EmptyIssuePointer data-testid="empty-issue-pointer" ref={pointerRef} />;
- }
-
- return <IssuePointer data-testid="issue-pointer" distance={distance} ref={pointerRef} />;
-}
-
-const EmptyIssuePointer = styled.div`
- bottom: -0.325rem;
- left: 50%;
- width: 0.3125rem;
- height: 0.3125rem;
- border: 0.125rem solid transparent;
- transform: translate(-50%, 0);
-
- ${tw`sw-block sw-absolute sw-rounded-2`};
-`;
-
-const IssuePointer = styled(EmptyIssuePointer)<{ distance: number }>`
- background-color: ${themeColor('codeLineIssueSquiggle')};
- border-color: ${themeColor('codeLineIssuePointerBorder')};
-
- &::after {
- position: absolute;
- top: 5px;
- left: 2px;
- display: block;
- width: 1px;
- height: ${({ distance }) => `${distance + POINTER_HANDLE_HEIGHT_OFFSET}px`};
- background-color: ${themeColor('codeLineIssueSquiggle')};
- content: '';
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/code-line/LineIssuesIndicatorIcon.tsx b/server/sonar-web/src/main/js/design-system/components/code-line/LineIssuesIndicatorIcon.tsx
deleted file mode 100644
index 80403bab3ee..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/code-line/LineIssuesIndicatorIcon.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { memo } from 'react';
-import tw from 'twin.macro';
-import { DotFillIcon } from '../icons';
-
-interface Props {
- issuesCount: number;
-}
-
-function LineIssueIndicatorIconFunc({ issuesCount }: Readonly<Props>) {
- return (
- <>
- <DotFillIcon />
- {issuesCount > 1 && <IssueIndicatorCounter>{issuesCount}</IssueIndicatorCounter>}
- </>
- );
-}
-
-export const LineIssuesIndicatorIcon = memo(LineIssueIndicatorIconFunc);
-
-const IssueIndicatorCounter = styled.span`
- font-size: 0.5rem;
- line-height: 0.5rem;
-
- ${tw`sw-ml-1/2`}
- ${tw`sw-align-top`}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/code-line/LineMarker.tsx b/server/sonar-web/src/main/js/design-system/components/code-line/LineMarker.tsx
deleted file mode 100644
index 02993c531a5..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/code-line/LineMarker.tsx
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { forwardRef, Ref, useCallback, useRef } from 'react';
-import tw from 'twin.macro';
-import { themeColor, themeContrast } from '../../helpers/theme';
-import { LocationMarker } from '../LocationMarker';
-
-interface Props {
- hideLocationIndex?: boolean;
- index: number;
- leading?: boolean;
- message?: string;
- onLocationSelect?: (index: number) => void;
- selected: boolean;
-}
-
-function LineMarkerFunc(
- { hideLocationIndex, index, leading, message, onLocationSelect, selected }: Props,
- ref: Ref<HTMLElement>,
-) {
- const element = useRef<HTMLDivElement | null>(null);
- const elementMessage = useRef<HTMLDivElement | null>(null);
-
- const handleClick = useCallback(() => {
- onLocationSelect?.(index);
- }, [index, onLocationSelect]);
-
- return (
- <Wrapper className={classNames({ leading })} ref={element}>
- <LocationMarker
- onClick={handleClick}
- ref={ref as React.RefObject<HTMLDivElement>}
- selected={selected}
- text={hideLocationIndex ? undefined : index + 1}
- />
- {message && <Message ref={elementMessage}>{message}</Message>}
- </Wrapper>
- );
-}
-
-const Message = styled.div`
- ${tw`sw-absolute`}
- ${tw`sw-typo-default`}
- ${tw`sw-rounded-1/2`}
- ${tw`sw-px-1`}
- ${tw`sw-left-0`}
-
- z-index: 1;
- bottom: calc(100% + 0.25rem);
- width: max-content;
- max-width: var(--max-width);
- color: ${themeContrast('codeLineIssueMessageTooltip')};
- background-color: ${themeColor('codeLineIssueMessageTooltip')};
- visibility: hidden;
-
- &.message-right {
- ${tw`sw-left-auto`}
- ${tw`sw-right-0`}
- }
-`;
-
-const Wrapper = styled.div`
- ${tw`sw-relative`}
- ${tw`sw-inline-block`}
- ${tw`sw-align-top`}
-
- &:not(:first-of-type) {
- ${tw`sw-ml-1`}
- }
-
- &.leading {
- margin-left: calc(var(--width) - 0.25rem);
- }
-
- &:hover ${Message} {
- visibility: visible;
- }
-`;
-
-export const LineMarker = forwardRef<HTMLElement, Props>(LineMarkerFunc);
diff --git a/server/sonar-web/src/main/js/design-system/components/code-line/LineNumber.tsx b/server/sonar-web/src/main/js/design-system/components/code-line/LineNumber.tsx
deleted file mode 100644
index 0a414118774..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/code-line/LineNumber.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { memo, useState } from 'react';
-import tw from 'twin.macro';
-import { PopupPlacement, PopupZLevel } from '../../helpers/positioning';
-import { DropdownToggler } from '../DropdownToggler';
-import { LineMeta } from './LineStyles';
-
-interface Props {
- ariaLabel: string;
- displayOptions: boolean;
- firstLineNumber: number;
- lineNumber: number;
- popup: React.ReactNode;
-}
-
-const FILE_TOP_THRESHOLD = 10;
-
-function LineNumberFunc({ firstLineNumber, lineNumber, popup, displayOptions, ariaLabel }: Props) {
- const [isOpen, setIsOpen] = useState<boolean>(false);
-
- const hasLineNumber = Boolean(lineNumber);
- const isFileTop = lineNumber - FILE_TOP_THRESHOLD < firstLineNumber;
-
- if (!hasLineNumber) {
- return <LineMeta className="sw-pl-2" />;
- }
-
- return (
- <LineMeta className="sw-pl-2" data-line-number={lineNumber}>
- {displayOptions ? (
- <DropdownToggler
- aria-labelledby={`line-number-trigger-${lineNumber}`}
- id={`line-number-dropdown-${lineNumber}`}
- onRequestClose={() => {
- setIsOpen(false);
- }}
- open={isOpen}
- overlay={popup}
- placement={isFileTop ? PopupPlacement.Bottom : PopupPlacement.Top}
- zLevel={PopupZLevel.Global}
- >
- <LineNumberStyled
- aria-controls={`line-number-dropdown-${lineNumber}`}
- aria-expanded={isOpen}
- aria-haspopup="menu"
- aria-label={ariaLabel}
- id={`line-number-trigger-${lineNumber}`}
- onClick={() => {
- setIsOpen(true);
- }}
- role="button"
- tabIndex={0}
- >
- {lineNumber}
- </LineNumberStyled>
- </DropdownToggler>
- ) : (
- lineNumber
- )}
- </LineMeta>
- );
-}
-
-export const LineNumber = memo(LineNumberFunc);
-
-const LineNumberStyled = styled.div`
- outline: none;
-
- ${tw`sw-pr-2`}
- ${tw`sw-cursor-pointer`}
-
- &:hover {
- color: var(--echoes-color-text-bold);
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/code-line/LineStyles.tsx b/server/sonar-web/src/main/js/design-system/components/code-line/LineStyles.tsx
deleted file mode 100644
index f1c99be7e9b..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/code-line/LineStyles.tsx
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeBorder, themeColor, themeContrast } from '../../helpers/theme';
-import { BareButton } from '../../sonar-aligned';
-
-export const SCMHighlight = styled.h6`
- color: ${themeColor('tooltipHighlight')};
-
- ${tw`sw-typo-semibold`};
- ${tw`sw-text-right`};
- ${tw`sw-min-w-[6rem]`};
- ${tw`sw-mr-4`};
- ${tw`sw-my-1`};
-`;
-
-export const LineSCMStyledDiv = styled.div`
- outline: none;
-
- ${tw`sw-pr-2`}
- ${tw`sw-truncate`}
- ${tw`sw-whitespace-nowrap`}
- ${tw`sw-cursor-pointer`}
- ${tw`sw-w-full sw-h-full`}
-
- &:hover {
- color: var(--echoes-color-text-bold);
- }
-`;
-
-export const DuplicationHighlight = styled.h6`
- color: ${themeColor('tooltipHighlight')};
-
- ${tw`sw-mb-2 sw-font-semibold`};
-`;
-
-export const LineStyled = styled.tr`
- display: grid;
- grid-template-rows: auto;
- grid-template-columns: var(--columns);
- align-items: center;
-
- ${tw`sw-code`}
-`;
-LineStyled.displayName = 'LineStyled';
-
-export const LineMeta = styled.td`
- color: var(--echoes-color-text-subdued);
- background-color: var(--line-background);
- outline: none;
-
- ${tw`sw-w-full sw-h-full`}
- ${tw`sw-box-border`}
- ${tw`sw-select-none`}
-
- ${LineStyled}:hover & {
- background-color: ${themeColor('codeLineHover')};
- }
-`;
-
-export const LineCodePreFormatted = styled.pre`
- position: relative;
- white-space: pre-wrap;
- overflow-wrap: anywhere;
- tab-size: 4;
-`;
-
-export const LineCodeLayer = styled.div`
- grid-row: 1;
- grid-column: 1;
-`;
-
-export const LineCodeLayers = styled.td`
- position: relative;
- display: grid;
- height: 100%;
- background-color: var(--line-background);
- border-left: ${themeBorder('default', 'codeLineBorder')};
-
- ${LineStyled}:hover & {
- background-color: ${themeColor('codeLineHover')};
- }
-`;
-
-export const NewCodeUnderline = styled(LineCodeLayer)`
- background-color: ${themeColor('codeLineNewCodeUnderline')};
-`;
-
-export const CoveredUnderline = styled(LineCodeLayer)`
- background-color: ${themeColor('codeLineCoveredUnderline')};
-`;
-
-export const UncoveredUnderline = styled(LineCodeLayer)`
- background-color: ${themeColor('codeLineUncoveredUnderline')};
-`;
-
-export const UnderlineLabels = styled.div<{ transparentBackground?: boolean }>`
- ${tw`sw-absolute`}
- ${tw`sw-flex sw-gap-1`}
- ${tw`sw-px-1`}
- ${tw`sw-right-0`}
-
-
- height: 1.125rem;
- margin-top: -1.125rem;
- background-color: ${({ transparentBackground, theme }) =>
- themeColor(transparentBackground ? 'transparent' : 'codeLine')({ theme })};
-`;
-
-export const UnderlineLabel = styled.span`
- ${tw`sw-rounded-t-1`}
- ${tw`sw-px-1`}
-`;
-
-export const NewCodeUnderlineLabel = styled(UnderlineLabel)`
- color: ${themeContrast('codeLineNewCodeUnderline')};
- background-color: ${themeColor('codeLineNewCodeUnderline')};
-`;
-
-export const CoveredUnderlineLabel = styled(UnderlineLabel)`
- color: ${themeContrast('codeLineCoveredUnderline')};
- background-color: ${themeColor('codeLineCoveredUnderline')};
-`;
-
-export const UncoveredUnderlineLabel = styled(UnderlineLabel)`
- color: ${themeContrast('codeLineUncoveredUnderline')};
- background-color: ${themeColor('codeLineUncoveredUnderline')};
-`;
-
-export const LineCodeEllipsisStyled = styled(BareButton)`
- ${tw`sw-flex sw-items-center sw-gap-2`}
- ${tw`sw-px-2 sw-py-1`}
- ${tw`sw-code`}
- ${tw`sw-w-full`}
- ${tw`sw-box-border`}
-
- border-top: ${themeBorder('default', 'codeLineBorder')};
- border-bottom: ${themeBorder('default', 'codeLineBorder')};
-
- color: var(--echoes-color-text-subdued);
- background-color: ${themeColor('codeLineEllipsis')};
-
- &:hover {
- background-color: ${themeColor('codeLineEllipsisHover')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/code-line/LineToken.tsx b/server/sonar-web/src/main/js/design-system/components/code-line/LineToken.tsx
deleted file mode 100644
index 5e40aecd9c1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/code-line/LineToken.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { ReactNode, RefObject } from 'react';
-import tw from 'twin.macro';
-import { themeColor } from '../../helpers/theme';
-import { LineIssuePointer } from './LineIssuePointer';
-
-export interface TokenModifiers {
- isHighlighted?: boolean;
- isLocation?: boolean;
- isSelected?: boolean;
- isUnderlined?: boolean;
-}
-
-interface Props extends TokenModifiers {
- children: ReactNode;
- className?: string;
- hasMarker?: boolean;
- issueFindingRef?: RefObject<HTMLDivElement>;
-}
-
-export function LineToken(props: Props) {
- const { children, className, hasMarker, issueFindingRef, ...modifiers } = props;
-
- return (
- <TokenStyled
- className={classNames(className, {
- 'issue-underline': modifiers.isUnderlined,
- 'issue-location': modifiers.isLocation,
- highlighted: modifiers.isHighlighted,
- selected: modifiers.isSelected,
- 'has-marker': hasMarker,
- })}
- >
- <>{children}</>
- {modifiers.isUnderlined && <LineIssuePointer issueFindingRef={issueFindingRef} />}
- </TokenStyled>
- );
-}
-
-const TokenStyled = styled.span`
- display: inline-block;
-
- &.sym {
- ${tw`sw-cursor-pointer`}
- }
-
- &.sym.highlighted {
- background-color: ${themeColor('codeLineLocationHighlighted')};
- transition: background-color 0.3s;
- }
-
- &.issue-underline {
- position: relative;
- z-index: 1;
- text-decoration: underline ${themeColor('codeLineIssueSquiggle')};
- text-decoration: underline ${themeColor('codeLineIssueSquiggle')} wavy;
- text-decoration-thickness: 2px;
- text-decoration-skip-ink: none;
- }
-
- &.issue-location {
- line-height: 1.125rem;
- background-color: ${themeColor('codeLineIssueLocation')};
- transition: background-color 0.3s ease;
- }
-
- &.issue-location.selected {
- background-color: ${themeColor('codeLineIssueLocationSelected')};
- }
-
- &.issue-location.has-marker {
- ${tw`sw-pl-1`}
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/code-line/LineWrapper.tsx b/server/sonar-web/src/main/js/design-system/components/code-line/LineWrapper.tsx
deleted file mode 100644
index 0bc51610e1b..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/code-line/LineWrapper.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { HTMLAttributes } from 'react';
-import { themeColor } from '../../helpers/theme';
-import { LineStyled } from './LineStyles';
-
-interface Props extends HTMLAttributes<HTMLDivElement> {
- displayCoverage: boolean;
- displaySCM: boolean;
- duplicationsCount: number;
- highlighted: boolean;
-}
-
-export function LineWrapper(props: Props) {
- const { displayCoverage, displaySCM, duplicationsCount, highlighted, ...htmlProps } = props;
- const theme = useTheme();
- const SCMCol = displaySCM ? '50px ' : '';
- const nbGutters = duplicationsCount + (displayCoverage ? 1 : 0);
- const gutterCols = nbGutters > 0 ? `repeat(${nbGutters}, 6px) ` : '';
- return (
- <LineStyled
- style={{
- '--columns': `44px ${SCMCol}26px ${gutterCols}1fr`,
- '--line-background': highlighted
- ? themeColor('codeLineHighlighted')({ theme })
- : themeColor('codeLine')({ theme }),
- }}
- {...htmlProps}
- />
- );
-}
-
-export function SuggestedLineWrapper(props: Readonly<HTMLAttributes<HTMLDivElement>>) {
- const theme = useTheme();
- return (
- <LineStyled
- as="div"
- style={{
- '--columns': `44px 26px 1rem 1fr`,
- '--line-background': themeColor('codeLine')({ theme }),
- }}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/AddNewIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/AddNewIcon.tsx
deleted file mode 100644
index 83b78dea6b7..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/AddNewIcon.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconPlus from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function AddNewIcon({ fill = 'currentColor', ...iconProps }: Readonly<IconProps>) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M8 0c-.55228 0-1 .44771-1 1v6H1c-.55229 0-1 .44771-1 1 0 .55228.44771 1 1 1h6v6c0 .5523.44772 1 1 1 .55229 0 1-.4477 1-1V9h6c.5523 0 1-.44771 1-1 0-.55228-.4477-1-1-1H9V1c0-.55229-.44771-1-1-1Z"
- fill={themeColor(fill)({ theme })}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/BranchIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/BranchIcon.tsx
deleted file mode 100644
index 579b6595d80..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/BranchIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { GitBranchIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconGitBranch from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const BranchIcon = OcticonHoc(GitBranchIcon, 'BranchIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/BugIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/BugIcon.tsx
deleted file mode 100644
index d4818cfb8e5..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/BugIcon.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconBug from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function BugIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <path
- d="M10.09,1.88A2.86,2.86,0,0,0,8,1a2.87,2.87,0,0,0-2.11.87A2.93,2.93,0,0,0,5,4h6A2.93,2.93,0,0,0,10.09,1.88Z"
- fill={themeColor(fill)({ theme })}
- />
- <path
- d="M14.54,9H13V5.6L14.3,4.42a.5.5,0,0,0,0-.71.49.49,0,0,0-.7,0L12.17,5H3.82L2.34,3.66a.5.5,0,0,0-.67.74L2.94,5.55V9H1.46a.5.5,0,0,0,0,1H3a5.2,5.2,0,0,0,1.05,2.32l-2,1.81a.5.5,0,1,0,.67.74l2-1.82A4.62,4.62,0,0,0,7,14.1V8A1,1,0,0,1,8,7a.94.94,0,0,1,1,.9v6.17A4.55,4.55,0,0,0,11.18,13l2,1.83a.51.51,0,0,0,.33.13.48.48,0,0,0,.37-.17.49.49,0,0,0,0-.7l-2-1.8a5.34,5.34,0,0,0,1-2.29h1.64a.5.5,0,0,0,0-1Z"
- fill={themeColor(fill)({ theme })}
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/CalendarIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/CalendarIcon.tsx
deleted file mode 100644
index 1b600d8b42b..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/CalendarIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CalendarIcon as Octicon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconCalendar from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const CalendarIcon = OcticonHoc(Octicon);
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/CheckIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/CheckIcon.tsx
deleted file mode 100644
index bde5e4f4698..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/CheckIcon.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconCheck from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function CheckIcon({ fill = 'iconCheck', ...iconProps }: IconProps) {
- const theme = useTheme();
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M11.6634 5.47789c.2884.29737.2811.77218-.0163 1.06054L7.52211 10.5384c-.29414.2852-.76273.2816-1.05244-.0081l-2-1.99997c-.29289-.29289-.29289-.76777 0-1.06066s.76777-.29289 1.06066 0L7.0081 8.94744l3.5948-3.48586c.2974-.28836.7722-.28105 1.0605.01631Z"
- fill={themeColor(fill)({ theme })}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/ChevronDownIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/ChevronDownIcon.tsx
deleted file mode 100644
index 208219afd0c..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/ChevronDownIcon.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconChevronDown from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function ChevronDownIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
- const theme = useTheme();
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M12.7236 5.83199c.1953.19527.1953.51185 0 .70711l-4.18499 4.185c-.19526.1953-.51184.1953-.7071 0l-4.18503-4.185c-.19527-.19526-.19527-.51184 0-.70711.19526-.19526.51184-.19526.7071 0l3.83148 3.83148 3.83144-3.83148c.1953-.19526.5119-.19526.7071 0Z"
- fill={themeColor(fill)({ theme })}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/ChevronLeftIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/ChevronLeftIcon.tsx
deleted file mode 100644
index 38c21ef2462..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/ChevronLeftIcon.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-export function ChevronLeftIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
- const theme = useTheme();
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M10.16801 12.7236c-.19527.1953-.51185.1953-.70711 0l-4.185-4.18499c-.1953-.19526-.1953-.51184 0-.7071l4.185-4.18503c.19526-.19527.51184-.19527.70711 0 .19526.19526.19526.51184 0 .7071L6.33653 8.18506l3.83148 3.83144c.19526.1953.19526.5119 0 .7071Z"
- fill={themeColor(fill)({ theme })}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/ChevronRightIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/ChevronRightIcon.tsx
deleted file mode 100644
index eb09bb6fd29..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/ChevronRightIcon.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-export function ChevronRightIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
- const theme = useTheme();
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M5.83199 3.2764c.19527-.1953.51185-.1953.70711 0l4.185 4.18499c.1953.19526.1953.51184 0 .7071l-4.185 4.18503c-.19526.19527-.51184.19527-.70711 0-.19526-.19526-.19526-.51184 0-.7071l3.83148-3.83148L5.83199 3.9835c-.19526-.1953-.19526-.5119 0-.7071Z"
- fill={themeColor(fill)({ theme })}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/ClockIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/ClockIcon.tsx
deleted file mode 100644
index 6c8a8231438..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/ClockIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ClockIcon as OcticonClockIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconClock from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const ClockIcon = OcticonHoc(OcticonClockIcon, 'ClockIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/CloseIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/CloseIcon.tsx
deleted file mode 100644
index 2c0daebf409..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/CloseIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { XIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconX from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const CloseIcon = OcticonHoc(XIcon, 'CloseIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/CodeEllipsisIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/CodeEllipsisIcon.tsx
deleted file mode 100644
index 481419392e0..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/CodeEllipsisIcon.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { IconProps } from '../../components/icons/Icon';
-import { UnfoldDownIcon } from './UnfoldDownIcon';
-import { UnfoldIcon } from './UnfoldIcon';
-import { UnfoldUpIcon } from './UnfoldUpIcon';
-
-export const enum CodeEllipsisDirection {
- Up = 'up',
- Down = 'down',
- Middle = 'middle',
-}
-
-interface Props extends IconProps {
- direction: CodeEllipsisDirection;
-}
-
-export function CodeEllipsisIcon({ direction, ...props }: Readonly<Props>) {
- if (direction === CodeEllipsisDirection.Up) {
- return <UnfoldUpIcon {...props} />;
- } else if (direction === CodeEllipsisDirection.Down) {
- return <UnfoldDownIcon {...props} />;
- }
- return <UnfoldIcon {...props} />;
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/CodeSmellIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/CodeSmellIcon.tsx
deleted file mode 100644
index e68cc4113e3..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/CodeSmellIcon.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconCodeSmell from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function CodeSmellIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <path
- d="M8,15.1a7,7,0,1,0-7-7A7,7,0,0,0,8,15.1Zm.74-8.9,1.46-2.52a.29.29,0,0,1,.25-.14.3.3,0,0,1,.15,0,5.26,5.26,0,0,1,2.61,4.53.28.28,0,0,1-.29.29H10a.28.28,0,0,1-.29-.29,1.78,1.78,0,0,0-.88-1.51A.29.29,0,0,1,8.75,6.2Zm.11,3.44A.23.23,0,0,1,9,9.6a.29.29,0,0,1,.25.14l1.46,2.52a.18.18,0,0,1,0,.13.3.3,0,0,1-.15.27,5.3,5.3,0,0,1-5.23,0,.3.3,0,0,1-.1-.4L6.73,9.74A.29.29,0,0,1,7,9.6a.23.23,0,0,1,.14,0A1.79,1.79,0,0,0,8.86,9.64ZM5.33,3.59a.3.3,0,0,1,.41.1L7.2,6.21a.29.29,0,0,1-.1.4,1.79,1.79,0,0,0-.87,1.51.28.28,0,0,1-.29.29H3a.32.32,0,0,1-.32-.29A5.26,5.26,0,0,1,5.33,3.59Z"
- fill={themeColor(fill)({ theme })}
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/CollapseIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/CollapseIcon.tsx
deleted file mode 100644
index 5040cc57804..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/CollapseIcon.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconCollapse from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function CollapseIcon({ fill = 'currentColor', ...iconProps }: Readonly<IconProps>) {
- const theme = useTheme();
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M2.82364 9h4.146a.25.25 0 0 1 .25.25v4.146a.2499.2499 0 0 1-.04199.1391.2503.2503 0 0 1-.11227.0923.24953.24953 0 0 1-.14463.0142.24976.24976 0 0 1-.12811-.0686l-1.543-1.543-2.98844 2.9884a.75009.75009 0 0 1-.52453.2012.75044.75044 0 0 1-.5171-.2196.75.75 0 0 1-.01837-1.0416L4.18964 10.97l-1.543-1.543a.24997.24997 0 0 1-.05439-.27273A.24995.24995 0 0 1 2.82364 9ZM13.396 7.24258H9.24996a.25.25 0 0 1-.25-.25v-4.146a.25.25 0 0 1 .427-.177l1.54304 1.543 3.0112-3.01129a.74997.74997 0 0 1 1.0416.01838.75042.75042 0 0 1 .2196.5171.75005.75005 0 0 1-.2012.52452L12.03 5.27258l1.543 1.543a.2505.2505 0 0 1 .0686.12811.25036.25036 0 0 1-.0142.14463.2503.2503 0 0 1-.0923.11227.2499.2499 0 0 1-.1391.04199Z"
- fill={themeColor(fill)({ theme })}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/CommentIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/CommentIcon.tsx
deleted file mode 100644
index f47270b3eba..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/CommentIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CommentIcon as OcticonCommentIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconComment from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const CommentIcon = OcticonHoc(OcticonCommentIcon, 'CommentIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/CopyIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/CopyIcon.tsx
deleted file mode 100644
index 700f8612465..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/CopyIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CopyIcon as OcticonCopyIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconCopy from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const CopyIcon = OcticonHoc(OcticonCopyIcon, 'CopyIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/DirectoryIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/DirectoryIcon.tsx
deleted file mode 100644
index c3dcaed09df..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/DirectoryIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FileDirectoryIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconDirectory from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const DirectoryIcon = OcticonHoc(FileDirectoryIcon, 'DirectoryIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/DotFillIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/DotFillIcon.tsx
deleted file mode 100644
index de58443fb59..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/DotFillIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { DotFillIcon as OcticonDotFillIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconDot with the isFilled prop from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const DotFillIcon = OcticonHoc(OcticonDotFillIcon, 'DotFillIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/DraggableIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/DraggableIcon.tsx
deleted file mode 100644
index 07c38690112..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/DraggableIcon.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import styled from '@emotion/styled';
-import { themeColor, themeContrast } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-export function DraggableIcon({
- fill = 'currentColor',
- ...iconProps
-}: IconProps & { x: number; y: number }) {
- const theme = useTheme();
- const fillColor = themeColor(fill)({ theme });
- const innerFillColor = themeContrast(fill)({ theme });
-
- return (
- <StyledCustomIcon {...iconProps}>
- <circle cx="8" cy="8" fill={fillColor} r="8" />
- <rect fill={innerFillColor} height="7" width="1" x="6" y="5" />
- <rect fill={innerFillColor} height="7" width="1" x="9" y="5" />
- </StyledCustomIcon>
- );
-}
-
-const StyledCustomIcon = styled(CustomIcon)`
- cursor: ew-resize;
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/ExecutionFlowIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/ExecutionFlowIcon.tsx
deleted file mode 100644
index 6a3a37d101e..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/ExecutionFlowIcon.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-export function ExecutionFlowIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
- const theme = useTheme();
- const fillColor = themeColor(fill)({ theme });
-
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M8.8928 7.89282C9.10919 7.67643 9.23076 7.38294 9.23076 7.07692C9.23076 6.7709 9.10919 6.47742 8.8928 6.26103C8.67642 6.04464 8.38293 5.92308 8.07691 5.92308C7.77089 5.92308 7.47741 6.04464 7.26102 6.26103C7.04463 6.47742 6.92307 6.7709 6.92307 7.07692C6.92307 7.38294 7.04463 7.67643 7.26102 7.89282C7.47741 8.1092 7.77089 8.23077 8.07691 8.23077C8.38293 8.23077 8.67642 8.1092 8.8928 7.89282ZM8.8928 3.96974C9.10919 3.75335 9.23076 3.45987 9.23076 3.15385C9.23076 2.84783 9.10919 2.55434 8.8928 2.33795C8.67642 2.12157 8.38293 2 8.07691 2C7.77089 2 7.47741 2.12157 7.26102 2.33795C7.04463 2.55434 6.92307 2.84783 6.92307 3.15385C6.92307 3.45987 7.04463 3.75335 7.26102 3.96974C7.47741 4.18613 7.77089 4.30769 8.07691 4.30769C8.38293 4.30769 8.67642 4.18613 8.8928 3.96974ZM9.54553 13.3917C9.15603 13.7812 8.62776 14 8.07692 14C7.52609 14 6.99782 13.7812 6.60832 13.3917C6.21882 13.0022 6 12.4739 6 11.9231C6 11.3722 6.21882 10.844 6.60832 10.4545C6.99782 10.065 7.52609 9.84615 8.07692 9.84615C8.62776 9.84615 9.15603 10.065 9.54553 10.4545C9.93503 10.844 10.1538 11.3722 10.1538 11.9231C10.1538 12.4739 9.93503 13.0022 9.54553 13.3917ZM7.58739 11.4335C7.71722 11.3037 7.89331 11.2308 8.07692 11.2308C8.26053 11.2308 8.43663 11.3037 8.56646 11.4335C8.69629 11.5634 8.76923 11.7395 8.76923 11.9231C8.76923 12.1067 8.69629 12.2828 8.56646 12.4126C8.43663 12.5424 8.26053 12.6154 8.07692 12.6154C7.89331 12.6154 7.71722 12.5424 7.58739 12.4126C7.45756 12.2828 7.38462 12.1067 7.38462 11.9231C7.38462 11.7395 7.45756 11.5634 7.58739 11.4335Z"
- fill={fillColor}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/ExpandIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/ExpandIcon.tsx
deleted file mode 100644
index de74960e9e9..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/ExpandIcon.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconExpand from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function ExpandIcon({ fill = 'currentColor', ...iconProps }: Readonly<IconProps>) {
- const theme = useTheme();
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M10.604 1h4.146a.24994.24994 0 0 1 .25.25v4.146a.24966.24966 0 0 1-.042.13913.24968.24968 0 0 1-.1122.09226.25028.25028 0 0 1-.1447.01423.25034.25034 0 0 1-.1281-.06862L13.03 4.03l-2.9884 2.98838a.75002.75002 0 0 1-1.06001-1.06L11.97 2.97l-1.543-1.543a.25047.25047 0 0 1-.0686-.1281.25035.25035 0 0 1 .0142-.14463.25027.25027 0 0 1 .0923-.11228A.25.25 0 0 1 10.604 1ZM5.39608 14.9813h-4.146a.2499.2499 0 0 1-.17677-.0732.25007.25007 0 0 1-.07323-.1768v-4.146a.25001.25001 0 0 1 .04199-.1391.25037.25037 0 0 1 .11228-.0923.24953.24953 0 0 1 .14463-.0142.24973.24973 0 0 1 .1281.0686l1.543 1.543L5.98132 8.94a.75.75 0 0 1 1.06 1.06l-3.01124 3.0113 1.543 1.543a.24987.24987 0 0 1 .06862.1281.24996.24996 0 0 1-.10649.2569.24964.24964 0 0 1-.13913.042Z"
- fill={themeColor(fill)({ theme })}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/FileIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/FileIcon.tsx
deleted file mode 100644
index fb2a67c26e5..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/FileIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FileIcon as OcticonFileIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconFile from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const FileIcon = OcticonHoc(OcticonFileIcon, 'FileIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/FilterIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/FilterIcon.tsx
deleted file mode 100644
index 40a4701b8a6..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/FilterIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FilterIcon as Icon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconFilter from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const FilterIcon = OcticonHoc(Icon, 'FilterIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/FlagErrorIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/FlagErrorIcon.tsx
deleted file mode 100644
index ec53a97d751..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/FlagErrorIcon.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconError from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function FlagErrorIcon({ fill = 'iconError', ...iconProps }: IconProps) {
- const theme = useTheme();
- return (
- <CustomIcon {...iconProps}>
- <path
- d="M7.364 1.707a1 1 0 0 1 1.414 0l5.657 5.657a1 1 0 0 1 0 1.414l-5.657 5.657a1 1 0 0 1-1.414 0L1.707 8.778a1 1 0 0 1 0-1.414l5.657-5.657ZM7 5a1 1 0 0 1 2 0v3a1 1 0 1 1-2 0V5Zm1 5a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"
- style={{ fill: themeColor(fill)({ theme }) }}
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/FlagInfoIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/FlagInfoIcon.tsx
deleted file mode 100644
index 04bb2a9cedd..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/FlagInfoIcon.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconInfo from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function FlagInfoIcon({ fill = 'iconInfo', ...iconProps }: IconProps) {
- const theme = useTheme();
- return (
- <CustomIcon {...iconProps}>
- <path
- d="M14 8A6 6 0 1 1 2 8a6 6 0 0 1 12 0Zm-5 3a1 1 0 1 1-2 0V8a1 1 0 0 1 2 0v3ZM8 6a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"
- style={{ fill: themeColor(fill)({ theme }) }}
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/FlagSuccessIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/FlagSuccessIcon.tsx
deleted file mode 100644
index 06a597a4983..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/FlagSuccessIcon.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconCheckCircle from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function FlagSuccessIcon({ fill = 'iconSuccess', ...iconProps }: IconProps) {
- const theme = useTheme();
- return (
- <CustomIcon {...iconProps}>
- <path
- d="M8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12Zm3.207-6.793a1 1 0 0 0-1.414-1.414L7 8.586 5.707 7.293a1 1 0 0 0-1.414 1.414l2 2a1 1 0 0 0 1.414 0l3.5-3.5Z"
- style={{ fill: themeColor(fill)({ theme }) }}
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/FlagWarningIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/FlagWarningIcon.tsx
deleted file mode 100644
index 8f4e1441d80..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/FlagWarningIcon.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconWarning from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function FlagWarningIcon({ fill = 'iconWarning', ...iconProps }: IconProps) {
- const theme = useTheme();
- return (
- <CustomIcon {...iconProps}>
- <path
- d="M14.41 12.55a1 1 0 0 1-.893 1.45H2.625a1 1 0 0 1-.892-1.45L7.178 1.766a1 1 0 0 1 1.786 0l5.445 10.782ZM7 6a1 1 0 1 1 2 0v3a1 1 0 1 1-2 0V6Zm1 5a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"
- style={{ fill: themeColor(fill)({ theme }) }}
- />
- </CustomIcon>
- );
-}
-FlagWarningIcon.displayName = 'FlagWarningIcon';
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/HelperHintIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/HelperHintIcon.tsx
deleted file mode 100644
index 08b33e90c88..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/HelperHintIcon.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { Fragment } from 'react';
-import { themeColor, themeContrast } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-type Props = IconProps & {
- raised?: boolean;
-};
-
-/** @deprecated Use IconQuestionMark from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function HelperHintIcon({ raised, ...iconProps }: Props) {
- const theme = useTheme();
- return (
- <CustomIcon {...iconProps}>
- {raised ? (
- // eslint-disable-next-line react/jsx-fragments
- <Fragment>
- <circle cx="8" cy="8" fill="var(--echoes-color-icon-subdued)" r="7" />
- <path
- d="M6.82812 10.2301H8.44318V10.0852C8.4517 9.25426 8.75 8.86648 9.4233 8.46165C10.2202 7.98864 10.7401 7.36222 10.7401 6.3608C10.7401 4.86932 9.53835 4 7.84659 4C6.29972 4 5.03835 4.80966 5 6.5142H6.73864C6.7642 5.8196 7.27983 5.44886 7.83807 5.44886C8.41335 5.44886 8.87784 5.83239 8.87784 6.42472C8.87784 6.98295 8.47301 7.35369 7.94886 7.68608C7.23295 8.13778 6.83239 8.59375 6.82812 10.0852V10.2301ZM7.66761 12.9574C8.21307 12.9574 8.68608 12.5014 8.69034 11.9347C8.68608 11.3764 8.21307 10.9205 7.66761 10.9205C7.10511 10.9205 6.64063 11.3764 6.64489 11.9347C6.64063 12.5014 7.10511 12.9574 7.66761 12.9574Z"
- fill="var(--echoes-color-icon-subdued)"
- />
- </Fragment>
- ) : (
- // eslint-disable-next-line react/jsx-fragments
- <Fragment>
- <circle cx="8" cy="8" fill={themeColor('iconHelperHint')({ theme })} r="7" />
- <path
- d="M6.82812 10.2301h1.61506v-.1449c.00852-.83094.30682-1.21872.98012-1.62355.7969-.47301 1.3168-1.09943 1.3168-2.10085C10.7401 4.86932 9.53835 4 7.84659 4 6.29972 4 5.03835 4.80966 5 6.5142h1.73864c.02556-.6946.54119-1.06534 1.09943-1.06534.57528 0 1.03977.38353 1.03977.97586 0 .55823-.40483.92897-.92898 1.26136-.71591.4517-1.11647.90767-1.12074 2.39912v.1449Zm.83949 2.7273c.54546 0 1.01847-.456 1.02273-1.0227-.00426-.5583-.47727-1.0142-1.02273-1.0142-.5625 0-1.02698.4559-1.02272 1.0142-.00426.5667.46022 1.0227 1.02272 1.0227Z"
- fill={themeContrast('iconHelperHint')({ theme })}
- />
- </Fragment>
- )}
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/HomeFillIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/HomeFillIcon.tsx
deleted file mode 100644
index f4e93da93d7..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/HomeFillIcon.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconHome with the isFilled prop from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function HomeFillIcon({ fill = 'iconFavorite', ...iconProps }: IconProps) {
- const theme = useTheme();
- const fillColor = themeColor(fill)({ theme });
- return (
- <CustomIcon {...iconProps}>
- <path
- d="M6.9995 0.280296C6.602 0.280296 6.21634 0.415622 5.906 0.664003L0.657 4.864C0.242 5.196 0 5.699 0 6.23V13.25C0 13.7141 0.184374 14.1593 0.512563 14.4874C0.840752 14.8156 1.28587 15 1.75 15H5.25C5.44891 15 5.63968 14.921 5.78033 14.7803C5.92098 14.6397 6 14.4489 6 14.25V9H8V14.25C8 14.4489 8.07902 14.6397 8.21967 14.7803C8.36032 14.921 8.55109 15 8.75 15H12.25C12.7141 15 13.1592 14.8156 13.4874 14.4874C13.8156 14.1593 14 13.7141 14 13.25V6.231C14 5.699 13.758 5.196 13.343 4.864L8.093 0.664003C7.78266 0.415622 7.397 0.280296 6.9995 0.280296Z"
- fill={fillColor}
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/HomeIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/HomeIcon.tsx
deleted file mode 100644
index 9b350fdfff5..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/HomeIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { HomeIcon as OcticonHomeIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconHome from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const HomeIcon = OcticonHoc(OcticonHomeIcon, 'HomeIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/Icon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/Icon.tsx
deleted file mode 100644
index 17d1b67d3d1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/Icon.tsx
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { OcticonProps } from '@primer/octicons-react';
-import React from 'react';
-import { theme } from 'twin.macro';
-import { themeColor } from '../../helpers/theme';
-import { CSSColor, ThemeColors } from '../../types/theme';
-
-interface Props {
- 'aria-hidden'?: boolean | 'true' | 'false';
- 'aria-label'?: string;
- children: React.ReactNode;
- className?: string;
- description?: React.ReactNode;
-}
-
-/** @deprecated Use IconProps from Echoes instead.
- *
- * Some of the props have been dropped:
- * - ~`aria-hidden`~ is now inferred from the absence of an `aria-label`
- * - ~`data-guiding-id`~ is no longer passed down to the DOM, put it on a wrapper instead
- * - ~`description`~ doesn't exist anymore
- * - ~`fill`~ is now `color`. You can use "echoes-colors-icons-*" design tokens for the `color`
- * prop. Without a specific `color`, icons take the color of their surroundings (currentColor)
- * or have an intrinsic color.
- * - ~`height`~ doesn't exist anymore, icons are sized based on the font-size of their parent
- * - ~`transform`~ doesn't exist anymore
- * - ~`viewbox`~ doesn't exist anymore, icons are sized based on the font-size of their parent
- * - ~`width`~ doesn't exist anymore, icons are sized based on the font-size of their parent
- */
-export interface IconProps extends Omit<Props, 'children'> {
- ['data-guiding-id']?: string;
- fill?: ThemeColors | CSSColor;
- height?: number;
- transform?: string;
- viewBox?: string;
- width?: number;
-}
-
-const PIXELS_IN_ONE_REM = 16;
-
-function convertRemToPixel(remString: string) {
- return Number(remString.replace('rem', '')) * PIXELS_IN_ONE_REM;
-}
-
-/** @deprecated Don't create new icons based on this, use the ones from Echoes instead. */
-export function CustomIcon(props: Props) {
- const {
- 'aria-label': ariaLabel,
- 'aria-hidden': ariaHidden,
- children,
- className,
- description,
- ...iconProps
- } = props;
- return (
- <svg
- aria-hidden={ariaHidden ?? (ariaLabel ? 'false' : 'true')}
- aria-label={ariaLabel}
- className={className}
- fill="none"
- height={convertRemToPixel(theme('height.icon'))}
- role="img"
- style={{
- clipRule: 'evenodd',
- display: 'inline-block',
- fillRule: 'evenodd',
- userSelect: 'none',
- verticalAlign: 'middle',
- strokeLinejoin: 'round',
- strokeMiterlimit: 1.414,
- }}
- version="1.1"
- viewBox="0 0 16 16"
- width={convertRemToPixel(theme('width.icon'))}
- xmlSpace="preserve"
- xmlnsXlink="http://www.w3.org/1999/xlink"
- {...iconProps}
- >
- {description && <desc>{description}</desc>}
- {children}
- </svg>
- );
-}
-
-/** @deprecated Don't create new icons based on this, use the ones from Echoes instead. */
-export function OcticonHoc(
- WrappedOcticon: React.ComponentType<React.PropsWithChildren<OcticonProps>>,
- displayName?: string,
-): React.ComponentType<React.PropsWithChildren<IconProps>> {
- function IconWrapper({ fill, ...props }: IconProps) {
- const theme = useTheme();
-
- const size = props.width ?? props.height ?? 'small';
-
- return (
- <WrappedOcticon
- fill={fill && themeColor(fill)({ theme })}
- size={size}
- verticalAlign="middle"
- {...props}
- />
- );
- }
-
- IconWrapper.displayName = displayName ?? WrappedOcticon.displayName ?? WrappedOcticon.name;
- return IconWrapper;
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/InProgressVisual.tsx b/server/sonar-web/src/main/js/design-system/components/icons/InProgressVisual.tsx
deleted file mode 100644
index 5000ba8ea83..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/InProgressVisual.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { keyframes, useTheme } from '@emotion/react';
-import styled from '@emotion/styled';
-import { themeColor } from '../../helpers/theme';
-
-export function InProgressVisual() {
- const theme = useTheme();
-
- return (
- <svg className="svg-animated" height="168" width="168" xmlns="http://www.w3.org/2000/svg">
- <path
- d="M149 151.15v-61.5c-6 48.4-49.17 61.34-70 61.5h70Z"
- fill={themeColor('illustrationShade')({ theme })}
- />
- <path
- d="M50.94 16.79 34 9.79 37.8 4l13.14 12.79ZM48.5 24.46 38 27.93V21l10.5 3.46ZM125.55 37.07l3.63-9.07 5.1 4.7-8.73 4.37ZM125 43.46 141.5 40v6.93L125 43.46ZM56.93 10.59 50 2.57 56.51 0l.42 10.59Z"
- fill={themeColor('illustrationPrimary')({ theme })}
- />
- <path
- d="M19 57.15v95h8v-95h-8ZM33 73.15h15v-8H33v8ZM56 73.15h15v-8H56v8Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- />
- <path
- clipRule="evenodd"
- d="M20 157a7 7 0 0 1-7-7V61a7 7 0 0 1 7-7h28.5v6H20a1 1 0 0 0-1 1v16.88h63v6.24H19V150a1 1 0 0 0 1 1h128a1 1 0 0 0 1-1V61a1 1 0 0 0-1-1h-11v-6h11a7 7 0 0 1 7 7v89a7 7 0 0 1-7 7H20Z"
- fill="var(--echoes-color-icon-subdued)"
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="M91 112.15H66v-6h25v6ZM62.09 129.5 48.6 142.54l-8.72-8.61 4.22-4.27 4.55 4.49 9.25-8.97 4.18 4.32ZM62.09 105.31 48.6 118.35l-8.72-8.6 4.22-4.28 4.55 4.5L57.9 101l4.18 4.31ZM91 137.34H66v-6h25v6Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- fillRule="evenodd"
- />
- <Wheel>
- <path
- clipRule="evenodd"
- d="m115.17 46.11-7.2-4.15a24.21 24.21 0 0 0 1.72-6.41H118v-6.1h-8.31c-.28-2.24-.87-4.4-1.72-6.4l7.2-4.16-3.05-5.28-7.2 4.16a24.55 24.55 0 0 0-4.69-4.7l4.16-7.2-5.28-3.04-4.15 7.2a24.21 24.21 0 0 0-6.41-1.72V0h-6.1v8.31c-2.24.28-4.4.87-6.4 1.72l-4.16-7.2-5.28 3.05 4.16 7.2a24.52 24.52 0 0 0-4.7 4.69l-7.2-4.16-3.04 5.28 7.2 4.15a24.2 24.2 0 0 0-1.72 6.41H53v6.1h8.31c.28 2.24.87 4.4 1.72 6.4l-7.2 4.16 3.05 5.28 7.2-4.16a24.52 24.52 0 0 0 4.69 4.7l-4.16 7.2 5.28 3.04 4.15-7.2c2.02.85 4.17 1.44 6.41 1.72V65h6.1v-8.31a24.2 24.2 0 0 0 6.4-1.72l4.16 7.2 5.28-3.05-4.16-7.2a24.51 24.51 0 0 0 4.7-4.69l7.2 4.16 3.04-5.28ZM85.5 51a18.5 18.5 0 1 0 0-37 18.5 18.5 0 0 0 0 37Z"
- fill={themeColor('illustrationPrimary')({ theme })}
- fillRule="evenodd"
- />
- </Wheel>
- <path
- clipRule="evenodd"
- d="M73 32.5a12.5 12.5 0 0 0 25 0h6a18.5 18.5 0 1 1-37 0h6Z"
- fill={themeColor('illustrationInlineBorder')({ theme })}
- fillRule="evenodd"
- />
- <WheelInverted>
- <path
- clipRule="evenodd"
- d="m105.3 54.74 4.74-2.74 1.93 3.34a18.95 18.95 0 0 1 14.2.06l1.97-3.4 4.74 2.74-1.98 3.44A18.98 18.98 0 0 1 137.76 70H142v6h-4.24a18.98 18.98 0 0 1-6.98 11.91l2.1 3.65-4.74 2.74-2.1-3.64a18.95 18.95 0 0 1-13.93.05l-2.07 3.6-4.74-2.75 2.05-3.55A18.98 18.98 0 0 1 100.24 76H96v-6h4.24a18.98 18.98 0 0 1 6.99-11.91l-1.93-3.35ZM119 86a13 13 0 1 0 0-26 13 13 0 0 0 0 26Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- fillRule="evenodd"
- />
- </WheelInverted>
- <circle cx="119" cy="73" fill={themeColor('illustrationPrimary')({ theme })} r="5" />
- </svg>
- );
-}
-
-const rotateKeyFrame = keyframes`
- from {
- transform: rotateZ(0deg);
- }
- to {
- transform: rotateZ(360deg);
- }
-`;
-
-const rotateKeyFrameInverse = keyframes`
- from {
- transform: rotateZ(360deg);
- }
- to {
- transform: rotateZ(0deg);
- }
-`;
-
-const Wheel = styled.g`
- transform-origin: 85.5px 32.5px 0;
- animation: ${rotateKeyFrame} 3s infinite;
-`;
-
-const WheelInverted = styled.g`
- transform-origin: 119px 73px 0;
- animation: ${rotateKeyFrameInverse} 3s infinite;
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/InheritanceIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/InheritanceIcon.tsx
deleted file mode 100644
index 6aa6c41ba47..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/InheritanceIcon.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconInheritance from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function InheritanceIcon({ fill = 'currentColor', ...iconProps }: Readonly<IconProps>) {
- const theme = useTheme();
- const fillColor = themeColor(fill)({ theme });
- return (
- <CustomIcon {...iconProps}>
- <mask fill="white" id="path-1-inside-1_3266_8058">
- <rect height="6" rx="0.5" width="6" x="1" y="1" />
- </mask>
- <rect
- height="6"
- mask="url(#path-1-inside-1_3266_8058)"
- rx="0.5"
- stroke={fillColor}
- strokeWidth="3"
- width="6"
- x="1"
- y="1"
- />
- <mask fill="white" id="path-2-inside-2_3266_8058">
- <rect height="6" rx="0.5" width="6" x="9" y="9" />
- </mask>
- <rect
- height="6"
- mask="url(#path-2-inside-2_3266_8058)"
- rx="0.5"
- stroke={fillColor}
- strokeWidth="3"
- width="6"
- x="9"
- y="9"
- />
- <path d="M4 7V11C4 11.5523 4.44772 12 5 12H9" stroke={fillColor} strokeWidth="1.5" />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/IssueLocationIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/IssueLocationIcon.tsx
deleted file mode 100644
index d9b9fe01199..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/IssueLocationIcon.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconDot with the isFilled prop from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function IssueLocationIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
- const theme = useTheme();
- const fillColor = themeColor(fill)({ theme });
-
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M8 11C8.79565 11 9.55871 10.6839 10.1213 10.1213C10.6839 9.55871 11 8.79565 11 8C11 7.20435 10.6839 6.44129 10.1213 5.87868C9.55871 5.31607 8.79565 5 8 5C7.20435 5 6.44129 5.31607 5.87868 5.87868C5.31607 6.44129 5 7.20435 5 8C5 8.79565 5.31607 9.55871 5.87868 10.1213C6.44129 10.6839 7.20435 11 8 11ZM8 7C7.73478 7 7.48043 7.10536 7.29289 7.29289C7.10536 7.48043 7 7.73478 7 8C7 8.26522 7.10536 8.51957 7.29289 8.70711C7.48043 8.89464 7.73478 9 8 9C8.26522 9 8.51957 8.89464 8.70711 8.70711C8.89464 8.51957 9 8.26522 9 8C9 7.73478 8.89464 7.48043 8.70711 7.29289C8.51957 7.10536 8.26522 7 8 7Z"
- fill={fillColor}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/IssueTypeIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/IssueTypeIcon.tsx
deleted file mode 100644
index a9efdaaac8c..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/IssueTypeIcon.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { IssueType } from '../../types';
-import { BugIcon } from './BugIcon';
-import { CodeSmellIcon } from './CodeSmellIcon';
-import { IconProps } from './Icon';
-import { SecurityFindingIcon } from './SecurityFindingIcon';
-import { VulnerabilityIcon } from './VulnerabilityIcon';
-
-export interface Props extends IconProps {
- // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
- type: string | IssueType;
-}
-
-export enum IssueTypeEnum {
- CODE_SMELL = 'CODE_SMELL',
- VULNERABILITY = 'VULNERABILITY',
- BUG = 'BUG',
- SECURITY_HOTSPOT = 'SECURITY_HOTSPOT',
-}
-
-export function IssueTypeIcon({ type, ...iconProps }: Props) {
- switch (type.toLowerCase()) {
- case IssueTypeEnum.BUG.toLowerCase():
- case 'bugs':
- case 'new_bugs':
- case IssueTypeEnum.BUG:
- return <BugIcon {...iconProps} />;
- case IssueTypeEnum.VULNERABILITY.toLowerCase():
- case 'vulnerabilities':
- case 'new_vulnerabilities':
- case IssueTypeEnum.VULNERABILITY:
- return <VulnerabilityIcon {...iconProps} />;
- case IssueTypeEnum.CODE_SMELL.toLowerCase():
- case 'code_smells':
- case 'new_code_smells':
- case IssueTypeEnum.CODE_SMELL:
- return <CodeSmellIcon {...iconProps} />;
- case IssueTypeEnum.SECURITY_HOTSPOT.toLowerCase():
- case 'security_hotspots':
- case 'new_security_hotspots':
- case IssueTypeEnum.SECURITY_HOTSPOT:
- return <SecurityFindingIcon {...iconProps} />;
- default:
- return null;
- }
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/LinkIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/LinkIcon.tsx
deleted file mode 100644
index 9eb16f90403..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/LinkIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkIcon as Icon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconLink from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const LinkIcon = OcticonHoc(Icon, 'LinkIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/LockIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/LockIcon.tsx
deleted file mode 100644
index e2aba5a119b..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/LockIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LockIcon as OcticonLockIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconLock from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const LockIcon = OcticonHoc(OcticonLockIcon, 'LockIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/LockIllustration.tsx b/server/sonar-web/src/main/js/design-system/components/icons/LockIllustration.tsx
deleted file mode 100644
index e1e8fc57153..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/LockIllustration.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export function LockIllustration() {
- return (
- <svg
- width="168"
- height="168"
- viewBox="0 0 168 168"
- fill="none"
- xmlns="http://www.w3.org/2000/svg"
- >
- <g clipPath="url(#clip0_21804_11)">
- <path d="M137 154.5V93C131 141.4 87.8333 154.333 67 154.5H137Z" fill="#F4F6FF" />
- <path d="M31 63L31 158H39L39 63H31Z" fill="#BDC6FF" />
- <path
- d="M38.4996 160.125C34.8538 160.125 31.7548 158.849 29.2028 156.297C26.6507 153.745 25.3746 150.646 25.3746 147V73.4999C25.3746 69.8541 26.6507 66.7551 29.2028 64.203C31.7548 61.6509 34.8538 60.3749 38.4996 60.3749H51.6246V42.8749C51.6246 33.8332 54.7601 26.177 61.0309 19.9061C67.3017 13.6353 74.958 10.4999 83.9996 10.4999C93.0413 10.4999 100.698 13.6353 106.968 19.9061C113.239 26.177 116.375 33.8332 116.375 42.8749V60.3749H129.5C133.145 60.3749 136.244 61.6509 138.797 64.203C141.349 66.7551 142.625 69.8541 142.625 73.4999V147C142.625 150.646 141.349 153.745 138.797 156.297C136.244 158.849 133.145 160.125 129.5 160.125H38.4996ZM38.4996 154H129.5C131.541 154 133.218 153.344 134.531 152.031C135.843 150.719 136.5 149.042 136.5 147V73.4999C136.5 71.4582 135.843 69.7811 134.531 68.4686C133.218 67.1561 131.541 66.4999 129.5 66.4999H38.4996C36.458 66.4999 34.7809 67.1561 33.4684 68.4686C32.1559 69.7811 31.4996 71.4582 31.4996 73.4999V147C31.4996 149.042 32.1559 150.719 33.4684 152.031C34.7809 153.344 36.458 154 38.4996 154ZM57.7496 60.3749H110.25V42.8749C110.25 35.5832 107.698 29.3853 102.593 24.2811C97.4892 19.177 91.2913 16.6249 83.9996 16.6249C76.708 16.6249 70.5101 19.177 65.4059 24.2811C60.3017 29.3853 57.7496 35.5832 57.7496 42.8749V60.3749Z"
- fill="#6A7590"
- />
- <path
- d="M92.4215 114.234C90.1611 116.495 87.3538 117.625 83.9996 117.625C80.6455 117.625 77.8382 116.495 75.5778 114.234C73.3173 111.974 72.1871 109.167 72.1871 105.813C72.1871 102.458 73.3173 99.651 75.5778 97.3906C77.8382 95.1302 80.6455 94 83.9996 94C87.3538 94 90.1611 95.1302 92.4215 97.3906C94.6819 99.651 95.8121 102.458 95.8121 105.813C95.8121 109.167 94.6819 111.974 92.4215 114.234Z"
- fill="#7B87D9"
- />
- <path d="M78 111.563H90V126.563H78V111.563Z" fill="#7B87D9" />
- <path
- d="M67 63.5V42.8C67 38.0963 68.6275 34.1903 71.944 30.907C75.2616 27.6225 79.2214 26 84 26C88.7786 26 92.7384 27.6225 96.056 30.907C99.3725 34.1903 101 38.0963 101 42.8V63.5H67Z"
- stroke="#6A7590"
- strokeWidth="6"
- />
- </g>
- <defs>
- <clipPath id="clip0_21804_11">
- <rect width="168" height="168" fill="white" />
- </clipPath>
- </defs>
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/MailIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/MailIcon.tsx
deleted file mode 100644
index 0998a3c1948..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/MailIcon.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '~design-system';
-
-export function MailIcon() {
- const theme = useTheme();
-
- return (
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
- <g id="mail">
- <mask
- id="mask0_6548_2965"
- style={{ maskType: 'alpha' }}
- maskUnits="userSpaceOnUse"
- x="0"
- y="0"
- width="16"
- height="16"
- >
- <rect id="Bounding box" width="16" height="16" fill="#D9D9D9" />
- </mask>
- <g mask="url(#mask0_6548_2965)">
- <path
- id="mail_2"
- d="M2.66659 13.3332C2.29992 13.3332 1.98603 13.2026 1.72492 12.9415C1.46381 12.6804 1.33325 12.3665 1.33325 11.9998V3.99984C1.33325 3.63317 1.46381 3.31928 1.72492 3.05817C1.98603 2.79706 2.29992 2.6665 2.66659 2.6665H13.3333C13.6999 2.6665 14.0138 2.79706 14.2749 3.05817C14.536 3.31928 14.6666 3.63317 14.6666 3.99984V11.9998C14.6666 12.3665 14.536 12.6804 14.2749 12.9415C14.0138 13.2026 13.6999 13.3332 13.3333 13.3332H2.66659ZM7.99992 8.6665L2.66659 5.33317V11.9998H13.3333V5.33317L7.99992 8.6665ZM7.99992 7.33317L13.3333 3.99984H2.66659L7.99992 7.33317ZM2.66659 5.33317V3.99984V11.9998V5.33317Z"
- fill={themeColor('currentColor')({ theme })}
- />
- </g>
- </g>
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/MainBranchIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/MainBranchIcon.tsx
deleted file mode 100644
index 0de937e2687..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/MainBranchIcon.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconBranch from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function MainBranchIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
- const theme = useTheme();
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M8.251 2.49932a.75003.75003 0 0 0-.75.75.75001.75001 0 1 0 .75-.75Zm-2.25.75A2.25004 2.25004 0 0 1 7.21713 1.2516a2.25 2.25 0 0 1 2.33319.16148 2.24917 2.24917 0 0 1 .76538.94287c.1639.37851.2206.79478.1639 1.20334a2.25026 2.25026 0 0 1-.48534 1.11323 2.25 2.25 0 0 1-.99326.6988v5.25598c.50069.177.92271.5252 1.1915.9832.2687.458.3669.9963.2771 1.5197a2.25092 2.25092 0 0 1-2.2186 1.8705 2.25092 2.25092 0 0 1-2.21861-1.8705 2.25115 2.25115 0 0 1 .27716-1.5197 2.2514 2.2514 0 0 1 1.19145-.9832V5.37132a2.24999 2.24999 0 0 1-1.5-2.122Zm2.25 8.74998a.74985.74985 0 0 0-.53033.2197.74987.74987 0 0 0-.21967.5303c0 .1989.07902.3897.21967.5304a.75017.75017 0 0 0 1.06066 0 .75023.75023 0 0 0 .21967-.5304.74983.74983 0 0 0-.21967-.5303.74981.74981 0 0 0-.53033-.2197Z"
- fill={themeColor(fill)({ theme })}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/MenuHelpIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/MenuHelpIcon.tsx
deleted file mode 100644
index ed38a889edb..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/MenuHelpIcon.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconQuestionMark from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function MenuHelpIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
- const theme = useTheme();
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16Zm.507-5.451H6.66v-.166c.005-1.704.462-2.226 1.28-2.742.6-.38 1.062-.803 1.062-1.441 0-.677-.53-1.116-1.188-1.116-.638 0-1.227.424-1.257 1.218H4.571c.044-1.948 1.486-2.873 3.254-2.873 1.933 0 3.307.993 3.307 2.698 0 1.144-.595 1.86-1.505 2.4-.77.463-1.11.906-1.12 1.856v.166Zm.282 1.948a1.185 1.185 0 0 1-1.169 1.169 1.164 1.164 0 1 1 0-2.328c.624 0 1.164.52 1.169 1.159Z"
- fill={themeColor(fill)({ theme })}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/MenuIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/MenuIcon.tsx
deleted file mode 100644
index 3a3dbe9c129..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/MenuIcon.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { KebabHorizontalIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconMoreVertical from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const MenuIcon = styled(OcticonHoc(KebabHorizontalIcon, 'MenuIcon'))`
- transform: rotate(90deg);
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/MenuSearchIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/MenuSearchIcon.tsx
deleted file mode 100644
index 081e8adebfc..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/MenuSearchIcon.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconSearch from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function MenuSearchIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M12 7c0 2.76142-2.23858 5-5 5S2 9.76142 2 7s2.23858-5 5-5 5 2.23858 5 5Zm-.8078 5.6064C10.0236 13.4816 8.57234 14 7 14c-3.86599 0-7-3.134-7-7 0-3.86599 3.13401-7 7-7 3.866 0 7 3.13401 7 7 0 1.57234-.5184 3.0236-1.3936 4.1922l3.0505 3.0504c.3905.3906.3905 1.0237 0 1.4143-.3906.3905-1.0237.3905-1.4143 0l-3.0504-3.0505Z"
- fill={themeColor(fill)({ theme })}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/MinimizeIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/MinimizeIcon.tsx
deleted file mode 100644
index 127e3918343..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/MinimizeIcon.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconDash from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function MinimizeIcon({ fill = 'currentColor', ...iconProps }: Readonly<IconProps>) {
- const theme = useTheme();
- return (
- <CustomIcon {...iconProps}>
- <rect fill={themeColor(fill)({ theme })} height="2" rx="1" width="12" x="2" y="11" />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/NoDataIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/NoDataIcon.tsx
deleted file mode 100644
index 49e891e77c4..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/NoDataIcon.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CustomIcon, IconProps } from './Icon';
-
-export interface NoDataIconProps extends IconProps {
- size?: 'xs' | 'sm' | 'md';
-}
-
-const SIZES: Record<NonNullable<NoDataIconProps['size']>, number> = {
- xs: 16,
- sm: 24,
- md: 36,
-};
-
-export function NoDataIcon({
- fill = 'currentColor',
- size = 'md',
- ...iconProps
-}: Readonly<NoDataIconProps>) {
- const iconSize = SIZES[size];
-
- return (
- <CustomIcon height={iconSize} width={iconSize} {...iconProps}>
- <path
- clipRule="evenodd"
- d="M16 8C16 12.4183 12.4183 16 8 16C5.5106 16 3.28676 14.863 1.81951 13.0799L15.4913 5.1865C15.8201 6.06172 16 7.00986 16 8ZM14.5574 3.41624L0.750565 11.3876C0.269025 10.3589 0 9.21089 0 8C0 3.58172 3.58172 0 8 0C10.7132 0 13.1109 1.35064 14.5574 3.41624Z"
- fill="#E1E6F3"
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/OpenCloseIndicator.tsx b/server/sonar-web/src/main/js/design-system/components/icons/OpenCloseIndicator.tsx
deleted file mode 100644
index 19db514b28b..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/OpenCloseIndicator.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ChevronDownIcon } from './ChevronDownIcon';
-import { ChevronRightIcon } from './ChevronRightIcon';
-import { IconProps } from './Icon';
-
-interface Props extends IconProps {
- open: boolean;
-}
-
-export function OpenCloseIndicator({ open, ...iconProps }: Props) {
- return open ? <ChevronDownIcon {...iconProps} /> : <ChevronRightIcon {...iconProps} />;
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/OpenNewTabIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/OpenNewTabIcon.tsx
deleted file mode 100644
index b5ca3715322..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/OpenNewTabIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { LinkExternalIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconLinkExternal from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const OpenNewTabIcon = OcticonHoc(LinkExternalIcon, 'OpenNewTabIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/OverridenIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/OverridenIcon.tsx
deleted file mode 100644
index d9b40bea4b4..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/OverridenIcon.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-export function OverridenIcon({ fill = 'currentColor', ...iconProps }: Readonly<IconProps>) {
- const theme = useTheme();
- const fillColor = themeColor(fill)({ theme });
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M2.5 2.5L2.5 5.5L5.5 5.5L5.5 2.5L2.5 2.5ZM1.5 1C1.22386 1 1 1.22386 1 1.5L0.999999 6.5C0.999999 6.77614 1.22386 7 1.5 7L6.5 7C6.77614 7 7 6.77614 7 6.5L7 1.5C7 1.22386 6.77614 1 6.5 1L1.5 1Z"
- fill={fillColor}
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="M3.25 11V7H4.78913V11C4.78913 11.1381 4.90398 11.25 5.04565 11.25H9.15V12.75H5.04565C4.05394 12.75 3.25 11.9665 3.25 11Z"
- fill={fillColor}
- fillRule="evenodd"
- />
- <circle cx="11.5" cy="11.5" fill={fillColor} r="3.5" />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/OverviewQGNotComputedIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/OverviewQGNotComputedIcon.tsx
deleted file mode 100644
index 2d1122133fd..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/OverviewQGNotComputedIcon.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-
-interface Props {
- className?: string;
-}
-
-export function OverviewQGNotComputedIcon({ className }: Readonly<Props>) {
- const theme = useTheme();
-
- return (
- <svg
- className={className}
- fill="none"
- height="168"
- role="img"
- viewBox="0 0 168 168"
- width="168"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- clipRule="evenodd"
- d="M149.542 26.472L141.248 37.2099C140.456 38.2345 140.645 39.7068 141.67 40.4983C142.695 41.2897 144.167 41.1007 144.959 40.076L153.253 29.3382C154.044 28.3135 153.855 26.8413 152.831 26.0498C151.806 25.2583 150.334 25.4473 149.542 26.472ZM137.915 45.3598C141.625 48.2252 146.955 47.5408 149.82 43.8312L158.114 33.0934C160.98 29.3837 160.295 24.0536 156.586 21.1883C152.876 18.3229 147.546 19.0072 144.681 22.7168L136.386 33.4547C133.521 37.1643 134.205 42.4944 137.915 45.3598Z"
- fill={themeColor('illustrationPrimary')({ theme })}
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="M149.385 57.9371C149.385 46.1503 139.83 36.5952 128.043 36.5952C116.257 36.5952 106.702 46.1503 106.702 57.9371C106.702 69.7238 116.257 79.2789 128.043 79.2789C139.83 79.2789 149.385 69.7238 149.385 57.9371ZM155.528 57.9371C155.528 42.7576 143.223 30.4523 128.043 30.4523C112.864 30.4523 100.559 42.7576 100.559 57.9371C100.559 73.1165 112.864 85.4218 128.043 85.4218C143.223 85.4218 155.528 73.1165 155.528 57.9371Z"
- fill={themeColor('illustrationPrimary')({ theme })}
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="M143.6 57.937C143.6 49.3459 136.635 42.3814 128.044 42.3814C119.453 42.3814 112.489 49.3459 112.489 57.937C112.489 66.5281 119.453 73.4925 128.044 73.4925C136.635 73.4925 143.6 66.528 143.6 57.937ZM149.743 57.937C149.743 45.9532 140.028 36.2385 128.044 36.2385C116.06 36.2385 106.346 45.9532 106.346 57.937C106.346 69.9207 116.06 79.6355 128.044 79.6355C140.028 79.6355 149.743 69.9207 149.743 57.937Z"
- fill={themeColor('illustrationShade')({ theme })}
- fillRule="evenodd"
- />
- <path d="M24 40L24 135H32L32 40H24Z" fill={themeColor('illustrationSecondary')({ theme })} />
- <path
- d="M38 56L53 56L53 48L38 48L38 56Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- />
- <path
- d="M61 56L76 56L76 48L61 48L61 56Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- />
- <path
- clipRule="evenodd"
- d="M88 67.5746H21V61.3297H88V67.5746Z"
- fill="var(--echoes-color-icon-subdued)"
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="M18 133C18 136.866 21.134 140 25 140H153C156.866 140 160 136.866 160 133V78H154V133C154 133.552 153.552 134 153 134H25C24.4477 134 24 133.552 24 133V44C24 43.4477 24.4477 43 25 43H72V37H25C21.134 37 18 40.134 18 44V133Z"
- fill="var(--echoes-color-icon-subdued)"
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="M69.2432 103.219L78.7954 93.6672L74.5527 89.4245L60.7578 103.219L74.5527 117.014L78.7954 112.771L69.2432 103.219Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="M108.906 103.219L99.3538 93.6672L103.596 89.4246L117.391 103.219L103.596 117.014L99.3538 112.771L108.906 103.219Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="M81.7179 119.862L91.0929 84.2365L96.8953 85.7635L87.5203 121.388L81.7179 119.862Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- fillRule="evenodd"
- />
- <path
- d="M51 128.953C51 141.379 40.9264 151.453 28.5 151.453C16.0736 151.453 6 141.379 6 128.953C6 116.526 16.0736 106.453 28.5 106.453C40.9264 106.453 51 116.526 51 128.953Z"
- fill={themeColor('illustrationPrimary')({ theme })}
- />
- <path
- clipRule="evenodd"
- d="M25 131.953V113.953H31V131.953H25Z"
- fill={themeColor('backgroundSecondary')({ theme })}
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="M25 142.453L25 136.453L31 136.453L31 142.453L25 142.453Z"
- fill={themeColor('backgroundSecondary')({ theme })}
- fillRule="evenodd"
- />
- <path
- d="M105.398 35.2089L90.7238 24.2245L95.8489 19.5626L105.398 35.2089Z"
- fill={themeColor('illustrationPrimary')({ theme })}
- />
- <path
- d="M99 41.5242L88.5 44.9883L88.5 38.0601L99 41.5242Z"
- fill={themeColor('illustrationPrimary')({ theme })}
- />
- <path
- d="M139.228 86.8865L147.417 92.2112L141.826 96.3028L139.228 86.8865Z"
- fill={themeColor('illustrationPrimary')({ theme })}
- />
- <path
- d="M132 88.5242L135.464 105.024H128.536L132 88.5242Z"
- fill={themeColor('illustrationPrimary')({ theme })}
- />
- <path
- d="M114 29.5242L110.536 19.7742L117.464 19.7742L114 29.5242Z"
- fill={themeColor('illustrationPrimary')({ theme })}
- />
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/OverviewQGPassedIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/OverviewQGPassedIcon.tsx
deleted file mode 100644
index a0d861b45c3..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/OverviewQGPassedIcon.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers';
-
-interface OverviewQGPassedIconProps {
- className?: string;
- height?: number;
- width?: number;
-}
-
-const DEFAULT_WIDTH = 154;
-const DEFAULT_HEIGHT = 136;
-
-export function OverviewQGPassedIcon({
- className,
- height,
- width,
-}: Readonly<OverviewQGPassedIconProps>) {
- const theme = useTheme();
- const actualWidth = width ?? DEFAULT_WIDTH;
- const actualHeight = height ?? DEFAULT_HEIGHT;
-
- return (
- <svg
- className={className}
- fill="none"
- height={actualHeight}
- role="img"
- viewBox={`0 0 ${DEFAULT_WIDTH} ${DEFAULT_HEIGHT}`}
- width={actualWidth}
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- d="M18 26.3839L18 128.594H26L26 26.3839H18Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- />
- <path
- d="M32 43.5982L47 43.5982L47 34.9911L32 34.9911L32 43.5982Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- />
- <path
- d="M55 43.5982L70 43.5982L70 34.9911L55 34.9911L55 43.5982Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- />
- <path d="M15 52.2054L87 52.2054" stroke="var(--echoes-color-icon-subdued)" strokeWidth="6" />
- <path
- d="M87 26.3839H19C16.7909 26.3839 15 28.1748 15 30.3839V126.746C15 128.955 16.7909 130.746 19 130.746H147C149.209 130.746 151 128.955 151 126.746V62.9643M136 26.3839H147C149.209 26.3839 151 28.1748 151 30.3839V42.5223"
- stroke="var(--echoes-color-icon-subdued)"
- strokeWidth="6"
- />
- <path
- d="M70.6736 103.733L59 91.1733L70.6736 78.614"
- stroke={themeColor('illustrationSecondary')({ theme })}
- strokeWidth="6"
- />
- <path
- d="M95.4744 78.614L107.148 91.1733L95.4744 103.733"
- stroke={themeColor('illustrationSecondary')({ theme })}
- strokeWidth="6"
- />
- <path
- d="M87.9937 71.5714L78.6187 109.9"
- stroke={themeColor('illustrationSecondary')({ theme })}
- strokeWidth="6"
- />
- <ellipse
- cx="22.5"
- cy="122.676"
- fill={themeColor('illustrationPrimary')({ theme })}
- rx="22.5"
- ry="22.5"
- />
- <path d="M14 121.063L21 128.594L34 114.607" stroke="white" strokeWidth="6" />
- <path
- d="M108.684 52.7433C116.712 48.065 123.243 41.1875 127.5 32.9269C131.757 41.1875 138.288 48.065 146.316 52.7433C138.288 57.4216 131.757 64.2991 127.5 72.5597C123.243 64.2991 116.712 57.4216 108.684 52.7433Z"
- stroke={themeColor('illustrationPrimary')({ theme })}
- strokeWidth="6"
- />
- <path
- d="M94.8732 23.1563C99.0981 20.5339 102.585 16.8739 105 12.5277C107.415 16.8739 110.902 20.5339 115.127 23.1563C110.902 25.7786 107.415 29.4386 105 33.7848C102.585 29.4386 99.0981 25.7786 94.8732 23.1563Z"
- stroke={themeColor('illustrationPrimary')({ theme })}
- strokeWidth="4.5"
- />
- <path
- d="M123.126 8.6317C124.893 7.43681 126.384 5.87768 127.5 4.06049C128.616 5.87768 130.107 7.43681 131.874 8.6317C130.107 9.82658 128.616 11.3857 127.5 13.2029C126.384 11.3857 124.893 9.82658 123.126 8.6317Z"
- stroke={themeColor('illustrationPrimary')({ theme })}
- strokeWidth="3"
- />
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/PencilIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/PencilIcon.tsx
deleted file mode 100644
index d33a5fffa40..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/PencilIcon.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { PencilIcon as PencilOcticonIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-export const PencilIcon = OcticonHoc(PencilOcticonIcon);
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/PinIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/PinIcon.tsx
deleted file mode 100644
index bafc55e50d7..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/PinIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { PinIcon as OcticonPinIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconPin from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const PinIcon = OcticonHoc(OcticonPinIcon, 'PinIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/ProjectIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/ProjectIcon.tsx
deleted file mode 100644
index e553f09d892..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/ProjectIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ProjectIcon as OcticonProjectIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconProject from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const ProjectIcon = OcticonHoc(OcticonProjectIcon, 'ProjectIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/PullRequestIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/PullRequestIcon.tsx
deleted file mode 100644
index 0cc9b256453..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/PullRequestIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { GitPullRequestIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconPullrequest from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const PullRequestIcon = OcticonHoc(GitPullRequestIcon, 'PullRequestIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/QualifierIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/QualifierIcon.tsx
deleted file mode 100644
index 9021b169ee2..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/QualifierIcon.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { DirectoryIcon } from './DirectoryIcon';
-import { FileIcon } from './FileIcon';
-import { CustomIcon, IconProps } from './Icon';
-import { ProjectIcon } from './ProjectIcon';
-import { TestFileIcon } from './TestFileIcon';
-
-interface Props extends IconProps {
- qualifier: string | null | undefined;
-}
-
-const defaultIconfill = 'var(--echoes-color-icon-subdued)';
-
-export function QualifierIcon({ qualifier, fill, ...iconProps }: Readonly<Props>) {
- const theme = useTheme();
-
- if (!qualifier) {
- return null;
- }
-
- const icon = {
- app: ApplicationIcon({ fill: fill ?? defaultIconfill, ...iconProps }),
- dir: <DirectoryIcon fill={fill ?? themeColor('iconDirectory')({ theme })} {...iconProps} />,
- fil: <FileIcon fill={fill ?? defaultIconfill} {...iconProps} />,
- svw: SubPortfolioIcon({ fill: fill ?? defaultIconfill, ...iconProps }),
- trk: <ProjectIcon fill={fill ?? defaultIconfill} {...iconProps} />,
- uts: <TestFileIcon fill={fill ?? defaultIconfill} {...iconProps} />,
- vw: PortfolioIcon({ fill: fill ?? defaultIconfill, ...iconProps }),
- }[qualifier.toLowerCase()];
-
- return icon ?? null;
-}
-
-function PortfolioIcon({ fill = 'currentColor', ...iconProps }: Readonly<IconProps>) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <path
- d="M14.97 14.97H1.016V1.015H14.97V14.97zm-1-12.955H2.015V13.97H13.97V2.015zm-.973 10.982H9V9h3.997v3.997zM7 12.996H3.004V9H7v3.996zM11.997 10H10v1.997h1.997V10zM6 10H4.004v1.996H6V10zm1-3H3.006V3.006H7V7zm5.985 0H9V3.015h3.985V7zM6 4.006H4.006V6H6V4.006zm5.985.009H10V6h1.985V4.015z"
- fill={themeColor(fill)({ theme })}
- />
- </CustomIcon>
- );
-}
-
-function ApplicationIcon({ fill = 'currentColor', ...iconProps }: Readonly<IconProps>) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <path
- d="M3.014 10.986a2 2 0 1 1-.001 4.001 2 2 0 0 1 .001-4.001zm9.984 0a2 2 0 1 1-.001 4.001 2 2 0 0 1 .001-4.001zm-5.004-.021c1.103 0 2 .896 2 2s-.897 2-2 2a2 2 0 0 1 0-4zm-4.98 1.021a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm9.984 0a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm-5.004-.021a1 1 0 1 1 0 2 1 1 0 0 1 0-2zM2.984 6a2 2 0 1 1-.001 4.001A2 2 0 0 1 2.984 6zm9.984 0a2 2 0 1 1-.001 4.001A2 2 0 0 1 12.968 6zm-5.004-.021c1.103 0 2 .897 2 2a2 2 0 1 1-2-2zM2.984 7a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm9.984 0a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm-5.004-.021a1.001 1.001 0 0 1 0 2 1 1 0 0 1 0-2zM3 1.025a2 2 0 1 1-.001 4.001A2 2 0 0 1 3 1.025zm9.984 0a2 2 0 1 1-.001 4.001 2 2 0 0 1 .001-4.001zM7.98 1.004c1.103 0 2 .896 2 2s-.897 2-2 2a2 2 0 0 1 0-4zM3 2.025a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm9.984 0a1 1 0 1 1 0 2 1 1 0 0 1 0-2zM7.98 2.004a1.001 1.001 0 0 1 0 2 1 1 0 0 1 0-2z"
- fill={themeColor(fill)({ theme })}
- />
- </CustomIcon>
- );
-}
-
-function SubPortfolioIcon({ fill = 'currentColor', ...iconProps }: Readonly<IconProps>) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <path
- d="M14 7h2v9H7v-2H0V0h14v7zM8 8v7h7V8H8zm3 6H9v-2h2v2zm3 0h-2v-2h2v2zm-1-7V1H1v12h6V7h6zm-7 5H2V8h4v4zm5-1H9V9h2v2zm3 0h-2V9h2v2zM5 9H3v2h2V9zm1-3H2V2h4v4zm6 0H8V2h4v4zM5 3H3v2h2V3zm6 0H9v2h2V3z"
- fill={themeColor(fill)({ theme })}
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/RecommendedIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/RecommendedIcon.tsx
deleted file mode 100644
index 7a8be83a51b..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/RecommendedIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { VerifiedIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconRecommended from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const RecommendedIcon = OcticonHoc(VerifiedIcon, 'RecommendedIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/RequiredIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/RequiredIcon.tsx
deleted file mode 100644
index b410de80d2a..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/RequiredIcon.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeColor } from '../../helpers/theme';
-
-export function RequiredIcon(props: React.ComponentPropsWithoutRef<'em'>) {
- return <StyledEm {...props}>*</StyledEm>;
-}
-
-export const StyledEm = styled.em`
- ${tw`sw-typo-default`}
- ${tw`sw-not-italic`}
- ${tw`sw-ml-2`}
- color: ${themeColor('inputRequired')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SearchIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SearchIcon.tsx
deleted file mode 100644
index cc02b360ee6..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SearchIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { SearchIcon as OcticonSearchIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconSearch from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const SearchIcon = OcticonHoc(OcticonSearchIcon, 'SearchIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SecurityFindingIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SecurityFindingIcon.tsx
deleted file mode 100644
index a0a3ef93a0c..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SecurityFindingIcon.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconSecurityFinding from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function SecurityFindingIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
- const theme = useTheme();
- const fillColor = themeColor(fill)({ theme });
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M13.2114 3.76857a.8571.8571 0 0 0-.5743-.66L8.13714 1.85714a.90869.90869 0 0 0-.42857 0l-4.5 1.25143c-.3046.08786-.52937.34618-.57429.66-.06857.48857-.63428 4.82572.97715 7.12283a7.7138 7.7138 0 0 0 4.11428 2.9657.72308.72308 0 0 0 .19714 0 .66187.66187 0 0 0 .18857 0 7.65392 7.65392 0 0 0 4.12288-2.9657c1.5732-2.27896 1.0457-6.56583.9786-7.11053l-.0015-.0123Zm-1.6028 4.08857a5.27096 5.27096 0 0 1-.7372 2.07429A6.78813 6.78813 0 0 1 8 12.1429V7.85714h3.6086Zm-3.6086 0H4.22a20.81886 20.81886 0 0 1 0-3.27428L8 3.57143v4.28571Z"
- fill={fillColor}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SecurityHotspotIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SecurityHotspotIcon.tsx
deleted file mode 100644
index c8298df6614..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SecurityHotspotIcon.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconSecurityFinding from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function SecurityHotspotIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <path
- d="M14.08 3.23a1 1 0 00-.67-.77L8.16 1a1.06 1.06 0 00-.5 0L2.41 2.46a.94.94 0 00-.67.77c-.08.57-.74 5.63 1.14 8.31A9 9 0 007.68 15a.85.85 0 00.23 0 .78.78 0 00.22 0 8.93 8.93 0 004.81-3.46c1.85-2.68 1.21-7.74 1.14-8.31zM12.21 8a6.15 6.15 0 01-.86 2.42A7.92 7.92 0 018 13V8zM8 3v5H3.59a24.29 24.29 0 010-3.82z"
- fill={themeColor(fill)({ theme })}
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SeparatorCircleIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SeparatorCircleIcon.tsx
deleted file mode 100644
index 8b880e89742..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SeparatorCircleIcon.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../../helpers/theme';
-
-export const SeparatorCircleIcon = styled.div`
- ${tw`sw-inline-block`}
- ${tw`sw-rounded-1`}
-
- background-color: ${themeColor('separatorCircle')};
- border: ${themeBorder('default', 'separatorCircle')};
- height: 2px;
- width: 2px;
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SeverityBlockerIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SeverityBlockerIcon.tsx
deleted file mode 100644
index bea88299489..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SeverityBlockerIcon.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor, themeContrast } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-export function SeverityBlockerIcon({ fill = 'iconSeverityMajor', ...iconProps }: IconProps) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <circle cx="8" cy="8" fill={themeColor(fill)({ theme })} r="7" />
- <rect fill={themeContrast(fill)({ theme })} height="1.5" rx="0.75" width="6" x="5" y="7.2" />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SeverityCriticalIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SeverityCriticalIcon.tsx
deleted file mode 100644
index 7fa0a5a99fb..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SeverityCriticalIcon.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor, themeContrast } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-export function SeverityCriticalIcon({ fill = 'iconSeverityMajor', ...iconProps }: IconProps) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <circle cx="8" cy="8" fill={themeColor(fill)({ theme })} r="7" />
- <path
- d="M5 6.67113C5 6.56986 5.05583 6.47727 5.14421 6.43198L7.88334 5.02823C7.95678 4.99059 8.04322 4.99059 8.11666 5.02823L10.8558 6.43198C10.9442 6.47727 11 6.56986 11 6.67113V10.7324C11 10.9191 10.8181 11.0483 10.6475 10.9827L8.0916 10.0003C8.03254 9.97763 7.96746 9.97763 7.9084 10.0003L5.35247 10.9827C5.18192 11.0483 5 10.9191 5 10.7324V6.67113Z"
- fill={themeContrast(fill)({ theme })}
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SeverityInfoIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SeverityInfoIcon.tsx
deleted file mode 100644
index a35b214a78a..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SeverityInfoIcon.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor, themeContrast } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconInfo from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function SeverityInfoIcon({ fill = 'iconSeverityInfo', ...iconProps }: IconProps) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <circle cx="8" cy="8" fill={themeColor(fill)({ theme })} r="7" />
- <path
- clipRule="evenodd"
- d="M6.5 7.75C6.5 7.55109 6.57902 7.36032 6.71967 7.21967C6.86032 7.07902 7.05109 7 7.25 7H8.25C8.44891 7 8.63968 7.07902 8.78033 7.21967C8.92098 7.36032 9 7.55109 9 7.75V10.5H9.25C9.44891 10.5 9.63968 10.579 9.78033 10.7197C9.92098 10.8603 10 11.0511 10 11.25C10 11.4489 9.92098 11.6397 9.78033 11.7803C9.63968 11.921 9.44891 12 9.25 12H7.25C7.05109 12 6.86032 11.921 6.71967 11.7803C6.57902 11.6397 6.5 11.4489 6.5 11.25C6.5 11.0511 6.57902 10.8603 6.71967 10.7197C6.86032 10.579 7.05109 10.5 7.25 10.5H7.5V8.5H7.25C7.05109 8.5 6.86032 8.42098 6.71967 8.28033C6.57902 8.13968 6.5 7.94891 6.5 7.75ZM8 6C8.26522 6 8.51957 5.89464 8.70711 5.70711C8.89464 5.51957 9 5.26522 9 5C9 4.73478 8.89464 4.48043 8.70711 4.29289C8.51957 4.10536 8.26522 4 8 4C7.73478 4 7.48043 4.10536 7.29289 4.29289C7.10536 4.48043 7 4.73478 7 5C7 5.26522 7.10536 5.51957 7.29289 5.70711C7.48043 5.89464 7.73478 6 8 6Z"
- fill={themeContrast(fill)({ theme })}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SeverityMajorIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SeverityMajorIcon.tsx
deleted file mode 100644
index 87f073b5305..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SeverityMajorIcon.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor, themeContrast } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-export function SeverityMajorIcon({ fill = 'iconSeverityMajor', ...iconProps }: IconProps) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <circle cx="8" cy="8" fill={themeColor(fill)({ theme })} r="7" />
- <path
- d="M10.7678 9.5 8 6.73223 5.23223 9.5"
- stroke={themeContrast(fill)({ theme })}
- strokeLinecap="round"
- strokeLinejoin="round"
- strokeWidth="1.5"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SeverityMinorIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SeverityMinorIcon.tsx
deleted file mode 100644
index fa8828169b6..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SeverityMinorIcon.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor, themeContrast } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-export function SeverityMinorIcon({ fill = 'iconSeverityMinor', ...iconProps }: IconProps) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <circle cx="8" cy="8" fill={themeColor(fill)({ theme })} r="7" />
- <path
- d="M5.23223 6.93223L8 9.7L10.7678 6.93223"
- stroke={themeContrast(fill)({ theme })}
- strokeLinecap="round"
- strokeLinejoin="round"
- strokeWidth="1.5"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SnoozeCircleIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SnoozeCircleIcon.tsx
deleted file mode 100644
index 7d8319c664a..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SnoozeCircleIcon.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor, themeContrast } from '../../helpers';
-import { ThemeColors } from '../../types';
-import { CustomIcon, IconProps } from './Icon';
-
-interface SnoozeCircleIconProps extends IconProps {
- color?: ThemeColors;
-}
-
-export function SnoozeCircleIcon(props: Readonly<SnoozeCircleIconProps>) {
- const { color = 'overviewCardWarningIcon', ...rest } = props;
- const theme = useTheme();
-
- const bgColor = themeColor(color)({ theme });
- const iconColor = themeContrast(color)({ theme });
-
- return (
- <CustomIcon height="36" viewBox="0 0 36 36" width="36" {...rest}>
- <circle cx="18" cy="18" fill={bgColor} r="18" />
- <path
- d="M16.5319 17.2149H18.4624L15.7318 20.2936C15.3281 20.7536 15.6658 21.4613 16.2897 21.4613H19.4681C19.8718 21.4613 20.2021 21.1428 20.2021 20.7536C20.2021 20.3643 19.8718 20.0458 19.4681 20.0458H17.5376L20.2682 16.9672C20.6719 16.5072 20.3342 15.7994 19.7103 15.7994H16.5319C16.1282 15.7994 15.7979 16.1179 15.7979 16.5072C15.7979 16.8964 16.1282 17.2149 16.5319 17.2149ZM24.8265 13.9735C24.5696 14.2707 24.1071 14.3132 23.7915 14.0655L21.538 12.2537C21.2297 11.9989 21.1857 11.553 21.4499 11.2558C21.7069 10.9585 22.1693 10.9161 22.4849 11.1638L24.7384 12.9756C25.0467 13.2304 25.0907 13.6762 24.8265 13.9735ZM11.1735 13.9735C11.4304 14.2778 11.8929 14.3132 12.2012 14.0655L14.4546 12.2537C14.7703 11.9989 14.8143 11.553 14.5501 11.2558C14.2931 10.9514 13.8307 10.9161 13.5224 11.1638L11.2616 12.9756C10.9533 13.2304 10.9093 13.6762 11.1735 13.9735ZM18 13.6762C20.8334 13.6762 23.1382 15.8985 23.1382 18.6304C23.1382 21.3622 20.8334 23.5845 18 23.5845C15.1666 23.5845 12.8618 21.3622 12.8618 18.6304C12.8618 15.8985 15.1666 13.6762 18 13.6762ZM18 12.2608C14.3519 12.2608 11.3937 15.1129 11.3937 18.6304C11.3937 22.1478 14.3519 25 18 25C21.6481 25 24.6063 22.1478 24.6063 18.6304C24.6063 15.1129 21.6481 12.2608 18 12.2608Z"
- fill={iconColor}
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityBlockerIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityBlockerIcon.tsx
deleted file mode 100644
index 65451a5ddd6..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityBlockerIcon.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers';
-import { CustomIcon, IconProps } from './Icon';
-
-export function SoftwareImpactSeverityBlockerIcon({
- disabled,
- ...iconProps
-}: IconProps & { disabled?: boolean }) {
- const theme = useTheme();
-
- const color = disabled
- ? 'var(--echoes-color-icon-disabled)'
- : themeColor('iconSoftwareImpactSeverityBlocker')({ theme });
-
- return (
- <CustomIcon viewBox="0 0 14 14" {...iconProps}>
- <path
- clipRule="evenodd"
- d="M7 13.375C10.5208 13.375 13.375 10.5208 13.375 7C13.375 3.47918 10.5208 0.625 7 0.625C3.47918 0.625 0.625 3.47918 0.625 7C0.625 10.5208 3.47918 13.375 7 13.375ZM4 6C3.44772 6 3 6.44772 3 7C3 7.55228 3.44772 8 4 8H10C10.5523 8 11 7.55228 11 7C11 6.44772 10.5523 6 10 6H4Z"
- fill={color}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityHighIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityHighIcon.tsx
deleted file mode 100644
index e9734376f44..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityHighIcon.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers';
-import { CustomIcon, IconProps } from './Icon';
-
-export function SoftwareImpactSeverityHighIcon({
- disabled,
- ...iconProps
-}: IconProps & { disabled?: boolean }) {
- const theme = useTheme();
-
- const color = disabled
- ? 'var(--echoes-color-icon-disabled)'
- : themeColor('iconSoftwareImpactSeverityHigh')({ theme });
-
- return (
- <CustomIcon viewBox="0 0 14 14" {...iconProps}>
- <path
- clipRule="evenodd"
- d="M7 13.375C10.5208 13.375 13.375 10.5208 13.375 7C13.375 3.47918 10.5208 0.625 7 0.625C3.47918 0.625 0.625 3.47918 0.625 7C0.625 10.5208 3.47918 13.375 7 13.375ZM4.3983 5.57213C4.31781 5.61338 4.26697 5.6977 4.26697 5.78993V9.48856C4.26697 9.65858 4.43265 9.77626 4.58796 9.71657L6.91569 8.82188C6.96948 8.80121 7.02875 8.80121 7.08253 8.82188L9.41026 9.71657C9.56557 9.77626 9.73125 9.65858 9.73125 9.48856V5.78993C9.73125 5.6977 9.68041 5.61338 9.59992 5.57213L7.10536 4.29371C7.03847 4.25944 6.95975 4.25944 6.89286 4.29371L4.3983 5.57213Z"
- fill={color}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityInfoIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityInfoIcon.tsx
deleted file mode 100644
index 62490f2c572..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityInfoIcon.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { IconInfo } from '@sonarsource/echoes-react';
-import { IconProps } from './Icon';
-
-const defaultIconSize = 15;
-
-export function SoftwareImpactSeverityInfoIcon({
- disabled,
- ...iconProps
-}: IconProps & { disabled?: boolean }) {
- const color = disabled ? 'echoes-color-icon-disabled' : 'echoes-color-icon-info';
-
- return <StyledIconInfo color={color} {...iconProps} />;
-}
-
-// Info icon is the only one that is imported from echoes, so we need to adjust its size
-const StyledIconInfo = styled(IconInfo)`
- ${(props: IconProps & { disabled?: boolean }) => {
- let size = props.width ?? props.height;
- size = size ? size + 1 : defaultIconSize;
-
- return `
- font-size: ${size}px;
- margin-left: -0.5px;
- `;
- }};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityLowIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityLowIcon.tsx
deleted file mode 100644
index 012f9436b69..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityLowIcon.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers';
-import { CustomIcon, IconProps } from './Icon';
-
-export function SoftwareImpactSeverityLowIcon({
- disabled,
- ...iconProps
-}: IconProps & { disabled?: boolean }) {
- const theme = useTheme();
-
- const color = disabled
- ? 'var(--echoes-color-icon-disabled)'
- : themeColor('iconSoftwareImpactSeverityLow')({ theme });
-
- return (
- <CustomIcon viewBox="0 0 14 14" {...iconProps}>
- <path
- clipRule="evenodd"
- d="M7 13.375C10.5208 13.375 13.375 10.5208 13.375 7C13.375 3.47918 10.5208 0.625 7 0.625C3.47918 0.625 0.625 3.47918 0.625 7C0.625 10.5208 3.47918 13.375 7 13.375ZM3.94899 6.55761L6.46964 9.07825C6.76253 9.37115 7.2374 9.37115 7.5303 9.07825L10.0509 6.55761C10.3438 6.26472 10.3438 5.78984 10.0509 5.49695C9.75805 5.20406 9.28317 5.20406 8.99028 5.49695L6.99997 7.48727L5.00965 5.49695C4.71676 5.20406 4.24188 5.20406 3.94899 5.49695C3.6561 5.78984 3.6561 6.26472 3.94899 6.55761Z"
- fill={color}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityMediumIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityMediumIcon.tsx
deleted file mode 100644
index bcf632761d1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SoftwareImpactSeverityMediumIcon.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers';
-import { CustomIcon, IconProps } from './Icon';
-
-export function SoftwareImpactSeverityMediumIcon({
- disabled,
- ...iconProps
-}: IconProps & { disabled?: boolean }) {
- const theme = useTheme();
-
- const color = disabled
- ? 'var(--echoes-color-icon-disabled)'
- : themeColor('iconSoftwareImpactSeverityMedium')({ theme });
-
- return (
- <CustomIcon viewBox="0 0 14 14" {...iconProps}>
- <path
- clipRule="evenodd"
- d="M7 13.375C10.5208 13.375 13.375 10.5208 13.375 7C13.375 3.47918 10.5208 0.625 7 0.625C3.47918 0.625 0.625 3.47918 0.625 7C0.625 10.5208 3.47918 13.375 7 13.375ZM10.051 7.83547L7.53033 5.31482C7.23744 5.02193 6.76256 5.02193 6.46967 5.31482L3.94903 7.83547C3.65613 8.12836 3.65613 8.60324 3.94903 8.89613C4.24192 9.18902 4.71679 9.18902 5.00969 8.89613L7 6.90581L8.99031 8.89613C9.28321 9.18902 9.75808 9.18902 10.051 8.89613C10.3439 8.60324 10.3439 8.12836 10.051 7.83547Z"
- fill={color}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SortAscendIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SortAscendIcon.tsx
deleted file mode 100644
index 2f85106888e..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SortAscendIcon.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { SortAscIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-export const SortAscendIcon = OcticonHoc(SortAscIcon, 'SortAscendIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/SortDescendIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/SortDescendIcon.tsx
deleted file mode 100644
index 99634592da0..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/SortDescendIcon.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { SortDescIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-export const SortDescendIcon = OcticonHoc(SortDescIcon, 'SortDescendIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/StarFillIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/StarFillIcon.tsx
deleted file mode 100644
index 6fcdd73f8d4..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/StarFillIcon.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { StarFillIcon as OcticonStarFillIcon } from '@primer/octicons-react';
-import { themeColor } from '../../helpers';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconStar with the isFilled prop from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const StarFillIcon = styled(OcticonHoc(OcticonStarFillIcon))`
- // provide a default fill color that is different from the default icon
- fill: ${themeColor('iconFavorite')};
-`;
-
-StarFillIcon.displayName = 'StarFillIcon';
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/StarIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/StarIcon.tsx
deleted file mode 100644
index d3106b1e560..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/StarIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { StarIcon as OcticonStarIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconStar from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const StarIcon = OcticonHoc(OcticonStarIcon, 'StarIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/StatusConfirmedIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/StatusConfirmedIcon.tsx
deleted file mode 100644
index 078e87740e1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/StatusConfirmedIcon.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconStatusConfirmed from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function StatusConfirmedIcon({ fill = 'iconStatus', ...iconProps }: IconProps) {
- const theme = useTheme();
- const fillColor = themeColor(fill)({ theme });
-
- return (
- <CustomIcon {...iconProps}>
- <circle cx="8" cy="8" r="6.25" stroke={fillColor} strokeWidth="1.5" />
- <circle cx="8" cy="8" fill={fillColor} r="2" />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/StatusOpenIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/StatusOpenIcon.tsx
deleted file mode 100644
index f860ed59146..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/StatusOpenIcon.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconStatusOpen from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function StatusOpenIcon({ fill = 'iconStatus', ...iconProps }: IconProps) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <circle cx="8" cy="8" r="6.25" stroke={themeColor(fill)({ theme })} strokeWidth="1.5" />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/StatusReopenedIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/StatusReopenedIcon.tsx
deleted file mode 100644
index 7c42c34f345..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/StatusReopenedIcon.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconStatusReopened from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function StatusReopenedIcon({ fill = 'iconStatus', ...iconProps }: IconProps) {
- const theme = useTheme();
- const fillColor = themeColor(fill)({ theme });
-
- return (
- <CustomIcon {...iconProps}>
- <circle cx="8" cy="8" r="6.25" stroke={fillColor} strokeWidth="1.5" />
- <path
- clipRule="evenodd"
- d="M8 14c3.3137 0 6-2.6863 6-6 0-3.31371-2.6863-6-6-6v12Z"
- fill={fillColor}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/StatusResolvedIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/StatusResolvedIcon.tsx
deleted file mode 100644
index 5a9f9478c96..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/StatusResolvedIcon.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconStatusResolved from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function StatusResolvedIcon({
- fill = 'var(--echoes-color-icon-subdued)',
- ...iconProps
-}: IconProps) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <circle cx="8" cy="8" fill={themeColor(fill)({ theme })} r="7" />
- <path
- clipRule="evenodd"
- d="M11.3105 6.22789c.2884.29737.2811.77219-.0163 1.06054L8.27211 10.25c-.29414.2852-.76273.2816-1.05244-.0081l-2-1.99999c-.29289-.2929-.29289-.76777 0-1.06066.29289-.2929.76777-.2929 1.06066 0L7.7581 8.65901 10.25 6.21158c.2974-.28835.7722-.28105 1.0605.01631Z"
- fill="var(--echoes-color-icon-on-color)"
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/TestFileIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/TestFileIcon.tsx
deleted file mode 100644
index bf5c541f2cd..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/TestFileIcon.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconFileCode from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function TestFileIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
- const theme = useTheme();
- const fillColor = themeColor(fill)({ theme });
-
- return (
- <CustomIcon {...iconProps}>
- <path
- clipRule="evenodd"
- d="M3.75 1.5a.25.25 0 0 0-.25.25v11.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25V6H9.75A1.75 1.75 0 0 1 8 4.25V1.5H3.75Zm5.75.56v2.19c0 .138.112.25.25.25h2.19L9.5 2.06ZM2 1.75C2 .784 2.784 0 3.75 0h5.086c.464 0 .909.184 1.237.513l3.414 3.414c.329.328.513.773.513 1.237v8.086A1.75 1.75 0 0 1 12.25 15h-8.5A1.75 1.75 0 0 1 2 13.25V1.75Z"
- fill={fillColor}
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="M8.605 11.528v-1.514l-.016-1.486.016-1.058 2.544 2.544-2.544 2.544v-1.03ZM7.545 8.5v1.514L7.56 11.5l-.017 1.058L5 10.014 7.544 7.47V8.5Z"
- fill={fillColor}
- fillRule="evenodd"
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/TrashIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/TrashIcon.tsx
deleted file mode 100644
index 63a2eb9ef13..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/TrashIcon.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { TrashIcon as BaseTrashIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-export const TrashIcon = OcticonHoc(BaseTrashIcon);
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/TrendDownCircleIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/TrendDownCircleIcon.tsx
deleted file mode 100644
index a52f1878b68..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/TrendDownCircleIcon.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor, themeContrast } from '../../helpers';
-import { CustomIcon, IconProps } from './Icon';
-
-export function TrendDownCircleIcon(props: Readonly<IconProps>) {
- const theme = useTheme();
-
- const bgColor = themeColor('overviewCardSuccessIcon')({ theme });
- const iconColor = themeContrast('overviewCardSuccessIcon')({ theme });
-
- return (
- <CustomIcon height="36" viewBox="0 0 36 36" width="36" {...props}>
- <circle cx="18" cy="16" fill={bgColor} r="16" />
- <path
- d="M23.3203 20.3404C23.3658 20.3291 23.4095 20.3116 23.4503 20.2886C23.4845 20.2687 23.5158 20.2441 23.5433 20.2156C23.567 20.1872 23.5886 20.157 23.6078 20.1254C23.6375 20.0862 23.6614 20.0428 23.6785 19.9967L23.6922 19.9051C23.7046 19.8587 23.7097 19.8107 23.7072 19.7627L23.6579 19.6389C23.6794 19.5866 23.6912 19.5308 23.6927 19.4743L22.4586 16.3778C22.3931 16.2136 22.2651 16.0821 22.1026 16.0122C21.9402 15.9424 21.7567 15.9399 21.5924 16.0054C21.4282 16.0709 21.2967 16.1989 21.2268 16.3613C21.157 16.5238 21.1545 16.7073 21.22 16.8715L21.9185 18.6241L18.0143 17.3095L18.5396 13.9999C18.5644 13.8431 18.5326 13.6826 18.4497 13.5473C18.3668 13.4119 18.2383 13.3106 18.0874 13.2615L13.1375 11.6461C13.0541 11.6189 12.9662 11.6084 12.8788 11.6152C12.7914 11.622 12.7062 11.646 12.628 11.6858C12.5499 11.7256 12.4804 11.7805 12.4235 11.8472C12.3666 11.9139 12.3234 11.9912 12.2964 12.0746C12.2485 12.2228 12.254 12.3831 12.3119 12.5277C12.348 12.6188 12.4038 12.7007 12.4751 12.7678C12.5465 12.8348 12.6318 12.8853 12.7249 12.9157L17.1303 14.3534L16.599 17.6297C16.5746 17.7848 16.6057 17.9435 16.6868 18.0779C16.7679 18.2123 16.8939 18.3137 17.0425 18.3643L21.1545 19.7683L19.7302 20.336C19.5659 20.4015 19.4344 20.5295 19.3646 20.6919C19.2947 20.8544 19.2923 21.0379 19.3577 21.2021C19.4232 21.3664 19.5512 21.4979 19.7137 21.5677C19.8761 21.6376 20.0596 21.64 20.2238 21.5746L23.3203 20.3404Z"
- fill={iconColor}
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/TrendIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/TrendIcon.tsx
deleted file mode 100644
index 9b0ec6dc79a..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/TrendIcon.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import {
- IconArrowDownRight,
- IconArrowUpRight,
- IconEqual,
- IconProps,
-} from '@sonarsource/echoes-react';
-import { themeColor } from '../../helpers/theme';
-import { CSSColor, ThemeColors } from '../../types';
-
-export const enum TrendDirection {
- Down = 'down',
- Up = 'up',
- Equal = 'equal',
-}
-
-export const enum TrendType {
- Positive = 'positive',
- Negative = 'negative',
- Neutral = 'neutral',
- Disabled = 'disabled',
-}
-
-interface Props extends IconProps {
- direction: TrendDirection;
- type: TrendType;
-}
-
-export function TrendIcon(props: Readonly<Props>) {
- const { direction, type, ...iconProps } = props;
-
- if (direction === TrendDirection.Up) {
- return (
- <TrendIconWrapper trendType={type}>
- <IconArrowUpRight aria-label="trend-up" {...iconProps} />
- </TrendIconWrapper>
- );
- }
-
- if (direction === TrendDirection.Down) {
- return (
- <TrendIconWrapper trendType={type}>
- <IconArrowDownRight aria-label="trend-down" {...iconProps} />
- </TrendIconWrapper>
- );
- }
-
- return (
- <TrendIconWrapper trendType={type}>
- <IconEqual aria-label="trend-equal" {...iconProps} />
- </TrendIconWrapper>
- );
-}
-
-const ICON_COLORS: Record<TrendType, ThemeColors | CSSColor> = {
- [TrendType.Positive]: 'iconTrendPositive',
- [TrendType.Negative]: 'iconTrendNegative',
- [TrendType.Neutral]: 'iconTrendNeutral',
- [TrendType.Disabled]: 'var(--echoes-color-icon-disabled)',
-};
-
-const TrendIconWrapper = styled.span<{
- trendType: TrendType;
-}>`
- color: ${({ trendType }) => themeColor(ICON_COLORS[trendType])};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/TrendUpCircleIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/TrendUpCircleIcon.tsx
deleted file mode 100644
index 89e9077b0a1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/TrendUpCircleIcon.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor, themeContrast } from '../../helpers';
-import { CustomIcon, IconProps } from './Icon';
-
-export function TrendUpCircleIcon(props: Readonly<IconProps>) {
- const theme = useTheme();
-
- const bgColor = themeColor('overviewCardErrorIcon')({ theme });
- const iconColor = themeContrast('overviewCardErrorIcon')({ theme });
-
- return (
- <CustomIcon height="36" viewBox="0 0 36 36" width="36" {...props}>
- <circle cx="18" cy="18" fill={bgColor} r="18" />
- <g clipPath="url(#clip0_2971_11471)">
- <path
- d="M20.8955 12.253C20.7186 12.1492 20.5107 12.1169 20.3175 12.1633C20.1242 12.2096 19.9615 12.3308 19.8652 12.5001C19.7688 12.6695 19.7467 12.8732 19.8036 13.0663C19.8605 13.2595 19.9919 13.4263 20.1688 13.5301L21.7029 14.4305L16.8273 15.1807C16.6524 15.2084 16.4961 15.2967 16.386 15.43C16.276 15.5633 16.2193 15.7331 16.2258 15.9094L16.4151 19.6577L11.2365 20.409C11.1385 20.4231 11.0453 20.4562 10.9621 20.5065C10.879 20.5568 10.8076 20.6233 10.752 20.7022C10.6963 20.7811 10.6576 20.8708 10.6379 20.9662C10.6183 21.0617 10.6181 21.161 10.6374 21.2584C10.6567 21.3559 10.6952 21.4496 10.7505 21.5343C10.8059 21.619 10.877 21.6929 10.96 21.7518C11.0429 21.8108 11.136 21.8537 11.2339 21.8779C11.3318 21.9022 11.4327 21.9075 11.5306 21.8934L17.3493 21.0493C17.5267 21.0238 17.6858 20.9361 17.798 20.802C17.9101 20.668 17.968 20.4964 17.9612 20.3181L17.8022 16.5791L22.3971 15.8686L21.3833 17.6502C21.287 17.8195 21.2648 18.0232 21.3218 18.2163C21.3787 18.4095 21.5101 18.5763 21.687 18.6802C21.8639 18.784 22.0718 18.8163 22.265 18.7699C22.4583 18.7236 22.6209 18.6024 22.7173 18.4331L24.5341 15.2403C24.5768 15.1605 24.6052 15.0735 24.6182 14.983L24.6157 14.8623C24.6171 14.8187 24.6153 14.7749 24.6102 14.7313C24.5971 14.6769 24.576 14.6244 24.5477 14.5753C24.5303 14.5366 24.51 14.4991 24.487 14.4631C24.4598 14.4263 24.4278 14.3931 24.3918 14.3646C24.3477 14.3042 24.293 14.2519 24.2305 14.2103L20.8955 12.253Z"
- fill={iconColor}
- />
- </g>
- <defs>
- <clipPath id="clip0_2971_11471">
- <rect fill="white" height="18" transform="translate(9 9)" width="18" />
- </clipPath>
- </defs>
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/TriangleDownIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/TriangleDownIcon.tsx
deleted file mode 100644
index 2fb7ea858e1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/TriangleDownIcon.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { TriangleDownIcon as Octicon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-export const TriangleDownIcon = OcticonHoc(Octicon);
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/TriangleLeftIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/TriangleLeftIcon.tsx
deleted file mode 100644
index 53ec906cea1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/TriangleLeftIcon.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { TriangleLeftIcon as Octicon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-export const TriangleLeftIcon = OcticonHoc(Octicon);
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/TriangleRightIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/TriangleRightIcon.tsx
deleted file mode 100644
index 386af1e5adc..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/TriangleRightIcon.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { TriangleRightIcon as Octicon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-export const TriangleRightIcon = OcticonHoc(Octicon);
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/TriangleUpIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/TriangleUpIcon.tsx
deleted file mode 100644
index 36dcff58a32..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/TriangleUpIcon.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { TriangleUpIcon as Octicon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-export const TriangleUpIcon = OcticonHoc(Octicon);
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/UnfoldDownIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/UnfoldDownIcon.tsx
deleted file mode 100644
index 4ab6276fd90..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/UnfoldDownIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FoldDownIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconUnfoldDown from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const UnfoldDownIcon = OcticonHoc(FoldDownIcon, 'UnfoldDownIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/UnfoldIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/UnfoldIcon.tsx
deleted file mode 100644
index 7bf4b7277bd..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/UnfoldIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { UnfoldIcon as OcticonUnfoldIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconUnfold from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const UnfoldIcon = OcticonHoc(OcticonUnfoldIcon, 'UnfoldIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/UnfoldUpIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/UnfoldUpIcon.tsx
deleted file mode 100644
index 02f7bab9e4c..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/UnfoldUpIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { FoldUpIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconUnfoldUp from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const UnfoldUpIcon = OcticonHoc(FoldUpIcon, 'UnfoldUpIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/UserGroupIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/UserGroupIcon.tsx
deleted file mode 100644
index 8c4b4a7e6e9..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/UserGroupIcon.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { PeopleIcon } from '@primer/octicons-react';
-import { OcticonHoc } from './Icon';
-
-/** @deprecated Use IconPeople from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export const UserGroupIcon = OcticonHoc(PeopleIcon, 'UserGroupIcon');
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/VulnerabilityIcon.tsx b/server/sonar-web/src/main/js/design-system/components/icons/VulnerabilityIcon.tsx
deleted file mode 100644
index eda4bbad453..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/VulnerabilityIcon.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-import { CustomIcon, IconProps } from './Icon';
-
-/** @deprecated Use IconVulnerability from Echoes instead, if possible.
- *
- * Be aware that the full icon set is not yet available in Echoes, and therefore you may not be able
- * to replace all of the icons yet. There are situations where it is OK to ignore this deprecation
- * warning when revisiting old code, but all new code should use the icons from Echoes.
- */
-export function VulnerabilityIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
- const theme = useTheme();
-
- return (
- <CustomIcon {...iconProps}>
- <path
- d="M12,7.05H6V5a2,2,0,1,1,4,0,1,1,0,0,0,2,0A4,4,0,1,0,4,5V7.06A1.12,1.12,0,0,0,3,8.17V14a1.12,1.12,0,0,0,1.12,1.12H12A1.12,1.12,0,0,0,13.1,14V8.17A1.12,1.12,0,0,0,12,7.05ZM8,13a2,2,0,1,1,2-2A2,2,0,0,1,8,13Z"
- fill={themeColor(fill)({ theme })}
- />
- </CustomIcon>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/__tests__/Icon-test.tsx b/server/sonar-web/src/main/js/design-system/components/icons/__tests__/Icon-test.tsx
deleted file mode 100644
index 875785a5e99..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/__tests__/Icon-test.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CheckIcon } from '@primer/octicons-react';
-import { screen } from '@testing-library/react';
-import { render } from '../../../helpers/testUtils';
-import { CustomIcon, OcticonHoc } from '../Icon';
-
-it('should render custom icon correctly', () => {
- render(
- <CustomIcon>
- <path d="test" />
- </CustomIcon>,
- );
-
- expect(screen.queryByRole('img')).not.toBeInTheDocument();
- expect(screen.getByRole('img', { hidden: true })).toContainHTML('<path d="test"/>');
-});
-
-it('should not be hidden when aria-label is set', () => {
- render(
- <CustomIcon aria-label="test">
- <path d="test" />
- </CustomIcon>,
- );
-
- expect(screen.getByRole('img')).toBeVisible();
-});
-
-describe('Octicon HOC', () => {
- it('should render correctly', () => {
- const Wrapped = OcticonHoc(CheckIcon, 'TestIcon');
-
- render(<Wrapped aria-label="visible" />);
-
- expect(screen.getByRole('img')).toBeVisible();
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/icons/index.ts b/server/sonar-web/src/main/js/design-system/components/icons/index.ts
deleted file mode 100644
index 45d0a0c4ff9..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/icons/index.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export { AddNewIcon } from './AddNewIcon';
-export { BranchIcon } from './BranchIcon';
-export { BugIcon } from './BugIcon';
-export { CalendarIcon } from './CalendarIcon';
-export { CheckIcon } from './CheckIcon';
-export { ChevronDownIcon } from './ChevronDownIcon';
-export { ChevronLeftIcon } from './ChevronLeftIcon';
-export { ChevronRightIcon } from './ChevronRightIcon';
-export { ClockIcon } from './ClockIcon';
-export { CloseIcon } from './CloseIcon';
-export { CodeEllipsisDirection, CodeEllipsisIcon } from './CodeEllipsisIcon';
-export { CodeSmellIcon } from './CodeSmellIcon';
-export { CollapseIcon } from './CollapseIcon';
-export { CommentIcon } from './CommentIcon';
-export { CopyIcon } from './CopyIcon';
-export { DirectoryIcon } from './DirectoryIcon';
-export { DotFillIcon } from './DotFillIcon';
-export { DraggableIcon } from './DraggableIcon';
-export { ExecutionFlowIcon } from './ExecutionFlowIcon';
-export { ExpandIcon } from './ExpandIcon';
-export { FileIcon } from './FileIcon';
-export { FilterIcon } from './FilterIcon';
-export { FlagErrorIcon } from './FlagErrorIcon';
-export { FlagInfoIcon } from './FlagInfoIcon';
-export { FlagSuccessIcon } from './FlagSuccessIcon';
-export { FlagWarningIcon } from './FlagWarningIcon';
-export { HelperHintIcon } from './HelperHintIcon';
-export { HomeFillIcon } from './HomeFillIcon';
-export { HomeIcon } from './HomeIcon';
-export * from './Icon';
-export { InheritanceIcon } from './InheritanceIcon';
-export { InProgressVisual } from './InProgressVisual';
-export { IssueLocationIcon } from './IssueLocationIcon';
-export { LinkIcon } from './LinkIcon';
-export { LockIcon } from './LockIcon';
-export { MainBranchIcon } from './MainBranchIcon';
-export { MenuHelpIcon } from './MenuHelpIcon';
-export { MenuIcon } from './MenuIcon';
-export { MenuSearchIcon } from './MenuSearchIcon';
-export { MinimizeIcon } from './MinimizeIcon';
-export { NoDataIcon } from './NoDataIcon';
-export { OpenCloseIndicator } from './OpenCloseIndicator';
-export { OpenNewTabIcon } from './OpenNewTabIcon';
-export { OverridenIcon } from './OverridenIcon';
-export { OverviewQGNotComputedIcon } from './OverviewQGNotComputedIcon';
-export { OverviewQGPassedIcon } from './OverviewQGPassedIcon';
-export { PencilIcon } from './PencilIcon';
-export { PinIcon } from './PinIcon';
-export { ProjectIcon } from './ProjectIcon';
-export { PullRequestIcon } from './PullRequestIcon';
-export { QualifierIcon } from './QualifierIcon';
-export { RequiredIcon } from './RequiredIcon';
-export { SecurityHotspotIcon } from './SecurityHotspotIcon';
-export { SeparatorCircleIcon } from './SeparatorCircleIcon';
-export { SeverityBlockerIcon } from './SeverityBlockerIcon';
-export { SeverityCriticalIcon } from './SeverityCriticalIcon';
-export { SeverityInfoIcon } from './SeverityInfoIcon';
-export { SeverityMajorIcon } from './SeverityMajorIcon';
-export { SeverityMinorIcon } from './SeverityMinorIcon';
-export { SnoozeCircleIcon } from './SnoozeCircleIcon';
-export { SoftwareImpactSeverityBlockerIcon } from './SoftwareImpactSeverityBlockerIcon';
-export { SoftwareImpactSeverityHighIcon } from './SoftwareImpactSeverityHighIcon';
-export { SoftwareImpactSeverityInfoIcon } from './SoftwareImpactSeverityInfoIcon';
-export { SoftwareImpactSeverityLowIcon } from './SoftwareImpactSeverityLowIcon';
-export { SoftwareImpactSeverityMediumIcon } from './SoftwareImpactSeverityMediumIcon';
-export { SortAscendIcon } from './SortAscendIcon';
-export { SortDescendIcon } from './SortDescendIcon';
-export { StarFillIcon } from './StarFillIcon';
-export { StarIcon } from './StarIcon';
-export { StatusConfirmedIcon } from './StatusConfirmedIcon';
-export { StatusOpenIcon } from './StatusOpenIcon';
-export { StatusReopenedIcon } from './StatusReopenedIcon';
-export { StatusResolvedIcon } from './StatusResolvedIcon';
-export { TestFileIcon } from './TestFileIcon';
-export { TrashIcon } from './TrashIcon';
-export { TrendDownCircleIcon } from './TrendDownCircleIcon';
-export { TrendDirection, TrendIcon, TrendType } from './TrendIcon';
-export { TrendUpCircleIcon } from './TrendUpCircleIcon';
-export { TriangleDownIcon } from './TriangleDownIcon';
-export { TriangleLeftIcon } from './TriangleLeftIcon';
-export { TriangleRightIcon } from './TriangleRightIcon';
-export { TriangleUpIcon } from './TriangleUpIcon';
-export { UnfoldDownIcon } from './UnfoldDownIcon';
-export { UnfoldIcon } from './UnfoldIcon';
-export { UnfoldUpIcon } from './UnfoldUpIcon';
-export { UserGroupIcon } from './UserGroupIcon';
-export { VulnerabilityIcon } from './VulnerabilityIcon';
diff --git a/server/sonar-web/src/main/js/design-system/components/index.ts b/server/sonar-web/src/main/js/design-system/components/index.ts
deleted file mode 100644
index 8d7292db47b..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/index.ts
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './Accordion';
-export * from './avatar/Avatar';
-export * from './avatar/GenericAvatar';
-export { Badge } from './Badge';
-export * from './Banner';
-export { BarChart } from './BarChart';
-export * from './BorderlessAccordion';
-export { Breadcrumbs } from './Breadcrumbs';
-export * from './BubbleChart';
-export * from './buttons';
-export { ClipboardButton, ClipboardIconButton } from './clipboard';
-export * from './code-line/LineCoverage';
-export * from './code-line/LineFinding';
-export * from './code-line/LineIssuesIndicatorIcon';
-export * from './code-line/LineMarker';
-export * from './code-line/LineNumber';
-export * from './code-line/LineStyles';
-export * from './code-line/LineToken';
-export * from './code-line/LineWrapper';
-export * from './CodeSnippet';
-export * from './CodeSyntaxHighlighter';
-export * from './ColorsLegend';
-export * from './CoverageIndicator';
-export * from './DonutChart';
-export { Dropdown } from './Dropdown';
-export * from './DropdownMenu';
-export { DropdownToggler } from './DropdownToggler';
-export * from './DuplicationsIndicator';
-export * from './ExecutionFlowAccordion';
-export * from './FacetBox';
-export * from './FacetItem';
-export { FailedQGConditionLink } from './FailedQGConditionLink';
-export * from './FavoriteButton';
-export * from './FlowStep';
-export * from './HighlightedSection';
-export * from './HighlightRing';
-export { Histogram } from './Histogram';
-export { HotspotRating } from './HotspotRating';
-export * from './HtmlFormatter';
-export * from './icons';
-export { IllustratedSelectionCard } from './IlllustredSelectionCard';
-export * from './input';
-export * from './InteractiveIcon';
-export * from './IssueMessageHighlighting';
-export * from './KeyboardHint';
-export * from './layouts';
-export * from './Link';
-export { StandoutLink as Link } from './Link';
-export * from './lists';
-export * from './LocationMarker';
-export * from './MainAppBar';
-export * from './MainMenu';
-export * from './MainMenuItem';
-export * from './modal/Modal';
-export * from './MultiSelector';
-export * from './NavBarTabs';
-export * from './NewCodeLegend';
-export * from './OutsideClickHandler';
-export * from './Pill';
-export * from './popups';
-export { QualityGateIndicator } from './QualityGateIndicator';
-export * from './SearchHighlighter';
-export * from './SelectionCard';
-export * from './Separator';
-export * from './SizeIndicator';
-export * from './SonarCodeColorizer';
-export * from './SonarQubeLogo';
-export { Spinner } from './Spinner';
-export * from './SpotlightTour';
-export * from './subnavigation';
-export * from './Switch';
-export * from './Tabs';
-export * from './Tags';
-export * from './Text';
-export * from './TextAccordion';
-export * from './toast-message/toast-utils';
-export { ToastMessageContainer } from './toast-message/ToastMessage';
-export { TopBar } from './TopBar';
-export * from './TreeMap';
-export * from './TreeMapRect';
-export * from './TutorialStep';
-export * from './TutorialStepList';
-export * from './visual-components';
diff --git a/server/sonar-web/src/main/js/design-system/components/input/Checkbox.tsx b/server/sonar-web/src/main/js/design-system/components/input/Checkbox.tsx
deleted file mode 100644
index be242079268..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/Checkbox.tsx
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import React from 'react';
-import tw from 'twin.macro';
-import { themeBorder, themeColor, themeContrast } from '../../helpers/theme';
-import { CheckIcon } from '../icons/CheckIcon';
-import { CustomIcon } from '../icons/Icon';
-import { Spinner } from '../Spinner';
-
-interface Props {
- checked: boolean;
- children?: React.ReactNode;
- className?: string;
- disabled?: boolean;
- id?: string;
- label?: string;
- loading?: boolean;
- onCheck: (checked: boolean, id?: string) => void;
- onClick?: (event: React.MouseEvent<HTMLLabelElement>) => void;
- onFocus?: VoidFunction;
- right?: boolean;
- thirdState?: boolean;
- title?: string;
-}
-
-/** @deprecated Use Checkbox from Echoes instead.
- *
- * Some of the props have changed or been renamed:
- * - ~`aria-disabled`~ is now inferred from `isDisabled`
- * - `ariaLabel` is now mandatory in the absence of `label`
- * - ~`children`~ has been removed
- * - `disabled` is now `isDisabled`
- * - `label` is no longer used in the aria-label but displayed next to the checkbox
- * - `loading` is now `isLoading`
- * - ~`onClick`~ has been removed
- * - ~`right`~ has been removed
- * - `thirdState` is now represented by the `indeterminate` value of the `checked` prop
- */
-export function Checkbox({
- checked,
- disabled,
- children,
- className,
- id,
- label,
- loading = false,
- onCheck,
- onFocus,
- onClick,
- right,
- thirdState = false,
- title,
-}: Props) {
- const handleChange = () => {
- if (!disabled) {
- onCheck(!checked, id);
- }
- };
-
- return (
- <CheckboxContainer className={className} disabled={disabled} onClick={onClick}>
- {right && children}
- <AccessibleCheckbox
- aria-label={label ?? title}
- checked={checked}
- disabled={disabled ?? loading}
- id={id}
- onChange={handleChange}
- onFocus={onFocus}
- type="checkbox"
- />
- <Spinner loading={loading}>
- <StyledCheckbox aria-hidden data-clickable="true" title={title}>
- <CheckboxIcon checked={checked} thirdState={thirdState} />
- </StyledCheckbox>
- </Spinner>
- {!right && children}
- </CheckboxContainer>
- );
-}
-
-interface CheckIconProps {
- checked?: boolean;
- thirdState?: boolean;
-}
-
-function CheckboxIcon({ checked, thirdState }: CheckIconProps) {
- if (checked && thirdState) {
- return (
- <CustomIcon>
- <rect fill="currentColor" height="2" rx="1" width="50%" x="4" y="7" />
- </CustomIcon>
- );
- } else if (checked) {
- return <CheckIcon fill="buttonSecondary" />;
- }
- return null;
-}
-
-const CheckboxContainer = styled.label<{ disabled?: boolean }>`
- color: ${themeContrast('backgroundSecondary')};
- user-select: none;
-
- ${tw`sw-inline-flex sw-items-center`};
-
- &:hover {
- ${tw`sw-cursor-pointer`}
- }
-
- &:disabled {
- color: ${themeContrast('checkboxDisabled')};
- ${tw`sw-cursor-not-allowed`}
- }
-`;
-
-export const StyledCheckbox = styled.span`
- border: ${themeBorder('default', 'primary')};
- color: ${themeContrast('primary')};
-
- ${tw`sw-w-4 sw-h-4`};
- ${tw`sw-rounded-1/2`};
- ${tw`sw-box-border`}
- ${tw`sw-inline-flex sw-items-center sw-justify-center`};
-`;
-
-export const AccessibleCheckbox = styled.input`
- // Following css makes the checkbox accessible and invisible
- border: 0;
- clip: rect(0 0 0 0);
- clip-path: inset(50%);
- height: 1px;
- overflow: hidden;
- padding: 0;
- white-space: nowrap;
- width: 1px;
- appearance: none;
-
- &:focus,
- &:active {
- &:not(:disabled) ~ ${StyledCheckbox} {
- outline: ${themeBorder('focus', 'primary')};
- }
- }
-
- &:checked {
- & ~ ${StyledCheckbox} {
- background: ${themeColor('primary')};
- }
- &:disabled ~ ${StyledCheckbox} {
- background: ${themeColor('checkboxDisabledChecked')};
- }
- }
-
- &:hover {
- &:not(:disabled) ~ ${StyledCheckbox} {
- background: ${themeColor('checkboxHover')};
- border: ${themeBorder('default', 'primary')};
- }
-
- &:checked:not(:disabled) ~ ${StyledCheckbox} {
- background: ${themeColor('checkboxCheckedHover')};
- border: ${themeBorder('default', 'checkboxCheckedHover')};
- }
- }
-
- &:disabled ~ ${StyledCheckbox} {
- background: ${themeColor('checkboxDisabled')};
- color: ${themeColor('checkboxDisabled')};
- border: ${themeBorder('default', 'checkboxDisabledChecked')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/input/DatePicker.tsx b/server/sonar-web/src/main/js/design-system/components/input/DatePicker.tsx
deleted file mode 100644
index c4df4f6861a..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/DatePicker.tsx
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { format } from 'date-fns';
-import * as React from 'react';
-import { ActiveModifiers, Matcher, DayPicker as OriginalDayPicker } from 'react-day-picker';
-import tw from 'twin.macro';
-import { PopupPlacement, PopupZLevel, themeBorder, themeColor, themeContrast } from '../../helpers';
-import { InputSizeKeys } from '../../types/theme';
-import EscKeydownHandler from '../EscKeydownHandler';
-import { FocusOutHandler } from '../FocusOutHandler';
-import { InteractiveIcon } from '../InteractiveIcon';
-import { OutsideClickHandler } from '../OutsideClickHandler';
-import { CalendarIcon } from '../icons';
-import { CloseIcon } from '../icons/CloseIcon';
-import { Popup } from '../popups';
-import { CustomCalendarNavigation } from './DatePickerCustomCalendarNavigation';
-import { InputField } from './InputField';
-
-// When no minDate is given, year dropdown will show year options up to PAST_MAX_YEARS in the past
-const YEARS_TO_DISPLAY = 10;
-
-interface Props {
- alignRight?: boolean;
- className?: string;
- clearButtonLabel: string;
- currentMonth?: Date;
- highlightFrom?: Date;
- highlightTo?: Date;
- id?: string;
- inputClassName?: string;
- inputRef?: React.Ref<HTMLInputElement>;
- maxDate?: Date;
- minDate?: Date;
- name?: string;
- onChange: (date: Date | undefined) => void;
- placeholder: string;
- showClearButton?: boolean;
- size?: InputSizeKeys;
- value?: Date;
- valueFormatter?: (date?: Date) => string;
- zLevel?: PopupZLevel;
-}
-
-interface State {
- currentMonth: Date;
- lastHovered?: Date;
- open: boolean;
-}
-
-function formatWeekdayName(date: Date) {
- return format(date, 'EEE'); // Short weekday name, e.g. Wed, Thu
-}
-
-export class DatePicker extends React.PureComponent<Props, State> {
- constructor(props: Props) {
- super(props);
-
- this.state = { currentMonth: props.value ?? props.currentMonth ?? new Date(), open: false };
- }
-
- handleResetClick = () => {
- this.closeCalendar();
- this.props.onChange(undefined);
- };
-
- openCalendar = () => {
- this.setState({
- currentMonth: this.props.value ?? this.props.currentMonth ?? new Date(),
- lastHovered: undefined,
- open: true,
- });
- };
-
- closeCalendar = () => {
- this.setState({ open: false });
- };
-
- handleDayClick = (day: Date, modifiers: ActiveModifiers) => {
- if (!modifiers.disabled) {
- this.closeCalendar();
- this.props.onChange(day);
- }
- };
-
- handleDayMouseEnter = (day: Date, modifiers: ActiveModifiers) => {
- this.setState({ lastHovered: modifiers.disabled ? undefined : day });
- };
-
- render() {
- const {
- alignRight,
- clearButtonLabel,
- highlightFrom,
- highlightTo,
- inputRef,
- minDate,
- maxDate = new Date(),
- value: selectedDay,
- name,
- className,
- inputClassName,
- id,
- placeholder,
- showClearButton = true,
- valueFormatter = (date?: Date) => (date ? format(date, 'MMM d, yyyy') : ''),
- size,
- zLevel = PopupZLevel.Global,
- } = this.props;
- const { lastHovered, currentMonth, open } = this.state;
-
- // Infer start and end dropdown year from min/max dates, if set
- const fromYear = minDate ? minDate.getFullYear() : new Date().getFullYear() - YEARS_TO_DISPLAY;
- const toYear = maxDate.getFullYear();
-
- const selectedDays = selectedDay ? [selectedDay] : [];
- let highlighted: Matcher = false;
- const lastHoveredOrValue = lastHovered ?? selectedDay;
-
- if (highlightFrom && lastHoveredOrValue) {
- highlighted = { from: highlightFrom, to: lastHoveredOrValue };
- selectedDays.push(highlightFrom);
- }
-
- if (highlightTo && lastHoveredOrValue) {
- highlighted = { from: lastHoveredOrValue, to: highlightTo };
- selectedDays.push(highlightTo);
- }
-
- return (
- <OutsideClickHandler onClickOutside={this.closeCalendar}>
- <FocusOutHandler onFocusOut={this.closeCalendar}>
- <EscKeydownHandler onKeydown={this.closeCalendar}>
- <Popup
- allowResizing
- className="sw-overflow-visible" //Necessary for the month & year selectors
- overlay={
- open ? (
- <div className={classNames('sw-p-2')}>
- <DayPicker
- captionLayout="dropdown-buttons"
- className="sw-typo-default"
- components={{
- Caption: CustomCalendarNavigation,
- }}
- disabled={{ after: maxDate, before: minDate }}
- formatters={{
- formatWeekdayName,
- }}
- fromYear={fromYear}
- mode="default"
- modifiers={{ highlighted }}
- modifiersClassNames={{ highlighted: 'rdp-highlighted' }}
- month={currentMonth}
- onDayClick={this.handleDayClick}
- onDayMouseEnter={this.handleDayMouseEnter}
- onMonthChange={(currentMonth) => {
- this.setState({ currentMonth });
- }}
- selected={selectedDays}
- toYear={toYear}
- weekStartsOn={1}
- />
- </div>
- ) : null
- }
- placement={alignRight ? PopupPlacement.BottomRight : PopupPlacement.BottomLeft}
- zLevel={zLevel}
- >
- <span
- className={classNames('sw-relative sw-inline-block sw-cursor-pointer', className)}
- >
- <StyledInputField
- aria-label={placeholder}
- className={classNames(inputClassName, {
- 'is-filled': selectedDay !== undefined && showClearButton,
- })}
- id={id}
- name={name}
- onClick={this.openCalendar}
- onFocus={this.openCalendar}
- placeholder={placeholder}
- readOnly
- ref={inputRef}
- size={size}
- title={valueFormatter(selectedDay)}
- type="text"
- value={valueFormatter(selectedDay)}
- />
-
- <StyledCalendarIcon fill="datePickerIcon" />
-
- {selectedDay !== undefined && showClearButton && (
- <StyledInteractiveIcon
- Icon={CloseIcon}
- aria-label={clearButtonLabel}
- onClick={this.handleResetClick}
- size="small"
- />
- )}
- </span>
- </Popup>
- </EscKeydownHandler>
- </FocusOutHandler>
- </OutsideClickHandler>
- );
- }
-}
-
-const StyledCalendarIcon = styled(CalendarIcon)`
- ${tw`sw-absolute`};
- ${tw`sw-top-[0.625rem] sw-left-2`};
-`;
-
-const StyledInteractiveIcon = styled(InteractiveIcon)`
- ${tw`sw-absolute`};
- ${tw`sw-top-[0.375rem] sw-right-[0.375rem]`};
-`;
-
-const StyledInputField = styled(InputField)`
- ${tw`sw-pl-8`};
- ${tw`sw-cursor-pointer`};
-
- &.is-filled {
- ${tw`sw-pr-8`};
- }
-`;
-
-const DayPicker = styled(OriginalDayPicker)`
- --rdp-cell-size: auto;
- /* Ensures the month/year dropdowns do not move on click, but rdp outline is not shown */
- --rdp-outline: 2px solid transparent;
- --rdp-outline-selected: 2px solid transparent;
-
- margin: 0;
-
- .rdp-head {
- color: ${themeContrast('datePicker')};
- }
-
- .rdp-day {
- height: 28px;
- width: 33px;
- border-radius: 0;
- color: ${themeContrast('datePickerDefault')};
- }
-
- /* Default modifiers */
-
- .rdp-day_disabled {
- cursor: not-allowed;
- background: ${themeColor('datePickerDisabled')};
- color: ${themeContrast('datePickerDisabled')};
- }
-
- .rdp-day:hover:not(.rdp-day_outside):not(.rdp-day_disabled):not(.rdp-day_selected) {
- background: ${themeColor('datePickerHover')};
- color: ${themeContrast('datePickerHover')};
- }
-
- .rdp-day:focus-visible {
- outline: ${themeBorder('focus', 'inputFocus')};
- background: inherit;
- z-index: 1;
- }
-
- .rdp-day.rdp-highlighted:not(.rdp-day_selected) {
- background: ${themeColor('datePickerRange')};
- color: ${themeContrast('datePickerRange')};
- }
-
- .rdp-day_selected,
- .rdp-day_selected:focus-visible {
- background: ${themeColor('datePickerSelected')};
- color: ${themeContrast('datePickerSelected')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/input/DatePickerCustomCalendarNavigation.tsx b/server/sonar-web/src/main/js/design-system/components/input/DatePickerCustomCalendarNavigation.tsx
deleted file mode 100644
index 1ac08f07ceb..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/DatePickerCustomCalendarNavigation.tsx
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- format,
- getYear,
- isSameMonth,
- isSameYear,
- setMonth,
- setYear,
- startOfMonth,
-} from 'date-fns';
-import { range } from 'lodash';
-import {
- CaptionProps,
- useNavigation as useCalendarNavigation,
- useDayPicker,
-} from 'react-day-picker';
-import { useIntl } from 'react-intl';
-import { InputSelect } from '../../sonar-aligned/components/input';
-import { InteractiveIcon } from '../InteractiveIcon';
-import { ChevronLeftIcon, ChevronRightIcon } from '../icons';
-
-const YEARS_TO_DISPLAY = 10;
-const MONTHS_IN_A_YEAR = 12;
-
-export function CustomCalendarNavigation(props: CaptionProps) {
- const { displayMonth } = props;
- const { fromYear, toYear } = useDayPicker();
- const { goToMonth, nextMonth, previousMonth } = useCalendarNavigation();
-
- const intl = useIntl();
-
- const formatChevronLabel = (date?: Date) => {
- if (date === undefined) {
- return intl.formatMessage({ id: 'disabled_' });
- }
- return `${intl.formatDate(date, { month: 'long' })} ${intl.formatDate(date, {
- year: 'numeric',
- })}`;
- };
-
- const baseDate = startOfMonth(displayMonth); // reference date
-
- const months = range(MONTHS_IN_A_YEAR).map((month) => {
- const monthValue = setMonth(baseDate, month);
-
- return {
- label: format(monthValue, 'MMM'),
- value: monthValue,
- };
- });
-
- const startYear = fromYear ?? getYear(Date.now()) - YEARS_TO_DISPLAY;
-
- const years = range(startYear, toYear ? toYear + 1 : undefined).map((year) => {
- const yearValue = setYear(baseDate, year);
-
- return {
- label: String(year),
- value: yearValue,
- };
- });
-
- return (
- <nav className="sw-flex sw-items-center sw-justify-between sw-py-1">
- <InteractiveIcon
- Icon={ChevronLeftIcon}
- aria-label={intl.formatMessage(
- { id: 'previous_month_x' },
- { month: formatChevronLabel(previousMonth) },
- )}
- className="sw-mr-2"
- disabled={previousMonth === undefined}
- onClick={() => {
- if (previousMonth) {
- goToMonth(previousMonth);
- }
- }}
- size="small"
- />
-
- <span data-testid="month-select">
- <InputSelect
- isClearable={false}
- onChange={(value) => {
- if (value) {
- goToMonth(value.value);
- }
- }}
- options={months}
- size="full"
- value={months.find((m) => isSameMonth(m.value, displayMonth))}
- />
- </span>
-
- <span data-testid="year-select">
- <InputSelect
- className="sw-ml-1"
- data-testid="year-select"
- isClearable={false}
- onChange={(value) => {
- if (value) {
- goToMonth(value.value);
- }
- }}
- options={years}
- size="full"
- value={years.find((y) => isSameYear(y.value, displayMonth))}
- />
- </span>
-
- <InteractiveIcon
- Icon={ChevronRightIcon}
- aria-label={intl.formatMessage(
- { id: 'next_month_x' },
- {
- month: formatChevronLabel(nextMonth),
- },
- )}
- className="sw-ml-2"
- disabled={nextMonth === undefined}
- onClick={() => {
- if (nextMonth) {
- goToMonth(nextMonth);
- }
- }}
- size="small"
- />
- </nav>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/DateRangePicker.tsx b/server/sonar-web/src/main/js/design-system/components/input/DateRangePicker.tsx
deleted file mode 100644
index 316a45d7df1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/DateRangePicker.tsx
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { max, min } from 'date-fns';
-import * as React from 'react';
-import { PopupZLevel } from '../../helpers';
-import { InputSizeKeys } from '../../types';
-import { LightLabel } from '../Text';
-import { DatePicker } from './DatePicker';
-
-interface DateRange {
- from?: Date;
- to?: Date;
-}
-
-interface Props {
- alignEndDateCalandarRight?: boolean;
- className?: string;
- endClearButtonLabel: string;
- fromLabel: string;
- inputSize?: InputSizeKeys;
- maxDate?: Date;
- minDate?: Date;
- onChange: (date: DateRange) => void;
- separatorText?: string;
- startClearButtonLabel: string;
- toLabel: string;
- value?: DateRange;
- valueFormatter?: (date?: Date) => string;
- zLevel?: PopupZLevel;
-}
-
-export class DateRangePicker extends React.PureComponent<Props> {
- toDateInput?: HTMLInputElement | null;
-
- get from() {
- return this.props.value?.from;
- }
-
- get to() {
- return this.props.value?.to;
- }
-
- handleFromChange = (from: Date | undefined) => {
- this.props.onChange({ from, to: this.to });
-
- // use `setTimeout` to work around the immediate closing of the `toDateInput`
- setTimeout(() => {
- if (from && !this.to && this.toDateInput) {
- this.toDateInput.focus();
- }
- }, 0);
- };
-
- handleToChange = (to: Date | undefined) => {
- this.props.onChange({ from: this.from, to });
- };
-
- render() {
- const {
- alignEndDateCalandarRight,
- startClearButtonLabel,
- endClearButtonLabel,
- fromLabel,
- inputSize = 'full',
- minDate,
- maxDate,
- separatorText,
- toLabel,
- valueFormatter,
- zLevel,
- } = this.props;
-
- return (
- <div className={classNames('sw-flex sw-items-center', this.props.className)}>
- <DatePicker
- clearButtonLabel={startClearButtonLabel}
- currentMonth={this.to}
- data-test="from"
- highlightTo={this.to}
- id="date-from"
- maxDate={maxDate && this.to ? min([maxDate, this.to]) : (maxDate ?? this.to)}
- minDate={minDate}
- onChange={this.handleFromChange}
- placeholder={fromLabel}
- size={inputSize}
- value={this.from}
- valueFormatter={valueFormatter}
- zLevel={zLevel}
- />
- <LightLabel className="sw-mx-2">{separatorText ?? '–'}</LightLabel>
- <DatePicker
- alignRight={alignEndDateCalandarRight}
- clearButtonLabel={endClearButtonLabel}
- currentMonth={this.from}
- data-test="to"
- highlightFrom={this.from}
- id="date-to"
- inputRef={(element: HTMLInputElement | null) => {
- this.toDateInput = element;
- }}
- maxDate={maxDate}
- minDate={minDate && this.from ? max([minDate, this.from]) : (minDate ?? this.from)}
- onChange={this.handleToChange}
- placeholder={toLabel}
- size={inputSize}
- value={this.to}
- valueFormatter={valueFormatter}
- zLevel={zLevel}
- />
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/DiscreetSelect.tsx b/server/sonar-web/src/main/js/design-system/components/input/DiscreetSelect.tsx
deleted file mode 100644
index bea14a8c309..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/DiscreetSelect.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { GroupBase, OnChangeValue } from 'react-select';
-import tw from 'twin.macro';
-import { themeBorder, themeColor, themeContrast } from '../../helpers/theme';
-import { InputSelect, SelectProps } from '../../sonar-aligned/components/input';
-
-type DiscreetProps<
- Option,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
-> = SelectProps<Option, IsMulti, Group> & {
- customValue?: JSX.Element;
- setValue: (value: OnChangeValue<Option, IsMulti>) => void;
-};
-
-/**
- * @deprecated Use Select or SelectAsync from Echoes instead, and use the SelectHighlight.Ghost highlight property.
- *
- * See the [Migration Guide](https://xtranet-sonarsource.atlassian.net/wiki/x/K4AYxw)
- */
-export function DiscreetSelect<
- Option,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
->({ customValue, size = 'small', setValue, ...props }: DiscreetProps<Option, IsMulti, Group>) {
- return (
- <StyledSelect<Option, IsMulti, Group>
- onChange={setValue}
- placeholder={customValue}
- size={size}
- {...props}
- />
- );
-}
-
-const StyledSelect = styled(InputSelect)`
- & {
- width: inherit !important;
- }
-
- & .react-select__dropdown-indicator {
- ${tw`sw-p-0 sw-py-1`};
- }
-
- & .react-select__value-container {
- ${tw`sw-p-0`};
- }
-
- & .react-select__menu {
- margin: 0;
- }
-
- & .react-select__control {
- height: auto;
- min-height: inherit;
- color: ${themeContrast('discreetBackground')};
- background: none;
- outline: inherit;
- box-shadow: none;
-
- ${tw`sw-border-none`};
- ${tw`sw-p-0`};
- ${tw`sw-cursor-pointer`};
- ${tw`sw-flex sw-items-center`};
- ${tw`sw-typo-default`};
- ${tw`sw-select-none`};
-
- &:hover {
- ${tw`sw-border-none`};
- outline: none;
- color: ${themeColor('discreetButtonHover')};
- border-color: inherit;
- box-shadow: none;
-
- & .react-select__single-value,
- & .react-select__dropdown-indicator,
- & .react-select__placeholder {
- color: ${themeColor('discreetButtonHover')};
- }
- }
-
- &:focus {
- ${tw`sw-rounded-1`};
- color: ${themeColor('discreetButtonHover')};
- background: ${themeColor('discreetBackground')};
- outline: ${themeBorder('focus', 'discreetFocusBorder')};
- border-color: inherit;
- box-shadow: none;
- }
- }
-
- & .react-select__control--is-focused,
- & .react-select__control--menu-is-open {
- ${tw`sw-border-none`};
- }
-` as typeof InputSelect;
diff --git a/server/sonar-web/src/main/js/design-system/components/input/FileInput.tsx b/server/sonar-web/src/main/js/design-system/components/input/FileInput.tsx
deleted file mode 100644
index 1388db830d1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/FileInput.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { useCallback, useRef, useState } from 'react';
-import { ButtonSecondary } from '../../sonar-aligned/components/buttons/ButtonSecondary';
-import { Note } from '../../sonar-aligned/components/typography';
-
-interface Props {
- chooseLabel: string;
- className?: string;
- clearLabel: string;
- id?: string;
- name?: string;
- noFileLabel: string;
- onFileSelected?: (file?: File) => void;
- required?: boolean;
-}
-
-export function FileInput(props: Readonly<Props>) {
- const { className, id, name, onFileSelected, required } = props;
- const { chooseLabel, clearLabel, noFileLabel } = props;
-
- const [selectedFileName, setSelectedFileName] = useState<string | undefined>(undefined);
- const fileInputRef = useRef<HTMLInputElement>(null);
-
- const handleFileInputChange = useCallback(
- (event: React.ChangeEvent<HTMLInputElement>) => {
- const file = event.target.files?.[0];
- onFileSelected?.(file);
- setSelectedFileName(file?.name);
- },
- [onFileSelected],
- );
-
- const handleFileInputReset = useCallback(() => {
- if (fileInputRef.current) {
- onFileSelected?.(undefined);
- fileInputRef.current.value = '';
- setSelectedFileName(undefined);
- }
- }, [fileInputRef, onFileSelected]);
-
- const handleFileInputClick = useCallback(() => {
- fileInputRef.current?.click();
- }, [fileInputRef]);
-
- return (
- <div className={classNames('sw-flex sw-items-center sw-gap-2', className)}>
- {selectedFileName ? (
- <>
- <ButtonSecondary onClick={handleFileInputReset}>{clearLabel}</ButtonSecondary>
- <Note>{selectedFileName}</Note>
- </>
- ) : (
- <>
- <ButtonSecondary onClick={handleFileInputClick}>{chooseLabel}</ButtonSecondary>
- <Note>{noFileLabel}</Note>
- </>
- )}
- <input
- data-testid="file-input"
- hidden
- id={id}
- name={name}
- onChange={handleFileInputChange}
- ref={fileInputRef}
- required={required}
- type="file"
- />
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/FormField.tsx b/server/sonar-web/src/main/js/design-system/components/input/FormField.tsx
deleted file mode 100644
index f40334f0339..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/FormField.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { Label } from '@sonarsource/echoes-react';
-import { ReactNode } from 'react';
-import tw from 'twin.macro';
-import { Note } from '../../sonar-aligned';
-import { Highlight } from '../Text';
-import { RequiredIcon } from '../icons';
-
-interface Props {
- ariaLabel?: string;
- children: ReactNode;
- className?: string;
- description?: string | ReactNode;
- disabled?: boolean;
- help?: ReactNode;
- htmlFor?: string;
- id?: string;
- label: string | ReactNode;
- required?: boolean;
- requiredAriaLabel?: string;
- title?: string;
-}
-
-export function FormField({
- children,
- className,
- description,
- disabled,
- help,
- id,
- required,
- label,
- htmlFor,
- title,
- ariaLabel,
- requiredAriaLabel,
-}: Readonly<Props>) {
- return (
- <FieldWrapper className={className} id={id}>
- <Highlight className="sw-mb-2 sw-flex sw-items-center sw-gap-2">
- <StyledLabel aria-label={ariaLabel} disabled={disabled} htmlFor={htmlFor} title={title}>
- {label}
- {required && (
- <RequiredIcon aria-label={requiredAriaLabel ?? 'required'} className="sw-ml-1" />
- )}
- </StyledLabel>
- {help}
- </Highlight>
-
- {children}
-
- {description && <Note className="sw-mt-2">{description}</Note>}
- </FieldWrapper>
- );
-}
-
-// This is needed to prevent the target input/button from being focused
-// when clicking/hovering on the label. More info https://stackoverflow.com/questions/9098581/why-is-hover-for-input-triggered-on-corresponding-label-in-css
-const StyledLabel = styled(Label)<{ disabled?: boolean }>`
- pointer-events: none;
- color: ${({ disabled }) => (disabled ? 'var(--echoes-color-text-disabled)' : 'inherit')};
-`;
-
-const FieldWrapper = styled.div`
- ${tw`sw-flex sw-flex-col sw-w-full`}
-
- &:not(:last-of-type) {
- ${tw`sw-mb-6`}
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/input/InputField.tsx b/server/sonar-web/src/main/js/design-system/components/input/InputField.tsx
deleted file mode 100644
index 3ba931e3cbe..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/InputField.tsx
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { css } from '@emotion/react';
-import styled from '@emotion/styled';
-import { forwardRef } from 'react';
-import tw from 'twin.macro';
-import { INPUT_SIZES } from '../../helpers/constants';
-import { themeBorder, themeColor, themeContrast } from '../../helpers/theme';
-import { InputSizeKeys, ThemedProps } from '../../types/theme';
-
-interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
- as?: React.ElementType;
- className?: string;
- isInvalid?: boolean;
- isValid?: boolean;
- size?: InputSizeKeys;
-}
-
-interface InputTextAreaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
- className?: string;
- isInvalid?: boolean;
- isValid?: boolean;
- size?: InputSizeKeys;
-}
-
-export const InputField = forwardRef<HTMLInputElement, InputProps>(
- ({ size = 'medium', style, ...props }, ref) => {
- return (
- <StyledInput ref={ref} style={{ ...style, '--inputSize': INPUT_SIZES[size] }} {...props} />
- );
- },
-);
-InputField.displayName = 'InputField';
-
-export const InputTextArea = forwardRef<HTMLTextAreaElement, InputTextAreaProps>(
- ({ size = 'medium', style, ...props }, ref) => {
- return (
- <StyledTextArea ref={ref} style={{ ...style, '--inputSize': INPUT_SIZES[size] }} {...props} />
- );
- },
-);
-InputTextArea.displayName = 'InputTextArea';
-
-const defaultStyle = (props: ThemedProps) => css`
- --border: ${themeBorder('default', 'inputBorder')(props)};
- --focusBorder: ${themeBorder('default', 'inputFocus')(props)};
- --focusOutline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
-`;
-
-const dangerStyle = (props: ThemedProps) => css`
- --border: ${themeBorder('default', 'inputDanger')(props)};
- --focusBorder: ${themeBorder('default', 'inputDangerFocus')(props)};
- --focusOutline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
-`;
-
-const successStyle = (props: ThemedProps) => css`
- --border: ${themeBorder('default', 'inputSuccess')(props)};
- --focusBorder: ${themeBorder('default', 'inputSuccessFocus')(props)};
- --focusOutline: ${themeBorder('focus', 'inputSuccessFocus')(props)};
-`;
-
-const getInputVariant = (props: ThemedProps & { isInvalid?: boolean; isValid?: boolean }) => {
- const { isValid, isInvalid } = props;
- if (isInvalid) {
- return dangerStyle;
- } else if (isValid) {
- return successStyle;
- }
- return defaultStyle;
-};
-
-const baseStyle = (props: ThemedProps) => css`
- color: ${themeContrast('inputBackground')(props)};
- background: ${themeColor('inputBackground')(props)};
- border: var(--border);
- width: var(--inputSize);
- transition: border-color 0.2s ease;
-
- ${tw`sw-typo-default`}
- ${tw`sw-box-border`}
- ${tw`sw-rounded-2`}
- ${tw`sw-px-3 sw-py-2`}
-
- &::placeholder {
- color: var(--echoes-color-text-placeholder);
- }
-
- &:hover {
- border: var(--focusBorder);
- }
-
- &:active,
- &:focus,
- &:focus-within,
- &:focus-visible {
- border: var(--focusBorder);
- outline: var(--focusOutline);
- outline-offset: var(--echoes-focus-border-offset-default);
- }
-
- &:disabled,
- &:disabled:hover {
- color: var(--echoes-color-text-disabled);
- background-color: ${themeColor('inputDisabled')(props)};
- border: ${themeBorder('default', 'inputDisabledBorder')(props)};
- outline: none;
-
- ${tw`sw-cursor-not-allowed`};
- &::placeholder {
- color: var(--echoes-color-text-disabled);
- }
- }
-`;
-
-const StyledInput = styled.input`
- ${getInputVariant}
- ${baseStyle}
- ${tw`sw-h-control`}
-`;
-
-const StyledTextArea = styled.textarea`
- ${getInputVariant};
- ${baseStyle};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/input/InputMultiSelect.tsx b/server/sonar-web/src/main/js/design-system/components/input/InputMultiSelect.tsx
deleted file mode 100644
index f809c6f23fd..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/InputMultiSelect.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { themeBorder } from '../../helpers';
-import { ButtonProps } from '../../sonar-aligned/components/buttons';
-import { Badge } from '../Badge';
-import { LightLabel } from '../Text';
-import { WrapperButton } from '../buttons';
-import { ChevronDownIcon } from '../icons';
-
-interface Props extends Pick<ButtonProps, 'onClick'> {
- className?: string;
- count?: number;
- id?: string;
- placeholder: string;
- selectedLabel: string;
-}
-
-export function InputMultiSelect(props: Props) {
- const { className, count, id, placeholder, selectedLabel } = props;
-
- return (
- <StyledWrapper
- className={classNames('sw-flex sw-justify-between sw-px-2 sw-typo-default', className)}
- id={id}
- onClick={props.onClick}
- role="combobox"
- >
- {count ? selectedLabel : <LightLabel>{placeholder}</LightLabel>}
-
- <div>
- {count !== undefined && count > 0 && <Badge variant="counter">{count}</Badge>}
- <ChevronDownIcon className="sw-ml-2" />
- </div>
- </StyledWrapper>
- );
-}
-
-const StyledWrapper = styled(WrapperButton)`
- border: ${themeBorder('default', 'inputBorder')};
-
- &:hover {
- border: ${themeBorder('default', 'inputFocus')};
- }
-
- &:active,
- &:focus,
- &:focus-within,
- &:focus-visible {
- border: ${themeBorder('default', 'inputFocus')};
- outline: ${themeBorder('focus', 'inputFocus')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/input/InputSearch.tsx b/server/sonar-web/src/main/js/design-system/components/input/InputSearch.tsx
deleted file mode 100644
index fc6555485c2..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/InputSearch.tsx
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { IconSearch } from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import { debounce } from 'lodash';
-import React, { PropsWithChildren, useEffect, useMemo, useRef, useState } from 'react';
-import { useIntl } from 'react-intl';
-import tw, { theme } from 'twin.macro';
-import { DEBOUNCE_DELAY, INPUT_SIZES } from '../../helpers/constants';
-import { Key } from '../../helpers/keyboard';
-import { themeBorder, themeColor, themeContrast } from '../../helpers/theme';
-import { isDefined } from '../../helpers/types';
-import { InputSizeKeys } from '../../types/theme';
-import { InteractiveIcon } from '../InteractiveIcon';
-import { Spinner } from '../Spinner';
-import { CloseIcon } from '../icons/CloseIcon';
-
-interface Props {
- autoFocus?: boolean;
- className?: string;
- id?: string;
- innerRef?: React.RefCallback<HTMLInputElement>;
- inputId?: string;
- loading?: boolean;
- maxLength?: number;
- minLength?: number;
- onBlur?: React.FocusEventHandler<HTMLInputElement>;
- onChange: (value: string) => void;
- onFocus?: React.FocusEventHandler<HTMLInputElement>;
- onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;
- onMouseDown?: React.MouseEventHandler<HTMLInputElement>;
- placeholder?: string;
- searchInputAriaLabel?: string;
- size?: InputSizeKeys;
- value?: string;
-}
-
-const DEFAULT_MAX_LENGTH = 100;
-
-export function InputSearch(props: PropsWithChildren<Props>) {
- const {
- autoFocus,
- id,
- className,
- innerRef,
- inputId,
- onBlur,
- onChange,
- onFocus,
- onKeyDown,
- onMouseDown,
- placeholder,
- loading,
- minLength,
- maxLength = DEFAULT_MAX_LENGTH,
- size = 'medium',
- value: parentValue,
- searchInputAriaLabel,
- } = props;
- const intl = useIntl();
- const input = useRef<null | HTMLElement>(null);
- const [value, setValue] = useState(parentValue ?? '');
- const debouncedOnChange = useMemo(
- () =>
- debounce((val: string) => {
- onChange(val);
- }, DEBOUNCE_DELAY),
- [onChange],
- );
-
- const tooShort = isDefined(minLength) && value.length > 0 && value.length < minLength;
- const inputClassName = classNames('js-input-search', {
- touched: value.length > 0 && (!minLength || minLength > value.length),
- 'sw-pr-10': value.length > 0,
- });
-
- useEffect(() => {
- // initially letting parentValue control the value of the input
- // later the value is controlled by the local value state
- if (parentValue === '' || (parentValue !== undefined && value === '')) {
- setValue(parentValue);
- }
- }, [parentValue]); // eslint-disable-line
-
- useEffect(() => {
- if (autoFocus && input.current) {
- input.current.focus();
- }
- }, [autoFocus]);
-
- const changeValue = (newValue: string) => {
- if (newValue.length === 0 || !minLength || minLength <= newValue.length) {
- debouncedOnChange(newValue);
- }
- };
-
- const handleInputChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
- const eventValue = event.currentTarget.value;
- setValue(eventValue);
- changeValue(eventValue);
- };
-
- const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
- if (event.key === Key.Escape) {
- event.preventDefault();
- handleClearClick();
- }
- onKeyDown?.(event);
- };
-
- const handleClearClick = () => {
- onChange('');
- setValue('');
- input.current?.focus();
- };
- const ref = (node: HTMLInputElement | null) => {
- input.current = node;
- innerRef?.(node);
- };
-
- return (
- <InputSearchWrapper
- className={className}
- id={id}
- onMouseDown={onMouseDown}
- style={{ '--inputSize': INPUT_SIZES[size] }}
- title={
- tooShort && isDefined(minLength)
- ? intl.formatMessage({ id: 'select2.tooShort' }, { 0: minLength })
- : ''
- }
- >
- <StyledInputWrapper className="sw-flex sw-items-center">
- <input
- aria-label={searchInputAriaLabel ?? placeholder}
- autoComplete="off"
- className={inputClassName}
- id={inputId}
- maxLength={maxLength}
- onBlur={onBlur}
- onChange={handleInputChange}
- onFocus={onFocus}
- onKeyDown={handleInputKeyDown}
- placeholder={placeholder}
- ref={ref}
- role="searchbox"
- type="search"
- value={value}
- />
- <StyledSearchIconWrapper>
- <Spinner className="sw-z-normal" loading={loading ?? false}>
- <StyledSearchIcon />
- </Spinner>
- </StyledSearchIconWrapper>
- {value && (
- <StyledInteractiveIcon
- Icon={CloseIcon}
- aria-label={intl.formatMessage({ id: 'clear' })}
- className="it__search-box-clear"
- onClick={handleClearClick}
- size="small"
- />
- )}
-
- {tooShort && isDefined(minLength) && (
- <StyledNote className="sw-ml-1" role="note">
- {intl.formatMessage({ id: 'select2.tooShort' }, { 0: minLength })}
- </StyledNote>
- )}
- </StyledInputWrapper>
- </InputSearchWrapper>
- );
-}
-
-InputSearch.displayName = 'InputSearch'; // so that tests don't see the obfuscated production name
-
-export const InputSearchWrapper = styled.div`
- width: var(--inputSize);
-
- ${tw`sw-relative sw-inline-block`}
- ${tw`sw-whitespace-nowrap`}
- ${tw`sw-align-middle`}
- ${tw`sw-h-control`}
-`;
-
-export const StyledInputWrapper = styled.div`
- input {
- background: ${themeColor('inputBackground')};
- color: ${themeContrast('inputBackground')};
- border: ${themeBorder('default', 'inputBorder')};
-
- ${tw`sw-rounded-2`}
- ${tw`sw-box-border`}
- ${tw`sw-pl-10`}
- ${tw`sw-typo-default`}
- ${tw`sw-w-full sw-h-control`}
-
- &::placeholder {
- color: var(--echoes-color-text-placeholder);
-
- ${tw`sw-truncate`}
- }
-
- &:hover {
- border: ${themeBorder('default', 'inputFocus')};
- }
-
- &:focus,
- &:active {
- border: ${themeBorder('default', 'inputFocus')};
- outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
- outline-offset: var(--echoes-focus-border-offset-default);
- }
-
- &::-webkit-search-decoration,
- &::-webkit-search-cancel-button,
- &::-webkit-search-results-button,
- &::-webkit-search-results-decoration {
- ${tw`sw-hidden sw-appearance-none`}
- }
- }
-`;
-
-export const StyledSearchIcon = styled(IconSearch)`
- color: ${themeColor('inputBorder')};
-`;
-
-export const StyledSearchIconWrapper = styled.div`
- ${tw`sw-left-3`}
- ${tw`sw-absolute`}
- ${tw`sw-z-normal`}
-`;
-
-export const StyledInteractiveIcon = styled(InteractiveIcon)`
- ${tw`sw-absolute`}
- ${tw`sw-right-2`}
-
- &:focus,
- &:active {
- outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
- }
-`;
-
-export const StyledNote = styled.span`
- color: var(--echoes-color-text-placeholder);
- top: calc(1px + ${theme('inset.2')});
-
- ${tw`sw-absolute`}
- ${tw`sw-left-12 sw-right-10`}
- ${tw`sw-typo-default`}
- ${tw`sw-text-right`}
- ${tw`sw-truncate`}
- ${tw`sw-pointer-events-none`}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/input/MultiSelectMenu.tsx b/server/sonar-web/src/main/js/design-system/components/input/MultiSelectMenu.tsx
deleted file mode 100644
index 0515aa6e4c7..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/MultiSelectMenu.tsx
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { difference } from 'lodash';
-import React, { PureComponent } from 'react';
-import { Key } from '../../helpers/keyboard';
-import { ItemDivider, ItemHeader } from '../DropdownMenu';
-import { InputSearch } from './InputSearch';
-import { MultiSelectMenuOption } from './MultiSelectMenuOption';
-
-interface Props {
- allowNewElements?: boolean;
- allowSearch?: boolean;
- allowSelection?: boolean;
- createElementLabel: string;
- elements: string[];
- elementsDisabled?: string[];
- footerNode?: React.ReactNode;
- headerNode?: React.ReactNode;
- inputId?: string;
- listSize: number;
- noResultsLabel: string;
- onSearch?: (query: string) => Promise<void>;
- onSelect: (item: string) => void;
- onUnselect: (item: string) => void;
- placeholder: string;
- renderTooltip?: (element: string, disabled: boolean) => React.ReactNode;
- searchInputAriaLabel: string;
- selectedElements: string[];
- selectedElementsDisabled?: string[];
- validateSearchInput?: (value: string) => string;
-}
-
-interface State {
- activeIdx: number;
- loading: boolean;
- query: string;
- selectedElements: string[];
- unselectedElements: string[];
-}
-
-interface DefaultProps {
- filterSelected: (query: string, selectedElements: string[]) => string[];
- renderAriaLabel: (element: string) => string;
- renderLabel: (element: string) => React.ReactNode;
- validateSearchInput: (value: string) => string;
-}
-
-type PropsWithDefault = Props & DefaultProps;
-
-export class MultiSelectMenu extends PureComponent<Props, State> {
- container?: HTMLDivElement | null;
- searchInput?: HTMLInputElement | null;
- mounted = false;
-
- static readonly defaultProps: DefaultProps = {
- filterSelected: (query: string, selectedElements: string[]) =>
- selectedElements.filter((elem) => elem.includes(query)),
- renderAriaLabel: (element: string) => element,
- renderLabel: (element: string) => element,
- validateSearchInput: (value: string) => value,
- };
-
- constructor(props: Props) {
- super(props);
- this.state = {
- activeIdx: 0,
- loading: true,
- query: '',
- selectedElements: [],
- unselectedElements: [],
- };
- }
-
- componentDidMount() {
- this.mounted = true;
- this.onSearchQuery('');
- this.updateSelectedElements(this.props as PropsWithDefault);
- this.updateUnselectedElements();
- if (this.container) {
- this.container.addEventListener('keydown', this.handleKeyboard, true);
- }
- }
-
- componentDidUpdate(prevProps: Props) {
- if (this.searchInput) {
- this.searchInput.focus();
- }
-
- if (
- prevProps.elements !== this.props.elements ||
- prevProps.selectedElements !== this.props.selectedElements
- ) {
- this.updateSelectedElements(this.props as PropsWithDefault);
- this.updateUnselectedElements();
-
- const totalElements = this.getAllElements(this.props, this.state).length;
-
- if (this.state.activeIdx >= totalElements) {
- this.setState({ activeIdx: totalElements - 1 });
- }
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- if (this.container) {
- this.container.removeEventListener('keydown', this.handleKeyboard);
- }
- }
-
- handleSelectChange = (selected: boolean, item: string) => {
- if (selected) {
- this.onSelectItem(item);
- } else {
- this.onUnselectItem(item);
- }
- };
-
- handleSearchChange = (value: string) => {
- this.onSearchQuery((this.props as PropsWithDefault).validateSearchInput(value));
- };
-
- handleElementHover = (element: string) => {
- this.setState((prevState, props) => {
- return { activeIdx: this.getAllElements(props, prevState).indexOf(element) };
- });
- };
-
- handleKeyboard = (evt: KeyboardEvent) => {
- switch (evt.key) {
- case Key.ArrowDown:
- evt.stopPropagation();
- evt.preventDefault();
- this.setState(this.selectNextElement);
- break;
- case Key.ArrowUp:
- evt.stopPropagation();
- evt.preventDefault();
- this.setState(this.selectPreviousElement);
- break;
- case Key.ArrowLeft:
- case Key.ArrowRight:
- evt.stopPropagation();
- break;
- case Key.Enter: {
- const allElements = this.getAllElements(this.props, this.state);
- if (this.state.activeIdx >= 0 && this.state.activeIdx < allElements.length) {
- this.toggleSelect(allElements[this.state.activeIdx]);
- }
- break;
- }
- }
- };
-
- onSearchQuery = (query: string) => {
- if (this.props.onSearch) {
- this.setState({ activeIdx: 0, loading: true, query });
- this.props.onSearch(query).then(this.stopLoading, this.stopLoading);
- }
- };
-
- onSelectItem = (item: string) => {
- if (this.isNewElement(item, this.props)) {
- this.onSearchQuery('');
- }
- this.props.onSelect(item);
- };
-
- onUnselectItem = (item: string) => {
- this.props.onUnselect(item);
- };
-
- isNewElement = (elem: string, { selectedElements, elements }: Props) =>
- elem.length > 0 && !selectedElements.includes(elem) && !elements.includes(elem);
-
- updateSelectedElements = (props: PropsWithDefault) => {
- this.setState((state: State) => {
- if (state.query) {
- return {
- selectedElements: props.filterSelected(state.query, props.selectedElements),
- };
- }
- return { selectedElements: [...props.selectedElements] };
- });
- };
-
- updateUnselectedElements = () => {
- const { listSize } = this.props;
- this.setState((state: State) => {
- if (listSize === 0) {
- return { unselectedElements: difference(this.props.elements, this.props.selectedElements) };
- } else if (listSize < state.selectedElements.length) {
- return { unselectedElements: [] };
- }
- return {
- unselectedElements: difference(this.props.elements, this.props.selectedElements).slice(
- 0,
- listSize - state.selectedElements.length,
- ),
- };
- });
- };
-
- getAllElements = (props: Props, state: State) => {
- const { allowNewElements = true } = props;
- if (allowNewElements && this.isNewElement(state.query, props)) {
- return [...state.selectedElements, ...state.unselectedElements, state.query];
- }
- return [...state.selectedElements, ...state.unselectedElements];
- };
-
- selectNextElement = (state: State, props: Props) => {
- const { activeIdx } = state;
- const allElements = this.getAllElements(props, state);
- if (activeIdx < 0 || activeIdx >= allElements.length - 1) {
- return { activeIdx: 0 };
- }
- return { activeIdx: activeIdx + 1 };
- };
-
- selectPreviousElement = (state: State, props: Props) => {
- const { activeIdx } = state;
- const allElements = this.getAllElements(props, state);
- if (activeIdx <= 0) {
- const lastIdx = allElements.length - 1;
- return { activeIdx: lastIdx };
- }
- return { activeIdx: activeIdx - 1 };
- };
-
- stopLoading = () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- };
-
- toggleSelect = (item: string) => {
- if (!this.props.selectedElements.includes(item)) {
- this.onSelectItem(item);
- this.setState(this.selectNextElement);
- } else {
- this.onUnselectItem(item);
- }
- };
-
- render() {
- const {
- allowSearch = true,
- allowSelection = true,
- allowNewElements = true,
- createElementLabel,
- selectedElementsDisabled = [],
- headerNode = '',
- footerNode = '',
- inputId,
- noResultsLabel,
- searchInputAriaLabel,
- elementsDisabled,
- renderTooltip,
- } = this.props;
- const { renderAriaLabel, renderLabel } = this.props as PropsWithDefault;
-
- const { query, activeIdx, selectedElements, unselectedElements } = this.state;
- const activeElement = this.getAllElements(this.props, this.state)[activeIdx];
- const showNewElement = allowNewElements && this.isNewElement(query, this.props);
- const isFixedHeight = this.props.listSize === 0;
- const hasFooter = Boolean(footerNode);
-
- return (
- <div ref={(div) => (this.container = div)}>
- {allowSearch && (
- <>
- <div className="sw-px-3">
- <InputSearch
- autoFocus
- className="sw-mt-1"
- id={inputId}
- loading={this.state.loading}
- onChange={this.handleSearchChange}
- placeholder={this.props.placeholder}
- searchInputAriaLabel={searchInputAriaLabel}
- size="full"
- value={query}
- />
- </div>
- <ItemHeader>{headerNode}</ItemHeader>
- </>
- )}
- <ul
- className={classNames({
- 'sw-mt-2': allowSearch,
- 'sw-max-h-abs-200 sw-overflow-y-auto': isFixedHeight,
- })}
- >
- {selectedElements.length > 0 &&
- selectedElements.map((element) => (
- <MultiSelectMenuOption
- active={activeElement === element}
- createElementLabel={createElementLabel}
- disabled={selectedElementsDisabled.includes(element)}
- element={element}
- key={element}
- onHover={this.handleElementHover}
- onSelectChange={this.handleSelectChange}
- renderAriaLabel={renderAriaLabel}
- renderLabel={renderLabel}
- renderTooltip={renderTooltip}
- selected
- />
- ))}
- {unselectedElements.length > 0 &&
- unselectedElements.map((element) => (
- <MultiSelectMenuOption
- active={activeElement === element}
- createElementLabel={createElementLabel}
- disabled={!allowSelection}
- element={element}
- key={element}
- onHover={this.handleElementHover}
- onSelectChange={this.handleSelectChange}
- renderAriaLabel={renderAriaLabel}
- renderLabel={renderLabel}
- renderTooltip={renderTooltip}
- />
- ))}
- {elementsDisabled?.map((element) => (
- <MultiSelectMenuOption
- active={activeElement === element}
- createElementLabel={createElementLabel}
- disabled
- element={element}
- key={element}
- onHover={this.handleElementHover}
- onSelectChange={this.handleSelectChange}
- renderAriaLabel={renderAriaLabel}
- renderLabel={renderLabel}
- renderTooltip={renderTooltip}
- />
- ))}
- {showNewElement && (
- <MultiSelectMenuOption
- active={activeElement === query}
- createElementLabel={createElementLabel}
- custom
- element={query}
- key={query}
- onHover={this.handleElementHover}
- onSelectChange={this.handleSelectChange}
- />
- )}
- {!showNewElement &&
- selectedElements.length < 1 &&
- unselectedElements.length < 1 &&
- (elementsDisabled ?? []).length < 1 && <li className="sw-ml-2">{noResultsLabel}</li>}
- </ul>
- {hasFooter && <ItemDivider className="sw-mt-2" />}
- <div className="sw-px-3">{footerNode}</div>
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/MultiSelectMenuOption.tsx b/server/sonar-web/src/main/js/design-system/components/input/MultiSelectMenuOption.tsx
deleted file mode 100644
index 55f048869dd..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/MultiSelectMenuOption.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { identity } from 'lodash';
-import { PopupPlacement } from '../../helpers';
-import { ItemCheckbox } from '../DropdownMenu';
-import { Tooltip } from '../Tooltip';
-
-export interface MultiSelectOptionProps {
- active?: boolean;
- createElementLabel: string;
- custom?: boolean;
- disabled?: boolean;
- element: string;
- onHover: (element: string) => void;
- onSelectChange: (selected: boolean, element: string) => void;
- renderAriaLabel?: (element: string) => string;
- renderLabel?: (element: string) => React.ReactNode;
- renderTooltip?: (element: string, disabled: boolean) => React.ReactNode;
- selected?: boolean;
-}
-
-export function MultiSelectMenuOption(props: Readonly<MultiSelectOptionProps>) {
- const {
- active,
- createElementLabel,
- custom,
- disabled = false,
- element,
- onSelectChange,
- renderAriaLabel = identity,
- renderLabel = identity,
- renderTooltip,
- selected,
- } = props;
-
- const onHover = () => {
- props.onHover(element);
- };
-
- const ariaLabel = renderAriaLabel(element);
- const label = renderLabel(element);
-
- return (
- <Tooltip content={renderTooltip?.(element, disabled)} placement={PopupPlacement.Right}>
- <ItemCheckbox
- checked={Boolean(selected)}
- className={classNames('sw-flex sw-py-2 sw-px-4', { active })}
- disabled={disabled}
- id={element}
- label={ariaLabel}
- onCheck={onSelectChange}
- onFocus={onHover}
- onPointerEnter={onHover}
- >
- {custom ? (
- <span
- aria-label={`${createElementLabel}: ${element}`}
- className="sw-ml-3"
- title={createElementLabel}
- >
- <span aria-hidden className="sw-mr-1">
- +
- </span>
- {element}
- </span>
- ) : (
- <span className="sw-ml-3">{label}</span>
- )}
- </ItemCheckbox>
- </Tooltip>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/RadioButton.tsx b/server/sonar-web/src/main/js/design-system/components/input/RadioButton.tsx
deleted file mode 100644
index 12edde48727..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/RadioButton.tsx
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import React from 'react';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../../helpers/theme';
-
-type AllowedRadioButtonAttributes = Pick<
- React.InputHTMLAttributes<HTMLInputElement>,
- 'aria-label' | 'autoFocus' | 'id' | 'name' | 'style' | 'title' | 'type'
->;
-
-interface PropsBase extends AllowedRadioButtonAttributes {
- checked: boolean;
- children?: React.ReactNode;
- className?: string;
- disabled?: boolean;
-}
-
-type Props =
- | ({ onCheck: (value: string) => void; value: string } & PropsBase)
- | ({ onCheck: () => void; value: never } & PropsBase);
-
-/** @deprecated Use RadioButtonGroup from Echoes instead.
- *
- * Individual Radio Buttons can't be used anymore.
- * Instead, build the list of options and pass it to the RadioButtonGroup component.
- */
-export function RadioButton({
- checked,
- children,
- className,
- disabled,
- onCheck,
- value,
- ...htmlProps
-}: Props) {
- const handleChange = () => {
- if (!disabled) {
- onCheck(value);
- }
- };
-
- return (
- <LabelStyled
- className={classNames(
- {
- disabled,
- },
- className,
- )}
- >
- <RadioButtonStyled
- aria-checked={checked}
- aria-disabled={disabled}
- checked={checked}
- disabled={disabled}
- onChange={handleChange}
- type="radio"
- value={value}
- {...htmlProps}
- />
- {children}
- </LabelStyled>
- );
-}
-
-const LabelStyled = styled.label<{ disabled?: boolean }>`
- ${tw`sw-flex sw-items-center`}
- ${tw`sw-cursor-pointer`}
-
- &.disabled {
- color: var(--echoes-color-text-disabled);
- ${tw`sw-cursor-not-allowed`}
- }
-`;
-
-/** @deprecated Use RadioButtonGroup from Echoes instead.
- *
- * Individual Radio Buttons can't be used anymore.
- * Instead, build the list of options and pass it to the RadioButtonGroup component.
- */
-export const RadioButtonStyled = styled.input`
- appearance: none; //disables native style
- border: ${themeBorder('default', 'radioBorder')};
-
- ${tw`sw-cursor-pointer`}
-
- ${tw`sw-w-4 sw-min-w-4 sw-h-4 sw-min-h-4`}
- ${tw`sw-p-1 sw-mr-2`}
- ${tw`sw-inline-block`}
- ${tw`sw-box-border`}
- ${tw`sw-rounded-pill`}
-
- &:hover {
- background: ${themeColor('radioHover')};
- }
-
- &:focus,
- &:focus-visible {
- background: ${themeColor('radioHover')};
- border: ${themeBorder('default', 'radioFocusBorder')};
- outline: ${themeBorder('focus', 'radioFocusOutline')};
- }
-
- &.is-checked,
- &:focus:checked,
- &:focus-visible:checked,
- &:hover:checked,
- &:checked {
- // Color cannot be used with multiple backgrounds, only image is allowed
- background-image: linear-gradient(to right, ${themeColor('radio')}, ${themeColor('radio')}),
- linear-gradient(to right, ${themeColor('radioChecked')}, ${themeColor('radioChecked')});
- background-clip: content-box, padding-box;
- border: ${themeBorder('default', 'radioBorder')};
- }
-
- &.is-disabled,
- &:disabled {
- background: ${themeColor('radioDisabledBackground')};
- border: ${themeBorder('default', 'radioDisabledBorder')};
- background-clip: unset;
-
- &.is-checked,
- &:checked {
- background-image: linear-gradient(
- to right,
- ${themeColor('radioDisabled')},
- ${themeColor('radioDisabled')}
- ),
- linear-gradient(
- to right,
- ${themeColor('radioDisabledBackground')},
- ${themeColor('radioDisabledBackground')}
- );
- background-clip: content-box, padding-box;
- border: ${themeBorder('default', 'radioDisabledBorder')};
- }
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/input/SearchSelect.tsx b/server/sonar-web/src/main/js/design-system/components/input/SearchSelect.tsx
deleted file mode 100644
index 81880590bd6..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/SearchSelect.tsx
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { omit } from 'lodash';
-import React from 'react';
-import { GroupBase, InputProps } from 'react-select';
-import AsyncSelect, { AsyncProps } from 'react-select/async';
-import { INPUT_SIZES } from '../../helpers';
-import { Key } from '../../helpers/keyboard';
-import { SelectProps, selectStyle } from '../../sonar-aligned/components/input';
-import { InputSearch } from './InputSearch';
-
-type SearchSelectProps<
- Option,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
-> = SelectProps<Option, IsMulti, Group> & AsyncProps<Option, IsMulti, Group>;
-
-/**
- * @deprecated Use Select or SelectAsync from Echoes instead.
- * See the [Migration Guide](https://xtranet-sonarsource.atlassian.net/wiki/x/K4AYxw)
- */
-export function SearchSelect<
- Option,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
->({ size = 'full', selectRef, ...props }: SearchSelectProps<Option, IsMulti, Group>) {
- const styles = selectStyle<Option, IsMulti, Group>({ size });
- return (
- <AsyncSelect<Option, IsMulti, Group>
- {...omit(props, 'className', 'large')}
- className={classNames('react-select', props.className)}
- classNamePrefix="react-select"
- classNames={{
- control: ({ isDisabled }) =>
- classNames(
- 'sw-border-0 sw-rounded-2 sw-outline-none sw-shadow-none',
- isDisabled && 'sw-pointer-events-none sw-cursor-not-allowed',
- ),
- indicatorsContainer: () => 'sw-hidden',
- input: () => `sw-flex sw-w-full sw-p-0 sw-m-0`,
- valueContainer: () => `sw-px-3 sw-pb-1 sw-mb-1 sw-pt-4`,
- placeholder: () => 'sw-hidden',
- ...props.classNames,
- }}
- components={{
- Input: SearchSelectInput,
- ...props.components,
- }}
- ref={selectRef}
- styles={{
- ...styles,
- menu: (base, props) => ({
- ...styles.menu?.(base, props),
- width: `calc(${INPUT_SIZES[size]} - 2px)`,
- }),
- }}
- />
- );
-}
-
-/**
- * @deprecated Use Select or SelectAsync from Echoes instead.
- */
-export function SearchSelectInput<
- Option,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
->(props: InputProps<Option, IsMulti, Group>) {
- const {
- selectProps: { placeholder, isLoading, inputValue, minLength },
- } = props;
-
- const onChange = (v: string, prevValue = '') => {
- props.selectProps.onInputChange(v, { action: 'input-change', prevInputValue: prevValue });
- };
-
- const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
- const target = event.target as HTMLInputElement;
-
- if (event.key === Key.Escape.toString() && target.value !== '') {
- event.stopPropagation();
- onChange('');
- }
- };
-
- return (
- <InputSearch
- {...omit(props, 'value', 'aria-label', 'id')}
- autoFocus
- inputId={props.id}
- loading={isLoading && inputValue.length >= (minLength ?? 0)}
- minLength={minLength}
- onChange={onChange}
- onKeyDown={handleKeyDown}
- placeholder={placeholder as string}
- searchInputAriaLabel={props['aria-label']}
- size="full"
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/SearchSelectDropdown.tsx b/server/sonar-web/src/main/js/design-system/components/input/SearchSelectDropdown.tsx
deleted file mode 100644
index 59bf62daf4f..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/SearchSelectDropdown.tsx
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import React from 'react';
-import {
- ActionMeta,
- GroupBase,
- InputActionMeta,
- OnChangeValue,
- OptionsOrGroups,
-} from 'react-select';
-import { AsyncProps } from 'react-select/async';
-import Select from 'react-select/dist/declarations/src/Select';
-import tw from 'twin.macro';
-import { PopupPlacement, PopupZLevel, themeBorder } from '../../helpers';
-import {
- IconOption,
- LabelValueSelectOption,
- SelectProps,
-} from '../../sonar-aligned/components/input';
-import { InputSizeKeys } from '../../types/theme';
-import { DropdownToggler } from '../DropdownToggler';
-import { SearchHighlighterContext } from '../SearchHighlighter';
-import { SearchSelect } from './SearchSelect';
-import { SearchSelectDropdownControl } from './SearchSelectDropdownControl';
-
-declare module 'react-select/dist/declarations/src/Select' {
- export interface Props<Option, IsMulti extends boolean, Group extends GroupBase<Option>> {
- minLength?: number;
- }
-}
-
-interface SearchSelectDropdownProps<
- V,
- Option extends LabelValueSelectOption<V>,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
-> extends SelectProps<Option, IsMulti, Group>,
- AsyncProps<Option, IsMulti, Group> {
- className?: string;
- controlAriaLabel?: string;
- controlLabel?: React.ReactNode | string;
- controlPlaceholder?: string;
- controlSize?: InputSizeKeys;
- isDiscreet?: boolean;
- zLevel?: PopupZLevel;
-}
-
-/**
- * @deprecated Use Select or SelectAsync from Echoes instead.
- *
- * See the [Migration Guide](https://xtranet-sonarsource.atlassian.net/wiki/x/K4AYxw)
- */
-export function SearchSelectDropdown<
- V,
- Option extends LabelValueSelectOption<V>,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
->(props: SearchSelectDropdownProps<V, Option, IsMulti, Group>) {
- const {
- className,
- isDiscreet,
- value,
- loadOptions,
- controlLabel,
- controlPlaceholder,
- controlSize,
- isDisabled,
- minLength,
- controlAriaLabel,
- menuIsOpen,
- onChange,
- onInputChange,
- isClearable,
- zLevel = PopupZLevel.Global,
- placeholder = '',
- ...rest
- } = props;
- const [open, setOpen] = React.useState(false);
- const [inputValue, setInputValue] = React.useState('');
-
- React.useEffect(() => {
- if (menuIsOpen) {
- setOpen(true);
- }
- }, [menuIsOpen]);
-
- const ref = React.useRef<Select<Option, IsMulti, Group>>(null);
-
- const computedControlLabel = controlLabel ?? (value as Option | undefined)?.label ?? null;
-
- const toggleDropdown = React.useCallback(
- (value?: boolean) => {
- setOpen(value ?? !open);
- },
- [open],
- );
-
- const handleChange = React.useCallback(
- (newValue: OnChangeValue<Option, IsMulti>, actionMeta: ActionMeta<Option>) => {
- toggleDropdown(false);
- onChange?.(newValue, actionMeta);
- },
- [toggleDropdown, onChange],
- );
-
- const handleLoadOptions = React.useCallback(
- (query: string, callback: (options: OptionsOrGroups<Option, Group>) => void) => {
- return query.length >= (minLength ?? 0) ? loadOptions?.(query, callback) : undefined;
- },
- [minLength, loadOptions],
- );
-
- const handleInputChange = React.useCallback(
- (newValue: string, actionMeta: InputActionMeta) => {
- if (actionMeta.action === 'menu-close') {
- setInputValue(actionMeta.prevInputValue);
- return actionMeta.prevInputValue;
- }
-
- setInputValue(newValue);
- onInputChange?.(newValue, actionMeta);
- return newValue;
- },
- [onInputChange],
- );
-
- const handleClear = () => {
- onChange?.(null as OnChangeValue<Option, IsMulti>, {
- action: 'clear',
- removedValues: [],
- });
- };
-
- React.useEffect(() => {
- if (open) {
- ref.current?.inputRef?.select();
- } else {
- setInputValue('');
- }
- }, [open]);
-
- return (
- <DropdownToggler
- allowResizing
- className="sw-overflow-visible sw-border-none"
- onRequestClose={() => {
- toggleDropdown(false);
- }}
- open={open}
- overlay={
- <SearchHighlighterContext.Provider value={inputValue}>
- <StyledSearchSelectWrapper>
- <SearchSelect
- cacheOptions
- {...rest}
- components={{
- SingleValue: () => null,
- Option: IconOption,
- ...rest.components,
- }}
- loadOptions={handleLoadOptions}
- menuIsOpen
- minLength={minLength}
- onChange={handleChange}
- onInputChange={handleInputChange}
- placeholder={placeholder}
- selectRef={ref}
- size="large"
- />
- </StyledSearchSelectWrapper>
- </SearchHighlighterContext.Provider>
- }
- placement={PopupPlacement.BottomLeft}
- zLevel={zLevel}
- >
- <SearchSelectDropdownControl
- ariaLabel={controlAriaLabel}
- className={className}
- disabled={isDisabled}
- isClearable={isClearable && Boolean(value)}
- isDiscreet={isDiscreet}
- label={computedControlLabel}
- onClear={handleClear}
- onClick={() => {
- toggleDropdown(true);
- }}
- placeholder={controlPlaceholder}
- size={controlSize}
- />
- </DropdownToggler>
- );
-}
-
-const StyledSearchSelectWrapper = styled.div`
- ${tw`sw-w-full`};
- ${tw`sw-rounded-2`};
-
- .react-select {
- border: ${themeBorder('default', 'inputDisabledBorder')};
- ${tw`sw-rounded-2`};
- }
-
- .react-select__menu {
- ${tw`sw-m-0`};
- ${tw`sw-relative`};
- ${tw`sw-shadow-none`};
- ${tw`sw-rounded-2`};
- }
-
- .react-select__menu-notice--loading {
- ${tw`sw-hidden`}
- }
-
- .react-select__input-container {
- &::after {
- content: '' !important;
- }
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/input/SearchSelectDropdownControl.tsx b/server/sonar-web/src/main/js/design-system/components/input/SearchSelectDropdownControl.tsx
deleted file mode 100644
index bfb355172ea..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/SearchSelectDropdownControl.tsx
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { useIntl } from 'react-intl';
-import tw from 'twin.macro';
-import { INPUT_SIZES, themeBorder, themeColor, themeContrast } from '../../helpers';
-import { Key } from '../../helpers/keyboard';
-import { InputSizeKeys } from '../../types/theme';
-import { InteractiveIcon } from '../InteractiveIcon';
-import { ChevronDownIcon, CloseIcon } from '../icons';
-
-interface SearchSelectDropdownControlProps {
- ariaLabel?: string;
- className?: string;
- disabled?: boolean;
- isClearable?: boolean;
- isDiscreet?: boolean;
- label?: React.ReactNode | string;
- onClear: VoidFunction;
- onClick: VoidFunction;
- placeholder?: string;
- size?: InputSizeKeys;
-}
-
-/**
- * @deprecated Use Select or SelectAsync from Echoes instead.
- *
- * See the [Migration Guide](https://xtranet-sonarsource.atlassian.net/wiki/x/K4AYxw)
- */
-export function SearchSelectDropdownControl(props: SearchSelectDropdownControlProps) {
- const {
- className,
- disabled,
- placeholder,
- label,
- isClearable,
- isDiscreet,
- onClear,
- onClick,
- size = 'full',
- ariaLabel = '',
- } = props;
-
- const intl = useIntl();
-
- return (
- <StyledControl
- aria-label={ariaLabel}
- className={classNames(className, { 'is-discreet': isDiscreet })}
- onClick={() => {
- if (!disabled) {
- onClick();
- }
- }}
- onKeyDown={(event) => {
- if (event.key === Key.Enter || event.key === Key.ArrowDown) {
- onClick();
- }
- }}
- role="combobox"
- style={{ '--inputSize': isDiscreet ? 'auto' : INPUT_SIZES[size] }}
- tabIndex={disabled ? -1 : 0}
- >
- <InputValue
- className={classNames(
- 'it__js-search-input-value sw-flex sw-justify-between sw-items-center',
- {
- 'is-disabled': disabled,
- 'is-placeholder': !label,
- },
- )}
- >
- <span className="sw-flex-1 sw-truncate">{label ?? placeholder}</span>
- <div className="sw-flex sw-items-center">
- {isClearable && (
- <InteractiveIcon
- Icon={CloseIcon}
- aria-label={intl.formatMessage({ id: 'clear' })}
- currentColor
- onClick={() => {
- onClear();
- }}
- size="small"
- />
- )}
- <ChevronDownIcon />
- </div>
- </InputValue>
- </StyledControl>
- );
-}
-
-const StyledControl = styled.div`
- color: ${themeContrast('inputBackground')};
- background: ${themeColor('inputBackground')};
- border: ${themeBorder('default', 'inputBorder')};
- width: var(--inputSize);
-
- ${tw`sw-flex sw-justify-between sw-items-center`};
- ${tw`sw-rounded-2`};
- ${tw`sw-box-border`};
- ${tw`sw-px-3`};
- ${tw`sw-typo-default`};
- ${tw`sw-h-control`};
- ${tw`sw-leading-6`};
- ${tw`sw-cursor-pointer`};
-
- &.is-discreet {
- ${tw`sw-border-none`};
- ${tw`sw-px-1`};
- ${tw`sw-w-auto sw-h-auto`};
-
- background: inherit;
- }
-
- &:hover {
- border: ${themeBorder('default', 'inputFocus')};
-
- &.is-discreet {
- ${tw`sw-border-none`};
- color: ${themeColor('discreetButtonHover')};
- }
- }
-
- &:focus,
- &:focus-visible,
- &:focus-within {
- border: ${themeBorder('default', 'inputFocus')};
- outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
-
- &.is-discreet {
- ${tw`sw-rounded-1 sw-border-none`};
- outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
- }
- }
-`;
-
-const InputValue = styled.span`
- height: 100%;
- width: 100%;
- color: ${themeContrast('inputBackground')};
-
- ${tw`sw-truncate`};
-
- &.is-placeholder {
- color: var(--echoes-color-text-placeholder);
- }
-
- &.is-disabled {
- color: var(--echoes-color-text-disabled);
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/input/__tests__/DatePicker-test.tsx b/server/sonar-web/src/main/js/design-system/components/input/__tests__/DatePicker-test.tsx
deleted file mode 100644
index 1010da38bbf..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/__tests__/DatePicker-test.tsx
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { getMonth, getYear, parseISO } from 'date-fns';
-import { byRole } from '~sonar-aligned/helpers/testSelector';
-import { renderWithContext } from '../../../helpers/testUtils';
-import { DatePicker } from '../DatePicker';
-
-it('behaves correctly', async () => {
- const user = userEvent.setup();
-
- const onChange = jest.fn((_: Date) => undefined);
- const currentMonth = parseISO('2022-06-13');
- renderDatePicker({ currentMonth, onChange });
-
- /*
- * Open the DatePicker, navigate to the previous month and choose an arbitrary day (7)
- * Then check that onChange was correctly called with a date in the previous month
- */
- await user.click(screen.getByRole('textbox'));
-
- const nav = screen.getByRole('navigation');
- expect(nav).toBeInTheDocument();
-
- await user.click(
- byRole('navigation')
- .byRole('button', { name: /previous_month_x/ })
- .get(),
- );
- await user.click(screen.getByText('7'));
-
- expect(onChange).toHaveBeenCalled();
- const newDate = onChange.mock.calls[0][0]; // first argument of the first and only call
- expect(getMonth(newDate)).toBe(getMonth(currentMonth) - 1);
-
- onChange.mockClear();
-
- /*
- * Open the DatePicker, navigate to the next month twice and choose an arbitrary day (12)
- * Then check that onChange was correctly called with a date in the following month
- */
- await user.click(screen.getByRole('textbox'));
- await user.click(screen.getByRole('button', { name: /next_month_x/ }));
- await user.click(screen.getByText('12'));
-
- expect(onChange).toHaveBeenCalled();
- const newDate2 = onChange.mock.calls[0][0]; // first argument
- expect(getMonth(newDate2)).toBe(getMonth(currentMonth) + 1);
-
- onChange.mockClear();
-
- /*
- * Open the DatePicker, select the month, select the year and choose an arbitrary day (10)
- * Then check that onChange was correctly called with a date in the selected month & year
- */
- await user.click(screen.getByRole('textbox'));
- // Select month
- await user.click(screen.getByText('Jun'));
- await user.click(screen.getByText('Feb'));
-
- // Select year
- await user.click(screen.getByText('2022'));
- await user.click(screen.getByText('2019'));
-
- await user.click(screen.getByText('10'));
-
- const newDate3 = onChange.mock.calls[0][0]; // first argument
-
- expect(getMonth(newDate3)).toBe(1);
- expect(getYear(newDate3)).toBe(2019);
-});
-
-it('should disable next navigation when not in the accepted range', async () => {
- const user = userEvent.setup();
-
- const currentDate = parseISO('2022-11-13');
-
- renderDatePicker({
- currentMonth: currentDate,
- maxDate: parseISO('2022-12-30'),
- value: currentDate,
- // eslint-disable-next-line jest/no-conditional-in-test
- valueFormatter: (date?: Date) => (date ? 'formatted date' : 'no date'),
- });
-
- await user.click(screen.getByRole('textbox'));
- await user.click(screen.getByRole('button', { name: /next_month_x/ }));
-
- expect(screen.getByRole('button', { name: /next_month_x/ })).toBeDisabled();
-});
-
-it('should clear the value', async () => {
- const user = userEvent.setup();
-
- const onChange = jest.fn((_: Date) => undefined);
-
- const currentDate = parseISO('2022-06-13');
-
- renderDatePicker({
- currentMonth: currentDate,
- onChange,
- showClearButton: true,
- value: currentDate,
- // eslint-disable-next-line jest/no-conditional-in-test
- valueFormatter: (date?: Date) => (date ? 'formatted date' : 'no date'),
- });
-
- await user.click(screen.getByRole('textbox'));
-
- await user.click(screen.getByLabelText('clear'));
-
- expect(onChange).toHaveBeenCalledWith(undefined);
-});
-
-it.each([
- [{ highlightFrom: parseISO('2022-06-12'), value: parseISO('2022-06-14') }],
- [{ alignRight: true, highlightTo: parseISO('2022-06-14'), value: parseISO('2022-06-12') }],
-])('highlights the appropriate days', async (props) => {
- const user = userEvent.setup();
-
- const hightlightClass = 'rdp-highlighted';
-
- renderDatePicker(props);
-
- await user.click(screen.getByRole('textbox'));
-
- expect(screen.getByText('11')).not.toHaveClass(hightlightClass);
- expect(screen.getByText('12')).toHaveClass(hightlightClass);
- expect(screen.getByText('13')).toHaveClass(hightlightClass);
- expect(screen.getByText('14')).toHaveClass(hightlightClass);
- expect(screen.getByText('15')).not.toHaveClass(hightlightClass);
-});
-
-function renderDatePicker(overrides: Partial<DatePicker['props']> = {}) {
- const defaultFormatter = (date?: Date) => (date ? date.toISOString() : '');
-
- renderWithContext(
- <DatePicker
- clearButtonLabel="clear"
- onChange={jest.fn()}
- placeholder="placeholder"
- valueFormatter={defaultFormatter}
- {...overrides}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/__tests__/DateRangePicker-test.tsx b/server/sonar-web/src/main/js/design-system/components/input/__tests__/DateRangePicker-test.tsx
deleted file mode 100644
index 7f3b976bd3e..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/__tests__/DateRangePicker-test.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { formatISO, parseISO } from 'date-fns';
-import { byRole } from '~sonar-aligned/helpers/testSelector';
-import { IntlWrapper, render } from '../../../helpers/testUtils';
-import { DateRangePicker } from '../DateRangePicker';
-
-beforeEach(() => {
- jest.useFakeTimers().setSystemTime(parseISO('2022-06-12'));
-});
-
-afterEach(() => {
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
-});
-
-it('behaves correctly', async () => {
- const nav = byRole('navigation');
- // Remove delay to play nice with fake timers
- const user = userEvent.setup({ delay: null });
-
- const onChange = jest.fn((_: { from?: Date; to?: Date }) => undefined);
- renderDateRangePicker({ onChange });
-
- await user.click(screen.getByRole('textbox', { name: 'from' }));
-
- const fromNav = nav.get();
- expect(fromNav).toBeInTheDocument();
-
- await user.click(nav.byRole('button', { name: /previous_month_x/ }).get());
- await user.click(screen.getByText('7'));
-
- expect(fromNav).not.toBeInTheDocument();
-
- expect(onChange).toHaveBeenCalled();
- const { from } = onChange.mock.calls[0][0]; // first argument
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- expect(formatISO(from!, { representation: 'date' })).toBe('2022-05-07');
-
- onChange.mockClear();
-
- jest.runAllTimers();
-
- const previousButton = nav.byRole('button', { name: /previous_month_x/ });
- const nextButton = nav.byRole('button', { name: /next_month_x/ });
- await user.click(previousButton.get());
- await user.click(nextButton.get());
- await user.click(previousButton.get());
- await user.click(screen.getByText('12'));
-
- expect(nav.query()).not.toBeInTheDocument();
-
- expect(onChange).toHaveBeenCalled();
- const { to } = onChange.mock.calls[0][0]; // first argument
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- expect(formatISO(to!, { representation: 'date' })).toBe('2022-05-12');
-});
-
-function renderDateRangePicker(overrides: Partial<DateRangePicker['props']> = {}) {
- const defaultFormatter = (date?: Date) =>
- date ? formatISO(date, { representation: 'date' }) : '';
-
- render(
- <IntlWrapper messages={{ next_: 'next', previous_: 'previous' }}>
- <DateRangePicker
- endClearButtonLabel="clear end date"
- fromLabel="from"
- onChange={jest.fn()}
- startClearButtonLabel="clear start date"
- toLabel="to"
- valueFormatter={defaultFormatter}
- {...overrides}
- />
- </IntlWrapper>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/__tests__/DiscreetSelect-test.tsx b/server/sonar-web/src/main/js/design-system/components/input/__tests__/DiscreetSelect-test.tsx
deleted file mode 100644
index fdcae349d04..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/__tests__/DiscreetSelect-test.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { render } from '../../../helpers/testUtils';
-import { FCProps } from '../../../types/misc';
-import { DiscreetSelect } from '../DiscreetSelect';
-
-it('should render discreet select and invoke CB on value click', async () => {
- const value = options[0];
- const setValue = jest.fn();
-
- const user = userEvent.setup();
- setupWithProps({ setValue, value });
- await user.click(screen.getByRole('combobox'));
- expect(screen.getByText(/option foo-bar selected/)).toBeInTheDocument();
- expect(screen.getByRole('note', { name: 'Icon' })).toBeInTheDocument();
- await user.click(screen.getByText('bar-foo'));
- expect(setValue).toHaveBeenCalled();
-});
-
-const options = [
- { label: 'foo-bar', value: 'foo', default: 1 },
- {
- label: 'bar-foo',
- value: 'bar',
- Icon: (
- <span role="note" title="Icon">
- Icon
- </span>
- ),
- },
-];
-
-function setupWithProps(props: Partial<FCProps<typeof DiscreetSelect>>) {
- return render(
- <DiscreetSelect options={options} setValue={jest.fn()} value={options[0]} {...props} />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/__tests__/FileInput-test.tsx b/server/sonar-web/src/main/js/design-system/components/input/__tests__/FileInput-test.tsx
deleted file mode 100644
index 8a2dc504087..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/__tests__/FileInput-test.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { fireEvent, screen } from '@testing-library/react';
-import { render } from '../../../helpers/testUtils';
-import { FCProps } from '../../../types/misc';
-import { FileInput } from '../FileInput';
-
-it('should correclty choose a file and reset it', async () => {
- const file = new File([''], 'file.txt', { type: 'text/plain' });
- const onFileSelected = jest.fn();
- const { user } = setupWithProps({ onFileSelected });
-
- expect(screen.getByRole('button')).toHaveTextContent('Choose');
- expect(screen.getByText('No file selected')).toBeVisible();
-
- await user.click(screen.getByRole('button'));
- fireEvent.change(screen.getByTestId('file-input'), {
- target: { files: [file] },
- });
- expect(onFileSelected).toHaveBeenCalledWith(file);
- expect(screen.getByText('file.txt')).toBeVisible();
- expect(screen.getByRole('button')).toHaveTextContent('Clear');
-
- await user.click(screen.getByRole('button'));
- expect(screen.getByText('No file selected')).toBeVisible();
- expect(onFileSelected).toHaveBeenCalledWith(undefined);
-});
-
-function setupWithProps(props: Partial<FCProps<typeof FileInput>> = {}) {
- return render(
- <FileInput chooseLabel="Choose" clearLabel="Clear" noFileLabel="No file selected" {...props} />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/__tests__/FormField-test.tsx b/server/sonar-web/src/main/js/design-system/components/input/__tests__/FormField-test.tsx
deleted file mode 100644
index 584176f7ef6..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/__tests__/FormField-test.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../../helpers/testUtils';
-import { FCProps } from '../../../types/misc';
-import { FormField } from '../FormField';
-
-it('should render correctly', () => {
- renderFormField({}, <input id="input" />);
- expect(screen.getByLabelText('Hello')).toBeInTheDocument();
-});
-
-it('should render with required and description', () => {
- renderFormField({ description: 'some description', required: true }, <input id="input" />);
- expect(screen.getByText('some description')).toBeInTheDocument();
- expect(screen.getByText('*')).toBeInTheDocument();
-});
-
-function renderFormField(
- props: Partial<FCProps<typeof FormField>> = {},
- children: any = <div>Fake input</div>,
-) {
- return render(
- <FormField htmlFor="input" label="Hello" {...props}>
- {children}
- </FormField>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/__tests__/InputField-test.tsx b/server/sonar-web/src/main/js/design-system/components/input/__tests__/InputField-test.tsx
deleted file mode 100644
index 6b3d74823e9..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/__tests__/InputField-test.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render, screen } from '@testing-library/react';
-import { InputField } from '../InputField';
-
-describe('Input Field', () => {
- it.each([
- ['default', false, false, 'defaultStyle'],
- ['invalid', true, false, 'dangerStyle'],
- ['valid', false, true, 'successStyle'],
- ])('should handle status %s', (_, isInvalid, isValid, expectedStyle) => {
- render(<InputField isInvalid={isInvalid} isValid={isValid} />);
-
- // Emotion classes contain pseudo-random parts, we're interesting in the fixed part
- // so we can't just check a specific class
- // eslint-disable-next-line jest-dom/prefer-to-have-class
- expect(screen.getByRole('textbox').className).toContain(expectedStyle);
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/input/__tests__/InputMultiSelect-test.tsx b/server/sonar-web/src/main/js/design-system/components/input/__tests__/InputMultiSelect-test.tsx
deleted file mode 100644
index 9d666af59c6..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/__tests__/InputMultiSelect-test.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render, screen } from '@testing-library/react';
-import { FCProps } from '../../../types/misc';
-import { InputMultiSelect } from '../InputMultiSelect';
-
-it('should render correctly', () => {
- renderInputMultiSelect();
- expect(screen.getByText('select')).toBeInTheDocument();
- expect(screen.queryByText('selected')).not.toBeInTheDocument();
- expect(screen.queryByText(/\d+/)).not.toBeInTheDocument();
-});
-
-it('should render correctly with a counter', () => {
- renderInputMultiSelect({ count: 42 });
- expect(screen.queryByText('select')).not.toBeInTheDocument();
- expect(screen.getByText('selected')).toBeInTheDocument();
- expect(screen.getByText('42')).toBeInTheDocument();
-});
-
-function renderInputMultiSelect(props: Partial<FCProps<typeof InputMultiSelect>> = {}) {
- render(<InputMultiSelect placeholder="select" selectedLabel="selected" {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/__tests__/InputSearch-test.tsx b/server/sonar-web/src/main/js/design-system/components/input/__tests__/InputSearch-test.tsx
deleted file mode 100644
index 5b9e9e1088e..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/__tests__/InputSearch-test.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen, waitFor } from '@testing-library/react';
-import { renderWithContext } from '../../../helpers/testUtils';
-import { FCProps } from '../../../types/misc';
-import { InputSearch } from '../InputSearch';
-
-it('should warn when input is too short', async () => {
- const { user } = setupWithProps({ value: 'f' });
- expect(screen.getByRole('note')).toBeInTheDocument();
- await user.type(screen.getByRole('searchbox'), 'oo');
- expect(screen.queryByRole('note')).not.toBeInTheDocument();
-});
-
-it('should show clear button only when there is a value', async () => {
- const { user } = setupWithProps({ value: 'f' });
- expect(screen.getByRole('button')).toBeInTheDocument();
- await user.clear(screen.getByRole('searchbox'));
- expect(screen.queryByRole('button')).not.toBeInTheDocument();
-});
-
-it('should attach ref', () => {
- const ref = jest.fn() as jest.Mock<unknown, unknown[]>;
- setupWithProps({ innerRef: ref });
- expect(ref).toHaveBeenCalled();
- expect(ref.mock.calls[0][0]).toBeInstanceOf(HTMLInputElement);
-});
-
-it('should trigger reset correctly with clear button', async () => {
- const onChange = jest.fn();
- const { user } = setupWithProps({ onChange });
- await user.click(screen.getByRole('button'));
- expect(onChange).toHaveBeenCalledWith('');
-});
-
-it('should trigger change correctly', async () => {
- const onChange = jest.fn();
- const { user } = setupWithProps({ onChange, value: 'f' });
- await user.type(screen.getByRole('searchbox'), 'oo');
- await waitFor(() => {
- expect(onChange).toHaveBeenCalledWith('foo');
- });
-});
-
-it('should not change when value is too short', async () => {
- const onChange = jest.fn();
- const { user } = setupWithProps({ onChange, value: '', minLength: 3 });
- await user.type(screen.getByRole('searchbox'), 'fo');
- expect(onChange).not.toHaveBeenCalled();
-});
-
-it('should clear input using escape', async () => {
- const onChange = jest.fn();
- const { user } = setupWithProps({ onChange, value: 'foo' });
- await user.type(screen.getByRole('searchbox'), '{Escape}');
- expect(onChange).toHaveBeenCalledWith('');
-});
-
-function setupWithProps(props: Partial<FCProps<typeof InputSearch>> = {}) {
- return renderWithContext(
- <InputSearch
- maxLength={150}
- minLength={2}
- onChange={jest.fn()}
- placeholder="placeholder"
- searchInputAriaLabel=""
- value="foo"
- {...props}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/__tests__/MultiSelectMenu-test.tsx b/server/sonar-web/src/main/js/design-system/components/input/__tests__/MultiSelectMenu-test.tsx
deleted file mode 100644
index 4da8c83284b..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/__tests__/MultiSelectMenu-test.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { renderWithContext } from '../../../helpers/testUtils';
-import { MultiSelectMenu } from '../MultiSelectMenu';
-
-const elements = ['foo', 'bar', 'baz'];
-
-it('should allow selecting and deselecting a new option', async () => {
- const user = userEvent.setup({ delay: null });
- const onSelect = jest.fn();
- const onUnselect = jest.fn();
- renderMultiselect({ elements, onSelect, onUnselect, allowNewElements: true });
-
- await user.keyboard('new option');
-
- expect(await screen.findByText('new option')).toBeInTheDocument();
-
- await user.click(screen.getByText('new option'));
-
- expect(onSelect).toHaveBeenCalledWith('new option');
-
- renderMultiselect({
- elements,
- onUnselect,
- allowNewElements: true,
- selectedElements: ['new option'],
- });
-
- await user.click(screen.getByText('new option'));
- expect(onUnselect).toHaveBeenCalledWith('new option');
-});
-
-it('should ignore the left and right arrow keys', async () => {
- const user = userEvent.setup({ delay: null });
- const onSelect = jest.fn();
- renderMultiselect({ elements, onSelect });
-
- /* eslint-disable testing-library/no-node-access */
- await user.keyboard('{arrowdown}');
- expect(screen.getAllByRole('checkbox')[1].parentElement).toHaveClass('active');
-
- await user.keyboard('{arrowleft}');
- expect(screen.getAllByRole('checkbox')[1].parentElement).toHaveClass('active');
-
- await user.keyboard('{arrowright}');
- expect(screen.getAllByRole('checkbox')[1].parentElement).toHaveClass('active');
-
- await user.keyboard('{arrowdown}');
- expect(screen.getAllByRole('checkbox')[1].parentElement).not.toHaveClass('active');
- expect(screen.getAllByRole('checkbox')[2].parentElement).toHaveClass('active');
-
- await user.keyboard('{arrowup}');
- await user.keyboard('{arrowup}');
- expect(screen.getAllByRole('checkbox')[0].parentElement).toHaveClass('active');
- await user.keyboard('{arrowup}');
- expect(screen.getAllByRole('checkbox')[2].parentElement).toHaveClass('active');
-
- expect(screen.getAllByRole('checkbox')[2]).not.toBeChecked();
- await user.keyboard('{enter}');
- expect(onSelect).toHaveBeenCalledWith('baz');
-});
-
-it('should show no results', async () => {
- renderMultiselect();
- expect(await screen.findByText('no results')).toBeInTheDocument();
-});
-
-function renderMultiselect(props: Partial<MultiSelectMenu['props']> = {}) {
- return renderWithContext(
- <MultiSelectMenu
- createElementLabel="create thing"
- elements={[]}
- filterSelected={jest.fn()}
- listSize={10}
- noResultsLabel="no results"
- onSearch={jest.fn(() => Promise.resolve())}
- onSelect={jest.fn()}
- onUnselect={jest.fn()}
- placeholder=""
- searchInputAriaLabel="search"
- selectedElements={[]}
- {...props}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/__tests__/RadioButton-test.tsx b/server/sonar-web/src/main/js/design-system/components/input/__tests__/RadioButton-test.tsx
deleted file mode 100644
index 67690e1145e..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/__tests__/RadioButton-test.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { render } from '../../../helpers/testUtils';
-import { FCProps } from '../../../types/misc';
-import { RadioButton } from '../RadioButton';
-
-const value = 'value';
-
-it('should render properly', () => {
- setupWithProps();
- expect(screen.getByRole('radio')).not.toBeChecked();
-});
-
-it('should render properly when checked', () => {
- setupWithProps({ checked: true });
- expect(screen.getByRole('radio')).toBeChecked();
-});
-
-it('should invoke callback on click', async () => {
- const user = userEvent.setup();
- const onCheck = jest.fn();
- setupWithProps({ onCheck, value });
-
- await user.click(screen.getByRole('radio'));
- expect(onCheck).toHaveBeenCalled();
-});
-
-it('should not invoke callback on click when disabled', async () => {
- const user = userEvent.setup();
- const onCheck = jest.fn();
- setupWithProps({ disabled: true, onCheck });
-
- await user.click(screen.getByRole('radio'));
- expect(onCheck).not.toHaveBeenCalled();
-});
-
-function setupWithProps(props?: Partial<FCProps<typeof RadioButton>>) {
- return render(
- <RadioButton checked={false} onCheck={jest.fn()} value="value" {...props}>
- foo
- </RadioButton>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/__tests__/SearchSelectDropdown-test.tsx b/server/sonar-web/src/main/js/design-system/components/input/__tests__/SearchSelectDropdown-test.tsx
deleted file mode 100644
index 0a26150060e..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/__tests__/SearchSelectDropdown-test.tsx
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { renderWithContext } from '../../../helpers/testUtils';
-import { LabelValueSelectOption } from '../../../sonar-aligned';
-import { FCProps } from '../../../types/misc';
-import { SearchSelectDropdown } from '../SearchSelectDropdown';
-
-const defaultOptions = [
- { label: 'label1', value: 'value1' },
- { label: 'different', value: 'diff1' },
-];
-
-const loadOptions = (
- query: string,
- cb: (options: Array<LabelValueSelectOption<string>>) => void,
-) => {
- cb(defaultOptions.filter((o) => o.label.includes(query)));
-};
-
-it('should render select input and be able to search and select an option', async () => {
- const user = userEvent.setup();
- const onChange = jest.fn();
- renderSearchSelectDropdown({ onChange });
- expect(screen.getByText('not assigned')).toBeInTheDocument();
- await user.click(screen.getByRole('combobox'));
- expect(screen.getByText('label1')).toBeInTheDocument();
- expect(screen.getByText('different')).toBeInTheDocument();
- await user.type(screen.getByRole('searchbox', { name: 'label' }), 'label');
- expect(await screen.findByText('label')).toBeInTheDocument();
- expect(screen.queryByText('different')).not.toBeInTheDocument();
- await user.click(screen.getByText('label'));
- expect(onChange).toHaveBeenLastCalledWith(defaultOptions[0], {
- action: 'select-option',
- name: undefined,
- option: undefined,
- });
-});
-
-it('should handle key navigation', async () => {
- const user = userEvent.setup();
- renderSearchSelectDropdown();
- await user.tab();
- await user.keyboard('{Enter}');
- await user.type(screen.getByRole('searchbox', { name: 'label' }), 'label');
- expect(await screen.findByText('label')).toBeInTheDocument();
- expect(screen.queryByText('different')).not.toBeInTheDocument();
- await user.keyboard('{Escape}');
- expect(await screen.findByText('different')).toBeInTheDocument();
- await user.keyboard('{Escape}');
- expect(screen.queryByText('different')).not.toBeInTheDocument();
- await user.tab({ shift: true });
- await user.keyboard('{ArrowDown}');
- expect(await screen.findByText('label1')).toBeInTheDocument();
-});
-
-it('behaves correctly in disabled state', async () => {
- const user = userEvent.setup();
- renderSearchSelectDropdown({ isDisabled: true });
- await user.click(screen.getByRole('combobox'));
- expect(screen.queryByText('label1')).not.toBeInTheDocument();
- await user.tab();
- await user.keyboard('{Enter}');
- expect(screen.queryByText('label1')).not.toBeInTheDocument();
-});
-
-function renderSearchSelectDropdown(props: Partial<FCProps<typeof SearchSelectDropdown>> = {}) {
- return renderWithContext(
- <SearchSelectDropdown
- aria-label="label"
- controlLabel="not assigned"
- defaultOptions={defaultOptions}
- isDiscreet
- loadOptions={loadOptions}
- placeholder="search for things"
- {...props}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/input/index.ts b/server/sonar-web/src/main/js/design-system/components/input/index.ts
deleted file mode 100644
index 7d61ef5c708..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/input/index.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './Checkbox';
-export * from './DatePicker';
-export * from './DateRangePicker';
-export * from './DiscreetSelect';
-export * from './FileInput';
-export * from './FormField';
-export * from './InputField';
-export * from './InputMultiSelect';
-export * from './InputSearch';
-export * from './MultiSelectMenu';
-export * from './RadioButton';
-export * from './SearchSelect';
-export * from './SearchSelectDropdown';
-export * from './SearchSelectDropdownControl';
diff --git a/server/sonar-web/src/main/js/design-system/components/layouts.tsx b/server/sonar-web/src/main/js/design-system/components/layouts.tsx
deleted file mode 100644
index 512556d8c8d..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/layouts.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import {
- LAYOUT_VIEWPORT_MAX_WIDTH,
- LAYOUT_VIEWPORT_MAX_WIDTH_LARGE,
- LAYOUT_VIEWPORT_MIN_WIDTH,
-} from '../helpers';
-
-const BaseLayout = styled.div`
- box-sizing: border-box;
- min-width: ${LAYOUT_VIEWPORT_MIN_WIDTH}px;
- margin: 0 auto;
-
- ${tw`sw-px-14`}
-`;
-
-export const CenteredLayout = styled(BaseLayout)`
- max-width: ${LAYOUT_VIEWPORT_MAX_WIDTH}px;
-`;
-
-export const LargeCenteredLayout = styled(BaseLayout)`
- max-width: ${LAYOUT_VIEWPORT_MAX_WIDTH_LARGE}px;
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/lists/ListItem.tsx b/server/sonar-web/src/main/js/design-system/components/lists/ListItem.tsx
deleted file mode 100644
index 80259aea919..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/lists/ListItem.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-
-export const ListItem = styled.li`
- ${tw`sw-my-3`}
-`;
-
-ListItem.displayName = 'ListItem';
diff --git a/server/sonar-web/src/main/js/design-system/components/lists/NumberedList.tsx b/server/sonar-web/src/main/js/design-system/components/lists/NumberedList.tsx
deleted file mode 100644
index 42f11169b21..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/lists/NumberedList.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-
-export const NumberedList = styled.ol`
- list-style: none;
- counter-reset: li;
- ${tw`sw-mt-4`}
- ${tw`sw-pl-0`}
-
- li:last-child {
- ${tw`sw-mb-0`}
- }
-`;
-
-NumberedList.displayName = 'NumberedList';
diff --git a/server/sonar-web/src/main/js/design-system/components/lists/NumberedListItem.tsx b/server/sonar-web/src/main/js/design-system/components/lists/NumberedListItem.tsx
deleted file mode 100644
index 48cb9ed7e0f..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/lists/NumberedListItem.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeColor } from '../../helpers/theme';
-
-export const NumberedListItem = styled.li`
- counter-increment: li;
- ${tw`sw-mb-4`}
- ${tw`sw-ml-1`}
-
- &::before {
- width: 19px;
- height: 19px;
- color: ${themeColor('numberedListText')};
- background-color: ${themeColor('numberedList')};
- border-radius: 20px;
- content: counter(li);
-
- ${tw`sw-typo-semibold`}
- ${tw`sw-p-1`}
- ${tw`sw-mr-3`}
- ${tw`sw-inline-block`}
- ${tw`sw-text-center`}
- }
-`;
-
-NumberedListItem.displayName = 'NumberedListItem';
diff --git a/server/sonar-web/src/main/js/design-system/components/lists/OrderedList.tsx b/server/sonar-web/src/main/js/design-system/components/lists/OrderedList.tsx
deleted file mode 100644
index bea6a0be112..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/lists/OrderedList.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-
-type TickStyles = 'DECIMAL' | 'ALPHA' | 'ROMAN';
-const ListStyle = {
- DECIMAL: 'decimal',
- ALPHA: 'lower-alpha',
- ROMAN: 'lower-roman',
-};
-
-export const OrderedList = styled.ol<{ tickStyle?: TickStyles }>`
- list-style: ${({ tickStyle }) => (tickStyle ? ListStyle[tickStyle] : 'decimal')};
- ${tw`sw-mt-4`}
- ${tw`sw-pl-0`}
-
- li:last-child {
- ${tw`sw-mb-0`}
- }
-`;
-
-OrderedList.displayName = 'OrderedList';
diff --git a/server/sonar-web/src/main/js/design-system/components/lists/UnorderedList.tsx b/server/sonar-web/src/main/js/design-system/components/lists/UnorderedList.tsx
deleted file mode 100644
index 9a32471c770..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/lists/UnorderedList.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-
-export const UnorderedList = styled.ul<{ ticks?: boolean }>`
- list-style: ${({ ticks }) => (ticks ? 'disc' : 'none')};
- ${tw`sw-mt-4`}
- ${tw`sw-pl-0`}
-
- li:last-child {
- ${tw`sw-mb-0`}
- }
-`;
-
-UnorderedList.displayName = 'UnorderedList';
diff --git a/server/sonar-web/src/main/js/design-system/components/lists/__tests__/NumberedList-test.tsx b/server/sonar-web/src/main/js/design-system/components/lists/__tests__/NumberedList-test.tsx
deleted file mode 100644
index e1977fbb542..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/lists/__tests__/NumberedList-test.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../../helpers/testUtils';
-import { NumberedList } from '../NumberedList';
-import { NumberedListItem } from '../NumberedListItem';
-
-it('renders correctly', () => {
- render(
- <NumberedList>
- <NumberedListItem>First item</NumberedListItem>
- <NumberedListItem>Second item</NumberedListItem>
- </NumberedList>,
- );
- expect(screen.getAllByRole('listitem')).toHaveLength(2);
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/lists/__tests__/UnorderedList-test.tsx b/server/sonar-web/src/main/js/design-system/components/lists/__tests__/UnorderedList-test.tsx
deleted file mode 100644
index 44ccbdc4c0c..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/lists/__tests__/UnorderedList-test.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../../helpers/testUtils';
-import { ListItem } from '../ListItem';
-import { UnorderedList } from '../UnorderedList';
-
-it('renders correctly', () => {
- render(
- <UnorderedList>
- <ListItem>First item</ListItem>
- <ListItem>Second item</ListItem>
- </UnorderedList>,
- );
- expect(screen.getAllByRole('listitem')).toHaveLength(2);
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/lists/index.ts b/server/sonar-web/src/main/js/design-system/components/lists/index.ts
deleted file mode 100644
index 0e6853e2eb5..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/lists/index.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './ListItem';
-export * from './NumberedList';
-export * from './NumberedListItem';
-export * from './OrderedList';
-export * from './UnorderedList';
diff --git a/server/sonar-web/src/main/js/design-system/components/modal/Modal.tsx b/server/sonar-web/src/main/js/design-system/components/modal/Modal.tsx
deleted file mode 100644
index ea6d5cd381c..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/modal/Modal.tsx
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Global, css, useTheme } from '@emotion/react';
-import { Button } from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import { Fragment, ReactNode } from 'react';
-import { useIntl } from 'react-intl';
-import ReactModal from 'react-modal';
-import tw from 'twin.macro';
-import { themeColor } from '../../helpers';
-import { REACT_DOM_CONTAINER } from '../../helpers/constants';
-import { Theme } from '../../types/theme';
-import { ModalBody } from './ModalBody';
-import { ModalFooter } from './ModalFooter';
-import { ModalHeader } from './ModalHeader';
-
-ReactModal.setAppElement(REACT_DOM_CONTAINER);
-
-/* eslint-disable react/jsx-fragments */
-
-interface CommonProps {
- closeOnOverlayClick?: boolean;
- isLarge?: boolean;
- isOpen?: boolean;
- isOverflowVisible?: boolean;
- isScrollable?: boolean;
- onClose: VoidFunction;
-}
-
-interface ChildrenProp {
- children: React.ReactNode;
-}
-
-interface NotChildrenProp {
- children?: never;
-}
-
-interface SectionsProps {
- body: React.ReactNode;
- headerDescription?: string | ReactNode;
- headerTitle: string | ReactNode;
- loading?: boolean;
- primaryButton?: ReactNode;
- secondaryButtonLabel?: ReactNode;
-}
-
-type NotSectionsProps = {
- [prop in keyof SectionsProps]?: never;
-};
-
-export type PropsWithChildren = CommonProps & ChildrenProp & NotSectionsProps;
-
-export type PropsWithSections = CommonProps & SectionsProps & NotChildrenProp;
-
-type Props = PropsWithChildren | PropsWithSections;
-
-function hasNoChildren(props: Partial<Props>): props is PropsWithSections {
- return (props as PropsWithChildren).children === undefined;
-}
-
-/** @deprecated Use either Modal or ModalAlert from Echoes instead.
- *
- * The props have changed significantly:
- * - `headerTitle` is now `title`
- * - `headerDescription` is now `description` and is announced to screen readers.
- * - `body` is replaced with `content`
- * - `isLarge` is replaced with `size` (ModalSize.Default or ModalSize.Wide)
- * - `isScrollable` and `isOverflowVisible` have been removed and the behavior is automatic!
- * - `closeOnOverlayClick` has been removed and is either
- * - always false for ModalAlert (it requires an action)
- * or
- * - always true for Modal
- *
- * By default, the Modal will be controlled automatically by its Trigger (child element).
- * This is the preferred way.
- *
- * If you need to control the Modal (e.g. open as a side effect, close after async action):
- * - `onClose` has been removed. Instead, use:
- * - `onOpenChange`: callback for `isOpen` value changes.
- * - `IsOpen`: controls the display of the Modal (conditional rendering isn't necessary anymore)
- *
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3465543707/Modals | Migration Guide} for more
- */
-export function Modal({
- closeOnOverlayClick = true,
- isLarge,
- isOpen = true,
- isOverflowVisible = false,
- isScrollable = true,
- onClose,
- ...props
-}: Props) {
- const theme = useTheme();
- const intl = useIntl();
- return (
- <Fragment>
- <Global styles={globalStyles({ theme })} />
-
- <ReactModal
- aria={{ labelledby: 'modal_header_title' }}
- className={classNames('design-system-modal-contents', { large: isLarge })}
- isOpen={isOpen}
- onRequestClose={onClose}
- overlayClassName="design-system-modal-overlay"
- shouldCloseOnEsc
- shouldCloseOnOverlayClick={closeOnOverlayClick}
- shouldFocusAfterRender
- shouldReturnFocusAfterClose
- >
- {hasNoChildren(props) ? (
- <Fragment>
- <ModalHeader description={props.headerDescription} title={props.headerTitle} />
-
- <ModalBody isOverflowVisible={isOverflowVisible} isScrollable={isScrollable}>
- {props.body}
- </ModalBody>
-
- <ModalFooter
- loading={props.loading}
- primaryButton={props.primaryButton}
- secondaryButton={
- <Button
- className="js-modal-close sw-capitalize"
- isDisabled={props.loading}
- onClick={onClose}
- type="reset"
- >
- {props.secondaryButtonLabel ?? intl.formatMessage({ id: 'close' })}
- </Button>
- }
- />
- </Fragment>
- ) : (
- (props as PropsWithChildren).children
- )}
- </ReactModal>
- </Fragment>
- );
-}
-
-const globalStyles = ({ theme }: { theme: Theme }) => css`
- .design-system-modal-contents {
- ${tw`sw-container sw-flex sw-flex-col`}
- ${tw`sw-p-9`}
- ${tw`sw-rounded-2`}
- ${tw`sw-z-modal`}
- ${tw`sw-box-border`}
-
- background-color: ${themeColor('modalContents')({ theme })};
- max-height: calc(100vh - 200px);
- min-height: 160px;
- width: 544px;
-
- &.large {
- max-width: 1280px;
- min-width: 1040px;
- }
- }
-
- .design-system-modal-overlay {
- ${tw`sw-fixed sw-inset-0`}
- ${tw`sw-flex sw-items-center sw-justify-center`}
- ${tw`sw-z-modal-overlay`}
-
- background-color: ${themeColor('modalOverlay')({ theme })};
- }
-`;
-
-Modal.displayName = 'Modal';
-Modal.Body = ModalBody;
-Modal.Footer = ModalFooter;
-Modal.Header = ModalHeader;
diff --git a/server/sonar-web/src/main/js/design-system/components/modal/ModalBody.tsx b/server/sonar-web/src/main/js/design-system/components/modal/ModalBody.tsx
deleted file mode 100644
index 81b78cba5d7..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/modal/ModalBody.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { ReactNode } from 'react';
-import tw from 'twin.macro';
-import { themeColor } from '../../helpers/theme';
-
-interface Props {
- children: ReactNode;
- isOverflowVisible?: boolean;
- isScrollable?: boolean;
-}
-
-export function ModalBody({ children, isScrollable = true, isOverflowVisible = false }: Props) {
- return (
- <StyledMain
- className={classNames({ scrollable: isScrollable, overflowVisible: isOverflowVisible })}
- >
- {children}
- </StyledMain>
- );
-}
-
-const StyledMain = styled.div`
- ${tw`sw-typo-default`}
- ${tw`sw-px-3`} // to accomodate a possible scrollbar
- ${tw`-sw-mx-3`}
- ${tw`sw-my-12`}
- ${tw`sw-overflow-x-hidden`}
-
- color: ${themeColor('pageContent')};
-
- &.scrollable {
- overflow-y: auto;
- }
-
- &.overflowVisible {
- overflow: visible;
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/modal/ModalFooter.tsx b/server/sonar-web/src/main/js/design-system/components/modal/ModalFooter.tsx
deleted file mode 100644
index 52ddd7ed1c0..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/modal/ModalFooter.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { ButtonGroup } from '@sonarsource/echoes-react';
-import tw from 'twin.macro';
-import { Spinner } from '../Spinner';
-
-interface Props {
- loading?: boolean;
- primaryButton?: React.ReactNode;
- secondaryButton: React.ReactNode;
-}
-
-export function ModalFooter({ loading = false, primaryButton, secondaryButton }: Readonly<Props>) {
- return (
- <StyledFooter>
- <Spinner loading={loading} />
-
- <ButtonGroup>
- {primaryButton}
- {secondaryButton}
- </ButtonGroup>
- </StyledFooter>
- );
-}
-
-const StyledFooter = styled.div`
- ${tw`sw-flex sw-gap-3 sw-items-center sw-justify-end`}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/modal/ModalHeader.tsx b/server/sonar-web/src/main/js/design-system/components/modal/ModalHeader.tsx
deleted file mode 100644
index 822ec5c97b8..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/modal/ModalHeader.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { ReactNode } from 'react';
-import tw from 'twin.macro';
-import { themeColor } from '../../helpers/theme';
-
-interface Props {
- description?: string | ReactNode;
- title: string | ReactNode;
-}
-
-export function ModalHeader({ description, title }: Props) {
- return (
- <div>
- <Title id="modal_header_title">{title}</Title>
- {description && <Description>{description}</Description>}
- </div>
- );
-}
-
-const Description = styled.p`
- ${tw`sw-typo-default`}
- ${tw`sw-mt-2`}
-
- color: ${themeColor('pageContent')};
-`;
-
-const Title = styled.h2`
- ${tw`sw-heading-xl`}
-
- color: ${themeColor('pageTitle')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/modal/__tests__/Modal-test.tsx b/server/sonar-web/src/main/js/design-system/components/modal/__tests__/Modal-test.tsx
deleted file mode 100644
index 2f57c125ff0..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/modal/__tests__/Modal-test.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { renderWithContext } from '../../../helpers/testUtils';
-import { Modal, PropsWithChildren, PropsWithSections } from '../Modal';
-
-it('should render default modal with predefined content', async () => {
- setupPredefinedContent({
- body: 'Modal body',
- headerTitle: 'Hello',
- headerDescription: 'Does this look OK?',
- secondaryButtonLabel: undefined, // should use the default of 'Close'
- });
-
- expect(await screen.findByText('Modal body')).toBeVisible();
- expect(await screen.findByText('Hello')).toBeVisible();
- expect(await screen.findByText('Does this look OK?')).toBeVisible();
- expect(await screen.findByRole('button', { name: 'close' })).toBeVisible();
-});
-
-it('should request close when pressing esc', async () => {
- const onClose = jest.fn();
- const { user } = setupPredefinedContent({ onClose });
-
- await user.keyboard('{Escape}');
-
- expect(onClose).toHaveBeenCalled();
-});
-
-it('should render modal with loose content', async () => {
- setupLooseContent(undefined, <div>Hello</div>);
-
- expect(await screen.findByText('Hello')).toBeVisible();
-});
-
-it('should request close when pressing esc on loose content', async () => {
- const onClose = jest.fn();
- const { user } = setupLooseContentWithMultipleChildren({ onClose });
-
- await user.keyboard('{Escape}');
-
- expect(onClose).toHaveBeenCalled();
-});
-
-function setupPredefinedContent(props: Partial<PropsWithSections> = {}) {
- return renderWithContext(
- <Modal
- body="Body"
- headerTitle="Hello"
- onClose={jest.fn()}
- secondaryButtonLabel="Close"
- {...props}
- />,
- );
-}
-
-function setupLooseContent(props: Partial<PropsWithChildren> = {}, children = <div />) {
- return renderWithContext(
- <Modal onClose={jest.fn()} {...props}>
- {children}
- </Modal>,
- );
-}
-
-function setupLooseContentWithMultipleChildren(props: Partial<PropsWithChildren> = {}) {
- return renderWithContext(
- <Modal onClose={jest.fn()} {...props}>
- <div>Hello there!</div>
- <div>How are you?</div>
- </Modal>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/modal/__tests__/ModalBody-test.tsx b/server/sonar-web/src/main/js/design-system/components/modal/__tests__/ModalBody-test.tsx
deleted file mode 100644
index d57bf781403..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/modal/__tests__/ModalBody-test.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render } from '../../../helpers/testUtils';
-import { ModalBody } from '../ModalBody';
-
-it('renders with children', () => {
- const children = <div>Hello!</div>;
- const { container } = setup(children);
-
- expect(container).toMatchSnapshot();
-});
-
-function setup(children = <div />) {
- return render(<ModalBody>{children}</ModalBody>);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/modal/__tests__/ModalFooter-test.tsx b/server/sonar-web/src/main/js/design-system/components/modal/__tests__/ModalFooter-test.tsx
deleted file mode 100644
index 423a018986e..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/modal/__tests__/ModalFooter-test.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { renderWithContext } from '../../../helpers/testUtils';
-import { FCProps } from '../../../types/misc';
-import { ModalFooter } from '../ModalFooter';
-
-it('should render with secondary button', () => {
- const { container } = setupWithProps({
- secondaryButton: (
- <button onClick={() => {}} type="button">
- Close
- </button>
- ),
- });
-
- expect(container).toMatchSnapshot();
-});
-
-it('should render with primary and secondary buttons', () => {
- const { container } = setupWithProps({
- primaryButton: (
- <button onClick={undefined} type="button">
- Primary
- </button>
- ),
- secondaryButton: (
- <button onClick={undefined} type="reset">
- Reset
- </button>
- ),
- });
-
- expect(container).toMatchSnapshot();
-});
-
-function setupWithProps(props: Partial<FCProps<typeof ModalFooter>> = {}) {
- return renderWithContext(<ModalFooter secondaryButton={<div />} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/modal/__tests__/ModalHeader-test.tsx b/server/sonar-web/src/main/js/design-system/components/modal/__tests__/ModalHeader-test.tsx
deleted file mode 100644
index 7d1842472af..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/modal/__tests__/ModalHeader-test.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render } from '../../../helpers/testUtils';
-import { FCProps } from '../../../types/misc';
-import { ModalHeader } from '../ModalHeader';
-
-it('should use the default title if not provided', () => {
- const { container } = setupWithProps();
-
- expect(container).toMatchSnapshot();
-});
-
-it('should render with title', () => {
- const { container } = setupWithProps({ title: 'Foo' });
-
- expect(container).toMatchSnapshot();
-});
-
-it('should render with title and description', () => {
- const { container } = setupWithProps({ title: 'Foo', description: 'Bar' });
-
- expect(container).toMatchSnapshot();
-});
-
-function setupWithProps(props: Partial<FCProps<typeof ModalHeader>> = {}) {
- return render(<ModalHeader title="Modal title" {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/modal/__tests__/__snapshots__/ModalBody-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/modal/__tests__/__snapshots__/ModalBody-test.tsx.snap
deleted file mode 100644
index b2f36f6b060..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/modal/__tests__/__snapshots__/ModalBody-test.tsx.snap
+++ /dev/null
@@ -1,33 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders with children 1`] = `
-.emotion-0 {
- font: var(--echoes-typography-text-default-regular);
- padding-left: 0.75rem;
- padding-right: 0.75rem;
- margin-left: -0.75rem;
- margin-right: -0.75rem;
- margin-top: 3rem;
- margin-bottom: 3rem;
- overflow-x: hidden;
- color: rgb(62,67,87);
-}
-
-.emotion-0.scrollable {
- overflow-y: auto;
-}
-
-.emotion-0.overflowVisible {
- overflow: visible;
-}
-
-<div>
- <div
- class="scrollable emotion-0 emotion-1"
- >
- <div>
- Hello!
- </div>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/modal/__tests__/__snapshots__/ModalFooter-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/modal/__tests__/__snapshots__/ModalFooter-test.tsx.snap
deleted file mode 100644
index 7b3942e017d..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/modal/__tests__/__snapshots__/ModalFooter-test.tsx.snap
+++ /dev/null
@@ -1,190 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render with primary and secondary buttons 1`] = `
-@keyframes animation-0 {
- from {
- -webkit-transform: rotate(0deg);
- -moz-transform: rotate(0deg);
- -ms-transform: rotate(0deg);
- transform: rotate(0deg);
- }
-
- to {
- -webkit-transform: rotate(-360deg);
- -moz-transform: rotate(-360deg);
- -ms-transform: rotate(-360deg);
- transform: rotate(-360deg);
- }
-}
-
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: end;
- -ms-flex-pack: end;
- -webkit-justify-content: flex-end;
- justify-content: flex-end;
- gap: 0.75rem;
-}
-
-.emotion-2 {
- border: 2px solid transparent;
- background: linear-gradient(0deg, rgb(93,108,208) 50%, transparent 50% 100%) border-box,linear-gradient(90deg, rgb(93,108,208) 25%, transparent 75% 100%) border-box;
- -webkit-mask: linear-gradient(#fff 0 0) padding-box,linear-gradient(#fff 0 0);
- mask: linear-gradient(#fff 0 0) padding-box,linear-gradient(#fff 0 0);
- -webkit-mask-composite: xor;
- -webkit-mask-composite: exclude;
- mask-composite: exclude;
- -webkit-animation: animation-0 1s infinite linear;
- animation: animation-0 1s infinite linear;
- height: 1rem;
- width: 1rem;
- display: inline-block;
- box-sizing: border-box;
- border-radius: 625rem;
-}
-
-.emotion-4 {
- display: -webkit-inline-box;
- display: -webkit-inline-flex;
- display: -ms-inline-flexbox;
- display: inline-flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- gap: var(--echoes-dimension-space-100);
-}
-
-<div>
- <div
- class="emotion-0 emotion-1"
- >
- <div
- class="sw-relative"
- >
- <div
- class="sw-overflow-hidden sw-sr-only"
- >
- <div
- aria-live="polite"
- class="emotion-2 emotion-3"
- role="status"
- />
- </div>
- </div>
- <span
- class="emotion-4 emotion-5"
- >
- <button
- type="button"
- >
- Primary
- </button>
- <button
- type="reset"
- >
- Reset
- </button>
- </span>
- </div>
-</div>
-`;
-
-exports[`should render with secondary button 1`] = `
-@keyframes animation-0 {
- from {
- -webkit-transform: rotate(0deg);
- -moz-transform: rotate(0deg);
- -ms-transform: rotate(0deg);
- transform: rotate(0deg);
- }
-
- to {
- -webkit-transform: rotate(-360deg);
- -moz-transform: rotate(-360deg);
- -ms-transform: rotate(-360deg);
- transform: rotate(-360deg);
- }
-}
-
-.emotion-0 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: end;
- -ms-flex-pack: end;
- -webkit-justify-content: flex-end;
- justify-content: flex-end;
- gap: 0.75rem;
-}
-
-.emotion-2 {
- border: 2px solid transparent;
- background: linear-gradient(0deg, rgb(93,108,208) 50%, transparent 50% 100%) border-box,linear-gradient(90deg, rgb(93,108,208) 25%, transparent 75% 100%) border-box;
- -webkit-mask: linear-gradient(#fff 0 0) padding-box,linear-gradient(#fff 0 0);
- mask: linear-gradient(#fff 0 0) padding-box,linear-gradient(#fff 0 0);
- -webkit-mask-composite: xor;
- -webkit-mask-composite: exclude;
- mask-composite: exclude;
- -webkit-animation: animation-0 1s infinite linear;
- animation: animation-0 1s infinite linear;
- height: 1rem;
- width: 1rem;
- display: inline-block;
- box-sizing: border-box;
- border-radius: 625rem;
-}
-
-.emotion-4 {
- display: -webkit-inline-box;
- display: -webkit-inline-flex;
- display: -ms-inline-flexbox;
- display: inline-flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- gap: var(--echoes-dimension-space-100);
-}
-
-<div>
- <div
- class="emotion-0 emotion-1"
- >
- <div
- class="sw-relative"
- >
- <div
- class="sw-overflow-hidden sw-sr-only"
- >
- <div
- aria-live="polite"
- class="emotion-2 emotion-3"
- role="status"
- />
- </div>
- </div>
- <span
- class="emotion-4 emotion-5"
- >
- <button
- type="button"
- >
- Close
- </button>
- </span>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/modal/__tests__/__snapshots__/ModalHeader-test.tsx.snap b/server/sonar-web/src/main/js/design-system/components/modal/__tests__/__snapshots__/ModalHeader-test.tsx.snap
deleted file mode 100644
index 1e7ed6edeb5..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/modal/__tests__/__snapshots__/ModalHeader-test.tsx.snap
+++ /dev/null
@@ -1,66 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render with title 1`] = `
-.emotion-0 {
- font: var(--echoes-typography-heading-xlarge);
- color: rgb(29,33,47);
-}
-
-<div>
- <div>
- <h2
- class="emotion-0 emotion-1"
- id="modal_header_title"
- >
- Foo
- </h2>
- </div>
-</div>
-`;
-
-exports[`should render with title and description 1`] = `
-.emotion-0 {
- font: var(--echoes-typography-heading-xlarge);
- color: rgb(29,33,47);
-}
-
-.emotion-2 {
- font: var(--echoes-typography-text-default-regular);
- margin-top: 0.5rem;
- color: rgb(62,67,87);
-}
-
-<div>
- <div>
- <h2
- class="emotion-0 emotion-1"
- id="modal_header_title"
- >
- Foo
- </h2>
- <p
- class="emotion-2 emotion-3"
- >
- Bar
- </p>
- </div>
-</div>
-`;
-
-exports[`should use the default title if not provided 1`] = `
-.emotion-0 {
- font: var(--echoes-typography-heading-xlarge);
- color: rgb(29,33,47);
-}
-
-<div>
- <div>
- <h2
- class="emotion-0 emotion-1"
- id="modal_header_title"
- >
- Modal title
- </h2>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/popups.tsx b/server/sonar-web/src/main/js/design-system/components/popups.tsx
deleted file mode 100644
index c39bff30fbb..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/popups.tsx
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { throttle } from 'lodash';
-import React, { AriaRole } from 'react';
-import { findDOMNode } from 'react-dom';
-import tw from 'twin.macro';
-import { THROTTLE_SCROLL_DELAY } from '../helpers/constants';
-import { PopupPlacement, PopupZLevel, popupPositioning } from '../helpers/positioning';
-import { themeBorder, themeColor, themeContrast, themeShadow } from '../helpers/theme';
-import ClickEventBoundary from './ClickEventBoundary';
-
-interface PopupBaseProps {
- 'aria-labelledby'?: string;
- children?: React.ReactNode;
- className?: string;
- id?: string;
- placement?: PopupPlacement;
- role?: AriaRole;
- style?: React.CSSProperties;
- zLevel?: PopupZLevel;
-}
-
-function PopupBase(props: PopupBaseProps, ref: React.Ref<HTMLDivElement>) {
- const {
- children,
- className,
- placement = PopupPlacement.Bottom,
- style,
- zLevel = PopupZLevel.Default,
- ...ariaProps
- } = props;
- return (
- <ClickEventBoundary>
- <PopupWrapper
- className={classNames(`is-${placement}`, className)}
- ref={ref ?? React.createRef()}
- style={style}
- zLevel={zLevel}
- {...ariaProps}
- >
- {children}
- </PopupWrapper>
- </ClickEventBoundary>
- );
-}
-
-const PopupWithRef = React.forwardRef(PopupBase);
-PopupWithRef.displayName = 'Popup';
-
-interface PopupProps extends Omit<PopupBaseProps, 'style'> {
- allowResizing?: boolean;
- children: React.ReactNode;
- overlay: React.ReactNode;
-}
-
-interface Measurements {
- height: number;
- left: number;
- top: number;
- width: number;
-}
-
-type State = Partial<Measurements>;
-
-function isMeasured(state: State): state is Measurements {
- return state.height !== undefined;
-}
-
-export class Popup extends React.PureComponent<PopupProps, State> {
- mounted = false;
- popupNode = React.createRef<HTMLDivElement>();
- throttledPositionTooltip: () => void;
-
- constructor(props: PopupProps) {
- super(props);
- this.state = {};
- this.throttledPositionTooltip = throttle(this.positionPopup, THROTTLE_SCROLL_DELAY);
- }
-
- componentDidMount() {
- this.positionPopup();
- this.addEventListeners();
- this.mounted = true;
- }
-
- componentDidUpdate(prevProps: PopupProps) {
- if (this.props.placement !== prevProps.placement || this.props.overlay !== prevProps.overlay) {
- this.positionPopup();
- }
- }
-
- componentWillUnmount() {
- this.removeEventListeners();
- this.mounted = false;
- }
-
- addEventListeners = () => {
- window.addEventListener('resize', this.throttledPositionTooltip);
- if (this.props.zLevel !== PopupZLevel.Global) {
- window.addEventListener('scroll', this.throttledPositionTooltip);
- }
- };
-
- removeEventListeners = () => {
- window.removeEventListener('resize', this.throttledPositionTooltip);
- if (this.props.zLevel !== PopupZLevel.Global) {
- window.removeEventListener('scroll', this.throttledPositionTooltip);
- }
- };
-
- positionPopup = () => {
- if (this.mounted && this.props.zLevel !== PopupZLevel.Absolute) {
- // `findDOMNode(this)` will search for the DOM node for the current component
- // first it will find a React.Fragment (see `render`),
- // so it will get the DOM node of the first child, i.e. DOM node of `this.props.children`
- // docs: https://reactjs.org/docs/refs-and-the-dom.html#exposing-dom-refs-to-parent-components
-
- // eslint-disable-next-line react/no-find-dom-node
- const toggleNode = findDOMNode(this);
- if (toggleNode && toggleNode instanceof Element && this.popupNode.current) {
- const { placement, zLevel } = this.props;
- const isGlobal = zLevel === PopupZLevel.Global;
- const { height, left, top, width } = popupPositioning(
- toggleNode,
- this.popupNode.current,
- placement,
- );
-
- // save width and height (and later set in `render`) to avoid resizing the popup element,
- // when it's placed close to the window edge
- this.setState({
- left: left + (isGlobal ? 0 : window.scrollX),
- top: top + (isGlobal ? 0 : window.scrollY),
- width,
- height,
- });
- }
- }
- };
-
- render() {
- const {
- allowResizing,
- children,
- overlay,
- placement = PopupPlacement.Bottom,
- ...popupProps
- } = this.props;
-
- let style: React.CSSProperties | undefined;
- if (isMeasured(this.state)) {
- style = { left: this.state.left, top: this.state.top };
- if (!allowResizing) {
- style.width = this.state.width;
- style.height = this.state.height;
- }
- }
- return (
- <>
- {this.props.children}
- {this.props.overlay && (
- <PopupWithRef placement={placement} ref={this.popupNode} style={style} {...popupProps}>
- {overlay}
- </PopupWithRef>
- )}
- </>
- );
- }
-}
-
-export const PopupWrapper = styled.div<{ zLevel: PopupZLevel }>`
- position: ${({ zLevel }) => (zLevel === PopupZLevel.Global ? 'fixed' : 'absolute')};
- background-color: ${themeColor('popup')};
- color: ${themeContrast('popup')};
- border: ${themeBorder('default', 'popupBorder')};
- box-shadow: ${themeShadow('md')};
-
- ${tw`sw-box-border`};
- ${tw`sw-rounded-2`};
- ${tw`sw-cursor-default`};
- ${tw`sw-overflow-hidden`};
- ${({ zLevel }) =>
- ({
- [PopupZLevel.Default]: tw`sw-z-popup`,
- [PopupZLevel.Global]: tw`sw-z-global-popup`,
- [PopupZLevel.Content]: tw`sw-z-content-popup`,
- [PopupZLevel.Absolute]: tw`sw-z-global-popup`,
- })[zLevel]};
-
- &.is-bottom,
- &.is-bottom-left,
- &.is-bottom-right {
- ${tw`sw-mt-2`};
- }
-
- &.is-top,
- &.is-top-left,
- &.is-top-right {
- ${tw`sw--mt-2`};
- }
-
- &.is-left,
- &.is-left-top,
- &.is-left-bottom {
- ${tw`sw--ml-2`};
- }
-
- &.is-right,
- &.is-right-top,
- &.is-right-bottom {
- ${tw`sw-ml-2`};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationAccordion.tsx b/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationAccordion.tsx
deleted file mode 100644
index 7202abc78bf..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationAccordion.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { ReactNode, useCallback, useState } from 'react';
-import tw from 'twin.macro';
-import { themeColor, themeContrast } from '../../helpers/theme';
-import { BareButton } from '../../sonar-aligned/components/buttons';
-import { OpenCloseIndicator } from '../icons/OpenCloseIndicator';
-import { SubnavigationGroup } from './SubnavigationGroup';
-
-interface CommonProps {
- children: ReactNode;
- className?: string;
- header: ReactNode;
- id: string;
- onSetExpanded?: (expanded: boolean) => void;
-}
-
-interface ControlledProps extends CommonProps {
- expanded: boolean | undefined;
- initExpanded?: never;
-}
-
-interface UncontrolledProps extends CommonProps {
- expanded?: never;
- initExpanded?: boolean;
-}
-
-type Props = ControlledProps | UncontrolledProps;
-
-export function SubnavigationAccordion(props: Props) {
- const { children, className, expanded, header, id, initExpanded, onSetExpanded } = props;
-
- const [innerExpanded, setInnerExpanded] = useState(initExpanded ?? false);
- const finalExpanded = expanded ?? innerExpanded;
-
- const toggleExpanded = useCallback(() => {
- setInnerExpanded(!finalExpanded);
- onSetExpanded?.(!finalExpanded);
- }, [finalExpanded, onSetExpanded]);
-
- return (
- <SubnavigationGroup className={className}>
- <SubnavigationAccordionItem
- aria-controls={`${id}-subnavigation-accordion`}
- aria-expanded={finalExpanded}
- id={`${id}-subnavigation-accordion-button`}
- onClick={toggleExpanded}
- >
- {header}
- <OpenCloseIndicator open={finalExpanded} />
- </SubnavigationAccordionItem>
- {finalExpanded && (
- <section
- aria-labelledby={`${id}-subnavigation-accordion-button`}
- id={`${id}-subnavigation-accordion`}
- >
- {children}
- </section>
- )}
- </SubnavigationGroup>
- );
-}
-
-const SubnavigationAccordionItem = styled(BareButton)`
- ${tw`sw-flex sw-items-center sw-justify-between`}
- ${tw`sw-box-border`}
- ${tw`sw-typo-semibold`}
- ${tw`sw-p-4`}
- ${tw`sw-w-full`}
- ${tw`sw-cursor-pointer`}
-
- color: ${themeContrast('subnavigation')};
- background-color: ${themeColor('subnavigation')};
- transition: 0.2 ease;
- transition-property: border-left, background-color, color;
-
- &:hover,
- &:focus {
- background-color: ${themeColor('subnavigationHover')};
- }
-`;
-SubnavigationAccordionItem.displayName = 'SubnavigationAccordionItem';
diff --git a/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationGroup.tsx b/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationGroup.tsx
deleted file mode 100644
index b17903088bc..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationGroup.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { Children, ElementType, Fragment, HtmlHTMLAttributes, ReactNode } from 'react';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../../helpers/theme';
-import { isDefined } from '../../helpers/types';
-
-interface Props extends HtmlHTMLAttributes<HTMLDivElement> {
- as?: ElementType;
- children: ReactNode;
- className?: string;
-}
-
-export function SubnavigationGroup({ as, className, children, ...htmlProps }: Readonly<Props>) {
- const childrenArray = Children.toArray(children).filter(isDefined);
- return (
- <Group as={as} className={className} {...htmlProps}>
- {childrenArray.map((child, index) => (
- <Fragment key={index}>
- {child}
- {index < childrenArray.length - 1 && <Separator />}
- </Fragment>
- ))}
- </Group>
- );
-}
-
-const Group = styled.div`
- ${tw`sw-relative`}
- ${tw`sw-flex sw-flex-col`}
- ${tw`sw-w-full`}
-
- background-color: ${themeColor('subnavigation')};
- border: ${themeBorder('default', 'subnavigationBorder')};
-`;
-
-const Separator = styled.div`
- ${tw`sw-w-full`}
-
- height: 1px;
- background-color: ${themeColor('subnavigationSeparator')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationHeading.tsx b/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationHeading.tsx
deleted file mode 100644
index 991cd37f0e8..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationHeading.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeColor, themeContrast } from '../../helpers/theme';
-
-export const SubnavigationHeading = styled.div`
- ${tw`sw-flex sw-items-center sw-justify-between`}
- ${tw`sw-box-border`}
- ${tw`sw-typo-default`}
- ${tw`sw-p-4`}
- ${tw`sw-w-full`}
-
- color: ${themeContrast('subnavigation')};
- background-color: ${themeColor('subnavigation')};
-`;
-SubnavigationHeading.displayName = 'SubnavigationHeading';
diff --git a/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationItem.tsx b/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationItem.tsx
deleted file mode 100644
index 251750e1ce9..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationItem.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { css } from '@emotion/react';
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { ReactNode, SyntheticEvent, useCallback } from 'react';
-import tw, { theme as twTheme } from 'twin.macro';
-import { themeBorder, themeColor, themeContrast } from '../../helpers/theme';
-import { ThemedProps } from '../../types';
-import NavLink, { NavLinkProps } from '../NavLink';
-
-interface Props {
- active?: boolean;
- ariaCurrent?: boolean;
- children: ReactNode;
- className?: string;
- id?: string;
- innerRef?: (node: HTMLAnchorElement) => void;
- onClick: (value?: string) => void;
- value?: string;
-}
-
-export function SubnavigationItem(props: Readonly<Props>) {
- const { active, ariaCurrent, className, children, id, innerRef, onClick, value } = props;
- const handleClick = useCallback(
- (e: SyntheticEvent<HTMLAnchorElement>) => {
- e.preventDefault();
- onClick(value);
- },
- [onClick, value],
- );
- return (
- <StyledSubnavigationItem
- aria-current={ariaCurrent}
- className={classNames({ active }, className)}
- data-testid="js-subnavigation-item"
- href="#"
- id={id}
- onClick={handleClick}
- ref={innerRef}
- >
- {children}
- </StyledSubnavigationItem>
- );
-}
-
-export function SubnavigationLinkItem({ children, ...props }: NavLinkProps) {
- return <SubnavigationLinkItemStyled {...props}>{children}</SubnavigationLinkItemStyled>;
-}
-
-const ItemBaseStyle = (props: ThemedProps) => css`
- ${tw`sw-flex sw-items-center sw-justify-between`}
- ${tw`sw-box-border`}
- ${tw`sw-typo-default`}
- ${tw`sw-py-4 sw-pr-4`}
- ${tw`sw-w-full`}
- ${tw`sw-cursor-pointer`}
-
- padding-left: calc(${twTheme('spacing.4')} - 3px);
- color: ${themeContrast('subnavigation')(props)};
- background-color: ${themeColor('subnavigation')(props)};
- border-bottom: none;
- border-left: ${themeBorder('active', 'transparent')(props)};
- transition: 0.2 ease;
- transition-property: border-left, background-color, color;
-
- &:hover,
- &:focus,
- &.active {
- background-color: ${themeColor('subnavigationHover')(props)};
- }
-
- &.active {
- color: ${themeContrast('subnavigationHover')(props)};
- border-left: ${themeBorder('active')(props)};
- }
-`;
-
-const StyledSubnavigationItem = styled.a`
- ${ItemBaseStyle};
-`;
-
-const SubnavigationLinkItemStyled = styled(NavLink)`
- ${ItemBaseStyle};
- ${tw`sw-no-underline`}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationSubheading.tsx b/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationSubheading.tsx
deleted file mode 100644
index 5555ac3d1b7..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/subnavigation/SubnavigationSubheading.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeColor } from '../../helpers/theme';
-
-export const SubnavigationSubheading = styled.div`
- ${tw`sw-flex`}
- ${tw`sw-box-border`}
- ${tw`sw-typo-default`}
- ${tw`sw-px-4 sw-pt-6 sw-pb-2`}
- ${tw`sw-w-full`}
-
- color: var(--echoes-color-text-subdued);
- background-color: ${themeColor('subnavigationSubheading')};
-`;
-SubnavigationSubheading.displayName = 'SubnavigationSubheading';
diff --git a/server/sonar-web/src/main/js/design-system/components/subnavigation/__tests__/SubnavigationAccordion-test.tsx b/server/sonar-web/src/main/js/design-system/components/subnavigation/__tests__/SubnavigationAccordion-test.tsx
deleted file mode 100644
index f4f47bf0aca..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/subnavigation/__tests__/SubnavigationAccordion-test.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { render } from '../../../helpers/testUtils';
-import { FCProps } from '../../../types/misc';
-import { SubnavigationAccordion } from '../SubnavigationAccordion';
-
-it('should have correct style and html structure', () => {
- setupWithProps({ expanded: false });
-
- expect(screen.getByRole('button', { expanded: false })).toBeVisible();
- expect(screen.queryByText('Foo')).not.toBeInTheDocument();
-});
-
-it('should display expanded', () => {
- setupWithProps({ initExpanded: true });
-
- expect(screen.getByRole('button', { expanded: true })).toBeVisible();
- expect(screen.getByText('Foo')).toBeVisible();
-});
-
-it('should display collapsed by default', () => {
- setupWithProps();
-
- expect(screen.getByRole('button')).toBeVisible();
- expect(screen.queryByText('Foo')).not.toBeInTheDocument();
-});
-
-it('should toggle expand', async () => {
- const user = userEvent.setup();
- const onSetExpanded = jest.fn();
- setupWithProps({ onSetExpanded, expanded: false });
-
- expect(onSetExpanded).not.toHaveBeenCalled();
- await user.click(screen.getByRole('button', { expanded: false }));
-
- expect(onSetExpanded).toHaveBeenCalledWith(true);
-});
-
-it('should toggle collapse', async () => {
- const user = userEvent.setup();
- const onSetExpanded = jest.fn();
- setupWithProps({ onSetExpanded, expanded: true });
-
- expect(onSetExpanded).not.toHaveBeenCalled();
- await user.click(screen.getByRole('button', { expanded: true }));
-
- expect(onSetExpanded).toHaveBeenCalledWith(false);
-});
-
-function setupWithProps(props: Partial<FCProps<typeof SubnavigationAccordion>> = {}) {
- return render(
- <SubnavigationAccordion header="Header" id="test" {...props}>
- <span>Foo</span>
- </SubnavigationAccordion>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/subnavigation/__tests__/SubnavigationItem-test.tsx b/server/sonar-web/src/main/js/design-system/components/subnavigation/__tests__/SubnavigationItem-test.tsx
deleted file mode 100644
index 50e566a7668..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/subnavigation/__tests__/SubnavigationItem-test.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../../helpers/testUtils';
-import { FCProps } from '../../../types/misc';
-import { SubnavigationItem } from '../SubnavigationItem';
-
-it('should call onClick with value when clicked', async () => {
- const onClick = jest.fn();
- const { user } = setupWithProps({ onClick });
-
- await user.click(screen.getByRole('button'));
- expect(onClick).toHaveBeenCalledWith('foo');
-});
-
-function setupWithProps(props: Partial<FCProps<typeof SubnavigationItem>> = {}) {
- return render(
- <SubnavigationItem active={false} onClick={jest.fn()} value="foo" {...props}>
- <button type="button">Foo</button>
- </SubnavigationItem>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/subnavigation/index.ts b/server/sonar-web/src/main/js/design-system/components/subnavigation/index.ts
deleted file mode 100644
index 3ff8a020faf..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/subnavigation/index.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './SubnavigationAccordion';
-export * from './SubnavigationGroup';
-export * from './SubnavigationHeading';
-export * from './SubnavigationItem';
-export * from './SubnavigationSubheading';
diff --git a/server/sonar-web/src/main/js/design-system/components/toast-message/ToastMessage.tsx b/server/sonar-web/src/main/js/design-system/components/toast-message/ToastMessage.tsx
deleted file mode 100644
index 50de44f5277..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/toast-message/ToastMessage.tsx
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import * as React from 'react';
-import { Slide, ToastContainer, ToastContainerProps } from 'react-toastify';
-import tw from 'twin.macro';
-import { TOAST_AUTOCLOSE_DELAY } from '../../helpers/constants';
-import { themeBorder, themeColor } from '../../helpers/theme';
-import { ToastMessageGlobalStyles } from './ToastMessageGlobalStyles';
-
-/** This wrapper function is required to remove the react-toastify theme prop as we use our own Themes */
-function WrappedToastContainer(
- props: Omit<ToastContainerProps, 'theme'> & React.RefAttributes<HTMLDivElement>,
-) {
- return <ToastContainer {...props} />;
-}
-
-export function ToastMessageContainer() {
- return (
- // Below: using <></> won't work in extenstions ('React' is not defined). This is because the
- // name 'React' would already have been minified to something else when <> is resolved to
- // React.Fragment
- // eslint-disable-next-line react/jsx-fragments
- <React.Fragment>
- <ToastMessageGlobalStyles />
-
- <StyledToastContainer
- autoClose={TOAST_AUTOCLOSE_DELAY}
- closeOnClick
- draggable
- hideProgressBar
- limit={0}
- newestOnTop={false}
- pauseOnFocusLoss
- pauseOnHover
- position="top-right"
- rtl={false}
- transition={Slide}
- />
- </React.Fragment>
- );
-}
-
-const StyledToastContainer = styled(WrappedToastContainer)`
- .Toastify__toast {
- ${tw`sw-p-0`}
- }
-
- .Toastify__toast-body {
- ${tw`sw-p-0 sw-m-0`}
- }
-
- .Toastify__close-button {
- ${tw`sw-pt-3 sw-pr-3`}
- color: var(--echoes-color-icon-subdued);
- opacity: 1;
- }
-
- .Toastify__toast-theme--light {
- ${tw`sw-inline-flex`}
- ${tw`sw-min-h-10`}
- ${tw`sw-rounded-1`}
- ${tw`sw-mb-2`}
-
- background-color: ${themeColor('toast')};
- border: ${themeBorder('default')};
-
- .Toastify__toast-icon {
- align-items: center;
- justify-content: center;
- width: 38px;
- height: calc(100%);
- }
-
- &.Toastify__toast--default,
- &.Toastify__toast--info,
- &.Toastify__toast--success,
- &.Toastify__toast--warning,
- &.Toastify__toast--error {
- color: ${themeColor('toastText')};
- }
-
- &.Toastify__toast--default,
- &.Toastify__toast--info {
- border-color: ${themeColor('toastInfoBorder')};
-
- .Toastify__toast-icon {
- background-color: ${themeColor('toastInfoIconBackground')};
- }
- }
-
- .Toastify__progress-bar--info {
- background-color: ${themeColor('toastInfoBorder')};
- }
-
- &.Toastify__toast--success {
- border-color: ${themeColor('toastSuccessBorder')};
-
- .Toastify__toast-icon {
- background-color: ${themeColor('toastSuccessIconBackground')};
- }
- }
-
- .Toastify__progress-bar--success {
- background-color: ${themeColor('toastSuccessBorder')};
- }
-
- &.Toastify__toast--warning {
- border-color: ${themeColor('toastWarningBorder')};
-
- .Toastify__toast-icon {
- background-color: ${themeColor('toastWarningIconBackground')};
- }
- }
-
- .Toastify__progress-bar--warning {
- background-color: ${themeColor('toastWarningBorder')};
- }
-
- &.Toastify__toast--error {
- border-color: ${themeColor('toastErrorBorder')};
-
- .Toastify__toast-icon {
- background-color: ${themeColor('toastErrorIconBackground')};
- }
- }
-
- .Toastify__progress-bar--error {
- background-color: ${themeColor('toastErrorBorder')};
- }
- }
-
- .Toastify__toast-theme--colored {
- .Toastify__progress-bar--default {
- background-color: ${themeColor('toastInfoBorder')};
- }
-
- &.Toastify__toast--info {
- background-color: ${themeColor('toastInfoBorder')};
- border-color: ${themeColor('toastInfoBorder')};
-
- .Toastify__toast-icon {
- background-color: ${themeColor('toastInfoBorder')};
- }
- }
-
- .Toastify__progress-bar--info {
- background-color: ${themeColor('toastInfoIconBackground')};
- }
-
- &.Toastify__toast--success {
- background-color: ${themeColor('toastSuccessBorder')};
- border-color: ${themeColor('toastSuccessBorder')};
-
- .Toastify__toast-icon {
- background-color: ${themeColor('toastSuccessBorder')};
- }
- }
-
- .Toastify__progress-bar--success {
- background-color: ${themeColor('toastSuccessIconBackground')};
- }
-
- &.Toastify__toast--warning {
- background-color: ${themeColor('toastWarningBorder')};
- border-color: ${themeColor('toastWarningBorder')};
-
- .Toastify__toast-icon {
- background-color: ${themeColor('toastWarningBorder')};
- }
- }
-
- .Toastify__progress-bar--warning {
- background-color: ${themeColor('toastWarningIconBackground')};
- }
-
- &.Toastify__toast--error {
- background-color: ${themeColor('toastErrorBorder')};
- border-color: ${themeColor('toastErrorBorder')};
-
- .Toastify__toast-icon {
- background-color: ${themeColor('toastErrorBorder')};
- }
- }
-
- .Toastify__progress-bar--error {
- background-color: ${themeColor('toastErrorIconBackground')};
- }
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/toast-message/ToastMessageGlobalStyles.tsx b/server/sonar-web/src/main/js/design-system/components/toast-message/ToastMessageGlobalStyles.tsx
deleted file mode 100644
index b5eaa4a0e87..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/toast-message/ToastMessageGlobalStyles.tsx
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Global, css } from '@emotion/react';
-
-export function ToastMessageGlobalStyles() {
- return <Global styles={globalStyles()} />;
-}
-
-const globalStyles = () => css`
- :root {
- --toastify-color-light: #fff;
- --toastify-color-dark: #121212;
- --toastify-color-info: #3498db;
- --toastify-color-success: #07bc0c;
- --toastify-color-warning: #f1c40f;
- --toastify-color-error: #e74c3c;
- --toastify-color-transparent: rgba(255, 255, 255, 0.7);
- --toastify-icon-color-info: var(--toastify-color-info);
- --toastify-icon-color-success: var(--toastify-color-success);
- --toastify-icon-color-warning: var(--toastify-color-warning);
- --toastify-icon-color-error: var(--toastify-color-error);
- --toastify-toast-width: 320px;
- --toastify-toast-background: #fff;
- --toastify-toast-min-height: 64px;
- --toastify-toast-max-height: 800px;
- --toastify-font-family: sans-serif;
- --toastify-z-index: 9999;
- --toastify-text-color-light: #757575;
- --toastify-text-color-dark: #fff;
- --toastify-text-color-info: #fff;
- --toastify-text-color-success: #fff;
- --toastify-text-color-warning: #fff;
- --toastify-text-color-error: #fff;
- --toastify-spinner-color: #616161;
- --toastify-spinner-color-empty-area: #e0e0e0;
- --toastify-color-progress-light: linear-gradient(
- to right,
- #4cd964,
- #5ac8fa,
- #007aff,
- #34aadc,
- #5856d6,
- #ff2d55
- );
- --toastify-color-progress-dark: #bb86fc;
- --toastify-color-progress-info: var(--toastify-color-info);
- --toastify-color-progress-success: var(--toastify-color-success);
- --toastify-color-progress-warning: var(--toastify-color-warning);
- --toastify-color-progress-error: var(--toastify-color-error);
- }
-
- .Toastify__toast-container {
- z-index: var(--toastify-z-index);
- -webkit-transform: translate3d(0, 0, var(--toastify-z-index) px);
- position: fixed;
- padding: 4px;
- width: var(--toastify-toast-width);
- box-sizing: border-box;
- color: #fff;
- }
- .Toastify__toast-container--top-left {
- top: 1em;
- left: 1em;
- }
- .Toastify__toast-container--top-center {
- top: 1em;
- left: 50%;
- transform: translateX(-50%);
- }
- .Toastify__toast-container--top-right {
- top: 1em;
- right: 1em;
- }
- .Toastify__toast-container--bottom-left {
- bottom: 1em;
- left: 1em;
- }
- .Toastify__toast-container--bottom-center {
- bottom: 1em;
- left: 50%;
- transform: translateX(-50%);
- }
- .Toastify__toast-container--bottom-right {
- bottom: 1em;
- right: 1em;
- }
-
- @media only screen and (max-width: 480px) {
- .Toastify__toast-container {
- width: 100vw;
- padding: 0;
- left: 0;
- margin: 0;
- }
- .Toastify__toast-container--top-left,
- .Toastify__toast-container--top-center,
- .Toastify__toast-container--top-right {
- top: 0;
- transform: translateX(0);
- }
- .Toastify__toast-container--bottom-left,
- .Toastify__toast-container--bottom-center,
- .Toastify__toast-container--bottom-right {
- bottom: 0;
- transform: translateX(0);
- }
- .Toastify__toast-container--rtl {
- right: 0;
- left: initial;
- }
- }
- .Toastify__toast {
- position: relative;
- min-height: var(--toastify-toast-min-height);
- box-sizing: border-box;
- margin-bottom: 1rem;
- padding: 8px;
- border-radius: 4px;
- box-shadow:
- 0 1px 10px 0 rgba(0, 0, 0, 0.1),
- 0 2px 15px 0 rgba(0, 0, 0, 0.05);
- display: -ms-flexbox;
- display: flex;
- -ms-flex-pack: justify;
- justify-content: space-between;
- max-height: var(--toastify-toast-max-height);
- overflow: hidden;
- font-family: var(--toastify-font-family);
- cursor: pointer;
- direction: ltr;
- }
- .Toastify__toast--rtl {
- direction: rtl;
- }
- .Toastify__toast-body {
- margin: auto 0;
- -ms-flex: 1 1 auto;
- flex: 1 1 auto;
- padding: 6px;
- display: -ms-flexbox;
- display: flex;
- -ms-flex-align: center;
- align-items: center;
- }
- .Toastify__toast-body > div:last-child {
- -ms-flex: 1;
- flex: 1;
- }
- .Toastify__toast-icon {
- -webkit-margin-end: 10px;
- margin-inline-end: 10px;
- width: 20px;
- -ms-flex-negative: 0;
- flex-shrink: 0;
- display: -ms-flexbox;
- display: flex;
- }
-
- .Toastify--animate {
- animation-fill-mode: both;
- animation-duration: 0.7s;
- }
-
- .Toastify--animate-icon {
- animation-fill-mode: both;
- animation-duration: 0.3s;
- }
-
- @media only screen and (max-width: 480px) {
- .Toastify__toast {
- margin-bottom: 0;
- border-radius: 0;
- }
- }
- .Toastify__toast-theme--dark {
- background: var(--toastify-color-dark);
- color: var(--toastify-text-color-dark);
- }
- .Toastify__toast-theme--light {
- background: var(--toastify-color-light);
- color: var(--toastify-text-color-light);
- }
- .Toastify__toast-theme--colored.Toastify__toast--default {
- background: var(--toastify-color-light);
- color: var(--toastify-text-color-light);
- }
- .Toastify__toast-theme--colored.Toastify__toast--info {
- color: var(--toastify-text-color-info);
- background: var(--toastify-color-info);
- }
- .Toastify__toast-theme--colored.Toastify__toast--success {
- color: var(--toastify-text-color-success);
- background: var(--toastify-color-success);
- }
- .Toastify__toast-theme--colored.Toastify__toast--warning {
- color: var(--toastify-text-color-warning);
- background: var(--toastify-color-warning);
- }
- .Toastify__toast-theme--colored.Toastify__toast--error {
- color: var(--toastify-text-color-error);
- background: var(--toastify-color-error);
- }
-
- .Toastify__progress-bar-theme--light {
- background: var(--toastify-color-progress-light);
- }
- .Toastify__progress-bar-theme--dark {
- background: var(--toastify-color-progress-dark);
- }
- .Toastify__progress-bar--info {
- background: var(--toastify-color-progress-info);
- }
- .Toastify__progress-bar--success {
- background: var(--toastify-color-progress-success);
- }
- .Toastify__progress-bar--warning {
- background: var(--toastify-color-progress-warning);
- }
- .Toastify__progress-bar--error {
- background: var(--toastify-color-progress-error);
- }
- .Toastify__progress-bar-theme--colored.Toastify__progress-bar--info,
- .Toastify__progress-bar-theme--colored.Toastify__progress-bar--success,
- .Toastify__progress-bar-theme--colored.Toastify__progress-bar--warning,
- .Toastify__progress-bar-theme--colored.Toastify__progress-bar--error {
- background: var(--toastify-color-transparent);
- }
-
- .Toastify__close-button {
- color: #fff;
- background: transparent;
- outline: none;
- border: none;
- padding: 0;
- cursor: pointer;
- opacity: 0.7;
- transition: 0.3s ease;
- -ms-flex-item-align: start;
- align-self: flex-start;
- }
- .Toastify__close-button--light {
- color: #000;
- opacity: 0.3;
- }
- .Toastify__close-button > svg {
- fill: currentColor;
- height: 16px;
- width: 14px;
- }
- .Toastify__close-button:hover,
- .Toastify__close-button:focus {
- opacity: 1;
- }
-
- @keyframes Toastify__trackProgress {
- 0% {
- transform: scaleX(1);
- }
- 100% {
- transform: scaleX(0);
- }
- }
- .Toastify__progress-bar {
- position: absolute;
- bottom: 0;
- left: 0;
- width: 100%;
- height: 5px;
- z-index: var(--toastify-z-index);
- opacity: 0.7;
- transform-origin: left;
- }
- .Toastify__progress-bar--animated {
- animation: Toastify__trackProgress linear 1 forwards;
- }
- .Toastify__progress-bar--controlled {
- transition: transform 0.2s;
- }
- .Toastify__progress-bar--rtl {
- right: 0;
- left: initial;
- transform-origin: right;
- }
-
- .Toastify__spinner {
- width: 20px;
- height: 20px;
- box-sizing: border-box;
- border: 2px solid;
- border-radius: 100%;
- border-color: var(--toastify-spinner-color-empty-area);
- border-right-color: var(--toastify-spinner-color);
- animation: Toastify__spin 0.65s linear infinite;
- }
-
- @keyframes Toastify__bounceInRight {
- from,
- 60%,
- 75%,
- 90%,
- to {
- animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
- }
- from {
- opacity: 0;
- transform: translate3d(3000px, 0, 0);
- }
- 60% {
- opacity: 1;
- transform: translate3d(-25px, 0, 0);
- }
- 75% {
- transform: translate3d(10px, 0, 0);
- }
- 90% {
- transform: translate3d(-5px, 0, 0);
- }
- to {
- transform: none;
- }
- }
- @keyframes Toastify__bounceOutRight {
- 20% {
- opacity: 1;
- transform: translate3d(-20px, 0, 0);
- }
- to {
- opacity: 0;
- transform: translate3d(2000px, 0, 0);
- }
- }
- @keyframes Toastify__bounceInLeft {
- from,
- 60%,
- 75%,
- 90%,
- to {
- animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
- }
- 0% {
- opacity: 0;
- transform: translate3d(-3000px, 0, 0);
- }
- 60% {
- opacity: 1;
- transform: translate3d(25px, 0, 0);
- }
- 75% {
- transform: translate3d(-10px, 0, 0);
- }
- 90% {
- transform: translate3d(5px, 0, 0);
- }
- to {
- transform: none;
- }
- }
- @keyframes Toastify__bounceOutLeft {
- 20% {
- opacity: 1;
- transform: translate3d(20px, 0, 0);
- }
- to {
- opacity: 0;
- transform: translate3d(-2000px, 0, 0);
- }
- }
- @keyframes Toastify__bounceInUp {
- from,
- 60%,
- 75%,
- 90%,
- to {
- animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
- }
- from {
- opacity: 0;
- transform: translate3d(0, 3000px, 0);
- }
- 60% {
- opacity: 1;
- transform: translate3d(0, -20px, 0);
- }
- 75% {
- transform: translate3d(0, 10px, 0);
- }
- 90% {
- transform: translate3d(0, -5px, 0);
- }
- to {
- transform: translate3d(0, 0, 0);
- }
- }
- @keyframes Toastify__bounceOutUp {
- 20% {
- transform: translate3d(0, -10px, 0);
- }
- 40%,
- 45% {
- opacity: 1;
- transform: translate3d(0, 20px, 0);
- }
- to {
- opacity: 0;
- transform: translate3d(0, -2000px, 0);
- }
- }
- @keyframes Toastify__bounceInDown {
- from,
- 60%,
- 75%,
- 90%,
- to {
- animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
- }
- 0% {
- opacity: 0;
- transform: translate3d(0, -3000px, 0);
- }
- 60% {
- opacity: 1;
- transform: translate3d(0, 25px, 0);
- }
- 75% {
- transform: translate3d(0, -10px, 0);
- }
- 90% {
- transform: translate3d(0, 5px, 0);
- }
- to {
- transform: none;
- }
- }
- @keyframes Toastify__bounceOutDown {
- 20% {
- transform: translate3d(0, 10px, 0);
- }
- 40%,
- 45% {
- opacity: 1;
- transform: translate3d(0, -20px, 0);
- }
- to {
- opacity: 0;
- transform: translate3d(0, 2000px, 0);
- }
- }
- .Toastify__bounce-enter--top-left,
- .Toastify__bounce-enter--bottom-left {
- animation-name: Toastify__bounceInLeft;
- }
- .Toastify__bounce-enter--top-right,
- .Toastify__bounce-enter--bottom-right {
- animation-name: Toastify__bounceInRight;
- }
- .Toastify__bounce-enter--top-center {
- animation-name: Toastify__bounceInDown;
- }
- .Toastify__bounce-enter--bottom-center {
- animation-name: Toastify__bounceInUp;
- }
-
- .Toastify__bounce-exit--top-left,
- .Toastify__bounce-exit--bottom-left {
- animation-name: Toastify__bounceOutLeft;
- }
- .Toastify__bounce-exit--top-right,
- .Toastify__bounce-exit--bottom-right {
- animation-name: Toastify__bounceOutRight;
- }
- .Toastify__bounce-exit--top-center {
- animation-name: Toastify__bounceOutUp;
- }
- .Toastify__bounce-exit--bottom-center {
- animation-name: Toastify__bounceOutDown;
- }
-
- @keyframes Toastify__zoomIn {
- from {
- opacity: 0;
- transform: scale3d(0.3, 0.3, 0.3);
- }
- 50% {
- opacity: 1;
- }
- }
- @keyframes Toastify__zoomOut {
- from {
- opacity: 1;
- }
- 50% {
- opacity: 0;
- transform: scale3d(0.3, 0.3, 0.3);
- }
- to {
- opacity: 0;
- }
- }
- .Toastify__zoom-enter {
- animation-name: Toastify__zoomIn;
- }
-
- .Toastify__zoom-exit {
- animation-name: Toastify__zoomOut;
- }
-
- @keyframes Toastify__flipIn {
- from {
- transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
- animation-timing-function: ease-in;
- opacity: 0;
- }
- 40% {
- transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
- animation-timing-function: ease-in;
- }
- 60% {
- transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
- opacity: 1;
- }
- 80% {
- transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
- }
- to {
- transform: perspective(400px);
- }
- }
- @keyframes Toastify__flipOut {
- from {
- transform: perspective(400px);
- }
- 30% {
- transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
- opacity: 1;
- }
- to {
- transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
- opacity: 0;
- }
- }
- .Toastify__flip-enter {
- animation-name: Toastify__flipIn;
- }
-
- .Toastify__flip-exit {
- animation-name: Toastify__flipOut;
- }
-
- @keyframes Toastify__slideInRight {
- from {
- transform: translate3d(110%, 0, 0);
- visibility: visible;
- }
- to {
- transform: translate3d(0, 0, 0);
- }
- }
- @keyframes Toastify__slideInLeft {
- from {
- transform: translate3d(-110%, 0, 0);
- visibility: visible;
- }
- to {
- transform: translate3d(0, 0, 0);
- }
- }
- @keyframes Toastify__slideInUp {
- from {
- transform: translate3d(0, 110%, 0);
- visibility: visible;
- }
- to {
- transform: translate3d(0, 0, 0);
- }
- }
- @keyframes Toastify__slideInDown {
- from {
- transform: translate3d(0, -110%, 0);
- visibility: visible;
- }
- to {
- transform: translate3d(0, 0, 0);
- }
- }
- @keyframes Toastify__slideOutRight {
- from {
- transform: translate3d(0, 0, 0);
- }
- to {
- visibility: hidden;
- transform: translate3d(110%, 0, 0);
- }
- }
- @keyframes Toastify__slideOutLeft {
- from {
- transform: translate3d(0, 0, 0);
- }
- to {
- visibility: hidden;
- transform: translate3d(-110%, 0, 0);
- }
- }
- @keyframes Toastify__slideOutDown {
- from {
- transform: translate3d(0, 0, 0);
- }
- to {
- visibility: hidden;
- transform: translate3d(0, 500px, 0);
- }
- }
- @keyframes Toastify__slideOutUp {
- from {
- transform: translate3d(0, 0, 0);
- }
- to {
- visibility: hidden;
- transform: translate3d(0, -500px, 0);
- }
- }
- .Toastify__slide-enter--top-left,
- .Toastify__slide-enter--bottom-left {
- animation-name: Toastify__slideInLeft;
- }
- .Toastify__slide-enter--top-right,
- .Toastify__slide-enter--bottom-right {
- animation-name: Toastify__slideInRight;
- }
- .Toastify__slide-enter--top-center {
- animation-name: Toastify__slideInDown;
- }
- .Toastify__slide-enter--bottom-center {
- animation-name: Toastify__slideInUp;
- }
-
- .Toastify__slide-exit--top-left,
- .Toastify__slide-exit--bottom-left {
- animation-name: Toastify__slideOutLeft;
- }
- .Toastify__slide-exit--top-right,
- .Toastify__slide-exit--bottom-right {
- animation-name: Toastify__slideOutRight;
- }
- .Toastify__slide-exit--top-center {
- animation-name: Toastify__slideOutUp;
- }
- .Toastify__slide-exit--bottom-center {
- animation-name: Toastify__slideOutDown;
- }
-
- @keyframes Toastify__spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
- }
-
- /*# sourceMappingURL=ReactToastify.css.map */
-`;
diff --git a/server/sonar-web/src/main/js/design-system/components/toast-message/__tests__/ToastMessage-test.tsx b/server/sonar-web/src/main/js/design-system/components/toast-message/__tests__/ToastMessage-test.tsx
deleted file mode 100644
index 684f29f71e2..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/toast-message/__tests__/ToastMessage-test.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ToastContainer } from 'react-toastify';
-import { TOAST_AUTOCLOSE_DELAY } from '../../../helpers/constants';
-import { render } from '../../../helpers/testUtils';
-import { ToastMessageContainer } from '../ToastMessage';
-
-jest.mock('react-toastify', () => ({
- Slide: 'mock slide',
- ToastContainer: jest.fn(() => null),
- toast: { POSITION: { TOP_RIGHT: 'mock top right' } },
-}));
-
-it('should render the ToastMessageContainer', () => {
- setupWithProps();
-
- expect(ToastContainer).toHaveBeenCalledWith(
- {
- autoClose: TOAST_AUTOCLOSE_DELAY,
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
- className: expect.any(String),
- closeOnClick: true,
- draggable: true,
- hideProgressBar: true,
- limit: 0,
- newestOnTop: false,
- pauseOnFocusLoss: true,
- pauseOnHover: true,
- position: 'top-right',
- rtl: false,
- transition: 'mock slide',
- },
- {},
- );
-});
-
-function setupWithProps() {
- return render(<ToastMessageContainer />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/toast-message/__tests__/toast-utils-test.tsx b/server/sonar-web/src/main/js/design-system/components/toast-message/__tests__/toast-utils-test.tsx
deleted file mode 100644
index 8585a52b6c1..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/toast-message/__tests__/toast-utils-test.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { toast } from 'react-toastify';
-import { FlagErrorIcon, FlagSuccessIcon } from '../../icons';
-import {
- addGlobalErrorMessage,
- addGlobalSuccessMessage,
- dismissAllGlobalMessages,
-} from '../toast-utils';
-
-jest.mock('react-toastify', () => ({
- toast: jest.fn(),
-}));
-
-it('should call react-toastify with the right args', () => {
- addGlobalErrorMessage(<span>error</span>, { position: 'top-left' });
-
- expect(toast).toHaveBeenCalledWith(
- <div className="fs-mask sw-typo-default sw-p-3 sw-pb-4" data-testid="global-message__ERROR">
- <span>error</span>
- </div>,
- { icon: <FlagErrorIcon />, type: 'error', position: 'top-left' },
- );
-
- addGlobalSuccessMessage('it worked');
-
- expect(toast).toHaveBeenCalledWith(
- <div className="fs-mask sw-typo-default sw-p-3 sw-pb-4" data-testid="global-message__SUCCESS">
- it worked
- </div>,
- { icon: <FlagSuccessIcon />, type: 'success' },
- );
-
- toast.dismiss = jest.fn();
-
- dismissAllGlobalMessages();
-
- expect(toast.dismiss).toHaveBeenCalled();
-});
diff --git a/server/sonar-web/src/main/js/design-system/components/toast-message/toast-utils.tsx b/server/sonar-web/src/main/js/design-system/components/toast-message/toast-utils.tsx
deleted file mode 100644
index 74482d18820..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/toast-message/toast-utils.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ReactNode } from 'react';
-import { ToastOptions, toast } from 'react-toastify';
-import { FlagErrorIcon, FlagSuccessIcon } from '../icons';
-
-export interface Message {
- level: MessageLevel;
- message: string;
-}
-
-export enum MessageLevel {
- Error = 'ERROR',
- Success = 'SUCCESS',
-}
-
-export function addGlobalErrorMessage(message: ReactNode, overrides?: ToastOptions) {
- return createToast(message, MessageLevel.Error, overrides);
-}
-
-export function addGlobalSuccessMessage(message: ReactNode, overrides?: ToastOptions) {
- return createToast(message, MessageLevel.Success, overrides);
-}
-
-export function dismissAllGlobalMessages() {
- toast.dismiss();
-}
-
-function createToast(message: ReactNode, level: MessageLevel, overrides?: ToastOptions) {
- return toast(
- <div
- className="fs-mask sw-typo-default sw-p-3 sw-pb-4"
- data-testid={`global-message__${level}`}
- >
- {message}
- </div>,
- {
- icon: level === MessageLevel.Error ? <FlagErrorIcon /> : <FlagSuccessIcon />,
- type: level === MessageLevel.Error ? 'error' : 'success',
- ...overrides,
- },
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/visual-components/FishVisual.tsx b/server/sonar-web/src/main/js/design-system/components/visual-components/FishVisual.tsx
deleted file mode 100644
index aaa16563685..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/visual-components/FishVisual.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-
-interface Props {
- className?: string;
-}
-
-export function FishVisual({ className }: Props) {
- const theme = useTheme();
-
- return (
- <svg
- className={className}
- fill="none"
- height="168"
- width="168"
- xmlns="http://www.w3.org/2000/svg"
- >
- <g clipPath="url(#a)">
- <path
- d="M7 96.939c44.414-18.728 131.812 14.152 153-.439-.653 2.194-2.176 6.256-3.482 9.214C126.569 125.531 82.424 95.788 17.229 118 9.612 105.934 7 96.939 7 96.939ZM163.931 77.355C115.704 96.06 27.656 67.785 4.649 82.357 4.216 79.85 4 75.245 4 71.765 36.52 51.972 92.273 80.185 163.065 58c1.299 15.294.866 19.355.866 19.355ZM161 51.205C146.124 49.19 78.726 42.909 5 56a122.739 122.739 0 0 1 2.813-10.99c28.002-12.889 125.425-4.826 151.24-.798A745.03 745.03 0 0 1 161 51.205Z"
- fill={themeColor('illustrationShade')({ theme })}
- />
- <path
- d="M134 133.844C120.137 144.595 102.699 151 83.758 151 57.4 151 33.956 138.598 19 119.341c61.278-7.139 76.068 16.657 115 14.503Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- />
- <path
- clipRule="evenodd"
- d="M26.371 19.118C13.431 33.093 5.526 51.785 5.526 72.328c0 25.124 11.826 47.485 30.228 61.828 13.287 10.356 29.995 16.525 48.152 16.525 43.288 0 78.379-35.08 78.379-78.353 0-20.543-7.905-39.235-20.845-53.21l3.691-3.416c13.767 14.868 22.184 34.767 22.184 56.626 0 46.051-37.344 83.382-83.41 83.382-19.315 0-37.104-6.567-51.244-17.588C13.091 122.868.496 99.068.496 72.328c0-21.86 8.418-41.758 22.184-56.626l3.691 3.416Z"
- fill="var(--echoes-color-icon-subdued)"
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="m27.073 19.091-.338.364C13.877 33.343 6.023 51.916 6.023 72.328c0 24.964 11.75 47.184 30.036 61.436 13.203 10.291 29.805 16.42 47.847 16.42 43.014 0 77.883-34.858 77.883-77.856 0-20.413-7.855-38.986-20.713-52.873l-.337-.364L145.158 15l.337.364c13.849 14.956 22.317 34.975 22.317 56.964 0 46.325-37.567 83.879-83.906 83.879-19.43 0-37.326-6.607-51.55-17.693C12.669 123.17 0 99.227 0 72.328c0-21.99 8.468-42.008 22.316-56.964l.337-.364 4.42 4.091Zm-.702.027-.013.015C13.426 33.105 5.526 51.791 5.526 72.328c0 25.124 11.826 47.485 30.228 61.828 13.287 10.356 29.995 16.525 48.152 16.525 43.288 0 78.379-35.08 78.379-78.353 0-20.536-7.9-39.223-20.832-53.196a.18.18 0 0 0-.013-.014l3.691-3.416.014.015.322.35c13.568 14.828 21.848 34.58 21.848 56.26 0 46.052-37.344 83.383-83.41 83.383-19.315 0-37.104-6.567-51.244-17.588C13.091 122.868.496 99.068.496 72.328c0-21.68 8.28-41.433 21.848-56.261l.32-.347.016-.018 3.691 3.416Z"
- fill="var(--echoes-color-icon-subdued)"
- fillRule="evenodd"
- />
- <path
- d="M68 19a5 5 0 1 0 10 0 5 5 0 0 0-10 0ZM76 40.925a5 5 0 1 0 10 0 5 5 0 0 0-10 0ZM68 62.12a5 5 0 1 0 10 0 5 5 0 0 0-10 0Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- />
- <path
- d="M152.238 54.288c-2.47.206-5.832 4.717-7.72 6.69l1.544 9.264c1.544 1.287 3.603 5.661 7.205 5.918 3.603.258 5.662-5.918 5.662-11.58 0-5.753-3.603-10.55-6.691-10.292Z"
- fill={themeColor('illustrationPrimary')({ theme })}
- />
- <path
- d="M146.062 70.242c10.035 34.224-51.723 17.498-63.303 6.176-.772-.258-1.08-3.448 1.802-2.83 9.263 1.028 10.035-7.206 10.55-11.066.515-3.86 3.345-17.755 25.218-21.1 21.873-3.346 27.019 14.152 23.931 19.814 4.375-.258 7.72 6.433 1.802 9.006Z"
- fill={themeColor('illustrationPrimary')({ theme })}
- />
- <path
- d="M100.49 70.868a5.844 5.844 0 1 0 11.689 0 5.844 5.844 0 0 0-11.689 0Z"
- fill={themeColor('illustrationPrimary')({ theme })}
- />
- <path
- clipRule="evenodd"
- d="M106.334 72.878a2.01 2.01 0 1 1 0-4.02 2.01 2.01 0 0 1 0 4.02Zm0 3.834a5.844 5.844 0 1 1 0-11.688 5.844 5.844 0 0 1 0 11.688Z"
- fill={themeColor('backgroundSecondary')({ theme })}
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="M115.047 107.823a1.78 1.78 0 1 1-3.301-1.332 1.78 1.78 0 0 1 3.301 1.332Zm-1.879 4.479a5.15 5.15 0 0 0 2.154-9.918 5.15 5.15 0 0 0-5.285 8.676l-1.572 3.898-8.012-3.231-1.26 3.123 8.012 3.232-6.841 16.96c-6.675-3.451-9.804-11.129-8.727-13.8l-2.842-1.147c-2.348 5.824 2.488 12.284 6.155 17.183 1.94 2.591 3.552 4.745 3.601 6.137.995-.964 3.62-1.374 6.785-1.869 6.029-.943 14.017-2.191 16.422-8.155l-2.842-1.146c-1.125 2.79-8.357 5.916-15.41 4.013l6.822-16.916 7.526 3.035 1.26-3.124-7.526-3.035 1.58-3.916Zm8.945 16.385-5.849 2.487 8.336 3.363-2.487-5.85ZM91.8 116.461l2.487 5.849-8.336-3.362 5.85-2.487Z"
- fill="var(--echoes-color-icon-subdued)"
- fillRule="evenodd"
- />
- </g>
- <defs>
- <clipPath id="a">
- <path d="M0 0h168v168H0z" fill={themeColor('backgroundSecondary')({ theme })} />
- </clipPath>
- </defs>
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/visual-components/FlagVisual.tsx b/server/sonar-web/src/main/js/design-system/components/visual-components/FlagVisual.tsx
deleted file mode 100644
index 92827199793..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/visual-components/FlagVisual.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { themeColor } from '../../helpers/theme';
-
-interface Props {
- className?: string;
-}
-
-export function FlagVisual({ className }: Props) {
- const theme = useTheme();
-
- return (
- <svg
- className={className}
- fill="none"
- height="168"
- width="168"
- xmlns="http://www.w3.org/2000/svg"
- >
- <path
- d="M49.05 153.5c-10.87-1-15.29 5-15.97 8.5H16.44c1.7-6.5 14.26-19.5 32.61-8.5Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- />
- <path
- clipRule="evenodd"
- d="M18.34 162h38.32c-2.83-6.1-9.95-11-19.16-11s-16.33 4.9-19.16 11Zm-7.12 3.01C12.92 153.72 24.03 145 37.5 145s24.59 8.72 26.28 20.01c.24 1.64-1.12 2.99-2.78 2.99H14c-1.66 0-3.02-1.35-2.78-2.99Z"
- fill="var(--echoes-color-icon-subdued)"
- fillRule="evenodd"
- />
- <path
- d="M46 98h87c-32.68-4.13-67.2-4.58-81.02-55H46v55ZM42 12c-9 5-6.5 11-4.5 16.5l-5-.5c-5.5-9.5 0-15 9.5-16Z"
- fill={themeColor('illustrationSecondary')({ theme })}
- />
- <path
- clipRule="evenodd"
- d="M37.5 27a6.5 6.5 0 1 0 0-13 6.5 6.5 0 0 0 0 13Zm0 6a12.5 12.5 0 1 0 0-25 12.5 12.5 0 0 0 0 25Z"
- fill="var(--echoes-color-icon-subdued)"
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="M40 33.41h-5V144.6h5V33.4ZM29 27v124h17V27H29Z"
- fill="var(--echoes-color-icon-subdued)"
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="M40 37h41.11v6H46v55h89.42a1 1 0 0 0 .88-1.46l-11.84-22.81a7 7 0 0 1 0-6.46l11.84-22.8a1 1 0 0 0-.88-1.47h-6.3v-6h6.3a7 7 0 0 1 6.2 10.23l-11.83 22.8a1 1 0 0 0 0 .93l11.84 22.81a7 7 0 0 1-6.21 10.23H40V37Z"
- fill="var(--echoes-color-icon-subdued)"
- fillRule="evenodd"
- />
- <path
- clipRule="evenodd"
- d="M117.18 5.7c-.96.74-2.03 1.35-3.18 1.8a13.33 13.33 0 0 1 7.5 7.5 13.29 13.29 0 0 1 7.5-7.5 13.33 13.33 0 0 1-7.5-7.5 13.29 13.29 0 0 1-4.32 5.7Zm2.55 1.8c.64.54 1.23 1.13 1.77 1.77.54-.64 1.13-1.23 1.77-1.77a16.35 16.35 0 0 1-1.77-1.77c-.54.64-1.13 1.23-1.77 1.77ZM87.92 30.06A45.26 45.26 0 0 1 81 33.5 45.26 45.26 0 0 1 106.5 59 45.21 45.21 0 0 1 132 33.5 45.24 45.24 0 0 1 106.5 8a45.21 45.21 0 0 1-18.58 22.06Zm5.71 3.44a51.28 51.28 0 0 1 12.87 12.87 51.28 51.28 0 0 1 12.87-12.87 51.28 51.28 0 0 1-12.87-12.87A51.28 51.28 0 0 1 93.63 33.5ZM132.01 17.38A26.64 26.64 0 0 1 127 20a26.64 26.64 0 0 1 15 15 26.62 26.62 0 0 1 15-15 26.64 26.64 0 0 1-15-15 26.61 26.61 0 0 1-9.99 12.38Zm4.07 2.62a31.13 31.13 0 0 1 5.92 5.92 31.13 31.13 0 0 1 5.92-5.92 31.13 31.13 0 0 1-5.92-5.92 31.13 31.13 0 0 1-5.92 5.92Z"
- fill={themeColor('illustrationPrimary')({ theme })}
- fillRule="evenodd"
- />
- </svg>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/components/visual-components/index.ts b/server/sonar-web/src/main/js/design-system/components/visual-components/index.ts
deleted file mode 100644
index 8259c122134..00000000000
--- a/server/sonar-web/src/main/js/design-system/components/visual-components/index.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './FishVisual';
-export * from './FlagVisual';
diff --git a/server/sonar-web/src/main/js/design-system/helpers/__tests__/colors-test.ts b/server/sonar-web/src/main/js/design-system/helpers/__tests__/colors-test.ts
deleted file mode 100644
index 76d324c6e80..00000000000
--- a/server/sonar-web/src/main/js/design-system/helpers/__tests__/colors-test.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as colors from '../colors';
-
-describe('#stringToColor', () => {
- it('should return a color for a text', () => {
- expect(colors.stringToColor('skywalker')).toBe('#97f047');
- });
-});
-
-describe('#isDarkColor', () => {
- it('should be dark', () => {
- expect(colors.isDarkColor('#000000')).toBe(true);
- expect(colors.isDarkColor('#222222')).toBe(true);
- expect(colors.isDarkColor('#000')).toBe(true);
- });
- it('should be light', () => {
- expect(colors.isDarkColor('#FFFFFF')).toBe(false);
- expect(colors.isDarkColor('#CDCDCD')).toBe(false);
- expect(colors.isDarkColor('#FFF')).toBe(false);
- });
-});
-
-describe('#getTextColor', () => {
- it('should return dark color', () => {
- expect(colors.getTextColor('#FFF', 'dark', 'light')).toBe('dark');
- expect(colors.getTextColor('#FFF')).toBe('#222');
- });
- it('should return light color', () => {
- expect(colors.getTextColor('#000', 'dark', 'light')).toBe('light');
- expect(colors.getTextColor('#000')).toBe('#fff');
- });
-});
-
-describe('rgb array to color', () => {
- it('should return rgb color without opacity', () => {
- expect(colors.getRGBAString([0, 0, 0])).toBe('rgb(0,0,0)');
- expect(colors.getRGBAString([255, 255, 255])).toBe('rgb(255,255,255)');
- });
- it('should return rgba color with opacity', () => {
- expect(colors.getRGBAString([5, 6, 100], 0.05)).toBe('rgba(5,6,100,0.05)');
- expect(colors.getRGBAString([255, 255, 255], 0)).toBe('rgba(255,255,255,0)');
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/helpers/__tests__/dom-test.ts b/server/sonar-web/src/main/js/design-system/helpers/__tests__/dom-test.ts
deleted file mode 100644
index d900cb22b91..00000000000
--- a/server/sonar-web/src/main/js/design-system/helpers/__tests__/dom-test.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { findAnchor } from '../dom';
-
-it('should find the correct anchor', () => {
- const targetRect = new DOMRect(20, 20, 10, 10);
-
- let rect = new DOMRect(25, 0, 30, 10);
- expect(findAnchor(rect, targetRect, 8)).toStrictEqual({
- left: -1.5,
- rotate: '-90deg',
- top: 16,
- width: 6,
- });
-
- rect = new DOMRect(35, 25, 30, 10);
- expect(findAnchor(rect, targetRect, 8)).toStrictEqual({
- left: -9,
- rotate: '0deg',
- top: -1.5,
- width: 1,
- });
-
- rect = new DOMRect(25, 35, 30, 10);
- expect(findAnchor(rect, targetRect, 8)).toStrictEqual({
- left: -1.5,
- rotate: '90deg',
- top: -9,
- width: 1,
- });
-
- rect = new DOMRect(0, 25, 10, 30);
- expect(findAnchor(rect, targetRect, 8)).toStrictEqual({
- left: 24,
- rotate: '180deg',
- top: -1.5,
- width: 14,
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/helpers/__tests__/positioning-test.ts b/server/sonar-web/src/main/js/design-system/helpers/__tests__/positioning-test.ts
deleted file mode 100644
index 2eafebe2aa2..00000000000
--- a/server/sonar-web/src/main/js/design-system/helpers/__tests__/positioning-test.ts
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { PopupPlacement, popupPositioning } from '../positioning';
-
-const toggleRect = {
- getBoundingClientRect: jest.fn().mockReturnValue({
- left: 400,
- top: 200,
- width: 50,
- height: 20,
- }),
-} as Element & { getBoundingClientRect: jest.Mock };
-
-const popupRect = {
- getBoundingClientRect: jest.fn().mockReturnValue({
- width: 200,
- height: 100,
- }),
-} as Element & { getBoundingClientRect: jest.Mock };
-
-beforeAll(() => {
- Object.defineProperties(document.documentElement, {
- clientWidth: {
- configurable: true,
- value: 1000,
- },
- clientHeight: {
- configurable: true,
- value: 1000,
- },
- });
-});
-
-it('should calculate positioning based on placement', () => {
- const fixes = { leftFix: 0, topFix: 0 };
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.Bottom)).toMatchObject({
- left: 325,
- top: 220,
- ...fixes,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.BottomLeft)).toMatchObject({
- left: 400,
- top: 220,
- ...fixes,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.BottomRight)).toMatchObject({
- left: 250,
- top: 220,
- ...fixes,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.Top)).toMatchObject({
- left: 325,
- top: 100,
- ...fixes,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.TopLeft)).toMatchObject({
- left: 400,
- top: 100,
- ...fixes,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.TopRight)).toMatchObject({
- left: 250,
- top: 100,
- ...fixes,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.Left)).toMatchObject({
- left: 200,
- top: 160,
- ...fixes,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.LeftBottom)).toMatchObject({
- left: 200,
- top: 120,
- ...fixes,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.LeftTop)).toMatchObject({
- left: 200,
- top: 200,
- ...fixes,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.Right)).toMatchObject({
- left: 450,
- top: 160,
- ...fixes,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.RightBottom)).toMatchObject({
- left: 450,
- top: 120,
- ...fixes,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.RightTop)).toMatchObject({
- left: 450,
- top: 200,
- ...fixes,
- });
-});
-
-it('should position the element in the boundaries of the screen', () => {
- toggleRect.getBoundingClientRect.mockReturnValueOnce({
- left: 0,
- top: 850,
- width: 50,
- height: 50,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.Bottom)).toMatchObject({
- left: 4,
- leftFix: 79,
- top: 896,
- topFix: -4,
- });
- toggleRect.getBoundingClientRect.mockReturnValueOnce({
- left: 900,
- top: 0,
- width: 50,
- height: 50,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.Top)).toMatchObject({
- left: 796,
- leftFix: -29,
- top: 4,
- topFix: 104,
- });
-});
-
-it('should position the element outside the boundaries of the screen when the toggle is outside', () => {
- toggleRect.getBoundingClientRect.mockReturnValueOnce({
- left: -100,
- top: 1100,
- width: 50,
- height: 50,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.Bottom)).toMatchObject({
- left: -75,
- leftFix: 100,
- top: 1025,
- topFix: -125,
- });
- toggleRect.getBoundingClientRect.mockReturnValueOnce({
- left: 1500,
- top: -200,
- width: 50,
- height: 50,
- });
- expect(popupPositioning(toggleRect, popupRect, PopupPlacement.Top)).toMatchObject({
- left: 1325,
- leftFix: -100,
- top: -175,
- topFix: 125,
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/helpers/__tests__/theme-test.ts b/server/sonar-web/src/main/js/design-system/helpers/__tests__/theme-test.ts
deleted file mode 100644
index aae6affd92f..00000000000
--- a/server/sonar-web/src/main/js/design-system/helpers/__tests__/theme-test.ts
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as ThemeHelper from '../../helpers/theme';
-import { lightTheme } from '../../theme';
-
-const props = {
- color: 'rgb(0,0,0)',
-};
-
-describe('getProp', () => {
- it('should work', () => {
- expect(ThemeHelper.getProp('color')(props)).toEqual('rgb(0,0,0)');
- });
-});
-
-describe('themeColor', () => {
- it('should work for light theme', () => {
- expect(ThemeHelper.themeColor('backgroundPrimary')({ theme: lightTheme })).toEqual(
- 'rgb(252,252,253)',
- );
- });
-
- it('should work with a theme-defined opacity', () => {
- expect(ThemeHelper.themeColor('bannerIconHover')({ theme: lightTheme })).toEqual(
- 'rgba(217,45,32,0.2)',
- );
- });
-
- it('should work for all kind of color parameters', () => {
- expect(ThemeHelper.themeColor('transparent')({ theme: lightTheme })).toEqual('transparent');
- expect(ThemeHelper.themeColor('currentColor')({ theme: lightTheme })).toEqual('currentColor');
- expect(ThemeHelper.themeColor('var(--test)')({ theme: lightTheme })).toEqual('var(--test)');
- expect(ThemeHelper.themeColor('rgb(0,0,0)')({ theme: lightTheme })).toEqual('rgb(0,0,0)');
- expect(ThemeHelper.themeColor('rgba(0,0,0,1)')({ theme: lightTheme })).toEqual('rgba(0,0,0,1)');
- expect(
- ThemeHelper.themeColor(ThemeHelper.themeContrast('backgroundPrimary')({ theme: lightTheme }))(
- {
- theme: lightTheme,
- },
- ),
- ).toEqual('rgb(8,9,12)');
- expect(
- ThemeHelper.themeColor(ThemeHelper.themeAvatarColor('luke')({ theme: lightTheme }))({
- theme: lightTheme,
- }),
- ).toEqual('rgb(209,215,254)');
- });
-});
-
-describe('themeContrast', () => {
- it('should work for light theme', () => {
- expect(ThemeHelper.themeContrast('backgroundPrimary')({ theme: lightTheme })).toEqual(
- 'rgb(8,9,12)',
- );
- });
-
- it('should work for all kind of color parameters', () => {
- expect(ThemeHelper.themeContrast('var(--test)')({ theme: lightTheme })).toEqual('var(--test)');
- expect(ThemeHelper.themeContrast('rgb(0,0,0)')({ theme: lightTheme })).toEqual('rgb(0,0,0)');
- expect(ThemeHelper.themeContrast('rgba(0,0,0,1)')({ theme: lightTheme })).toEqual(
- 'rgba(0,0,0,1)',
- );
- expect(
- ThemeHelper.themeContrast(ThemeHelper.themeColor('backgroundPrimary')({ theme: lightTheme }))(
- {
- theme: lightTheme,
- },
- ),
- ).toEqual('rgb(252,252,253)');
- expect(
- ThemeHelper.themeContrast(ThemeHelper.themeAvatarColor('luke')({ theme: lightTheme }))({
- theme: lightTheme,
- }),
- ).toEqual('rgb(209,215,254)');
- expect(
- ThemeHelper.themeContrast('backgroundPrimary')({
- theme: {
- ...lightTheme,
- contrasts: { ...lightTheme.contrasts, backgroundPrimary: 'inherit' },
- },
- }),
- ).toEqual('inherit');
- });
-});
-
-describe('themeBorder', () => {
- it('should work for light theme', () => {
- expect(ThemeHelper.themeBorder()({ theme: lightTheme })).toEqual('1px solid rgb(235,235,235)');
- });
- it('should allow to override the color of the border', () => {
- expect(ThemeHelper.themeBorder('focus', 'primaryLight')({ theme: lightTheme })).toEqual(
- '4px solid rgba(123,135,217,0.2)',
- );
- });
- it('should allow to override the opacity of the border', () => {
- expect(ThemeHelper.themeBorder('focus', undefined, 0.5)({ theme: lightTheme })).toEqual(
- '4px solid rgba(197,205,223,0.5)',
- );
- });
- it('should allow to pass a CSS prop as color name', () => {
- expect(
- ThemeHelper.themeBorder('focus', 'var(--outlineColor)', 0.5)({ theme: lightTheme }),
- ).toEqual('4px solid var(--outlineColor)');
- });
-});
-
-describe('themeShadow', () => {
- it('should work for light theme', () => {
- expect(ThemeHelper.themeShadow('xs')({ theme: lightTheme })).toEqual(
- '0px 1px 2px 0px rgba(29,33,47,0.05)',
- );
- });
- it('should allow to override the color of the shadow', () => {
- expect(ThemeHelper.themeShadow('xs', 'backgroundPrimary')({ theme: lightTheme })).toEqual(
- '0px 1px 2px 0px rgba(252,252,253,0.05)',
- );
- expect(ThemeHelper.themeShadow('xs', 'transparent')({ theme: lightTheme })).toEqual(
- '0px 1px 2px 0px transparent',
- );
- });
- it('should allow to override the opacity of the shadow', () => {
- expect(ThemeHelper.themeShadow('xs', 'backgroundPrimary', 0.8)({ theme: lightTheme })).toEqual(
- '0px 1px 2px 0px rgba(252,252,253,0.8)',
- );
- });
- it('should allow to pass a CSS prop as color name', () => {
- expect(ThemeHelper.themeShadow('xs', 'var(--shadowColor)')({ theme: lightTheme })).toEqual(
- '0px 1px 2px 0px var(--shadowColor)',
- );
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/helpers/colors.ts b/server/sonar-web/src/main/js/design-system/helpers/colors.ts
deleted file mode 100644
index 93fd0b2eb68..00000000000
--- a/server/sonar-web/src/main/js/design-system/helpers/colors.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CSSColor } from '../types/theme';
-
-/* eslint-disable no-bitwise, no-mixed-operators */
-
-export function stringToColor(str: string) {
- let hash = 0;
-
- for (let i = 0; i < str.length; i++) {
- hash = str.charCodeAt(i) + ((hash << 5) - hash);
- }
-
- let color = '#';
-
- for (let i = 0; i < 3; i++) {
- const value = (hash >> (i * 8)) & 0xff;
- color += value.toString(16).padStart(2, '0');
- }
-
- return color;
-}
-
-export function isDarkColor(color: string) {
- color = color.substring(1);
-
- if (color.length === 3) {
- // shortcut notation: #f90
- color = color[0] + color[0] + color[1] + color[1] + color[2] + color[2];
- }
-
- const rgb = parseInt(color.substring(1), 16);
- const r = (rgb >> 16) & 0xff;
- const g = (rgb >> 8) & 0xff;
- const b = (rgb >> 0) & 0xff;
- const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b;
-
- return luma < 140;
-}
-
-export function getTextColor(background: string, dark = '#222', light = '#fff') {
- return isDarkColor(background) ? light : dark;
-}
-
-export function getRGBAString([r, g, b]: Array<number | string>, a?: number | string) {
- return (a !== undefined ? `rgba(${r},${g},${b},${a})` : `rgb(${r},${g},${b})`) as CSSColor;
-}
diff --git a/server/sonar-web/src/main/js/design-system/helpers/constants.ts b/server/sonar-web/src/main/js/design-system/helpers/constants.ts
deleted file mode 100644
index 10666ac45bd..00000000000
--- a/server/sonar-web/src/main/js/design-system/helpers/constants.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { theme } from 'twin.macro';
-
-export const DEFAULT_LOCALE = 'en';
-export const IS_SSR = typeof window === 'undefined';
-export const REACT_DOM_CONTAINER = '#content';
-
-export const RULE_STATUSES = ['READY', 'BETA', 'DEPRECATED'];
-
-export const THROTTLE_SCROLL_DELAY = 10;
-export const THROTTLE_KEYPRESS_DELAY = 100;
-
-export const DEBOUNCE_DELAY = 250;
-
-export const DEBOUNCE_LONG_DELAY = 1000;
-
-export const DEBOUNCE_SUCCESS_DELAY = 1000;
-
-export const INTERACTIVE_TOOLTIP_DELAY = 0.5;
-
-export const LEAK_PERIOD = 'sonar.leak.period';
-
-export const LEAK_PERIOD_TYPE = 'sonar.leak.period.type';
-
-export const INPUT_SIZES = {
- small: theme('width.input-small'),
- medium: theme('width.input-medium'),
- large: theme('width.input-large'),
- full: theme('width.full'),
- auto: theme('width.auto'),
-};
-
-export const LAYOUT_VIEWPORT_MIN_WIDTH = 1280;
-export const LAYOUT_VIEWPORT_MAX_WIDTH = 1280;
-export const LAYOUT_VIEWPORT_MAX_WIDTH_LARGE = 1680;
-export const LAYOUT_MAIN_CONTENT_GUTTER = 60;
-export const LAYOUT_SIDEBAR_WIDTH = 240;
-export const LAYOUT_SIDEBAR_COLLAPSED_WIDTH = 60;
-export const LAYOUT_SIDEBAR_BREAKPOINT = 1320;
-export const LAYOUT_BANNER_HEIGHT = 44;
-export const LAYOUT_BRANDING_ICON_WIDTH = 198;
-export const LAYOUT_FILTERBAR_HEADER = 56;
-export const LAYOUT_GLOBAL_NAV_HEIGHT = 52;
-export const LAYOUT_PROJECT_NAV_HEIGHT = 108;
-export const LAYOUT_LOGO_MARGIN_RIGHT = 45;
-export const LAYOUT_LOGO_MAX_HEIGHT = 40;
-export const LAYOUT_LOGO_MAX_WIDTH = 150;
-export const LAYOUT_FOOTER_HEIGHT = 69;
-export const LAYOUT_NOTIFICATIONSBAR_WIDTH = 350;
-
-export const CORE_CONCEPTS_WIDTH = 350;
-
-export const DARK_THEME_ID = 'dark-theme';
-
-export const OPACITY_20_PERCENT = 0.2;
-
-export const OPACITY_75_PERCENT = 0.75;
-
-export const GLOBAL_POPUP_Z_INDEX = 5000;
-
-export const TOAST_AUTOCLOSE_DELAY = 5000;
diff --git a/server/sonar-web/src/main/js/design-system/helpers/dom.ts b/server/sonar-web/src/main/js/design-system/helpers/dom.ts
deleted file mode 100644
index 03bdf13085a..00000000000
--- a/server/sonar-web/src/main/js/design-system/helpers/dom.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/**
- * This function find the point on the target element using the rect coordinat.
- * This point will serve as an anchor for rect to be attached
- *
- * This function assume that rect side will overlap the target facing side. If not
- * the case the point would be outside the target rect. For now we don't need to
- * handle this situation.
- * @param rect
- * @param targetRect
- */
-export function findAnchor(rect: DOMRect, targetRect: DOMRect, offset: number) {
- const offestTop = rect.top < targetRect.top ? targetRect.top - rect.top : 0;
- const offestLeft = rect.left < targetRect.left ? targetRect.left - rect.left : 0;
-
- if (targetRect.right < rect.left) {
- const left = targetRect.right - rect.left - offset / 2;
- const top =
- (Math.min(targetRect.bottom, rect.bottom) - Math.max(targetRect.top, rect.top)) / 2 -
- offset / 2 +
- offestTop;
- const rotate = '0deg';
- const width = -left - offset;
-
- return { left, top, rotate, width };
- } else if (targetRect.left > rect.right) {
- const left = rect.width + targetRect.left - rect.right + offset / 2;
- const top =
- (Math.min(targetRect.bottom, rect.bottom) - Math.max(targetRect.top, rect.top)) / 2 -
- offset / 2 +
- offestTop;
- const rotate = '180deg';
- const width = left - rect.width;
- return { left, top, rotate, width };
- } else if (targetRect.bottom < rect.top) {
- const left =
- (Math.min(targetRect.right, rect.right) - Math.max(targetRect.left, rect.left)) / 2 -
- offset / 2 +
- offestLeft;
- const top = targetRect.bottom - rect.top - offset / 2;
- const rotate = '90deg';
- const width = -top - offset;
- return { left, top, rotate, width };
- } else if (targetRect.top > rect.bottom) {
- const left =
- (Math.min(targetRect.right, rect.right) - Math.max(targetRect.left, rect.left)) / 2 -
- offset / 2 +
- offestLeft;
- const top = targetRect.top - rect.top - offset / 2;
- const rotate = '-90deg';
- const width = top - rect.height;
- return { left, top, rotate, width };
- }
-
- // When rectagle overlap
- return { left: 0, top: 0, rotate: '0deg', width: 0 };
-}
diff --git a/server/sonar-web/src/main/js/design-system/helpers/index.ts b/server/sonar-web/src/main/js/design-system/helpers/index.ts
deleted file mode 100644
index 7af0536ce90..00000000000
--- a/server/sonar-web/src/main/js/design-system/helpers/index.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './colors';
-export * from './constants';
-export * from './keyboard';
-export * from './positioning';
-export * from './theme';
diff --git a/server/sonar-web/src/main/js/design-system/helpers/keyboard.ts b/server/sonar-web/src/main/js/design-system/helpers/keyboard.ts
deleted file mode 100644
index a95b0d6366f..00000000000
--- a/server/sonar-web/src/main/js/design-system/helpers/keyboard.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum Key {
- ArrowLeft = 'ArrowLeft',
- ArrowUp = 'ArrowUp',
- ArrowRight = 'ArrowRight',
- ArrowDown = 'ArrowDown',
-
- Alt = 'Alt',
- Option = 'Option',
- Backspace = 'Backspace',
- CapsLock = 'CapsLock',
- Meta = 'Meta',
- Control = 'Control',
- Command = 'Command',
- Delete = 'Delete',
- End = 'End',
- Enter = 'Enter',
- Escape = 'Escape',
- Home = 'Home',
- PageDown = 'PageDown',
- PageUp = 'PageUp',
- Shift = 'Shift',
- Space = ' ',
- Tab = 'Tab',
- Click = 'Click',
-}
-
-export function isShortcut(event: KeyboardEvent): boolean {
- return event.ctrlKey || event.metaKey;
-}
-
-const INPUT_TAGS = ['INPUT', 'SELECT', 'TEXTAREA', 'UBCOMMENT'];
-
-export function isInput(event: KeyboardEvent): boolean {
- const { tagName } = event.target as HTMLElement;
- return INPUT_TAGS.includes(tagName);
-}
-
-export function isTextarea(
- event: KeyboardEvent,
-): event is KeyboardEvent & { target: HTMLTextAreaElement } {
- return event.target instanceof HTMLTextAreaElement;
-}
diff --git a/server/sonar-web/src/main/js/design-system/helpers/positioning.ts b/server/sonar-web/src/main/js/design-system/helpers/positioning.ts
deleted file mode 100644
index 9b56acf546d..00000000000
--- a/server/sonar-web/src/main/js/design-system/helpers/positioning.ts
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/**
- * Positioning rules:
- * - Bottom = below the block, horizontally centered
- * - BottomLeft = below the block, horizontally left-aligned
- * - BottomRight = below the block, horizontally right-aligned
- * - Left = Left of the block, vertically centered
- * - LeftTop = on the left-side of the block, vertically top-aligned
- * - LeftBottom = on the left-side of the block, vertically bottom-aligned
- * - Right = Right of the block, vertically centered
- * - RightTop = on the right-side of the block, vertically top-aligned
- * - RightBottom = on the right-side of the block, vetically bottom-aligned
- * - Top = above the block, horizontally centered
- * - TopLeft = above the block, horizontally left-aligned
- * - TopRight = above the block, horizontally right-aligned
- */
-
-export enum PopupPlacement {
- Bottom = 'bottom',
- BottomLeft = 'bottom-left',
- BottomRight = 'bottom-right',
- Left = 'left',
- LeftTop = 'left-top',
- LeftBottom = 'left-bottom',
- Right = 'right',
- RightTop = 'right-top',
- RightBottom = 'right-bottom',
- Top = 'top',
- TopLeft = 'top-left',
- TopRight = 'top-right',
-}
-
-export enum PopupZLevel {
- Content = 'content',
- Default = 'popup',
- Global = 'global',
- Absolute = 'absolute',
-}
-
-export type BasePlacement = Extract<
- PopupPlacement,
- PopupPlacement.Bottom | PopupPlacement.Top | PopupPlacement.Left | PopupPlacement.Right
->;
-
-export const PLACEMENT_FLIP_MAP: { [key in PopupPlacement]: PopupPlacement } = {
- [PopupPlacement.Left]: PopupPlacement.Right,
- [PopupPlacement.LeftBottom]: PopupPlacement.RightBottom,
- [PopupPlacement.LeftTop]: PopupPlacement.RightTop,
- [PopupPlacement.Right]: PopupPlacement.Left,
- [PopupPlacement.RightBottom]: PopupPlacement.LeftBottom,
- [PopupPlacement.RightTop]: PopupPlacement.LeftTop,
- [PopupPlacement.Top]: PopupPlacement.Bottom,
- [PopupPlacement.TopLeft]: PopupPlacement.BottomLeft,
- [PopupPlacement.TopRight]: PopupPlacement.BottomRight,
- [PopupPlacement.Bottom]: PopupPlacement.Top,
- [PopupPlacement.BottomLeft]: PopupPlacement.TopLeft,
- [PopupPlacement.BottomRight]: PopupPlacement.TopRight,
-};
-
-const MARGIN_TO_EDGE = 4;
-
-export function popupPositioning(
- toggleNode: Element,
- popupNode: Element,
- placement: PopupPlacement = PopupPlacement.Bottom,
-) {
- const toggleRect = toggleNode.getBoundingClientRect();
- const popupRect = popupNode.getBoundingClientRect();
-
- let { left, top } = toggleRect;
-
- switch (placement) {
- case PopupPlacement.Bottom:
- left += toggleRect.width / 2 - popupRect.width / 2;
- top += toggleRect.height;
- break;
- case PopupPlacement.BottomLeft:
- top += toggleRect.height;
- break;
- case PopupPlacement.BottomRight:
- left += toggleRect.width - popupRect.width;
- top += toggleRect.height;
- break;
- case PopupPlacement.Left:
- left -= popupRect.width;
- top += toggleRect.height / 2 - popupRect.height / 2;
- break;
- case PopupPlacement.LeftTop:
- left -= popupRect.width;
- break;
- case PopupPlacement.LeftBottom:
- left -= popupRect.width;
- top += toggleRect.height - popupRect.height;
- break;
- case PopupPlacement.Right:
- left += toggleRect.width;
- top += toggleRect.height / 2 - popupRect.height / 2;
- break;
- case PopupPlacement.RightTop:
- left += toggleRect.width;
- break;
- case PopupPlacement.RightBottom:
- left += toggleRect.width;
- top += toggleRect.height - popupRect.height;
- break;
- case PopupPlacement.Top:
- left += toggleRect.width / 2 - popupRect.width / 2;
- top -= popupRect.height;
- break;
- case PopupPlacement.TopLeft:
- top -= popupRect.height;
- break;
- case PopupPlacement.TopRight:
- left += toggleRect.width - popupRect.width;
- top -= popupRect.height;
- break;
- }
-
- const inBoundariesLeft = Math.min(
- Math.max(left, getMinLeftPlacement(toggleRect)),
- getMaxLeftPlacement(toggleRect, popupRect),
- );
-
- const inBoundariesTop = Math.min(
- Math.max(top, getMinTopPlacement(toggleRect)),
- getMaxTopPlacement(toggleRect, popupRect),
- );
-
- return {
- height: popupRect.height,
- left: inBoundariesLeft,
- leftFix: inBoundariesLeft - left,
- top: inBoundariesTop,
- topFix: inBoundariesTop - top,
- width: popupRect.width,
- };
-}
-
-function getMinLeftPlacement(toggleRect: DOMRect) {
- return Math.min(
- MARGIN_TO_EDGE, // Left edge of the sceen
- toggleRect.left + toggleRect.width / 2, // Left edge of the screen when scrolled
- );
-}
-
-function getMaxLeftPlacement(toggleRect: DOMRect, popupRect: DOMRect) {
- return Math.max(
- document.documentElement.clientWidth - popupRect.width - MARGIN_TO_EDGE, // Right edge of the screen
- toggleRect.left + toggleRect.width / 2 - popupRect.width, // Right edge of the screen when scrolled
- );
-}
-
-function getMinTopPlacement(toggleRect: DOMRect) {
- return Math.min(
- MARGIN_TO_EDGE, // Top edge of the sceen
- toggleRect.top + toggleRect.height / 2, // Top edge of the screen when scrolled
- );
-}
-
-function getMaxTopPlacement(toggleRect: DOMRect, popupRect: DOMRect) {
- return Math.max(
- document.documentElement.clientHeight - popupRect.height - MARGIN_TO_EDGE, // Bottom edge of the screen
- toggleRect.top + toggleRect.height / 2 - popupRect.height, // Bottom edge of the screen when scrolled
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/helpers/testUtils.tsx b/server/sonar-web/src/main/js/design-system/helpers/testUtils.tsx
deleted file mode 100644
index c31a0a5216d..00000000000
--- a/server/sonar-web/src/main/js/design-system/helpers/testUtils.tsx
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { RenderOptions, RenderResult, render as rtlRender } from '@testing-library/react';
-import userEvent, { UserEvent } from '@testing-library/user-event';
-import { Options as UserEventsOptions } from '@testing-library/user-event/dist/types/options';
-import { InitialEntry } from 'history';
-import { identity, kebabCase } from 'lodash';
-import React, { PropsWithChildren, ReactNode } from 'react';
-import { HelmetProvider } from 'react-helmet-async';
-import { IntlProvider, ReactIntlErrorCode } from 'react-intl';
-import { MemoryRouter, Route, Routes } from 'react-router-dom';
-
-type RenderResultWithUser = RenderResult & { user: UserEvent };
-
-export function render(
- ui: React.ReactElement,
- options?: RenderOptions,
- userEventOptions?: UserEventsOptions,
-): RenderResultWithUser {
- return { ...rtlRender(ui, options), user: userEvent.setup(userEventOptions) };
-}
-
-type RenderContextOptions = Omit<RenderOptions, 'wrapper'> & {
- initialEntries?: InitialEntry[];
- userEventOptions?: UserEventsOptions;
-};
-
-export function renderWithContext(
- ui: React.ReactElement,
- { userEventOptions, ...options }: RenderContextOptions = {},
-) {
- return render(ui, { ...options, wrapper: getContextWrapper() }, userEventOptions);
-}
-
-interface RenderRouterOptions {
- additionalRoutes?: ReactNode;
-}
-
-export function renderWithRouter(
- ui: React.ReactElement,
- options: RenderContextOptions & RenderRouterOptions = {},
-) {
- const { additionalRoutes, userEventOptions, ...renderOptions } = options;
-
- function RouterWrapper({ children }: React.PropsWithChildren<object>) {
- return (
- <HelmetProvider>
- <IntlWrapper>
- <MemoryRouter>
- <Routes>
- <Route element={children} path="/" />
- {additionalRoutes}
- </Routes>
- </MemoryRouter>
- </IntlWrapper>
- </HelmetProvider>
- );
- }
-
- return render(ui, { ...renderOptions, wrapper: RouterWrapper }, userEventOptions);
-}
-
-function getContextWrapper() {
- return function ContextWrapper({ children }: React.PropsWithChildren<object>) {
- return (
- <HelmetProvider>
- <IntlWrapper>{children}</IntlWrapper>
- </HelmetProvider>
- );
- };
-}
-
-export function mockComponent(name: string, transformProps: (props: any) => any = identity) {
- function MockedComponent({ ...props }: PropsWithChildren<any>) {
- return React.createElement('mocked-' + kebabCase(name), transformProps(props));
- }
-
- MockedComponent.displayName = `mocked(${name})`;
- return MockedComponent;
-}
-
-export const debounceTimer = jest
- .fn()
- .mockImplementation((callback: (...args: unknown[]) => void, timeout: number) => {
- let timeoutId: number;
-
- const debounced = jest.fn((...args: unknown[]) => {
- window.clearTimeout(timeoutId);
-
- timeoutId = window.setTimeout(() => {
- callback(...args);
- }, timeout);
- });
-
- (debounced as typeof debounced & { cancel: () => void }).cancel = jest.fn(() => {
- window.clearTimeout(timeoutId);
- });
-
- return debounced;
- });
-
-export function IntlWrapper({
- children,
- messages = {},
-}: {
- children: ReactNode;
- messages?: Record<string, string>;
-}) {
- return (
- <IntlProvider
- defaultLocale="en"
- locale="en"
- messages={messages}
- onError={(e) => {
- // ignore missing translations, there are none!
- if (
- e.code !== ReactIntlErrorCode.MISSING_TRANSLATION &&
- e.code !== ReactIntlErrorCode.UNSUPPORTED_FORMATTER
- ) {
- // eslint-disable-next-line no-console
- console.error(e);
- }
- }}
- >
- {children}
- </IntlProvider>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/helpers/theme.ts b/server/sonar-web/src/main/js/design-system/helpers/theme.ts
deleted file mode 100644
index adcc56bf650..00000000000
--- a/server/sonar-web/src/main/js/design-system/helpers/theme.ts
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CSSColor, Theme, ThemeColors, ThemeContrasts, ThemedProps } from '../types/theme';
-import { getRGBAString } from './colors';
-
-export function getProp<T>(name: keyof Omit<T, keyof ThemedProps>) {
- return (props: T) => props[name];
-}
-
-export function themeColor(name: ThemeColors | CSSColor, opacity?: number) {
- return function ({ theme }: ThemedProps) {
- return getColor(theme, [], name, opacity);
- };
-}
-
-export function themeContrast(name: ThemeColors | CSSColor) {
- return function ({ theme }: ThemedProps) {
- return getContrast(theme, name);
- };
-}
-
-export function themeBorder(
- name: keyof Theme['borders'] = 'default',
- color?: ThemeColors | CSSColor,
- opacity?: number,
-) {
- return function ({ theme }: ThemedProps) {
- const [width, style, ...rgba] = theme.borders[name];
- return `${width} ${style} ${getColor(theme, rgba as number[], color, opacity)}`;
- };
-}
-
-export function themeShadow(
- name: keyof Theme['shadows'],
- color?: ThemeColors | CSSColor,
- opacity?: number,
-) {
- return function ({ theme }: ThemedProps) {
- const shadows = theme.shadows[name];
- return shadows
- .map((item) => {
- const [x, y, blur, spread, ...rgba] = item;
- return `${x}px ${y}px ${blur}px ${spread}px ${getColor(theme, rgba, color, opacity)}`;
- })
- .join(',');
- };
-}
-
-export function themeAvatarColor(name: string, contrast = false) {
- return function ({ theme }: ThemedProps) {
- let hash = 0;
- for (let i = 0; i < name.length; i++) {
- hash = name.charCodeAt(i) + ((hash << 5) - hash);
- }
-
- // Reduces number length to avoid modulo's limit.
- hash = parseInt(hash.toString().slice(-5), 10);
- if (contrast) {
- return getColor(theme, theme.avatar.contrast[hash % theme.avatar.contrast.length]);
- }
- return getColor(theme, theme.avatar.color[hash % theme.avatar.color.length]);
- };
-}
-
-export function themeImage(imageKey: keyof Theme['images']) {
- return function ({ theme }: ThemedProps) {
- return theme.images[imageKey];
- };
-}
-
-function getColor(
- theme: Theme,
- [r, g, b, a]: number[],
- colorOverride?: ThemeColors | CSSColor,
- opacityOverride?: number,
-) {
- // Custom CSS property or rgb(a) color, return it directly
- if (
- colorOverride?.startsWith('var(--') ||
- colorOverride?.startsWith('rgb(') ||
- colorOverride?.startsWith('rgba(')
- ) {
- return colorOverride as CSSColor;
- }
- // Is theme color overridden by a color name ?
- const color = colorOverride ? theme.colors[colorOverride as ThemeColors] : [r, g, b];
-
- if (typeof color === 'string') {
- return color as CSSColor;
- }
-
- return getRGBAString(color, opacityOverride ?? (color[3] as number | string | undefined) ?? a);
-}
-
-// Simplified version of getColor for contrast colors, fallback to colors if contrast isn't found
-function getContrast(theme: Theme, colorOverride: ThemeContrasts | ThemeColors | CSSColor) {
- // Custom CSS property or rgb(a) color, return it directly
- if (
- colorOverride.startsWith('var(--') ||
- colorOverride.startsWith('rgb(') ||
- colorOverride.startsWith('rgba(')
- ) {
- return colorOverride as CSSColor;
- }
-
- // For contrast we always require a color override (it's the principle of a contrast)
- const color =
- theme.contrasts[colorOverride as ThemeContrasts] || theme.colors[colorOverride as ThemeColors];
- if (typeof color === 'string') {
- return color as CSSColor;
- }
-
- return getRGBAString(color, color[3]);
-}
diff --git a/server/sonar-web/src/main/js/design-system/helpers/types.ts b/server/sonar-web/src/main/js/design-system/helpers/types.ts
deleted file mode 100644
index 563a2c152d6..00000000000
--- a/server/sonar-web/src/main/js/design-system/helpers/types.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export function isDefined<T>(x: T | undefined | null): x is T {
- return x !== undefined && x !== null;
-}
diff --git a/server/sonar-web/src/main/js/design-system/hooks/__tests__/useResizeObserver-test.tsx b/server/sonar-web/src/main/js/design-system/hooks/__tests__/useResizeObserver-test.tsx
deleted file mode 100644
index f9abdf68266..00000000000
--- a/server/sonar-web/src/main/js/design-system/hooks/__tests__/useResizeObserver-test.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { createRef, useRef } from 'react';
-import { render } from '../../helpers/testUtils';
-import { useResizeObserver } from '../useResizeObserver';
-
-it('should return the correct width and height of the element', () => {
- render(<ExampleWithRefComponent />);
- expect(screen.getByText('width: 100')).toBeInTheDocument();
- expect(screen.getByText('height: 200')).toBeInTheDocument();
-});
-
-it('should return no values if no ref element is passed', () => {
- render(<ExampleNoRefComponent />);
- expect(screen.getByText('width: NONE')).toBeInTheDocument();
- expect(screen.getByText('height: NONE')).toBeInTheDocument();
-});
-
-function ExampleWithRefComponent() {
- const containerRef = useRef(null);
- const [width, height] = useResizeObserver(containerRef);
- return (
- <div ref={containerRef}>
- some content<span>width: {width}</span>
- <span>height: {height}</span>
- </div>
- );
-}
-
-function ExampleNoRefComponent() {
- const ref = createRef<HTMLDivElement>();
- const [width, height] = useResizeObserver(ref);
- return (
- <div>
- some content<span>width: {width ?? 'NONE'}</span>
- <span>height: {height ?? 'NONE'}</span>
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/hooks/useResizeObserver.ts b/server/sonar-web/src/main/js/design-system/hooks/useResizeObserver.ts
deleted file mode 100644
index 4dd580e93d3..00000000000
--- a/server/sonar-web/src/main/js/design-system/hooks/useResizeObserver.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { RefObject, useCallback, useLayoutEffect, useState } from 'react';
-
-// Modified from source: https://codesandbox.io/s/zw8kylol8m
-export interface ResizeObserverEntry {
- contentRect: DOMRectReadOnly;
- target: Element;
-}
-
-export const useResizeObserver = (ref: RefObject<Element>) => {
- const [width, setWidth] = useState<number>();
- const [height, setHeight] = useState<number>();
-
- const handleResize = useCallback((entries: ResizeObserverEntry[]) => {
- if (!Array.isArray(entries)) {
- return;
- }
-
- const entry = entries[0];
- setWidth(entry.contentRect.width);
- setHeight(entry.contentRect.height);
- }, []);
-
- useLayoutEffect(() => {
- if (!ref.current) {
- return;
- }
-
- const RO = new ResizeObserver(handleResize);
- RO.observe(ref.current);
-
- return () => {
- RO.disconnect();
- };
- }, [handleResize, ref]);
-
- return [width, height] as const;
-};
diff --git a/server/sonar-web/src/main/js/design-system/index.ts b/server/sonar-web/src/main/js/design-system/index.ts
deleted file mode 100644
index 08e634ab684..00000000000
--- a/server/sonar-web/src/main/js/design-system/index.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './components';
-export * from './helpers';
-export * from './sonar-aligned';
-export * from './theme';
-export * from './types';
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/Card.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/Card.tsx
deleted file mode 100644
index 2849511b519..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/Card.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import * as React from 'react';
-import tw from 'twin.macro';
-import { BasicSeparator } from '../../components/Separator';
-import { themeBorder, themeColor } from '../../helpers/theme';
-
-interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
- children: React.ReactNode;
-}
-
-export function Card(props: Readonly<CardProps>) {
- const { children, ...rest } = props;
-
- return <CardStyled {...rest}>{children}</CardStyled>;
-}
-
-export function GreyCard(props: Readonly<CardProps>) {
- const { children, ...rest } = props;
-
- return <GreyCardStyled {...rest}>{children}</GreyCardStyled>;
-}
-
-export function LightGreyCard(props: Readonly<CardProps>) {
- const { children, ...rest } = props;
-
- return <LightGreyCardStyled {...rest}>{children}</LightGreyCardStyled>;
-}
-
-export function LightGreyCardTitle({ children }: Readonly<React.PropsWithChildren>) {
- return (
- <>
- <div className="sw-flex sw-items-center sw-justify-between sw-w-full sw-mb-4 sw-min-h-6">
- {children}
- </div>
- <BasicSeparator className="sw--mx-6 sw-my-0" />
- </>
- );
-}
-
-export const CardWithPrimaryBackground = styled(Card)`
- background-color: ${themeColor('backgroundPrimary')};
-`;
-
-export function InfoCard(props: Readonly<CardProps & { footer?: React.ReactNode }>) {
- return (
- <BlueCard>
- <CardContent>{props.children}</CardContent>
- {props.footer !== undefined && (
- <>
- <BasicSeparator />
- <CardContent>{props.footer}</CardContent>
- </>
- )}
- </BlueCard>
- );
-}
-
-const CardStyled = styled.div`
- background-color: ${themeColor('backgroundSecondary')};
- border: ${themeBorder('default', 'projectCardBorder')};
-
- ${tw`sw-p-6`};
- ${tw`sw-rounded-1`};
-`;
-
-const LightGreyCardStyled = styled(CardStyled)`
- border: ${themeBorder('default')};
-`;
-
-const GreyCardStyled = styled(CardStyled)`
- border: ${themeBorder('default', 'almCardBorder')};
-`;
-
-const BlueCard = styled.div`
- ${tw`sw-rounded-1`};
- border: 1px solid var(--echoes-color-border-default);
- background: var(--echoes-color-background-info-weak);
-`;
-const CardContent = styled.div`
- padding: var(--echoes-dimension-space-200);
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/FlagMessage.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/FlagMessage.tsx
deleted file mode 100644
index af4e821fd60..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/FlagMessage.tsx
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import * as React from 'react';
-import { useIntl } from 'react-intl';
-import tw from 'twin.macro';
-import { InteractiveIcon } from '../../components/InteractiveIcon';
-import {
- CloseIcon,
- FlagErrorIcon,
- FlagInfoIcon,
- FlagSuccessIcon,
- FlagWarningIcon,
-} from '../../components/icons';
-import { themeBorder, themeColor, themeContrast } from '../../helpers/theme';
-import { ThemeColors } from '../../types/theme';
-
-export type Variant = 'error' | 'warning' | 'success' | 'info';
-
-interface Props {
- variant: Variant;
-}
-
-function getVariantInfo(variant: Variant) {
- const variantList = {
- error: {
- icon: <FlagErrorIcon />,
- borderColor: 'errorBorder',
- backGroundColor: 'errorBackground',
- },
- warning: {
- icon: <FlagWarningIcon />,
- borderColor: 'warningBorder',
- backGroundColor: 'warningBackground',
- },
- success: {
- icon: <FlagSuccessIcon />,
- borderColor: 'successBorder',
- backGroundColor: 'successBackground',
- },
- info: {
- icon: <FlagInfoIcon />,
- borderColor: 'infoBorder',
- backGroundColor: 'infoBackground',
- },
- } as const;
-
- return variantList[variant];
-}
-
-export function FlagMessage(props: Props & React.HTMLAttributes<HTMLDivElement>) {
- const { className, variant, ...domProps } = props;
- const variantInfo = getVariantInfo(variant);
-
- return (
- <StyledFlag
- backGroundColor={variantInfo.backGroundColor}
- borderColor={variantInfo.borderColor}
- className={classNames('alert', className)}
- {...domProps}
- >
- {props.children && (
- <div className="flag-inner">
- <div className="flag-icon">{variantInfo.icon}</div>
- <div className="flag-content">{props.children}</div>
- </div>
- )}
- </StyledFlag>
- );
-}
-
-FlagMessage.displayName = 'FlagMessage'; // so that tests don't see the obfuscated production name
-
-interface DismissableFlagMessageProps extends Props {
- onDismiss: () => void;
-}
-
-export function DismissableFlagMessage(
- props: DismissableFlagMessageProps & React.HTMLAttributes<HTMLDivElement>,
-) {
- const { onDismiss, children, ...flagMessageProps } = props;
- const intl = useIntl();
- return (
- <FlagMessage {...flagMessageProps}>
- {children}
- <DismissIcon
- Icon={CloseIcon}
- aria-label={intl.formatMessage({ id: 'dismiss' })}
- className="sw-ml-3"
- onClick={onDismiss}
- size="small"
- />
- </FlagMessage>
- );
-}
-
-DismissableFlagMessage.displayName = 'DismissableFlagMessage'; // so that tests don't see the obfuscated production name
-
-export const StyledFlag = styled.div<{
- backGroundColor: ThemeColors;
- borderColor: ThemeColors;
-}>`
- ${tw`sw-inline-flex`}
- ${tw`sw-min-h-10`}
- ${tw`sw-rounded-1`}
- ${tw`sw-box-border`}
- border: ${({ borderColor }) => themeBorder('default', borderColor)};
- background-color: ${themeColor('flagMessageBackground')};
-
- :empty {
- display: none;
- }
-
- & > .flag-inner {
- ${tw`sw-flex sw-items-stretch`}
- ${tw`sw-box-border`}
- }
-
- & .flag-icon {
- ${tw`sw-flex sw-justify-center sw-items-center`}
- ${tw`sw-rounded-l-1`}
- ${tw`sw-px-3`}
- background-color: ${({ backGroundColor }) => themeColor(backGroundColor)};
- }
-
- & .flag-content {
- ${tw`sw-flex sw-flex-auto sw-items-center`}
- ${tw`sw-overflow-auto`}
- ${tw`sw-text-left`}
- ${tw`sw-px-3 sw-py-2`}
- ${tw`sw-typo-default`}
- color: ${themeContrast('flagMessageBackground')};
- }
-`;
-
-export const DismissIcon = styled(InteractiveIcon)`
- --background: ${themeColor('productNews')};
- --backgroundHover: ${themeColor('productNewsHover')};
- --color: ${themeContrast('productNews')};
- --colorHover: ${themeContrast('productNewsHover')};
- --focus: ${themeColor('interactiveIconFocus', 0.2)};
-
- height: 28px;
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/FlagMessageV2.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/FlagMessageV2.tsx
deleted file mode 100644
index d7c98e40a60..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/FlagMessageV2.tsx
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import {
- IconCheckCircle,
- IconError,
- IconInfo,
- IconRecommended,
- IconWarning,
- IconX,
-} from '@sonarsource/echoes-react';
-import classNames from 'classnames';
-import { HTMLAttributes } from 'react';
-import { IntlShape, useIntl } from 'react-intl';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../../helpers/theme';
-import { ThemeColors } from '../../types/theme';
-
-export type FlagMessageV2Variant = 'error' | 'warning' | 'success' | 'info' | 'recommended';
-
-interface Props {
- hasIcon?: boolean;
- onDismiss?: () => void;
- title?: string;
- variant: FlagMessageV2Variant;
-}
-
-interface VariantInformation {
- backGroundColor: ThemeColors;
- borderColor: ThemeColors;
- icon: JSX.Element;
- iconColor: ThemeColors;
- iconFocusBackground: ThemeColors;
- iconHover: ThemeColors;
- iconHoverBackground: ThemeColors;
-}
-
-function getAlertVariantInfo(variant: FlagMessageV2Variant, intl: IntlShape): VariantInformation {
- const variantList: Record<FlagMessageV2Variant, VariantInformation> = {
- error: {
- icon: <IconError aria-label={intl.formatMessage({ id: 'flagmessage.tooltip.error' })} />,
- borderColor: 'errorBorder',
- backGroundColor: 'errorBackground',
- iconColor: 'errorIcon',
- iconHover: 'errorIconHover',
- iconHoverBackground: 'errorIconHoverBackground',
- iconFocusBackground: 'errorIconFocusBackground',
- },
- warning: {
- icon: <IconWarning aria-label={intl.formatMessage({ id: 'flagmessage.tooltip.warning' })} />,
- borderColor: 'warningBorder',
- backGroundColor: 'warningBackground',
- iconColor: 'warningIcon',
- iconHover: 'warningIconHover',
- iconHoverBackground: 'warningIconHoverBackground',
- iconFocusBackground: 'warningIconFocusBackground',
- },
- success: {
- icon: (
- <IconCheckCircle aria-label={intl.formatMessage({ id: 'flagmessage.tooltip.success' })} />
- ),
- borderColor: 'successBorder',
- backGroundColor: 'successBackground',
- iconColor: 'successIcon',
- iconHover: 'successIconHover',
- iconHoverBackground: 'successIconHoverBackground',
- iconFocusBackground: 'successIconFocusBackground',
- },
- info: {
- icon: <IconInfo aria-label={intl.formatMessage({ id: 'flagmessage.tooltip.info' })} />,
- borderColor: 'infoBorder',
- backGroundColor: 'infoBackground',
- iconColor: 'infoIcon',
- iconHover: 'infoIconHover',
- iconHoverBackground: 'infoIconHoverBackground',
- iconFocusBackground: 'infoIconFocusBackground',
- },
- recommended: {
- icon: <IconRecommended aria-label={intl.formatMessage({ id: 'flagmessage.tooltip.info' })} />,
- borderColor: 'recommendedBorder',
- backGroundColor: 'recommendedBackground',
- iconColor: 'recommendedIcon',
- iconHover: 'recommendedIconHover',
- iconHoverBackground: 'recommendedIconHoverBackground',
- iconFocusBackground: 'recommendedIconFocusBackground',
- },
- };
-
- return variantList[variant];
-}
-
-export function FlagMessageV2(props: Readonly<Props & HTMLAttributes<HTMLDivElement>>) {
- const { className, children, hasIcon = true, onDismiss, title, variant, ...domProps } = props;
- const intl = useIntl();
- const variantInfo = getAlertVariantInfo(variant, intl);
-
- return (
- <StyledFlag
- className={classNames('js-flag-message', className)}
- role="alert"
- variantInfo={variantInfo}
- {...domProps}
- >
- {hasIcon && <IconWrapper variantInfo={variantInfo}>{variantInfo.icon}</IconWrapper>}
- <div className="sw-flex sw-flex-col sw-gap-2">
- {title && <Title>{title}</Title>}
- <StyledFlagContent>{children}</StyledFlagContent>
- </div>
- {onDismiss !== undefined && (
- <DismissButton
- aria-label={intl.formatMessage({ id: 'close' })}
- onClick={onDismiss}
- variantInfo={variantInfo}
- >
- <IconX />
- </DismissButton>
- )}
- </StyledFlag>
- );
-}
-
-const StyledFlag = styled.div<{
- variantInfo: VariantInformation;
-}>`
- ${tw`sw-inline-flex sw-gap-1`}
- ${tw`sw-box-border`}
- ${tw`sw-px-4 sw-py-2`}
- ${tw`sw-mb-1`}
- ${tw`sw-rounded-2`}
-
- background-color: ${({ variantInfo }) => themeColor(variantInfo.backGroundColor)};
- border: ${({ variantInfo }) => themeBorder('default', variantInfo.borderColor)};
-`;
-
-const IconWrapper = styled.div<{
- variantInfo: VariantInformation;
-}>`
- ${tw`sw-flex`}
- ${tw`sw-text-[1rem]`}
- color: ${({ variantInfo }) => themeColor(variantInfo.iconColor)};
-`;
-
-const Title = styled.span`
- ${tw`sw-typo-lg-semibold`}
- color: ${themeColor('flagMessageText')};
-`;
-
-const StyledFlagContent = styled.div`
- ${tw`sw-pt-1/2`}
- ${tw`sw-overflow-auto`}
- ${tw`sw-typo-default`}
-`;
-
-const DismissButton = styled.button<{
- variantInfo: VariantInformation;
-}>`
- ${tw`sw-flex sw-justify-center sw-items-center sw-shrink-0`}
- ${tw`sw-w-6 sw-h-6`}
- ${tw`sw-box-border`}
- ${tw`sw-rounded-1`}
- ${tw`sw-cursor-pointer`}
- ${tw`sw-border-none`}
- background: none;
-
- color: ${({ variantInfo }) => themeColor(variantInfo.iconColor)};
- transition:
- box-shadow 0.2s ease,
- outline 0.2s ease,
- color 0.2s ease;
-
- &:focus,
- &:active {
- background-color: ${({ theme, variantInfo }) =>
- `${themeColor(variantInfo.iconFocusBackground)({ theme })}`};
- box-shadow:
- 0px 0px 0px 1px ${themeColor('backgroundSecondary')},
- 0px 0px 0px 3px ${themeColor('flagMessageFocusBackground')};
- }
-
- &:hover {
- color: ${({ theme, variantInfo }) => `${themeColor(variantInfo.iconHover)({ theme })}`};
- background-color: ${({ theme, variantInfo }) =>
- `${themeColor(variantInfo.iconHoverBackground)({ theme })}`};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/MetricsRatingBadge.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/MetricsRatingBadge.tsx
deleted file mode 100644
index 5e491cf9638..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/MetricsRatingBadge.tsx
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { forwardRef } from 'react';
-import tw from 'twin.macro';
-import { getProp, themeColor, themeContrast } from '../../helpers/theme';
-import { RatingLabel } from '../types/measures';
-
-type sizeType = keyof typeof SIZE_MAPPING;
-interface Props extends React.AriaAttributes {
- className?: string;
- label?: string;
- rating?: RatingLabel;
- size?: sizeType;
-}
-
-const SIZE_MAPPING = {
- xs: '1rem',
- sm: '1.5rem',
- md: '2rem',
- lg: '2.8rem',
- xl: '4rem',
-};
-
-export const MetricsRatingBadge = forwardRef<HTMLDivElement, Props>(
- ({ className, size = 'sm', label, rating, ...ariaAttrs }: Readonly<Props>, ref) => {
- if (!rating) {
- return (
- <StyledNoRatingBadge
- aria-label={label}
- className={className}
- ref={ref}
- size={SIZE_MAPPING[size]}
- {...ariaAttrs}
- >
- —
- </StyledNoRatingBadge>
- );
- }
- return (
- <MetricsRatingBadgeStyled
- aria-label={label}
- className={className}
- rating={rating}
- ref={ref}
- size={SIZE_MAPPING[size]}
- {...ariaAttrs}
- >
- {rating}
- </MetricsRatingBadgeStyled>
- );
- },
-);
-
-MetricsRatingBadge.displayName = 'MetricsRatingBadge';
-
-const StyledNoRatingBadge = styled.div<{ size: string }>`
- display: inline-flex;
- align-items: center;
- justify-content: center;
-
- width: ${getProp('size')};
- height: ${getProp('size')};
-`;
-
-const getFontSize = (size: string) => {
- switch (size) {
- case '2rem':
- return '0.875rem';
- case '4rem':
- return '1.5rem';
- default:
- return '0.75rem';
- }
-};
-
-const MetricsRatingBadgeStyled = styled.div<{
- rating: RatingLabel;
- size: string;
-}>`
- width: ${getProp('size')};
- height: ${getProp('size')};
- color: ${({ rating }) => themeContrast(`rating.${rating}`)};
- font-size: ${({ size }) => getFontSize(size)};
- background-color: ${({ rating }) => themeColor(`rating.${rating}`)};
- user-select: none;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
-
- ${tw`sw-rounded-pill`};
- ${tw`sw-font-semibold`};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/Table.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/Table.tsx
deleted file mode 100644
index e5db95df85d..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/Table.tsx
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import classNames from 'classnames';
-import { isNumber, times } from 'lodash';
-import { ComponentProps, ReactNode, createContext, useContext } from 'react';
-import tw from 'twin.macro';
-import { themeBorder, themeColor } from '../../helpers/theme';
-import { FCProps } from '../../types/misc';
-
-interface TableBaseProps extends ComponentProps<'table'> {
- caption?: ReactNode;
- header?: ReactNode;
- noHeaderTopBorder?: boolean;
- noSidePadding?: boolean;
- withRoundedBorder?: boolean;
-}
-
-interface ColumnWidthsProps extends TableBaseProps {
- columnCount: number;
- columnWidths?: Array<number | string>;
- gridTemplate?: never;
-}
-
-interface GridTemplateProps extends TableBaseProps {
- columnCount?: never;
- columnWidths?: never;
- gridTemplate: string;
-}
-
-export type TableProps = ColumnWidthsProps | GridTemplateProps;
-
-export function Table(props: Readonly<TableProps>) {
- const { columnCount, gridTemplate } = props;
- const {
- className,
- columnWidths,
- header,
- caption,
- children,
- noHeaderTopBorder,
- noSidePadding,
- withRoundedBorder,
- ...rest
- } = props;
-
- return (
- <StyledTable
- className={classNames(
- {
- 'no-header-top-border': noHeaderTopBorder,
- 'no-side-padding': noSidePadding,
- 'with-rounded-border': withRoundedBorder,
- 'with-grid-template': gridTemplate !== undefined,
- },
- className,
- )}
- {...rest}
- >
- {isNumber(columnCount) && (
- <colgroup>
- {times(columnCount, (i) => (
- <col key={i} width={columnWidths?.[i] ?? 'auto'} />
- ))}
- </colgroup>
- )}
-
- {caption && (
- <caption>
- <div className="sw-py-4 sw-text-middle sw-flex sw-justify-center sw-typo-semibold">
- {caption}
- </div>
- </caption>
- )}
-
- {header && (
- <thead>
- <CellTypeContext.Provider value="th">{header}</CellTypeContext.Provider>
- </thead>
- )}
-
- <tbody>{children}</tbody>
- </StyledTable>
- );
-}
-
-export const TableSeparator = styled.tr`
- ${tw`sw-h-4`}
- border-top: ${themeBorder('default')};
-`;
-
-export const TableRow = styled.tr`
- td,
- th {
- border-top: ${themeBorder('default')};
- }
-
- .no-header-top-border & th {
- ${tw`sw-border-t-0`}
- }
-
- td:first-of-type,
- th:first-of-type,
- td:last-child,
- th:last-child {
- border-right: ${themeBorder('default', 'transparent')};
- border-left: ${themeBorder('default', 'transparent')};
- }
-
- .no-side-padding & {
- td:first-of-type,
- th:first-of-type {
- ${tw`sw-pl-0`}
- }
-
- td:last-child,
- th:last-child {
- ${tw`sw-pr-0`}
- }
- }
-
- &:last-child > td {
- border-bottom: ${themeBorder('default')};
- }
-`;
-
-interface TableRowInteractiveProps extends FCProps<typeof TableRow> {
- selected?: boolean;
-}
-
-function TableRowInteractiveBase({
- className,
- children,
- selected,
- ...props
-}: Readonly<TableRowInteractiveProps>) {
- return (
- <TableRow aria-selected={selected} className={classNames(className, { selected })} {...props}>
- {children}
- </TableRow>
- );
-}
-
-export const TableRowInteractive = styled(TableRowInteractiveBase)`
- &:hover > td,
- &.selected > td,
- &.selected > th,
- th.selected,
- td.selected {
- background: ${themeColor('tableRowHover')};
- }
-
- &.selected > td:first-of-type,
- &.selected > th:first-of-type,
- th.selected:first-of-type,
- td.selected:first-of-type {
- border-left: ${themeBorder('default', 'tableRowSelected')};
- }
-
- &.selected > td,
- &.selected > th,
- th.selected,
- td.selected {
- border-top: ${themeBorder('default', 'tableRowSelected')};
- border-bottom: ${themeBorder('default', 'tableRowSelected')};
- }
-
- &.selected > td:last-child,
- &.selected > th:last-child,
- th.selected:last-child,
- td.selected:last-child {
- border-right: ${themeBorder('default', 'tableRowSelected')};
- }
-
- &.selected + &:not(.selected) > td {
- border-top: none;
- }
-`;
-
-const CellTypeContext = createContext<'th' | 'td'>('td');
-type CellComponentProps = ComponentProps<'th' | 'td'>;
-
-export function CellComponent(props: CellComponentProps) {
- const containerType = useContext(CellTypeContext);
- return <CellComponentStyled as={containerType} {...props} />;
-}
-
-export function ContentCell({
- children,
- cellClassName,
- className,
- ...props
-}: CellComponentProps & { cellClassName?: string }) {
- return (
- <CellComponent className={cellClassName} {...props}>
- <div
- className={classNames('sw-text-left sw-justify-start sw-flex sw-items-center', className)}
- >
- {children}
- </div>
- </CellComponent>
- );
-}
-
-export function NumericalCell({ children, ...props }: CellComponentProps) {
- return (
- <CellComponent {...props}>
- <div className="sw-text-right sw-justify-end sw-flex sw-items-center">{children}</div>
- </CellComponent>
- );
-}
-
-export function RatingCell({ children, ...props }: CellComponentProps) {
- return (
- <CellComponent {...props}>
- <div className="sw-text-right sw-justify-end sw-flex sw-items-center">{children}</div>
- </CellComponent>
- );
-}
-
-export function ActionCell({ children, ...props }: CellComponentProps) {
- return (
- <CellComponent {...props}>
- <div className="sw-text-right sw-justify-end sw-flex sw-items-center">{children}</div>
- </CellComponent>
- );
-}
-
-export function CheckboxCell({ children, ...props }: CellComponentProps) {
- return (
- <CellComponent {...props}>
- <div className="sw-text-center sw-justify-center sw-flex sw-items-center">{children}</div>
- </CellComponent>
- );
-}
-
-const StyledTable = styled.table<{ gridTemplate?: string }>`
- width: 100%;
- border-collapse: collapse;
-
- &.with-grid-template {
- display: grid;
- grid-template-columns: ${(props) => props.gridTemplate};
- thead,
- tbody,
- tr {
- display: contents;
- }
- }
-
- &.with-rounded-border {
- border-collapse: separate;
- border: ${themeBorder('default', 'breakdownBorder')};
- ${tw`sw-rounded-1`};
-
- th:first-of-type {
- ${tw`sw-rounded-tl-1`};
- }
- th:last-of-type {
- ${tw`sw-rounded-tr-1`};
- }
-
- tr:last-child > td {
- border-bottom: none;
- }
- }
-`;
-
-const CellComponentStyled = styled.td`
- color: ${themeColor('pageContent')};
- ${tw`sw-items-center`}
- ${tw`sw-typo-default`}
- ${tw`sw-py-4 sw-px-2`}
- ${tw`sw-align-middle`}
-
- thead > tr > & {
- color: ${themeColor('pageTitle')};
-
- ${tw`sw-typo-semibold`}
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/Text.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/Text.tsx
deleted file mode 100644
index 7d517c97dde..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/Text.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { themeColor } from '../../helpers/theme';
-
-export const PageContentFontWrapper = styled.div`
- color: ${themeColor('pageContent')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/ToggleButton.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/ToggleButton.tsx
deleted file mode 100644
index c95e335862a..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/ToggleButton.tsx
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { Badge } from '../../components/Badge';
-import { themeBorder, themeColor, themeContrast } from '../../helpers/theme';
-import { getTabId, getTabPanelId } from '../helpers/tabs';
-import { ButtonSecondary } from './buttons';
-
-type ToggleButtonValueType = string | number | boolean;
-
-export interface ToggleButtonsOption<T extends ToggleButtonValueType> {
- counter?: number;
- disabled?: boolean;
- label: string | React.ReactNode;
- value: T;
-}
-
-export interface ButtonToggleProps<T extends ToggleButtonValueType> {
- disabled?: boolean;
- label?: string;
- onChange: (value: T) => void;
- options: ReadonlyArray<ToggleButtonsOption<T>>;
- role?: 'radiogroup' | 'tablist';
- value?: T;
-}
-
-export function ToggleButton<T extends ToggleButtonValueType>(props: ButtonToggleProps<T>) {
- const { disabled = false, label, options, value, role = 'radiogroup' } = props;
- const isRadioGroup = role === 'radiogroup';
-
- return (
- <Wrapper aria-label={label} role={role}>
- {options.map((option) => (
- <OptionButton
- aria-checked={isRadioGroup ? option.value === value : undefined}
- aria-controls={isRadioGroup ? undefined : getTabPanelId(String(option.value))}
- aria-current={option.value === value}
- aria-selected={!isRadioGroup ? option.value === value : undefined}
- data-value={option.value}
- disabled={disabled || option.disabled}
- id={getTabId(String(option.value))}
- key={option.value.toString()}
- onClick={() => {
- if (option.value !== value) {
- props.onChange(option.value);
- }
- }}
- role={isRadioGroup ? 'radio' : 'tab'}
- selected={option.value === value}
- >
- {option.label}
- {option.counter ? (
- <Badge className="sw-ml-1" variant="counter">
- {option.counter}
- </Badge>
- ) : null}
- </OptionButton>
- ))}
- </Wrapper>
- );
-}
-
-const Wrapper = styled.div`
- border: ${themeBorder('default', 'toggleBorder')};
-
- ${tw`sw-inline-flex`}
- ${tw`sw-h-control`}
- ${tw`sw-box-border`}
- ${tw`sw-font-semibold`}
- ${tw`sw-rounded-2`}
-`;
-
-const OptionButton = styled(ButtonSecondary)<{ selected: boolean }>`
- background: ${(props) => (props.selected ? themeColor('toggleHover') : themeColor('toggle'))};
- border: none;
- color: ${(props) => (props.selected ? themeContrast('toggleHover') : themeContrast('toggle'))};
- font-weight: ${(props) =>
- props.selected ? 'var(--echoes-font-weight-semi-bold)' : 'var(--echoes-font-weight-regular)'};
- height: auto;
-
- ${tw`sw-rounded-0`};
- ${tw`sw-truncate`};
-
- &:first-of-type {
- ${tw`sw-rounded-l-2`};
- }
-
- &:last-of-type {
- ${tw`sw-rounded-r-2`};
- }
-
- &:not(:last-of-type) {
- border-right: ${themeBorder('default', 'toggleBorder')};
- }
-
- &:hover {
- background: ${themeColor('toggleHover')};
- color: ${themeContrast('toggleHover')};
- }
-
- &:focus-visible {
- outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
- outline-offset: var(--echoes-focus-border-offset-default);
- z-index: 1;
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/Card-test.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/Card-test.tsx
deleted file mode 100644
index c80217f6c9a..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/Card-test.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../../helpers/testUtils';
-import { Card, GreyCard, LightGreyCard } from '../Card';
-
-it('renders card correctly', () => {
- render(<Card>Hello</Card>);
- const cardContent = screen.getByText('Hello');
- expect(cardContent).toHaveStyle({
- border: '1px solid rgb(225,230,243)',
- 'background-color': 'rgb(255,255,255)',
- });
-});
-
-it.each([Card, GreyCard, LightGreyCard])(
- 'renders %p correctly with classNames',
- (CardComponent) => {
- render(
- <CardComponent className="sw-bg-black sw-border-8" role="tabpanel">
- Hello
- </CardComponent>,
- );
- const cardContent = screen.getByText('Hello');
- expect(cardContent).toHaveClass('sw-bg-black sw-border-8');
- expect(cardContent).toHaveAttribute('role', 'tabpanel');
- },
-);
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/FlagMessage-test.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/FlagMessage-test.tsx
deleted file mode 100644
index e62982ce3d6..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/FlagMessage-test.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { IntlShape } from 'react-intl';
-import { render } from '../../../helpers/testUtils';
-import { FCProps } from '../../../types/misc';
-import { DismissableFlagMessage, FlagMessage, Variant } from '../FlagMessage';
-
-jest.mock(
- 'react-intl',
- () =>
- ({
- ...jest.requireActual('react-intl'),
- useIntl: () => ({
- formatMessage: ({ id }: { id: string }, values = {}) =>
- [id, ...Object.values(values)].join('.'),
- }),
- }) as IntlShape,
-);
-
-it.each([
- ['error', '1px solid rgb(249,112,102)'],
- ['warning', '1px solid rgb(248,205,92)'],
- ['success', '1px solid rgb(166,208,91)'],
- ['info', '1px solid rgb(143,202,234)'],
-])('should render properly for "%s" variant', (variant: Variant, color) => {
- renderFlagMessage({ variant });
-
- const item = screen.getByRole('status');
- expect(item).toBeInTheDocument();
- expect(item).toHaveStyle({ border: color });
-});
-
-it('should render Dismissable flag message properly', () => {
- const dismissFunc = jest.fn();
- render(<DismissableFlagMessage onDismiss={dismissFunc} role="status" variant="error" />);
- const item = screen.getByRole('status');
- expect(item).toBeInTheDocument();
- expect(item).toHaveStyle({ border: '1px solid rgb(249,112,102)' });
- const dismissButton = screen.getByRole('button');
- expect(dismissButton).toBeInTheDocument();
- dismissButton.click();
- expect(dismissFunc).toHaveBeenCalled();
-});
-
-function renderFlagMessage(props: Partial<FCProps<typeof FlagMessage>> = {}) {
- return render(
- <FlagMessage role="status" variant="error" {...props}>
- This is an error!
- </FlagMessage>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/FlagMessageV2-test.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/FlagMessageV2-test.tsx
deleted file mode 100644
index c4691ee45c3..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/FlagMessageV2-test.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { ComponentProps } from 'react';
-import { IntlShape } from 'react-intl';
-import { render } from '../../../helpers/testUtils';
-import { FlagMessageV2, FlagMessageV2Variant } from '../FlagMessageV2';
-
-jest.mock(
- 'react-intl',
- () =>
- ({
- ...jest.requireActual('react-intl'),
- useIntl: () => ({
- formatMessage: ({ id }: { id: string }, values = {}) =>
- [id, ...Object.values(values)].join('.'),
- }),
- }) as IntlShape,
-);
-
-it.each([
- ['error', '1px solid rgb(249,112,102)'],
- ['warning', '1px solid rgb(248,205,92)'],
- ['success', '1px solid rgb(166,208,91)'],
- ['info', '1px solid rgb(143,202,234)'],
- ['recommended', '1px solid rgb(93,108,208)'],
-])('should render properly for "%s" variant', (variant: FlagMessageV2Variant, color) => {
- renderFlagMessage({ variant });
-
- const item = screen.getByRole('status');
- expect(item).toBeInTheDocument();
- expect(item).toHaveStyle({ border: color });
-});
-
-it('should render correctly with optional props', async () => {
- const onDismiss = jest.fn();
- const { user } = renderFlagMessage({
- title: 'This is a title',
- hasIcon: false,
- onDismiss,
- });
- expect(screen.getByText('This is a title')).toBeInTheDocument();
- expect(screen.queryByRole('img')).not.toBeInTheDocument();
- await user.click(screen.getByRole('button'));
- expect(onDismiss).toHaveBeenCalled();
-});
-
-function renderFlagMessage(props: Partial<ComponentProps<typeof FlagMessageV2>> = {}) {
- return render(
- <FlagMessageV2 role="status" variant="error" {...props}>
- This is an error!
- </FlagMessageV2>,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/MetricsRatingBadge-test.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/MetricsRatingBadge-test.tsx
deleted file mode 100644
index 88bf77aed89..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/MetricsRatingBadge-test.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../../helpers/testUtils';
-import { FCProps } from '../../../types/misc';
-
-import { MetricsRatingBadge } from '../MetricsRatingBadge';
-
-it('should display RatingIndicator', () => {
- setupWithProps();
- expect(screen.getByLabelText('New label')).toBeInTheDocument();
-});
-
-it('should display RatingIndicator with value', () => {
- setupWithProps({ rating: 'A' });
- expect(screen.getByText('A')).toBeInTheDocument();
-});
-
-function setupWithProps(props: Partial<FCProps<typeof MetricsRatingBadge>> = {}) {
- return render(<MetricsRatingBadge label="New label" {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/Table-test.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/Table-test.tsx
deleted file mode 100644
index 9802899c740..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/Table-test.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { render } from '../../../helpers/testUtils';
-import {
- ActionCell,
- CheckboxCell,
- ContentCell,
- NumericalCell,
- RatingCell,
- Table,
- TableProps,
- TableRow,
- TableRowInteractive,
-} from '../Table';
-
-it.each([
- [
- 'using column count and widths',
- {
- columnCount: 5,
- columnWidths: ['1%', 'auto', '1%', '1%', '1%'],
- 'aria-colcount': 5,
- },
- ],
- [
- 'using column count only',
- {
- columnCount: 5,
- 'aria-colcount': 5,
- },
- ],
- [
- 'using column grid template only',
- {
- gridTemplate: '1fr auto 1fr 1fr 1fr',
- 'aria-colcount': 5,
- },
- ],
-])('check that the html structure and style is correct %s', (_, props) => {
- renderTable({
- ...props,
- header: (
- <TableRow>
- <ContentCell>ContentCellHeader</ContentCell>
- <NumericalCell>NumericalCellHeader</NumericalCell>
- <CheckboxCell>CheckboxCellHeader</CheckboxCell>
- <RatingCell>RatingCellHeader</RatingCell>
- <ActionCell>ActionCellHeader</ActionCell>
- </TableRow>
- ),
- children: (
- <>
- <TableRowInteractive>
- <ContentCell>ContentCell 1</ContentCell>
- <NumericalCell>NumericalCell 1</NumericalCell>
- <CheckboxCell>CheckboxCell 1</CheckboxCell>
- <RatingCell>RatingCell 1</RatingCell>
- <ActionCell>ActionCell 1</ActionCell>
- </TableRowInteractive>
- <TableRowInteractive selected>
- <ContentCell>ContentCell 2</ContentCell>
- <NumericalCell>NumericalCell 2</NumericalCell>
- <CheckboxCell>CheckboxCell 2</CheckboxCell>
- <RatingCell>RatingCell 2</RatingCell>
- <ActionCell>ActionCell 2</ActionCell>
- </TableRowInteractive>
- <TableRow>
- <ContentCell aria-colspan={5}>ContentCell 3</ContentCell>
- </TableRow>
- <TableRowInteractive>
- <NumericalCell aria-colindex={2}>NumericalCell 4</NumericalCell>
- <CheckboxCell aria-colindex={3}>CheckboxCell 4</CheckboxCell>
- <RatingCell aria-colindex={4}>RatingCell 4</RatingCell>
- <ActionCell aria-colindex={5}>ActionCell 4</ActionCell>
- </TableRowInteractive>
- </>
- ),
- });
-
- // Table should have accessible attribute
- expect(screen.getByRole('table')).toHaveAttribute('aria-colcount', '5');
-
- // Rows should have accessible attributes
- expect(
- screen.getByRole('row', {
- name: 'ContentCellHeader NumericalCellHeader CheckboxCellHeader RatingCellHeader ActionCellHeader',
- }),
- ).toBeInTheDocument();
- expect(
- screen.getByRole('row', {
- name: 'ContentCell 1 NumericalCell 1 CheckboxCell 1 RatingCell 1 ActionCell 1',
- }),
- ).toBeInTheDocument();
- expect(
- screen.getByRole('row', {
- name: 'ContentCell 1 NumericalCell 1 CheckboxCell 1 RatingCell 1 ActionCell 1',
- }),
- ).not.toHaveAttribute('aria-selected');
- expect(
- screen.getByRole('row', {
- selected: true,
- name: 'ContentCell 2 NumericalCell 2 CheckboxCell 2 RatingCell 2 ActionCell 2',
- }),
- ).toBeInTheDocument();
- expect(
- screen.getByRole('row', {
- name: 'NumericalCell 4 CheckboxCell 4 RatingCell 4 ActionCell 4',
- }),
- ).toBeInTheDocument();
-
- // Cells should have accessible attributes
- expect(screen.getByRole('cell', { name: 'NumericalCell 4' })).toHaveAttribute(
- 'aria-colindex',
- '2',
- );
- expect(screen.getByRole('cell', { name: 'CheckboxCell 4' })).toHaveAttribute(
- 'aria-colindex',
- '3',
- );
- expect(screen.getByRole('cell', { name: 'RatingCell 4' })).toHaveAttribute('aria-colindex', '4');
- expect(screen.getByRole('cell', { name: 'ActionCell 4' })).toHaveAttribute('aria-colindex', '5');
-});
-
-function renderTable(props: TableProps) {
- return render(<Table {...props}>{props.children}</Table>);
-}
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/ToggleButton-test.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/ToggleButton-test.tsx
deleted file mode 100644
index 838b9aaaaa8..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/__tests__/ToggleButton-test.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { render } from '../../../helpers/testUtils';
-import { FCProps } from '../../../types/misc';
-import { getTabPanelId } from '../../helpers';
-import { ToggleButton, ToggleButtonsOption } from '../ToggleButton';
-
-it('should render all options', async () => {
- const user = userEvent.setup();
- const onChange = jest.fn();
- const options: Array<ToggleButtonsOption<number>> = [
- { value: 1, label: 'first' },
- { value: 2, label: 'disabled', disabled: true },
- { value: 3, label: 'has counter', counter: 7 },
- ];
- renderToggleButtons({ onChange, options, value: 1 });
-
- expect(screen.getAllByRole('radio')).toHaveLength(3);
-
- await user.click(screen.getByText('first'));
-
- expect(onChange).not.toHaveBeenCalled();
-
- await user.click(screen.getByText('has counter'));
-
- expect(onChange).toHaveBeenCalledWith(3);
-});
-
-it('should work in tablist mode', () => {
- const onChange = jest.fn();
- const options: Array<ToggleButtonsOption<number>> = [
- { value: 1, label: 'first' },
- { value: 2, label: 'second' },
- { value: 3, label: 'third' },
- ];
- renderToggleButtons({ onChange, options, value: 1, role: 'tablist' });
-
- expect(screen.getAllByRole('tab')).toHaveLength(3);
- expect(screen.getByRole('tab', { name: 'second' })).toHaveAttribute(
- 'aria-controls',
- getTabPanelId(2),
- );
-});
-
-function renderToggleButtons(props: Partial<FCProps<typeof ToggleButton>> = {}) {
- return render(<ToggleButton onChange={jest.fn()} options={[]} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/BareButton.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/BareButton.tsx
deleted file mode 100644
index 3b5572c5913..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/BareButton.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { themeColor } from '../../../helpers';
-
-export const BareButton = styled.button`
- all: unset;
- cursor: pointer;
-
- &:focus-visible {
- background-color: ${themeColor('dropdownMenuHover')};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/Button.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/Button.tsx
deleted file mode 100644
index 3301bd71d36..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/Button.tsx
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { css } from '@emotion/react';
-import styled from '@emotion/styled';
-import React, { MouseEvent, ReactNode, forwardRef, useCallback } from 'react';
-import tw from 'twin.macro';
-import { BaseLink, LinkProps } from '../../../components/Link';
-import { themeBorder, themeColor } from '../../../helpers/theme';
-import { ThemedProps } from '../../../types/theme';
-
-type AllowedButtonAttributes = Pick<
- React.ButtonHTMLAttributes<HTMLButtonElement>,
- 'aria-label' | 'autoFocus' | 'id' | 'name' | 'role' | 'style' | 'title' | 'type' | 'form'
->;
-
-export interface ButtonProps extends AllowedButtonAttributes {
- children?: ReactNode;
- className?: string;
- disabled?: boolean;
- download?: string;
- icon?: ReactNode;
- isExternal?: LinkProps['isExternal'];
- onClick?: (event: MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => unknown;
-
- preventDefault?: boolean;
- reloadDocument?: LinkProps['reloadDocument'];
- showExternalIcon?: boolean;
- stopPropagation?: boolean;
- target?: LinkProps['target'];
- to?: LinkProps['to'];
-}
-
-/**
- * @deprecated Use Button from Echoes instead.
- * Use the `variety` prop with the ButtonVariety enum to change the button's look and feel.
- *
- * Some of the props have changed or been renamed:
- * - `blurAfterClick` is now `shouldBlurAfterClick`
- * - `disabled` is now `isDisabled`, note that a Echoes Tooltip won't work
- * on a disabled button, use a text notice or ToggleTip next to the disabled button instead.
- * - `icon` is now replace by `prefix` which works the same way
- * - `preventDefault` is now `shouldPreventDefault`
- * - `stopPropagation` is now `shouldStopPropagation`
- *
- * The button can't be used as a link anymore, and all props related to links have been dropped.
- * Use a real Echoes Link instead.
- *
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3382706231/Button | Migration Guide} for more information.
- */
-export const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
- const {
- children,
- disabled,
- icon,
- onClick,
- preventDefault = props.type !== 'submit',
- stopPropagation = false,
- to,
- type = 'button',
- ...htmlProps
- } = props;
-
- const handleClick = useCallback(
- (event: MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => {
- if (preventDefault || disabled) {
- event.preventDefault();
- }
-
- if (stopPropagation) {
- event.stopPropagation();
- }
-
- if (onClick && !disabled) {
- onClick(event);
- }
- },
- [disabled, onClick, preventDefault, stopPropagation],
- );
-
- const buttonProps = {
- ...htmlProps,
- 'aria-disabled': disabled,
- disabled,
- type,
- };
-
- if (to) {
- return (
- <BaseButtonLink {...buttonProps} onClick={onClick} to={to}>
- {icon}
- {children}
- </BaseButtonLink>
- );
- }
-
- return (
- <BaseButton {...buttonProps} onClick={handleClick} ref={ref}>
- {icon}
- {children}
- </BaseButton>
- );
-});
-Button.displayName = 'Button';
-
-export const buttonStyle = (props: ThemedProps) => css`
- box-sizing: border-box;
- text-decoration: none;
- outline: none;
- border: var(--border);
- color: var(--color);
- background-color: var(--background);
- transition: background-color 0.2s ease;
-
- ${tw`sw-inline-flex sw-items-center`}
- ${tw`sw-h-control`}
- ${tw`sw-typo-semibold`}
- ${tw`sw-py-2 sw-px-4`}
- ${tw`sw-rounded-2`}
- ${tw`sw-cursor-pointer`}
-
- &:hover, &:active {
- color: var(--color);
- background-color: var(--backgroundHover);
- }
-
- &:focus,
- &:active,
- &:focus-visible {
- color: var(--color);
- }
-
- &:focus-visible {
- outline: var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default);
- outline-offset: var(--echoes-focus-border-offset-default);
- }
-
- &:disabled,
- &:disabled:hover {
- color: var(--echoes-color-text-disabled);
- background-color: ${themeColor('buttonDisabled')(props)};
- border: ${themeBorder('default', 'buttonDisabledBorder')(props)};
-
- ${tw`sw-cursor-not-allowed`}
- }
-
- & > svg {
- ${tw`sw-mr-1`}
- }
-`;
-
-const BaseButtonLink = styled(BaseLink)`
- ${buttonStyle}
-
- /*
- Workaround to apply disable style to button-link
- as link does not have disabled attribute, using props instead
- */
-
- ${({ disabled, theme }) =>
- disabled
- ? `&, &:hover, &:focus, &:active {
- color: var(--echoes-color-text-disabled);
- background-color: ${themeColor('buttonDisabled')({ theme })};
- border: ${themeBorder('default', 'buttonDisabledBorder')({ theme })};
- cursor: not-allowed;
- }`
- : undefined};
-`;
-
-const BaseButton = styled.button`
- ${buttonStyle}
-
- /*
- Workaround for tooltips issue with onMouseLeave in disabled buttons:
- https://github.com/facebook/react/issues/4251
- */
- & [disabled] {
- ${tw`sw-pointer-events-none`};
- }
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/ButtonPrimary.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/ButtonPrimary.tsx
deleted file mode 100644
index 9011fae73d4..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/ButtonPrimary.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { css } from '@emotion/react';
-import styled from '@emotion/styled';
-import { OPACITY_20_PERCENT, themeBorder, themeColor, themeContrast } from '../../../helpers';
-import { ThemedProps } from '../../../types';
-import { Button } from './Button';
-
-export const PrimaryStyle = (props: ThemedProps) => css`
- --background: ${themeColor('button')(props)};
- --backgroundHover: ${themeColor('buttonHover')(props)};
- --color: ${themeContrast('primary')(props)};
- --focus: ${themeColor('button', OPACITY_20_PERCENT)(props)};
- --border: ${themeBorder('default', 'transparent')(props)};
-`;
-
-/**
- * @deprecated Use Button from Echoes instead with the `variety` prop set
- * to ButtonVariety.Primary to have the same look and feel.
- *
- * Some of the props have changed or been renamed:
- * - `blurAfterClick` is now `shouldBlurAfterClick`
- * - `disabled` is now `isDisabled`, note that a Echoes Tooltip won't work
- * on a disabled button, use a text notice or ToggleTip next to the disabled button instead.
- * - `icon` is now replace by `prefix` which works the same way
- * - `preventDefault` is now `shouldPreventDefault`
- * - `stopPropagation` is now `shouldStopPropagation`
- *
- * The button can't be used as a link anymore, and all props related to links have been dropped.
- * Use a real Echoes Link instead.
- *
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3382706231/Button | Migration Guide} for more information.
- */
-export const ButtonPrimary = styled(Button)`
- ${PrimaryStyle}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/ButtonSecondary.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/ButtonSecondary.tsx
deleted file mode 100644
index 971f3554e98..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/ButtonSecondary.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { OPACITY_20_PERCENT, themeBorder, themeColor, themeContrast } from '../../../helpers';
-import { Button } from './Button';
-
-/**
- * @deprecated Use Button from Echoes instead without the `variety` prop set,
- * this is the default look and feel of the button.
- *
- * Some of the props have changed or been renamed:
- * - `blurAfterClick` is now `shouldBlurAfterClick`
- * - `disabled` is now `isDisabled`, note that a Echoes Tooltip won't work
- * on a disabled button, use a text notice or ToggleTip next to the disabled button instead.
- * - `icon` is now replace by `prefix` which works the same way
- * - `preventDefault` is now `shouldPreventDefault`
- * - `stopPropagation` is now `shouldStopPropagation`
- *
- * The button can't be used as a link anymore, and all props related to links have been dropped.
- * Use a real Echoes Link instead.
- *
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3382706231/Button | Migration Guide} for more information.
- */
-export const ButtonSecondary = styled(Button)`
- --background: ${themeColor('buttonSecondary')};
- --backgroundHover: ${themeColor('buttonSecondaryHover')};
- --color: ${themeContrast('buttonSecondary')};
- --focus: ${themeColor('buttonSecondaryBorder', OPACITY_20_PERCENT)};
- --border: ${themeBorder('default', 'buttonSecondaryBorder')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/DangerButtonPrimary.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/DangerButtonPrimary.tsx
deleted file mode 100644
index 9d60d6bf11e..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/DangerButtonPrimary.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { OPACITY_20_PERCENT, themeBorder, themeColor, themeContrast } from '../../../helpers';
-import { Button } from './Button';
-
-/**
- * @deprecated Use Button from Echoes instead with the `variety` prop set
- * to ButtonVariety.Danger to have the same look and feel.
- *
- * Some of the props have changed or been renamed:
- * - `blurAfterClick` is now `shouldBlurAfterClick`
- * - `disabled` is now `isDisabled`, note that a Echoes Tooltip won't work
- * on a disabled button, use a text notice or ToggleTip next to the disabled button instead.
- * - `icon` is now replace by `prefix` which works the same way
- * - `preventDefault` is now `shouldPreventDefault`
- * - `stopPropagation` is now `shouldStopPropagation`
- *
- * The button can't be used as a link anymore, and all props related to links have been dropped.
- * Use a real Echoes Link instead.
- *
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3382706231/Button | Migration Guide} for more information.
- */
-export const DangerButtonPrimary = styled(Button)`
- --background: ${themeColor('dangerButton')};
- --backgroundHover: ${themeColor('dangerButtonHover')};
- --color: ${themeContrast('dangerButton')};
- --focus: ${themeColor('dangerButtonFocus', OPACITY_20_PERCENT)};
- --border: ${themeBorder('default', 'transparent')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/DangerButtonSecondary.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/DangerButtonSecondary.tsx
deleted file mode 100644
index aa714154140..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/DangerButtonSecondary.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { OPACITY_20_PERCENT, themeBorder, themeColor, themeContrast } from '../../../helpers';
-import { Button } from './Button';
-
-/**
- * @deprecated Use Button from Echoes instead with the `variety` prop set
- * to ButtonVariety.DangerOutline to have the same look and feel.
- *
- * Some of the props have changed or been renamed:
- * - `blurAfterClick` is now `shouldBlurAfterClick`
- * - `disabled` is now `isDisabled`, note that a Echoes Tooltip won't work
- * on a disabled button, use a text notice or ToggleTip next to the disabled button instead.
- * - `icon` is now replace by `prefix` which works the same way
- * - `preventDefault` is now `shouldPreventDefault`
- * - `stopPropagation` is now `shouldStopPropagation`
- *
- * The button can't be used as a link anymore, and all props related to links have been dropped.
- * Use a real Echoes Link instead.
- *
- * See the {@link https://xtranet-sonarsource.atlassian.net/wiki/spaces/Platform/pages/3382706231/Button | Migration Guide} for more information.
- */
-export const DangerButtonSecondary = styled(Button)`
- --background: ${themeColor('dangerButtonSecondary')};
- --backgroundHover: ${themeColor('dangerButtonSecondaryHover')};
- --color: ${themeContrast('dangerButtonSecondary')};
- --focus: ${themeColor('dangerButtonSecondaryFocus', OPACITY_20_PERCENT)};
- --border: ${themeBorder('default', 'dangerButtonSecondaryBorder')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/ThirdPartyButton.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/ThirdPartyButton.tsx
deleted file mode 100644
index 702c32050d3..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/ThirdPartyButton.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import { OPACITY_20_PERCENT } from '../../../helpers/constants';
-import { themeBorder, themeColor, themeContrast } from '../../../helpers/theme';
-import { Button, ButtonProps } from './Button';
-
-interface ThirdPartyProps extends Omit<ButtonProps, 'Icon'> {
- iconPath: string;
- name: string;
-}
-
-export function ThirdPartyButton({
- children,
- iconPath,
- name,
- ...buttonProps
-}: Readonly<ThirdPartyProps>) {
- const size = 16;
- return (
- <ThirdPartyButtonStyled {...buttonProps}>
- <img alt={name} className="sw-mr-2" height={size} src={iconPath} width={size} />
- {children}
- </ThirdPartyButtonStyled>
- );
-}
-
-const ThirdPartyButtonStyled = styled(Button)`
- --background: ${themeColor('thirdPartyButton')};
- --backgroundHover: ${themeColor('thirdPartyButtonHover')};
- --color: ${themeContrast('thirdPartyButton')};
- --focus: ${themeColor('thirdPartyButtonBorder', OPACITY_20_PERCENT)};
- --border: ${themeBorder('default', 'thirdPartyButtonBorder')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/__tests__/ButtonPrimary-test.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/__tests__/ButtonPrimary-test.tsx
deleted file mode 100644
index 3bea90998ed..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/__tests__/ButtonPrimary-test.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render, screen } from '@testing-library/react';
-import { ButtonPrimary } from '../ButtonPrimary';
-
-it('renders ButtonPrimary correctly', () => {
- render(<ButtonPrimary>Hello</ButtonPrimary>);
- expect(screen.getByRole('button', { name: 'Hello' })).toBeInTheDocument();
-});
-
-it('renders ButtonPrimary correctly when to is defined', () => {
- render(
- <ButtonPrimary download="http://link.com" to="http://link.com">
- Hello
- </ButtonPrimary>,
- );
- expect(screen.queryByRole('button', { name: 'Hello' })).not.toBeInTheDocument();
- expect(screen.getByRole('link', { name: 'Hello' })).toBeInTheDocument();
-});
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/index.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/index.ts
deleted file mode 100644
index 6ee90cb4fa7..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/buttons/index.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './BareButton';
-export * from './Button';
-export * from './ButtonPrimary';
-export * from './ButtonSecondary';
-export * from './DangerButtonPrimary';
-export * from './DangerButtonSecondary';
-export * from './ThirdPartyButton';
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/index.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/index.ts
deleted file mode 100644
index 4c7641353c3..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/index.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './buttons';
-export * from './Card';
-export { DismissableFlagMessage, FlagMessage } from './FlagMessage';
-export { FlagMessageV2 } from './FlagMessageV2';
-export * from './input';
-export * from './MetricsRatingBadge';
-export * from './Table';
-export * from './Text';
-export * from './ToggleButton';
-export * from './typography';
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/InputSelect.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/InputSelect.tsx
deleted file mode 100644
index 09c78a502b4..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/InputSelect.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { omit } from 'lodash';
-import { useMemo } from 'react';
-import ReactSelect, { GroupBase } from 'react-select';
-import {
- ClearIndicator,
- DropdownIndicator,
- IconOption,
- SelectProps,
- SingleValue,
- selectStyle,
-} from './SelectCommon';
-
-/**
- * @deprecated Use Select or SelectAsync from Echoes instead.
- *
- * See the [Migration Guide](https://xtranet-sonarsource.atlassian.net/wiki/x/K4AYxw)
- */
-export function InputSelect<
- Option,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
->({
- size = 'medium',
- className,
- options,
- getOptionLabel,
- selectRef,
- shouldSortOption = false,
- ...props
-}: SelectProps<Option, IsMulti, Group>) {
- const orderedOptions = useMemo(() => {
- if (!options || options.length === 0) {
- return options;
- }
-
- if (shouldSortOption) {
- return (options as Option[]).sort((a, b) => {
- const nameA = getOptionLabel?.(a).toUpperCase() ?? '';
- const nameB = getOptionLabel?.(b).toUpperCase() ?? '';
- if (nameA < nameB) {
- return -1;
- }
- if (nameA > nameB) {
- return 1;
- }
-
- return 0;
- });
- }
-
- return options;
- }, [shouldSortOption, getOptionLabel, options]);
-
- return (
- <ReactSelect<Option, IsMulti, Group>
- {...omit(props, 'className', 'large')}
- className={classNames('react-select', className)}
- classNamePrefix="react-select"
- classNames={{
- container: () => 'sw-relative sw-inline-block sw-align-middle',
- placeholder: () => 'sw-truncate sw-leading-4',
- menu: () => 'sw-z-dropdown-menu sw-ml-1/2 sw-mt-2',
- menuList: () => 'sw-overflow-y-auto sw-py-2 sw-max-h-[12.25rem]',
- clearIndicator: () => 'sw-p-0',
- dropdownIndicator: () => classNames(props.isClearable && 'sw-p-0'),
- control: ({ isDisabled }) =>
- classNames(
- 'sw-box-border sw-rounded-2 sw-overflow-hidden',
- isDisabled && 'sw-pointer-events-none sw-cursor-not-allowed',
- ),
- option: ({ isDisabled }) =>
- classNames(
- 'it__select-option sw-py-2 sw-px-3 sw-cursor-pointer',
- isDisabled && 'sw-pointer-events-none sw-cursor-not-allowed',
- ),
- ...props.classNames,
- }}
- components={{
- ClearIndicator,
- Option: IconOption,
- SingleValue,
- DropdownIndicator,
- IndicatorSeparator: null,
- ...props.components,
- }}
- getOptionLabel={getOptionLabel}
- isClearable={props.isClearable ?? false}
- isSearchable={props.isSearchable ?? false}
- onMenuOpen={props.onMenuOpen}
- options={orderedOptions}
- ref={selectRef}
- styles={selectStyle({ size })}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/SelectCommon.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/SelectCommon.tsx
deleted file mode 100644
index 66a331362f9..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/SelectCommon.tsx
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme as themeInfo } from '@emotion/react';
-import { RefObject } from 'react';
-import { useIntl } from 'react-intl';
-import {
- ClearIndicatorProps,
- GroupBase,
- Props as NamedProps,
- OptionProps,
- StylesConfig,
- components,
-} from 'react-select';
-import Select from 'react-select/dist/declarations/src/Select';
-import { InteractiveIcon } from '../../../components/InteractiveIcon';
-import { SearchHighlighter } from '../../../components/SearchHighlighter';
-import { ChevronDownIcon, CloseIcon } from '../../../components/icons';
-import { INPUT_SIZES } from '../../../helpers';
-import { themeBorder, themeColor, themeContrast } from '../../../helpers/theme';
-import { InputSizeKeys } from '../../../types/theme';
-
-export interface ExtensionProps<
- Option,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
-> {
- clearLabel?: string;
- selectRef?: RefObject<Select<Option, IsMulti, Group>>;
- shouldSortOption?: boolean;
- size?: InputSizeKeys;
-}
-
-export type SelectProps<
- Option,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
-> = NamedProps<Option, IsMulti, Group> & ExtensionProps<Option, IsMulti, Group>;
-
-export function IconOption<
- Option,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
->(props: OptionProps<Option, IsMulti, Group>) {
- const { label, isSelected } = props;
- const { Icon } = props.data as { Icon: JSX.Element };
-
- // For tests and a11y
- props.innerProps.role = 'option';
- props.innerProps['aria-selected'] = isSelected;
-
- return (
- <components.Option {...props}>
- <div className="sw-flex sw-items-center sw-gap-1">
- {Icon}
- <SearchHighlighter>{label}</SearchHighlighter>
- </div>
- </components.Option>
- );
-}
-
-export function SingleValue<
- Option,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
->(props: OptionProps<Option, IsMulti, Group>) {
- const label = props.selectProps.getOptionLabel(props.data);
- const { Icon } = props.data as { Icon: JSX.Element };
-
- return (
- <components.SingleValue {...props}>
- <div className="sw-flex sw-items-center sw-gap-1">
- {Icon}
- {label}
- </div>
- </components.SingleValue>
- );
-}
-
-export function ClearIndicator<
- Option,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
->(
- props: ClearIndicatorProps<Option, IsMulti, Group> & {
- selectProps: SelectProps<Option, IsMulti, Group>;
- },
-) {
- const intl = useIntl();
- const {
- selectProps: { clearLabel },
- } = props;
-
- return (
- <components.ClearIndicator {...props}>
- <InteractiveIcon
- Icon={CloseIcon}
- aria-label={clearLabel ?? intl.formatMessage({ id: 'clear' })}
- onClick={props.clearValue}
- size="small"
- />
- </components.ClearIndicator>
- );
-}
-
-export function DropdownIndicator<
- Option,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
->(props: OptionProps<Option, IsMulti, Group>) {
- return (
- <components.DropdownIndicator {...props}>
- <div className="sw-pr-2 sw-flex">
- <ChevronDownIcon />
- </div>
- </components.DropdownIndicator>
- );
-}
-
-export function selectStyle<
- Option,
- IsMulti extends boolean = false,
- Group extends GroupBase<Option> = GroupBase<Option>,
->({ size }: { size: InputSizeKeys }): StylesConfig<Option, IsMulti, Group> {
- const theme = themeInfo();
-
- return {
- control: (base, { isFocused, menuIsOpen, isDisabled }) => ({
- ...base,
- color: themeContrast('inputBackground')({ theme }),
- cursor: 'pointer',
- background: themeColor('inputBackground')({ theme }),
- transition: 'border 0.2s ease, outline 0.2s ease',
- outline:
- isFocused && !menuIsOpen
- ? 'var(--echoes-focus-border-width-default) solid var(--echoes-color-focus-default)'
- : 'none',
- borderRadius: '4px',
- ...(isDisabled && {
- color: 'var(--echoes-color-text-disabled)',
- background: themeColor('inputDisabled')({ theme }),
- border: themeBorder('default', 'inputDisabledBorder')({ theme }),
- outline: 'none',
- }),
- ...(isFocused && {
- border: themeBorder('default', 'inputBorder')({ theme }),
- }),
- }),
- menu: (base) => ({
- ...base,
- width: INPUT_SIZES[size],
- }),
- option: (base, { isFocused, isSelected }) => ({
- ...base,
- borderLeft: '2px solid transparent',
- ...((isSelected || isFocused) && {
- background: themeColor('selectOptionSelected')({ theme }),
- color: themeContrast('primaryLight')({ theme }),
- borderLeftColor: 'var(--echoes-color-focus-default)',
- }),
- }),
- singleValue: (base) => ({
- ...base,
- color: themeContrast('primaryLight')({ theme }),
- }),
- placeholder: (base) => ({
- ...base,
- color: 'var(--echoes-color-text-placeholder)',
- }),
- };
-}
-
-export interface LabelValueSelectOption<V = string> {
- Icon?: React.ReactNode;
- label: string;
- value: V;
-}
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/__tests__/InputSelect-test.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/__tests__/InputSelect-test.tsx
deleted file mode 100644
index 5b72e42562e..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/__tests__/InputSelect-test.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { renderWithContext } from '../../../../helpers/testUtils';
-import { FCProps } from '../../../../types/misc';
-import { InputSelect } from '../InputSelect';
-
-it('should render select input and be able to click and change', async () => {
- const setValue = jest.fn();
- const user = userEvent.setup();
- setupWithProps({ placeholder: 'placeholder-foo', onChange: setValue });
- expect(screen.getByText('placeholder-foo')).toBeInTheDocument();
- await user.click(screen.getByRole('combobox'));
- expect(screen.getByText(/option foo-bar focused/)).toBeInTheDocument();
- expect(screen.getByRole('note', { name: 'Icon' })).toBeInTheDocument();
- await user.click(screen.getByText('bar-foo'));
- expect(setValue).toHaveBeenCalled();
- expect(screen.queryByText('placeholder-foo')).not.toBeInTheDocument();
- expect(screen.getByRole('note', { name: 'Icon' })).toBeInTheDocument();
-});
-
-it('should render select input with clearable', async () => {
- const setValue = jest.fn();
- const user = userEvent.setup();
- setupWithProps({
- placeholder: 'placeholder-foo',
- onChange: setValue,
- isClearable: true,
- clearLabel: 'clear-label',
- });
- expect(screen.getByText('placeholder-foo')).toBeInTheDocument();
- await user.click(screen.getByRole('combobox'));
- expect(screen.getByText(/option foo-bar focused/)).toBeInTheDocument();
- expect(screen.getByRole('note', { name: 'Icon' })).toBeInTheDocument();
- await user.click(screen.getByText('bar-foo'));
- expect(setValue).toHaveBeenCalled();
- expect(screen.queryByText('placeholder-foo')).not.toBeInTheDocument();
- expect(screen.getByRole('note', { name: 'Icon' })).toBeInTheDocument();
-
- // Clear button container aria-hidden by default
- expect(screen.getByRole('button', { name: 'clear-label', hidden: true })).toBeInTheDocument();
- await user.click(screen.getByRole('button', { name: 'clear-label', hidden: true }));
- expect(screen.getByText('placeholder-foo')).toBeInTheDocument();
-});
-
-it('should render select input with disabled prop', () => {
- const setValue = jest.fn();
- setupWithProps({ placeholder: 'placeholder-foo', onChange: setValue, isDisabled: true });
- expect(screen.getByText('placeholder-foo')).toBeInTheDocument();
- expect(screen.getByRole('combobox')).toBeDisabled();
-});
-
-it('should render the select options with sorting when shouldSortOption is true and getOptionLabel passed', async () => {
- const { user } = setupWithProps({
- shouldSortOption: true,
- getOptionLabel: (o: { label: string }) => o.label,
- });
- await user.click(screen.getByRole('combobox'));
- const options = screen.getAllByRole('option');
- expect(options).toHaveLength(2);
- expect(options[0]).toHaveTextContent('bar-foo');
- expect(options[1]).toHaveTextContent('foo-bar');
-});
-
-function setupWithProps(props: Partial<FCProps<typeof InputSelect>>) {
- return renderWithContext(
- <InputSelect
- {...props}
- options={[
- { label: 'foo-bar', value: 'foo' },
- {
- label: 'bar-foo',
- value: 'bar',
- Icon: (
- <span role="note" title="Icon">
- Icon
- </span>
- ),
- },
- ]}
- />,
- );
-}
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/index.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/index.ts
deleted file mode 100644
index b8fd68f2a75..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/input/index.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './InputSelect';
-export * from './SelectCommon';
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/typography/Note.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/typography/Note.tsx
deleted file mode 100644
index bf259e4fd0c..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/typography/Note.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-
-export const Note = styled.span`
- color: var(--echoes-color-text-subdued);
-
- ${tw`sw-typo-default`}
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/typography/Title.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/typography/Title.tsx
deleted file mode 100644
index 30f71f3b4af..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/typography/Title.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import styled from '@emotion/styled';
-import tw from 'twin.macro';
-import { themeColor } from '../../../helpers/theme';
-
-/** @deprecated Use Heading from Echoes instead.
- */
-export const Title = styled.h1`
- ${tw`sw-heading-xl`}
- ${tw`sw-mb-4`}
- color: ${themeColor('pageTitle')};
-`;
-
-/** @deprecated Use Heading from Echoes instead.
- */
-export const SubTitle = styled.h2`
- ${tw`sw-heading-lg`}
- ${tw`sw-mb-4`}
- color: ${themeColor('pageTitle')};
-`;
-
-/** @deprecated Use Heading from Echoes instead.
- */
-export const HeadingDark = styled.h2`
- color: ${themeColor('pageContentDark')};
-
- ${tw`sw-typo-semibold`}
-`;
-
-/** @deprecated Use Heading from Echoes instead.
- */
-export const SubHeading = styled.h3`
- ${tw`sw-typo-lg-semibold`}
- ${tw`sw-mb-2`}
- color: ${themeColor('pageContent')};
-`;
-
-/** @deprecated Use Heading from Echoes instead.
- */
-export const SubHeadingHighlight = styled(SubHeading)`
- color: ${themeColor('pageContentDark')};
-`;
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/typography/index.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/components/typography/index.ts
deleted file mode 100644
index 113312da470..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/components/typography/index.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './Note';
-export * from './Title';
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/__tests__/sanitize-test.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/__tests__/sanitize-test.tsx
deleted file mode 100644
index b8be9b99daf..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/__tests__/sanitize-test.tsx
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render, screen } from '@testing-library/react';
-import {
- SafeHTMLInjection,
- sanitizeHTMLNoSVGNoMathML,
- sanitizeHTMLRestricted,
- sanitizeHTMLToPreventCSSInjection,
- sanitizeHTMLUserInput,
-} from '../sanitize';
-
-/*
- * Test code borrowed from OWASP's sanitizer tests
- * https://github.com/OWASP/java-html-sanitizer/blob/master/src/test/resources/org/owasp/html/htmllexerinput1.html
- */
-const tainted = `<?xml version="not-even-close"?>
-
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-
-<!-- a test input for HtmlLexer -->
-
-<html lang="en" xml:lang="en">
-<head>
-<title>Test File For HtmlLexer &amp; HtmlParser</title>
-<link rel=stylesheet type="text/css" src=foo/bar.css />
-<body
- bgcolor=white
- linkcolor = "blue"
- onload="document.writeln(
- &quot;&lt;p&gt;properly escaped code in a handler&lt;/p&gt;&quot;);"
->
-
-<script type="text/javascript"><!--
-document.writeln("<p>Some initialization code in global context</p>");
---></script>
-
-<script type="text/javascript">
-// hi there
-document.writeln("<p>More initialization</p>");
-</script>
-
-<div id=clickydiv onclick="handleClicky(event)"
- ondblclick=this.onclick(event);return(false)>
-Clicky
-</div>
-
-<input id=foo>
-<gxp:attr name="onchange">alert("&lt;b&gt;hi&lt;/b&gt;");</gxp:attr>
-</input>
-
-<pre>&lt;div id=notarealtag onclick=notcode()&gt;</pre>
-
-<!-- some tokenization corner cases -->
-
-< notatag <atag/>
-
-</ notatag> </redundantlyclosed/>
-
-<messyattributes a=b=c d="e"f=g h =i j= k l = m checked n="o"/>
-
-< < < all in one text block > > >
-
-<xmp>Make sure that <!-- comments don't obscure the xmp close</xmp>
-<% # some php code here
-write("<pre>$horriblySyntacticConstruct1</pre>\n\n");
-%>
-<script type="text/javascript"><!--
-alert("hello world");
-// --></script>
-
-<script>/* </script> */alert('hi');</script>
-<script><!--/* </script> */alert('hi');--></script>
-
-<xmp style=color:blue><!--/* </xmp> */alert('hi');--></xmp>
-
-<style><!-- p { contentf: '</style>' } --></style>
-<style>Foo<!-- > </style> --></style>
-<textarea><!-- Zoicks </textarea>--></textarea>
-<!-- An escaping text span start may share its U+002D HYPHEN-MINUS characters
- - with its corresponding escaping text span end. -->
-<script><!--></script>
-<script><!---></script>
-<script><!----></script>
-
-This is <b>bold</b> and this is <i>italic</i> and this is <u>underlined</u>.
-<br />
-A <blockquote>quote</blockquote> and a <code>code</code> and a <pre>pre</pre>.
-An <h1>h1</h1> and an <h2>h2</h2> and an <h3>h3</h3> and an <h4>h4</h4> and an <h5>h5</h5> and an <h6>h6</h6>.
-An <ol><li>ol</li></ol> and a <ul><li>ul</li></ul> and a <p style="color:blue">p</p>.
-A <strong>strong</strong> and a <a href="foo" ping="pong" rel="noopener" target="__blank" >link</a>
-
-<a href="javascript:alert('hello')" target="_blank">this is wrong</a>
-
-<svg><text>SVG isn't always allowed</text></svg>
-
-<math xmlns="http://www.w3.org/1998/Math/MathML">
- <infinity />
-</math>
-
-</body>
-</html>
-<![CDATA[ No such thing as a CDATA> section in HTML ]]>
-<script>a<b</script>
-<img src=foo.gif /><a href=><a href=/>
-<span title=malformed attribs' do=don't id=foo checked onclick="a<b">Bar</span>`;
-
-describe('sanitizeHTMLToPreventCSSInjection', () => {
- it('should strip off style attributes', () => {
- const clean = `
- <div id="clickydiv">
- Clicky
- </div>
- <input id="foo">
- alert("&lt;b&gt;hi&lt;/b&gt;");
- <pre>&lt;div id=notarealtag onclick=notcode()&gt;</pre>
- &lt; notatag
- &lt; &lt; &lt; all in one text block &gt; &gt; &gt;
- &lt;% # some php code here
- write("<pre>$horriblySyntacticConstruct1</pre>
- ");
- %&gt;
- */alert('hi');
- */alert('hi');--&gt;
- */alert('hi');--&gt; ' } --&gt;
- --&gt;
- <textarea>&lt;!-- Zoicks </textarea>--&gt;
- This is <b>bold</b> and this is <i>italic</i> and this is <u>underlined</u>.
- <br>
- A <blockquote>quote</blockquote> and a <code>code</code> and a <pre>pre</pre>.
- An <h1>h1</h1> and an <h2>h2</h2> and an <h3>h3</h3> and an <h4>h4</h4> and an <h5>h5</h5> and an <h6>h6</h6>.
- An <ol><li>ol</li></ol> and a <ul><li>ul</li></ul> and a <p>p</p>.
- A <strong>strong</strong> and a <a rel="noopener" href="foo">link</a>
- <a>this is wrong</a>
- <svg><text>SVG isn't always allowed</text></svg>
- <math xmlns="http://www.w3.org/1998/Math/MathML">
- </math>
- section in HTML ]]&gt;
- <img src="foo.gif"><a href=""></a><a href="/">
- <span checked="" id="foo" title="malformed">Bar</span></a>`;
-
- expect(sanitizeHTMLToPreventCSSInjection(tainted).trimEnd().replace(/\s+/g, ' ')).toBe(
- clean.replace(/\s+/g, ' '),
- );
- });
-});
-
-describe('sanitizeHTMLNoSVGNoMathML', () => {
- it('should not allow MathML and SVG', () => {
- const clean = `
- <div id="clickydiv">
- Clicky
- </div>
- <input id="foo">
- alert("&lt;b&gt;hi&lt;/b&gt;");
- <pre>&lt;div id=notarealtag onclick=notcode()&gt;</pre>
- &lt; notatag
- &lt; &lt; &lt; all in one text block &gt; &gt; &gt;
- &lt;% # some php code here
- write("<pre>$horriblySyntacticConstruct1</pre>
- ");
- %&gt;
- */alert('hi');
- */alert('hi');--&gt;
- */alert('hi');--&gt; ' } --&gt;
- --&gt;
- <textarea>&lt;!-- Zoicks </textarea>--&gt;
- This is <b>bold</b> and this is <i>italic</i> and this is <u>underlined</u>.
- <br>
- A <blockquote>quote</blockquote> and a <code>code</code> and a <pre>pre</pre>.
- An <h1>h1</h1> and an <h2>h2</h2> and an <h3>h3</h3> and an <h4>h4</h4> and an <h5>h5</h5> and an <h6>h6</h6>.
- An <ol><li>ol</li></ol> and a <ul><li>ul</li></ul> and a <p>p</p>.
- A <strong>strong</strong> and a <a rel="noopener" href="foo">link</a>
- <a>this is wrong</a>
- section in HTML ]]&gt;
- <img src="foo.gif"><a href=""></a><a href="/">
- <span checked="" id="foo" title="malformed">Bar</span></a>`;
-
- expect(sanitizeHTMLNoSVGNoMathML(tainted).trimEnd().replace(/\s+/g, ' ')).toBe(
- clean.replace(/\s+/g, ' '),
- );
- });
-});
-
-describe('sanitizeHTMLUserInput', () => {
- it('should preserve only specific formatting tags and attributes', () => {
- const clean = `
- Clicky
- alert("&lt;b&gt;hi&lt;/b&gt;");
- <pre>&lt;div id=notarealtag onclick=notcode()&gt;</pre>
- &lt; notatag
- &lt; &lt; &lt; all in one text block &gt; &gt; &gt;
- &lt;% # some php code here
- write("<pre>$horriblySyntacticConstruct1</pre>
- ");
- %&gt;
- */alert('hi');
- */alert('hi');--&gt;
- */alert('hi');--&gt; ' } --&gt;
- --&gt;
- &lt;!-- Zoicks --&gt;
- This is <b>bold</b> and this is <i>italic</i> and this is underlined.
- <br>
- A <blockquote>quote</blockquote> and a <code>code</code> and a <pre>pre</pre>.
- An <h1>h1</h1> and an <h2>h2</h2> and an <h3>h3</h3> and an <h4>h4</h4> and an <h5>h5</h5> and an <h6>h6</h6>.
- An <ol><li>ol</li></ol> and a <ul><li>ul</li></ul> and a <p>p</p>.
- A <strong>strong</strong> and a <a rel="noopener" href="foo">link</a>
- <a>this is wrong</a>
- section in HTML ]]&gt;
- <a href=""></a><a href="/">
- Bar</a>`;
-
- expect(sanitizeHTMLUserInput(tainted).trimEnd().replace(/\s+/g, ' ')).toBe(
- clean.replace(/\s+/g, ' '),
- );
- });
-});
-
-describe('sanitizeHTMLRestricted', () => {
- it('should preserve only a very limited list of formatting tags and attributes', () => {
- const clean = `
- Clicky
- alert("&lt;b&gt;hi&lt;/b&gt;");
- &lt;div id=notarealtag onclick=notcode()&gt;
- &lt; notatag
- &lt; &lt; &lt; all in one text block &gt; &gt; &gt;
- &lt;% # some php code here
- write("$horriblySyntacticConstruct1
- ");
- %&gt;
- */alert('hi');
- */alert('hi');--&gt;
- */alert('hi');--&gt; ' } --&gt;
- --&gt;
- &lt;!-- Zoicks --&gt;
- This is <b>bold</b> and this is <i>italic</i> and this is underlined.
- <br>
- A quote and a <code>code</code> and a pre.
- An h1 and an h2 and an h3 and an h4 and an h5 and an h6.
- An <li>ol</li> and a <ul><li>ul</li></ul> and a <p>p</p>.
- A <strong>strong</strong> and a <a href="foo">link</a>
- <a>this is wrong</a>
- section in HTML ]]&gt;
- <a href=""></a><a href="/">
- Bar</a>`;
-
- expect(sanitizeHTMLRestricted(tainted).trimEnd().replace(/\s+/g, ' ')).toBe(
- clean.replace(/\s+/g, ' '),
- );
- });
-});
-
-describe('SafeHTMLInjection', () => {
- it('should default to a span and the SanitizeLevel.FORBID_STYLE level', () => {
- const tainted = `
- <head>
- <link rel=stylesheet type="text/css" src=foo/bar.css />
- <style>some style</style>
- </head>
-
- <body>
- <p style="color:blue">a stylish paragraph</p>
-
- <svg><text>SVG isn't always allowed</text></svg>
-
- <math xmlns="http://www.w3.org/1998/Math/MathML">
- <infinity />
- </math>
- </body>
- `;
-
- render(<SafeHTMLInjection htmlAsString={tainted} />);
-
- expect(screen.getByText('a stylish paragraph')).toBeInTheDocument();
- expect(screen.getByText("SVG isn't always allowed")).toBeInTheDocument();
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/__tests__/tabs-test.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/__tests__/tabs-test.ts
deleted file mode 100644
index b2bb634e174..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/__tests__/tabs-test.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getTabId, getTabPanelId } from '../tabs';
-
-it('should correctly generate IDs', () => {
- expect(getTabId('ID')).toBe('tab-ID');
- expect(getTabPanelId('ID')).toBe('tabpanel-ID');
-});
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/index.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/index.ts
deleted file mode 100644
index e288f05e8ee..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/index.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './sanitize';
-export * from './tabs';
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/sanitize.tsx b/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/sanitize.tsx
deleted file mode 100644
index 1426c567efd..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/sanitize.tsx
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import dompurify from 'dompurify';
-
-import React from 'react';
-
-const { sanitize } = dompurify;
-
-export enum SanitizeLevel {
- FORBID_STYLE, // minimum sanitation level to prevent CSS injections
- FORBID_SVG_MATHML, // adds SVG and MathML exclusion
- USER_INPUT, // adds restrictions on tags and attributes
- RESTRICTED, // adds even more restrictions on tags and attributes
-}
-
-export const sanitizeFunctionByLevel = (sanitizeLevel: SanitizeLevel) =>
- ({
- [SanitizeLevel.FORBID_STYLE]: sanitizeHTMLToPreventCSSInjection,
- [SanitizeLevel.FORBID_SVG_MATHML]: sanitizeHTMLNoSVGNoMathML,
- [SanitizeLevel.USER_INPUT]: sanitizeHTMLUserInput,
- [SanitizeLevel.RESTRICTED]: sanitizeHTMLRestricted,
- })[sanitizeLevel];
-
-export const sanitizeHTMLToPreventCSSInjection = (htmlAsString: string) =>
- sanitize(htmlAsString, {
- FORBID_ATTR: ['style'],
- FORBID_TAGS: ['style'],
- });
-
-export function sanitizeHTMLNoSVGNoMathML(htmlAsString: string) {
- return sanitize(htmlAsString, {
- FORBID_ATTR: ['style'],
- FORBID_TAGS: ['style'],
- USE_PROFILES: { html: true },
- });
-}
-
-export function sanitizeHTMLUserInput(htmlAsString: string) {
- return sanitize(htmlAsString, {
- ALLOWED_ATTR: ['href', 'rel'],
- ALLOWED_TAGS: [
- 'a',
- 'b',
- 'blockquote',
- 'br',
- 'code',
- 'h1',
- 'h2',
- 'h3',
- 'h4',
- 'h5',
- 'h6',
- 'i',
- 'li',
- 'ol',
- 'p',
- 'pre',
- 'strong',
- 'ul',
- ],
- });
-}
-
-export function sanitizeHTMLRestricted(htmlAsString: string) {
- return sanitize(htmlAsString, {
- ALLOWED_ATTR: ['href'],
- ALLOWED_TAGS: ['a', 'b', 'br', 'code', 'i', 'li', 'p', 'strong', 'ul'],
- });
-}
-
-/**
- * Safely injects HTML into an element with no risk of XSS attacks.
- *
- * @param children The React element to clone with the sanitized HTML (defaults to a `span`)
- * @param htmlAsString The HTML string to sanitize and inject (required)
- * @param sanitizeLevel The level of sanitation to apply (defaults to `SanitizeLevel.FORBID_STYLE`)
- *
- * @returns A React element with the sanitized HTML injected, and all other props preserved
- *
- * @example
- * Here's a simple example with no children:
- * ```
- * <SafeHTMLInjection htmlAsString={taintedString} />
- * ```
- *
- * @example
- * Here's an example with a custom `sanitizeLevel` and a child `div`:
- * ```
- * <SafeHTMLInjection htmlAsString={taintedString} sanitizeLevel={SanitizeLevel.RESTRICTED}>
- * // the HTML will be safely injected in the div below, with the className preserved:
- * <div className="someClassThatWillBePreserved" />
- * </SafeHTMLInjection>
- * ```
- */
-export const SafeHTMLInjection = ({
- children,
- htmlAsString,
- sanitizeLevel = SanitizeLevel.FORBID_STYLE,
-}: Readonly<{
- children?: React.ReactElement;
- htmlAsString: string;
- sanitizeLevel?: SanitizeLevel;
-}>) =>
- React.cloneElement(children ?? <span />, {
- dangerouslySetInnerHTML: { __html: sanitizeFunctionByLevel(sanitizeLevel)(htmlAsString) },
- });
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/tabs.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/tabs.ts
deleted file mode 100644
index 277cf1040ac..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/helpers/tabs.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export function getTabPanelId(key: string | number) {
- return `tabpanel-${key}`;
-}
-
-export function getTabId(key: string | number) {
- return `tab-${key}`;
-}
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/HljsIssueIndicatorPlugin.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/HljsIssueIndicatorPlugin.ts
deleted file mode 100644
index 782a23d1bea..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/HljsIssueIndicatorPlugin.ts
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { BeforeHighlightContext, HighlightResult } from 'highlight.js';
-
-const BREAK_LINE_REGEXP = /\n/g;
-
-/**
- * Plugin for HLJS to add issue indicators to the code.
- *
- * In order to add issue indicators (sidebar with indicators to issue count on each line), the input source code must be preprocessed using the addIssuesToLines() method. This method will update the source code to prepend the list of issues key of this line.
- * Then, the `before` hook of the HLJS plugin will extract the issue keys from the source code, store them in memory for later use, and drop the issue keys token from the source code.
- * Finally, the `after` hook will add some HTML markup with a reference to the issue key in the transformed code source. The actual interactive issue indicators will be attached inside this HTML markup later on with a React Portal.
- *
- * Each line is wrapped with a div element that contains the issue indicators and the line content.
- */
-export class HljsIssueIndicatorPlugin {
- static readonly LINE_WRAPPER_STYLE = [
- 'display: inline-grid',
- 'grid-template-rows: auto',
- 'grid-template-columns: 26px 1fr',
- 'align-items: center',
- ].join(';');
-
- private issueKeys: { [line: string]: string[] };
- static readonly LINE_WRAPPER_OPEN_TAG = `<div style="${this.LINE_WRAPPER_STYLE}">`;
- static readonly LINE_WRAPPER_CLOSE_TAG = `</div>`;
- static readonly EMPTY_INDICATOR_COLUMN = `<div></div>`;
- public lineIssueIndicatorElement(issueKey: string) {
- return `<div id="issue-key-${issueKey}"></div>`;
- }
-
- constructor() {
- this.issueKeys = {};
- }
-
- 'before:highlight'(data: BeforeHighlightContext) {
- data.code = this.extractIssue(data.code);
- }
-
- 'after:highlight'(data: HighlightResult) {
- if (Object.keys(this.issueKeys).length > 0) {
- data.value = this.addIssueIndicator(data.value);
- }
- // reset issueKeys for next CodeSnippet
- this.issueKeys = {};
- }
-
- addIssuesToLines = (sourceLines: string[], issues: { [line: number]: string[] }) => {
- return sourceLines.map((line, lineIndex) => {
- const issuesByLine = issues[lineIndex];
- if (!issues || !issuesByLine) {
- return line;
- }
-
- return `[ISSUE_KEYS:${issuesByLine.join(',')}]${line}`;
- });
- };
-
- private getLines(text: string) {
- if (text.length === 0) {
- return [];
- }
- return text.split(BREAK_LINE_REGEXP);
- }
-
- private extractIssue(inputHtml: string) {
- const lines = this.getLines(inputHtml);
- const issueKeysPattern = /\[ISSUE_KEYS:([^\]]+)\](.+)/;
- const removeIssueKeysPattern = /\[ISSUE_KEYS:[^\]]+\](.+)/;
-
- const wrappedLines = lines.map((line, lineNumber) => {
- const match = issueKeysPattern.exec(line);
-
- if (match) {
- const issueKeys = match[1].split(',');
- if (!this.issueKeys[lineNumber]) {
- this.issueKeys[lineNumber] = issueKeys;
- } else {
- this.issueKeys[lineNumber].push(...issueKeys);
- }
- }
-
- const result = removeIssueKeysPattern.exec(line);
-
- return result ? result[1] : line;
- });
-
- return wrappedLines.join('\n');
- }
-
- private addIssueIndicator(inputHtml: string) {
- const lines = this.getLines(inputHtml);
-
- const wrappedLines = lines.map((line, lineNumber) => {
- const issueKeys = this.issueKeys[lineNumber];
-
- if (issueKeys) {
- // the react portal looks for the first issue key
- const referenceIssueKey = issueKeys[0];
- return [
- HljsIssueIndicatorPlugin.LINE_WRAPPER_OPEN_TAG,
- this.lineIssueIndicatorElement(referenceIssueKey),
- '<div>',
- line,
- '</div>',
- HljsIssueIndicatorPlugin.LINE_WRAPPER_CLOSE_TAG,
- ].join('');
- }
-
- // Keep the correct structure when at least one line has issues
- return [
- HljsIssueIndicatorPlugin.LINE_WRAPPER_OPEN_TAG,
- HljsIssueIndicatorPlugin.EMPTY_INDICATOR_COLUMN,
- '<div>',
- line,
- '</div>',
- HljsIssueIndicatorPlugin.LINE_WRAPPER_CLOSE_TAG,
- ].join('');
- });
-
- return wrappedLines.join('\n');
- }
-}
-
-const hljsIssueIndicatorPlugin = new HljsIssueIndicatorPlugin();
-export { hljsIssueIndicatorPlugin };
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/HljsUnderlinePlugin.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/HljsUnderlinePlugin.ts
deleted file mode 100644
index bca593e8e40..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/HljsUnderlinePlugin.ts
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { HighlightResult } from 'highlight.js';
-
-export interface UnderlineRangePosition {
- cursorOffset: number;
- line: number;
-}
-
-interface UnderlineRange {
- end: UnderlineRangePosition;
- start: UnderlineRangePosition;
-}
-
-/**
- * Plugin for HLJS to underline content.
- *
- * In order to underline code, the input source code must be preprocessed using the tokenize() method.
- * Then, the after hook will replace the tokens with the appropriate HTML markup to underline the content.
- */
-export class HljsUnderlinePlugin {
- static readonly SPAN_REGEX = '<\\/?span[^>]*>';
-
- static readonly TOKEN_PREFIX = 'SNR_TGXRJVF'; // Random string to avoid conflicts with real code
-
- static readonly TOKEN_SUFFIX_START = '_START';
-
- static readonly TOKEN_SUFFIX_END = '_END';
-
- static readonly TOKEN_START =
- HljsUnderlinePlugin.TOKEN_PREFIX + HljsUnderlinePlugin.TOKEN_SUFFIX_START;
-
- static readonly TOKEN_END =
- HljsUnderlinePlugin.TOKEN_PREFIX + HljsUnderlinePlugin.TOKEN_SUFFIX_END;
-
- static readonly OPEN_TAG = '<span data-testid="hljs-sonar-underline" class="sonar-underline">';
-
- static readonly CLOSE_TAG = '</span>';
-
- /**
- * Add a pair of tokens to the source code to mark the start and end of the content to be underlined.
- */
- tokenize(source: string[], ranges: UnderlineRange[]): string[] {
- // Order ranges by start position, ascending
- ranges.sort((a, b) => {
- if (a.start.line === b.start.line) {
- return a.start.cursorOffset - b.start.cursorOffset;
- }
- return a.start.line - b.start.line;
- });
-
- // We want to merge overlapping ranges to ensure the underline markup doesn't intesect with itself in the after hook
- const simplifiedRanges: UnderlineRange[] = [];
- let currentRange = ranges[0];
- for (let i = 1; i < ranges.length; i++) {
- const nextRange = ranges[i];
-
- if (
- currentRange.start.line <= nextRange.start.line &&
- currentRange.start.cursorOffset <= nextRange.start.cursorOffset &&
- currentRange.end.line >= nextRange.end.line &&
- currentRange.end.cursorOffset >= nextRange.end.cursorOffset
- ) {
- // Range is contained in the current range. Do nothing
- } else if (
- currentRange.end.line >= nextRange.start.line &&
- currentRange.end.cursorOffset >= nextRange.start.cursorOffset
- ) {
- // Ranges overlap
- currentRange.end = nextRange.end;
- } else {
- simplifiedRanges.push(currentRange);
- currentRange = nextRange;
- }
- }
- simplifiedRanges.push(currentRange);
-
- // Add tokens to the source code, from the end to the start to avoid messing up the indices
- for (let i = simplifiedRanges.length - 1; i >= 0; i--) {
- const range = simplifiedRanges[i];
-
- source[range.end.line] = [
- source[range.end.line].slice(0, range.end.cursorOffset),
- HljsUnderlinePlugin.TOKEN_END,
- source[range.end.line].slice(range.end.cursorOffset),
- ].join('');
-
- // If there are lines between the start and end, we re-tokenize each line
- if (range.end.line !== range.start.line) {
- source[range.end.line] = HljsUnderlinePlugin.TOKEN_START + source[range.end.line];
- for (let j = range.end.line - 1; j > range.start.line; j--) {
- source[j] = [
- HljsUnderlinePlugin.TOKEN_START,
- source[j],
- HljsUnderlinePlugin.TOKEN_END,
- ].join('');
- }
- source[range.start.line] += HljsUnderlinePlugin.TOKEN_END;
- }
-
- source[range.start.line] = [
- source[range.start.line].slice(0, range.start.cursorOffset),
- HljsUnderlinePlugin.TOKEN_START,
- source[range.start.line].slice(range.start.cursorOffset),
- ].join('');
- }
-
- return source;
- }
-
- /**
- * Replace the tokens with the appropriate HTML markup to underline the content.
- * Tokens were added using the tokenize() method.
- */
- 'after:highlight'(result: HighlightResult) {
- const re = new RegExp(HljsUnderlinePlugin.TOKEN_START, 'g');
- re.lastIndex = 0;
- let match = re.exec(result.value);
- while (match) {
- result.value = this.replaceTokens(result.value, match.index);
- match = re.exec(result.value);
- }
- }
-
- /**
- * Whether the content is intersecting with HTML <span> tags added by HLJS or this plugin.
- */
- isIntersectingHtmlMarkup(content: string) {
- const re = new RegExp(HljsUnderlinePlugin.SPAN_REGEX, 'g');
- let depth = 0;
- let intersecting = false;
- let tag = re.exec(content);
- while (tag) {
- if (tag[0].startsWith('</')) {
- depth--;
- } else {
- depth++;
- }
-
- // If at any point we're closing one-too-many tag, we're intersecting
- if (depth < 0) {
- intersecting = true;
- break;
- }
-
- tag = re.exec(content);
- }
-
- // If at the end we're not at 0, we're intersecting
- intersecting = intersecting || depth !== 0;
-
- return intersecting;
- }
-
- /**
- * Replace a pair of tokens and everything between with the appropriate HTML markup to underline the content.
- */
- private replaceTokens(htmlMarkup: string, startTokenIndex: number) {
- const endTagIndex = htmlMarkup.indexOf(HljsUnderlinePlugin.TOKEN_END);
-
- // Just in case the end tag is before the start tag (or the end tag isn't found)
- if (endTagIndex <= startTokenIndex) {
- return htmlMarkup;
- }
-
- let content = htmlMarkup.slice(
- startTokenIndex + HljsUnderlinePlugin.TOKEN_START.length,
- endTagIndex,
- );
-
- // If intersecting, we highlight in a safe way
- // We could always use this method, but this creates visual artifacts in the underline wave
- if (this.isIntersectingHtmlMarkup(content)) {
- content = content.replace(
- new RegExp(HljsUnderlinePlugin.SPAN_REGEX, 'g'),
- (tag) => `${HljsUnderlinePlugin.CLOSE_TAG}${tag}${HljsUnderlinePlugin.OPEN_TAG}`,
- );
- }
-
- // If no intersection, it's safe to add the tags
- const stringRegex = [
- HljsUnderlinePlugin.TOKEN_START,
- '(.+?)',
- HljsUnderlinePlugin.TOKEN_END,
- ].join('');
- htmlMarkup = htmlMarkup.replace(
- new RegExp(stringRegex, 's'),
- `${HljsUnderlinePlugin.OPEN_TAG}${content}${HljsUnderlinePlugin.CLOSE_TAG}`,
- );
-
- return htmlMarkup;
- }
-}
-
-const hljsUnderlinePlugin = new HljsUnderlinePlugin();
-export { hljsUnderlinePlugin };
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/__tests__/HljsIssueIndicatorPlugin-test.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/__tests__/HljsIssueIndicatorPlugin-test.ts
deleted file mode 100644
index b1c4a34d312..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/__tests__/HljsIssueIndicatorPlugin-test.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { BeforeHighlightContext, HighlightResult } from 'highlight.js';
-import { hljsIssueIndicatorPlugin, HljsIssueIndicatorPlugin } from '../HljsIssueIndicatorPlugin';
-
-describe('HljsIssueIndicatorPlugin', () => {
- it('should prepend to the line the issues that were found', () => {
- expect(
- hljsIssueIndicatorPlugin.addIssuesToLines(['line1', 'line2', 'line3', `line4`, 'line5'], {
- 1: ['123abd', '234asd'],
- }),
- ).toEqual(['line1', '[ISSUE_KEYS:123abd,234asd]line2', 'line3', `line4`, 'line5']);
-
- expect(
- hljsIssueIndicatorPlugin.addIssuesToLines(['line1', 'line2', 'line3', `line4`, 'line5'], {
- 1: ['123abd'],
- }),
- ).toEqual(['line1', '[ISSUE_KEYS:123abd]line2', 'line3', `line4`, 'line5']);
- });
- describe('when tokens exist in the code snippet', () => {
- it('should indicate an issue on a line', () => {
- const inputHtml = {
- code: hljsIssueIndicatorPlugin
- .addIssuesToLines(['line1', 'line2', 'line3', `line4`, 'line5'], { 1: ['123abd'] })
- .join('\n'),
- } as BeforeHighlightContext;
- const result = {
- value: ['line1', `line2`, 'line3', `line4`, 'line5'].join('\n'),
- } as HighlightResult;
-
- //find issue keys
- hljsIssueIndicatorPlugin['before:highlight'](inputHtml);
- //add the issue indicator html
- hljsIssueIndicatorPlugin['after:highlight'](result);
-
- expect(result.value).toEqual(
- [
- `${HljsIssueIndicatorPlugin.LINE_WRAPPER_OPEN_TAG}${HljsIssueIndicatorPlugin.EMPTY_INDICATOR_COLUMN}<div>line1</div>${HljsIssueIndicatorPlugin.LINE_WRAPPER_CLOSE_TAG}`,
- `${HljsIssueIndicatorPlugin.LINE_WRAPPER_OPEN_TAG}<div id="issue-key-123abd"></div><div>line2</div>${HljsIssueIndicatorPlugin.LINE_WRAPPER_CLOSE_TAG}`,
- `${HljsIssueIndicatorPlugin.LINE_WRAPPER_OPEN_TAG}${HljsIssueIndicatorPlugin.EMPTY_INDICATOR_COLUMN}<div>line3</div>${HljsIssueIndicatorPlugin.LINE_WRAPPER_CLOSE_TAG}`,
- `${HljsIssueIndicatorPlugin.LINE_WRAPPER_OPEN_TAG}${HljsIssueIndicatorPlugin.EMPTY_INDICATOR_COLUMN}<div>line4</div>${HljsIssueIndicatorPlugin.LINE_WRAPPER_CLOSE_TAG}`,
- `${HljsIssueIndicatorPlugin.LINE_WRAPPER_OPEN_TAG}${HljsIssueIndicatorPlugin.EMPTY_INDICATOR_COLUMN}<div>line5</div>${HljsIssueIndicatorPlugin.LINE_WRAPPER_CLOSE_TAG}`,
- ].join('\n'),
- );
- });
-
- it('should support multiple issues found on one line', () => {
- const inputHtml = {
- code: hljsIssueIndicatorPlugin
- .addIssuesToLines(['line1', 'line2 issue2', 'line3', `line4`, 'line5'], {
- 1: ['123abd', '234asd'],
- })
- .join('\n'),
- } as BeforeHighlightContext;
- const result = {
- value: ['line1', `line2 issue2`, 'line3', `line4`, 'line5'].join('\n'),
- } as HighlightResult;
-
- //find issue keys
- hljsIssueIndicatorPlugin['before:highlight'](inputHtml);
- //add the issue indicator html
- hljsIssueIndicatorPlugin['after:highlight'](result);
-
- expect(result.value).toEqual(
- [
- `${HljsIssueIndicatorPlugin.LINE_WRAPPER_OPEN_TAG}${HljsIssueIndicatorPlugin.EMPTY_INDICATOR_COLUMN}<div>line1</div>${HljsIssueIndicatorPlugin.LINE_WRAPPER_CLOSE_TAG}`,
- `${HljsIssueIndicatorPlugin.LINE_WRAPPER_OPEN_TAG}<div id="issue-key-123abd"></div><div>line2 issue2</div>${HljsIssueIndicatorPlugin.LINE_WRAPPER_CLOSE_TAG}`,
- `${HljsIssueIndicatorPlugin.LINE_WRAPPER_OPEN_TAG}${HljsIssueIndicatorPlugin.EMPTY_INDICATOR_COLUMN}<div>line3</div>${HljsIssueIndicatorPlugin.LINE_WRAPPER_CLOSE_TAG}`,
- `${HljsIssueIndicatorPlugin.LINE_WRAPPER_OPEN_TAG}${HljsIssueIndicatorPlugin.EMPTY_INDICATOR_COLUMN}<div>line4</div>${HljsIssueIndicatorPlugin.LINE_WRAPPER_CLOSE_TAG}`,
- `${HljsIssueIndicatorPlugin.LINE_WRAPPER_OPEN_TAG}${HljsIssueIndicatorPlugin.EMPTY_INDICATOR_COLUMN}<div>line5</div>${HljsIssueIndicatorPlugin.LINE_WRAPPER_CLOSE_TAG}`,
- ].join('\n'),
- );
- });
-
- it('should not render anything if no source code is passed', () => {
- const inputHtml = {
- code: '',
- } as BeforeHighlightContext;
- const result = {
- value: '',
- } as HighlightResult;
-
- //find issue keys
- hljsIssueIndicatorPlugin['before:highlight'](inputHtml);
- //add the issue indicator html
- hljsIssueIndicatorPlugin['after:highlight'](result);
-
- expect(result.value).toEqual('');
- });
- });
-
- describe('when no tokens exist in the code snippet', () => {
- it('should not change the source', () => {
- const inputHtml = {
- code: ['line1', `line2`, 'line3', `line4`, 'line5'].join('\n'),
- } as BeforeHighlightContext;
- const result = {
- value: ['line1', `line2`, 'line3', `line4`, 'line5'].join('\n'),
- } as HighlightResult;
-
- //find issue keys
- hljsIssueIndicatorPlugin['before:highlight'](inputHtml);
- //add the issue indicator html
- hljsIssueIndicatorPlugin['after:highlight'](result);
-
- expect(result.value).toEqual(['line1', 'line2', 'line3', 'line4', 'line5'].join('\n'));
- });
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/__tests__/HljsUnderlinePlugin-test.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/__tests__/HljsUnderlinePlugin-test.ts
deleted file mode 100644
index aba15bdea86..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/__tests__/HljsUnderlinePlugin-test.ts
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { HighlightResult } from 'highlight.js';
-import { HljsUnderlinePlugin, hljsUnderlinePlugin } from '../HljsUnderlinePlugin';
-
-const START_TOKEN = HljsUnderlinePlugin.TOKEN_START;
-const END_TOKEN = HljsUnderlinePlugin.TOKEN_END;
-
-describe('should add tokens', () => {
- it('with multiple overlapping ranges', () => {
- expect(
- hljsUnderlinePlugin.tokenize(
- ['line1', 'line2', 'line3', 'line4', 'line5'],
- [
- {
- start: { line: 1, cursorOffset: 2 },
- end: { line: 2, cursorOffset: 2 },
- },
- {
- start: { line: 3, cursorOffset: 2 },
- end: { line: 3, cursorOffset: 4 },
- },
- {
- start: { line: 1, cursorOffset: 1 },
- end: { line: 1, cursorOffset: 3 },
- },
- ],
- ),
- ).toEqual([
- 'line1',
- `l${START_TOKEN}ine2${END_TOKEN}`,
- `${START_TOKEN}li${END_TOKEN}ne3`,
- `li${START_TOKEN}ne${END_TOKEN}4`,
- 'line5',
- ]);
- });
-
- it('highlight multiple issues on the same line', () => {
- expect(
- hljsUnderlinePlugin.tokenize(
- ['line1', 'line2', 'line3', 'line4', 'line5'],
- [
- {
- start: { line: 1, cursorOffset: 1 },
- end: { line: 1, cursorOffset: 2 },
- },
- {
- start: { line: 1, cursorOffset: 3 },
- end: { line: 1, cursorOffset: 4 },
- },
- ],
- ),
- ).toEqual([
- 'line1',
- `l${START_TOKEN}i${END_TOKEN}n${START_TOKEN}e${END_TOKEN}2`,
- 'line3',
- 'line4',
- 'line5',
- ]);
- });
-
- it('highlight multiple successive lines', () => {
- expect(
- hljsUnderlinePlugin.tokenize(
- ['line1', 'line2', 'line3', 'line4', 'line5'],
- [
- {
- start: { line: 1, cursorOffset: 2 },
- end: { line: 4, cursorOffset: 4 },
- },
- ],
- ),
- ).toEqual([
- 'line1',
- `li${START_TOKEN}ne2${END_TOKEN}`,
- `${START_TOKEN}line3${END_TOKEN}`,
- `${START_TOKEN}line4${END_TOKEN}`,
- `${START_TOKEN}line${END_TOKEN}5`,
- ]);
- });
-});
-
-describe('should detect html markup intersection', () => {
- it.each([
- '... <span a="b"> ....',
- '... </span> ...',
- '<span> ...',
- '... </span>',
- '... </span> ... <span a="b"> ...',
- '... <span><span a="b"> ... </span> ...',
- '... <span> ... <span a="b"> ... </span> ... </span> ... </span> ...',
- ])('should detect intersection (%s)', (code) => {
- expect(hljsUnderlinePlugin.isIntersectingHtmlMarkup(code)).toBe(true);
- });
-
- it.each([
- '... <span a="b"> ... </span> ...',
- '<span> ... </span> ... <span> ... <span class="abc"><span> ... </span></span> ... </span>',
- ])('should not detect intersection (%s)', (code) => {
- expect(hljsUnderlinePlugin.isIntersectingHtmlMarkup(code)).toBe(false);
- });
-});
-
-describe('underline plugin should work', () => {
- it('should underline on different lines', () => {
- const result = {
- value: ['line1', `l${START_TOKEN}ine2`, 'line3', `lin${END_TOKEN}e4`, 'line5'].join('\n'),
- } as HighlightResult;
-
- hljsUnderlinePlugin['after:highlight'](result);
-
- expect(result.value).toEqual(
- [
- 'line1',
- `l${HljsUnderlinePlugin.OPEN_TAG}ine2`,
- 'line3',
- `lin${HljsUnderlinePlugin.CLOSE_TAG}e4`,
- 'line5',
- ].join('\n'),
- );
- });
-
- it('should underline on same lines', () => {
- const result = {
- value: ['line1', `l${START_TOKEN}ine${END_TOKEN}2`, 'line3'].join('\n'),
- } as HighlightResult;
-
- hljsUnderlinePlugin['after:highlight'](result);
-
- expect(result.value).toEqual(
- [
- 'line1',
- `l${HljsUnderlinePlugin.OPEN_TAG}ine${HljsUnderlinePlugin.CLOSE_TAG}2`,
- 'line3',
- ].join('\n'),
- );
- });
-
- it('should not underline if end tag is before start tag', () => {
- const result = {
- value: ['line1', `l${END_TOKEN}ine${START_TOKEN}2`, 'line3'].join('\n'),
- } as HighlightResult;
-
- hljsUnderlinePlugin['after:highlight'](result);
-
- expect(result.value).toEqual(['line1', `l${END_TOKEN}ine${START_TOKEN}2`, 'line3'].join('\n'));
- });
-
- it('should not underline if there is no end tag', () => {
- const result = {
- value: ['line1', `l${START_TOKEN}ine2`, 'line3'].join('\n'),
- } as HighlightResult;
-
- hljsUnderlinePlugin['after:highlight'](result);
-
- expect(result.value).toEqual(['line1', `l${START_TOKEN}ine2`, 'line3'].join('\n'));
- });
-
- it('should underline even when intersecting html markup', () => {
- const result = {
- value: `.. <span class="hljs-keyword"> .${START_TOKEN}. <span class="hljs-keyword"> .. </span> .. </span> .. ${END_TOKEN} ..`,
- } as HighlightResult;
-
- hljsUnderlinePlugin['after:highlight'](result);
-
- expect(result.value).toEqual(
- `.. <span class="hljs-keyword"> .${HljsUnderlinePlugin.OPEN_TAG}. ${HljsUnderlinePlugin.CLOSE_TAG}<span class="hljs-keyword">${HljsUnderlinePlugin.OPEN_TAG} .. ${HljsUnderlinePlugin.CLOSE_TAG}</span>${HljsUnderlinePlugin.OPEN_TAG} .. ${HljsUnderlinePlugin.CLOSE_TAG}</span>${HljsUnderlinePlugin.OPEN_TAG} .. ${HljsUnderlinePlugin.CLOSE_TAG} ..`,
- );
- });
-});
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/index.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/index.ts
deleted file mode 100644
index a0279b93e76..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/hljs/index.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export { hljsIssueIndicatorPlugin } from './HljsIssueIndicatorPlugin';
-export { hljsUnderlinePlugin } from './HljsUnderlinePlugin';
-export type { UnderlineRangePosition } from './HljsUnderlinePlugin';
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/index.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/index.ts
deleted file mode 100644
index 2a116ed0d06..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/index.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './components';
-export * from './helpers';
-export * from './hljs';
-export * from './types';
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/types/index.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/types/index.ts
deleted file mode 100644
index 076ba52f860..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/types/index.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './measures';
diff --git a/server/sonar-web/src/main/js/design-system/sonar-aligned/types/measures.ts b/server/sonar-web/src/main/js/design-system/sonar-aligned/types/measures.ts
deleted file mode 100644
index b7e402a65f7..00000000000
--- a/server/sonar-web/src/main/js/design-system/sonar-aligned/types/measures.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum RatingEnum {
- A = 'A',
- B = 'B',
- C = 'C',
- D = 'D',
- E = 'E',
-}
-
-export type RatingLabel = keyof typeof RatingEnum;
diff --git a/server/sonar-web/src/main/js/design-system/theme/colors.ts b/server/sonar-web/src/main/js/design-system/theme/colors.ts
deleted file mode 100644
index faf51585884..00000000000
--- a/server/sonar-web/src/main/js/design-system/theme/colors.ts
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export default {
- white: [255, 255, 255],
- black: [0, 0, 0],
- sonarcloud: [243, 112, 42],
- grey: { 50: [235, 235, 235], 100: [221, 221, 221] },
- blueGrey: {
- 25: [252, 252, 253],
- 35: [247, 249, 252],
- 50: [239, 242, 249],
- 100: [225, 230, 243],
- 200: [197, 205, 223],
- 300: [166, 173, 194],
- 400: [106, 117, 144],
- 500: [62, 67, 87],
- 600: [42, 47, 64],
- 700: [29, 33, 47],
- 800: [18, 20, 29],
- 900: [8, 9, 12],
- },
- indigo: {
- 25: [244, 246, 255],
- 50: [232, 235, 255],
- 100: [209, 215, 254],
- 200: [189, 198, 255],
- 300: [159, 169, 237],
- 400: [123, 135, 217],
- 500: [93, 108, 208],
- 600: [75, 86, 187],
- 700: [71, 81, 143],
- 800: [43, 51, 104],
- 900: [27, 34, 80],
- },
- tangerine: {
- 25: [255, 248, 244],
- 50: [250, 230, 220],
- 100: [246, 206, 187],
- 200: [243, 185, 157],
- 300: [240, 166, 130],
- 400: [237, 148, 106],
- 500: [235, 131, 82],
- 600: [233, 116, 63],
- 700: [231, 102, 49],
- 800: [181, 68, 25],
- 900: [130, 43, 10],
- },
- green: {
- 50: [246, 254, 249],
- 100: [236, 253, 243],
- 200: [209, 250, 223],
- 300: [166, 244, 197],
- 400: [50, 213, 131],
- 500: [18, 183, 106],
- 600: [3, 152, 85],
- 700: [2, 122, 72],
- 800: [5, 96, 58],
- 900: [5, 79, 49],
- },
- yellowGreen: {
- 50: [247, 251, 230],
- 100: [241, 250, 210],
- 200: [225, 245, 168],
- 300: [197, 230, 124],
- 400: [166, 208, 91],
- 500: [110, 183, 18],
- 600: [104, 154, 48],
- 700: [83, 128, 39],
- 800: [63, 104, 29],
- 900: [49, 85, 22],
- },
- yellow: {
- 50: [252, 245, 228],
- 100: [254, 245, 208],
- 200: [252, 233, 163],
- 300: [250, 220, 121],
- 400: [248, 205, 92],
- 500: [245, 184, 64],
- 600: [209, 152, 52],
- 700: [174, 122, 41],
- 800: [140, 94, 30],
- 900: [102, 64, 15],
- },
- orange: {
- 50: [255, 240, 235],
- 100: [254, 219, 199],
- 200: [255, 214, 175],
- 300: [254, 150, 75],
- 400: [253, 113, 34],
- 500: [247, 95, 9],
- 600: [220, 94, 3],
- 700: [181, 71, 8],
- 800: [147, 55, 13],
- 900: [122, 46, 14],
- },
- red: {
- 50: [254, 243, 242],
- 100: [254, 228, 226],
- 200: [254, 205, 202],
- 300: [253, 162, 155],
- 400: [249, 112, 102],
- 500: [240, 68, 56],
- 600: [217, 45, 32],
- 700: [180, 35, 24],
- 800: [128, 27, 20],
- 900: [93, 29, 19],
- },
- blue: {
- 50: [245, 251, 255],
- 100: [233, 244, 251],
- 200: [184, 222, 241],
- 300: [143, 202, 234],
- 400: [110, 185, 228],
- 500: [85, 170, 223],
- 600: [69, 149, 203],
- 700: [58, 127, 173],
- 800: [49, 108, 146],
- 900: [23, 67, 97],
- },
- codeSnippetLight: {
- body: [51, 53, 60],
- annotations: [34, 84, 192],
- constants: [126, 83, 5],
- comments: [109, 111, 119],
- keyword: [152, 29, 150],
- string: [32, 105, 31],
- 'keyword-light': [28, 28, 163], // Not used currently in code snippet
- 'preprocessing-directive': [47, 103, 48],
- },
- codeSnippetDark: {
- body: [241, 245, 253],
- annotations: [137, 214, 255],
- constants: [237, 182, 130],
- comments: [156, 164, 175],
- keyword: [251, 173, 255],
- string: [177, 220, 146],
- 'keyword-light': [185, 185, 255], // Not used currently in code snippet
- 'preprocessing-directive': [133, 228, 134],
- },
- codeSyntaxLight: {
- body: [56, 58, 66],
- annotations: [35, 91, 213],
- constants: [135, 87, 2],
- comments: [95, 96, 102],
- keyword: [162, 34, 160],
- string: [36, 117, 35],
- 'keyword-light': [30, 30, 173],
- 'preprocessing-directive': [52, 114, 53],
- },
- codeSyntaxDark: {
- body: [226, 231, 241],
- annotations: [97, 174, 238],
- constants: [209, 154, 102],
- comments: [167, 172, 180],
- keyword: [223, 145, 246],
- string: [152, 195, 121],
- 'keyword-light': [171, 171, 255],
- 'preprocessing-directive': [120, 215, 121],
- },
-};
diff --git a/server/sonar-web/src/main/js/design-system/theme/index.ts b/server/sonar-web/src/main/js/design-system/theme/index.ts
deleted file mode 100644
index ddd0b10c444..00000000000
--- a/server/sonar-web/src/main/js/design-system/theme/index.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './light';
-export * from './withTheme';
diff --git a/server/sonar-web/src/main/js/design-system/theme/light.ts b/server/sonar-web/src/main/js/design-system/theme/light.ts
deleted file mode 100644
index f9c0aaa006f..00000000000
--- a/server/sonar-web/src/main/js/design-system/theme/light.ts
+++ /dev/null
@@ -1,1003 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { OPACITY_20_PERCENT, OPACITY_75_PERCENT } from '../helpers/constants';
-import COLORS from './colors';
-
-const primary = {
- light: COLORS.indigo[400],
- default: COLORS.indigo[500],
- dark: COLORS.indigo[600],
-};
-
-const secondary = {
- light: COLORS.blueGrey[50],
- default: COLORS.blueGrey[200],
- dark: COLORS.blueGrey[400],
- darker: COLORS.blueGrey[500],
-};
-
-const danger = {
- lightest: COLORS.red[50],
- lighter: COLORS.red[300],
- light: COLORS.red[400],
- default: COLORS.red[600],
- dark: COLORS.red[700],
- darker: COLORS.red[800],
-};
-
-const codeSnippetLight = {
- annotations: [34, 84, 192],
- body: [51, 53, 60],
- constants: [126, 83, 5],
- comments: [109, 111, 119],
- keyword: [152, 29, 150],
- string: [32, 105, 31],
- 'keyword-light': [28, 28, 163], // Not used currently in code snippet
- 'preprocessing-directive': [47, 103, 48],
-};
-
-export const lightTheme = {
- id: 'light-theme',
- highlightTheme: 'atom-one-light.css',
- logo: 'sonarcloud-logo-black.svg',
-
- colors: {
- transparent: 'transparent',
- currentColor: 'currentColor',
-
- backgroundPrimary: COLORS.blueGrey[25],
- backgroundSecondary: COLORS.white,
- border: COLORS.grey[50],
- sonarcloud: COLORS.sonarcloud,
-
- // primary
- primaryLight: primary.light,
- primary: primary.default,
- primaryDark: primary.dark,
-
- // danger
- danger: danger.dark,
-
- // text
- textSuccess: COLORS.yellowGreen[700],
-
- //Project list card
- projectCardDisabled: COLORS.blueGrey[200],
-
- // buttons
- button: primary.default,
- buttonHover: primary.dark,
- buttonSecondary: COLORS.white,
- buttonSecondaryBorder: secondary.default,
- buttonSecondaryHover: secondary.light,
- buttonDisabled: secondary.light,
- buttonDisabledBorder: secondary.default,
-
- // danger buttons
- dangerButton: danger.default,
- dangerButtonHover: danger.dark,
- dangerButtonFocus: danger.default,
- dangerButtonSecondary: COLORS.white,
- dangerButtonSecondaryBorder: danger.lighter,
- dangerButtonSecondaryHover: danger.lightest,
- dangerButtonSecondaryFocus: danger.light,
-
- // third party button
- thirdPartyButton: COLORS.white,
- thirdPartyButtonBorder: secondary.default,
- thirdPartyButtonHover: secondary.light,
-
- // popup
- popup: COLORS.white,
- popupBorder: secondary.default,
-
- // Toasts
- toast: COLORS.white,
- toastText: secondary.darker,
-
- toastErrorBorder: danger.light,
- toastErrorIconBackground: danger.lightest,
-
- toastWarningBorder: COLORS.yellow[400],
- toastWarningIconBackground: COLORS.yellow[50],
-
- toastSuccessBorder: COLORS.yellowGreen[400],
- toastSuccessIconBackground: COLORS.yellowGreen[50],
-
- toastInfoBorder: COLORS.blue[400],
- toastInfoIconBackground: COLORS.blue[50],
-
- // spotlight
- spotlightPulseBackground: primary.default,
- spotlightBackgroundColor: COLORS.blueGrey[50],
-
- // modal
- modalContents: COLORS.white,
- modalOverlay: [...COLORS.blueGrey[900], OPACITY_75_PERCENT],
-
- // dropdown menu
- dropdownMenu: COLORS.white,
- dropdownMenuHover: secondary.light,
- dropdownMenuFocus: COLORS.indigo[50],
- dropdownMenuFocusBorder: primary.light,
- dropdownMenuDisabled: COLORS.white,
- dropdownMenuHeader: COLORS.white,
- dropdownMenuDanger: danger.default,
-
- // radio
- radio: primary.default,
- radioBorder: primary.default,
- radioHover: COLORS.indigo[50],
- radioFocus: COLORS.indigo[50],
- radioFocusBorder: COLORS.indigo[300],
- radioFocusOutline: [...COLORS.indigo[300], OPACITY_20_PERCENT],
- radioChecked: COLORS.indigo[50],
- radioDisabled: secondary.default,
- radioDisabledBackground: secondary.light,
- radioDisabledBorder: secondary.default,
-
- // switch
- switch: secondary.default,
- switchDisabled: COLORS.blueGrey[100],
- switchActive: primary.default,
- switchHover: COLORS.blueGrey[300],
- switchHoverActive: primary.light,
- switchButton: COLORS.white,
- switchButtonDisabled: secondary.light,
-
- // sidebar
- // NOTE: these aren't used because the sidebar is exclusively dark. but for type purposes are listed here
- sidebarBackground: COLORS.blueGrey[700],
- sidebarItemActive: COLORS.blueGrey[800],
- sidebarBorder: COLORS.blueGrey[500],
- sidebarActiveIcon: COLORS.blueGrey[200],
-
- //separator-circle
- separatorCircle: COLORS.blueGrey[200],
-
- // rule breakdown table
- breakdownBorder: COLORS.grey[100],
- breakdownHeaderBackground: COLORS.blueGrey[50],
-
- // flag message
- flagMessageBackground: COLORS.white,
- flagMessageFocusBackground: COLORS.indigo[600],
- flagMessageText: COLORS.blueGrey[500],
-
- errorBorder: danger.light,
- errorBackground: danger.lightest,
- errorIconBackground: danger.lightest,
- errorText: danger.dark,
- errorIcon: COLORS.red[600],
- errorIconHover: COLORS.red[800],
- errorIconHoverBackground: COLORS.red[100],
- errorIconFocusBackground: COLORS.red[50],
-
- warningBorder: COLORS.yellow[400],
- warningBackground: COLORS.yellow[50],
- warningIconBackground: COLORS.yellow[50],
- warningText: COLORS.yellow[900],
- warningIcon: COLORS.yellow[700],
- warningIconHover: COLORS.yellow[800],
- warningIconHoverBackground: COLORS.yellow[100],
- warningIconFocusBackground: COLORS.yellow[50],
-
- successBorder: COLORS.yellowGreen[400],
- successBackground: COLORS.green[50],
- successIconBackground: COLORS.yellowGreen[50],
- successText: COLORS.green[900],
- successIcon: COLORS.yellowGreen[600],
- successIconHover: COLORS.yellowGreen[800],
- successIconHoverBackground: COLORS.yellowGreen[100],
- successIconFocusBackground: COLORS.yellowGreen[50],
-
- infoBorder: COLORS.blue[300],
- infoBackground: COLORS.blue[50],
- infoIconBackground: COLORS.blue[50],
- infoContrast: COLORS.blue[900],
- infoText: COLORS.blue[900],
- infoIcon: COLORS.blue[600],
- infoIconHover: COLORS.blue[800],
- infoIconHoverBackground: COLORS.blue[100],
- infoIconFocusBackground: COLORS.blue[50],
-
- recommendedBorder: COLORS.indigo[500],
- recommendedBackground: COLORS.indigo[50],
- recommendedIcon: COLORS.indigo[500],
- recommendedIconHover: COLORS.indigo[800],
- recommendedIconHoverBackground: COLORS.indigo[50],
- recommendedIconFocusBackground: COLORS.indigo[50],
-
- // banner message
- bannerMessage: danger.lightest,
- bannerMessageIcon: danger.darker,
-
- // toggle buttons
- toggle: COLORS.white,
- toggleBorder: secondary.default,
- toggleHover: secondary.light,
- toggleFocus: [...secondary.default, OPACITY_20_PERCENT],
-
- // code snippet
- codeSnippetBackground: COLORS.blueGrey[25],
- codeSnippetBorder: COLORS.blueGrey[100],
- codeSnippetHighlight: secondary.default,
- codeSnippetBody: codeSnippetLight.body,
- codeSnippetAnnotations: codeSnippetLight.annotations,
- codeSnippetComments: codeSnippetLight.comments,
- codeSnippetConstants: codeSnippetLight.constants,
- codeSnippetKeyword: codeSnippetLight.keyword,
- codeSnippetString: codeSnippetLight.string,
- codeSnippetKeywordLight: codeSnippetLight['keyword-light'],
- codeSnippetPreprocessingDirective: codeSnippetLight['preprocessing-directive'],
- codeSnippetInline: COLORS.blueGrey[500],
-
- // code viewer
- codeLine: COLORS.white,
- codeLineBorder: COLORS.grey[100],
- codeLineLocationMarker: COLORS.red[200],
- codeLineLocationMarkerSelected: danger.lighter,
- codeLineLocationSelected: COLORS.blueGrey[100],
- codeLineCoveredUnderline: [...COLORS.green[500], 0.15],
- codeLineUncoveredUnderline: [...COLORS.red[500], 0.15],
-
- codeLineHover: secondary.light,
- codeLineHighlighted: COLORS.blueGrey[100],
- codeLineNewCodeUnderline: [...COLORS.indigo[300], 0.15],
- codeLineDuplication: secondary.default,
- codeLineCovered: COLORS.green[300],
- codeLineUncovered: danger.default,
- codeLinePartiallyCoveredA: danger.default,
- codeLinePartiallyCoveredB: COLORS.white,
- codeLineIssueSquiggle: danger.lighter,
- codeLineIssuePointerBorder: COLORS.white,
- codeLineLocationHighlighted: [...COLORS.blueGrey[200], 0.6],
- codeLineEllipsis: COLORS.white,
- codeLineEllipsisHover: secondary.light,
- codeLineIssueLocation: [...danger.lighter, 0.15],
- codeLineIssueLocationSelected: [...danger.lighter, 0.5],
- codeLineIssueMessageTooltip: secondary.darker,
-
- // code syntax highlight
- codeSyntaxBody: COLORS.codeSyntaxLight.body,
- codeSyntaxAnnotations: COLORS.codeSyntaxLight.annotations,
- codeSyntaxConstants: COLORS.codeSyntaxLight.constants,
- codeSyntaxComments: COLORS.codeSyntaxLight.comments,
- codeSyntaxKeyword: COLORS.codeSyntaxLight.keyword,
- codeSyntaxString: COLORS.codeSyntaxLight.string,
- codeSyntaxKeywordLight: COLORS.codeSyntaxLight['keyword-light'],
- codeSyntaxPreprocessingDirective: COLORS.codeSyntaxLight['preprocessing-directive'],
-
- // checkbox
- checkboxHover: COLORS.indigo[50],
- checkboxCheckedHover: primary.light,
- checkboxDisabled: secondary.light,
- checkboxDisabledChecked: secondary.default,
- checkboxLabel: COLORS.blueGrey[500],
-
- // input search
- searchHighlight: COLORS.tangerine[50],
-
- // input field
- inputBackground: COLORS.white,
- inputBorder: secondary.default,
- inputFocus: primary.light,
- inputDanger: danger.default,
- inputDangerFocus: danger.light,
- inputSuccess: COLORS.yellowGreen[500],
- inputSuccessFocus: COLORS.yellowGreen[400],
- inputDisabled: secondary.light,
- inputDisabledBorder: secondary.default,
-
- // required input
- inputRequired: danger.dark,
-
- // tooltip
- tooltipBackground: COLORS.blueGrey[600],
- tooltipHighlight: secondary.default,
-
- // avatar
- avatarBackground: COLORS.white,
- avatarBorder: COLORS.blueGrey[100],
-
- // badges
- badgeNew: COLORS.indigo[100],
- badgeDefault: COLORS.blueGrey[100],
- badgeDeleted: COLORS.red[100],
- badgeCounter: COLORS.blueGrey[100],
- badgeCounterFailed: COLORS.red[50],
- badgeCounterFailedBorder: COLORS.red[200],
-
- // pills
- pillCritical: COLORS.red[100],
- pillCriticalBorder: COLORS.red[800],
- pillCriticalHover: COLORS.red[300],
- pillDanger: COLORS.red[50],
- pillDangerBorder: COLORS.red[600],
- pillDangerHover: COLORS.red[200],
- pillWarning: COLORS.orange[50],
- pillWarningBorder: COLORS.orange[300],
- pillWarningHover: COLORS.orange[200],
- pillCaution: COLORS.yellow[50],
- pillCautionBorder: COLORS.yellow[300],
- pillCautionHover: COLORS.yellow[200],
- pillInfo: COLORS.blue[50],
- pillInfoBorder: COLORS.blue[300],
- pillInfoHover: COLORS.blue[200],
- pillAccent: COLORS.indigo[50],
- pillAccentBorder: 'transparent',
- pillAccentHover: COLORS.indigo[100],
- pillSuccess: COLORS.green[100],
- pillSuccessBorder: COLORS.green[600],
- pillSuccessHover: COLORS.green[200],
- pillNeutral: COLORS.blueGrey[50],
- pillNeutralBorder: COLORS.blueGrey[400],
- pillNeutralHover: COLORS.blueGrey[100],
-
- // input select
- selectOptionSelected: secondary.light,
-
- // breadcrumbs
- breadcrumb: 'transparent',
-
- // tab
- tabBorder: primary.light,
-
- // tabs
- tabSelected: primary.default,
- tabHover: COLORS.blueGrey[50],
-
- //table
- tableRowHover: COLORS.indigo[25],
- tableRowSelected: COLORS.indigo[300],
-
- // links
- linkDefault: primary.default,
- linkNaked: COLORS.blueGrey[700],
- linkActive: COLORS.indigo[600],
- linkDiscreet: 'currentColor',
- linkTooltipDefault: COLORS.indigo[200],
- linkTooltipActive: COLORS.indigo[100],
- linkBorder: COLORS.indigo[300],
- linkExternalIcon: COLORS.indigo[300],
- linkExternalIconActive: COLORS.indigo[400],
- contentLinkBorder: COLORS.blueGrey[200],
-
- // discreet select
- discreetBorder: secondary.default,
- discreetBackground: COLORS.white,
- discreetHover: secondary.light,
- discreetButtonHover: COLORS.indigo[500],
- discreetFocus: COLORS.indigo[50],
- discreetFocusBorder: primary.light,
-
- // interactive icon
- interactiveIcon: 'transparent',
- interactiveIconHover: COLORS.indigo[50],
- interactiveIconFocus: primary.default,
- bannerIcon: 'transparent',
- bannerIconHover: [...COLORS.red[600], OPACITY_20_PERCENT],
- bannerIconFocus: danger.default,
- destructiveIcon: 'transparent',
- destructiveIconHover: danger.lightest,
- destructiveIconFocus: danger.default,
-
- // icons
- iconSoftwareImpactSeverityBlocker: COLORS.red[800],
- iconSoftwareImpactSeverityHigh: COLORS.red[600],
- iconSoftwareImpactSeverityMedium: COLORS.orange[400],
- iconSoftwareImpactSeverityLow: COLORS.yellow[500],
- iconSoftwareImpactSeverityInfo: COLORS.blue[600],
- iconSeverityMajor: danger.light,
- iconSeverityMinor: COLORS.yellowGreen[400],
- iconSeverityInfo: COLORS.blue[400],
- iconDirectory: COLORS.orange[300],
- iconFavorite: COLORS.tangerine[400],
- iconCheck: COLORS.green[500],
- iconPositiveUpdate: COLORS.green[300],
- iconNegativeUpdate: COLORS.red[300],
- iconTrendPositive: COLORS.green[400],
- iconTrendNegative: COLORS.red[400],
- iconTrendNeutral: COLORS.blue[600],
- iconError: danger.default,
- iconWarning: COLORS.yellow[600],
- iconSuccess: COLORS.green[600],
- iconInfo: COLORS.blue[600],
- iconStatus: COLORS.blueGrey[200],
- iconNotificationsOn: COLORS.indigo[300],
- iconHelperHint: COLORS.blueGrey[100],
- iconRuleInheritanceOverride: danger.light,
-
- // numbered list
- numberedList: COLORS.indigo[50],
- numberedListText: COLORS.indigo[800],
-
- // unordered list
- listMarker: COLORS.blueGrey[300],
-
- // product news
- productNews: COLORS.indigo[50],
- productNewsHover: COLORS.indigo[100],
-
- // scrollbar
- scrollbar: COLORS.blueGrey[25],
-
- // resizer
- resizer: secondary.default,
-
- // coverage indicators
- coverageGreen: COLORS.green[500],
- coverageRed: danger.dark,
-
- // duplications indicators
- 'duplicationsIndicator.A': COLORS.green[500],
- 'duplicationsIndicator.B': COLORS.green[500],
- 'duplicationsIndicator.C': COLORS.yellowGreen[500],
- 'duplicationsIndicator.D': COLORS.yellow[500],
- 'duplicationsIndicator.E': COLORS.orange[500],
- 'duplicationsIndicator.F': COLORS.red[500],
- duplicationsIndicatorSecondary: secondary.light,
-
- // size indicators
- sizeIndicator: COLORS.blue[500],
-
- // rating colors
- 'rating.A': COLORS.green[200],
- 'rating.B': COLORS.yellowGreen[200],
- 'rating.C': COLORS.yellow[200],
- 'rating.D': COLORS.orange[200],
- 'rating.E': COLORS.red[200],
-
- 'portfolio.rating.A.text': COLORS.green[900],
- 'portfolio.rating.A.background': COLORS.green[100],
- 'portfolio.rating.A.border': COLORS.green[400],
- 'portfolio.rating.B.text': COLORS.yellowGreen[900],
- 'portfolio.rating.B.background': COLORS.yellowGreen[100],
- 'portfolio.rating.B.border': COLORS.yellowGreen[400],
- 'portfolio.rating.C.text': COLORS.yellow[900],
- 'portfolio.rating.C.background': COLORS.yellow[100],
- 'portfolio.rating.C.border': COLORS.yellow[500],
- 'portfolio.rating.D.text': COLORS.orange[900],
- 'portfolio.rating.D.background': COLORS.orange[100],
- 'portfolio.rating.D.border': COLORS.orange[300],
- 'portfolio.rating.E.text': COLORS.red[900],
- 'portfolio.rating.E.background': COLORS.red[100],
- 'portfolio.rating.E.border': COLORS.red[400],
- 'portfolio.rating.NONE.text': COLORS.blueGrey[300],
- 'portfolio.rating.NONE.background': COLORS.blueGrey[50],
- 'portfolio.rating.NONE.border': COLORS.blueGrey[200],
-
- // rating donut outside circle indicators
- 'ratingDonut.A': COLORS.green[400],
- 'ratingDonut.B': COLORS.yellowGreen[400],
- 'ratingDonut.C': COLORS.yellow[400],
- 'ratingDonut.D': COLORS.orange[400],
- 'ratingDonut.E': COLORS.red[400],
-
- // date picker
- datePicker: COLORS.white,
- datePickerIcon: secondary.default,
- datePickerDisabled: COLORS.white,
- datePickerDefault: COLORS.white,
- datePickerHover: COLORS.blueGrey[100],
- datePickerSelected: primary.default,
- datePickerRange: COLORS.indigo[100],
-
- // tags
- tag: secondary.light,
-
- // quality gate indicator
- qgIndicatorPassed: COLORS.green[200],
- qgIndicatorFailed: COLORS.red[200],
- qgIndicatorNotComputed: COLORS.blueGrey[200],
-
- // quality gate status card
- qgCardFailed: COLORS.red[300],
-
- // quality gate texts colors
- qgConditionNotCayc: COLORS.red[600],
- qgConditionCayc: COLORS.green[600],
-
- // main bar
- mainBar: COLORS.white,
- mainBarHover: COLORS.blueGrey[600],
- mainBarLogo: COLORS.white,
- mainBarDarkLogo: COLORS.blueGrey[800],
- mainBarNews: COLORS.indigo[50],
- menuBorder: primary.light,
-
- // navbar
- navbar: COLORS.white,
- navbarTextMeta: secondary.darker,
-
- // filterbar
- filterbar: COLORS.white,
- filterbarBorder: COLORS.blueGrey[100],
-
- // facets
- facetHeader: COLORS.blueGrey[600],
- facetItemSelected: COLORS.indigo[50],
- facetItemSelectedHover: COLORS.indigo[100],
- facetItemSelectedBorder: primary.light,
- facetItemGraph: secondary.default,
- facetKeyboardHint: COLORS.blueGrey[50],
- facetToggleActive: COLORS.green[500],
- facetToggleInactive: COLORS.red[500],
- facetToggleHover: COLORS.blueGrey[600],
-
- // subnavigation sidebar
- subnavigation: COLORS.white,
- subnavigationHover: COLORS.blueGrey[50],
- subnavigationSelected: COLORS.blueGrey[100],
- subnavigationBorder: COLORS.grey[100],
- subnavigationSeparator: COLORS.grey[50],
- subnavigationSubheading: COLORS.blueGrey[25],
- subnavigationExecutionFlow: COLORS.blueGrey[25],
- subnavigationExecutionFlowBorder: secondary.default,
- subnavigationExecutionFlowSeparator: COLORS.blueGrey[100],
- subnavigationExecutionFlowActive: COLORS.indigo[500],
-
- // footer
- footer: COLORS.white,
- footerBorder: COLORS.grey[100],
-
- // project
- projectCardBackground: COLORS.white,
- projectCardBorder: COLORS.blueGrey[100],
- projectCardInfo: COLORS.blueGrey[35],
-
- // overview
- backgroundPromotedSection: secondary.light,
- overviewCardDefaultIcon: secondary.light,
- overviewCardWarningIcon: COLORS.yellow[50],
- overviewCardErrorIcon: COLORS.red[100],
- overviewCardSuccessIcon: COLORS.green[200],
-
- // overview software impact breakdown
- overviewSoftwareImpactSeverityNeutral: COLORS.blueGrey[35],
- overviewSoftwareImpactSeverityHigh: COLORS.red[100],
- overviewSoftwareImpactSeverityMedium: COLORS.yellow[100],
- overviewSoftwareImpactSeverityLow: COLORS.blue[100],
-
- // graph - chart
- graphPointCircleColor: COLORS.white,
- 'graphLineColor.0': COLORS.blue[500],
- 'graphLineColor.1': COLORS.blue[700],
- 'graphLineColor.2': COLORS.blue[300],
- 'graphLineColor.3': COLORS.blue[500],
- 'graphLineColor.4': COLORS.blue[700],
- 'graphLineColor.5': COLORS.blue[300],
- graphGridColor: COLORS.grey[50],
- newCodeHighlight: COLORS.indigo[300],
- graphZoomBackgroundColor: COLORS.blueGrey[25],
- graphZoomBorderColor: COLORS.blueGrey[100],
- graphLegendBorder: secondary.darker,
-
- // page
- pageTitle: COLORS.blueGrey[700],
- pageContent: secondary.darker,
- pageContentDark: COLORS.blueGrey[600],
- pageBlock: COLORS.white,
- pageBlockBorder: COLORS.blueGrey[100],
-
- // core concepts
- coreConceptsTitle: secondary.darker,
- coreConceptsBody: secondary.darker,
- coreConceptsHomeBorder: COLORS.blueGrey[100],
- coreConceptsCompleted: COLORS.green[500],
- coreConceptsPulse: COLORS.indigo[500],
- coreConceptsPulseFallback: COLORS.white,
-
- // progress bar
- coreConceptsProgressBar: secondary.light,
-
- // issue box
- issueBoxSelectedBorder: danger.lighter,
- issueBoxBorder: secondary.default,
- issueBoxBorderDepracated: secondary.default,
- issueTypeIcon: COLORS.red[200],
-
- // separator
- pipeSeparator: COLORS.blueGrey[100],
-
- // drilldown link
- drilldown: secondary.darker,
- drilldownBorder: secondary.default,
-
- // selection card
- selectionCardHeader: secondary.darker,
- selectionCardDisabled: secondary.light,
- selectionCardBorder: COLORS.blueGrey[100],
- selectionCardBorderHover: COLORS.indigo[200],
- selectionCardBorderSelected: primary.light,
- selectionCardBorderDisabled: secondary.default,
-
- // bubble charts
- bubbleChartLine: COLORS.grey[50],
- bubbleDefault: [...COLORS.blue[500], 0.3],
-
- 'bubble.1': [...COLORS.green[500], 0.3],
- 'bubble.2': [...COLORS.yellowGreen[500], 0.3],
- 'bubble.3': [...COLORS.yellow[500], 0.3],
- 'bubble.4': [...COLORS.orange[500], 0.3],
- 'bubble.5': [...COLORS.red[500], 0.3],
-
- // TreeMap Colors
- 'treeMap.A': COLORS.green[500],
- 'treeMap.B': COLORS.yellowGreen[500],
- 'treeMap.C': COLORS.yellow[500],
- 'treeMap.D': COLORS.orange[500],
- 'treeMap.E': COLORS.red[500],
-
- 'treeMap.NA1': COLORS.blueGrey[300],
- 'treeMap.NA2': COLORS.blueGrey[200],
- treeMapCellTextColor: COLORS.blueGrey[900],
-
- // new code legend
- newCodeLegend: [...COLORS.indigo[300], 0.15],
- newCodeLegendBorder: COLORS.indigo[200],
-
- // highlighted section
- highlightedSection: COLORS.blueGrey[25],
- highlightedSectionBorder: COLORS.blueGrey[100],
-
- // highlight ring
- highlightRingBackground: secondary.light,
-
- // activity comments
- activityCommentPipe: COLORS.tangerine[200],
-
- // illustrations
- illustrationInlineBorder: COLORS.blueGrey[100],
- illustrationPrimary: COLORS.indigo[400],
- illustrationSecondary: COLORS.indigo[200],
- illustrationShade: COLORS.indigo[25],
-
- // news bar
- newsBar: COLORS.white,
- newsBorder: COLORS.grey[100],
- newsContent: COLORS.white,
- newsTag: COLORS.blueGrey[50],
- roadmap: COLORS.indigo[25],
- roadmapContent: 'transparent',
-
- // project analyse page
- almCardBorder: COLORS.grey[100],
-
- // Keyboard hint
- keyboardHintKey: COLORS.blueGrey[100],
-
- // progressBar
- progressBarForeground: COLORS.indigo[500],
- progressBarBackground: COLORS.indigo[100],
-
- //education principles
- educationPrincipleBackground: COLORS.indigo[25],
- educationPrincipleBorder: COLORS.indigo[300],
-
- // SonarLint PromotionNotification
- promotionNotification: COLORS.blueGrey[35],
- promotionNotificationBackground: COLORS.blueGrey[700],
- promotionNotificationSeparator: COLORS.blueGrey[500],
-
- // Workspace
- workSpaceViewerBackground: COLORS.blueGrey[25],
- workSpaceViewerShadow: COLORS.blueGrey[700],
- workSpaceNavItem: COLORS.white,
- workSpaceNavItemBackground: COLORS.blueGrey[500],
- },
-
- // contrast colors to be used for text when using a color background with the same name
- // must match the color name
- contrasts: {
- backgroundPrimary: COLORS.blueGrey[900],
- backgroundSecondary: COLORS.blueGrey[900],
- primaryLight: secondary.darker,
- primary: COLORS.white,
-
- // switch
- switchHover: primary.light,
- switchButton: primary.default,
-
- // sidebar
- sidebarBackground: COLORS.blueGrey[200],
- sidebarItemActive: COLORS.blueGrey[25],
-
- // flag message
- flagMessageBackground: secondary.darker,
-
- // info message
- infoBackground: COLORS.blue[900],
-
- // banner message
- bannerMessage: COLORS.red[900],
-
- // buttons
- buttonSecondary: secondary.darker,
-
- // danger buttons
- dangerButton: COLORS.white,
- dangerButtonSecondary: danger.dark,
-
- // third party button
- thirdPartyButton: secondary.darker,
-
- // popup
- popup: secondary.darker,
-
- // dropdown menu
- dropdownMenu: secondary.darker,
-
- // toggle buttons
- toggle: secondary.darker,
- toggleHover: secondary.darker,
-
- // code viewer
- codeLineNewCodeUnderline: COLORS.indigo[500],
- codeLineCoveredUnderline: COLORS.green[700],
- codeLineUncoveredUnderline: COLORS.red[700],
- codeLineLocationMarker: COLORS.red[900],
- codeLineLocationMarkerSelected: COLORS.red[900],
- codeLineIssueMessageTooltip: COLORS.blueGrey[25],
-
- // code snippet
- codeSnippetHighlight: danger.default,
-
- // checkbox
- checkboxDisabled: secondary.default,
-
- // input search
- searchHighlight: secondary.darker,
-
- // input field
- inputBackground: secondary.darker,
-
- // tooltip
- tooltipBackground: secondary.light,
-
- // badges
- badgeNew: COLORS.indigo[900],
- badgeDefault: COLORS.blueGrey[700],
- badgeDeleted: COLORS.red[900],
- badgeCounter: secondary.darker,
- badgeCounterFailed: danger.dark,
-
- // pills
- pillCritical: COLORS.red[800],
- pillDanger: COLORS.red[700],
- pillWarning: COLORS.orange[800],
- pillCaution: COLORS.yellow[800],
- pillInfo: COLORS.blue[800],
- pillAccent: COLORS.indigo[500],
- pillSuccess: COLORS.green[800],
- pillNeutral: COLORS.blueGrey[500],
-
- // project cards
- overviewCardDefaultIcon: COLORS.blueGrey[500],
- overviewCardWarningIcon: COLORS.yellow[700],
- overviewCardErrorIcon: COLORS.red[500],
- overviewCardSuccessIcon: COLORS.green[500],
-
- // discreet select
- discreetBackground: secondary.darker,
- discreetHover: secondary.darker,
-
- // interactive icons
- interactiveIcon: primary.dark,
- interactiveIconHover: COLORS.indigo[800],
- bannerIcon: danger.darker,
- bannerIconHover: danger.darker,
- destructiveIcon: danger.default,
- destructiveIconHover: danger.darker,
-
- // icons
- iconSeverityMajor: COLORS.white,
- iconSeverityMinor: COLORS.white,
- iconSeverityInfo: COLORS.white,
- iconHelperHint: secondary.darker,
- iconHelperHintRaised: COLORS.white,
-
- // numbered list
- numberedList: COLORS.indigo[800],
-
- // product news
- productNews: secondary.darker,
- productNewsHover: secondary.darker,
-
- // scrollbar
- scrollbar: COLORS.grey[100],
-
- // size indicators
- sizeIndicator: COLORS.white,
-
- // rating colors
- 'rating.A': COLORS.green[900],
- 'rating.B': COLORS.yellowGreen[900],
- 'rating.C': COLORS.yellow[900],
- 'rating.D': COLORS.orange[900],
- 'rating.E': COLORS.red[900],
-
- // date picker
- datePicker: COLORS.blueGrey[300],
- datePickerDisabled: COLORS.blueGrey[300],
- datePickerDefault: COLORS.blueGrey[600],
- datePickerHover: COLORS.blueGrey[600],
- datePickerSelected: COLORS.white,
- datePickerRange: COLORS.blueGrey[600],
-
- // tags
- tag: secondary.darker,
-
- // quality gate indicator
- qgIndicatorPassed: COLORS.green[800],
- qgIndicatorFailed: danger.darker,
- qgIndicatorNotComputed: COLORS.blueGrey[800],
-
- // main bar
- mainBar: secondary.darker,
- mainBarLogo: COLORS.black,
- mainBarDarkLogo: COLORS.white,
- mainBarNews: secondary.darker,
-
- // navbar
- navbar: secondary.darker,
-
- // filterbar
- filterbar: secondary.darker,
-
- // facet
- facetKeyboardHint: secondary.darker,
- facetToggleActive: COLORS.white,
- facetToggleInactive: COLORS.white,
-
- // subnavigation sidebar
- subnavigation: secondary.darker,
- subnavigationExecutionFlow: COLORS.blueGrey[700],
- subnavigationHover: COLORS.blueGrey[700],
-
- // page
- pageBlock: secondary.darker,
-
- // graph - chart
- graphZoomHandleColor: COLORS.white,
-
- // progress bar
- coreConceptsProgressBar: primary.light,
-
- // issue box
- issueTypeIcon: COLORS.red[900],
- iconSeverityDisabled: COLORS.white,
- iconTypeDisabled: COLORS.white,
-
- // bubble charts
- bubbleDefault: COLORS.blue[500],
-
- 'bubble.1': COLORS.green[500],
- 'bubble.2': COLORS.yellowGreen[500],
- 'bubble.3': COLORS.yellow[500],
- 'bubble.4': COLORS.orange[500],
- 'bubble.5': COLORS.red[500],
-
- // news bar
- newsBar: COLORS.blueGrey[600],
- newsContent: COLORS.blueGrey[500],
- newsTag: COLORS.blueGrey[500],
- roadmap: COLORS.blueGrey[600],
- roadmapContent: COLORS.blueGrey[500],
-
- // Keyboard hint
- keyboardHintKey: COLORS.blueGrey[500],
- },
-
- // predefined shadows
- shadows: {
- xs: [[0, 1, 2, 0, ...COLORS.blueGrey[700], 0.05]],
- sm: [
- [0, 1, 3, 0, ...COLORS.blueGrey[700], 0.05],
- [0, 1, 25, 0, ...COLORS.blueGrey[700], 0.05],
- ],
- md: [
- [0, 4, 8, -2, ...COLORS.blueGrey[700], 0.1],
- [0, 2, 15, -2, ...COLORS.blueGrey[700], 0.06],
- ],
- lg: [
- [0, 12, 16, -4, ...COLORS.blueGrey[700], 0.1],
- [0, 4, 6, -2, ...COLORS.blueGrey[700], 0.05],
- ],
- xl: [
- [15, 20, 24, -4, ...COLORS.blueGrey[700], 0.1],
- [0, 8, 8, -4, ...COLORS.blueGrey[700], 0.06],
- ],
- scrolling: [[0, 0, 8, 0, ...COLORS.blueGrey[700], 0.2]],
- },
-
- // predefined borders
- borders: {
- default: ['1px', 'solid', ...COLORS.grey[50]],
- active: ['4px', 'solid', ...primary.light],
- xsActive: ['3px', 'solid', ...primary.light],
- focus: ['4px', 'solid', ...secondary.default, OPACITY_20_PERCENT],
- heavy: ['2px', 'solid', ...COLORS.grey[50]],
- },
-
- avatar: {
- color: [
- COLORS.blueGrey[100],
- COLORS.indigo[100],
- COLORS.tangerine[100],
- COLORS.green[100],
- COLORS.yellowGreen[100],
- COLORS.yellow[100],
- COLORS.orange[100],
- COLORS.red[100],
- COLORS.blue[100],
- ],
- contrast: [
- COLORS.blueGrey[900],
- COLORS.indigo[900],
- COLORS.tangerine[900],
- COLORS.green[900],
- COLORS.yellowGreen[900],
- COLORS.yellow[900],
- COLORS.orange[900],
- COLORS.red[900],
- COLORS.blue[900],
- ],
- },
-
- // Theme specific icons and images
- images: {
- azure: 'azure.svg',
- bitbucket: 'bitbucket.svg',
- github: 'github.svg',
- gitlab: 'gitlab.svg',
- microsoft: 'microsoft.svg',
- 'cayc-1': 'cayc-1-light.gif',
- 'cayc-2': 'cayc-2-light.gif',
- 'cayc-3': 'cayc-3-light.svg',
- 'cayc-4': 'cayc-4-light.svg',
- 'new-code-1': 'new-code-1.svg',
- 'new-code-2': 'new-code-2-light.svg',
- 'new-code-3': 'new-code-3.gif',
- 'new-code-4': 'new-code-4.gif',
- 'new-code-5': 'new-code-5.png',
- 'pull-requests-1': 'pull-requests-1-light.gif',
- 'pull-requests-2': 'pull-requests-2-light.svg',
- 'pull-requests-3': 'pull-requests-3.svg',
- 'quality-gate-1': 'quality-gate-1.png',
- 'quality-gate-2a': 'quality-gate-2a.svg',
- 'quality-gate-2b': 'quality-gate-2b.png',
- 'quality-gate-2c': 'quality-gate-2c.png',
- 'quality-gate-3': 'quality-gate-3-light.svg',
- 'quality-gate-4': 'quality-gate-4.png',
- 'quality-gate-5': 'quality-gate-5.svg',
-
- // project configure page
- AzurePipe: '/images/alms/azure.svg',
- BitbucketPipe: '/images/alms/bitbucket.svg',
- BitbucketAzure: '/images/alms/azure.svg',
- BitbucketCircleCI: '/images/tutorials/circleci.svg',
- GitHubActions: '/images/alms/github.svg',
- GitHubCircleCI: '/images/tutorials/circleci.svg',
- GitHubTravis: '/images/tutorials/TravisCI-Mascot.png',
- GitLabPipeline: '/images/alms/gitlab.svg',
- },
-};
diff --git a/server/sonar-web/src/main/js/design-system/theme/withTheme.tsx b/server/sonar-web/src/main/js/design-system/theme/withTheme.tsx
deleted file mode 100644
index 35b9841f215..00000000000
--- a/server/sonar-web/src/main/js/design-system/theme/withTheme.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useTheme } from '@emotion/react';
-import { Theme } from '../types/theme';
-
-export interface ThemeProp {
- theme: Theme;
-}
-
-export function withTheme<P>(
- WrappedComponent: React.ComponentType<React.PropsWithChildren<P & ThemeProp>>,
-): React.ComponentType<React.PropsWithChildren<P>> {
- return function WrappedComponentWithTheme(props: P) {
- const theme = useTheme();
-
- return <WrappedComponent theme={theme} {...props} />;
- };
-}
diff --git a/server/sonar-web/src/main/js/design-system/types/charts.ts b/server/sonar-web/src/main/js/design-system/types/charts.ts
deleted file mode 100644
index 204b0a710f9..00000000000
--- a/server/sonar-web/src/main/js/design-system/types/charts.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export interface ChartPoint {
- x: Date;
- y: number | string | undefined;
-}
-
-export interface ChartSerie {
- data: ChartPoint[];
- name: string;
- translatedName: string;
- type: string;
-}
-
-export type BubbleColorVal = 1 | 2 | 3 | 4 | 5;
diff --git a/server/sonar-web/src/main/js/design-system/types/index.ts b/server/sonar-web/src/main/js/design-system/types/index.ts
deleted file mode 100644
index b24d64198ce..00000000000
--- a/server/sonar-web/src/main/js/design-system/types/index.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export * from './charts';
-export * from './issues';
-export * from './measures';
-export * from './theme';
diff --git a/server/sonar-web/src/main/js/design-system/types/issues.ts b/server/sonar-web/src/main/js/design-system/types/issues.ts
deleted file mode 100644
index 52db6b9fe4b..00000000000
--- a/server/sonar-web/src/main/js/design-system/types/issues.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export type IssueType = 'BUG' | 'VULNERABILITY' | 'CODE_SMELL' | 'SECURITY_HOTSPOT';
diff --git a/server/sonar-web/src/main/js/design-system/types/measures.ts b/server/sonar-web/src/main/js/design-system/types/measures.ts
deleted file mode 100644
index 427ea92ef74..00000000000
--- a/server/sonar-web/src/main/js/design-system/types/measures.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum DuplicationEnum {
- A = 'A',
- B = 'B',
- C = 'C',
- D = 'D',
- E = 'E',
- F = 'F',
-}
-
-export type DuplicationLabel = keyof typeof DuplicationEnum;
-
-export enum SizeEnum {
- XS = 'XS',
- S = 'S',
- M = 'M',
- L = 'L',
- XL = 'XL',
-}
-export type SizeLabel = keyof typeof SizeEnum;
-
-export enum HotspotRatingEnum {
- LOW = 'LOW',
- MEDIUM = 'MEDIUM',
- HIGH = 'HIGH',
-}
-
-export type HotspotRatingLabel = keyof typeof HotspotRatingEnum;
diff --git a/server/sonar-web/src/main/js/design-system/types/misc.ts b/server/sonar-web/src/main/js/design-system/types/misc.ts
deleted file mode 100644
index 467399208ad..00000000000
--- a/server/sonar-web/src/main/js/design-system/types/misc.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export type FCProps<T extends React.FunctionComponent<React.PropsWithChildren<any>>> =
- Parameters<T>[0];
diff --git a/server/sonar-web/src/main/js/design-system/types/quality-gates.ts b/server/sonar-web/src/main/js/design-system/types/quality-gates.ts
deleted file mode 100644
index 40fea00492a..00000000000
--- a/server/sonar-web/src/main/js/design-system/types/quality-gates.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export type QGStatus = 'ERROR' | 'OK' | 'NONE' | 'NOT_COMPUTED';
diff --git a/server/sonar-web/src/main/js/design-system/types/theme.ts b/server/sonar-web/src/main/js/design-system/types/theme.ts
deleted file mode 100644
index 9d5dc6f0d00..00000000000
--- a/server/sonar-web/src/main/js/design-system/types/theme.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { lightTheme } from '../theme';
-
-export type InputSizeKeys = 'small' | 'medium' | 'large' | 'full' | 'auto';
-
-type LightTheme = typeof lightTheme;
-type ThemeColor = string | number[];
-export interface Theme extends Omit<LightTheme, 'colors' | 'contrasts'> {
- colors: {
- [key in keyof LightTheme['colors']]: ThemeColor;
- };
- contrasts: {
- [key in keyof LightTheme['colors'] & keyof LightTheme['contrasts']]: ThemeColor;
- };
-}
-
-export type ThemeColors = keyof Theme['colors'];
-export type ThemeContrasts = keyof Theme['contrasts'];
-
-type RGBColor = `rgb(${number},${number},${number})`;
-type RGBAColor = `rgba(${number},${number},${number},${number})`;
-type CSSCustomProp = `var(--${string})`;
-export type CSSColor = CSSCustomProp | RGBColor | RGBAColor;
-
-export interface ThemedProps {
- theme: Theme;
-}
diff --git a/server/sonar-web/src/main/js/helpers/UseQuery.tsx b/server/sonar-web/src/main/js/helpers/UseQuery.tsx
deleted file mode 100644
index 1880d24a9bf..00000000000
--- a/server/sonar-web/src/main/js/helpers/UseQuery.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { UseQueryResult } from '@tanstack/react-query';
-import { ReactElement } from 'react';
-
-type QueryHook<TData, TArgs extends any[]> = (...args: TArgs) => UseQueryResult<TData>;
-
-interface Props<TData, TArgs extends any[]> {
- args?: TArgs;
- children: (value: UseQueryResult<TData>) => ReactElement | null;
- query: QueryHook<TData, TArgs>;
-}
-
-export default function UseQuery<TData, TArgs extends any[]>(props: Props<TData, TArgs>) {
- const { query, args = [] as unknown as TArgs } = props;
-
- return props.children(query(...args));
-}
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/code-difference-test.tsx.snap b/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/code-difference-test.tsx.snap
deleted file mode 100644
index 658db41a02f..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/code-difference-test.tsx.snap
+++ /dev/null
@@ -1,57 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should apply diff view correctly: differenciatedCode 1`] = `
-HTMLCollection [
- <pre
- class="code-difference-scrollable"
- >
- <div
- class="code-difference-container"
- >
- public void endpoint(HttpServletRequest request, HttpServletResponse response) throws IOException
-{
- String data = request.getParameter("input");
- PrintWriter writer = response.getWriter();
-
-
- <div
- class="code-removed"
- >
- writer.print(data); // Noncompliant
-
- </div>
- }
-
- </div>
- </pre>,
- <pre
- class="code-difference-scrollable"
- >
- <div
- class="code-difference-container"
- >
- <div
- class="code-added"
- >
- import org.owasp.encoder.Encode;
-
-
- </div>
- public void endpoint(HttpServletRequest request, HttpServletResponse response) throws IOException
-{
- String data = request.getParameter("input");
- PrintWriter writer = response.getWriter();
-
-
- <div
- class="code-added"
- >
- writer.print(Encode.forHtml(data));
-
- </div>
- }
-
- </div>
- </pre>,
-]
-`;
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/extensions-test.ts.snap b/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/extensions-test.ts.snap
deleted file mode 100644
index 6ec1897850b..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/extensions-test.ts.snap
+++ /dev/null
@@ -1,5 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`installScript should add the given script to the dom 1`] = `"<script src="custom_script.js"></script>"`;
-
-exports[`installStyles should add the given stylesheet to the dom 1`] = `"<link href="custom_styles.css" rel="stylesheet">"`;
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/query-test.ts.snap b/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/query-test.ts.snap
deleted file mode 100644
index e3c36aed9da..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/query-test.ts.snap
+++ /dev/null
@@ -1,11 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`cleanQuery should remove undefined and null query items 1`] = `
-{
- "a": "b",
- "d": "",
- "e": 0,
-}
-`;
-
-exports[`parseAsDate should parse string date correctly 1`] = `2016-06-20T13:09:48.256Z`;
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/branch-like-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/branch-like-test.ts
deleted file mode 100644
index 6d5c7d7c635..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/branch-like-test.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getBrancheLikesAsTree, isSameBranchLike, sortBranches } from '../branch-like';
-import { mockBranch, mockMainBranch, mockPullRequest } from '../mocks/branch-like';
-
-describe('#getBrancheLikesAsTree', () => {
- it('should correctly map branches and prs to tree object', () => {
- const main = mockMainBranch({ name: 'master' });
- const branch1 = mockBranch({ name: 'branch-1' });
- const branch2 = mockBranch({ name: 'branch-2' });
- const branch3 = mockBranch({ name: 'branch-3' });
- const branch4 = mockBranch({ name: 'branch-4' });
-
- const mainPr1 = mockPullRequest({ base: main.name, key: '1' });
- const mainPr2 = mockPullRequest({ base: main.name, key: '2' });
- const branch1Pr1 = mockPullRequest({ base: branch1.name, key: '3' });
- const branch1Pr2 = mockPullRequest({ base: branch1.name, key: '4' });
- const branch2Pr1 = mockPullRequest({ base: branch2.name, key: '5' });
- const branch2Pr2 = mockPullRequest({ base: branch2.name, key: '6' });
- const orphanPR1 = mockPullRequest({ isOrphan: true, key: '7' });
- const orphanPR2 = mockPullRequest({ isOrphan: true, key: '8' });
- const parentlessPR1 = mockPullRequest({ base: 'not_present_branch_1', key: '9' });
- const parentlessPR2 = mockPullRequest({ base: 'not_present_branch_2', key: '10' });
-
- expect(
- getBrancheLikesAsTree([
- branch2,
- branch1,
- main,
- orphanPR2,
- orphanPR1,
- branch4,
- branch3,
- mainPr2,
- mainPr1,
- parentlessPR2,
- parentlessPR1,
- branch2Pr2,
- branch2Pr1,
- branch1Pr2,
- branch1Pr1,
- ]),
- ).toEqual({
- mainBranchTree: {
- branch: main,
- pullRequests: [mainPr2, mainPr1],
- },
- branchTree: [
- { branch: branch1, pullRequests: [branch1Pr2, branch1Pr1] },
- { branch: branch2, pullRequests: [branch2Pr2, branch2Pr1] },
- { branch: branch3, pullRequests: [] },
- { branch: branch4, pullRequests: [] },
- ],
- parentlessPullRequests: [parentlessPR2, parentlessPR1],
- orphanPullRequests: [orphanPR2, orphanPR1],
- });
- });
-});
-
-describe('#sortBranches', () => {
- it('should sort branches correctly', () => {
- const main = mockMainBranch();
- const foo = mockBranch({ name: 'shortFoo' });
- const bar = mockBranch({ name: 'shortBar' });
- const pre = mockBranch({ name: 'shortPre' });
- const baz = mockBranch({ name: 'longBaz' });
- const qux = mockBranch({ name: 'longQux' });
- const qwe = mockBranch({ name: 'longQwe' });
- const branchList = [foo, baz, pre, qux, main, qwe, bar];
-
- const sortedBrancList = sortBranches(branchList);
-
- expect(sortedBrancList).toEqual([main, baz, qux, qwe, bar, foo, pre]);
- });
-});
-
-describe('#isSameBranchLike', () => {
- it('compares different kinds', () => {
- const main = mockMainBranch();
- const foo = mockBranch({ name: 'foo' });
- const foo1 = mockBranch({ name: 'foo-1' });
- const pr = mockPullRequest();
- expect(isSameBranchLike(main, pr)).toBe(false);
- expect(isSameBranchLike(main, foo1)).toBe(false);
- expect(isSameBranchLike(main, foo)).toBe(false);
- expect(isSameBranchLike(pr, foo1)).toBe(false);
- expect(isSameBranchLike(pr, foo)).toBe(false);
- expect(isSameBranchLike(foo1, foo)).toBe(false);
- });
-
- it('compares pull requests', () => {
- expect(
- isSameBranchLike(mockPullRequest({ key: '1234' }), mockPullRequest({ key: '1234' })),
- ).toBe(true);
- expect(
- isSameBranchLike(mockPullRequest({ key: '1234' }), mockPullRequest({ key: '5678' })),
- ).toBe(false);
- });
-
- it('compares branches', () => {
- expect(isSameBranchLike(mockBranch({ name: 'foo' }), mockBranch({ name: 'foo' }))).toBe(true);
- expect(isSameBranchLike(mockBranch({ name: 'foo' }), mockBranch({ name: 'foo' }))).toBe(true);
- expect(isSameBranchLike(mockBranch({ name: 'foo' }), mockBranch({ name: 'bar' }))).toBe(false);
- expect(isSameBranchLike(mockBranch({ name: 'foo' }), mockBranch({ name: 'bar' }))).toBe(false);
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/code-difference-test.tsx b/server/sonar-web/src/main/js/helpers/__tests__/code-difference-test.tsx
deleted file mode 100644
index fee14f5e403..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/code-difference-test.tsx
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render } from '@testing-library/react';
-import { SafeHTMLInjection } from '~design-system';
-import applyCodeDifferences from '../code-difference';
-
-it('should apply diff view correctly', () => {
- const { container } = renderDom(properCodeSnippet);
- applyCodeDifferences(container);
- // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
- expect(container.getElementsByClassName('code-difference-scrollable')).toMatchSnapshot(
- 'differenciatedCode',
- );
-});
-
-it('should not apply diff view if 3 examples are present', () => {
- const { container } = renderDom(codeSnippetWith3Examples);
- applyCodeDifferences(container);
- // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
- expect(container.getElementsByClassName('code-difference-scrollable').length).toEqual(0);
-});
-
-it('should not apply diff view if compliant code is absent', () => {
- const { container } = renderDom(codeSnippetWithoutCompliantCode);
- applyCodeDifferences(container);
- // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
- expect(container.getElementsByClassName('code-difference-scrollable').length).toEqual(0);
-});
-
-const properCodeSnippet = `<!DOCTYPE html><body>
-<h1>Some title</h1>
-<p>Some paragraph...</p>
-
-<h2>Example 1</h2>
-
-<pre data-diff-id="1" data-diff-type="noncompliant">
-public void endpoint(HttpServletRequest request, HttpServletResponse response) throws IOException
-{
- String data = request.getParameter("input");
- PrintWriter writer = response.getWriter();
-
- writer.print(data); // Noncompliant
-}
-</pre>
-
-<p>Some other paragraph</p>
-
-<pre data-diff-id="1" data-diff-type="compliant">
-import org.owasp.encoder.Encode;
-
-public void endpoint(HttpServletRequest request, HttpServletResponse response) throws IOException
-{
- String data = request.getParameter("input");
- PrintWriter writer = response.getWriter();
-
- writer.print(Encode.forHtml(data));
-}
-</pre>
-
-<p>Final paragraph</p>
-</body></html>`;
-
-const codeSnippetWith3Examples = `<!DOCTYPE html><body>
-<h1>Some title</h1>
-<p>Some paragraph...</p>
-
-<h2>Example 1</h2>
-
-<pre data-diff-id="1" data-diff-type="noncompliant">
-public void endpoint(HttpServletRequest request, HttpServletResponse response) throws IOException
-{
- String data = request.getParameter("input");
- PrintWriter writer = response.getWriter();
-
- writer.print(data); // Noncompliant
-}
-</pre>
-
-<p>Some other paragraph</p>
-
-<pre data-diff-id="1" data-diff-type="compliant">
-import org.owasp.encoder.Encode;
-
-public void endpoint(HttpServletRequest request, HttpServletResponse response) throws IOException
-{
- String data = request.getParameter("input");
- PrintWriter writer = response.getWriter();
-
- writer.print(Encode.forHtml(data));
-}
-</pre>
-
-<p>Some other paragraph</p>
-
-<pre data-diff-id="1" data-diff-type="compliant">
-import org.owasp.encoder.Encode;
-
-public void endpoint(HttpServletRequest request, HttpServletResponse response) throws IOException
-{
- String data = request.getParameter("input");
- PrintWriter writer = response.getWriter();
-
- writer.print(Encode.forHtml(data));
-}
-</pre>
-
-<p>Final paragraph</p>
-</body></html>`;
-
-const codeSnippetWithoutCompliantCode = `<!DOCTYPE html><body>
-<h1>Some title</h1>
-<p>Some paragraph...</p>
-
-<h2>Example 1</h2>
-
-<pre data-diff-id="1" data-diff-type="noncompliant">
-public void endpoint(HttpServletRequest request, HttpServletResponse response) throws IOException
-{
- String data = request.getParameter("input");
- PrintWriter writer = response.getWriter();
-
- writer.print(data); // Noncompliant
-}
-</pre>
-
-<p>Some other paragraph</p>
-<p>Final paragraph</p>
-</body></html>`;
-
-function renderDom(codeSnippet: string) {
- return render(
- <SafeHTMLInjection htmlAsString={codeSnippet}>
- <div className="markdown" />
- </SafeHTMLInjection>,
- );
-}
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/dates-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/dates-test.ts
deleted file mode 100644
index b8bcbde87dd..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/dates-test.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as dates from '../dates';
-
-const { parseDate } = dates;
-const recentDate = parseDate('2017-08-16T12:00:00.000Z');
-
-it('toShortISO8601String', () => {
- expect(dates.toShortISO8601String(recentDate)).toBe('2017-08-16');
-});
-
-it('toISO8601WithOffsetString', () => {
- expect(dates.toISO8601WithOffsetString(recentDate)).toBe('2017-08-16T12:00:00+0000');
-});
-
-it('isValidDate', () => {
- expect(dates.isValidDate(recentDate)).toBe(true);
- expect(dates.isValidDate(new Date())).toBe(true);
- expect(dates.isValidDate(parseDate('foo'))).toBe(false);
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/error-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/error-test.ts
deleted file mode 100644
index 22406c3c17e..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/error-test.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { addGlobalErrorMessage } from '~design-system';
-import { throwGlobalError } from '~sonar-aligned/helpers/error';
-
-jest.mock('~design-system', () => ({
- addGlobalErrorMessage: jest.fn(),
-}));
-
-beforeEach(() => {
- jest.useFakeTimers();
- jest.clearAllMocks();
-});
-
-afterEach(() => {
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
-});
-
-it('should display the error message', async () => {
- const response = new Response();
- response.json = jest.fn().mockResolvedValue({ errors: [{ msg: 'error 1' }] });
-
- // We need to catch because throwGlobalError rethrows after displaying the message
- await throwGlobalError(response)
- .then(() => {
- throw new Error('Should throw');
- })
- .catch(() => {});
-
- expect(addGlobalErrorMessage).toHaveBeenCalledWith('error 1');
-});
-
-it('should display the default error messsage', async () => {
- const response = new Response();
- response.json = jest.fn().mockResolvedValue({});
-
- // We need to catch because throwGlobalError rethrows after displaying the message
- await throwGlobalError(response)
- .then(() => {
- throw new Error('Should throw');
- })
- .catch(() => {});
-
- expect(addGlobalErrorMessage).toHaveBeenCalledWith('default_error_message');
-});
-
-it('should handle weird response types', async () => {
- const response = { weird: 'response type' };
-
- await expect(
- throwGlobalError(response).then(() => {
- throw new Error('Should throw');
- }),
- ).rejects.toBe(response);
-});
-
-it('should unwrap response if necessary', async () => {
- const response = new Response();
- response.json = jest.fn().mockResolvedValue({});
-
- /* eslint-disable-next-line no-console */
- console.warn = jest.fn();
-
- // We need to catch because throwGlobalError rethrows after displaying the message
- await throwGlobalError({ response })
- .then(() => {
- throw new Error('Should throw');
- })
- .catch(() => {});
-
- /* eslint-disable-next-line no-console */
- expect(console.warn).toHaveBeenCalled();
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/extensions-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/extensions-test.ts
deleted file mode 100644
index 996332e0a12..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/extensions-test.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { setImmediate } from 'timers';
-import exposeLibraries from '../../app/components/extensions/exposeLibraries';
-import { getExtensionStart, installScript, installStyles } from '../extensions';
-import { installExtensionsHandler } from '../extensionsHandler';
-
-jest.mock('../../app/components/extensions/exposeLibraries', () => jest.fn());
-
-beforeEach(() => {
- jest.clearAllMocks();
- document.body.childNodes.forEach((node) => document.body.removeChild(node));
- document.head.childNodes.forEach((node) => document.head.removeChild(node));
-});
-
-describe('installScript', () => {
- it('should add the given script to the dom', () => {
- installScript('custom_script.js');
- expect(document.body.innerHTML).toMatchSnapshot();
- });
-});
-
-describe('installStyles', () => {
- it('should add the given stylesheet to the dom', async () => {
- installStyles('custom_styles.css');
- await new Promise(setImmediate);
- expect(document.head.innerHTML).toMatchSnapshot();
- });
-});
-
-describe('getExtensionStart', () => {
- const originalCreateElement = document.createElement;
- const scriptTag = document.createElement('script');
- const linkTag = document.createElement('link');
-
- beforeEach(() => {
- Object.defineProperty(document, 'createElement', {
- writable: true,
- value: jest.fn().mockReturnValueOnce(scriptTag).mockReturnValueOnce(linkTag),
- });
- });
-
- afterEach(() => {
- Object.defineProperty(document, 'createElement', {
- writable: true,
- value: originalCreateElement,
- });
- });
-
- it('should install the extension in the to dom', async () => {
- const start = jest.fn();
- installExtensionsHandler();
-
- const result = getExtensionStart('bar');
-
- await new Promise(setImmediate);
- expect(exposeLibraries).toHaveBeenCalled();
-
- (window as any).registerExtension('bar', start, true);
-
- (scriptTag.onload as Function)();
- await new Promise(setImmediate);
-
- (linkTag.onload as Function)();
- await new Promise(setImmediate);
-
- return expect(result).resolves.toBe(start);
- });
-
- it('should get the extension from the cache', () => {
- const start = jest.fn();
- installExtensionsHandler();
- (window as any).registerExtension('baz', start);
- return expect(getExtensionStart('baz')).resolves.toBe(start);
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/extensionsHandler-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/extensionsHandler-test.ts
deleted file mode 100644
index 12eaeacc978..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/extensionsHandler-test.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- getExtensionFromCache,
- getWebAnalyticsPageHandlerFromCache,
- installExtensionsHandler,
- installWebAnalyticsHandler,
-} from '../extensionsHandler';
-
-describe('installExtensionsHandler & extensions.getExtensionFromCache', () => {
- it('should register the global "registerExtension" function and retrieve extension', () => {
- expect((window as any).registerExtension).toBeUndefined();
- installExtensionsHandler();
- expect((window as any).registerExtension).toEqual(expect.any(Function));
-
- const start = jest.fn();
- (window as any).registerExtension('foo', start, true);
- expect(getExtensionFromCache('foo')).toEqual({ start, providesCSSFile: true });
- });
-});
-
-describe('setWebAnalyticsPageChangeHandler & getWebAnalyticsPageHandlerFromCache', () => {
- it('should register the global "setWebAnalyticsPageChangeHandler" function and retrieve analytics extension', () => {
- expect((window as any).setWebAnalyticsPageChangeHandler).toBeUndefined();
- installWebAnalyticsHandler();
- expect((window as any).setWebAnalyticsPageChangeHandler).toEqual(expect.any(Function));
-
- const pageChange = jest.fn();
- (window as any).setWebAnalyticsPageChangeHandler(pageChange);
- expect(getWebAnalyticsPageHandlerFromCache()).toBe(pageChange);
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/handleRequiredAuthentication-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/handleRequiredAuthentication-test.ts
deleted file mode 100644
index 949a93f6986..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/handleRequiredAuthentication-test.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import handleRequiredAuthentication from '../handleRequiredAuthentication';
-
-const originalLocation = window.location;
-
-const replace = jest.fn();
-
-beforeAll(() => {
- const location = {
- ...window.location,
- pathname: '/path',
- search: '?id=12',
- hash: '#tag',
- replace,
- };
- Object.defineProperty(window, 'location', {
- writable: true,
- value: location,
- });
-});
-
-afterAll(() => {
- Object.defineProperty(window, 'location', {
- writable: true,
- value: originalLocation,
- });
-});
-
-it('should not render for anonymous user', () => {
- handleRequiredAuthentication();
- expect(replace).toHaveBeenCalledWith('/sessions/new?return_to=%2Fpath%3Fid%3D12%23tag');
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/issues-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/issues-test.ts
deleted file mode 100644
index 3e900ed8bc5..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/issues-test.ts
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { IssueType } from '../../types/issues';
-import { parseIssueFromResponse, sortByType } from '../issues';
-import { mockIssue } from '../testMocks';
-
-it('should sort issues correctly by type', () => {
- const bug1 = mockIssue(false, { type: IssueType.Bug, key: 'bug1' });
- const bug2 = mockIssue(false, { type: IssueType.Bug, key: 'bug2' });
- const codeSmell = mockIssue(false, { type: IssueType.CodeSmell, key: 'code_smell' });
- const vulnerability1 = mockIssue(false, { type: IssueType.Vulnerability, key: 'vulnerability1' });
- const vulnerability2 = mockIssue(false, { type: IssueType.Vulnerability, key: 'vulnerability2' });
- const securityHotspot = mockIssue(false, {
- type: IssueType.SecurityHotspot,
- key: 'security_hotspot',
- });
-
- expect(
- sortByType([bug1, codeSmell, bug2, securityHotspot, vulnerability1, vulnerability2]),
- ).toEqual([bug1, bug2, vulnerability1, vulnerability2, codeSmell, securityHotspot]);
-});
-
-it('should populate comments data', () => {
- const users = [
- {
- active: true,
- avatar: 'c1244e6857f7be3dc4549d9e9d51c631',
- login: 'admin',
- name: 'Admin Admin',
- },
- ];
- const issue = {
- comments: [
- {
- createdAt: '2017-04-11T10:38:090200',
- htmlText: 'comment!',
- key: 'AVtcKbZkQmGLa7yW8J71',
- login: 'admin',
- markdown: 'comment!',
- updatable: true,
- },
- ],
- } as any;
- expect(parseIssueFromResponse(issue, undefined, users, undefined).comments).toEqual([
- {
- author: 'admin',
- authorActive: true,
- authorAvatar: 'c1244e6857f7be3dc4549d9e9d51c631',
- authorLogin: 'admin',
- authorName: 'Admin Admin',
- createdAt: '2017-04-11T10:38:090200',
- htmlText: 'comment!',
- key: 'AVtcKbZkQmGLa7yW8J71',
- login: undefined,
- markdown: 'comment!',
- updatable: true,
- },
- ]);
-});
-
-it('orders secondary locations', () => {
- const issue = {
- flows: [
- {
- locations: [
- {
- component: 'foo',
- textRange: { startLine: 68, startOffset: 5, endLine: 68, endOffset: 7 },
- },
- ],
- },
- {
- locations: [
- {
- component: 'unknown',
- textRange: { startLine: 43, startOffset: 8, endLine: 43, endOffset: 12 },
- },
- ],
- },
- {
- locations: [
- {
- component: 'bar',
- textRange: { startLine: 43, startOffset: 6, endLine: 43, endOffset: 8 },
- },
- ],
- },
- {
- locations: [
- {
- component: 'foo',
- textRange: { startLine: 70, startOffset: 12, endLine: 70, endOffset: 16 },
- },
- ],
- },
- ],
- } as any;
- const components = [
- { key: 'foo', name: 'src/foo.js' },
- { key: 'bar', name: 'src/bar.js' },
- ];
- expect(parseIssueFromResponse(issue, components).secondaryLocations).toEqual([
- {
- component: 'bar',
- componentName: 'src/bar.js',
- textRange: { endLine: 43, endOffset: 8, startLine: 43, startOffset: 6 },
- },
- {
- component: 'unknown',
- componentName: undefined,
- textRange: { endLine: 43, endOffset: 12, startLine: 43, startOffset: 8 },
- },
- {
- component: 'foo',
- componentName: 'src/foo.js',
- textRange: { endLine: 68, endOffset: 7, startLine: 68, startOffset: 5 },
- },
- {
- component: 'foo',
- componentName: 'src/foo.js',
- textRange: { endLine: 70, endOffset: 16, startLine: 70, startOffset: 12 },
- },
- ]);
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/l10n-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/l10n-test.ts
deleted file mode 100644
index e1d3df12fce..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/l10n-test.ts
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { IntlShape } from 'react-intl';
-import { Dict } from '../../types/types';
-import {
- getLocalizedCategoryMetricName,
- getLocalizedMetricDomain,
- getLocalizedMetricName,
- getShortMonthName,
- getShortWeekDayName,
- getWeekDayName,
- hasMessage,
- translate,
- translateWithParameters,
-} from '../l10n';
-import { getIntl, getMessages } from '../l10nBundle';
-
-const MSG = 'my_message';
-
-jest.unmock('../l10n');
-
-jest.mock('../l10nBundle', () => {
- const bundle = jest.requireActual('../l10nBundle');
- return {
- ...bundle,
- getIntl: jest.fn().mockReturnValue({ formatMessage: jest.fn(({ id }) => `${id}`) }),
- getMessages: jest.fn().mockReturnValue({}),
- };
-});
-
-const resetMessages = (messages: Dict<string>) => {
- jest.mocked(getMessages).mockReturnValue(messages);
-
- jest.mocked(getIntl).mockReturnValue({
- formatMessage: jest.fn(({ id }) => {
- return id ? (messages[id] ?? id) : `${id}`;
- }),
- } as unknown as IntlShape);
-};
-
-beforeEach(() => {
- resetMessages({});
-});
-
-describe('hasMessage', () => {
- it('should return that the message exists', () => {
- resetMessages({
- foo: 'foo',
- 'foo.bar': 'foobar',
- });
- expect(hasMessage('foo')).toBe(true);
- expect(hasMessage('foo', 'bar')).toBe(true);
- });
-
- it('should return that the message is missing', () => {
- expect(hasMessage('foo')).toBe(false);
- expect(hasMessage('foo', 'bar')).toBe(false);
- });
-});
-
-describe('translate', () => {
- it('should translate simple message', () => {
- resetMessages({ my_key: MSG });
- expect(translate('my_key')).toBe(MSG);
- });
-
- it('should translate message with composite key', () => {
- resetMessages({ 'my.composite.message': MSG });
- expect(translate('my', 'composite', 'message')).toBe(MSG);
- expect(translate('my.composite', 'message')).toBe(MSG);
- expect(translate('my', 'composite.message')).toBe(MSG);
- expect(translate('my.composite.message')).toBe(MSG);
- });
-
- it('should not translate message but return its key', () => {
- expect(translate('random')).toBe('random');
- expect(translate('random', 'key')).toBe('random.key');
- expect(translate('composite.random', 'key')).toBe('composite.random.key');
- });
-
- it('should fall back to the old system when intl is undefined', () => {
- jest.mocked(getIntl).mockReturnValueOnce(undefined as unknown as IntlShape);
- resetMessages({ exists: 'this exists' });
-
- expect(translate('exists')).toBe('this exists');
- });
-});
-
-describe('translateWithParameters', () => {
- it('should translate message with one parameter in the beginning', () => {
- resetMessages({ x_apples: '{0} apples' });
- expect(translateWithParameters('x_apples', 5)).toBe('5 apples');
- });
-
- it('should translate message with one parameter in the middle', () => {
- resetMessages({ x_apples: 'I have {0} apples' });
- expect(translateWithParameters('x_apples', 5)).toBe('I have 5 apples');
- });
-
- it('should translate message with one parameter in the end', () => {
- resetMessages({ x_apples: 'Apples: {0}' });
- expect(translateWithParameters('x_apples', 5)).toBe('Apples: 5');
- });
-
- it('should translate message with several parameters', () => {
- resetMessages({
- x_apples: '{0}: I have {2} apples in my {1} baskets - {3}',
- });
- expect(translateWithParameters('x_apples', 1, 2, 3, 4)).toBe(
- '1: I have 3 apples in my 2 baskets - 4',
- );
- });
-
- it('should not be affected by replacement pattern XSS vulnerability of String.replace', () => {
- resetMessages({ x_apples: 'I have {0} apples' });
- expect(translateWithParameters('x_apples', '$`')).toBe('I have $` apples');
- });
-
- it('should not translate message but return its key', () => {
- expect(translateWithParameters('random', 5)).toBe('random.5');
- expect(translateWithParameters('random', 1, 2, 3)).toBe('random.1.2.3');
- expect(translateWithParameters('composite.random', 1, 2)).toBe('composite.random.1.2');
- });
-});
-
-describe('getLocalizedMetricName', () => {
- const metric = { key: 'new_code', name: 'new_code_metric_name' };
-
- it('should return the metric name translation', () => {
- resetMessages({ 'metric.new_code.name': 'metric.new_code.name_t' });
- expect(getLocalizedMetricName(metric)).toBe('metric.new_code.name_t');
- });
-
- it('should return the metric short name', () => {
- resetMessages({
- 'metric.new_code.short_name': 'metric.new_code.short_name_t',
- });
- expect(getLocalizedMetricName(metric, true)).toBe('metric.new_code.short_name_t');
- });
-
- it('should fallback on name if short name is absent', () => {
- resetMessages({ 'metric.new_code.name': 'metric.new_code.name_t' });
- expect(getLocalizedMetricName(metric, true)).toBe('metric.new_code.name_t');
- });
-
- it('should fallback on metric name if translation is absent', () => {
- expect(getLocalizedMetricName(metric)).toBe('new_code_metric_name');
- });
-
- it('should fallback on metric key if nothing else is available', () => {
- expect(getLocalizedMetricName({ key: 'new_code' })).toBe('new_code');
- });
-});
-
-describe('getLocalizedCategoryMetricName', () => {
- it('should return metric category name translation', () => {
- resetMessages({
- 'metric.new_code.extra_short_name': 'metric.new_code.extra_short_name_t',
- });
- expect(getLocalizedCategoryMetricName({ key: 'new_code' })).toBe(
- 'metric.new_code.extra_short_name_t',
- );
- });
-
- it('should fallback on metric name if extra_short_name is absent', () => {
- resetMessages({ 'metric.new_code.name': 'metric.new_code.name_t' });
- expect(getLocalizedCategoryMetricName({ key: 'new_code' })).toBe('metric.new_code.name_t');
- });
-});
-
-describe('getLocalizedMetricDomain', () => {
- it('should return metric domain name translation', () => {
- resetMessages({ 'metric_domain.domain': 'metric_domain.domain_t' });
- expect(getLocalizedMetricDomain('domain')).toBe('metric_domain.domain_t');
- });
-
- it('should fallback on metric domain name', () => {
- expect(getLocalizedMetricDomain('domain')).toBe('domain');
- });
-});
-
-describe('getShortMonthName', () => {
- it('should properly translation months', () => {
- resetMessages({ Jan: 'Jan_t' });
- expect(getShortMonthName(0)).toBe('Jan_t');
- });
-});
-
-describe('getWeekDayName', () => {
- it('should properly translation weekday', () => {
- resetMessages({ Sunday: 'Sunday_t' });
- expect(getWeekDayName(0)).toBe('Sunday_t');
- });
-});
-
-describe('getShortWeekDayName', () => {
- it('should properly translation short weekday', () => {
- resetMessages({ Sun: 'Sun_t' });
- expect(getShortWeekDayName(0)).toBe('Sun_t');
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/l10nBundle-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/l10nBundle-test.ts
deleted file mode 100644
index 930f244e8a9..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/l10nBundle-test.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { fetchL10nBundle } from '../../api/l10n';
-import { loadL10nBundle } from '../l10nBundle';
-import { mockAppState } from '../testMocks';
-
-beforeEach(() => {
- jest.clearAllMocks();
- jest.spyOn(window.navigator, 'languages', 'get').mockReturnValue(['de']);
-});
-
-jest.mock('../../api/l10n', () => ({
- fetchL10nBundle: jest.fn().mockResolvedValue({
- effectiveLocale: 'de',
- messages: { foo: 'Foo', 'foo.bar': 'Foo Bar' },
- }),
-}));
-
-const APP_STATE = mockAppState({});
-
-describe('#loadL10nBundle', () => {
- it('should fetch bundle without any timestamp', async () => {
- await loadL10nBundle(APP_STATE);
-
- expect(fetchL10nBundle).toHaveBeenCalledWith({ locale: 'de', ts: undefined });
- });
-
- it('should ftech bundle without local storage timestamp if locales are different', async () => {
- const cachedBundle = { timestamp: 'timestamp', locale: 'fr', messages: { cache: 'cache' } };
- (window as unknown as any).sonarQubeL10nBundle = cachedBundle;
-
- await loadL10nBundle(APP_STATE);
-
- expect(fetchL10nBundle).toHaveBeenCalledWith({ locale: 'de', ts: undefined });
- });
-
- it('should fetch bundle with cached bundle timestamp and browser locale', async () => {
- const cachedBundle = { timestamp: 'timestamp', locale: 'de', messages: { cache: 'cache' } };
- (window as unknown as any).sonarQubeL10nBundle = cachedBundle;
-
- await loadL10nBundle(APP_STATE);
-
- expect(fetchL10nBundle).toHaveBeenCalledWith({ locale: 'de', ts: cachedBundle.timestamp });
- });
-
- it('should fallback to cached bundle if the server respond with 304', async () => {
- const cachedBundle = { timestamp: 'timestamp', locale: 'fr', messages: { cache: 'cache' } };
- (fetchL10nBundle as jest.Mock).mockRejectedValueOnce({ status: 304 });
- (window as unknown as any).sonarQubeL10nBundle = cachedBundle;
-
- const bundle = await loadL10nBundle(APP_STATE);
-
- expect(bundle).toEqual(
- expect.objectContaining({ locale: cachedBundle.locale, messages: cachedBundle.messages }),
- );
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts
deleted file mode 100644
index 4c8516d50fb..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { CCT_SOFTWARE_QUALITY_METRICS } from '../constants';
-import {
- areCCTMeasuresComputed,
- enhanceConditionWithMeasure,
- isPeriodBestValue,
-} from '../measures';
-import { mockQualityGateStatusCondition } from '../mocks/quality-gates';
-import { mockMeasure, mockMeasureEnhanced, mockMetric } from '../testMocks';
-
-jest.mock('../l10nBundle', () => {
- const bundle = jest.requireActual('../l10nBundle');
- return {
- ...bundle,
- getIntl: () => ({ formatMessage: jest.fn(({ id }) => `${id}`) }),
- };
-});
-
-describe('enhanceConditionWithMeasure', () => {
- it('should correctly map enhance conditions with measure data', () => {
- const measures = [
- mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.bugs }), period: undefined }),
- mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_bugs }) }),
- ];
-
- expect(
- enhanceConditionWithMeasure(
- mockQualityGateStatusCondition({ metric: MetricKey.bugs }),
- measures,
- ),
- ).toMatchObject({
- measure: expect.objectContaining({
- metric: expect.objectContaining({ key: MetricKey.bugs }),
- }),
- });
-
- expect(
- enhanceConditionWithMeasure(
- mockQualityGateStatusCondition({ metric: MetricKey.new_bugs }),
- measures,
- ),
- ).toMatchObject({
- measure: expect.objectContaining({
- metric: expect.objectContaining({ key: MetricKey.new_bugs }),
- }),
- period: 1,
- });
- });
-
- it('should return undefined if no match can be found', () => {
- expect(enhanceConditionWithMeasure(mockQualityGateStatusCondition(), [])).toBeUndefined();
- });
-});
-
-describe('isPeriodBestValue', () => {
- it('should work as expected', () => {
- expect(isPeriodBestValue(mockMeasureEnhanced({ period: undefined }))).toBe(false);
- expect(
- isPeriodBestValue(
- mockMeasureEnhanced({ period: { index: 1, value: '1.0', bestValue: false } }),
- ),
- ).toBe(false);
- expect(
- isPeriodBestValue(
- mockMeasureEnhanced({ period: { index: 1, value: '1.0', bestValue: true } }),
- ),
- ).toBe(true);
- });
-});
-
-describe('areCCTMeasuresComputed', () => {
- it('returns true when measures include maintainability_,security_,reliability_issues', () => {
- expect(
- areCCTMeasuresComputed(CCT_SOFTWARE_QUALITY_METRICS.map((metric) => mockMeasure({ metric }))),
- ).toBe(true);
- });
-
- it('returns false otherwise', () => {
- expect(areCCTMeasuresComputed([mockMeasure()])).toBe(false);
- expect(
- areCCTMeasuresComputed([
- mockMeasure(),
- mockMeasure({ metric: CCT_SOFTWARE_QUALITY_METRICS[0] }),
- ]),
- ).toBe(false);
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/new-code-definition-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/new-code-definition-test.ts
deleted file mode 100644
index f7039ffe246..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/new-code-definition-test.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { NewCodeDefinition, NewCodeDefinitionType } from '../../types/new-code-definition';
-import { mockNewCodePeriod } from '../mocks/new-code-definition';
-import {
- NUMBER_OF_DAYS_DEFAULT_VALUE,
- getNumberOfDaysDefaultValue,
- isNewCodeDefinitionCompliant,
-} from '../new-code-definition';
-
-describe('isNewCodeDefinitionCompliant', () => {
- it.each([
- [mockNewCodePeriod({ type: NewCodeDefinitionType.NumberOfDays, value: '0' }), false],
- [mockNewCodePeriod({ type: NewCodeDefinitionType.NumberOfDays, value: '15' }), true],
- [mockNewCodePeriod({ type: NewCodeDefinitionType.NumberOfDays, value: '15.' }), false],
- [mockNewCodePeriod({ type: NewCodeDefinitionType.NumberOfDays, value: '15.0' }), false],
- [mockNewCodePeriod({ type: NewCodeDefinitionType.NumberOfDays, value: '15.3' }), false],
- [mockNewCodePeriod({ type: NewCodeDefinitionType.NumberOfDays, value: '91' }), false],
- [mockNewCodePeriod({ type: NewCodeDefinitionType.PreviousVersion }), true],
- [mockNewCodePeriod({ type: NewCodeDefinitionType.ReferenceBranch }), true],
- [mockNewCodePeriod({ type: NewCodeDefinitionType.SpecificAnalysis }), false],
- ])(
- 'should test for new code definition compliance properly %s',
- (newCodePeriod: NewCodeDefinition, result: boolean) => {
- expect(isNewCodeDefinitionCompliant(newCodePeriod)).toEqual(result);
- },
- );
-});
-
-describe('getNumberOfDaysDefaultValue', () => {
- it.each([
- [null, null, NUMBER_OF_DAYS_DEFAULT_VALUE.toString()],
- [
- mockNewCodePeriod({ type: NewCodeDefinitionType.PreviousVersion }),
- null,
- NUMBER_OF_DAYS_DEFAULT_VALUE.toString(),
- ],
- [
- null,
- mockNewCodePeriod({ type: NewCodeDefinitionType.PreviousVersion }),
- NUMBER_OF_DAYS_DEFAULT_VALUE.toString(),
- ],
- [
- mockNewCodePeriod({ type: NewCodeDefinitionType.NumberOfDays, value: '91' }),
- null,
- NUMBER_OF_DAYS_DEFAULT_VALUE.toString(),
- ],
- [
- null,
- mockNewCodePeriod({ type: NewCodeDefinitionType.NumberOfDays, value: '91' }),
- NUMBER_OF_DAYS_DEFAULT_VALUE.toString(),
- ],
- [mockNewCodePeriod({ type: NewCodeDefinitionType.NumberOfDays, value: '90' }), null, '90'],
- [null, mockNewCodePeriod({ type: NewCodeDefinitionType.NumberOfDays, value: '90' }), '90'],
- ])(
- 'should return the defaut number of days vale properly %s',
- (
- globalNewCodeDefinition: NewCodeDefinition | null,
- inheritedNewCodeDefinition: NewCodeDefinition | null,
- result: string,
- ) => {
- expect(
- getNumberOfDaysDefaultValue(globalNewCodeDefinition, inheritedNewCodeDefinition),
- ).toEqual(result);
- },
- );
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/new-code-period-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/new-code-period-test.ts
deleted file mode 100644
index 13fe6c3e422..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/new-code-period-test.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { NewCodeDefinitionType } from '../../types/new-code-definition';
-import { getNewCodePeriodLabel } from '../new-code-period';
-import { mockPeriod } from '../testMocks';
-
-const formatter = jest.fn((v) => v);
-
-beforeEach(() => {
- formatter.mockClear();
-});
-
-describe('getPeriodLabel', () => {
- it('should handle missing value', () => {
- expect(getNewCodePeriodLabel(undefined, formatter)).toBeUndefined();
- });
-
- it('should handle date', () => {
- expect(getNewCodePeriodLabel(mockPeriod({ mode: 'date' }), formatter)).toBe(
- 'overview.period.date.',
- );
- expect(
- getNewCodePeriodLabel(
- mockPeriod({ mode: 'date', parameter: '2019-02-21T01:11:21+0100' }),
- formatter,
- ),
- ).toBe('overview.period.date.2019-02-21T01:11:21+0100');
- expect(formatter).toHaveBeenCalledTimes(1);
- });
-
- it('should handle days', () => {
- expect(getNewCodePeriodLabel(mockPeriod({ mode: 'days', modeParam: '12' }), formatter)).toBe(
- 'overview.period.days.12',
- );
- expect(formatter).not.toHaveBeenCalled();
- });
-
- it('should handle previous analysis', () => {
- expect(
- getNewCodePeriodLabel(
- mockPeriod({ mode: 'previous_analysis', parameter: 'param' }),
- formatter,
- ),
- ).toBe('overview.period.previous_analysis.param');
- expect(formatter).not.toHaveBeenCalled();
- });
-
- it('should handle previous version', () => {
- expect(getNewCodePeriodLabel(mockPeriod({ mode: 'previous_version' }), formatter)).toBe(
- 'overview.period.previous_version_only_date',
- );
- expect(
- getNewCodePeriodLabel(mockPeriod({ mode: 'previous_version', parameter: '7.9' }), formatter),
- ).toBe('overview.period.previous_version.7.9');
- expect(formatter).not.toHaveBeenCalled();
- });
-
- it('should handle version', () => {
- expect(
- getNewCodePeriodLabel(mockPeriod({ mode: 'version', modeParam: '7.2' }), formatter),
- ).toBe('overview.period.version.7.2');
- expect(
- getNewCodePeriodLabel(mockPeriod({ mode: 'previous_version', parameter: '7.9' }), formatter),
- ).toBe('overview.period.previous_version.7.9');
- expect(formatter).not.toHaveBeenCalled();
- });
-
- it('should handle manual baseline', () => {
- expect(
- getNewCodePeriodLabel(
- mockPeriod({ mode: 'manual_baseline', modeParam: 'A658678DE' }),
- formatter,
- ),
- ).toBe('overview.period.manual_baseline.A658678DE');
- expect(getNewCodePeriodLabel(mockPeriod({ mode: 'manual_baseline' }), formatter)).toBe(
- 'overview.period.manual_baseline.2019-04-23T02:12:32+0100',
- );
- expect(formatter).toHaveBeenCalledTimes(1);
- });
-
- it('should handle SPECIFIC_ANALYSIS', () => {
- expect(
- getNewCodePeriodLabel(
- mockPeriod({ mode: NewCodeDefinitionType.SpecificAnalysis, parameter: '7.1' }),
- formatter,
- ),
- ).toBe('overview.period.specific_analysis.2019-04-23T02:12:32+0100');
- expect(
- getNewCodePeriodLabel(
- mockPeriod({ mode: NewCodeDefinitionType.SpecificAnalysis }),
- formatter,
- ),
- ).toBe('overview.period.specific_analysis.2019-04-23T02:12:32+0100');
- expect(formatter).toHaveBeenCalledTimes(2);
- });
-
- it('should handle PREVIOUS_VERSION', () => {
- expect(
- getNewCodePeriodLabel(
- mockPeriod({ mode: NewCodeDefinitionType.PreviousVersion, modeParam: 'A658678DE' }),
- formatter,
- ),
- ).toBe('overview.period.previous_version.A658678DE');
- expect(
- getNewCodePeriodLabel(mockPeriod({ mode: NewCodeDefinitionType.PreviousVersion }), formatter),
- ).toBe('overview.period.previous_version.2019-04-23T02:12:32+0100');
- expect(formatter).toHaveBeenCalledTimes(1);
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/path-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/path-test.ts
deleted file mode 100644
index 2604e250bda..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/path-test.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- collapsedDirFromPath,
- collapsePath,
- cutLongWords,
- fileFromPath,
- limitComponentName,
- splitPath,
-} from '../path';
-
-describe('#collapsedDirFromPath()', () => {
- it('should return null when pass null', () => {
- expect(collapsedDirFromPath(null)).toBeNull();
- });
-
- it('should return "/" when pass "/"', () => {
- expect(collapsedDirFromPath('/')).toBe('/');
- });
-
- it('should not cut short path', () => {
- expect(collapsedDirFromPath('src/main/js/components/state.js')).toBe('src/main/js/components/');
- });
-
- it('should cut long path', () => {
- expect(collapsedDirFromPath('src/main/js/components/navigator/app/models/state.js')).toBe(
- 'src/.../components/navigator/app/models/',
- );
- });
-
- it('should cut very long path', () => {
- expect(
- collapsedDirFromPath('src/main/another/js/components/navigator/app/models/state.js'),
- ).toBe('src/.../components/navigator/app/models/');
- });
-});
-
-describe('#fileFromPath()', () => {
- it('should return null when pass null', () => {
- expect(fileFromPath(null)).toBeNull();
- });
-
- it('should return empty string when pass "/"', () => {
- expect(fileFromPath('/')).toBe('');
- });
-
- it('should return file name when pass only file name', () => {
- expect(fileFromPath('file.js')).toBe('file.js');
- });
-
- it('should return file name when pass file path', () => {
- expect(fileFromPath('src/main/js/file.js')).toBe('file.js');
- });
-
- it('should return file name when pass file name without extension', () => {
- expect(fileFromPath('src/main/file')).toBe('file');
- });
-});
-
-describe('#cutLongWords', () => {
- it('should cut the long work in the middle', () => {
- expect(cutLongWords('This is a reallylongwordthatdontexistforthe test')).toBe(
- 'This is a reallylongwordthatdontexistfor... test',
- );
- });
-
- it('should not cut anything', () => {
- expect(cutLongWords('This is a test')).toBe('This is a test');
- });
-});
-
-describe('collapsePath', () => {
- it('should fail fast if path is not a string', () => {
- expect(collapsePath({} as string)).toBe('');
- });
-
- it('should not collapse short path', () => {
- const path = 'my/path';
- expect(collapsePath(path)).toBe(path);
- });
-
- it('should collapse path longer than the limit', () => {
- const path = 'my/long/path/very/long/path';
- expect(collapsePath(path, 10)).toBe('my/.../very/long/path');
- expect(collapsePath(path, 5)).toBe('my/.../long/path');
- expect(collapsePath(path, 2)).toBe('my/.../path');
- });
-});
-
-describe('splitPath', () => {
- it('should split path properly', () => {
- expect(splitPath('my/super/path')).toEqual({ head: 'my/super', tail: 'path' });
- expect(splitPath('my/super/very/long/path')).toEqual({
- head: 'my/super/very/long',
- tail: 'path',
- });
- });
-});
-
-describe('limitComponentName', () => {
- const name = 'my/super/name';
-
- it('should fail fast if component name is not a string', () => {
- expect(limitComponentName({} as string)).toBe('');
- });
-
- it('should limiit component name longer than the limit', () => {
- expect(limitComponentName(name)).toBe(name);
- expect(limitComponentName(name, 10)).toBe('my/super/n...');
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/permissions-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/permissions-test.ts
deleted file mode 100644
index 1c371edf826..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/permissions-test.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { convertToPermissionDefinitions } from '../permissions';
-
-jest.mock('../l10nBundle', () => ({
- getMessages: jest.fn().mockReturnValue({}),
-}));
-
-describe('convertToPermissionDefinitions', () => {
- it('should convert and translate a permission definition', () => {
- const data = convertToPermissionDefinitions(['admin'], 'global_permissions');
- const expected = [
- {
- description: 'global_permissions.admin.desc',
- key: 'admin',
- name: 'global_permissions.admin',
- },
- ];
-
- expect(data).toEqual(expected);
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/projectLinks-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/projectLinks-test.ts
deleted file mode 100644
index a0d92b076f5..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/projectLinks-test.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getLinkName, isProvided, orderLinks } from '../projectLinks';
-
-it('#isProvided', () => {
- expect(isProvided({ type: 'homepage' })).toBe(true);
- expect(isProvided({ type: 'custom' })).toBe(false);
-});
-
-it('#orderLinks', () => {
- const homepage = { type: 'homepage' };
- const issues = { type: 'issue' };
- const foo = { name: 'foo', type: 'foo' };
- const bar = { name: 'bar', type: 'bar' };
- expect(orderLinks([foo, homepage, issues, bar])).toEqual([homepage, issues, bar, foo]);
- expect(orderLinks([foo, bar])).toEqual([bar, foo]);
- expect(orderLinks([issues, homepage])).toEqual([homepage, issues]);
-});
-
-it('#getLinkName', () => {
- expect(getLinkName({ type: 'homepage' })).toBe('project_links.homepage');
- expect(getLinkName({ name: 'foo', type: 'custom' })).toBe('foo');
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/projects-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/projects-test.ts
deleted file mode 100644
index 2a8dcb2d257..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/projects-test.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ProjectKeyValidationResult } from '../../types/component';
-import { PROJECT_KEY_MAX_LEN } from '../constants';
-import { validateProjectKey } from '../projects';
-
-describe('validateProjectKey', () => {
- it('should correctly flag an invalid key', () => {
- // Cannot have special characters except whitelist.
- expect(validateProjectKey('foo/bar')).toBe(ProjectKeyValidationResult.InvalidChar);
- // Cannot contain only numbers.
- expect(validateProjectKey('123')).toBe(ProjectKeyValidationResult.OnlyDigits);
- // Cannot be more than 400 chars long.
- expect(validateProjectKey(new Array(PROJECT_KEY_MAX_LEN + 1).fill('a').join(''))).toBe(
- ProjectKeyValidationResult.TooLong,
- );
- // Cannot be empty.
- expect(validateProjectKey('')).toBe(ProjectKeyValidationResult.Empty);
- });
-
- it('should not flag a valid key', () => {
- expect(validateProjectKey('foo:bar_baz-12.is')).toBe(ProjectKeyValidationResult.Valid);
- expect(validateProjectKey('12:34')).toBe(ProjectKeyValidationResult.Valid);
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/qualityGates-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/qualityGates-test.ts
deleted file mode 100644
index d33628344a2..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/qualityGates-test.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- mockQualityGateApplicationStatus,
- mockQualityGateProjectStatus,
-} from '../mocks/quality-gates';
-import {
- extractStatusConditionsFromApplicationStatusChildProject,
- extractStatusConditionsFromProjectStatus,
-} from '../qualityGates';
-
-describe('extractStatusConditionsFromProjectStatus', () => {
- it('should correclty extract the conditions for the project status', () => {
- expect(extractStatusConditionsFromProjectStatus(mockQualityGateProjectStatus())).toEqual([
- {
- actual: '0',
- error: '1.0',
- level: 'OK',
- metric: 'new_bugs',
- op: 'GT',
- period: 1,
- },
- ]);
- });
-});
-
-describe('extractStatusConditionsFromApplicationStatusChildProject', () => {
- it('should correclty extract the conditions for the application child project status', () => {
- expect(
- extractStatusConditionsFromApplicationStatusChildProject(
- mockQualityGateApplicationStatus().projects[0],
- ),
- ).toEqual([
- {
- actual: '10',
- error: '1.0',
- level: 'ERROR',
- metric: 'coverage',
- op: 'GT',
- period: undefined,
- },
- {
- actual: '5',
- error: '1.0',
- level: 'ERROR',
- metric: 'new_bugs',
- op: 'GT',
- period: 1,
- },
- ]);
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/query-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/query-test.ts
deleted file mode 100644
index bc921f82ec4..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/query-test.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { parseDate } from '../dates';
-import * as query from '../query';
-
-describe('queriesEqual', () => {
- it('should correctly test equality of two queries', () => {
- expect(query.queriesEqual({ a: 'test', b: 'test' }, { a: 'test', b: 'test' })).toBe(true);
- expect(query.queriesEqual({ a: [1, 2], b: 'test' }, { a: [1, 2], b: 'test' })).toBe(true);
- expect(query.queriesEqual({ a: 'a' }, { a: 'test', b: 'test' })).toBe(false);
- expect(query.queriesEqual({ a: [1, 2], b: 'test' }, { a: [1], b: 'test' })).toBe(false);
- });
-});
-
-describe('cleanQuery', () => {
- it('should remove undefined and null query items', () => {
- expect(query.cleanQuery({ a: 'b', b: undefined, c: null, d: '', e: 0 })).toMatchSnapshot();
- });
-});
-
-describe('parseAsBoolean', () => {
- it('should parse booleans correctly', () => {
- expect(query.parseAsBoolean('false')).toBe(false);
- expect(query.parseAsBoolean('true')).toBe(true);
- });
-
- it('should return a default value', () => {
- expect(query.parseAsBoolean('1')).toBe(true);
- expect(query.parseAsBoolean('foo')).toBe(true);
- });
-});
-
-describe('parseAsString', () => {
- it('should parse strings correctly', () => {
- expect(query.parseAsString('random')).toBe('random');
- expect(query.parseAsString('')).toBe('');
- expect(query.parseAsString(undefined)).toBe('');
- });
-});
-
-describe('parseAsArray', () => {
- it('should parse string arrays correctly', () => {
- expect(query.parseAsArray('1,2,3', query.parseAsString)).toEqual(['1', '2', '3']);
- expect(query.parseAsArray(undefined, query.parseAsString)).toEqual([]);
- });
-});
-
-describe('parseAsOptionalArray', () => {
- it('should parse optional arrays correctly', () => {
- expect(query.parseAsOptionalArray('true,false,false', query.parseAsBoolean)).toEqual([
- true,
- false,
- false,
- ]);
- expect(query.parseAsOptionalArray(undefined, query.parseAsString)).toBeUndefined();
- });
-});
-
-describe('parseAsDate', () => {
- it('should parse string date correctly', () => {
- expect(query.parseAsDate('2016-06-20T13:09:48.256Z')).toMatchSnapshot();
- expect(query.parseAsDate('')).toBeUndefined();
- expect(query.parseAsDate()).toBeUndefined();
- });
-});
-
-describe('serializeDate', () => {
- const date = parseDate('2016-06-20T13:09:48.256Z');
- it('should serialize string correctly', () => {
- expect(query.serializeDate(date)).toBe('2016-06-20T13:09:48+0000');
- expect(query.serializeDate()).toBeUndefined();
- });
-});
-
-describe('serializeString', () => {
- it('should serialize string correctly', () => {
- expect(query.serializeString('foo')).toBe('foo');
- expect(query.serializeString('')).toBeUndefined();
- });
-});
-
-describe('serializeStringArray', () => {
- it('should serialize array of string correctly', () => {
- expect(query.serializeStringArray(['1', '2', '3'])).toBe('1,2,3');
- expect(query.serializeStringArray([])).toBeUndefined();
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/ratings-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/ratings-test.ts
deleted file mode 100644
index 44b5299f5b4..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/ratings-test.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- getCoverageRatingAverageValue,
- getCoverageRatingLabel,
- getDuplicationsRatingLabel,
- getSizeRatingAverageValue,
- getSizeRatingLabel,
-} from '../ratings';
-
-describe('getCoverageRatingLabel', () => {
- it('should fail', () => {
- expect(() => {
- getCoverageRatingLabel(-1);
- }).toThrow();
- });
- it.each([
- [1, '≥ 80%'],
- [2, '70% - 80%'],
- [3, '50% - 70%'],
- [4, '30% - 50%'],
- [5, '< 30%'],
- ])('should return the correct label for %s', (rating, label) => {
- expect(getCoverageRatingLabel(rating)).toBe(label);
- });
-});
-
-describe('getCoverageRatingAverageValue', () => {
- it.each([
- [1, 90],
- [2, 75],
- [3, 60],
- [4, 40],
- [5, 15],
- ])('should return the correct value', (rating, value) => {
- expect(getCoverageRatingAverageValue(rating)).toBe(value);
- });
-});
-
-describe('getDuplicationsRatingLabel', () => {
- it('should fail', () => {
- expect(() => {
- getCoverageRatingLabel(-1);
- }).toThrow();
- });
- it.each([
- [1, '< 3%'],
- [2, '3% - 5%'],
- [3, '5% - 10%'],
- [4, '10% - 20%'],
- [5, '> 20%'],
- ])('should return the correct label for %s', (rating, label) => {
- expect(getDuplicationsRatingLabel(rating)).toBe(label);
- });
-});
-
-describe('getSizeRatingLabel', () => {
- it('should fail', () => {
- expect(() => {
- getCoverageRatingLabel(-1);
- }).toThrow();
- });
- it.each([
- [1, '< 1k'],
- [2, '1k - 10k'],
- [3, '10k - 100k'],
- [4, '100k - 500k'],
- [5, '> 500k'],
- ])('should return the correct label for %s', (rating, label) => {
- expect(getSizeRatingLabel(rating)).toBe(label);
- });
-});
-
-describe('getSizeRatingAverageValue', () => {
- it.each([
- [1, 500],
- [2, 5000],
- [3, 50000],
- [4, 250000],
- [5, 750000],
- ])('should return the correct value', (rating, value) => {
- expect(getSizeRatingAverageValue(rating)).toBe(value);
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/request-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/request-test.ts
deleted file mode 100644
index 00801470f44..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/request-test.ts
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* eslint-disable no-await-in-loop */
-
-import { setImmediate } from 'timers';
-import { Dict } from '../../types/types';
-import handleRequiredAuthentication from '../handleRequiredAuthentication';
-import {
- checkStatus,
- getText,
- HttpStatus,
- isSuccessStatus,
- parseError,
- parseJSON,
- parseText,
- post,
- postJSON,
- postJSONBody,
- requestTryAndRepeatUntil,
-} from '../request';
-
-jest.mock('../handleRequiredAuthentication', () => jest.fn());
-
-const url = '/my-url';
-
-beforeEach(() => {
- jest.clearAllMocks();
- window.fetch = jest.fn().mockResolvedValue(mockResponse({}, HttpStatus.Ok, {}));
-});
-
-describe('getText', () => {
- it('should get text without parameters', async () => {
- const response = mockResponse({}, HttpStatus.Ok, '');
- window.fetch = jest.fn().mockResolvedValue(response);
- getText(url);
- await new Promise(setImmediate);
-
- expect(window.fetch).toHaveBeenCalledWith(url, expect.objectContaining({ method: 'GET' }));
- expect(response.text).toHaveBeenCalled();
- });
-
- it('should get text with parameters', () => {
- getText(url, { data: 'test' });
- expect(window.fetch).toHaveBeenCalledWith(
- url + '?data=test',
- expect.objectContaining({ method: 'GET' }),
- );
- });
-});
-
-describe('parseError', () => {
- it('should parse error and return the message', async () => {
- const response = new Response(JSON.stringify({ errors: [{ msg: 'Error1' }] }), {
- status: HttpStatus.BadRequest,
- });
- await expect(parseError(response)).resolves.toBe('Error1');
- });
-
- it('should parse error and return concatenated messages', async () => {
- const response = new Response(
- JSON.stringify({ errors: [{ msg: 'Error1' }, { msg: 'Error2' }] }),
- { status: HttpStatus.BadRequest },
- );
- await expect(parseError(response)).resolves.toBe('Error1. Error2');
- });
-
- it('should parse error and return default message', async () => {
- const response = new Response('{}', { status: HttpStatus.BadRequest });
- await expect(parseError(response)).resolves.toBe('default_error_message');
- const responseUndefined = new Response('', { status: HttpStatus.BadRequest });
- await expect(parseError(responseUndefined)).resolves.toBe('default_error_message');
- });
-});
-
-describe('parseJSON', () => {
- it('should return a json response', () => {
- const body = { test: 2 };
- const response = mockResponse({}, HttpStatus.Ok, body);
- const jsonResponse = parseJSON(response);
- expect(response.json).toHaveBeenCalled();
- return expect(jsonResponse).resolves.toEqual(body);
- });
-});
-
-describe('parseText', () => {
- it('should return a text response', () => {
- const body = 'test';
- const response = mockResponse({}, HttpStatus.Ok, body);
- const textResponse = parseText(response);
- expect(response.text).toHaveBeenCalled();
- return expect(textResponse).resolves.toBe(body);
- });
-});
-
-describe('postJSON', () => {
- it('should post without parameters and get json', async () => {
- const response = mockResponse();
- window.fetch = jest.fn().mockResolvedValue(response);
- postJSON(url);
- await new Promise(setImmediate);
-
- expect(window.fetch).toHaveBeenCalledWith(url, expect.objectContaining({ method: 'POST' }));
- expect(response.json).toHaveBeenCalled();
- });
-
- it('should post with a body and get json', () => {
- postJSON(url, { data: 'test' });
- expect(window.fetch).toHaveBeenCalledWith(
- url,
- expect.objectContaining({ body: 'data=test', method: 'POST' }),
- );
- });
-});
-
-describe('postJSONBody', () => {
- it('should post without parameters and get json', async () => {
- const response = mockResponse();
- window.fetch = jest.fn().mockResolvedValue(response);
- postJSONBody(url);
- await new Promise(setImmediate);
-
- expect(window.fetch).toHaveBeenCalledWith(url, expect.objectContaining({ method: 'POST' }));
- expect(response.json).toHaveBeenCalled();
- });
-
- it('should post with a body and get json', () => {
- postJSONBody(url, { nested: { data: 'test', withArray: [1, 2] } });
- expect(window.fetch).toHaveBeenCalledWith(
- url,
- expect.objectContaining({
- headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
- body: '{"nested":{"data":"test","withArray":[1,2]}}',
- method: 'POST',
- }),
- );
- });
-});
-
-describe('post', () => {
- it('should post without parameters and return nothing', async () => {
- const response = mockResponse();
- window.fetch = jest.fn().mockResolvedValue(response);
- post(url, { data: 'test' });
- await new Promise(setImmediate);
-
- expect(window.fetch).toHaveBeenCalledWith(
- url,
- expect.objectContaining({ body: 'data=test', method: 'POST' }),
- );
- expect(response.json).not.toHaveBeenCalled();
- expect(response.text).not.toHaveBeenCalled();
- });
-
- it('should handle array values', async () => {
- const response = mockResponse();
- window.fetch = jest.fn().mockResolvedValue(response);
- post(url, { dataArray: ['1', '2'] });
- await new Promise(setImmediate);
-
- expect(window.fetch).toHaveBeenCalledWith(
- url,
- expect.objectContaining({ body: 'dataArray=1&dataArray=2', method: 'POST' }),
- );
- });
-});
-
-describe('requestTryAndRepeatUntil', () => {
- beforeEach(() => {
- jest.clearAllTimers();
- jest.useFakeTimers();
- });
-
- afterEach(() => {
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
- });
-
- it('should repeat call until stop condition is met', async () => {
- const apiCall = jest.fn().mockResolvedValue({ repeat: true });
- const stopRepeat = jest.fn().mockImplementation(({ repeat }) => !repeat);
-
- const promiseResult = requestTryAndRepeatUntil(
- apiCall,
- { max: -1, slowThreshold: -20 },
- stopRepeat,
- );
-
- for (let i = 1; i < 5; i++) {
- jest.runAllTimers();
- expect(apiCall).toHaveBeenCalledTimes(i);
- await new Promise(setImmediate);
- expect(stopRepeat).toHaveBeenCalledTimes(i);
- }
- apiCall.mockResolvedValue({ repeat: false });
- jest.runAllTimers();
- expect(apiCall).toHaveBeenCalledTimes(5);
- await new Promise(setImmediate);
- expect(stopRepeat).toHaveBeenCalledTimes(5);
-
- await expect(promiseResult).resolves.toEqual({ repeat: false });
- });
-
- it('should repeat call as long as there is an error', async () => {
- const apiCall = jest.fn().mockRejectedValue({ status: HttpStatus.GatewayTimeout });
- const stopRepeat = jest.fn().mockReturnValue(true);
- const promiseResult = requestTryAndRepeatUntil(
- apiCall,
- { max: -1, slowThreshold: -20 },
- stopRepeat,
- [HttpStatus.GatewayTimeout],
- );
-
- for (let i = 1; i < 5; i++) {
- jest.runAllTimers();
- expect(apiCall).toHaveBeenCalledTimes(i);
- await new Promise(setImmediate);
- }
- apiCall.mockResolvedValue('Success');
- jest.runAllTimers();
- expect(apiCall).toHaveBeenCalledTimes(5);
- await new Promise(setImmediate);
- expect(stopRepeat).toHaveBeenCalledTimes(1);
-
- await expect(promiseResult).resolves.toBe('Success');
- });
-
- it('should stop after 3 calls', async () => {
- const apiCall = jest.fn().mockResolvedValue({});
- const stopRepeat = jest.fn().mockReturnValue(false);
- const promiseResult = requestTryAndRepeatUntil(
- apiCall,
- { max: 3, slowThreshold: 0 },
- stopRepeat,
- );
-
- for (let i = 1; i < 3; i++) {
- expect(apiCall).toHaveBeenCalledTimes(i);
- await new Promise(setImmediate);
- jest.runAllTimers();
- }
- expect(apiCall).toHaveBeenCalledTimes(3);
- await expect(promiseResult).rejects.toBeUndefined();
-
- // It should not call anymore after 3 times
- jest.runAllTimers();
- expect(apiCall).toHaveBeenCalledTimes(3);
- });
-
- it('should slow down after 2 calls', async () => {
- const apiCall = jest.fn().mockResolvedValue({});
- const stopRepeat = jest.fn().mockReturnValue(false);
- const promiseResult = requestTryAndRepeatUntil(
- apiCall,
- { max: 5, slowThreshold: 3 },
- stopRepeat,
- );
-
- for (let i = 1; i < 3; i++) {
- jest.advanceTimersByTime(500);
- expect(apiCall).toHaveBeenCalledTimes(i);
- await new Promise(setImmediate);
- }
-
- jest.advanceTimersByTime(500);
- expect(apiCall).toHaveBeenCalledTimes(2);
- jest.advanceTimersByTime(2000);
- expect(apiCall).toHaveBeenCalledTimes(2);
- jest.advanceTimersByTime(500);
- expect(apiCall).toHaveBeenCalledTimes(3);
- await new Promise(setImmediate);
-
- jest.advanceTimersByTime(3000);
- expect(apiCall).toHaveBeenCalledTimes(4);
-
- await new Promise(setImmediate);
- jest.runAllTimers();
- expect(apiCall).toHaveBeenCalledTimes(5);
-
- await expect(promiseResult).rejects.toBeUndefined();
- });
-});
-
-describe('checkStatus', () => {
- it('should resolve with the response', async () => {
- const response = mockResponse();
- await expect(checkStatus(response)).resolves.toBe(response);
- });
-
- it('should reject with the response', async () => {
- const response = mockResponse({}, HttpStatus.InternalServerError);
- await expect(checkStatus(response)).rejects.toEqual(response);
- });
-
- it('should handle required authentication', async () => {
- await checkStatus(mockResponse({}, HttpStatus.Unauthorized)).catch(() => {});
- expect(handleRequiredAuthentication).toHaveBeenCalled();
- });
-
- it('should bybass the redirect with a 401 error', async () => {
- const mockedResponse = mockResponse({}, HttpStatus.Unauthorized);
- await expect(checkStatus(mockedResponse, true)).rejects.toBe(mockedResponse);
- expect(handleRequiredAuthentication).not.toHaveBeenCalled();
- });
-});
-it('should export status codes', () => {
- expect(HttpStatus.NotFound).toEqual(404);
-});
-
-describe('isSuccessStatus', () => {
- it('should work for a successful response status', () => {
- expect(isSuccessStatus(HttpStatus.Ok)).toBe(true);
- expect(isSuccessStatus(HttpStatus.Created)).toBe(true);
- });
-
- it('should work for an unsuccessful response status', () => {
- expect(isSuccessStatus(HttpStatus.MultipleChoices)).toBe(false);
- expect(isSuccessStatus(HttpStatus.NotFound)).toBe(false);
- expect(isSuccessStatus(HttpStatus.InternalServerError)).toBe(false);
- });
-});
-
-function mockResponse(headers: Dict<string> = {}, status = HttpStatus.Ok, value?: any): Response {
- const body = value && value instanceof Object ? JSON.stringify(value) : value;
- const response = new Response(body, { headers, status });
- response.json = jest.fn().mockResolvedValue(value);
- response.text = jest.fn().mockResolvedValue(value);
- return response;
-}
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/security-standard-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/security-standard-test.ts
deleted file mode 100644
index de456248356..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/security-standard-test.ts
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Standards } from '../../types/security';
-import {
- renderCASACategory,
- renderCWECategory,
- renderOwaspAsvs40Category,
- renderOwaspTop10Category,
- renderPciDss32Category,
- renderPciDss40Category,
- renderSonarSourceSecurityCategory,
- renderStigCategory,
-} from '../security-standard';
-
-describe('standards renderers', () => {
- const standards: Standards = {
- cwe: {
- '1004': {
- title: "Sensitive Cookie Without 'HttpOnly' Flag",
- },
- unknown: {
- title: 'No CWE associated',
- },
- },
- owaspTop10: {
- a1: {
- title: 'Injection',
- },
- },
- 'owaspTop10-2021': {
- a1: {
- title: 'Injection',
- },
- },
- sonarsourceSecurity: {
- xss: {
- title: 'Cross-Site Scripting (XSS)',
- },
- others: {
- title: 'Others',
- },
- },
- 'pciDss-3.2': {
- '1': {
- title: 'Install and maintain a firewall configuration to protect cardholder data',
- },
- },
- 'pciDss-4.0': {
- '1': {
- title: 'Install and maintain a firewall configuration to protect cardholder data',
- },
- },
- 'owaspAsvs-4.0': {
- '1': {
- title: 'Main category',
- },
- '1.1': {
- title: 'Sub category',
- level: '2',
- },
- },
- casa: {
- '1': {
- title: 'Main category',
- },
- },
- 'stig-ASD_V5R3': {
- 'v-123': {
- title: 'Stig requirement',
- },
- },
- };
-
- it('should render cwe categories correctly', () => {
- expect(renderCWECategory(standards, '1004')).toEqual(
- "CWE-1004 - Sensitive Cookie Without 'HttpOnly' Flag",
- );
- expect(renderCWECategory(standards, '124')).toEqual('CWE-124');
- expect(renderCWECategory(standards, 'unknown')).toEqual('No CWE associated');
- });
-
- it('should render owasp categories correctly', () => {
- expect(renderOwaspTop10Category(standards, 'a1')).toEqual('A1 - Injection');
- expect(renderOwaspTop10Category(standards, 'a1', true)).toEqual('OWASP A1 - Injection');
- expect(renderOwaspTop10Category(standards, 'a2')).toEqual('A2');
- expect(renderOwaspTop10Category(standards, 'a2', true)).toEqual('OWASP A2');
- });
-
- it('should render OwaspAsvs 4.0 correctly', () => {
- expect(renderOwaspAsvs40Category(standards, '1')).toEqual('1 - Main category');
- expect(renderOwaspAsvs40Category(standards, '1.1')).toEqual('1.1 - Sub category (Level 2)');
- });
-
- it('should render Pci Dss 3.2 correctly', () => {
- expect(renderPciDss32Category(standards, '1')).toEqual(
- '1 - Install and maintain a firewall configuration to protect cardholder data',
- );
- expect(renderPciDss32Category(standards, '1.1')).toEqual('1.1');
- });
-
- it('should render Pci Dss 4.0 correctly', () => {
- expect(renderPciDss40Category(standards, '1')).toEqual(
- '1 - Install and maintain a firewall configuration to protect cardholder data',
- );
- expect(renderPciDss40Category(standards, '1.1')).toEqual('1.1');
- });
-
- it('should render sonarsource categories correctly', () => {
- expect(renderSonarSourceSecurityCategory(standards, 'xss')).toEqual(
- 'Cross-Site Scripting (XSS)',
- );
- expect(renderSonarSourceSecurityCategory(standards, 'xss', true)).toEqual(
- 'SONAR Cross-Site Scripting (XSS)',
- );
- expect(renderSonarSourceSecurityCategory(standards, 'others')).toEqual('Others');
- expect(renderSonarSourceSecurityCategory(standards, 'others', true)).toEqual('Others');
- });
-
- it('should render casa categories correctly', () => {
- expect(renderCASACategory(standards, '1')).toEqual('1 - Main category');
- expect(renderCASACategory(standards, '2')).toEqual('2');
- });
-
- it('should render stig requirements correctly', () => {
- expect(renderStigCategory(standards, 'v-123')).toEqual('v-123 - Stig requirement');
- expect(renderStigCategory(standards, 'none')).toEqual('none');
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/sonarlint-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/sonarlint-test.ts
deleted file mode 100644
index 920728b1388..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/sonarlint-test.ts
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { NewUserToken, TokenType } from '../../types/token';
-import { HttpStatus } from '../request';
-import {
- buildPortRange,
- openFixOrIssueInSonarLint,
- openHotspot,
- portIsValid,
- probeSonarLintServers,
- sendUserToken,
- SONARLINT_PORT_RANGE,
- SONARLINT_PORT_START,
-} from '../sonarlint';
-
-const PROJECT_KEY = 'my-project:key';
-
-describe('buildPortRange', () => {
- it('should build a port range of size <size> starting at port <port>', () => {
- expect(buildPortRange(SONARLINT_PORT_START, 5)).toStrictEqual([
- SONARLINT_PORT_START,
- SONARLINT_PORT_START + 1,
- SONARLINT_PORT_START + 2,
- SONARLINT_PORT_START + 3,
- SONARLINT_PORT_START + 4,
- ]);
- });
-});
-
-describe('probeSonarLintServers', () => {
- const sonarLintResponse = { description: 'Hello World', ideName: 'BlueJ IDE', needsToken: true };
-
- window.fetch = jest.fn((input: string) => {
- const calledPort = new URL(input).port;
-
- if (calledPort === SONARLINT_PORT_START.toString()) {
- const resp = new Response();
-
- resp.json = () => Promise.resolve(sonarLintResponse);
-
- return Promise.resolve(resp);
- }
-
- return Promise.reject(new Error('oops'));
- });
-
- it('should probe all ports in range', async () => {
- const results = await probeSonarLintServers();
-
- expect(results).toStrictEqual([{ port: SONARLINT_PORT_START, ...sonarLintResponse }]);
- });
-});
-
-describe('openHotspot', () => {
- it('should send the correct request to the IDE to open a hotspot', async () => {
- const resp = new Response();
-
- window.fetch = jest.fn((input: string) => {
- const calledUrl = new URL(input);
-
- try {
- expect(calledUrl.searchParams.get('server')).toStrictEqual('http://localhost');
- expect(calledUrl.searchParams.get('project')).toStrictEqual(PROJECT_KEY);
- expect(calledUrl.searchParams.get('hotspot')).toStrictEqual('my-hotspot-key');
- } catch (error) {
- return Promise.reject(error);
- }
-
- return Promise.resolve(resp);
- });
-
- const result = await openHotspot(SONARLINT_PORT_START, PROJECT_KEY, 'my-hotspot-key');
-
- expect(result).toBe(resp);
- });
-});
-
-describe('open ide', () => {
- it('should send the correct request to the IDE to open an issue', async () => {
- let branchName: string | undefined = undefined;
- let pullRequestID: string | undefined = undefined;
- let tokenName: string | undefined = undefined;
- let tokenValue: string | undefined = undefined;
- const issueKey = 'my-issue-key';
- const resp = new Response();
-
- window.fetch = jest.fn((input: RequestInfo) => {
- const calledUrl = new URL(input.toString());
-
- try {
- expect(calledUrl.searchParams.get('server')).toStrictEqual('http://localhost');
- expect(calledUrl.searchParams.get('project')).toStrictEqual(PROJECT_KEY);
- expect(calledUrl.searchParams.get('issue')).toStrictEqual(issueKey);
- // eslint-disable-next-line jest/no-conditional-in-test
- expect(calledUrl.searchParams.get('branch') ?? undefined).toStrictEqual(branchName);
- // eslint-disable-next-line jest/no-conditional-in-test
- expect(calledUrl.searchParams.get('pullRequest') ?? undefined).toStrictEqual(pullRequestID);
- // eslint-disable-next-line jest/no-conditional-in-test
- expect(calledUrl.searchParams.get('tokenName') ?? undefined).toStrictEqual(tokenName);
- // eslint-disable-next-line jest/no-conditional-in-test
- expect(calledUrl.searchParams.get('tokenValue') ?? undefined).toStrictEqual(tokenValue);
- } catch (error) {
- return Promise.reject(error);
- }
-
- return Promise.resolve(resp);
- });
-
- type OpenIssueParams = Parameters<typeof openFixOrIssueInSonarLint>[0];
- type PartialOpenIssueParams = Partial<OpenIssueParams>;
- let params: PartialOpenIssueParams = {};
-
- const testWith = async (args: PartialOpenIssueParams) => {
- params = { ...params, ...args };
- const result = await openFixOrIssueInSonarLint(params as OpenIssueParams);
- expect(result).toBe(resp);
- };
-
- await testWith({
- calledPort: SONARLINT_PORT_START,
- issueKey,
- projectKey: PROJECT_KEY,
- });
-
- branchName = 'branch-1';
- await testWith({ branchLike: { name: branchName, isMain: false, excludedFromPurge: false } });
-
- pullRequestID = 'pr-1';
- await testWith({
- branchLike: {
- key: pullRequestID,
- branch: branchName,
- name: branchName,
- base: 'foo',
- target: 'bar',
- title: 'test',
- },
- });
-
- tokenName = 'token-name';
- tokenValue = 'token-value';
- await testWith({ token: { token: tokenValue, name: tokenName } as NewUserToken });
- });
-});
-
-describe('portIsValid', () => {
- it.each([
- [SONARLINT_PORT_START - 1, false],
- [SONARLINT_PORT_START, true],
- [SONARLINT_PORT_START + SONARLINT_PORT_RANGE - 1, true],
- [SONARLINT_PORT_START + SONARLINT_PORT_RANGE, false],
- [SONARLINT_PORT_START + SONARLINT_PORT_RANGE + 1, false],
- ])('should validate port %s is within the expected range', (port, expectation) => {
- expect(portIsValid(port)).toBe(expectation);
- });
-});
-
-describe('sendUserToken', () => {
- it('should send the token the right port', async () => {
- const token = {
- createdAt: '12-12-2018',
- expirationDate: '17-02-2019',
- login: 'Takeshi',
- name: 'sonarlint-vscode-1',
- token: '78gfh78d6gf8h',
- type: TokenType.User,
- };
-
- const resp = new Response();
-
- window.fetch = jest.fn((_url, { body }: RequestInit) => {
- try {
- const data = JSON.parse((body as BodyInit).toString());
-
- expect(data).toEqual(token);
- } catch (error) {
- return Promise.reject(error);
- }
-
- return Promise.resolve(resp);
- });
-
- const result = await sendUserToken(SONARLINT_PORT_START, { ...token, isExpired: false });
-
- expect(result).toBeUndefined();
- });
-
- it('should handle errors', async () => {
- const token = {
- createdAt: '12-12-2018',
- expirationDate: '17-02-2019',
- login: 'Takeshi',
- name: 'sonarlint-vscode-1',
- token: '78gfh78d6gf8h',
- type: TokenType.User,
- };
-
- const resp = new Response('Meh', { status: HttpStatus.BadRequest, statusText: 'I no likez' });
-
- window.fetch = jest.fn(() => {
- return Promise.resolve(resp);
- });
-
- await expect(async () => {
- await sendUserToken(SONARLINT_PORT_START, { ...token, isExpired: false });
- }).rejects.toThrow('400 I no likez. Meh');
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/stringify-queryparams-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/stringify-queryparams-test.ts
deleted file mode 100644
index c490497d781..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/stringify-queryparams-test.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { stringify } from '../stringify-queryparams';
-
-describe('stringify', () => {
- it('should properly format query params object', () => {
- const obj = {
- prop1: 'a string',
- prop2: 123,
- prop3: true,
- prop4: '',
- prop5: [9, 8, 7],
- prop6: { test: 'test' },
- };
-
- expect(stringify(obj)).toEqual(
- 'prop1=a%20string&prop2=123&prop3=true&prop4=&prop5=9&prop5=8&prop5=7&prop6=',
- );
- });
-
- it('should return empty if name is not defined', () => {
- expect(stringify('test_obj', undefined, undefined, undefined)).toEqual('');
- });
-
- it('should properly format a query param', () => {
- expect(stringify('test_obj', undefined, undefined, 'test_name')).toEqual('test_name=test_obj');
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/strings-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/strings-test.ts
deleted file mode 100644
index 67228a2f376..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/strings-test.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { decodeJwt, latinize } from '../strings';
-
-describe('#decodeJwt', () => {
- it('should correctly decode a jwt token', () => {
- const claims = {
- aud: 'ari:cloud:bitbucket::app/{327713ed-f1b2-4659-9c91-c8ecf8be7f3e}/sonarcloud-greg',
- exp: 1541062205,
- iat: 1541058605,
- iss: 'ari:cloud:bitbucket::app/{327713ed-f1b2-4659-9c91-c8ecf8be7f3e}/sonarcloud-greg',
- qsh: 'a6c93addd971c05d08da1e1669c2640fba529e98fbb5b2b9effadf00bf484277',
- };
- expect(
- decodeJwt(
- 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhcmk6Y2xvdWQ6Yml0YnVja2V0OjphcHAvezMyNzcxM2VkLWYxYjItNDY1OS05YzkxLWM4ZWNmOGJlN2YzZX0vc29uYXJjbG91ZC1ncmVnIiwiaWF0IjoxNTQxMDU4NjA1LCJxc2giOiJhNmM5M2FkZGQ5NzFjMDVkMDhkYTFlMTY2OWMyNjQwZmJhNTI5ZTk4ZmJiNWIyYjllZmZhZGYwMGJmNDg0Mjc3IiwiYXVkIjoiYXJpOmNsb3VkOmJpdGJ1Y2tldDo6YXBwL3szMjc3MTNlZC1mMWIyLTQ2NTktOWM5MS1jOGVjZjhiZTdmM2V9L3NvbmFyY2xvdWQtZ3JlZyIsImV4cCI6MTU0MTA2MjIwNX0.5_0dFh_TPT_UorDewu2JEErgQE2ZnzBjvCDrOThseRo',
- ),
- ).toEqual(claims);
- expect(
- decodeJwt(
- 'eyJpc3MiOiJhcmk6Y2xvdWQ6Yml0YnVja2V0OjphcHAvezMyNzcxM2VkLWYxYjItNDY1OS05YzkxLWM4ZWNmOGJlN2YzZX0vc29uYXJjbG91ZC1ncmVnIiwiaWF0IjoxNTQxMDU4NjA1LCJxc2giOiJhNmM5M2FkZGQ5NzFjMDVkMDhkYTFlMTY2OWMyNjQwZmJhNTI5ZTk4ZmJiNWIyYjllZmZhZGYwMGJmNDg0Mjc3IiwiYXVkIjoiYXJpOmNsb3VkOmJpdGJ1Y2tldDo6YXBwL3szMjc3MTNlZC1mMWIyLTQ2NTktOWM5MS1jOGVjZjhiZTdmM2V9L3NvbmFyY2xvdWQtZ3JlZyIsImV4cCI6MTU0MTA2MjIwNX0',
- ),
- ).toEqual(claims);
- });
-});
-
-describe('#latinize', () => {
- it('should remove diacritics and replace them with normal letters', () => {
- expect(latinize('âêîôûŵŷäëïöüẅÿàèìòùẁỳáéíóúẃýøāēīūčģķļņšž')).toBe(
- 'aeiouwyaeiouwyaeiouwyaeiouwyoaeiucgklnsz',
- );
- expect(latinize('ASDFGhjklQWERTz')).toBe('ASDFGhjklQWERTz');
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/system-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/system-test.ts
deleted file mode 100644
index 56a98e50244..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/system-test.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { AppVariablesElement } from '../../types/browser';
-import { InstanceType } from '../../types/system';
-import { initAppVariables } from '../system';
-
-// Faking window so we don't pollute real window set in /config/jest/SetupTestEnvironment
-const fakeWindow = {};
-jest.mock('../browser', () => ({
- getEnhancedWindow: jest.fn(() => fakeWindow),
-}));
-
-afterEach(() => {
- jest.restoreAllMocks();
-});
-
-describe('initAppVariables', () => {
- it('should correctly init app variables', () => {
- const dataset: AppVariablesElement['dataset'] = {
- baseUrl: 'test/base-url',
- serverStatus: 'DOWN',
- instance: InstanceType.SonarQube,
- official: 'false',
- };
-
- const appVariablesElement = document.querySelector('#content') as AppVariablesElement;
- Object.assign(appVariablesElement.dataset, dataset);
-
- initAppVariables();
-
- expect(fakeWindow).toEqual({
- ...dataset,
- official: Boolean(dataset.official),
- });
- });
-
- it('should throw error if app variables element is not found', () => {
- const querySelector = jest.spyOn(document, 'querySelector');
- querySelector.mockReturnValue(null);
-
- expect(initAppVariables).toThrow();
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/tokens-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/tokens-test.ts
deleted file mode 100644
index 727f0dad026..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/tokens-test.ts
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getAllValues } from '../../api/settings';
-import { SettingsKey } from '../../types/settings';
-import { TokenExpiration } from '../../types/token';
-import { mockSettingValue } from '../mocks/settings';
-import { mockUserToken } from '../mocks/token';
-import {
- computeTokenExpirationDate,
- EXPIRATION_OPTIONS,
- getAvailableExpirationOptions,
- getNextTokenName,
-} from '../tokens';
-
-jest.mock('../../api/settings', () => {
- return {
- getAllValues: jest.fn().mockResolvedValue([]),
- };
-});
-
-jest.mock('../dates', () => {
- return {
- ...jest.requireActual('../dates'),
- now: jest.fn(() => new Date('2022-06-01T12:00:00Z')),
- };
-});
-
-describe('getAvailableExpirationOptions', () => {
- it('should correctly return all options if no setting', async () => {
- expect(await getAvailableExpirationOptions()).toEqual(EXPIRATION_OPTIONS);
- });
-
- it('should correctly return all options if the max setting is no expiration', async () => {
- (getAllValues as jest.Mock).mockResolvedValueOnce([
- mockSettingValue({ key: SettingsKey.TokenMaxAllowedLifetime, value: 'No expiration' }),
- ]);
- expect(await getAvailableExpirationOptions()).toEqual(EXPIRATION_OPTIONS);
- });
-
- it('should correctly limit options if the max setting is 1 year', async () => {
- (getAllValues as jest.Mock).mockResolvedValueOnce([
- mockSettingValue({ key: SettingsKey.TokenMaxAllowedLifetime, value: '1 year' }),
- ]);
- expect(await getAvailableExpirationOptions()).toEqual(
- [TokenExpiration.OneMonth, TokenExpiration.ThreeMonths, TokenExpiration.OneYear].map(
- (value) => {
- return {
- value,
- label: `users.tokens.expiration.${value.toString()}`,
- };
- },
- ),
- );
- });
-
- it('should correctly limit options if the max setting is 3 months', async () => {
- (getAllValues as jest.Mock).mockResolvedValueOnce([
- mockSettingValue({ key: SettingsKey.TokenMaxAllowedLifetime, value: '90 days' }),
- ]);
- expect(await getAvailableExpirationOptions()).toEqual(
- [TokenExpiration.OneMonth, TokenExpiration.ThreeMonths].map((value) => {
- return {
- value,
- label: `users.tokens.expiration.${value.toString()}`,
- };
- }),
- );
- });
-
- it('should correctly limit options if the max setting is 30 days', async () => {
- (getAllValues as jest.Mock).mockResolvedValueOnce([
- mockSettingValue({ key: SettingsKey.TokenMaxAllowedLifetime, value: '30 days' }),
- ]);
- expect(await getAvailableExpirationOptions()).toEqual([
- {
- value: TokenExpiration.OneMonth,
- label: `users.tokens.expiration.${TokenExpiration.OneMonth.toString()}`,
- },
- ]);
- });
-});
-
-describe('computeTokenExpirationDate', () => {
- it.each([
- [TokenExpiration.OneMonth, '2022-07-01'],
- [TokenExpiration.ThreeMonths, '2022-08-30'],
- [TokenExpiration.OneYear, '2023-06-01'],
- ])('should correctly compute the proper expiration date for %s days', (days, expected) => {
- expect(computeTokenExpirationDate(days)).toBe(expected);
- });
-});
-
-describe('getNextTokenName', () => {
- it('should preserve the base name for the firts token', () => {
- const tokens = [mockUserToken({ name: 'whatever' })];
- const tokenName = 'sl-vscode';
-
- expect(getNextTokenName(tokenName, tokens)).toBe(tokenName);
- });
-
- it('should increment until the first available value', () => {
- const tokenName = 'sl-vscode';
- const tokens = [
- mockUserToken({ name: `${tokenName}` }),
- mockUserToken({ name: `${tokenName}-1` }),
- mockUserToken({ name: `${tokenName}-2` }),
- mockUserToken({ name: `${tokenName}-4` }),
- ];
-
- expect(getNextTokenName(tokenName, tokens)).toBe(`${tokenName}-3`);
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts
deleted file mode 100644
index a67dfa8c0dd..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { searchParamsToQuery } from '~sonar-aligned/helpers/router';
-import { queryToSearchString } from '~sonar-aligned/helpers/urls';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { AlmKeys } from '../../types/alm-settings';
-import { IssueType } from '../../types/issues';
-import { MeasurePageView } from '../../types/measures';
-import { mockBranch, mockMainBranch, mockPullRequest } from '../mocks/branch-like';
-import { mockLocation } from '../testMocks';
-import {
- CodeScope,
- convertGithubApiUrlToLink,
- convertToTo,
- getComponentAdminUrl,
- getComponentDrilldownUrl,
- getComponentDrilldownUrlWithSelection,
- getComponentOverviewUrl,
- getCreateProjectModeLocation,
- getDeprecatedActiveRulesUrl,
- getGlobalSettingsUrl,
- getIssuesUrl,
- getPathUrlAsString,
- getProjectSettingsUrl,
- getQualityGateUrl,
- getQualityGatesUrl,
- getReturnUrl,
- isRelativeUrl,
- stripTrailingSlash,
-} from '../urls';
-
-const SIMPLE_COMPONENT_KEY = 'sonarqube';
-const COMPLEX_COMPONENT_KEY = 'org.sonarsource.sonarqube:sonarqube';
-const METRIC = 'coverage';
-const COMPLEX_COMPONENT_KEY_ENCODED = encodeURIComponent(COMPLEX_COMPONENT_KEY);
-
-describe('#convertGithubApiUrlToLink', () => {
- it('should correctly convert a GitHub API URL to a Web URL', () => {
- expect(convertGithubApiUrlToLink('https://api.github.com')).toBe('https://github.com');
- expect(convertGithubApiUrlToLink('https://company.github.com/api/v3')).toBe(
- 'https://company.github.com',
- );
- });
-});
-
-describe('#stripTrailingSlash', () => {
- it('should correctly strip trailing slashes from any URL', () => {
- expect(stripTrailingSlash('https://example.com/')).toBe('https://example.com');
- expect(convertGithubApiUrlToLink('https://example.com')).toBe('https://example.com');
- });
-});
-
-describe('getComponentAdminUrl', () => {
- it.each([
- [
- 'Portfolio',
- ComponentQualifier.Portfolio,
- { pathname: '/project/admin/extension/governance/console', search: '?id=key&qualifier=VW' },
- ],
- [
- 'Application',
- ComponentQualifier.Application,
- {
- pathname: '/project/admin/extension/developer-server/application-console',
- search: '?id=key',
- },
- ],
- ['Project', ComponentQualifier.Project, { pathname: '/dashboard', search: '?id=key' }],
- ])('should work for %s', (_qualifierName, qualifier, result) => {
- expect(getComponentAdminUrl('key', qualifier)).toEqual(result);
- });
-});
-
-describe('#getComponentOverviewUrl', () => {
- it('should return a portfolio url for a portfolio', () => {
- expect(getComponentOverviewUrl(SIMPLE_COMPONENT_KEY, ComponentQualifier.Portfolio)).toEqual(
- expect.objectContaining({
- pathname: '/portfolio',
- search: queryToSearchString({ id: SIMPLE_COMPONENT_KEY }),
- }),
- );
- });
- it('should return a portfolio url for a subportfolio', () => {
- expect(getComponentOverviewUrl(SIMPLE_COMPONENT_KEY, ComponentQualifier.SubPortfolio)).toEqual(
- expect.objectContaining({
- pathname: '/portfolio',
- search: queryToSearchString({ id: SIMPLE_COMPONENT_KEY }),
- }),
- );
- });
- it('should return a dashboard url for a project', () => {
- expect(getComponentOverviewUrl(SIMPLE_COMPONENT_KEY, ComponentQualifier.Project)).toEqual(
- expect.objectContaining({
- pathname: '/dashboard',
- search: queryToSearchString({ id: SIMPLE_COMPONENT_KEY }),
- }),
- );
- });
- it('should return correct dashboard url for a project when navigating from new code', () => {
- expect(
- getComponentOverviewUrl(
- SIMPLE_COMPONENT_KEY,
- ComponentQualifier.Project,
- undefined,
- CodeScope.New,
- ),
- ).toEqual(
- expect.objectContaining({
- pathname: '/dashboard',
- search: queryToSearchString({ id: SIMPLE_COMPONENT_KEY, codeScope: 'new' }),
- }),
- );
- });
- it('should return correct dashboard url for a project when navigating from overall code', () => {
- expect(
- getComponentOverviewUrl(
- SIMPLE_COMPONENT_KEY,
- ComponentQualifier.Project,
- undefined,
- CodeScope.Overall,
- ),
- ).toEqual(
- expect.objectContaining({
- pathname: '/dashboard',
- search: queryToSearchString({ id: SIMPLE_COMPONENT_KEY, codeScope: 'overall' }),
- }),
- );
- });
- it('should return a dashboard url for an app', () => {
- expect(getComponentOverviewUrl(SIMPLE_COMPONENT_KEY, ComponentQualifier.Application)).toEqual(
- expect.objectContaining({
- pathname: '/dashboard',
- search: queryToSearchString({ id: SIMPLE_COMPONENT_KEY }),
- }),
- );
- });
-});
-
-describe('#getComponentDrilldownUrl', () => {
- it('should return component drilldown url', () => {
- expect(
- getComponentDrilldownUrl({ componentKey: SIMPLE_COMPONENT_KEY, metric: METRIC }),
- ).toEqual(
- expect.objectContaining({
- pathname: '/component_measures',
- search: queryToSearchString({ id: SIMPLE_COMPONENT_KEY, metric: METRIC }),
- }),
- );
- });
-
- it('should not encode component key', () => {
- expect(
- getComponentDrilldownUrl({ componentKey: COMPLEX_COMPONENT_KEY, metric: METRIC }),
- ).toEqual(
- expect.objectContaining({
- pathname: '/component_measures',
- search: queryToSearchString({ id: COMPLEX_COMPONENT_KEY, metric: METRIC }),
- }),
- );
- });
-
- it('should add asc param only when its list view', () => {
- expect(
- getComponentDrilldownUrl({ componentKey: SIMPLE_COMPONENT_KEY, metric: METRIC, asc: false }),
- ).toEqual(
- expect.objectContaining({
- pathname: '/component_measures',
- search: queryToSearchString({ id: SIMPLE_COMPONENT_KEY, metric: METRIC }),
- }),
- );
-
- expect(
- getComponentDrilldownUrl({
- componentKey: SIMPLE_COMPONENT_KEY,
- metric: METRIC,
- listView: true,
- asc: false,
- }),
- ).toEqual(
- expect.objectContaining({
- pathname: '/component_measures',
- search: queryToSearchString({
- id: SIMPLE_COMPONENT_KEY,
- metric: METRIC,
- view: 'list',
- asc: 'false',
- }),
- }),
- );
- });
-});
-
-describe('#getComponentDrilldownUrlWithSelection', () => {
- it('should return component drilldown url with selection', () => {
- expect(
- getComponentDrilldownUrlWithSelection(SIMPLE_COMPONENT_KEY, COMPLEX_COMPONENT_KEY, METRIC),
- ).toEqual(
- expect.objectContaining({
- pathname: '/component_measures',
- search: queryToSearchString({
- id: SIMPLE_COMPONENT_KEY,
- metric: METRIC,
- selected: COMPLEX_COMPONENT_KEY,
- }),
- }),
- );
- });
-
- it('should return component drilldown url with branchLike', () => {
- expect(
- getComponentDrilldownUrlWithSelection(
- SIMPLE_COMPONENT_KEY,
- COMPLEX_COMPONENT_KEY,
- METRIC,
- mockBranch({ name: 'foo' }),
- ),
- ).toEqual(
- expect.objectContaining({
- pathname: '/component_measures',
- search: queryToSearchString({
- id: SIMPLE_COMPONENT_KEY,
- metric: METRIC,
- branch: 'foo',
- selected: COMPLEX_COMPONENT_KEY,
- }),
- }),
- );
- });
-
- it('should return component drilldown url with view parameter', () => {
- expect(
- getComponentDrilldownUrlWithSelection(
- SIMPLE_COMPONENT_KEY,
- COMPLEX_COMPONENT_KEY,
- METRIC,
- undefined,
- MeasurePageView.list,
- ),
- ).toEqual(
- expect.objectContaining({
- pathname: '/component_measures',
- search: queryToSearchString({
- id: SIMPLE_COMPONENT_KEY,
- metric: METRIC,
- view: MeasurePageView.list,
- selected: COMPLEX_COMPONENT_KEY,
- }),
- }),
- );
-
- expect(
- getComponentDrilldownUrlWithSelection(
- SIMPLE_COMPONENT_KEY,
- COMPLEX_COMPONENT_KEY,
- METRIC,
- mockMainBranch(),
- MeasurePageView.treemap,
- ),
- ).toEqual(
- expect.objectContaining({
- pathname: '/component_measures',
- search: queryToSearchString({
- id: SIMPLE_COMPONENT_KEY,
- metric: METRIC,
- view: MeasurePageView.treemap,
- selected: COMPLEX_COMPONENT_KEY,
- }),
- }),
- );
-
- expect(
- getComponentDrilldownUrlWithSelection(
- SIMPLE_COMPONENT_KEY,
- COMPLEX_COMPONENT_KEY,
- METRIC,
- mockPullRequest({ key: '1' }),
- MeasurePageView.tree,
- ),
- ).toEqual(
- expect.objectContaining({
- pathname: '/component_measures',
- search: queryToSearchString({
- id: SIMPLE_COMPONENT_KEY,
- metric: METRIC,
- pullRequest: '1',
- selected: COMPLEX_COMPONENT_KEY,
- }),
- }),
- );
- });
-});
-
-describe('getDeprecatedActiveRulesUrl', () => {
- it('should include query params', () => {
- expect(getDeprecatedActiveRulesUrl({ languages: 'js' })).toEqual({
- pathname: '/coding_rules',
- search: '?languages=js&activation=true&statuses=DEPRECATED',
- });
- });
- it('should handle empty query', () => {
- expect(getDeprecatedActiveRulesUrl()).toEqual({
- pathname: '/coding_rules',
- search: '?activation=true&statuses=DEPRECATED',
- });
- });
-});
-
-describe('#getQualityGate(s)Url', () => {
- it('should work as expected', () => {
- expect(getQualityGatesUrl()).toEqual({ pathname: '/quality_gates' });
- expect(getQualityGateUrl('bar')).toEqual({ pathname: '/quality_gates/show/bar' });
- });
-});
-
-describe('#getIssuesUrl', () => {
- it('should work as expected', () => {
- const type = IssueType.Bug;
- expect(getIssuesUrl({ type })).toEqual({
- pathname: '/issues',
- search: queryToSearchString({ type }),
- });
- });
-});
-
-describe('#getGlobalSettingsUrl', () => {
- it('should work as expected', () => {
- expect(getGlobalSettingsUrl('foo')).toEqual({
- pathname: '/admin/settings',
- search: queryToSearchString({ category: 'foo' }),
- });
- expect(getGlobalSettingsUrl('foo', { alm: AlmKeys.GitHub })).toEqual({
- pathname: '/admin/settings',
- search: queryToSearchString({ category: 'foo', alm: AlmKeys.GitHub }),
- });
- });
-});
-
-describe('#getProjectSettingsUrl', () => {
- it('should work as expected', () => {
- expect(getProjectSettingsUrl('foo')).toEqual({
- pathname: '/project/settings',
- search: queryToSearchString({ id: 'foo' }),
- });
- expect(getProjectSettingsUrl('foo', 'bar')).toEqual({
- pathname: '/project/settings',
- search: queryToSearchString({ id: 'foo', category: 'bar' }),
- });
- });
-});
-
-describe('#getPathUrlAsString', () => {
- it('should return component url', () => {
- expect(
- getPathUrlAsString({
- pathname: '/dashboard',
- search: queryToSearchString({ id: SIMPLE_COMPONENT_KEY }),
- }),
- ).toBe('/dashboard?id=' + SIMPLE_COMPONENT_KEY);
- });
-
- it('should encode component key', () => {
- expect(
- getPathUrlAsString({
- pathname: '/dashboard',
- search: queryToSearchString({ id: COMPLEX_COMPONENT_KEY }),
- }),
- ).toBe('/dashboard?id=' + COMPLEX_COMPONENT_KEY_ENCODED);
- });
-
- it('should handle partial arguments', () => {
- expect(getPathUrlAsString({}, true)).toBe('/');
- });
-});
-
-describe('#getReturnUrl', () => {
- it('should get the return url', () => {
- expect(getReturnUrl({ query: { return_to: '/test' } })).toBe('/test');
- expect(getReturnUrl({ query: { return_to: 'http://www.google.com' } })).toBe('/');
- expect(getReturnUrl({})).toBe('/');
- });
-});
-
-describe('#isRelativeUrl', () => {
- it('should check a relative url', () => {
- expect(isRelativeUrl('/test')).toBe(true);
- expect(isRelativeUrl('http://www.google.com')).toBe(false);
- expect(isRelativeUrl('javascript:alert("test")')).toBe(false);
- expect(isRelativeUrl('\\test')).toBe(false);
- expect(isRelativeUrl('//test')).toBe(false);
- });
-});
-
-describe('#getHostUrl', () => {
- beforeEach(() => {
- jest.resetModules();
- });
- it('should return host url on client side', () => {
- jest.mock('../system', () => ({
- getBaseUrl: () => '',
- }));
- const mockedUrls = require('../urls');
- expect(mockedUrls.getHostUrl()).toBe('http://localhost');
- });
-});
-
-describe('searchParamsToQuery', () => {
- it('should handle arrays and single params', () => {
- const searchParams = new URLSearchParams([
- ['a', 'v1'],
- ['a', 'v2'],
- ['b', 'awesome'],
- ['a', 'v3'],
- ]);
-
- const result = searchParamsToQuery(searchParams);
-
- expect(result).toEqual({ a: ['v1', 'v2', 'v3'], b: 'awesome' });
- });
-});
-
-describe('convertToTo', () => {
- it('should handle locations with a query', () => {
- expect(convertToTo(mockLocation({ pathname: '/account', query: { id: 1 } }))).toEqual({
- pathname: '/account',
- search: '?id=1',
- });
- });
-
- it('should forward strings', () => {
- expect(convertToTo('/whatever')).toBe('/whatever');
- });
-});
-
-describe('#get import devops config URL', () => {
- it('should work as expected', () => {
- expect(getCreateProjectModeLocation(AlmKeys.GitHub)).toEqual({
- search: '?mode=github',
- });
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/users-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/users-test.ts
deleted file mode 100644
index 7e442b1619a..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/users-test.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { isSameHomePage } from '../users';
-
-describe('isSameHomePage', () => {
- it('should homepage equality properly', () => {
- expect(
- isSameHomePage(
- {
- type: 'APPLICATION',
- branch: 'test-branch',
- component: 'test-component',
- },
- {
- type: 'APPLICATION',
- branch: 'test-branch',
- component: 'test-component',
- },
- ),
- ).toBe(true);
-
- expect(
- isSameHomePage(
- {
- type: 'APPLICATION',
- branch: 'test-branch',
- component: 'test-component',
- },
- {
- type: 'ISSUES',
- },
- ),
- ).toBe(false);
-
- expect(
- isSameHomePage(
- {
- type: 'APPLICATION',
- branch: 'test-branch',
- component: 'test-component',
- },
- {
- type: 'APPLICATION',
- branch: 'test-branch-1',
- component: 'test-component',
- },
- ),
- ).toBe(false);
-
- expect(
- isSameHomePage(
- {
- type: 'APPLICATION',
- branch: 'test-branch',
- component: 'test-component',
- },
- {
- type: 'APPLICATION',
- branch: 'test-branch',
- component: 'test-component-1',
- },
- ),
- ).toBe(false);
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/activity-graph.ts b/server/sonar-web/src/main/js/helpers/activity-graph.ts
deleted file mode 100644
index ea0ccc4dd03..00000000000
--- a/server/sonar-web/src/main/js/helpers/activity-graph.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ScaleTime } from 'd3-scale';
-import { TimeMachineResponse } from '../api/time-machine';
-import { MQR_CONDITIONS_MAP, STANDARD_CONDITIONS_MAP } from '../apps/quality-gates/utils';
-
-export const mergeMeasureHistory = (
- historyData: TimeMachineResponse | undefined,
- parseDateFn: (date: string) => Date,
- isStandardMode = false,
-) => {
- const standardMeasuresMap = new Map<
- string,
- { history: { date: string; value?: string }[]; index: number; splitDate?: Date }
- >();
- if (isStandardMode) {
- return (
- historyData?.measures.map((measure) => ({
- metric: measure.metric,
- history: measure.history.map((historyItem) => ({
- date: parseDateFn(historyItem.date),
- value: historyItem.value,
- })),
- })) ?? []
- );
- }
-
- const historyDataFiltered =
- historyData?.measures?.filter((measure) => {
- if (MQR_CONDITIONS_MAP[measure.metric]) {
- const splitPointIndex = measure.history.findIndex(
- (historyItem) => historyItem.value != null,
- );
- standardMeasuresMap.set(measure.metric, {
- history: measure.history,
- index: measure.history.findIndex((historyItem) => historyItem.value != null),
- splitDate:
- // Don't show splitPoint if it's the first history item
- splitPointIndex !== -1 && splitPointIndex !== 0
- ? parseDateFn(measure.history[splitPointIndex].date)
- : undefined,
- });
- return false;
- }
- return true;
- }) ?? [];
-
- const historyMapper = (historyItem: { date: string; value?: string }) => ({
- date: parseDateFn(historyItem.date),
- value: historyItem.value,
- });
-
- return historyDataFiltered.map((measure) => {
- const metric = STANDARD_CONDITIONS_MAP[measure.metric];
- const softwareQualityMetric = standardMeasuresMap.get(metric as string);
- if (softwareQualityMetric !== undefined && metric) {
- return {
- metric,
- splitPointDate: softwareQualityMetric.splitDate,
- history: measure.history
- .slice(0, softwareQualityMetric.index)
- .map(historyMapper)
- .concat(
- softwareQualityMetric.history.slice(softwareQualityMetric.index).map(historyMapper),
- ),
- };
- }
-
- return {
- metric: measure.metric,
- history: measure.history.map(historyMapper),
- };
- });
-};
-
-export const shouldShowSplitLine = (
- splitPointDate: Date | undefined,
- xScale: ScaleTime<number, number>,
-): splitPointDate is Date =>
- splitPointDate !== undefined &&
- xScale(splitPointDate) >= xScale.range()[0] &&
- xScale(splitPointDate) <= xScale.range()[1];
diff --git a/server/sonar-web/src/main/js/helpers/branch-like.ts b/server/sonar-web/src/main/js/helpers/branch-like.ts
deleted file mode 100644
index 3317e12e38e..00000000000
--- a/server/sonar-web/src/main/js/helpers/branch-like.ts
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { orderBy } from 'lodash';
-import { isBranch, isMainBranch, isPullRequest } from '~sonar-aligned/helpers/branch-like';
-import { Branch, BranchLike, BranchLikeTree, PullRequest } from '../types/branch-like';
-
-export function sortBranches(branches: Branch[]) {
- return orderBy(branches, [(b) => b.isMain, (b) => b.name], ['desc', 'asc']);
-}
-
-export function sortPullRequests(pullRequests: PullRequest[]) {
- return orderBy(pullRequests, (pr) => getPullRequestDisplayName(pr));
-}
-
-export function getPullRequestDisplayName(pullRequest: PullRequest) {
- return `${pullRequest.key} – ${pullRequest.title}`;
-}
-
-export function getBranchLikeDisplayName(branchLike: BranchLike) {
- return isPullRequest(branchLike) ? getPullRequestDisplayName(branchLike) : branchLike.name;
-}
-
-export function getBranchLikeKey(branchLike: BranchLike) {
- return isPullRequest(branchLike) ? `pull-request-${branchLike.key}` : `branch-${branchLike.name}`;
-}
-
-export function isSameBranchLike(a: BranchLike | undefined, b: BranchLike | undefined) {
- // main branches are always equal
- if (isMainBranch(a) && isMainBranch(b)) {
- return true;
- }
-
- // Branches are compared by name
- if (isBranch(a) && isBranch(b)) {
- return a.name === b.name;
- }
-
- // pull requests are compared by id
- if (isPullRequest(a) && isPullRequest(b)) {
- return a.key === b.key;
- }
-
- // finally if both parameters are `undefined`, consider them equal
- return a === b;
-}
-
-export function getBrancheLikesAsTree(branchLikes: BranchLike[]): BranchLikeTree {
- const mainBranch = branchLikes.find(isMainBranch);
- const branches = orderBy(
- branchLikes.filter(isBranch).filter((b) => !isMainBranch(b)),
- (b) => b.name,
- );
- const pullRequests = orderBy(branchLikes.filter(isPullRequest), (b) => parseInt(b.key, 10), [
- 'desc',
- ]);
- const parentlessPullRequests = pullRequests.filter(
- (pr) => !pr.isOrphan && ![mainBranch, ...branches].find((b) => !!b && b.name === pr.base),
- );
- const orphanPullRequests = pullRequests.filter((pr) => pr.isOrphan);
-
- const tree: BranchLikeTree = {
- branchTree: branches.map((b) => ({ branch: b, pullRequests: getPullRequests(b) })),
- parentlessPullRequests,
- orphanPullRequests,
- };
-
- if (mainBranch) {
- tree.mainBranchTree = {
- branch: mainBranch,
- pullRequests: getPullRequests(mainBranch),
- };
- }
-
- return tree;
-
- function getPullRequests(branch: Branch) {
- return pullRequests.filter((pr) => !pr.isOrphan && pr.base === branch.name);
- }
-}
-
-// Create branch object from branch name or pull request key
-export function fillBranchLike(
- branch?: string,
- pullRequest?: string,
-): Branch | PullRequest | undefined {
- if (branch) {
- return {
- isMain: false,
- name: branch,
- } as Branch;
- } else if (pullRequest) {
- return { base: '', branch: '', key: pullRequest, title: '' } as PullRequest;
- }
- return undefined;
-}
diff --git a/server/sonar-web/src/main/js/helpers/browser.ts b/server/sonar-web/src/main/js/helpers/browser.ts
deleted file mode 100644
index a1260467d63..00000000000
--- a/server/sonar-web/src/main/js/helpers/browser.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { EnhancedWindow } from '../types/browser';
-
-export function getEnhancedWindow() {
- return window as unknown as EnhancedWindow;
-}
diff --git a/server/sonar-web/src/main/js/helpers/code-difference.ts b/server/sonar-web/src/main/js/helpers/code-difference.ts
deleted file mode 100644
index 637ddf8e67d..00000000000
--- a/server/sonar-web/src/main/js/helpers/code-difference.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { diffLines } from 'diff';
-import { groupBy, keyBy } from 'lodash';
-import { sanitizeHTMLNoSVGNoMathML } from '~design-system';
-
-const NUMBER_OF_EXAMPLES = 2;
-
-type DiffBlock = { compliant: Element; noncompliant: Element };
-
-export default function applyCodeDifferences(element: Element | null) {
- if (element === null) {
- return;
- }
- const codeExamples = getExamplesFromDom(element);
-
- codeExamples.forEach(({ noncompliant, compliant }) => {
- if (noncompliant === undefined || compliant === undefined) {
- return;
- }
- const [markedNonCompliant, markedCompliantCode] = differentiateCode(
- noncompliant.innerHTML,
- compliant.innerHTML,
- );
-
- replaceInDom(noncompliant, markedNonCompliant);
- replaceInDom(compliant, markedCompliantCode);
- });
-}
-
-function getExamplesFromDom(element: Element) {
- const pres = Array.from(element.querySelectorAll(`pre[data-diff-id]`));
-
- return (
- Object.values(
- groupBy(
- pres.filter((e) => e.getAttribute('data-diff-id') !== undefined),
- (e) => e.getAttribute('data-diff-id'),
- ),
- )
- // If we have 1 or 3+ example we can't display any differences
- .filter((diffsBlock) => diffsBlock.length === NUMBER_OF_EXAMPLES)
- .map(
- (diffBlock) =>
- keyBy(diffBlock, (block) => block.getAttribute('data-diff-type')) as DiffBlock,
- )
- );
-}
-
-function differentiateCode(compliant: string, nonCompliant: string) {
- const hunks = diffLines(compliant, nonCompliant);
-
- let nonCompliantCode = '';
- let compliantCode = '';
-
- hunks.forEach((hunk) => {
- const { value } = hunk;
- if (!hunk.added && !hunk.removed) {
- nonCompliantCode += value;
- compliantCode += value;
- }
-
- if (hunk.added) {
- compliantCode += `<div class='code-added'>${value}</div>`;
- }
-
- if (hunk.removed) {
- nonCompliantCode += `<div class='code-removed'>${value}</div>`;
- }
- });
- return [sanitizeHTMLNoSVGNoMathML(nonCompliantCode), sanitizeHTMLNoSVGNoMathML(compliantCode)];
-}
-
-function replaceInDom(current: Element, code: string) {
- const markedCode = document.createElement('pre');
- markedCode.classList.add('code-difference-scrollable');
- const div = document.createElement('div');
- div.classList.add('code-difference-container');
- div.innerHTML = code;
- markedCode.appendChild(div);
- current.parentNode?.replaceChild(markedCode, current);
-}
diff --git a/server/sonar-web/src/main/js/helpers/code-viewer.ts b/server/sonar-web/src/main/js/helpers/code-viewer.ts
deleted file mode 100644
index 9945e2abbd1..00000000000
--- a/server/sonar-web/src/main/js/helpers/code-viewer.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import type { LineMap, SourceLine } from '../types/types';
-
-export function decorateWithUnderlineFlags(line: SourceLine, sourcesMap: LineMap) {
- const previousLine: SourceLine | undefined = sourcesMap[line.line - 1];
-
- const decoratedLine = { ...line };
-
- if (line.coverageStatus) {
- decoratedLine.coverageBlock =
- line.coverageStatus === previousLine?.coverageStatus
- ? (previousLine.coverageBlock ?? line.line)
- : line.line;
- }
-
- if (line.isNew) {
- decoratedLine.newCodeBlock = previousLine?.isNew
- ? (previousLine.newCodeBlock ?? line.line)
- : line.line;
- }
-
- return decoratedLine;
-}
diff --git a/server/sonar-web/src/main/js/helpers/component.ts b/server/sonar-web/src/main/js/helpers/component.ts
deleted file mode 100644
index a49547d4324..00000000000
--- a/server/sonar-web/src/main/js/helpers/component.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentMeasure, ComponentMeasureEnhanced } from '../types/types';
-
-export function getComponentMeasureUniqueKey(
- component?: ComponentMeasure | ComponentMeasureEnhanced,
-) {
- return component ? [component.key, component.branch].filter((s) => !!s).join('/') : undefined;
-}
diff --git a/server/sonar-web/src/main/js/helpers/constants.ts b/server/sonar-web/src/main/js/helpers/constants.ts
deleted file mode 100644
index bf0ce79b695..00000000000
--- a/server/sonar-web/src/main/js/helpers/constants.ts
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { AlmKeys } from '../types/alm-settings';
-import {
- CleanCodeAttribute,
- CleanCodeAttributeCategory,
- SoftwareImpactSeverity,
- SoftwareQuality,
-} from '../types/clean-code-taxonomy';
-import {
- IssueResolution,
- IssueScope,
- IssueSeverity,
- IssueStatus,
- IssueType,
-} from '../types/issues';
-import { RuleType } from '../types/types';
-
-export const SEVERITIES = Object.values(IssueSeverity);
-
-export const IMPACT_SEVERITIES = Object.values(SoftwareImpactSeverity);
-
-export const CLEAN_CODE_CATEGORIES = Object.values(CleanCodeAttributeCategory);
-
-export const CLEAN_CODE_ATTRIBUTES_BY_CATEGORY = {
- [CleanCodeAttributeCategory.Consistent]: [
- CleanCodeAttribute.Conventional,
- CleanCodeAttribute.Identifiable,
- CleanCodeAttribute.Formatted,
- ],
- [CleanCodeAttributeCategory.Intentional]: [
- CleanCodeAttribute.Logical,
- CleanCodeAttribute.Clear,
- CleanCodeAttribute.Complete,
- CleanCodeAttribute.Efficient,
- ],
- [CleanCodeAttributeCategory.Adaptable]: [
- CleanCodeAttribute.Focused,
- CleanCodeAttribute.Distinct,
- CleanCodeAttribute.Modular,
- CleanCodeAttribute.Tested,
- ],
- [CleanCodeAttributeCategory.Responsible]: [
- CleanCodeAttribute.Trustworthy,
- CleanCodeAttribute.Lawful,
- CleanCodeAttribute.Respectful,
- ],
-};
-
-export const SOFTWARE_QUALITIES = Object.values(SoftwareQuality);
-
-export const STATUSES = ['OPEN', 'CONFIRMED', 'REOPENED', 'RESOLVED', 'CLOSED'];
-
-export const ISSUE_STATUSES = [
- IssueStatus.Open,
- IssueStatus.Accepted,
- IssueStatus.FalsePositive,
- IssueStatus.Confirmed,
- IssueStatus.Fixed,
-];
-
-export const ISSUE_TYPES: IssueType[] = [
- IssueType.Bug,
- IssueType.Vulnerability,
- IssueType.CodeSmell,
- IssueType.SecurityHotspot,
-];
-
-export const CCT_SOFTWARE_QUALITY_METRICS = [
- MetricKey.software_quality_security_issues,
- MetricKey.software_quality_reliability_issues,
- MetricKey.software_quality_maintainability_issues,
-];
-
-export const LEAK_CCT_SOFTWARE_QUALITY_METRICS = [
- MetricKey.new_software_quality_security_issues,
- MetricKey.new_software_quality_reliability_issues,
- MetricKey.new_software_quality_maintainability_issues,
-];
-
-export const OLD_TAXONOMY_METRICS = [
- MetricKey.vulnerabilities,
- MetricKey.bugs,
- MetricKey.code_smells,
-];
-
-export const LEAK_OLD_TAXONOMY_METRICS = [
- MetricKey.new_vulnerabilities,
- MetricKey.new_bugs,
- MetricKey.new_code_smells,
-];
-
-export const OLD_TAXONOMY_RATINGS = [
- MetricKey.sqale_rating,
- MetricKey.security_rating,
- MetricKey.reliability_rating,
- MetricKey.sqale_index,
- MetricKey.reliability_remediation_effort,
- MetricKey.security_remediation_effort,
- MetricKey.sqale_debt_ratio,
- MetricKey.effort_to_reach_maintainability_rating_a,
-];
-
-export const LEAK_OLD_TAXONOMY_RATINGS = [
- MetricKey.new_maintainability_rating,
- MetricKey.new_security_rating,
- MetricKey.new_reliability_rating,
- MetricKey.new_technical_debt,
- MetricKey.new_security_remediation_effort,
- MetricKey.new_reliability_remediation_effort,
- MetricKey.new_sqale_debt_ratio,
-];
-
-export const OLD_TO_NEW_TAXONOMY_METRICS_MAP: { [key in MetricKey]?: MetricKey } = {
- [MetricKey.vulnerabilities]: MetricKey.software_quality_security_issues,
- [MetricKey.bugs]: MetricKey.software_quality_reliability_issues,
- [MetricKey.code_smells]: MetricKey.software_quality_maintainability_issues,
-};
-
-export const SOFTWARE_QUALITIES_ISSUES_KEYS_MAP: Record<string, MetricKey> = {
- [MetricKey.maintainability_issues]: MetricKey.software_quality_maintainability_issues,
- [MetricKey.new_maintainability_issues]: MetricKey.new_software_quality_maintainability_issues,
- [MetricKey.reliability_issues]: MetricKey.software_quality_reliability_issues,
- [MetricKey.new_reliability_issues]: MetricKey.new_software_quality_reliability_issues,
- [MetricKey.security_issues]: MetricKey.software_quality_security_issues,
- [MetricKey.new_security_issues]: MetricKey.new_software_quality_security_issues,
-};
-
-export const RESOLUTIONS = [
- IssueResolution.Unresolved,
- IssueResolution.FalsePositive,
- IssueResolution.Fixed,
- IssueResolution.Removed,
- IssueResolution.WontFix,
-];
-
-export const SOURCE_SCOPES = [
- { scope: IssueScope.Main, qualifier: ComponentQualifier.File },
- { scope: IssueScope.Test, qualifier: ComponentQualifier.TestFile },
-];
-
-export const RULE_TYPES: RuleType[] = ['BUG', 'VULNERABILITY', 'CODE_SMELL', 'SECURITY_HOTSPOT'];
-
-export const RULE_STATUSES = ['READY', 'BETA', 'DEPRECATED'];
-
-/**
- * @deprecated Legacy colors. Equivalents should be added to the Echoes design system soon
- */
-const colors = {
- success300: '#6CD46C',
- success300a20: 'rgba(108, 212, 108, 0.2)',
- success500: '#008223',
- successVariant: '#C6E056',
- successVarianta20: 'rgba(198, 224, 86, 0.2)',
- successVariantDark: '#809E00',
-
- warning: '#B95E04',
- warningVariant: '#F4D348',
- warningVarianta20: 'rgba(244, 211, 72, 0.2)',
- warningVariantDark: '#B18F00',
- warningAccent: '#F69D53',
- warningAccenta20: 'rgba(246, 157, 83, 0.2)',
-
- error400: '#F0878E',
- error400a20: 'rgba(240, 135, 142, 0.2)',
- error700: '#B81723',
-};
-
-export const RATING_COLORS = [
- { fill: colors.success300, fillTransparent: colors.success300a20, stroke: colors.success500 },
- {
- fill: colors.successVariant,
- fillTransparent: colors.successVarianta20,
- stroke: colors.successVariantDark,
- },
- {
- fill: colors.warningVariant,
- fillTransparent: colors.warningVarianta20,
- stroke: colors.warningVariantDark,
- },
- { fill: colors.warningAccent, fillTransparent: colors.warningAccenta20, stroke: colors.warning },
- { fill: colors.error400, fillTransparent: colors.error400a20, stroke: colors.error700 },
-];
-
-export const HIDDEN_METRICS = [
- MetricKey.open_issues,
- MetricKey.reopened_issues,
- MetricKey.high_impact_accepted_issues,
-];
-
-export const DEPRECATED_ACTIVITY_METRICS = [MetricKey.confirmed_issues];
-
-export const SOFTWARE_QUALITY_RATING_METRICS_MAP: Record<string, MetricKey> = {
- [MetricKey.sqale_rating]: MetricKey.software_quality_maintainability_rating,
- [MetricKey.maintainability_rating_distribution]:
- MetricKey.software_quality_maintainability_rating_distribution,
- [MetricKey.security_rating]: MetricKey.software_quality_security_rating,
- [MetricKey.security_rating_distribution]: MetricKey.software_quality_security_rating_distribution,
- [MetricKey.reliability_rating]: MetricKey.software_quality_reliability_rating,
- [MetricKey.reliability_rating_distribution]:
- MetricKey.software_quality_reliability_rating_distribution,
- [MetricKey.reliability_remediation_effort]:
- MetricKey.software_quality_reliability_remediation_effort,
- [MetricKey.security_remediation_effort]: MetricKey.software_quality_security_remediation_effort,
- [MetricKey.sqale_index]: MetricKey.software_quality_maintainability_remediation_effort,
- [MetricKey.sqale_debt_ratio]: MetricKey.software_quality_maintainability_debt_ratio,
- [MetricKey.effort_to_reach_maintainability_rating_a]:
- MetricKey.effort_to_reach_software_quality_maintainability_rating_a,
- [MetricKey.last_change_on_maintainability_rating]:
- MetricKey.last_change_on_software_quality_maintainability_rating,
- [MetricKey.last_change_on_reliability_rating]:
- MetricKey.last_change_on_software_quality_reliability_rating,
- [MetricKey.last_change_on_security_rating]:
- MetricKey.last_change_on_software_quality_security_rating,
- [MetricKey.maintainability_rating_effort]:
- MetricKey.software_quality_maintainability_rating_effort,
- [MetricKey.reliability_rating_effort]: MetricKey.software_quality_reliability_rating_effort,
- [MetricKey.security_rating_effort]: MetricKey.software_quality_security_rating_effort,
- [MetricKey.new_maintainability_rating]: MetricKey.new_software_quality_maintainability_rating,
- [MetricKey.new_maintainability_rating_distribution]:
- MetricKey.new_software_quality_maintainability_rating_distribution,
- [MetricKey.new_security_rating]: MetricKey.new_software_quality_security_rating,
- [MetricKey.new_security_rating_distribution]:
- MetricKey.new_software_quality_security_rating_distribution,
- [MetricKey.new_reliability_rating]: MetricKey.new_software_quality_reliability_rating,
- [MetricKey.new_reliability_rating_distribution]:
- MetricKey.new_software_quality_reliability_rating_distribution,
- [MetricKey.new_technical_debt]: MetricKey.new_software_quality_maintainability_remediation_effort,
- [MetricKey.new_reliability_remediation_effort]:
- MetricKey.new_software_quality_reliability_remediation_effort,
- [MetricKey.new_security_remediation_effort]:
- MetricKey.new_software_quality_security_remediation_effort,
- [MetricKey.new_sqale_debt_ratio]: MetricKey.new_software_quality_maintainability_debt_ratio,
-};
-
-export const SOFTWARE_QUALITY_RATING_METRICS = [
- MetricKey.software_quality_maintainability_rating,
- MetricKey.software_quality_security_rating,
- MetricKey.software_quality_reliability_rating,
- MetricKey.software_quality_maintainability_remediation_effort,
- MetricKey.software_quality_reliability_remediation_effort,
- MetricKey.software_quality_security_remediation_effort,
- MetricKey.software_quality_maintainability_debt_ratio,
- MetricKey.effort_to_reach_software_quality_maintainability_rating_a,
- MetricKey.new_software_quality_maintainability_rating,
- MetricKey.new_software_quality_security_rating,
- MetricKey.new_software_quality_reliability_rating,
- MetricKey.new_software_quality_maintainability_remediation_effort,
- MetricKey.new_software_quality_reliability_remediation_effort,
- MetricKey.new_software_quality_security_remediation_effort,
- MetricKey.new_software_quality_maintainability_debt_ratio,
-];
-
-export const PROJECT_KEY_MAX_LEN = 400;
-
-export const IMPORT_COMPATIBLE_ALMS = [
- AlmKeys.Azure,
- AlmKeys.BitbucketServer,
- AlmKeys.BitbucketCloud,
- AlmKeys.GitHub,
- AlmKeys.GitLab,
-];
-
-export const GRADLE_SCANNER_VERSION = '6.0.1.5171';
-
-export const ONE_SECOND = 1000;
-
-export enum CustomEvents {
- OpenHelpMenu = 'open-help-menu',
- CloseHelpMenu = 'close-help-menu',
- HelpMenuClosed = 'help-menu-closed',
- RunTourMode = 'runTour-mode',
-}
diff --git a/server/sonar-web/src/main/js/helpers/cookies.ts b/server/sonar-web/src/main/js/helpers/cookies.ts
deleted file mode 100644
index 437f446dbe2..00000000000
--- a/server/sonar-web/src/main/js/helpers/cookies.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { memoize } from 'lodash';
-import { Dict } from '../types/types';
-
-const parseCookies = memoize((documentCookie: string): Dict<string> => {
- const rawCookies = documentCookie.split('; ');
- const cookies: Dict<string> = {};
- rawCookies.forEach((candidate) => {
- const [key, value] = candidate.split('=');
- cookies[key] = value;
- });
- return cookies;
-});
-
-export function getCookie(name: string): string | undefined {
- return parseCookies(document.cookie)[name];
-}
diff --git a/server/sonar-web/src/main/js/helpers/csv.ts b/server/sonar-web/src/main/js/helpers/csv.ts
deleted file mode 100644
index f245967a31b..00000000000
--- a/server/sonar-web/src/main/js/helpers/csv.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export function csvEscape(value: string): string {
- const escaped = value.replace(/"/g, '\\"');
- return `"${escaped}"`;
-}
diff --git a/server/sonar-web/src/main/js/helpers/dates.ts b/server/sonar-web/src/main/js/helpers/dates.ts
deleted file mode 100644
index 3ad435a1426..00000000000
--- a/server/sonar-web/src/main/js/helpers/dates.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ParsableDate } from '../types/dates';
-
-function pad(number: number) {
- if (number < 10) {
- return '0' + number.toString();
- }
- return number;
-}
-
-export function parseDate(rawDate: ParsableDate): Date {
- return new Date(rawDate);
-}
-
-export function toShortISO8601String(rawDate: ParsableDate): string {
- const date = parseDate(rawDate);
- return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
-}
-
-export function toISO8601WithOffsetString(rawDate: ParsableDate): string {
- const date = parseDate(rawDate);
- // JS ISO Date implementation returns a datetime in UTC time (suffixed by "Z"). But the backend
- // expects a datetime with a timeoffset (e.g., +0200). UTC time is actually "+0000", so we convert
- // the string to this other format for the backend. The backend also doesn't expect milliseconds, so
- // we truncate that part, too.
- return date.toISOString().split('.')[0] + '+0000';
-}
-
-export function isValidDate(date: Date): boolean {
- return !isNaN(date.getTime());
-}
-
-export function now() {
- return new Date();
-}
diff --git a/server/sonar-web/src/main/js/helpers/doc-links.ts b/server/sonar-web/src/main/js/helpers/doc-links.ts
deleted file mode 100644
index 45ade402034..00000000000
--- a/server/sonar-web/src/main/js/helpers/doc-links.ts
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { AlmKeys } from '../types/alm-settings';
-
-export const COMMUNITY_FORUM_URL = 'https://community.sonarsource.com/c/help/sq';
-
-export const DOC_URL = 'https://docs.sonarsource.com/sonarqube/latest';
-
-export enum DocLink {
- AccountTokens = '/user-guide/managing-tokens/',
- ActiveVersions = '/server-upgrade-and-maintenance/upgrade/upgrade-the-server/active-versions/',
- AiCodeAssurance = '/user-guide/ai-features/',
- AiCodeFixEnabling = '/instance-administration/system-functions/managing-ai-features/#enabling-ai-generated-fix-suggestions',
- AiCodeAssuranceQualifyQualityGate = '/instance-administration/analysis-functions/ai-standards/#apply-qualified-quality-gate',
- AlmAzureIntegration = '/devops-platform-integration/azure-devops-integration/',
- AlmBitBucketCloudAuth = '/instance-administration/authentication/bitbucket-cloud/',
- AlmBitBucketCloudIntegration = '/devops-platform-integration/bitbucket-integration/bitbucket-cloud-integration/',
- AlmBitBucketCloudSettings = '/instance-administration/authentication/bitbucket-cloud/#setting-your-authentication-settings-in-sonarqube',
- AlmBitBucketServerIntegration = '/devops-platform-integration/bitbucket-integration/bitbucket-server-integration/',
- AlmGitHubAuth = '/instance-administration/authentication/github/',
- AlmGitHubIntegration = '/devops-platform-integration/github-integration/introduction/',
- AlmGitHubMonorepoWorkfileExample = '/devops-platform-integration/github-integration/adding-analysis-to-github-actions-workflow/#configuring-the-buildyml-file',
- AlmGitLabAuth = '/instance-administration/authentication/gitlab/setting-up/',
- AlmGitLabAuthJITProvisioningMethod = '/instance-administration/authentication/gitlab/provisioning-modes/just-in-time/',
- AlmGitLabAuthAutoProvisioningMethod = '/instance-administration/authentication/gitlab/provisioning-modes/automatic/',
- AlmGitLabIntegration = '/devops-platform-integration/gitlab-integration/introduction/',
- AlmSamlAuth = '/instance-administration/authentication/saml/overview/',
- AlmSamlScimAuth = '/instance-administration/authentication/saml/scim/overview/',
- AnalysisScope = '/project-administration/analysis-scope/',
- AnalysisScopeWildcardPatterns = '/project-administration/analysis-scope/#wildcard-patterns',
- AuthOverview = '/instance-administration/authentication/overview/',
- BackgroundTasks = '/analyzing-source-code/background-tasks/',
- BranchAnalysis = '/analyzing-source-code/branch-analysis/introduction/',
- CaYC = '/core-concepts/clean-as-you-code/introduction/',
- CFamilyBuildWrapper = '/analyzing-source-code/languages/c-family/prerequisites/#using-buildwrapper',
- CFamilyCompilationDatabase = '/analyzing-source-code/languages/c-family/prerequisites/#using-thirdparty-tools',
- CIAnalysisSetup = '/analyzing-source-code/ci-integration/overview/',
- CIJenkins = '/analyzing-source-code/ci-integration/jenkins-integration/key-features/',
- CleanCodeIntroduction = '/core-concepts/clean-code/introduction/',
- CleanCodeSoftwareQualities = '/core-concepts/clean-code/software-qualities/',
- CleanCodeDefinition = '/core-concepts/clean-code/definition/',
- CodeAnalysis = '/core-concepts/clean-code/code-analysis/',
- InactiveBranches = '/project-administration/maintaining-the-branches-of-your-project/#manage-inactive-branches',
- InstanceAdminEncryption = '/instance-administration/system-functions/security/#settings-encryption',
- InstanceAdminLicense = '/instance-administration/license-administration/',
- InstanceAdminLoC = '/server-upgrade-and-maintenance/monitoring/lines-of-code/',
- InstanceAdminMarketplace = '/server-upgrade-and-maintenance/upgrade/marketplace/',
- InstanceAdminPluginVersionMatrix = '/setup-and-upgrade/plugins/plugin-version-matrix/',
- InstanceAdminQualityProfiles = '/instance-administration/analysis-functions/quality-profiles/',
- InstanceAdminQualityProfilesPrioritizingRules = '/instance-administration/analysis-functions/quality-profiles/#prioritizing-rules',
- InstanceAdminReindexation = '/server-upgrade-and-maintenance/maintenance/reindexing/',
- InstanceAdminSecurity = '/instance-administration/system-functions/security/',
- IssueResolutions = '/user-guide/issues/solution-overview/#deprecated-features',
- Issues = '/user-guide/issues/introduction/',
- IssueStatuses = '/user-guide/issues/solution-overview/#life-cycle',
- MainBranchAnalysis = '/project-administration/maintaining-the-branches-of-your-project/',
- ManagingPortfolios = '/project-administration/managing-portfolios/',
- MetricDefinitions = '/user-guide/code-metrics/metrics-definition/',
- ModeOverview = '/instance-administration/analysis-functions/instance-mode/instance-mode-overview',
- ModeMQR = '/instance-administration/analysis-functions/instance-mode/mqr-mode',
- ModeStandard = '/instance-administration/analysis-functions/instance-mode/standard-experience',
- Monorepos = '/project-administration/monorepos/',
- NewCodeDefinition = '/core-concepts/clean-as-you-code/about-new-code/',
- NewCodeDefinitionOptions = '/core-concepts/clean-as-you-code/about-new-code/#new-code-definition-options',
- Portfolios = '/user-guide/viewing-reports/portfolios/',
- PullRequestAnalysis = '/analyzing-source-code/pull-request-analysis/introduction/',
- QualityGates = '/instance-administration/analysis-functions/quality-gates/',
- Root = '/',
- RuleSeverity = '/instance-administration/analysis-functions/quality-profiles/#rule-severity',
- MQRSeverity = '/instance-administration/analysis-functions/instance-mode/mqr-mode/#mqr-severity',
- RulesOverview = '/user-guide/rules/overview',
- SecurityHotspots = '/user-guide/security-hotspots/',
- SecurityReports = '/user-guide/viewing-reports/security-reports/',
- ServerUpgradeRoadmap = '/server-upgrade-and-maintenance/upgrade/upgrade-the-server/roadmap/',
- SonarLintConnectedMode = '/user-guide/sonarlint-connected-mode/',
- SonarScanner = '/analyzing-source-code/scanners/sonarscanner/',
- SonarScannerRequirements = '/analyzing-source-code/scanners/scanner-environment/general-requirements/',
- SonarScannerDotNet = '/analyzing-source-code/scanners/dotnet/introduction/',
- SonarScannerGradle = '/analyzing-source-code/scanners/sonarscanner-for-gradle/',
- SonarScannerMaven = '/analyzing-source-code/scanners/sonarscanner-for-maven/',
- SonarWayQualityGate = '/instance-administration/analysis-functions/quality-gates/#using-sonar-way-the-recommended-quality-gate',
- Webhooks = '/project-administration/webhooks/',
- Dependencies = '/project-administration/managing-dependencies/',
-}
-
-export const DocTitle = {
- [DocLink.BackgroundTasks]: 'About Background Tasks',
- [DocLink.CaYC]: 'Clean as You Code',
- [DocLink.CIAnalysisSetup]: 'Set up CI analysis',
- [DocLink.InstanceAdminQualityProfiles]: 'About Quality Profiles',
- [DocLink.MetricDefinitions]: 'Metric Definitions',
- [DocLink.NewCodeDefinition]: 'Defining New Code',
- [DocLink.PullRequestAnalysis]: 'Analyzing Pull Requests',
- [DocLink.SecurityReports]: 'About Security Reports',
- [DocLink.SonarLintConnectedMode]: 'SonarLint Connected Mode',
- [DocLink.Webhooks]: 'About Webhooks',
-};
-
-export type DocTitleKey = keyof typeof DocTitle;
-
-const asDocSections = <T>(element: { [K in keyof T]: DocTitleKey[] }) => element;
-
-export const DocSection = asDocSections({
- component_measures: [DocLink.CaYC, DocLink.MetricDefinitions],
- overview: [
- DocLink.PullRequestAnalysis,
- DocLink.CIAnalysisSetup,
- DocLink.CaYC,
- DocLink.SonarLintConnectedMode,
- ],
- pull_requests: [DocLink.CaYC, DocLink.PullRequestAnalysis, DocLink.SonarLintConnectedMode],
-});
-
-export type DocSectionKey = keyof typeof DocSection;
-
-export const AlmAuthDocLinkKeys = {
- [AlmKeys.BitbucketServer]: DocLink.AlmBitBucketCloudAuth,
- [AlmKeys.GitHub]: DocLink.AlmGitHubAuth,
- [AlmKeys.GitLab]: DocLink.AlmGitLabAuth,
- saml: DocLink.AlmSamlAuth,
-};
diff --git a/server/sonar-web/src/main/js/helpers/docs.ts b/server/sonar-web/src/main/js/helpers/docs.ts
deleted file mode 100644
index 32460839c66..00000000000
--- a/server/sonar-web/src/main/js/helpers/docs.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React from 'react';
-import { AppStateContext } from '../app/components/app-state/AppStateContext';
-import { DocLink } from './doc-links';
-
-// This is only meant to be used directly for DocumentationRedirect. For all other uses,
-// please use useDocUrl instead (it forces the use of a catalogued documentation link)
-export function useUncataloguedDocUrl(to?: string) {
- const { documentationUrl: docUrl } = React.useContext(AppStateContext);
-
- const formatDocUrl = React.useCallback(
- (href: string) => {
- const path = href.replace(/^\//, '');
-
- return `${docUrl}/${path}`;
- },
- [docUrl],
- );
-
- return to ? formatDocUrl(to) : formatDocUrl;
-}
-
-export function useDocUrl(to: DocLink): string;
-export function useDocUrl(): (to: DocLink) => string;
-export function useDocUrl(to?: DocLink) {
- return useUncataloguedDocUrl(to);
-}
diff --git a/server/sonar-web/src/main/js/helpers/editions.ts b/server/sonar-web/src/main/js/helpers/editions.ts
deleted file mode 100644
index 4509bb3913a..00000000000
--- a/server/sonar-web/src/main/js/helpers/editions.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { omitNil } from '../helpers/request';
-import { Edition, EditionKey } from '../types/editions';
-import { SystemUpgrade } from '../types/system';
-
-const EDITIONS: { [x in EditionKey]: Edition } = {
- community: {
- key: EditionKey.community,
- name: 'Community Build',
- homeUrl: 'https://www.sonarsource.com/open-source-editions/',
- downloadProperty: 'downloadUrl',
- },
- developer: {
- key: EditionKey.developer,
- name: 'Developer Edition',
- homeUrl: 'https://www.sonarsource.com/products/sonarqube/developer-edition/marketplace/',
- downloadProperty: 'downloadDeveloperUrl',
- },
- enterprise: {
- key: EditionKey.enterprise,
- name: 'Enterprise Edition',
- homeUrl: 'https://www.sonarsource.com/products/sonarqube/enterprise-edition/marketplace/',
- downloadProperty: 'downloadEnterpriseUrl',
- },
- datacenter: {
- key: EditionKey.datacenter,
- name: 'Data Center Edition',
- homeUrl: 'https://www.sonarsource.com/products/sonarqube/data-center-edition/marketplace/',
- downloadProperty: 'downloadDatacenterUrl',
- },
-};
-
-export function getEdition(editionKey: EditionKey) {
- return EDITIONS[editionKey];
-}
-
-export function getAllEditionsAbove(currentEdition?: EditionKey) {
- const editions = Object.values(EDITIONS);
- const currentEditionIdx = editions.findIndex((edition) => edition.key === currentEdition);
- return editions.slice(currentEditionIdx + 1);
-}
-
-export function getEditionUrl(
- edition: Edition,
- data: { ncloc?: number; serverId?: string; sourceEdition?: EditionKey },
-) {
- let url = edition.homeUrl;
- const query = new URLSearchParams(omitNil(data)).toString();
- if (query) {
- url += '?' + query;
- }
- return url;
-}
-
-export function getEditionDownloadUrl(edition: Edition, lastUpgrade: SystemUpgrade) {
- return lastUpgrade[edition.downloadProperty] || lastUpgrade.downloadUrl;
-}
-
-export function getEditionDownloadFilename(url: string) {
- return url.replace(/^.+\/(sonarqube-[\w\-.]+\.zip)$/, '$1');
-}
diff --git a/server/sonar-web/src/main/js/helpers/extensions.ts b/server/sonar-web/src/main/js/helpers/extensions.ts
deleted file mode 100644
index 272c1359209..00000000000
--- a/server/sonar-web/src/main/js/helpers/extensions.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getBaseUrl } from '../helpers/system';
-import { ExtensionStartMethod } from '../types/extension';
-import { getExtensionFromCache } from './extensionsHandler';
-
-let librariesExposed = false;
-
-export function installStyles(url: string, target: 'body' | 'head' = 'head'): Promise<any> {
- return new Promise((resolve) => {
- const linkTag = document.createElement('link');
- linkTag.href = `${getBaseUrl()}${url}`;
- linkTag.rel = 'stylesheet';
- linkTag.onload = resolve;
- document.getElementsByTagName(target)[0].appendChild(linkTag);
- });
-}
-
-export function installScript(url: string, target: 'body' | 'head' = 'body'): Promise<any> {
- return new Promise((resolve) => {
- const scriptTag = document.createElement('script');
- scriptTag.src = `${getBaseUrl()}${url}`;
- scriptTag.onload = resolve;
- document.getElementsByTagName(target)[0].appendChild(scriptTag);
- });
-}
-
-export async function getExtensionStart(key: string): Promise<ExtensionStartMethod | undefined> {
- const fromCache = getExtensionFromCache(key);
- if (fromCache) {
- return Promise.resolve(fromCache.start);
- }
-
- if (!librariesExposed) {
- librariesExposed = true;
- // Async import allows to reduce initial vendor bundle size
- const exposeLibraries = (await import('../app/components/extensions/exposeLibraries')).default;
- exposeLibraries();
- }
-
- await installScript(`/static/${key}.js`);
-
- const extension = getExtensionFromCache(key);
- if (!extension) {
- return Promise.reject();
- }
-
- if (extension.providesCSSFile) {
- await installStyles(`/static/${key}.css`);
- }
-
- return extension.start;
-}
diff --git a/server/sonar-web/src/main/js/helpers/extensionsHandler.ts b/server/sonar-web/src/main/js/helpers/extensionsHandler.ts
deleted file mode 100644
index 45443474836..00000000000
--- a/server/sonar-web/src/main/js/helpers/extensionsHandler.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-// Do not import dependencies in this helper, to keep initial bundle load as small as possible
-
-import { ExtensionRegistryEntry, ExtensionStartMethod } from '../types/extension';
-import { Dict } from '../types/types';
-import { getEnhancedWindow } from './browser';
-
-const WEB_ANALYTICS_EXTENSION = 'sq-web-analytics';
-
-const extensions: Dict<ExtensionRegistryEntry> = {};
-
-function registerExtension(key: string, start: ExtensionStartMethod, providesCSSFile = false) {
- extensions[key] = { start, providesCSSFile };
-}
-
-function setWebAnalyticsPageChangeHandler(pageHandler: (pathname: string) => void) {
- registerExtension(WEB_ANALYTICS_EXTENSION, pageHandler);
-}
-
-export function installExtensionsHandler() {
- getEnhancedWindow().registerExtension = registerExtension;
-}
-
-export function installWebAnalyticsHandler() {
- getEnhancedWindow().setWebAnalyticsPageChangeHandler = setWebAnalyticsPageChangeHandler;
-}
-
-export function getExtensionFromCache(key: string): ExtensionRegistryEntry | undefined {
- return extensions[key];
-}
-
-export function getWebAnalyticsPageHandlerFromCache(): Function | undefined {
- return extensions[WEB_ANALYTICS_EXTENSION]?.start;
-}
diff --git a/server/sonar-web/src/main/js/helpers/globalMessages.ts b/server/sonar-web/src/main/js/helpers/globalMessages.ts
deleted file mode 100644
index f9716befe3c..00000000000
--- a/server/sonar-web/src/main/js/helpers/globalMessages.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { addGlobalErrorMessage } from '~design-system';
-import { parseError } from './request';
-
-export function addGlobalErrorMessageFromAPI(param: Response | string) {
- if (param instanceof Response) {
- return parseError(param).then(addGlobalErrorMessage, () => {
- /* ignore parsing errors */
- });
- }
-
- if (typeof param === 'string') {
- return Promise.resolve(param).then(addGlobalErrorMessage);
- }
-
- return Promise.resolve();
-}
diff --git a/server/sonar-web/src/main/js/helpers/handleRequiredAuthentication.ts b/server/sonar-web/src/main/js/helpers/handleRequiredAuthentication.ts
deleted file mode 100644
index 77f6255e57d..00000000000
--- a/server/sonar-web/src/main/js/helpers/handleRequiredAuthentication.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getBaseUrl } from './system';
-
-export default function handleRequiredAuthentication() {
- const returnTo = window.location.pathname + window.location.search + window.location.hash;
- const searchParams = new URLSearchParams({ return_to: returnTo });
- window.location.replace(`${getBaseUrl()}/sessions/new?${searchParams.toString()}`);
-}
diff --git a/server/sonar-web/src/main/js/helpers/issues.ts b/server/sonar-web/src/main/js/helpers/issues.ts
deleted file mode 100644
index 2964d45b7f9..00000000000
--- a/server/sonar-web/src/main/js/helpers/issues.ts
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { flatten, sortBy } from 'lodash';
-import { BugIcon, CodeSmellIcon, SecurityHotspotIcon, VulnerabilityIcon } from '~design-system';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { SoftwareQuality } from '../types/clean-code-taxonomy';
-import { IssueType, RawIssue } from '../types/issues';
-import { Dict, Flow, FlowLocation, FlowType, Issue, TextRange } from '../types/types';
-import { UserBase } from '../types/users';
-import { ISSUE_TYPES } from './constants';
-
-interface Rule {}
-
-interface Component {
- key: string;
- name: string;
-}
-
-export function sortByType<T extends Pick<Issue, 'type'>>(issues: T[]): T[] {
- return sortBy(issues, (issue) => ISSUE_TYPES.indexOf(issue.type as IssueType));
-}
-
-function injectRelational(
- issue: Dict<any>,
- source: any[] | undefined,
- baseField: string,
- lookupField: string,
-) {
- const newFields: Dict<any> = {};
- const baseValue = issue[baseField];
- if (baseValue !== undefined && source !== undefined) {
- const lookupValue = source.find((candidate) => candidate[lookupField] === baseValue);
- if (lookupValue != null) {
- Object.keys(lookupValue).forEach((key) => {
- const newKey = baseField + key.charAt(0).toUpperCase() + key.slice(1);
- newFields[newKey] = lookupValue[key];
- });
- }
- }
- return newFields;
-}
-
-function injectCommentsRelational(issue: RawIssue, users?: UserBase[]) {
- if (!issue.comments) {
- return {};
- }
- const comments = issue.comments.map((comment) => {
- const commentWithAuthor = { ...comment, author: comment.login, login: undefined };
- return {
- ...commentWithAuthor,
- ...injectRelational(commentWithAuthor, users, 'author', 'login'),
- };
- });
- return { comments };
-}
-
-function prepareClosed(issue: RawIssue) {
- return issue.status === 'CLOSED'
- ? { flows: [], line: undefined, textRange: undefined, secondaryLocations: [] }
- : {};
-}
-
-function ensureTextRange(issue: RawIssue): { textRange?: TextRange } {
- return issue.line && !issue.textRange
- ? {
- textRange: {
- startLine: issue.line,
- endLine: issue.line,
- startOffset: 0,
- endOffset: 999999,
- },
- }
- : {};
-}
-
-function reverseLocations(locations: FlowLocation[]): FlowLocation[] {
- const x = [...locations];
- x.reverse();
- return x;
-}
-
-const FLOW_ORDER_MAP = {
- [FlowType.DATA]: 0,
- [FlowType.EXECUTION]: 1,
-};
-
-function splitFlows(
- issue: RawIssue,
- components: Component[] = [],
-): { flows: FlowLocation[][]; flowsWithType: Flow[]; secondaryLocations: FlowLocation[] } {
- if (issue.flows?.some((flow) => flow.type !== undefined)) {
- const flowsWithType = issue.flows.filter((flow) => flow.type !== undefined) as Flow[];
- flowsWithType.sort((f1, f2) => FLOW_ORDER_MAP[f1.type] - FLOW_ORDER_MAP[f2.type]);
-
- return {
- flows: [],
- flowsWithType,
- secondaryLocations: [],
- };
- }
-
- const parsedFlows: FlowLocation[][] = (issue.flows ?? [])
- .filter((flow) => flow.locations !== undefined)
- .map((flow) => flow.locations!.filter((location) => location.textRange != null))
- .map((flow) =>
- flow.map((location) => {
- const component = components.find((component) => component.key === location.component);
- return { ...location, componentName: component?.name };
- }),
- );
-
- const onlySecondaryLocations = parsedFlows.every((flow) => flow.length === 1);
-
- return onlySecondaryLocations
- ? { secondaryLocations: orderLocations(flatten(parsedFlows)), flowsWithType: [], flows: [] }
- : {
- secondaryLocations: [],
- flowsWithType: [],
- flows: parsedFlows.map(reverseLocations),
- };
-}
-
-function orderLocations(locations: FlowLocation[]) {
- return sortBy(
- locations,
- (location) => location.textRange?.startLine,
- (location) => location.textRange?.startOffset,
- );
-}
-
-export function parseIssueFromResponse(
- issue: RawIssue,
- components?: Component[],
- users?: UserBase[],
- rules?: Rule[],
-): Issue {
- return {
- ...issue,
- ...injectRelational(issue, components, 'component', 'key'),
- ...injectRelational(issue, components, 'project', 'key'),
- ...injectRelational(issue, rules, 'rule', 'key'),
- ...injectRelational(issue, users, 'assignee', 'login'),
- ...injectCommentsRelational(issue, users),
- ...splitFlows(issue, components),
- ...prepareClosed(issue),
- ...ensureTextRange(issue),
- } as Issue;
-}
-
-export function getIssueTypeBySoftwareQuality(quality: SoftwareQuality): IssueType {
- const map = {
- [SoftwareQuality.Maintainability]: IssueType.CodeSmell,
- [SoftwareQuality.Security]: IssueType.Vulnerability,
- [SoftwareQuality.Reliability]: IssueType.Bug,
- };
-
- return map[quality];
-}
-
-export const SOFTWARE_QUALITIES_METRIC_KEYS_MAP = {
- [SoftwareQuality.Security]: {
- metric: MetricKey.software_quality_security_issues,
- deprecatedMetric: MetricKey.vulnerabilities,
- rating: MetricKey.security_rating,
- newRating: MetricKey.new_security_rating,
- },
- [SoftwareQuality.Reliability]: {
- metric: MetricKey.software_quality_reliability_issues,
- deprecatedMetric: MetricKey.bugs,
- rating: MetricKey.reliability_rating,
- newRating: MetricKey.new_reliability_rating,
- },
- [SoftwareQuality.Maintainability]: {
- metric: MetricKey.software_quality_maintainability_issues,
- deprecatedMetric: MetricKey.code_smells,
- rating: MetricKey.sqale_rating,
- newRating: MetricKey.new_maintainability_rating,
- },
-};
-
-export const ISSUETYPE_METRIC_KEYS_MAP = {
- [IssueType.CodeSmell]: {
- metric: MetricKey.code_smells,
- newMetric: MetricKey.new_code_smells,
- rating: MetricKey.sqale_rating,
- newRating: MetricKey.new_maintainability_rating,
- ratingName: 'Maintainability',
- iconClass: CodeSmellIcon,
- },
- [IssueType.Vulnerability]: {
- metric: MetricKey.vulnerabilities,
- newMetric: MetricKey.new_vulnerabilities,
- rating: MetricKey.security_rating,
- newRating: MetricKey.new_security_rating,
- ratingName: 'Security',
- iconClass: VulnerabilityIcon,
- },
- [IssueType.Bug]: {
- metric: MetricKey.bugs,
- newMetric: MetricKey.new_bugs,
- rating: MetricKey.reliability_rating,
- newRating: MetricKey.new_reliability_rating,
- ratingName: 'Reliability',
- iconClass: BugIcon,
- },
- [IssueType.SecurityHotspot]: {
- metric: MetricKey.security_hotspots,
- newMetric: MetricKey.new_security_hotspots,
- rating: MetricKey.security_review_rating,
- newRating: MetricKey.new_security_review_rating,
- ratingName: 'SecurityReview',
- iconClass: SecurityHotspotIcon,
- },
-};
diff --git a/server/sonar-web/src/main/js/helpers/keyboardEventHelpers.ts b/server/sonar-web/src/main/js/helpers/keyboardEventHelpers.ts
deleted file mode 100644
index 8cd8f55bd8d..00000000000
--- a/server/sonar-web/src/main/js/helpers/keyboardEventHelpers.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export function isShortcut(event: KeyboardEvent): boolean {
- return event.ctrlKey || event.metaKey;
-}
-
-export function isTextarea(
- event: KeyboardEvent,
-): event is KeyboardEvent & { target: HTMLTextAreaElement } {
- return event.target instanceof HTMLTextAreaElement;
-}
-
-export function isInput(
- event: KeyboardEvent,
-): event is KeyboardEvent & { target: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement } {
- return (
- event.target instanceof HTMLInputElement ||
- event.target instanceof HTMLSelectElement ||
- event.target instanceof HTMLTextAreaElement
- );
-}
-
-export function isDropdown(event: KeyboardEvent) {
- const role = (event.target as HTMLElement | null)?.role ?? '';
-
- return ['menu', 'menuitem'].includes(role);
-}
diff --git a/server/sonar-web/src/main/js/helpers/keycodes.ts b/server/sonar-web/src/main/js/helpers/keycodes.ts
deleted file mode 100644
index a51a2e57dcb..00000000000
--- a/server/sonar-web/src/main/js/helpers/keycodes.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum KeyboardKeys {
- LeftArrow = 'ArrowLeft',
- UpArrow = 'ArrowUp',
- RightArrow = 'ArrowRight',
- DownArrow = 'ArrowDown',
- Backspace = 'Backspace',
- CapsLock = 'CapsLock',
- Command = 'ContextMenu',
- Delete = 'Delete',
- End = 'End',
- Enter = 'Enter',
- Escape = 'Escape',
- Home = 'Home',
- PageDown = 'PageDown',
- PageUp = 'PageUp',
- Space = 'Space',
- Tab = 'Tab',
- Alt = 'Alt',
- KeyF = 'f',
- KeyA = 'a',
- KeyM = 'm',
- KeyI = 'i',
- KeyT = 't',
- KeyS = 's',
- KeyQuestionMark = '?',
-}
diff --git a/server/sonar-web/src/main/js/helpers/l10n.ts b/server/sonar-web/src/main/js/helpers/l10n.ts
deleted file mode 100644
index 4594e4ae636..00000000000
--- a/server/sonar-web/src/main/js/helpers/l10n.ts
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getIntl, getMessages } from './l10nBundle';
-
-export function hasMessage(...keys: string[]): boolean {
- const messageKey = keys.join('.');
-
- return getMessages()[messageKey] !== undefined;
-}
-
-export function translate(...keys: string[]): string {
- const messageKey = keys.join('.');
- const l10nMessages = getMessages();
-
- if (process.env.NODE_ENV === 'development' && !l10nMessages[messageKey]) {
- // eslint-disable-next-line no-console
- console.error(`No message for: ${messageKey}`);
- }
-
- const intl = getIntl();
- // fallback to old if in extension
- return intl ? intl.formatMessage({ id: messageKey }) : l10nMessages[messageKey];
-}
-
-/**
- * @param messageKey @deprecated Use react-intl instead
- */
-export function translateWithParameters(
- messageKey: string,
- ...parameters: Array<string | number>
-): string {
- const message = getMessages()[messageKey];
-
- if (message) {
- return parameters
- .map((parameter) => String(parameter))
- .reduce((acc, parameter, index) => acc.replaceAll(`{${index}}`, () => parameter), message);
- }
-
- if (process.env.NODE_ENV === 'development') {
- // eslint-disable-next-line no-console
- console.error(`No message for: ${messageKey}`);
- }
-
- return `${messageKey}.${parameters.join('.')}`;
-}
-
-export function getLocalizedMetricName(
- metric: { key: string; name?: string },
- short = false,
-): string {
- const bundleKey = `metric.${metric.key}.${short ? 'short_name' : 'name'}`;
-
- if (hasMessage(bundleKey)) {
- return translate(bundleKey);
- } else if (short) {
- return getLocalizedMetricName(metric);
- }
-
- return metric.name || metric.key;
-}
-
-export function getLocalizedCategoryMetricName(metric: { key: string; name?: string }) {
- const bundleKey = `metric.${metric.key}.extra_short_name`;
-
- return hasMessage(bundleKey) ? translate(bundleKey) : getLocalizedMetricName(metric, true);
-}
-
-export function getLocalizedMetricDomain(domainName: string) {
- const bundleKey = `metric_domain.${domainName}`;
-
- return hasMessage(bundleKey) ? translate(bundleKey) : domainName;
-}
-
-export function getMonthName(index: number) {
- const months = [
- 'January',
- 'February',
- 'March',
- 'April',
- 'May',
- 'June',
- 'July',
- 'August',
- 'September',
- 'October',
- 'November',
- 'December',
- ];
-
- return translate(months[index]);
-}
-
-export function getShortMonthName(index: number) {
- const months = [
- 'Jan',
- 'Feb',
- 'Mar',
- 'Apr',
- 'May',
- 'Jun',
- 'Jul',
- 'Aug',
- 'Sep',
- 'Oct',
- 'Nov',
- 'Dec',
- ];
-
- return translate(months[index]);
-}
-
-export function getWeekDayName(index: number) {
- const weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
-
- return weekdays[index] ? translate(weekdays[index]) : '';
-}
-
-export function getShortWeekDayName(index: number) {
- const weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
-
- return weekdays[index] ? translate(weekdays[index]) : '';
-}
diff --git a/server/sonar-web/src/main/js/helpers/l10nBundle.ts b/server/sonar-web/src/main/js/helpers/l10nBundle.ts
deleted file mode 100644
index 9354364fe71..00000000000
--- a/server/sonar-web/src/main/js/helpers/l10nBundle.ts
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { IntlShape, createIntl, createIntlCache } from 'react-intl';
-import { fetchL10nBundle } from '../api/l10n';
-import { AppState } from '../types/appstate';
-import { EditionKey } from '../types/editions';
-import { L10nBundle, L10nBundleRequestParams } from '../types/l10nBundle';
-import { ProductName } from '../types/system';
-import { Dict } from '../types/types';
-import { toISO8601WithOffsetString } from './dates';
-import { isDefined } from './types';
-
-const DEFAULT_LOCALE = 'en';
-const DEFAULT_MESSAGES: Dict<string> = {
- // eslint-disable-next-line camelcase
- default_error_message: 'The request cannot be processed. Try again later.',
-};
-
-let intl: IntlShape;
-
-export function getIntl() {
- return intl;
-}
-
-export function getMessages() {
- return getL10nBundleFromCache().messages ?? DEFAULT_MESSAGES;
-}
-
-export function getCurrentLocale() {
- return getL10nBundleFromCache().locale ?? DEFAULT_LOCALE;
-}
-
-export function getCurrentL10nBundle() {
- return getL10nBundleFromCache();
-}
-
-export async function loadL10nBundle(appState: AppState | undefined) {
- const browserLocale = getPreferredLanguage();
- const cachedBundle = getL10nBundleFromCache();
-
- const params: L10nBundleRequestParams = {};
-
- if (browserLocale) {
- params.locale = browserLocale;
-
- if (
- cachedBundle.locale &&
- browserLocale.startsWith(cachedBundle.locale) &&
- cachedBundle.timestamp &&
- cachedBundle.messages
- ) {
- params.ts = cachedBundle.timestamp;
- }
- }
-
- const { effectiveLocale, messages } = await fetchL10nBundle(params).catch((response) => {
- if (response && response.status === 304) {
- return {
- effectiveLocale: cachedBundle.locale || browserLocale || DEFAULT_LOCALE,
- messages: cachedBundle.messages ?? {},
- };
- }
- throw new Error(`Unexpected status code: ${response.status}`);
- });
-
- const bundle = {
- timestamp: toISO8601WithOffsetString(new Date()),
- locale: effectiveLocale,
- messages,
- };
-
- persistL10nBundleInCache(bundle);
-
- const cache = createIntlCache();
-
- intl = createIntl(
- {
- locale: effectiveLocale,
- messages,
-
- /*
- * This sets a default value for translations, so devs do not need to pass the {productName}
- * value to every instance of FormattedMessage.
- * It is a bit of a hack, abusing this config item that is normally for tag replacement only,
- * hence the ts-expect-error tag
- */
- defaultRichTextElements: {
- // @ts-expect-error
- productName: getProductName(appState),
- },
- },
- cache,
- );
-
- return intl;
-}
-
-function getPreferredLanguage() {
- return window.navigator.languages ? window.navigator.languages[0] : window.navigator.language;
-}
-
-function getL10nBundleFromCache(): L10nBundle {
- return (window as unknown as any).sonarQubeL10nBundle ?? {};
-}
-
-function persistL10nBundleInCache(bundle: L10nBundle) {
- (window as unknown as any).sonarQubeL10nBundle = bundle;
-}
-
-function getProductName(appState?: AppState) {
- if (isDefined(appState?.edition)) {
- return appState?.edition === EditionKey.community
- ? ProductName.SonarQubeCommunityBuild
- : ProductName.SonarQubeServer;
- }
-
- return 'SonarQube';
-}
diff --git a/server/sonar-web/src/main/js/helpers/measures.ts b/server/sonar-web/src/main/js/helpers/measures.ts
deleted file mode 100644
index 364ee85d42c..00000000000
--- a/server/sonar-web/src/main/js/helpers/measures.ts
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import {
- QualityGateStatusCondition,
- QualityGateStatusConditionEnhanced,
-} from '../types/quality-gates';
-import { Measure, MeasureEnhanced, Metric } from '../types/types';
-import {
- CCT_SOFTWARE_QUALITY_METRICS,
- LEAK_CCT_SOFTWARE_QUALITY_METRICS,
- LEAK_OLD_TAXONOMY_METRICS,
-} from './constants';
-import { translate } from './l10n';
-import { isDefined } from './types';
-
-export const MEASURES_REDIRECTION: Partial<Record<MetricKey, MetricKey>> = {
- [MetricKey.wont_fix_issues]: MetricKey.accepted_issues,
- [MetricKey.open_issues]: MetricKey.violations,
- [MetricKey.reopened_issues]: MetricKey.violations,
-};
-
-export function enhanceMeasuresWithMetrics(
- measures: Measure[],
- metrics: Metric[],
-): MeasureEnhanced[] {
- return measures
- .map((measure) => {
- const metric = metrics.find((metric) => metric.key === measure.metric);
- return metric && { ...measure, metric };
- })
- .filter(isDefined);
-}
-
-export function enhanceConditionWithMeasure(
- condition: QualityGateStatusCondition,
- measures: MeasureEnhanced[],
-): QualityGateStatusConditionEnhanced | undefined {
- const measure = measures.find((m) => m.metric.key === condition.metric);
-
- // Make sure we have a period index. This is necessary when dealing with
- // applications.
- let { period } = condition;
- if (measure?.period && !period) {
- period = measure.period.index;
- }
-
- return measure && { ...condition, period, measure };
-}
-
-export function isPeriodBestValue(measure: Measure | MeasureEnhanced): boolean {
- return measure.period?.bestValue ?? false;
-}
-
-/** Check if metric is differential */
-export function isDiffMetric(metricKey: MetricKey | string): boolean {
- return metricKey.startsWith('new_');
-}
-
-export function getDisplayMetrics(metrics: Metric[]) {
- return metrics.filter(
- (metric) =>
- !metric.hidden &&
- ![MetricType.Data, MetricType.Distribution].includes(metric.type as MetricType),
- );
-}
-
-export function findMeasure(measures: MeasureEnhanced[], metric: MetricKey | string) {
- return measures.find((measure) => measure.metric.key === metric);
-}
-
-export function areLeakCCTMeasuresComputed(measures?: Measure[] | MeasureEnhanced[]) {
- if (
- LEAK_OLD_TAXONOMY_METRICS.every(
- (metric) =>
- !measures?.find((measure) =>
- isMeasureEnhanced(measure) ? measure.metric.key === metric : measure.metric === metric,
- ),
- )
- ) {
- return true;
- }
- return LEAK_CCT_SOFTWARE_QUALITY_METRICS.every((metric) =>
- measures?.find((measure) =>
- isMeasureEnhanced(measure) ? measure.metric.key === metric : measure.metric === metric,
- ),
- );
-}
-
-export function areCCTMeasuresComputed(measures?: Measure[] | MeasureEnhanced[]) {
- if (!measures || measures.length === 0) {
- return true;
- }
- return CCT_SOFTWARE_QUALITY_METRICS.every((metric) =>
- measures?.find((measure) =>
- isMeasureEnhanced(measure) ? measure.metric.key === metric : measure.metric === metric,
- ),
- );
-}
-export function areSoftwareQualityRatingsComputed(measures?: Measure[] | MeasureEnhanced[]) {
- return [
- MetricKey.software_quality_reliability_rating,
- MetricKey.software_quality_security_rating,
- MetricKey.software_quality_maintainability_rating,
- ].every((metric) =>
- measures?.find((measure) =>
- isMeasureEnhanced(measure) ? measure.metric.key === metric : measure.metric === metric,
- ),
- );
-}
-
-export function areLeakSoftwareQualityRatingsComputed(measures?: Measure[] | MeasureEnhanced[]) {
- return [
- MetricKey.new_software_quality_reliability_rating,
- MetricKey.new_software_quality_security_rating,
- MetricKey.new_software_quality_maintainability_rating,
- ].every((metric) =>
- measures?.find((measure) =>
- isMeasureEnhanced(measure) ? measure.metric.key === metric : measure.metric === metric,
- ),
- );
-}
-
-export function areLeakAndOverallCCTMeasuresComputed(measures?: Measure[] | MeasureEnhanced[]) {
- return areLeakCCTMeasuresComputed(measures) && areCCTMeasuresComputed(measures);
-}
-
-function isMeasureEnhanced(measure: Measure | MeasureEnhanced): measure is MeasureEnhanced {
- return (measure.metric as Metric)?.key !== undefined;
-}
-
-type RatingValue = 'A' | 'B' | 'C' | 'D' | 'E';
-const RATING_VALUES: RatingValue[] = ['A', 'B', 'C', 'D', 'E'];
-export function formatRating(value: string | number | undefined): RatingValue | undefined {
- if (!value) {
- return undefined;
- }
-
- if (typeof value === 'string') {
- value = parseInt(value, 10);
- }
-
- // rating is 1-5, adjust for 0-based indexing
- return RATING_VALUES[value - 1];
-}
-
-/** Return a localized metric name */
-export function localizeMetric(metricKey: string): string {
- return translate('metric', metricKey, 'name');
-}
-
-/** Return corresponding "short" for better display in UI */
-export function getShortType(type: string): string {
- if (type === MetricType.Integer) {
- return MetricType.ShortInteger;
- } else if (type === 'WORK_DUR') {
- return MetricType.ShortWorkDuration;
- }
- return type;
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/alm-integrations.ts b/server/sonar-web/src/main/js/helpers/mocks/alm-integrations.ts
deleted file mode 100644
index 700920c668a..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/alm-integrations.ts
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- AzureProject,
- AzureRepository,
- BitbucketCloudRepository,
- BitbucketProject,
- BitbucketRepository,
- GithubRepository,
- GitlabProject,
-} from '../../types/alm-integration';
-import { GitlabConfiguration, ProvisioningType } from '../../types/provisioning';
-
-export function mockAzureProject(overrides: Partial<AzureProject> = {}): AzureProject {
- return {
- name: 'azure-project-1',
- description: 'Azure Project',
- ...overrides,
- };
-}
-
-export function mockAzureRepository(overrides: Partial<AzureRepository> = {}): AzureRepository {
- return {
- name: 'Azure repo 1',
- projectName: 'Azure Project',
- ...overrides,
- };
-}
-
-export function mockBitbucketProject(overrides: Partial<BitbucketProject> = {}): BitbucketProject {
- return {
- id: 1,
- key: 'project',
- name: 'Project',
- ...overrides,
- };
-}
-
-export function mockBitbucketRepository(
- overrides: Partial<BitbucketRepository> = {},
-): BitbucketRepository {
- return {
- id: 1,
- slug: 'project__repo',
- name: 'Repo',
- projectKey: 'project',
- ...overrides,
- };
-}
-
-export function mockBitbucketCloudRepository(
- overrides: Partial<BitbucketCloudRepository> = {},
-): BitbucketCloudRepository {
- return {
- uuid: 1,
- slug: 'project__repo',
- name: 'Repo',
- projectKey: 'project',
- workspace: 'worksapce',
- ...overrides,
- };
-}
-
-export function mockGitHubRepository(overrides: Partial<GithubRepository> = {}): GithubRepository {
- return {
- id: 'id1234',
- key: 'key3456',
- name: 'repository 1',
- url: 'https://github.com/owner/repo1',
- ...overrides,
- };
-}
-
-export function mockGitlabProject(overrides: Partial<GitlabProject> = {}): GitlabProject {
- return {
- id: 'id1234',
- name: 'Awesome Project !',
- slug: 'awesome-project-exclamation',
- pathName: 'Company / Best Projects',
- pathSlug: 'company/best-projects',
- url: 'https://gitlab.company.com/best-projects/awesome-project-exclamation',
- ...overrides,
- };
-}
-
-export function mockGitlabConfiguration(
- overrides: Partial<GitlabConfiguration> = {},
-): GitlabConfiguration {
- return {
- id: Math.random().toString(),
- enabled: false,
- url: 'URL',
- applicationId: '123',
- allowUsersToSignUp: false,
- synchronizeGroups: true,
- provisioningType: ProvisioningType.jit,
- allowedGroups: ['Cypress Hill'],
- isProvisioningTokenSet: false,
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts b/server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts
deleted file mode 100644
index f506f6106a7..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/alm-settings.ts
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- AlmKeys,
- AlmSettingsBindingStatus,
- AlmSettingsBindingStatusType,
- AlmSettingsInstance,
- AzureBindingDefinition,
- BitbucketCloudBindingDefinition,
- BitbucketServerBindingDefinition,
- GithubBindingDefinition,
- GitlabBindingDefinition,
- ProjectAlmBindingConfigurationErrors,
- ProjectAlmBindingConfigurationErrorScope,
- ProjectAlmBindingResponse,
- ProjectAzureBindingResponse,
- ProjectBitbucketBindingResponse,
- ProjectBitbucketCloudBindingResponse,
- ProjectGitHubBindingResponse,
- ProjectGitLabBindingResponse,
-} from '../../types/alm-settings';
-
-export function mockAlmSettingsInstance(
- overrides: Partial<AlmSettingsInstance> = {},
-): AlmSettingsInstance {
- return {
- alm: AlmKeys.GitHub,
- key: 'key',
- ...overrides,
- };
-}
-
-export function mockBitbucketCloudAlmSettingsInstance(
- overrides: Partial<AlmSettingsInstance> = {},
-): AlmSettingsInstance {
- return {
- alm: AlmKeys.BitbucketCloud,
- key: 'key',
- ...overrides,
- };
-}
-
-export function mockAzureBindingDefinition(
- overrides: Partial<AzureBindingDefinition> = {},
-): AzureBindingDefinition {
- return {
- key: 'key',
- personalAccessToken: 'asdf1234',
- ...overrides,
- };
-}
-
-export function mockBitbucketServerBindingDefinition(
- overrides: Partial<BitbucketServerBindingDefinition> = {},
-): BitbucketServerBindingDefinition {
- return {
- key: 'key',
- personalAccessToken: 'asdf1234',
- url: 'http://bbs.enterprise.com',
- ...overrides,
- };
-}
-
-export function mockBitbucketCloudBindingDefinition(
- overrides: Partial<BitbucketCloudBindingDefinition> = {},
-): BitbucketCloudBindingDefinition {
- return {
- key: 'key',
- clientId: 'client1',
- clientSecret: '**clientsecret**',
- workspace: 'workspace',
- ...overrides,
- };
-}
-
-export function mockGithubBindingDefinition(
- overrides: Partial<GithubBindingDefinition> = {},
-): GithubBindingDefinition {
- return {
- key: 'key',
- url: 'http://github.enterprise.com',
- appId: '123456',
- clientId: 'client1',
- clientSecret: '**clientsecret**',
- privateKey: 'asdf1234',
- webhookSecret: 'verySecretText!!',
- ...overrides,
- };
-}
-
-export function mockGitlabBindingDefinition(
- overrides: Partial<GitlabBindingDefinition> = {},
-): GitlabBindingDefinition {
- return {
- key: 'foo',
- personalAccessToken: 'foobar',
- ...overrides,
- };
-}
-
-export function mockProjectAlmBindingResponse(
- overrides: Partial<ProjectAlmBindingResponse> = {},
-): ProjectAlmBindingResponse {
- return {
- alm: AlmKeys.GitHub,
- key: 'foo',
- repository: 'repo',
- monorepo: false,
- ...overrides,
- };
-}
-
-export function mockProjectBitbucketBindingResponse(
- overrides: Partial<ProjectBitbucketBindingResponse> = {},
-): ProjectBitbucketBindingResponse {
- return {
- alm: AlmKeys.BitbucketServer,
- key: 'foo',
- repository: 'PROJECT_KEY',
- slug: 'repo-slug',
- monorepo: true,
- ...overrides,
- };
-}
-
-export function mockProjectBitbucketCloudBindingResponse(
- overrides: Partial<ProjectBitbucketCloudBindingResponse> = {},
-): ProjectBitbucketCloudBindingResponse {
- return {
- alm: AlmKeys.BitbucketCloud,
- key: 'foo',
- repository: 'repo-slug',
- monorepo: true,
- ...overrides,
- };
-}
-
-export function mockProjectGithubBindingResponse(
- overrides: Partial<ProjectGitHubBindingResponse> = {},
-): ProjectGitHubBindingResponse {
- return {
- alm: AlmKeys.GitHub,
- key: 'foo',
- repository: 'PROJECT_KEY',
- monorepo: true,
- ...overrides,
- };
-}
-
-export function mockProjectGitLabBindingResponse(
- overrides: Partial<ProjectGitLabBindingResponse> = {},
-): ProjectGitLabBindingResponse {
- return {
- alm: AlmKeys.GitLab,
- key: 'foo',
- repository: 'PROJECT_KEY',
- url: 'https://gitlab.com/api/v4',
- monorepo: true,
- ...overrides,
- };
-}
-
-export function mockProjectAzureBindingResponse(
- overrides: Partial<ProjectAzureBindingResponse> = {},
-): ProjectAzureBindingResponse {
- return {
- alm: AlmKeys.Azure,
- key: 'foo',
- slug: 'PROJECT_NAME',
- repository: 'REPOSITORY_NAME',
- url: 'https://ado.my_company.com/mycollection',
- monorepo: false,
- ...overrides,
- };
-}
-
-export function mockAlmSettingsBindingStatus(
- overrides: Partial<AlmSettingsBindingStatus>,
-): AlmSettingsBindingStatus {
- return {
- alertSuccess: false,
- failureMessage: '',
- type: AlmSettingsBindingStatusType.Validating,
- ...overrides,
- };
-}
-
-export function mockProjectAlmBindingConfigurationErrors(
- overrides: Partial<ProjectAlmBindingConfigurationErrors> = {},
-): ProjectAlmBindingConfigurationErrors {
- return {
- scope: ProjectAlmBindingConfigurationErrorScope.Global,
- errors: [{ msg: 'Foo bar is not correct' }, { msg: 'Bar baz has no permissions here' }],
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/application.ts b/server/sonar-web/src/main/js/helpers/mocks/application.ts
deleted file mode 100644
index 8666da7a209..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/application.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ApplicationPeriod } from '../../types/application';
-
-export function mockApplicationPeriod(
- overrides: Partial<ApplicationPeriod> = {},
-): ApplicationPeriod {
- return {
- date: '2017-10-01',
- project: 'foo',
- projectName: 'Foo',
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/branch-like.ts b/server/sonar-web/src/main/js/helpers/mocks/branch-like.ts
deleted file mode 100644
index 7eb716e979e..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/branch-like.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Branch, BranchLike, MainBranch, PullRequest } from '../../types/branch-like';
-
-export function mockBranch(overrides: Partial<Branch> = {}): Branch {
- return {
- analysisDate: '2018-01-01',
- excludedFromPurge: true,
- isMain: false,
- name: 'branch-6.7',
- ...overrides,
- };
-}
-
-export function mockMainBranch(overrides: Partial<MainBranch> = {}): MainBranch {
- return mockBranch({
- isMain: true,
- name: 'master',
- ...overrides,
- }) as MainBranch;
-}
-
-export function mockPullRequest(overrides: Partial<PullRequest> = {}): PullRequest {
- return {
- analysisDate: '2018-01-01',
- base: 'master',
- branch: 'feature/foo/bar',
- key: '1001',
- target: 'master',
- title: 'Foo Bar feature',
- ...overrides,
- };
-}
-
-export function mockSetOfBranchAndPullRequest(): BranchLike[] {
- return [
- mockBranch({ name: 'branch-11' }),
- mockBranch({ name: 'branch-1' }),
- mockMainBranch(),
- mockPullRequest({ key: '1', title: 'PR-1' }),
- mockBranch({ name: 'branch-12' }),
- mockPullRequest({ key: '2', title: 'PR-2' }),
- mockBranch({ name: 'branch-3' }),
- mockBranch({ name: 'branch-2' }),
- mockPullRequest({
- key: '2',
- title: 'PR-2',
- target: 'llb-100',
- isOrphan: true,
- }),
- ];
-}
-
-export function mockSetOfBranchAndPullRequestForBranchSelector(): BranchLike[] {
- return [
- mockBranch({ name: 'branch-1', status: { qualityGateStatus: 'OK' } }),
- mockMainBranch(),
- mockPullRequest({ key: '1', title: 'PR-1', status: { qualityGateStatus: 'OK' } }),
- mockBranch({ name: 'branch-2', status: { qualityGateStatus: 'OK' } }),
- mockPullRequest({ key: '2', title: 'PR-2', status: { qualityGateStatus: 'OK' } }),
- mockBranch({ name: 'branch-3', status: { qualityGateStatus: 'OK' } }),
- ];
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/component-report.ts b/server/sonar-web/src/main/js/helpers/mocks/component-report.ts
deleted file mode 100644
index 8e5c7d3e6d8..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/component-report.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentReportStatus } from '../../types/component-report';
-
-export function mockComponentReportStatus(
- props?: Partial<ComponentReportStatus>,
-): ComponentReportStatus {
- return {
- canAdmin: true,
- canDownload: true,
- canSubscribe: true,
- componentRecipients: [],
- globalFrequency: '',
- globalRecipients: [],
- subscribed: false,
- ...props,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/component.ts b/server/sonar-web/src/main/js/helpers/mocks/component.ts
deleted file mode 100644
index fe93701c862..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/component.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentQualifier, Visibility } from '~sonar-aligned/types/component';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { ComponentRaw } from '../../api/components';
-import { TreeComponent } from '../../types/component';
-import { Component, ComponentMeasure, ComponentMeasureEnhanced } from '../../types/types';
-import { mockMeasureEnhanced } from '../testMocks';
-
-export function mockComponent(overrides: Partial<Component> = {}): Component {
- return {
- breadcrumbs: [],
- key: 'my-project',
- name: 'MyProject',
- qualifier: ComponentQualifier.Project,
- qualityGate: { isDefault: true, key: '30', name: 'Sonar way' },
- qualityProfiles: [
- {
- deleted: false,
- key: 'my-qp',
- language: 'ts',
- name: 'Sonar way',
- },
- ],
- tags: [],
- ...overrides,
- };
-}
-
-export function mockComponentRaw(overrides: Partial<ComponentRaw> = {}): ComponentRaw {
- return {
- key: 'my-project',
- name: 'MyProject',
- qualifier: ComponentQualifier.Project,
- tags: [],
- ...overrides,
- visibility: Visibility.Public,
- };
-}
-
-export function mockTreeComponent(overrides: Partial<TreeComponent>): TreeComponent {
- return {
- key: 'my-key',
- qualifier: ComponentQualifier.Project,
- name: 'component',
- visibility: Visibility.Public,
- ...overrides,
- };
-}
-
-export function mockComponentMeasure(
- file = false,
- overrides: Partial<ComponentMeasure> = {},
-): ComponentMeasure {
- if (file) {
- return {
- key: 'foo:src/index.tsx',
- name: 'index.tsx',
- qualifier: ComponentQualifier.File,
- path: 'src/index.tsx',
- measures: [{ metric: MetricKey.bugs, value: '1', bestValue: false }],
- ...overrides,
- };
- }
- return {
- key: 'foo',
- name: 'Foo',
- qualifier: ComponentQualifier.Project,
- measures: [{ metric: MetricKey.bugs, value: '12', bestValue: false }],
- ...overrides,
- };
-}
-
-export function mockComponentMeasureEnhanced(
- overrides: Partial<ComponentMeasureEnhanced> = {},
-): ComponentMeasureEnhanced {
- return {
- ...mockComponentMeasure(false, overrides as ComponentMeasure),
- leak: undefined,
- measures: [mockMeasureEnhanced()],
- value: undefined,
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/definitions-list.ts b/server/sonar-web/src/main/js/helpers/mocks/definitions-list.ts
deleted file mode 100644
index d7920ab15d7..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/definitions-list.ts
+++ /dev/null
@@ -1,2472 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ExtendedSettingDefinition, SettingType } from '../../types/settings';
-
-export const definitions: ExtendedSettingDefinition[] = [
- {
- key: 'sonar.abap.file.suffixes',
- name: 'File suffixes',
- description: 'List of suffixes for files to analyze. To not filter, leave the list empty.',
- category: 'ABAP',
- subCategory: 'General',
- defaultValue: '.abap,.ab4,.flow,.asprog',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.apex.file.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes for files to analyze.',
- category: 'Apex',
- subCategory: 'General',
- defaultValue: '.cls,.trigger',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.apex.coverage.reportPath',
- name: 'Path to coverage report',
- description:
- 'Path to coverage report file (test-result-codecoverage.json) generated by Salesforce CLI test command for Apex. The path may be absolute or relative to the project base directory.',
- category: 'Apex',
- subCategory: 'Test and Coverage',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.saml.enabled',
- name: 'Enabled',
- description:
- 'Enable SAML users to login. Value is ignored if provider ID, login url, certificate, login, name attributes are not defined.',
- type: SettingType.BOOLEAN,
- category: 'authentication',
- subCategory: 'saml',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.github.enabled',
- name: 'Enabled',
- description:
- 'Enable GitHub users to login. Value is ignored if client ID and secret are not defined.',
- type: SettingType.BOOLEAN,
- category: 'authentication',
- subCategory: 'github',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.bitbucket.enabled',
- name: 'Enabled',
- description:
- 'Enable Bitbucket users to login. Value is ignored if consumer key and secret are not defined.',
- type: SettingType.BOOLEAN,
- category: 'authentication',
- subCategory: 'bitbucket',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.saml.applicationId',
- name: 'Application ID',
- description: 'The identifier used on the Identity Provider for registering SonarQube.',
- category: 'authentication',
- subCategory: 'saml',
- defaultValue: 'sonarqube',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.github.clientId.secured',
- name: 'Client ID',
- description: 'Client ID provided by GitHub when registering the application.',
- category: 'authentication',
- subCategory: 'github',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.bitbucket.clientId.secured',
- name: 'OAuth consumer key',
- description: 'Consumer key provided by Bitbucket when registering the consumer.',
- category: 'authentication',
- subCategory: 'bitbucket',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.github.appId',
- name: 'App ID',
- description:
- 'The App ID is found on your GitHub App\u0027s page on GitHub at Settings \u003e Developer Settings \u003e GitHub Apps.',
- category: 'authentication',
- subCategory: 'github',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.github.privateKey.secured',
- name: 'Private Key',
- description:
- 'Your GitHub App\u0027s private key. You can generate a .pem file from your GitHub App\u0027s page under Private keys.\nCopy and paste the whole contents of the file here.',
- type: SettingType.TEXT,
- category: 'authentication',
- subCategory: 'github',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.github.clientSecret.secured',
- name: 'Client Secret',
- description: 'Client password provided by GitHub when registering the application.',
- type: SettingType.PASSWORD,
- category: 'authentication',
- subCategory: 'github',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.bitbucket.clientSecret.secured',
- name: 'OAuth consumer secret',
- description: 'Consumer secret provided by Bitbucket when registering the consumer.',
- category: 'authentication',
- subCategory: 'bitbucket',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.saml.providerName',
- name: 'Provider Name',
- description:
- 'Name of the Identity Provider displayed in the login page when SAML authentication is active.',
- category: 'authentication',
- subCategory: 'saml',
- defaultValue: 'SAML',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.bitbucket.allowUsersToSignUp',
- name: 'Allow users to sign up',
- description:
- 'Allow new users to authenticate. When set to disabled, only existing users will be able to authenticate.',
- type: SettingType.BOOLEAN,
- category: 'authentication',
- subCategory: 'bitbucket',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.github.allowUsersToSignUp',
- name: 'Allow users to sign up',
- description:
- 'Allow new users to authenticate. When set to disabled, only existing users will be able to authenticate to the server.',
- type: SettingType.BOOLEAN,
- category: 'authentication',
- subCategory: 'github',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.saml.providerId',
- name: 'Provider ID',
- description:
- 'Identifier of the Identity Provider, the entity that provides SAML authentication.',
- category: 'authentication',
- subCategory: 'saml',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.saml.loginUrl',
- name: 'SAML login url',
- description: 'The URL where the Identity Provider expects to receive SAML requests.',
- category: 'authentication',
- subCategory: 'saml',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.bitbucket.workspaces',
- name: 'Workspaces',
- description:
- 'Only members of at least one of these workspace will be able to authenticate. Keep empty to disable workspace restriction. You can use either the workspace name, or the workspace slug (ex: https://bitbucket.org/{workspace-slug}).',
- category: 'authentication',
- subCategory: 'bitbucket',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.saml.certificate.secured',
- name: 'Identity provider certificate',
- description:
- 'The public X.509 certificate used by the Identity Provider to authenticate SAML messages.',
- type: SettingType.PASSWORD,
- category: 'authentication',
- subCategory: 'saml',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.github.groupsSync',
- name: 'Synchronize teams as groups',
- description:
- 'Synchronize GitHub team with SonarQube group memberships when users log in to SonarQube. For each GitHub team they belong to, users will be associated to a group of the same name if it exists in SonarQube.',
- type: SettingType.BOOLEAN,
- category: 'authentication',
- subCategory: 'github',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.saml.user.login',
- name: 'SAML user login attribute',
- description:
- 'The name of the attribute where the SAML Identity Provider will put the login of the authenticated user.',
- category: 'authentication',
- subCategory: 'saml',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.github.apiUrl',
- name: 'The API url for a GitHub instance.',
- description:
- 'The API url for a GitHub instance. https://api.github.com/ for Github.com, https://github.company.com/api/v3/ when using Github Enterprise',
- category: 'authentication',
- subCategory: 'github',
- defaultValue: 'https://api.github.com/',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.saml.user.name',
- name: 'SAML user name attribute',
- description:
- 'The name of the attribute where the SAML Identity Provider will put the name of the authenticated user.',
- category: 'authentication',
- subCategory: 'saml',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.github.webUrl',
- name: 'The WEB url for a GitHub instance.',
- description:
- 'The WEB url for a GitHub instance. https://github.com/ for Github.com, https://github.company.com/ when using GitHub Enterprise.',
- category: 'authentication',
- subCategory: 'github',
- defaultValue: 'https://github.com/',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.github.organizations',
- name: 'Organizations',
- description:
- 'Only members of these organizations will be able to authenticate to the server. ⚠︎ if not set, users from any organization where the GitHub App is installed will be able to login to this SonarQube instance.',
- category: 'authentication',
- subCategory: 'github',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.saml.user.email',
- name: 'SAML user email attribute',
- description:
- 'The name of the attribute where the SAML Identity Provider will put the email of the authenticated user.',
- category: 'authentication',
- subCategory: 'saml',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.saml.group.name',
- name: 'SAML group attribute',
- description:
- 'Attribute defining the user groups in SAML. Users are associated to the default group only if no attribute is defined.',
- category: 'authentication',
- subCategory: 'saml',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.saml.signature.enabled',
- name: 'Sign requests',
- description:
- 'Enables signature of SAML requests. It requires both service provider private key and certificate to be set.',
- type: SettingType.BOOLEAN,
- category: 'authentication',
- subCategory: 'saml',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.saml.sp.privateKey.secured',
- name: 'Service provider private key',
- description:
- 'PKCS8 stored private key used for signing the requests and decrypting responses from the identity provider. ',
- type: SettingType.PASSWORD,
- category: 'authentication',
- subCategory: 'saml',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.saml.sp.certificate.secured',
- name: 'Service provider certificate',
- description: 'X.509 certificate for the service provider, used for signing the requests.',
- type: SettingType.PASSWORD,
- category: 'authentication',
- subCategory: 'saml',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cfamily.bullseye.reportPath',
- name: 'Bullseye XML report',
- description:
- 'Path to the Bullseye XML Coverage Report. The path may be either absolute or relative to the project base directory.',
- category: 'C / C++ / Objective-C',
- subCategory: ' Coverage',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.c.file.suffixes',
- name: 'C file suffixes',
- description: 'List of suffixes of C files to analyze.',
- category: 'C / C++ / Objective-C',
- subCategory: ' C and C++',
- defaultValue: '.c,.h',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cpp.file.suffixes',
- name: 'C++ file suffixes',
- description: 'List of suffixes of C++ files to analyze.',
- category: 'C / C++ / Objective-C',
- subCategory: ' C and C++',
- defaultValue: '.cc,.cpp,.cxx,.c++,.hh,.hpp,.hxx,.h++,.ipp',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cfamily.cppunit.reportsPath',
- name: 'CppUnit reports',
- description:
- 'Path to the directory containing the *.xml CppUnit report files. The path may be either absolute or relative to the project base directory.',
- category: 'C / C++ / Objective-C',
- subCategory: ' Tests',
- options: [],
- fields: [],
- deprecatedKey: 'sonar.cpp.cppunit.reportsPath',
- },
- {
- key: 'sonar.cfamily.gcov.reportsPath',
- name: 'Gcov reports',
- description:
- 'Path to the directory containing the *.gcov Gcov report files. The path may be either absolute or relative to the project base directory.',
- category: 'C / C++ / Objective-C',
- subCategory: ' Coverage',
- options: [],
- fields: [],
- deprecatedKey: 'sonar.cpp.gcov.reportsPath',
- },
- {
- key: 'sonar.cfamily.ignoreHeaderComments',
- name: 'Ignore header comments',
- description:
- 'If set to "true", the file headers (that are usually the same on each file: licensing information for example) are not considered as comments. Thus metrics such as "Comment lines" do not get incremented. If set to "false", those file headers are considered as comments and metrics such as "Comment lines" get incremented.',
- type: SettingType.BOOLEAN,
- category: 'C / C++ / Objective-C',
- subCategory: ' Miscellaneous',
- defaultValue: 'true',
- options: [],
- fields: [],
- deprecatedKey: 'sonar.cpp.ignoreHeaderComments',
- },
- {
- key: 'sonar.cfamily.llvm-cov.reportPath',
- name: 'llvm-cov report',
- description:
- 'Path to the Coverage Report generated by "llvm-cov show". The path may be either absolute or relative to the project base directory.',
- category: 'C / C++ / Objective-C',
- subCategory: ' Coverage',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.objc.file.suffixes',
- name: 'Objective-C file suffixes',
- description: 'List of suffixes of Objective-C files to analyze.',
- category: 'C / C++ / Objective-C',
- subCategory: ' Objective-C',
- defaultValue: '.m',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cfamily.vscoveragexml.reportsPath',
- name: 'Visual Studio XML reports',
- description:
- 'Pattern for search for Visual Studio Coverage XML reports. The pattern may be either absolute or relative to the project base directory. For example: "**/*.coveragexml" will find all "*.coveragexml" files in all sub-directories of current project.',
- category: 'C / C++ / Objective-C',
- subCategory: ' Coverage',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cs.analyzeGeneratedCode',
- name: 'Analyze generated code',
- description:
- 'If set to "true", the files containing generated code are analyzed. If set to "false", the files containing generated code are ignored.',
- type: SettingType.BOOLEAN,
- category: 'C#',
- subCategory: 'C#',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cs.file.suffixes',
- name: 'File suffixes',
- description: 'List of suffixes for files to analyze.',
- category: 'C#',
- subCategory: 'C#',
- defaultValue: '.cs',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cs.ignoreHeaderComments',
- name: 'Ignore header comments',
- description:
- 'If set to "true", the file headers (that are usually the same on each file: licensing information for example) are not considered as comments. Thus metrics such as "Comment lines" do not get incremented. If set to "false", those file headers are considered as comments and metrics such as "Comment lines" get incremented.',
- type: SettingType.BOOLEAN,
- category: 'C#',
- subCategory: 'C#',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cloudformation.activate',
- name: 'Activate CloudFormation analysis',
- description: 'Activate analysis of JSON and Yaml files recognized as CloudFormation files.',
- type: SettingType.BOOLEAN,
- category: 'CloudFormation',
- subCategory: 'General',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cloudformation.file.identifier',
- name: 'File Identifier',
- description:
- 'Files without the identifier are excluded from the analysis. The identifier can be anywhere in the file.',
- category: 'CloudFormation',
- subCategory: 'General',
- defaultValue: 'AWSTemplateFormatVersion',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cobol.aucobol.preprocessor.directives.default',
- name: 'AcuCobol preprocessor default directives',
- description:
- 'This property allows to set preprocessor directives used to compile every COBOL program. See the \'ACUCOBOL-GT Source Code Control directives\' section in the <a target="_blank" href="http://docs.sonarsource.com/sonarqube/display/PLUG/COBOL+Plugin+Advanced+Configuration">documentation of the plugin</a>.',
- category: 'COBOL',
- subCategory: 'Preprocessor',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cobol.adaprep.activation',
- name: 'ADAPREP preprocessor activation',
- description:
- 'ADAPREP is a COBOL preprocessor which provides the programmer with the full ADABAS (See Software AG) capability. Activating this property is mandatory if the COBOL source code might contain some ADAPREP directives.',
- type: SettingType.BOOLEAN,
- category: 'COBOL',
- subCategory: 'Preprocessor',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cobol.copy.suffixes',
- name: 'Copy suffixes',
- description:
- "Comma-separated list of suffixes for copybook to analyze, ex: 'cpy, cbl'. To not filter, leave the list empty.",
- category: 'COBOL',
- subCategory: 'Preprocessor',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cobol.copy.directories',
- name: 'Copybook directories',
- description:
- 'Comma-separated list of all directories containing some copybooks required to analyze the COBOL programs. Both relative and absolute paths can be used.',
- category: 'COBOL',
- subCategory: 'Preprocessor',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cobol.copy.exclusions',
- name: 'Copybooks to exclude',
- description:
- 'Comma-separated list of copybooks exclusion patterns. If one copybook name matches one exclusion pattern, no violation will be reported on this copybook. The exclusion pattern must be a case-insensitive regular expression and should not include the copybook suffix.<p>For instance "one\\d*,TWO." will exclude violations reported on one23.cpy, ONE111.cpy, TWOX, and TWO2.cpy copybooks.</p>',
- category: 'COBOL',
- subCategory: 'Preprocessor',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cobol.byteBasedColumnCount',
- name: 'Count columns based on bytes',
- description:
- 'This property should be set to true if source columns have to be counted based on bytes rather than characters. That may be useful for projects using double-byte character set.',
- type: SettingType.BOOLEAN,
- category: 'COBOL',
- subCategory: 'COBOL',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cobol.preprocessor.skipping.first.matching.characters',
- name: 'Custom skipping preprocessor first matching characters',
- description:
- "<p>To support a maximum number of legacy COBOL preprocessors, this property allows to define which lines of code should be considered as a preprocessing line and so should be ignored when analyzing the COBOL source code.</p><p>For example, if this property is set to '%', all lines starting with a '%' character, and whatever is the position of this first character in the line, won't be analyzed. If this property is set to '%?', all lines starting with a '%' or a '?' will be ignored.</p>",
- category: 'COBOL',
- subCategory: 'Preprocessor',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cobol.db2include.directories',
- name: 'DB2 Include directories',
- description:
- 'Comma-separated list of all directories (either relative or absolute paths) containing some copybooks required to analyze the COBOL programs. This property is used when interpreting the DB2 INCLUDE preprocessing directive (EXEC SQL INCLUDE ... END-EXEC) to locate the copybook files. When this property is not set, the property "sonar.cobol.copy.directories" is used instead.',
- category: 'COBOL',
- subCategory: 'SQL/CICS',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cobol.dialect',
- name: 'Dialect',
- description: 'The COBOL dialect to be used for the analysis.',
- type: SettingType.SINGLE_SELECT_LIST,
- category: 'COBOL',
- subCategory: 'COBOL',
- defaultValue: 'ibm-enterprise-cobol',
- options: [
- 'bull-gcos-cobol',
- 'hp-tandem-cobol',
- 'ibm-os/vs-cobol',
- 'ibm-ile-cobol',
- 'ibm-cobol/ii',
- 'ibm-cobol/400',
- 'ibm-enterprise-cobol',
- 'microfocus-cobol',
- 'microfocus-acucobol-gt-cobol',
- 'opencobol/cobol-it',
- ],
- fields: [],
- },
- {
- key: 'sonar.cobol.exec.recoveryMode',
- name: 'Exec SQL/CICS Recovery mode',
- description:
- 'This option must be activated when the COBOL parser is unable to parse a specific SQL dialect like Pro*Cobol for instance.',
- type: SettingType.BOOLEAN,
- category: 'COBOL',
- subCategory: 'SQL/CICS',
- defaultValue: 'true',
- options: [],
- fields: [],
- deprecatedKey: 'sonar.cobol.sql.recoveryMode',
- },
- {
- key: 'sonar.cobol.file.suffixes',
- name: 'File suffixes',
- description:
- 'Comma-separated list of suffixes for files to analyze. To not filter, leave the list empty.',
- category: 'COBOL',
- subCategory: 'COBOL',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cpd.cobol.ignoreLiteral',
- name: 'Ignore literals',
- description:
- "If true, CPD ignores literal value differences when evaluating a duplicated block. This means that 'my first text'; and 'my second text' will be seen as equivalent.",
- type: SettingType.BOOLEAN,
- category: 'COBOL',
- subCategory: 'Duplications',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cobol.compilationConstants',
- name: 'Microfocus Compilation Constants',
- description:
- 'If your code takes advantage of conditional compilation features provided by Microfocus, you may have to configure compiler constants for your analysis.',
- type: SettingType.PROPERTY_SET,
- category: 'COBOL',
- subCategory: 'Preprocessor',
- multiValues: true,
- options: [],
- fields: [
- {
- key: 'name',
- name: 'Compilation Constant Name',
- options: [],
- },
- {
- key: 'value',
- name: 'Compilation Constant Value',
- options: [],
- },
- ],
- },
- {
- key: 'sonar.cobol.sql.catalog.defaultSchema',
- name: 'Names of default database schemas',
- description:
- 'Comma-separated list of default database schemas used in embedded SQL statements. If a table name matches more than one, the table will be resolved to the first matching schema.',
- category: 'COBOL',
- subCategory: 'SQL/CICS',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cobol.sql.catalog.csv.path',
- name: 'Path for database catalog CSV files',
- description: 'Path of the directory containing CSV files for the database catalog.',
- category: 'COBOL',
- subCategory: 'SQL/CICS',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cobol.sourceFormat',
- name: 'Source format',
- description:
- 'In fixed format, there is both a left and right margin; the indicator area is expected in column 7 and the code area ends in column 72. In variable format, there is only a left margin; the indicator area is expected in column 7. In free format, there is no margin; the indicator area is expected in column 1.',
- type: SettingType.SINGLE_SELECT_LIST,
- category: 'COBOL',
- subCategory: 'COBOL',
- defaultValue: 'fixed',
- options: ['fixed', 'variable', 'free'],
- fields: [],
- },
- {
- key: 'sonar.cobol.tab.width',
- name: 'Tab width',
- description:
- 'Number of expanded spaces for a tab character (\'\t\'). This property really matters when the Source format is "fixed".',
- type: SettingType.INTEGER,
- category: 'COBOL',
- subCategory: 'COBOL',
- defaultValue: '8',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.css.file.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes for files to analyze.',
- category: 'CSS',
- subCategory: 'General',
- defaultValue: '.css,.less,.scss',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.docker.activate',
- name: 'Activate Docker Analysis',
- description:
- 'Disabling Docker analysis ensures that no Docker files are parsed, highlighted and analyzed, and no IaC analysis results are included in the quality gate.',
- type: SettingType.BOOLEAN,
- category: 'Docker',
- subCategory: 'General',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.global.exclusions',
- name: 'Global Source File Exclusions',
- category: 'exclusions',
- subCategory: 'files',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.exclusions',
- name: 'Source File Exclusions',
- category: 'exclusions',
- subCategory: 'files',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.global.test.exclusions',
- name: 'Global Test File Exclusions',
- category: 'exclusions',
- subCategory: 'files',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.issue.ignore.allfile',
- name: 'Ignore Issues on Files',
- description:
- 'Patterns to ignore all issues on files that contain a block of code matching a given regular expression.',
- type: SettingType.PROPERTY_SET,
- category: 'exclusions',
- subCategory: 'issues',
- options: [],
- fields: [
- {
- key: 'fileRegexp',
- name: 'Regular Expression',
- description:
- 'If this regular expression is found in a file, then the whole file is ignored.',
- options: [],
- },
- ],
- },
- {
- key: 'sonar.inclusions',
- name: 'Source File Inclusions',
- category: 'exclusions',
- subCategory: 'files',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.issue.ignore.block',
- name: 'Ignore Issues in Blocks',
- description:
- 'Patterns to ignore all issues on specific blocks of code, while continuing to scan and mark issues on the remainder of the file.',
- type: SettingType.PROPERTY_SET,
- category: 'exclusions',
- subCategory: 'issues',
- options: [],
- fields: [
- {
- key: 'beginBlockRegexp',
- name: 'Regular Expression for Start of Block',
- description:
- 'If this regular expression is found in a file, then following lines are ignored until end of block.',
- options: [],
- },
- {
- key: 'endBlockRegexp',
- name: 'Regular Expression for End of Block',
- description:
- 'If specified, this regular expression is used to determine the end of code blocks to ignore. If not, then block ends at the end of file.',
- options: [],
- },
- ],
- },
- {
- key: 'sonar.test.exclusions',
- name: 'Test File Exclusions',
- category: 'exclusions',
- subCategory: 'files',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.issue.ignore.multicriteria',
- name: 'Ignore Issues on Multiple Criteria',
- description:
- 'Patterns to ignore issues on certain components and for certain coding rules.<br/>A rule key pattern consists of the rule repository name, followed by a colon, followed by a rule key or rule name fragment. For example:<ul><li>java:S1195</li><li>java:*Naming*</li></ul>',
- type: SettingType.PROPERTY_SET,
- category: 'exclusions',
- subCategory: 'issues',
- options: [],
- fields: [
- {
- key: 'ruleKey',
- name: 'Rule Key Pattern',
- description: 'Pattern to match rules which should be ignored.',
- options: [],
- },
- {
- key: 'resourceKey',
- name: 'File Path Pattern',
- description: 'Pattern to match files which should be ignored.',
- options: [],
- },
- ],
- },
- {
- key: 'sonar.test.inclusions',
- name: 'Test File Inclusions',
- category: 'exclusions',
- subCategory: 'files',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.issue.enforce.multicriteria',
- name: 'Restrict Scope of Coding Rules',
- description:
- 'Patterns to restrict the application of a rule to only certain components, ignoring all others.<br/>A rule key pattern consists of the rule repository name, followed by a colon, followed by a rule key or rule name fragment. For example:<ul><li>java:S1195</li><li>java:*Naming*</li></ul>',
- type: SettingType.PROPERTY_SET,
- category: 'exclusions',
- subCategory: 'issues',
- options: [],
- fields: [
- {
- key: 'ruleKey',
- name: 'Rule Key Pattern',
- description: 'Pattern used to match rules which should be restricted.',
- options: [],
- },
- {
- key: 'resourceKey',
- name: 'File Path Pattern',
- description: 'Pattern used to match files to which the rules should be restricted.',
- options: [],
- },
- ],
- },
- {
- key: 'sonar.coverage.exclusions',
- category: 'exclusions',
- subCategory: 'coverage',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cpd.exclusions',
- name: 'Duplication Exclusions',
- description:
- 'Patterns used to exclude some source files from the duplication detection mechanism. See below to know how to use wildcards to specify this property.',
- category: 'exclusions',
- subCategory: 'duplications',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.vbnet.roslyn.ignoreIssues',
- name: 'Ignore issues from external Roslyn analyzers',
- description:
- "If set to 'true', issues reported by external Roslyn analyzers won't be imported.",
- type: SettingType.BOOLEAN,
- category: 'External Analyzers',
- subCategory: 'VB.NET',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cs.roslyn.ignoreIssues',
- name: 'Ignore issues from external Roslyn analyzers',
- description:
- "If set to 'true', issues reported by external Roslyn analyzers won't be imported.",
- type: SettingType.BOOLEAN,
- category: 'External Analyzers',
- subCategory: 'C#',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.vbnet.roslyn.bugCategories',
- name: 'Rule categories associated with Bugs',
- description: 'External rule categories to be treated as Bugs.',
- category: 'External Analyzers',
- subCategory: 'VB.NET',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cs.roslyn.bugCategories',
- name: 'Rule categories associated with Bugs',
- description: 'External rule categories to be treated as Bugs.',
- category: 'External Analyzers',
- subCategory: 'C#',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cs.roslyn.vulnerabilityCategories',
- name: 'Rule categories associated with Vulnerabilities',
- description: 'External rule categories to be treated as Vulnerabilities.',
- category: 'External Analyzers',
- subCategory: 'C#',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.vbnet.roslyn.vulnerabilityCategories',
- name: 'Rule categories associated with Vulnerabilities',
- description: 'External rule categories to be treated as Vulnerabilities.',
- category: 'External Analyzers',
- subCategory: 'VB.NET',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cs.roslyn.codeSmellCategories',
- name: 'Rule categories associated with Code Smells',
- description:
- 'External rule categories to be treated as Code Smells. By default, external issues are Code Smells, or Bugs when the severity is error.',
- category: 'External Analyzers',
- subCategory: 'C#',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.vbnet.roslyn.codeSmellCategories',
- name: 'Rule categories associated with Code Smells',
- description:
- 'External rule categories to be treated as Code Smells. By default, external issues are Code Smells, or Bugs when the severity is error.',
- category: 'External Analyzers',
- subCategory: 'VB.NET',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cloudformation.cfn-lint.reportPaths',
- name: 'Cfn-Lint Report Files',
- description: 'Paths (absolute or relative) to the files with Cfn-Lint issues.',
- category: 'External Analyzers',
- subCategory: 'CloudFormation',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.androidLint.reportPaths',
- name: 'Android Lint Report Files',
- description: 'Paths (absolute or relative) to xml files with Android Lint issues.',
- category: 'External Analyzers',
- subCategory: 'Android',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.python.bandit.reportPaths',
- name: 'Bandit Report Files',
- description: 'Paths (absolute or relative) to json files with Bandit issues.',
- category: 'External Analyzers',
- subCategory: 'Python',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.java.checkstyle.reportPaths',
- name: 'Checkstyle Report Files',
- description: 'Paths (absolute or relative) to xml files with Checkstyle issues.',
- category: 'External Analyzers',
- subCategory: 'Java',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.kotlin.detekt.reportPaths',
- name: 'Detekt Report Files',
- description: 'Paths (absolute or relative) to checkstyle xml files with Detekt issues.',
- category: 'External Analyzers',
- subCategory: 'Kotlin',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.eslint.reportPaths',
- name: 'ESLint Report Files',
- description: 'Paths (absolute or relative) to the JSON files with ESLint issues.',
- category: 'External Analyzers',
- subCategory: 'JavaScript/TypeScript',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.python.flake8.reportPaths',
- name: 'Flake8 Report Files',
- description: 'Paths (absolute or relative) to report files with Flake8 issues.',
- category: 'External Analyzers',
- subCategory: 'Python',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.kotlin.ktlint.reportPaths',
- name: 'Ktlint Report Files',
- description: 'Paths (absolute or relative) to checkstyle xml or json files with Ktlint issues.',
- category: 'External Analyzers',
- subCategory: 'Kotlin',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.php.phpstan.reportPaths',
- name: 'PHPStan Report Files',
- description: 'Paths (absolute or relative) to report files with PHPStan issues.',
- category: 'External Analyzers',
- subCategory: 'PHP',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.apex.pmd.reportPaths',
- name: 'PMD Report Files',
- description: 'Paths (absolute or relative) to xml files with PMD issues.',
- category: 'External Analyzers',
- subCategory: 'Apex',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.java.pmd.reportPaths',
- name: 'PMD Report Files',
- description: 'Paths (absolute or relative) to xml files with PMD issues.',
- category: 'External Analyzers',
- subCategory: 'Java',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.php.psalm.reportPaths',
- name: 'Psalm Report Files',
- description: 'Paths (absolute or relative) to report files with Psalm issues.',
- category: 'External Analyzers',
- subCategory: 'PHP',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.python.pylint.reportPaths',
- name: 'Pylint Report Files',
- description: 'Paths (absolute or relative) to report files with Pylint issues.',
- category: 'External Analyzers',
- subCategory: 'Python',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.ruby.rubocop.reportPaths',
- name: 'RuboCop Report Files',
- description: 'Paths (absolute or relative) to json files with RuboCop issues.',
- category: 'External Analyzers',
- subCategory: 'Ruby',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.scala.scalastyle.reportPaths',
- name: 'Scalastyle Report Files',
- description: 'Paths (absolute or relative) to scalastyle xml files with Scalastyle issues.',
- category: 'External Analyzers',
- subCategory: 'Scala',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.scala.scapegoat.reportPaths',
- name: 'Scapegoat Report Files',
- description:
- 'Paths (absolute or relative) to scapegoat xml files using scalastyle format. For example: scapegoat-scalastyle.xml',
- category: 'External Analyzers',
- subCategory: 'Scala',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.java.spotbugs.reportPaths',
- name: 'SpotBugs Report Files',
- description: 'Paths (absolute or relative) to xml files with SpotBugs issues.',
- category: 'External Analyzers',
- subCategory: 'Java',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.css.stylelint.reportPaths',
- name: 'Stylelint Report Files',
- description: 'Paths (absolute or relative) to the JSON files with stylelint issues.',
- category: 'External Analyzers',
- subCategory: 'CSS',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.swift.swiftLint.reportPaths',
- name: 'SwiftLint Report Files',
- description: 'Paths (absolute or relative) to the JSON files with SwiftLint issues.',
- category: 'External Analyzers',
- subCategory: 'Swift',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.typescript.tslint.reportPaths',
- name: 'TSLint Report Files',
- description: 'Paths (absolute or relative) to the JSON files with TSLint issues.',
- category: 'External Analyzers',
- subCategory: 'JavaScript/TypeScript',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.flex.cobertura.reportPaths',
- name: 'Cobertura xml report paths',
- description:
- 'Comma separated list of paths to the Cobertura coverage report file. The paths may be either absolute or relative to the project base directory.',
- category: 'Flex',
- subCategory: 'Flex',
- multiValues: true,
- options: [],
- fields: [],
- deprecatedKey: 'sonar.flex.cobertura.reportPath',
- },
- {
- key: 'sonar.flex.file.suffixes',
- name: 'File suffixes',
- description: 'List of suffixes for files to analyze. To not filter, leave the list empty.',
- category: 'Flex',
- subCategory: 'Flex',
- defaultValue: 'as',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'email.smtp_host.secured',
- name: 'SMTP host',
- description: 'For example "smtp.gmail.com". Leave blank to disable email sending.',
- category: 'general',
- subCategory: 'email',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.login.message',
- name: 'Log-in Message',
- description:
- 'If "Display log-in message" is set to True, the log-in message will be visible to anyone who can access the log-in page of this SonarQube instance.',
- type: SettingType.FORMATTED_TEXT,
- category: 'general',
- subCategory: 'Log-in message',
- options: [],
- fields: [],
- },
- {
- key: 'email.smtp_port.secured',
- name: 'SMTP port',
- description: 'Port number to connect with SMTP server.',
- type: SettingType.INTEGER,
- category: 'general',
- subCategory: 'email',
- defaultValue: '25',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.login.displayMessage',
- name: 'Display log-in Message',
- description:
- 'Display the log-in message on the log-in page of this SonarQube instance. <br><br>Note: If the log-in message is empty. It will not appear even if this parameter is set to True',
- type: SettingType.BOOLEAN,
- category: 'general',
- subCategory: 'Log-in message',
- options: [],
- fields: [],
- },
- {
- key: 'email.smtp_secure_connection.secured',
- name: 'Secure connection',
- description: 'Type of secure connection. Leave empty to not use secure connection.',
- type: SettingType.SINGLE_SELECT_LIST,
- category: 'general',
- subCategory: 'email',
- options: ['ssl', 'starttls'],
- fields: [],
- },
- {
- key: 'email.smtp_username.secured',
- name: 'SMTP username',
- description: 'Username to use with authenticated SMTP.',
- category: 'general',
- subCategory: 'email',
- options: [],
- fields: [],
- },
- {
- key: 'email.smtp_password.secured',
- name: 'SMTP password',
- description: 'Password to use with authenticated SMTP.',
- type: SettingType.PASSWORD,
- category: 'general',
- subCategory: 'email',
- options: [],
- fields: [],
- },
- {
- key: 'email.from',
- name: 'From address',
- description:
- 'Emails will come from this address. For example - "noreply@sonarsource.com". Note that the mail server may ignore this setting.',
- category: 'general',
- subCategory: 'email',
- defaultValue: 'noreply@nowhere',
- options: [],
- fields: [],
- },
- {
- key: 'email.fromName',
- name: 'From name',
- description:
- 'Emails will come from this address name. For example - "SonarQube". Note that the mail server may ignore this setting.',
- category: 'general',
- subCategory: 'email',
- defaultValue: 'SonarQube',
- options: [],
- fields: [],
- },
- {
- key: 'email.prefix',
- name: 'Email prefix',
- description: 'Prefix will be prepended to all outgoing email subjects.',
- category: 'general',
- subCategory: 'email',
- defaultValue: '[SONARQUBE]',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.announcement.message',
- name: 'Announcement message',
- description:
- 'If "Display announcement message" is set to True, this message will be displayed in a warning banner to anyone who can access SonarQube. If this field is empty, no message will be displayed, even if "Display announcement message" is set to True.',
- type: SettingType.TEXT,
- category: 'general',
- subCategory: 'announcement',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.builtInQualityProfiles.disableNotificationOnUpdate',
- name: 'Avoid quality profiles notification',
- description:
- 'Avoid sending email notification on each update of built-in quality profiles to quality profile administrators.',
- type: SettingType.BOOLEAN,
- category: 'general',
- subCategory: 'general',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.cpd.cross_project',
- name: 'Cross project duplication detection',
- description:
- 'DEPRECATED - By default, SonarQube detects duplications at project level. This means that a block duplicated on two different projects won\'t be reported. Setting this parameter to "true" allows to detect duplicates across projects. Note that activating this property will significantly increase each SonarQube analysis time, and therefore badly impact the performances of report processing as more and more projects are getting involved in this cross project duplication mechanism.',
- type: SettingType.BOOLEAN,
- category: 'general',
- subCategory: 'duplications',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.issues.defaultAssigneeLogin',
- name: 'Default Assignee',
- description:
- 'New issues will be assigned to this user each time it is not possible to determine the user who is the author of the issue.',
- type: SettingType.USER_LOGIN,
- category: 'general',
- subCategory: 'issues',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.projectCreation.mainBranchName',
- name: 'Default main branch name',
- description:
- 'Each project has a main branch at creation. This setting defines the instance-wide default main branch name. A user can override this when creating a project. This setting does not apply to projects imported from a DevOps platform.',
- category: 'general',
- subCategory: 'subProjectCreation',
- defaultValue: 'main',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.developerAggregatedInfo.disabled',
- name: 'Disable developer aggregated information',
- description: "Don't show issue facets aggregating information per developer",
- type: SettingType.BOOLEAN,
- category: 'general',
- subCategory: 'issues',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.announcement.displayMessage',
- name: 'Display announcement message',
- description:
- 'If set to True, the "Announcement message" will be displayed in a warning banner to anyone who can access SonarQube.',
- type: SettingType.BOOLEAN,
- category: 'general',
- subCategory: 'announcement',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.ce.parallelProjectTasks',
- name: 'Enable running project analysis tasks in parallel',
- description:
- 'When enabled, this feature will allow the Compute Engine to process pull request analysis tasks in parallel with other pull request or branch analysis tasks of the same project.',
- type: SettingType.BOOLEAN,
- category: 'general',
- subCategory: 'Compute Engine',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.lf.enableGravatar',
- name: 'Enable support of gravatars',
- description: 'Gravatars are profile pictures of users based on their email.',
- type: SettingType.BOOLEAN,
- category: 'general',
- subCategory: 'looknfeel',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.lf.gravatarServerUrl',
- name: 'Gravatar URL',
- description:
- 'Optional URL of custom Gravatar service. Accepted variables are {EMAIL_MD5} for MD5 hash of email and {SIZE} for the picture size in pixels.',
- category: 'general',
- subCategory: 'looknfeel',
- defaultValue: 'https://secure.gravatar.com/avatar/{EMAIL_MD5}.jpg?s={SIZE}&d=identicon',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.qualitygate.ignoreSmallChanges',
- name: 'Ignore duplication and coverage on small changes',
- description:
- 'Quality Gate conditions about duplications in new code and coverage on new code are ignored until the number of new lines is at least 20.',
- type: SettingType.BOOLEAN,
- category: 'general',
- subCategory: 'qualityGate',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.lf.logoUrl',
- name: 'Logo URL',
- description: 'URL to logo image. Any standard format is accepted.',
- category: 'general',
- subCategory: 'looknfeel',
- options: [],
- fields: [],
- deprecatedKey: 'sonar.branding.image',
- },
- {
- key: 'sonar.core.serverBaseURL',
- name: 'Server base URL',
- description:
- 'HTTP(S) URL of this SonarQube server, such as <i>https://yourhost.yourdomain/sonar</i>. This value is used outside SonarQube itself, e.g. for PR decoration, emails, etc.',
- category: 'general',
- subCategory: 'general',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.lf.logoWidthPx',
- name: 'Width of image in pixels',
- description:
- 'Width in pixels, constrained to 150px (the height of the image is constrained to 40px).',
- category: 'general',
- subCategory: 'looknfeel',
- options: [],
- fields: [],
- deprecatedKey: 'sonar.branding.image.width',
- },
- {
- key: 'sonar.go.file.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes for files to analyze.',
- category: 'Go',
- subCategory: 'General',
- defaultValue: '.go',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.go.exclusions',
- name: 'Go Exclusions',
- description: 'List of file path patterns to be excluded from analysis of Go files.',
- category: 'Go',
- subCategory: 'General',
- defaultValue: '**/vendor/**',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.go.tests.reportPaths',
- name: 'Path to test execution report(s)',
- description:
- "Path to test execution reports generated by Go with '-json' key, available since go1.10 (e.g.: go test -json > test-report.out).",
- category: 'Go',
- subCategory: 'Test and Coverage',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.go.coverage.reportPaths',
- name: 'Path to coverage report(s)',
- description:
- 'Path to coverage reports generated by Go (e.g.: go test -coverprofile=coverage.out), ant patterns relative to project root are supported.',
- category: 'Go',
- subCategory: 'Test and Coverage',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.go.govet.reportPaths',
- name: '"go vet" Report Files',
- description: 'Paths (absolute or relative) to the files with "go vet" issues.',
- category: 'Go',
- subCategory: 'Popular Rule Engines',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.go.golint.reportPaths',
- name: 'Golint Report Files',
- description: 'Paths (absolute or relative) to the files with Golint issues.',
- category: 'Go',
- subCategory: 'Popular Rule Engines',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.go.gometalinter.reportPaths',
- name: 'GoMetaLinter Report Files',
- description: 'Paths (absolute or relative) to the files with GoMetaLinter issues.',
- category: 'Go',
- subCategory: 'Popular Rule Engines',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.go.golangci-lint.reportPaths',
- name: 'GolangCI-Lint Report Files',
- description: 'Paths (absolute or relative) to the files with GolangCI-Lint issues.',
- category: 'Go',
- subCategory: 'Popular Rule Engines',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.governance.report.project.branch.frequency',
- name: 'PDF Reports Frequency',
- description:
- 'Define the frequency at which to send PDF reports.<ul><li>"Daily" => report is sent on a daily basis</li><li>"Weekly" => report is sent on a weekly basis</li><li>"Monthly" => report is sent on a monthly basis</li></ul>',
- type: SettingType.SINGLE_SELECT_LIST,
- category: 'Governance',
- subCategory: 'Project and Application PDF Reports',
- defaultValue: 'Monthly',
- options: ['Daily', 'Weekly', 'Monthly'],
- fields: [],
- },
- {
- key: 'sonar.portfolios.recompute.hours',
- name: 'Portfolio Calculation Hours',
- description:
- 'Hours of the day at which outdated portfolios will be recalculated. Portfolios will be queued at the beginning of each selected hour. A 24-hour clock is used, so valid values are 0–23. If this value is empty or invalid, each portfolio will be recalculated immediately after it becomes outdated.',
- type: SettingType.INTEGER,
- category: 'Governance',
- subCategory: 'Recalculation',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.governance.report.view.frequency',
- name: 'Portfolio Reports Frequency',
- description:
- 'Define the default frequency that will be used to send PDF reports for portfolios.<ul><li>"Daily" => report is sent during the first portfolio calculation of the day (if any)</li><li>"Weekly" => report is sent during the first portfolio calculation of the week (if any), starting from Midnight on Monday</li><li>"Monthly" => report is sent during the first portfolio calculation of the month (if any), starting from the first day of the current month</li></ul>',
- type: SettingType.SINGLE_SELECT_LIST,
- category: 'Governance',
- subCategory: 'Portfolio PDF Reports',
- defaultValue: 'Monthly',
- options: ['Daily', 'Weekly', 'Monthly'],
- fields: [],
- },
- {
- key: 'sonar.governance.report.view.recipients',
- name: 'Recipients',
- description:
- 'Email addresses of people who will automatically receive a PDF report for every portfolio defined in the system, based on the given frequency.',
- category: 'Governance',
- subCategory: 'Portfolio PDF Reports',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.dbcleaner.hoursBeforeKeepingOnlyOneSnapshotByDay',
- name: 'Keep only one analysis a day after',
- description:
- 'After this number of hours, if there are several analyses during the same day, the DbCleaner keeps the most recent one and fully deletes the other ones.',
- type: SettingType.INTEGER,
- category: 'housekeeping',
- subCategory: 'general',
- defaultValue: '24',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.dbcleaner.daysBeforeDeletingInactiveBranchesAndPRs',
- name: 'Number of days before purging inactive branches and pull requests',
- description:
- 'Branches and pull requests are permanently deleted when there has been no analysis for the configured number of days.',
- type: SettingType.INTEGER,
- category: 'housekeeping',
- subCategory: 'branchesAndPullRequests',
- defaultValue: '30',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.dbcleaner.branchesToKeepWhenInactive',
- name: 'Branches to keep when inactive',
- description:
- 'By default, branches and pull requests are automatically deleted when inactive. This setting allows you to protect branches (but not pull requests) from this deletion. When a branch is created with a name that matches any of the regular expressions on the list of values of this setting, the branch will not be deleted automatically even when it becomes inactive.<br>Example:<ul><li>develop</li><li>release-.*</li></ul>',
- type: SettingType.REGULAR_EXPRESSION,
- category: 'housekeeping',
- subCategory: 'branchesAndPullRequests',
- defaultValue: 'main,master,develop,trunk',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.dbcleaner.weeksBeforeKeepingOnlyOneSnapshotByWeek',
- name: 'Keep only one analysis a week after',
- description:
- 'After this number of weeks, if there are several analyses during the same week, the DbCleaner keeps the most recent one and fully deletes the other ones',
- type: SettingType.INTEGER,
- category: 'housekeeping',
- subCategory: 'general',
- defaultValue: '4',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.dbcleaner.weeksBeforeKeepingOnlyOneSnapshotByMonth',
- name: 'Keep only one analysis a month after',
- description:
- 'After this number of weeks, if there are several analyses during the same month, the DbCleaner keeps the most recent one and fully deletes the other ones.',
- type: SettingType.INTEGER,
- category: 'housekeeping',
- subCategory: 'general',
- defaultValue: '52',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.dbcleaner.weeksBeforeKeepingOnlyAnalysesWithVersion',
- name: 'Keep only analyses with a version event after',
- description:
- 'After this number of weeks, the DbCleaner keeps only analyses with a version event associated.',
- type: SettingType.INTEGER,
- category: 'housekeeping',
- subCategory: 'general',
- defaultValue: '104',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.dbcleaner.weeksBeforeDeletingAllSnapshots',
- name: 'Delete all analyses after',
- description: 'After this number of weeks, all analyses are fully deleted.',
- type: SettingType.INTEGER,
- category: 'housekeeping',
- subCategory: 'general',
- defaultValue: '260',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.dbcleaner.daysBeforeDeletingClosedIssues',
- name: 'Delete closed issues after',
- description: 'Issues that have been closed for more than this number of days will be deleted.',
- type: SettingType.INTEGER,
- category: 'housekeeping',
- subCategory: 'general',
- defaultValue: '30',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.dbcleaner.auditHousekeeping',
- name: 'Audit Logs Housekeeping Frequency',
- description:
- 'Define the frequency that will be used to delete security-related audit logs.<br>Setting your housekeeping policy to keep your audit logs for a long period of time (for example, only deleting logs yearly) can increase your database size and the amount of time it takes to download audit logs.<ul><li>"Weekly" => Audit logs older than a week will be deleted</li><li>"Monthly" => Audit logs older than a month will be deleted</li><li>"Trimestrial" => Audit logs older than 3 months will be deleted</li><li>"Yearly" => Audit logs older than a year will be deleted</li></ul>',
- type: SettingType.SINGLE_SELECT_LIST,
- category: 'housekeeping',
- subCategory: 'auditLogs',
- defaultValue: 'Monthly',
- options: ['Weekly', 'Monthly', 'Trimestrial', 'Yearly'],
- fields: [],
- },
- {
- key: 'sonar.html.file.suffixes',
- name: 'HTML File suffixes',
- description: 'List of file suffixes that will be scanned.',
- category: 'HTML',
- subCategory: 'HTML',
- defaultValue: '.html,.xhtml,.cshtml,.vbhtml,.aspx,.ascx,.rhtml,.erb,.shtm,.shtml,.cmp,.twig',
- multiValues: true,
- options: [],
- fields: [],
- deprecatedKey: 'sonar.web.file.suffixes',
- },
- {
- key: 'sonar.jsp.file.suffixes',
- name: 'JSP File suffixes',
- description: 'List of JSP file suffixes that will be scanned.',
- category: 'HTML',
- subCategory: 'HTML',
- defaultValue: '.jsp,.jspf,.jspx',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.coverage.jacoco.xmlReportPaths',
- description:
- 'Paths to JaCoCo XML coverage report files. Each path can be either absolute or relative to the project base directory. Wildcard patterns are accepted (*, ** and ?).',
- category: 'JaCoCo',
- subCategory: 'JaCoCo',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.java.file.suffixes',
- name: 'File suffixes',
- description: 'List of suffixes for Java files to analyze. To not filter, leave the list empty.',
- category: 'java',
- subCategory: 'General',
- defaultValue: '.java,.jav',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.junit.reportPaths',
- name: 'JUnit Report Paths',
- description:
- 'Comma-separated paths to the various directories containing the *.xml JUnit report files. Each path may be absolute or relative to the project base directory.',
- category: 'java',
- subCategory: 'JUnit',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.javascript.globals',
- name: 'Global variables',
- description: 'List of global variables.',
- category: 'JavaScript / TypeScript',
- subCategory: 'General',
- defaultValue: 'angular,goog,google,OenLayers,d3,dojo,dojox,dijit,Backbone,moment,casper,_,sap',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.javascript.ignoreHeaderComments',
- name: 'Ignore header comments',
- description: 'True to not count file header comments in comment metrics.',
- type: SettingType.BOOLEAN,
- category: 'JavaScript / TypeScript',
- subCategory: 'General',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.javascript.environments',
- name: 'JavaScript execution environments',
- description:
- 'List of environments names. The analyzer automatically adds global variables based on that list. Available environment names: amd, applescript, atomtest, browser, commonjs, couch, embertest, flow, greasemonkey, jasmine, jest, jquery, meteor, mocha, mongo, nashorn, node, phantomjs, prototypejs, protractor, qunit, rhino, serviceworker, shared-node-browser, shelljs, webextensions, worker, wsh, yui.',
- category: 'JavaScript / TypeScript',
- subCategory: 'General',
- defaultValue:
- 'amd,applescript,atomtest,browser,commonjs,couch,embertest,flow,greasemonkey,jasmine,jest,jquery,meteor,mocha,mongo,nashorn,node,phantomjs,prototypejs,protractor,qunit,rhino,serviceworker,shared-node-browser,shelljs,webextensions,worker,wsh,yui',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.javascript.file.suffixes',
- name: 'JavaScript File Suffixes',
- description: 'List of suffixes for files to analyze.',
- category: 'JavaScript / TypeScript',
- subCategory: 'General',
- defaultValue: '.js,.jsx,.cjs,.mjs,.vue',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.javascript.lcov.reportPaths',
- name: 'LCOV Files',
- description: 'Paths (absolute or relative) to the files with LCOV data.',
- category: 'JavaScript / TypeScript',
- subCategory: 'Tests and Coverage',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.javascript.maxFileSize',
- name: 'Maximum size of analyzed files',
- description:
- 'Threshold for the maximum size of analyzed files (in kilobytes). Files that are larger are excluded from the analysis.',
- type: SettingType.INTEGER,
- category: 'JavaScript / TypeScript',
- subCategory: 'General',
- defaultValue: '1000',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.typescript.file.suffixes',
- name: 'TypeScript File Suffixes',
- description: 'List of suffixes for files to analyze.',
- category: 'JavaScript / TypeScript',
- subCategory: 'General',
- defaultValue: '.ts,.tsx,.cts,.mts',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.typescript.tsconfigPaths',
- name: 'TypeScript tsconfig.json location',
- description: 'Comma-delimited list of paths to TSConfig files. Wildcards are supported.',
- category: 'JavaScript / TypeScript',
- subCategory: 'TypeScript',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.json.file.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes of JSON files to be indexed.',
- category: SettingType.JSON,
- subCategory: 'General',
- defaultValue: '.json',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.kotlin.file.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes for files to analyze.',
- category: 'Kotlin',
- subCategory: 'General',
- defaultValue: '.kt',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.kubernetes.activate',
- name: 'Activate Kubernetes analysis',
- description: 'Activate analysis of JSON and Yaml files recognized as Kubernetes files.',
- type: SettingType.BOOLEAN,
- category: 'Kubernetes',
- subCategory: 'General',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.php.coverage.reportPaths',
- name: 'Coverage Reports',
- description:
- 'List of PHPUnit code coverage report files. Each path can be either absolute or relative.',
- category: 'PHP',
- subCategory: 'PHPUnit',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.php.file.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes of PHP files to analyze.',
- category: 'PHP',
- subCategory: 'General',
- defaultValue: 'php,php3,php4,php5,phtml,inc',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.php.exclusions',
- name: 'PHP Exclusions',
- description: 'List of file path patterns to be excluded from analysis of PHP files.',
- category: 'PHP',
- subCategory: 'General',
- defaultValue: '**/vendor/**',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.php.tests.reportPath',
- name: 'Unit Test Report',
- description:
- 'Path to the PHPUnit unit test execution report file. The path may be either absolute or relative to the project base directory.',
- category: 'PHP',
- subCategory: 'PHPUnit',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.pli.extralingualCharacters',
- name: 'Extralingual characters',
- description:
- 'Extralingual characters which should be considered as valid in identifiers. No separator should be used. Example: #@$£§',
- category: 'PL/I',
- subCategory: 'PL/I',
- defaultValue: '#@$',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.pli.file.suffixes',
- name: 'File suffixes',
- description:
- 'List of suffixes for PL/I files to analyze. To not change the defaults, leave the list empty.',
- category: 'PL/I',
- subCategory: 'PL/I',
- defaultValue: '.pli',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.pli.ignoreHeaderComments',
- name: 'Ignore header comments',
- description: "Set to 'true' to enable, or 'false' to disable.",
- type: SettingType.BOOLEAN,
- category: 'PL/I',
- subCategory: 'PL/I',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.pli.marginLeft',
- name: 'Margin left',
- description:
- "The column number of the source's leftmost character, must be greater or equal to 1.",
- type: SettingType.INTEGER,
- category: 'PL/I',
- subCategory: 'PL/I',
- defaultValue: '2',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.pli.marginRight',
- name: 'Margin right',
- description:
- "The column number of the source's rightmost character, must be greater or equal to the leftmost's one, or 0 to indicate an unlimited right margin.",
- type: SettingType.INTEGER,
- category: 'PL/I',
- subCategory: 'PL/I',
- defaultValue: '72',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.plsql.file.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes for files to analyze.',
- category: 'PL/SQL',
- subCategory: 'General',
- defaultValue: 'sql,pks,pkb',
- multiValues: true,
- options: [],
- fields: [],
- deprecatedKey: 'sonar.plsql.suffixes',
- },
- {
- key: 'sonar.plsql.ignoreHeaderComments',
- name: 'Ignore Header Comments',
- description:
- 'If set to "true", the file headers (that are usually the same on each file: licensing information for example) are not considered as comments. Thus metrics such as "Comment lines" do not get incremented. If set to "false", those file headers are considered as comments and metrics such as "Comment lines" get incremented.',
- type: SettingType.BOOLEAN,
- category: 'PL/SQL',
- subCategory: 'General',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.python.file.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes of Python files to analyze.',
- category: 'Python',
- subCategory: 'General',
- defaultValue: 'py',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.python.coverage.reportPaths',
- name: 'Path to coverage report(s)',
- description:
- 'List of paths pointing to coverage reports. Ant patterns are accepted for relative path. The reports have to conform to the Cobertura XML format.',
- category: 'Python',
- subCategory: 'Tests and Coverage',
- defaultValue: 'coverage-reports/*coverage-*.xml',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.python.coverage.reportPath',
- name: 'Path to coverage report',
- description:
- 'DEPRECATED : Use sonar.python.coverage.reportPaths instead. Path to a coverage report. Ant patterns are accepted for relative path. The report has to conform to the Cobertura XML format.',
- category: 'Python',
- subCategory: 'Tests and Coverage',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.python.xunit.skipDetails',
- name: 'Skip the details when importing the Xunit reports',
- description:
- 'When enabled the test execution statistics is provided only on project level. Use this mode when paths in report are not found. Disabled by default.',
- type: SettingType.BOOLEAN,
- category: 'Python',
- subCategory: 'Tests and Coverage',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.python.xunit.reportPath',
- name: 'Path to xunit report(s)',
- description:
- "Path to the report of test execution, relative to project's root. Ant patterns are accepted. The reports have to conform to the junitreport XML format.",
- category: 'Python',
- subCategory: 'Tests and Coverage',
- defaultValue: 'xunit-reports/xunit-result-*.xml',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.rpg.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes of RPG files to analyze.',
- category: 'RPG',
- subCategory: 'RPG',
- defaultValue: '.rpg,.rpgle,.sqlrpgle,.RPG,.RPGLE,.SQLRPGLE',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.rpg.leftMarginWidth',
- name: 'Left margin width',
- description:
- 'Number of characters to the left of the standard 5-character comment block. In an RPG "source physical file" this will typically be 12, but it may not be present in your files depending on your extraction process.',
- type: SettingType.INTEGER,
- category: 'RPG',
- subCategory: 'RPG',
- defaultValue: '12',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.ruby.file.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes for files to analyze.',
- category: 'Ruby',
- subCategory: 'General',
- defaultValue: '.rb',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.ruby.coverage.reportPaths',
- name: 'Path to coverage report(s)',
- description:
- 'Path to coverage report files (.resultset.json) generated by SimpleCov. The path may be absolute or relative to the project base directory.',
- category: 'Ruby',
- subCategory: 'Test and Coverage',
- defaultValue: 'coverage/.resultset.json',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.ruby.exclusions',
- name: 'Ruby Exclusions',
- description: 'List of file path patterns to be excluded from analysis of Ruby files.',
- category: 'Ruby',
- subCategory: 'General',
- defaultValue: '**/vendor/**',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.security.config.roslyn.sonaranalyzer.security.cs',
- name: 'C# custom configuration',
- description:
- "Custom configuration of the C# SAST engine. Details on the expected JSON format can be found on the 'Security Engine Custom Configuration' documentation page.",
- type: SettingType.JSON,
- category: 'SAST Engine',
- subCategory: 'Configuration',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.security.config.javasecurity',
- name: 'Java custom configuration',
- description:
- "Custom configuration of the Java SAST engine. Details on the expected JSON format can be found on the 'Security Engine Custom Configuration' documentation page.",
- type: SettingType.JSON,
- category: 'SAST Engine',
- subCategory: 'Configuration',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.security.config.phpsecurity',
- name: 'PHP custom configuration',
- description:
- "Custom configuration of the PHP SAST engine. Details on the expected JSON format can be found on the 'Security Engine Custom Configuration' documentation page.",
- type: SettingType.JSON,
- category: 'SAST Engine',
- subCategory: 'Configuration',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.security.config.pythonsecurity',
- name: 'Python custom configuration',
- description:
- "Custom configuration of the Python SAST engine. Details on the expected JSON format can be found on the 'Security Engine Custom Configuration' documentation page.",
- type: SettingType.JSON,
- category: 'SAST Engine',
- subCategory: 'Configuration',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.scala.file.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes for files to analyze.',
- category: 'Scala',
- subCategory: 'General',
- defaultValue: '.scala',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.scala.coverage.reportPaths',
- name: 'Path to Scoverage report',
- description:
- 'Path to Scoverage report file(s) (scoverage.xml). Usually in target\\scala-X.X\\scoverage-report',
- category: 'Scala',
- subCategory: 'Test and Coverage',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.scm.disabled',
- name: 'Disable the SCM Sensor',
- description: 'Disable the retrieval of blame information from Source Control Manager',
- type: SettingType.BOOLEAN,
- category: 'scm',
- subCategory: 'scm',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.text.excluded.file.suffixes',
- name: 'Additional binary file suffixes',
- description:
- 'Additional list of binary file suffixes that should not be analyzed with rules targeting text files.',
- category: 'Secrets',
- subCategory: 'General',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.auth.token.max.allowed.lifetime',
- name: 'Maximum allowed lifetime for token',
- description:
- 'Define the maximum lifetime that can be used for new tokens. Existing tokens are not impacted and may need to be manually revoked.',
- type: SettingType.SINGLE_SELECT_LIST,
- category: 'security',
- subCategory: 'security',
- defaultValue: 'No expiration',
- options: ['30 days', '90 days', '1 year', 'No expiration'],
- fields: [],
- },
- {
- key: 'sonar.validateWebhooks',
- name: 'Enable local webhooks validation',
- description:
- 'Forcing local webhooks validation prevents the creation and triggering of local webhooks<br><strong>Disabling this setting can expose the instance to security risks.</strong>',
- type: SettingType.BOOLEAN,
- category: 'security',
- subCategory: 'security',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.allowPermissionManagementForProjectAdmins',
- name: 'Enable permission management for project administrators',
- description:
- "Set if users with 'Administer' role in a project should be allowed to change project permissions. By default users with 'Administer' role are allowed to change both project configuration and project permissions.",
- type: SettingType.BOOLEAN,
- category: 'security',
- subCategory: 'security',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.forceAuthentication',
- name: 'Force user authentication',
- description:
- 'Forcing user authentication prevents anonymous users from accessing the SonarQube UI, or project data via the Web API. Some specific read-only Web APIs, including those required to prompt authentication, are still available anonymously.<br><strong>Disabling this setting can expose the instance to security risks.</strong>',
- type: SettingType.BOOLEAN,
- category: 'security',
- subCategory: 'security',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.swift.coverage.reportPath',
- name: 'Code coverage report',
- description:
- 'DEPRECATED: Path of the coverage report generated from "llvm-cov show". This path can be either absolute or relative to the project directory.',
- category: 'Swift',
- subCategory: 'Swift',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.swift.coverage.reportPaths',
- name: 'Code coverage reports',
- description:
- 'Paths to the coverage reports generated from "llvm-cov show". These paths can be either absolute or relative to the project directory.',
- category: 'Swift',
- subCategory: 'Swift',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.swift.file.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes for files to analyze.',
- category: 'Swift',
- subCategory: 'Swift',
- defaultValue: '.swift',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.tsql.file.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes for files to analyze.',
- category: 'T-SQL',
- subCategory: 'General',
- defaultValue: '.tsql',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.technicalDebt.developmentCost',
- name: 'Development cost',
- description:
- 'Cost to develop one line of code (LOC). Example: if the cost to develop 1 LOC has been estimated at 30 minutes, then the value of this property would be 30.',
- category: 'technicalDebt',
- subCategory: 'technicalDebt',
- defaultValue: '30',
- options: [],
- fields: [],
- deprecatedKey: 'workUnitsBySizePoint',
- },
- {
- key: 'sonar.technicalDebt.ratingGrid',
- name: 'Maintainability rating grid',
- description:
- 'Maintainability ratings range from A (very good) to E (very bad). The rating is determined by the value of the Technical Debt Ratio, which compares the technical debt on a project to the cost it would take to rewrite the code from scratch. The default values for A through D are 0.05,0.1,0.2,0.5. Anything over 0.5 is an E. Example: assuming the development cost is 30 minutes, a project with a technical debt of 24,000 minutes for 2,500 LOC will have a technical debt ratio of 24000/(30 * 2,500) = 0.32. That yields a maintainability rating of D.',
- category: 'technicalDebt',
- subCategory: 'technicalDebt',
- defaultValue: '0.05,0.1,0.2,0.5',
- options: [],
- fields: [],
- deprecatedKey: 'ratingGrid',
- },
- {
- key: 'sonar.terraform.activate',
- name: 'Activate Terraform Analysis',
- description:
- 'Disabling Terraform analysis ensures that no Terraform files are parsed, highlighted and analyzed, and no IaC analysis results are included in the quality gate.',
- type: SettingType.BOOLEAN,
- category: 'Terraform',
- subCategory: 'General',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.terraform.file.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes of Terraform files to analyze.',
- category: 'Terraform',
- subCategory: 'General',
- defaultValue: '.tf',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.terraform.provider.aws.version',
- name: 'AWS Provider Version',
- description:
- 'Version of the AWS provider of lifecycle management of AWS resources. Use semantic versioning format like `3.4`, `4.17.1` or `4`',
- category: 'Terraform',
- subCategory: 'Provider Versions',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.terraform.provider.azure.version',
- name: 'Azure Provider Version',
- description:
- 'Version of the Azure Resource Manager provider of lifecycle management of Microsoft Azure resources. Use semantic versioning format like `3.4`, `4.17.1` or `4`',
- category: 'Terraform',
- subCategory: 'Provider Versions',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.vbnet.analyzeGeneratedCode',
- name: 'Analyze generated code',
- description:
- 'If set to "true", the files containing generated code are analyzed. If set to "false", the files containing generated code are ignored.',
- type: SettingType.BOOLEAN,
- category: 'VB.NET',
- subCategory: 'VB.NET',
- defaultValue: 'false',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.vbnet.file.suffixes',
- name: 'File suffixes',
- description: 'List of suffixes for files to analyze.',
- category: 'VB.NET',
- subCategory: 'VB.NET',
- defaultValue: '.vb',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.vbnet.ignoreHeaderComments',
- name: 'Ignore header comments',
- description:
- 'If set to "true", the file headers (that are usually the same on each file: licensing information for example) are not considered as comments. Thus metrics such as "Comment lines" do not get incremented. If set to "false", those file headers are considered as comments and metrics such as "Comment lines" get incremented.',
- type: SettingType.BOOLEAN,
- category: 'VB.NET',
- subCategory: 'VB.NET',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.vb.file.suffixes',
- name: 'File Suffixes',
- description:
- 'List of suffixes for Visual Basic files to analyze. To not change the defaults, leave the list empty.',
- category: 'Visual Basic',
- subCategory: 'Visual Basic',
- defaultValue: '.bas,.frm,.cls,.ctl,.BAS,.FRM,.CLS,.CTL',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.vb.ignoreHeaderComments',
- name: 'Ignore header comments',
- description: "Set to 'true' to enable, or 'false' to disable.",
- type: SettingType.BOOLEAN,
- category: 'Visual Basic',
- subCategory: 'Visual Basic',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
- {
- key: 'sonar.xml.file.suffixes',
- name: 'File suffixes',
- description: 'List of suffixes for XML files to analyze.',
- category: 'XML',
- subCategory: 'XML',
- defaultValue: '.xml,.xsd,.xsl',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- key: 'sonar.yaml.file.suffixes',
- name: 'File Suffixes',
- description: 'List of suffixes of YAML files to be indexed.',
- category: 'YAML',
- subCategory: 'General',
- defaultValue: '.yaml,.yml',
- multiValues: true,
- options: [],
- fields: [],
- },
- {
- name: 'Provision project visibility',
- key: 'provisioning.github.project.visibility.enabled',
- description:
- 'Change project visibility based on GitHub repository visibility. If disabled, every provisioned project will be private in SonarQube and visible only to users with explicit GitHub permissions for the corresponding repository. Changes take effect at the next synchronization.',
- type: SettingType.BOOLEAN,
- category: 'authentication',
- subCategory: 'github',
- defaultValue: 'true',
- options: [],
- fields: [],
- },
-];
diff --git a/server/sonar-web/src/main/js/helpers/mocks/dom.ts b/server/sonar-web/src/main/js/helpers/mocks/dom.ts
deleted file mode 100644
index 4c6dabe9fee..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/dom.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export function mockHtmlElement<T extends Element>(overrides: Partial<T> = {}): T {
- return {
- getBoundingClientRect: () => ({
- bottom: 0,
- height: 100,
- width: 50,
- left: 0,
- right: 0,
- top: 10,
- x: 12,
- y: 23,
- toJSON: () => '',
- }),
- ...overrides,
- } as T;
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/dop-translation.ts b/server/sonar-web/src/main/js/helpers/mocks/dop-translation.ts
deleted file mode 100644
index d7d1fa53f46..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/dop-translation.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { GitHubConfigurationResponse } from '../../types/dop-translation';
-import { ProvisioningType } from '../../types/provisioning';
-
-export function mockGitHubConfiguration(
- overrides: Partial<GitHubConfigurationResponse> = {},
-): GitHubConfigurationResponse {
- return {
- allowUsersToSignUp: true,
- allowedOrganizations: [],
- apiUrl: 'apiUrl',
- applicationId: 'app123',
- enabled: true,
- id: '123',
- projectVisibility: true,
- provisioningType: ProvisioningType.jit,
- synchronizeGroups: true,
- userConsentRequiredAfterUpgrade: false,
- webUrl: 'webUrl',
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/editions.ts b/server/sonar-web/src/main/js/helpers/mocks/editions.ts
deleted file mode 100644
index 1e40b788151..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/editions.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { License } from '../../types/editions';
-
-export function mockLicense(override?: Partial<License>) {
- return {
- contactEmail: 'contact@sonarsource.com',
- edition: 'Developer Edition',
- expiresAt: '2018-05-18',
- isExpired: false,
- isValidEdition: true,
- isValidServerId: true,
- isOfficialDistribution: true,
- isSupported: false,
- canActivateGracePeriod: false,
- loc: 120085,
- maxLoc: 500000,
- plugins: ['Branches', 'PLI language'],
- remainingLocThreshold: 490000,
- serverId: 'AU-TpxcA-iU5OvuD2FL0',
- type: 'production',
- ...override,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/issues.ts b/server/sonar-web/src/main/js/helpers/mocks/issues.ts
deleted file mode 100644
index 1b0f89a7184..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/issues.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Query } from '../../apps/issues/utils';
-import { IssueChangelog, IssueChangelogDiff } from '../../types/types';
-
-export function mockIssueAuthors(overrides: string[] = []): string[] {
- return [
- 'email1@sonarsource.com',
- 'email2@sonarsource.com',
- 'email3@sonarsource.com',
- 'email4@sonarsource.com',
- ...overrides,
- ];
-}
-
-export function mockIssueChangelog(overrides: Partial<IssueChangelog> = {}): IssueChangelog {
- return {
- creationDate: '2018-10-01',
- isUserActive: true,
- user: 'luke.skywalker',
- userName: 'Luke Skywalker',
- diffs: [mockIssueChangelogDiff()],
- ...overrides,
- };
-}
-
-export function mockIssueChangelogDiff(
- overrides: Partial<IssueChangelogDiff> = {},
-): IssueChangelogDiff {
- return {
- key: 'assign',
- newValue: 'darth.vader',
- oldValue: 'luke.skywalker',
- ...overrides,
- };
-}
-
-export function mockQuery(overrides: Partial<Query> = {}): Query {
- return {
- assigned: false,
- assignees: [],
- author: [],
- cleanCodeAttributeCategories: [],
- codeVariants: [],
- createdAfter: undefined,
- createdAt: '',
- createdBefore: undefined,
- createdInLast: '',
- cwe: [],
- directories: [],
- files: [],
- fixedInPullRequest: '',
- issues: [],
- languages: [],
- owaspTop10: [],
- casa: [],
- 'stig-ASD_V5R3': [],
- 'owaspTop10-2021': [],
- 'pciDss-3.2': [],
- 'pciDss-4.0': [],
- 'owaspAsvs-4.0': [],
- owaspAsvsLevel: '',
- projects: [],
- rules: [],
- scopes: [],
- severities: [],
- impactSeverities: [],
- impactSoftwareQualities: [],
- inNewCodePeriod: false,
- sonarsourceSecurity: [],
- issueStatuses: [],
- sort: '',
- tags: [],
- types: [],
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/metrics.ts b/server/sonar-web/src/main/js/helpers/mocks/metrics.ts
deleted file mode 100644
index 359bcd6c19b..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/metrics.ts
+++ /dev/null
@@ -1,2003 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Dict, Metric } from '../../types/types';
-
-export const DEFAULT_METRICS: Dict<Metric> = {
- accepted_issues: {
- id: 'AXJMbIl_PAOIsUIE3gt5',
- key: 'accepted_issues',
- type: 'INT',
- name: 'Accepted Issues',
- description: 'Accepted issues',
- domain: 'Issues',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- new_technical_debt: {
- id: 'AXJMbIl_PAOIsUIE3guE',
- key: 'new_technical_debt',
- type: 'WORK_DUR',
- name: 'Added Technical Debt',
- description: 'Added technical debt',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_software_quality_maintainability_remediation_effort: {
- id: 'bf182476-9397-4471-812d-7e40568ef1b0',
- key: 'new_software_quality_maintainability_remediation_effort',
- type: 'WORK_DUR',
- name: 'Added Technical Debt',
- description:
- 'Total effort (in minutes) to fix all the maintainability issues on new code on the component and therefore to comply to all the requirements.',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- analysis_from_sonarqube_9_4: {
- id: 'AX_iDGfBRf9uEywNDdeh',
- key: 'analysis_from_sonarqube_9_4',
- type: 'BOOL',
- name: 'Analysis From SonarQube 9.4',
- description:
- 'Indicates whether the analysis has been run after the upgrade to SonarQube 9.4. It affects how the issues will be detected for branches that use reference branch as the strategy for detecting new code.',
- domain: 'Issues',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- high_impact_accepted_issues: {
- id: 'AY0aC41wVDhd53-OniNc',
- key: 'high_impact_accepted_issues',
- type: 'INT',
- name: 'Blocker and High Severity Accepted Issues',
- description: 'Accepted issues with blocker or high impact',
- domain: 'Issues',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- blocker_violations: {
- id: 'AXJMbIl_PAOIsUIE3gtt',
- key: 'blocker_violations',
- type: 'INT',
- name: 'Blocker Issues',
- description: 'Blocker issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_blocker_issues: {
- id: '9a1650ae-056f-4d40-b761-0ae06b9f15b2',
- key: 'software_quality_blocker_issues',
- type: 'INT',
- name: 'Blocker Severity Issues',
- description: 'Blocker Severity issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- bugs: {
- id: 'AXJMbIl_PAOIsUIE3gt_',
- key: 'bugs',
- type: 'INT',
- name: 'Bugs',
- description: 'Bugs',
- domain: 'Reliability',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- classes: {
- id: 'AXJMbImPPAOIsUIE3gu5',
- key: 'classes',
- type: 'INT',
- name: 'Classes',
- description: 'Classes',
- domain: 'Size',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- code_smells: {
- id: 'AXJMbIl_PAOIsUIE3gt9',
- key: 'code_smells',
- type: 'INT',
- name: 'Code Smells',
- description: 'Code Smells',
- domain: 'Maintainability',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- cognitive_complexity: {
- id: 'AXJMbIl9PAOIsUIE3gtZ',
- key: 'cognitive_complexity',
- type: 'INT',
- name: 'Cognitive Complexity',
- description: 'Cognitive complexity',
- domain: 'Complexity',
- direction: 0, // manually changed direction to test quality gate condition operator
- qualitative: false,
- hidden: false,
- },
- comment_lines: {
- id: 'AXJMbImPPAOIsUIE3gup',
- key: 'comment_lines',
- type: 'INT',
- name: 'Comment Lines',
- description: 'Number of comment lines',
- domain: 'Size',
- direction: 1,
- qualitative: false,
- hidden: false,
- },
- comment_lines_data: {
- id: 'AXJMbImPPAOIsUIE3guV',
- key: 'comment_lines_data',
- type: 'DATA',
- name: 'comment_lines_data',
- domain: 'Size',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- comment_lines_density: {
- id: 'AXJMbImPPAOIsUIE3guq',
- key: 'comment_lines_density',
- type: 'PERCENT',
- name: 'Comments (%)',
- description: 'Comments balanced by ncloc + comment lines',
- domain: 'Size',
- direction: 1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- branch_coverage: {
- id: 'AXJMbIl9PAOIsUIE3gs-',
- key: 'branch_coverage',
- type: 'PERCENT',
- name: 'Condition Coverage',
- description: 'Condition coverage',
- domain: 'Coverage',
- direction: 1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- new_branch_coverage: {
- id: 'AXJMbIl9PAOIsUIE3gs_',
- key: 'new_branch_coverage',
- type: 'PERCENT',
- name: 'Condition Coverage on New Code',
- description: 'Condition coverage of new/changed code',
- domain: 'Coverage',
- direction: 1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- conditions_to_cover: {
- id: 'AXJMbIl9PAOIsUIE3gqt',
- key: 'conditions_to_cover',
- type: 'INT',
- name: 'Conditions to Cover',
- description: 'Conditions to cover',
- domain: 'Coverage',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- new_conditions_to_cover: {
- id: 'AXJMbIl9PAOIsUIE3gs7',
- key: 'new_conditions_to_cover',
- type: 'INT',
- name: 'Conditions to Cover on New Code',
- description: 'Conditions to cover on new code',
- domain: 'Coverage',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- confirmed_issues: {
- id: 'AXJMbIl_PAOIsUIE3gt8',
- key: 'confirmed_issues',
- type: 'INT',
- name: 'Confirmed Issues',
- description: 'Confirmed issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- coverage: {
- id: 'AXJMbIl9PAOIsUIE3gtg',
- key: 'coverage',
- type: 'PERCENT',
- name: 'Coverage',
- description: 'Coverage by tests',
- domain: 'Coverage',
- direction: 1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- new_coverage: {
- id: 'AXJMbIl_PAOIsUIE3gth',
- key: 'new_coverage',
- type: 'PERCENT',
- name: 'Coverage on New Code',
- description: 'Coverage of new/changed code',
- domain: 'Coverage',
- direction: 1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- critical_violations: {
- id: 'AXJMbIl_PAOIsUIE3gtu',
- key: 'critical_violations',
- type: 'INT',
- name: 'Critical Issues',
- description: 'Critical issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- complexity: {
- id: 'AXJMbImPPAOIsUIE3gut',
- key: 'complexity',
- type: 'INT',
- name: 'Cyclomatic Complexity',
- description: 'Cyclomatic complexity',
- domain: 'Complexity',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- last_commit_date: {
- id: 'AXJMbImPPAOIsUIE3gua',
- key: 'last_commit_date',
- type: 'MILLISEC',
- name: 'Date of Last Commit',
- domain: 'SCM',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- development_cost: {
- id: 'AXJMbIl_PAOIsUIE3guI',
- key: 'development_cost',
- type: 'STRING',
- name: 'Development Cost',
- description: 'Development cost',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- new_development_cost: {
- id: 'AXJMbIl_PAOIsUIE3guJ',
- key: 'new_development_cost',
- type: 'FLOAT',
- name: 'Development Cost on New Code',
- description: 'Development cost on new code',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: true,
- decimalScale: 1,
- },
- duplicated_blocks: {
- id: 'AXJMbIl9PAOIsUIE3gsu',
- key: 'duplicated_blocks',
- type: 'INT',
- name: 'Duplicated Blocks',
- description: 'Duplicated blocks',
- domain: 'Duplications',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_duplicated_blocks: {
- id: 'AXJMbIl_PAOIsUIE3gto',
- key: 'new_duplicated_blocks',
- type: 'INT',
- name: 'Duplicated Blocks on New Code',
- description: 'Duplicated blocks on new code',
- domain: 'Duplications',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- duplicated_files: {
- id: 'AXJMbImPPAOIsUIE3gvA',
- key: 'duplicated_files',
- type: 'INT',
- name: 'Duplicated Files',
- description: 'Duplicated files',
- domain: 'Duplications',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- duplicated_lines: {
- id: 'AXJMbIl9PAOIsUIE3gss',
- key: 'duplicated_lines',
- type: 'INT',
- name: 'Duplicated Lines',
- description: 'Duplicated lines',
- domain: 'Duplications',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- duplicated_lines_density: {
- id: 'AXJMbIl_PAOIsUIE3gtp',
- key: 'duplicated_lines_density',
- type: 'PERCENT',
- name: 'Duplicated Lines (%)',
- description: 'Duplicated lines balanced by statements',
- domain: 'Duplications',
- direction: -1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- new_duplicated_lines_density: {
- id: 'AXJMbIl_PAOIsUIE3gtq',
- key: 'new_duplicated_lines_density',
- type: 'PERCENT',
- name: 'Duplicated Lines (%) on New Code',
- description: 'Duplicated lines (%) on new code balanced by statements',
- domain: 'Duplications',
- direction: -1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- new_duplicated_lines: {
- id: 'AXJMbIl9PAOIsUIE3gst',
- key: 'new_duplicated_lines',
- type: 'INT',
- name: 'Duplicated Lines on New Code',
- description: 'Duplicated Lines on New Code',
- domain: 'Duplications',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- duplications_data: {
- id: 'AXJMbIl_PAOIsUIE3gtr',
- key: 'duplications_data',
- type: 'DATA',
- name: 'Duplication Details',
- description: 'Duplications details',
- domain: 'Duplications',
- direction: 0,
- qualitative: false,
- hidden: false,
- },
- effort_to_reach_software_quality_maintainability_rating_a: {
- id: '0f195cdf-5d79-4be0-90e4-c6e0afb58551',
- key: 'effort_to_reach_software_quality_maintainability_rating_a',
- type: 'WORK_DUR',
- name: 'Effort to Reach Maintainability Rating A',
- description: 'Effort to reach maintainability rating A',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- effort_to_reach_maintainability_rating_a: {
- id: 'AXJMbIl_PAOIsUIE3guM',
- key: 'effort_to_reach_maintainability_rating_a',
- type: 'WORK_DUR',
- name: 'Effort to Reach Maintainability Rating A',
- description: 'Effort to reach maintainability rating A',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- executable_lines_data: {
- id: 'AXJMbImPPAOIsUIE3guW',
- key: 'executable_lines_data',
- type: 'DATA',
- name: 'executable_lines_data',
- domain: 'Coverage',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- false_positive_issues: {
- id: 'AXJMbIl_PAOIsUIE3gt4',
- key: 'false_positive_issues',
- type: 'INT',
- name: 'False Positive Issues',
- description: 'False positive issues',
- domain: 'Issues',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- files: {
- id: 'AXJMbImPPAOIsUIE3gu6',
- key: 'files',
- type: 'INT',
- name: 'Files',
- description: 'Number of files',
- domain: 'Size',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- functions: {
- id: 'AXJMbImPPAOIsUIE3gu-',
- key: 'functions',
- type: 'INT',
- name: 'Functions',
- description: 'Functions',
- domain: 'Size',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- generated_lines: {
- id: 'AXJMbImPPAOIsUIE3gu0',
- key: 'generated_lines',
- type: 'INT',
- name: 'Generated Lines',
- description: 'Number of generated lines',
- domain: 'Size',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- generated_ncloc: {
- id: 'AXJMbImPPAOIsUIE3gu4',
- key: 'generated_ncloc',
- type: 'INT',
- name: 'Generated Lines of Code',
- description: 'Generated non Commenting Lines of Code',
- domain: 'Size',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- software_quality_high_issues: {
- id: '50f6240a-85c5-4aaf-a928-657c7f03b6ef',
- key: 'software_quality_high_issues',
- type: 'INT',
- name: 'High Severity Issues',
- description: 'High Severity issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- info_violations: {
- id: 'AXJMbIl_PAOIsUIE3gtx',
- key: 'info_violations',
- type: 'INT',
- name: 'Info Issues',
- description: 'Info issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_info_issues: {
- id: 'cfc48499-476f-43fb-999e-43bb33e7c93a',
- key: 'software_quality_info_issues',
- type: 'INT',
- name: 'Info Severity Issues',
- description: 'Info Severity issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- violations: {
- id: 'AXJMbImPPAOIsUIE3gul',
- key: 'violations',
- type: 'INT',
- name: 'Issues',
- description: 'Issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- prioritized_rule_issues: {
- id: '789e3a55-205b-46c8-b9dc-9fa92734c0fc',
- key: 'prioritized_rule_issues',
- type: 'INT',
- name: 'Issues from prioritized rules',
- description: 'Count of issues that have a flag Prioritized Rule.',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- last_change_on_maintainability_rating: {
- id: 'AXJMbImPPAOIsUIE3gud',
- key: 'last_change_on_maintainability_rating',
- type: 'DATA',
- name: 'Last Change on Maintainability Rating',
- domain: 'Maintainability',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- last_change_on_releasability_rating: {
- id: 'AXJMbImPPAOIsUIE3gue',
- key: 'last_change_on_releasability_rating',
- type: 'DATA',
- name: 'Last Change on Releasability Rating',
- domain: 'Releasability',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- last_change_on_reliability_rating: {
- id: 'AXJMbImPPAOIsUIE3guf',
- key: 'last_change_on_reliability_rating',
- type: 'DATA',
- name: 'Last Change on Reliability Rating',
- domain: 'Reliability',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- last_change_on_security_rating: {
- id: 'AXJMbImPPAOIsUIE3gug',
- key: 'last_change_on_security_rating',
- type: 'DATA',
- name: 'Last Change on Security Rating',
- domain: 'Security',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- last_change_on_security_review_rating: {
- id: 'AXJMbIl9PAOIsUIE3gs4',
- key: 'last_change_on_security_review_rating',
- type: 'DATA',
- name: 'Last Change on Security Review Rating',
- domain: 'Security',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- last_change_on_software_quality_maintainability_rating: {
- id: 'f82cff1f-a70a-497a-bca8-33d8abb20e2e',
- key: 'last_change_on_software_quality_maintainability_rating',
- type: 'DATA',
- name: 'Last Change on Software Quality Maintainability Rating',
- domain: 'Maintainability',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- last_change_on_software_quality_reliability_rating: {
- id: '42889539-14b7-45a5-a383-8c4d4a5e48a5',
- key: 'last_change_on_software_quality_reliability_rating',
- type: 'DATA',
- name: 'Last Change on Software Quality Reliability Rating',
- domain: 'Reliability',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- last_change_on_software_quality_security_rating: {
- id: 'd236e941-90e8-4c35-b995-47d05637b6a4',
- key: 'last_change_on_software_quality_security_rating',
- type: 'DATA',
- name: 'Last Change on Software Quality Security Rating',
- domain: 'Security',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- line_coverage: {
- id: 'AXJMbIl_PAOIsUIE3gtl',
- key: 'line_coverage',
- type: 'PERCENT',
- name: 'Line Coverage',
- description: 'Line coverage',
- domain: 'Coverage',
- direction: 1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- new_line_coverage: {
- id: 'AXJMbIl_PAOIsUIE3gtm',
- key: 'new_line_coverage',
- type: 'PERCENT',
- name: 'Line Coverage on New Code',
- description: 'Line coverage of added/changed code',
- domain: 'Coverage',
- direction: 1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- lines: {
- id: 'AXJMbImPPAOIsUIE3guz',
- key: 'lines',
- type: 'INT',
- name: 'Lines',
- description: 'Lines',
- domain: 'Size',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- ncloc: {
- id: 'AXJMbImPPAOIsUIE3gu1',
- key: 'ncloc',
- type: 'INT',
- name: 'Lines of Code',
- description: 'Non commenting lines of code',
- domain: 'Size',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- ncloc_language_distribution: {
- id: 'AXJMbImPPAOIsUIE3gu3',
- key: 'ncloc_language_distribution',
- type: 'DATA',
- name: 'Lines of Code Per Language',
- description: 'Non Commenting Lines of Code Distributed By Language',
- domain: 'Size',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- lines_to_cover: {
- id: 'AXJMbImPPAOIsUIE3gu_',
- key: 'lines_to_cover',
- type: 'INT',
- name: 'Lines to Cover',
- description: 'Lines to cover',
- domain: 'Coverage',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- new_lines_to_cover: {
- id: 'AXJMbIl_PAOIsUIE3gti',
- key: 'new_lines_to_cover',
- type: 'INT',
- name: 'Lines to Cover on New Code',
- description: 'Lines to cover on new code',
- domain: 'Coverage',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- leak_projects: {
- id: 'AXJMbImPPAOIsUIE3gvE',
- key: 'leak_projects',
- type: 'DATA',
- name: 'List of technical projects with their leaks',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- software_quality_low_issues: {
- id: '452a1f9d-c0c6-4001-b5ce-921b748423e2',
- key: 'software_quality_low_issues',
- type: 'INT',
- name: 'Low Severity Issues',
- description: 'Low Severity issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- maintainability_issues: {
- id: 'acc8fd75-3acf-499f-809c-f104af89d16d',
- key: 'maintainability_issues',
- type: 'DATA',
- name: 'Maintainability Issues',
- description: 'Maintainability issues',
- domain: 'Maintainability',
- direction: 0,
- qualitative: false,
- hidden: false,
- },
- software_quality_maintainability_issues: {
- id: '163c2107-797a-46c8-a1a9-912b00dae7df',
- key: 'software_quality_maintainability_issues',
- type: 'INT',
- name: 'Maintainability Issues',
- description: 'Maintainability Issues',
- domain: 'Maintainability',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- software_quality_maintainability_rating: {
- id: '9fc76baf-f660-4f65-a271-b2ae7f849239',
- key: 'software_quality_maintainability_rating',
- type: 'RATING',
- name: 'Maintainability Rating',
- description: 'Maintainability rating',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- sqale_rating: {
- id: 'AXJMbIl_PAOIsUIE3guF',
- key: 'sqale_rating',
- type: 'RATING',
- name: 'Maintainability Rating',
- description: 'A-to-E rating based on the technical debt ratio',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- maintainability_rating_distribution: {
- id: 'AX3sJDjtJHBehddvNyhN',
- key: 'maintainability_rating_distribution',
- type: 'DATA',
- name: 'Maintainability Rating Distribution',
- description: 'Maintainability rating distribution',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- new_maintainability_rating_distribution: {
- id: 'AX3sJDjvJHBehddvNyhR',
- key: 'new_maintainability_rating_distribution',
- type: 'DATA',
- name: 'Maintainability Rating Distribution on New Code',
- description: 'Maintainability rating distribution on new code',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- new_software_quality_maintainability_rating: {
- id: 'c5d12cc4-e712-4701-a395-c9113ce13c3e',
- key: 'new_software_quality_maintainability_rating',
- type: 'RATING',
- name: 'Maintainability Rating on New Code',
- description: 'Maintainability rating on new code',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_maintainability_rating: {
- id: 'AXJMbIl_PAOIsUIE3guH',
- key: 'new_maintainability_rating',
- type: 'RATING',
- name: 'Maintainability Rating on New Code',
- description: 'Maintainability rating on new code',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- major_violations: {
- id: 'AXJMbIl_PAOIsUIE3gtv',
- key: 'major_violations',
- type: 'INT',
- name: 'Major Issues',
- description: 'Major issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_medium_issues: {
- id: '5c85ee75-753a-44db-b357-5ea54cd2d88b',
- key: 'software_quality_medium_issues',
- type: 'INT',
- name: 'Medium Severity Issues',
- description: 'Medium Severity issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- minor_violations: {
- id: 'AXJMbIl_PAOIsUIE3gtw',
- key: 'minor_violations',
- type: 'INT',
- name: 'Minor Issues',
- description: 'Minor issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- ncloc_data: {
- id: 'AXJMbImPPAOIsUIE3guU',
- key: 'ncloc_data',
- type: 'DATA',
- name: 'ncloc_data',
- domain: 'Size',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- new_accepted_issues: {
- id: 'AY0aC41wVDhd53-OniNb',
- key: 'new_accepted_issues',
- type: 'INT',
- name: 'New Accepted Issues',
- description: 'New accepted issues',
- domain: 'Issues',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- new_blocker_violations: {
- id: 'AXJMbIl_PAOIsUIE3gtz',
- key: 'new_blocker_violations',
- type: 'INT',
- name: 'New Blocker Issues',
- description: 'New Blocker issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_software_quality_blocker_issues: {
- id: '24492b83-d35f-4cbd-b12f-0b1168cb7c9a',
- key: 'new_software_quality_blocker_issues',
- type: 'INT',
- name: 'New Blocker Severity Issues',
- description: 'New Blocker Severity issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_bugs: {
- id: 'AXJMbIl_PAOIsUIE3guA',
- key: 'new_bugs',
- type: 'INT',
- name: 'New Bugs',
- description: 'New Bugs',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_code_smells: {
- id: 'AXJMbIl_PAOIsUIE3gt-',
- key: 'new_code_smells',
- type: 'INT',
- name: 'New Code Smells',
- description: 'New Code Smells',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_critical_violations: {
- id: 'AXJMbIl_PAOIsUIE3gt0',
- key: 'new_critical_violations',
- type: 'INT',
- name: 'New Critical Issues',
- description: 'New Critical issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_software_quality_high_issues: {
- id: '1f2e2f4d-4069-4998-885b-287cb87939b6',
- key: 'new_software_quality_high_issues',
- type: 'INT',
- name: 'New High Severity Issues',
- description: 'New High Severity issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_info_violations: {
- id: 'AXJMbIl_PAOIsUIE3gt3',
- key: 'new_info_violations',
- type: 'INT',
- name: 'New Info Issues',
- description: 'New Info issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_software_quality_info_issues: {
- id: '6857dd13-4d48-4a6f-b985-889930ee3508',
- key: 'new_software_quality_info_issues',
- type: 'INT',
- name: 'New Info Severity Issues',
- description: 'New Info Severity issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_violations: {
- id: 'AXJMbIl_PAOIsUIE3gty',
- key: 'new_violations',
- type: 'INT',
- name: 'New Issues',
- description: 'New issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_lines: {
- id: 'AXJMbImPPAOIsUIE3gu2',
- key: 'new_lines',
- type: 'INT',
- name: 'New Lines',
- description: 'New lines',
- domain: 'Size',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- new_software_quality_low_issues: {
- id: '8ecc3d65-72e7-4a36-9d1b-84344ba017f3',
- key: 'new_software_quality_low_issues',
- type: 'INT',
- name: 'New Low Severity Issues',
- description: 'New Low Severity issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_maintainability_issues: {
- id: '9385d0e6-8991-40b1-b94a-5a260e6146f0',
- key: 'new_maintainability_issues',
- type: 'DATA',
- name: 'New Maintainability Issues',
- description: 'New maintainability issues',
- domain: 'Maintainability',
- direction: 0,
- qualitative: false,
- hidden: false,
- },
- new_software_quality_maintainability_issues: {
- id: 'e0216417-de54-4beb-8948-f61bd53987ed',
- key: 'new_software_quality_maintainability_issues',
- type: 'INT',
- name: 'New Maintainability Issues',
- description: 'New Maintainability Issues',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_major_violations: {
- id: 'AXJMbIl_PAOIsUIE3gt1',
- key: 'new_major_violations',
- type: 'INT',
- name: 'New Major Issues',
- description: 'New Major issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_software_quality_medium_issues: {
- id: '9d634fca-caee-4bee-8e23-37744d014194',
- key: 'new_software_quality_medium_issues',
- type: 'INT',
- name: 'New Medium Severity Issues',
- description: 'New Medium Severity issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_minor_violations: {
- id: 'AXJMbIl_PAOIsUIE3gt2',
- key: 'new_minor_violations',
- type: 'INT',
- name: 'New Minor Issues',
- description: 'New Minor issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_reliability_issues: {
- id: 'e1cbc8a4-82d7-4d41-8c95-ad86fcd3d57d',
- key: 'new_reliability_issues',
- type: 'DATA',
- name: 'New Reliability Issues',
- description: 'New reliability issues',
- domain: 'Reliability',
- direction: 0,
- qualitative: false,
- hidden: false,
- },
- new_software_quality_reliability_issues: {
- id: 'bfcac26d-2ce7-4fbf-b5c6-ea4f6556825d',
- key: 'new_software_quality_reliability_issues',
- type: 'INT',
- name: 'New Reliability Issues',
- description: 'New Reliability Issues',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_security_hotspots: {
- id: 'AXJMbIl9PAOIsUIE3gsw',
- key: 'new_security_hotspots',
- type: 'INT',
- name: 'New Security Hotspots',
- description: 'New Security Hotspots',
- domain: 'SecurityReview',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_software_quality_security_issues: {
- id: 'ecf1983d-ea7e-4df6-b377-d16f4a5a59e6',
- key: 'new_software_quality_security_issues',
- type: 'INT',
- name: 'New Security Issues',
- description: 'New Security Issues',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_security_issues: {
- id: '6887ef7d-ee21-449c-b1ff-f3f7930ba27f',
- key: 'new_security_issues',
- type: 'DATA',
- name: 'New Security Issues',
- description: 'New security issues',
- domain: 'Security',
- direction: 0,
- qualitative: false,
- hidden: false,
- },
- new_vulnerabilities: {
- id: 'AXJMbIl_PAOIsUIE3guC',
- key: 'new_vulnerabilities',
- type: 'INT',
- name: 'New Vulnerabilities',
- description: 'New Vulnerabilities',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- unanalyzed_c: {
- id: 'AXTb6RMqLLQlB5osv3xN',
- key: 'unanalyzed_c',
- type: 'INT',
- name: 'Number of unanalyzed c files',
- domain: 'Size',
- direction: -1,
- qualitative: false,
- hidden: true,
- },
- unanalyzed_cpp: {
- id: 'AXTb6RMtLLQlB5osv3xO',
- key: 'unanalyzed_cpp',
- type: 'INT',
- name: 'Number of unanalyzed c++ files',
- domain: 'Size',
- direction: -1,
- qualitative: false,
- hidden: true,
- },
- open_issues: {
- id: 'AXJMbIl_PAOIsUIE3gt6',
- key: 'open_issues',
- type: 'INT',
- name: 'Open Issues',
- description: 'Open issues',
- domain: 'Issues',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- quality_profiles: {
- id: 'AXJMbImPPAOIsUIE3guZ',
- key: 'quality_profiles',
- type: 'DATA',
- name: 'Profiles',
- description: 'Details of quality profiles used during analysis',
- domain: 'General',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- projects: {
- id: 'AXJMbImPPAOIsUIE3guo',
- key: 'projects',
- type: 'INT',
- name: 'Project branches',
- description: 'Number of project branches',
- domain: 'Size',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- public_api: {
- id: 'AXJMbImPPAOIsUIE3gun',
- key: 'public_api',
- type: 'INT',
- name: 'Public API',
- description: 'Public API',
- domain: 'Documentation',
- direction: -1,
- qualitative: false,
- hidden: true,
- },
- public_documented_api_density: {
- id: 'AXJMbImPPAOIsUIE3gur',
- key: 'public_documented_api_density',
- type: 'PERCENT',
- name: 'Public Documented API (%)',
- description: 'Public documented classes and functions balanced by ncloc',
- domain: 'Documentation',
- direction: 1,
- qualitative: true,
- hidden: true,
- decimalScale: 1,
- },
- public_undocumented_api: {
- id: 'AXJMbImPPAOIsUIE3gus',
- key: 'public_undocumented_api',
- type: 'INT',
- name: 'Public Undocumented API',
- description: 'Public undocumented classes, functions and variables',
- domain: 'Documentation',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- pull_request_fixed_issues: {
- id: 'AY0aC410VDhd53-OniNd',
- key: 'pull_request_fixed_issues',
- type: 'INT',
- name: 'Pull request fixed issues',
- description: 'Count of issues that would be fixed by the pull request.',
- domain: 'Issues',
- direction: 1,
- qualitative: false,
- hidden: true,
- },
- quality_gate_details: {
- id: 'AXJMbImPPAOIsUIE3guY',
- key: 'quality_gate_details',
- type: 'DATA',
- name: 'Quality Gate Details',
- description: 'The project detailed status with regard to its quality gate',
- domain: 'General',
- direction: 0,
- qualitative: false,
- hidden: false,
- },
- alert_status: {
- id: 'AXJMbImPPAOIsUIE3guX',
- key: 'alert_status',
- type: 'LEVEL',
- name: 'Quality Gate Status',
- description: 'The project status with regard to its quality gate.',
- domain: 'Releasability',
- direction: 1,
- qualitative: true,
- hidden: false,
- },
- releasability_rating: {
- id: 'AXJMbImPPAOIsUIE3guc',
- key: 'releasability_rating',
- type: 'RATING',
- name: 'Releasability rating',
- domain: 'Releasability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- releasability_rating_distribution: {
- id: 'AX3sJDivJHBehddvNyhM',
- key: 'releasability_rating_distribution',
- type: 'DATA',
- name: 'Releasability Rating Distribution',
- description: 'Releasability rating distribution',
- domain: 'Releasability',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- reliability_issues: {
- id: 'b11a4b65-4070-487d-a973-8ec85e2858b3',
- key: 'reliability_issues',
- type: 'DATA',
- name: 'Reliability Issues',
- description: 'Reliability issues',
- domain: 'Reliability',
- direction: 0,
- qualitative: false,
- hidden: false,
- },
- software_quality_reliability_issues: {
- id: '765f3905-47df-4d9c-b568-9184f341a737',
- key: 'software_quality_reliability_issues',
- type: 'INT',
- name: 'Reliability Issues',
- description: 'Reliability Issues',
- domain: 'Reliability',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- reliability_rating: {
- id: 'AXJMbIl_PAOIsUIE3guP',
- key: 'reliability_rating',
- type: 'RATING',
- name: 'Reliability Rating',
- description: 'Reliability rating',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_reliability_rating: {
- id: '6548ffa4-8a5e-4445-a28d-e2fd9fdbba78',
- key: 'software_quality_reliability_rating',
- type: 'RATING',
- name: 'Reliability Rating',
- description: 'Reliability rating',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- reliability_rating_distribution: {
- id: 'AX3sJDjuJHBehddvNyhO',
- key: 'reliability_rating_distribution',
- type: 'DATA',
- name: 'Reliability Rating Distribution',
- description: 'Reliability rating distribution',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- new_reliability_rating_distribution: {
- id: 'AX3sJDjvJHBehddvNyhS',
- key: 'new_reliability_rating_distribution',
- type: 'DATA',
- name: 'Reliability Rating Distribution on New Code',
- description: 'Reliability rating distribution on new code',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- new_reliability_rating: {
- id: 'AXJMbIl_PAOIsUIE3guQ',
- key: 'new_reliability_rating',
- type: 'RATING',
- name: 'Reliability Rating on New Code',
- description: 'Reliability rating on new code',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_software_quality_reliability_rating: {
- id: 'ab82dcac-cf81-4780-965d-1384ce9e8983',
- key: 'new_software_quality_reliability_rating',
- type: 'RATING',
- name: 'Reliability Rating on New Code',
- description: 'Reliability rating on new code',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- reliability_remediation_effort: {
- id: 'AXJMbIl_PAOIsUIE3guN',
- key: 'reliability_remediation_effort',
- type: 'WORK_DUR',
- name: 'Reliability Remediation Effort',
- description: 'Reliability Remediation Effort',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_reliability_remediation_effort: {
- id: 'f2094b93-e08c-4350-ad8f-f265974278a8',
- key: 'software_quality_reliability_remediation_effort',
- type: 'WORK_DUR',
- name: 'Reliability Remediation Effort',
- description: 'Reliability remediation effort',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_software_quality_reliability_remediation_effort: {
- id: '45f9a292-5f6e-459e-8d81-134d5aaedef9',
- key: 'new_software_quality_reliability_remediation_effort',
- type: 'WORK_DUR',
- name: 'Reliability Remediation Effort on New Code',
- description: 'Reliability remediation effort on new code',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_reliability_remediation_effort: {
- id: 'AXJMbIl_PAOIsUIE3guO',
- key: 'new_reliability_remediation_effort',
- type: 'WORK_DUR',
- name: 'Reliability Remediation Effort on New Code',
- description: 'Reliability remediation effort on new code',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- reopened_issues: {
- id: 'AXJMbIl_PAOIsUIE3gt7',
- key: 'reopened_issues',
- type: 'INT',
- name: 'Reopened Issues',
- description: 'Reopened issues',
- domain: 'Issues',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- security_hotspots: {
- id: 'AXJMbIl9PAOIsUIE3gsv',
- key: 'security_hotspots',
- type: 'INT',
- name: 'Security Hotspots',
- description: 'Security Hotspots',
- domain: 'SecurityReview',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- security_hotspots_reviewed: {
- id: 'AXJMbIl9PAOIsUIE3gs0',
- key: 'security_hotspots_reviewed',
- type: 'PERCENT',
- name: 'Security Hotspots Reviewed',
- description: 'Percentage of Security Hotspots Reviewed',
- domain: 'SecurityReview',
- direction: 1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- new_security_hotspots_reviewed: {
- id: 'AXJMbIl9PAOIsUIE3gs1',
- key: 'new_security_hotspots_reviewed',
- type: 'PERCENT',
- name: 'Security Hotspots Reviewed on New Code',
- description: 'Percentage of Security Hotspots Reviewed on New Code',
- domain: 'SecurityReview',
- direction: 1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- security_issues: {
- id: 'e6ddc573-16b7-4bc4-aff8-6d28b59035e0',
- key: 'security_issues',
- type: 'DATA',
- name: 'Security Issues',
- description: 'Security issues',
- domain: 'Security',
- direction: 0,
- qualitative: false,
- hidden: false,
- },
- software_quality_security_issues: {
- id: '7133e418-aadb-4cac-b31f-b13bf036a7ff',
- key: 'software_quality_security_issues',
- type: 'INT',
- name: 'Security Issues',
- description: 'Security Issues',
- domain: 'Security',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- security_rating: {
- id: 'AXJMbIl_PAOIsUIE3guS',
- key: 'security_rating',
- type: 'RATING',
- name: 'Security Rating',
- description: 'Security rating',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_security_rating: {
- id: 'db22dacd-a3fd-41d2-8617-0cb7cfc86429',
- key: 'software_quality_security_rating',
- type: 'RATING',
- name: 'Security Rating',
- description: 'Security rating',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- security_rating_distribution: {
- id: 'AX3sJDjuJHBehddvNyhP',
- key: 'security_rating_distribution',
- type: 'DATA',
- name: 'Security Rating Distribution',
- description: 'Security rating distribution',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- new_security_rating_distribution: {
- id: 'AX3sJDjvJHBehddvNyhT',
- key: 'new_security_rating_distribution',
- type: 'DATA',
- name: 'Security Rating Distribution on New Code',
- description: 'Security rating distribution on new code',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- new_software_quality_security_rating: {
- id: '228b9a04-09a2-418e-9ea4-3584a57a95ba',
- key: 'new_software_quality_security_rating',
- type: 'RATING',
- name: 'Security Rating on New Code',
- description: 'Security rating on new code',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_security_rating: {
- id: 'AXJMbImPPAOIsUIE3guT',
- key: 'new_security_rating',
- type: 'RATING',
- name: 'Security Rating on New Code',
- description: 'Security rating on new code',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_security_remediation_effort: {
- id: '43652a84-3ca7-4506-9c09-00ea2b6c6e71',
- key: 'software_quality_security_remediation_effort',
- type: 'WORK_DUR',
- name: 'Security Remediation Effort',
- description: 'Security remediation effort',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- security_remediation_effort: {
- id: 'AXJMbIl_PAOIsUIE3guG',
- key: 'security_remediation_effort',
- type: 'WORK_DUR',
- name: 'Security Remediation Effort',
- description: 'Security remediation effort',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_security_remediation_effort: {
- id: 'AXJMbIl_PAOIsUIE3guR',
- key: 'new_security_remediation_effort',
- type: 'WORK_DUR',
- name: 'Security Remediation Effort on New Code',
- description: 'Security remediation effort on new code',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_software_quality_security_remediation_effort: {
- id: 'd5d0020a-419c-4387-b00f-523ad8a6a3e4',
- key: 'new_software_quality_security_remediation_effort',
- type: 'WORK_DUR',
- name: 'Security Remediation Effort on New Code',
- description: 'Security remediation effort on new code',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- security_review_rating: {
- id: 'AXJMbIl9PAOIsUIE3gsx',
- key: 'security_review_rating',
- type: 'RATING',
- name: 'Security Review Rating',
- description: 'Security Review Rating',
- domain: 'SecurityReview',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- security_review_rating_distribution: {
- id: 'AX3sJDjuJHBehddvNyhQ',
- key: 'security_review_rating_distribution',
- type: 'DATA',
- name: 'Security Review Rating Distribution',
- description: 'Security review rating distribution',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- new_security_review_rating_distribution: {
- id: 'AX3sJDjwJHBehddvNyhU',
- key: 'new_security_review_rating_distribution',
- type: 'DATA',
- name: 'Security Review Rating Distribution on New Code',
- description: 'Security review rating distribution on new code',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- new_security_review_rating: {
- id: 'AXJMbIl9PAOIsUIE3gtA',
- key: 'new_security_review_rating',
- type: 'RATING',
- name: 'Security Review Rating on New Code',
- description: 'Security Review Rating on New Code',
- domain: 'SecurityReview',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- security_hotspots_reviewed_status: {
- id: 'AXJMbIl9PAOIsUIE3gs2',
- key: 'security_hotspots_reviewed_status',
- type: 'INT',
- name: 'Security Review Reviewed Status',
- description: 'Security Review Reviewed Status',
- domain: 'SecurityReview',
- direction: -1,
- qualitative: false,
- hidden: true,
- },
- new_security_hotspots_reviewed_status: {
- id: 'AXJMbIl9PAOIsUIE3gtB',
- key: 'new_security_hotspots_reviewed_status',
- type: 'INT',
- name: 'Security Review Reviewed Status on New Code',
- description: 'Security Review Reviewed Status on New Code',
- domain: 'SecurityReview',
- direction: -1,
- qualitative: false,
- hidden: true,
- },
- security_hotspots_to_review_status: {
- id: 'AXJMbIl9PAOIsUIE3gs3',
- key: 'security_hotspots_to_review_status',
- type: 'INT',
- name: 'Security Review To Review Status',
- description: 'Security Review To Review Status',
- domain: 'SecurityReview',
- direction: -1,
- qualitative: false,
- hidden: true,
- },
- new_security_hotspots_to_review_status: {
- id: 'AXJMbIl9PAOIsUIE3gs5',
- key: 'new_security_hotspots_to_review_status',
- type: 'INT',
- name: 'Security Review To Review Status on New Code',
- description: 'Security Review To Review Status on New Code',
- domain: 'SecurityReview',
- direction: -1,
- qualitative: false,
- hidden: true,
- },
- skipped_tests: {
- id: 'AXJMbIl9PAOIsUIE3gtd',
- key: 'skipped_tests',
- type: 'INT',
- name: 'Skipped Unit Tests',
- description: 'Number of skipped unit tests',
- domain: 'Coverage',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_maintainability_rating_distribution: {
- id: 'b39b797b-216d-4800-810e-2277012ee096',
- key: 'software_quality_maintainability_rating_distribution',
- type: 'DATA',
- name: 'Software Quality Maintainability Rating Distribution',
- description: 'Software Quality Maintainability rating distribution',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- new_software_quality_maintainability_rating_distribution: {
- id: '21d0f133-de6d-4b2e-8302-99169720f8c6',
- key: 'new_software_quality_maintainability_rating_distribution',
- type: 'DATA',
- name: 'Software Quality Maintainability Rating Distribution on New Code',
- description: 'Software Quality Maintainability rating distribution on new code',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- software_quality_maintainability_rating_effort: {
- id: '0a25e15c-10c9-4d66-8dc0-41446319405d',
- key: 'software_quality_maintainability_rating_effort',
- type: 'DATA',
- name: 'Software Quality Maintainability Rating Effort',
- domain: 'Maintainability',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- software_quality_reliability_rating_distribution: {
- id: '571de2d7-d1ef-460b-8f99-e29e0aa6218c',
- key: 'software_quality_reliability_rating_distribution',
- type: 'DATA',
- name: 'Software Quality Reliability Rating Distribution',
- description: 'Software Quality Reliability rating distribution',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- new_software_quality_reliability_rating_distribution: {
- id: '77693e0a-fc61-465f-8fe0-a5fe77f4d507',
- key: 'new_software_quality_reliability_rating_distribution',
- type: 'DATA',
- name: 'Software Quality Reliability Rating Distribution on New Code',
- description: 'Software Quality Reliability rating distribution on new code',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- software_quality_reliability_rating_effort: {
- id: '38f61088-42f3-437f-b2b5-65a8fa4c7448',
- key: 'software_quality_reliability_rating_effort',
- type: 'DATA',
- name: 'Software Quality Reliability Rating Effort',
- domain: 'Reliability',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- software_quality_security_rating_distribution: {
- id: 'f9a76abe-7663-47b3-a27c-1dea7e6b4861',
- key: 'software_quality_security_rating_distribution',
- type: 'DATA',
- name: 'Software Quality Security Rating Distribution',
- description: 'Software Quality Security rating distribution',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- new_software_quality_security_rating_distribution: {
- id: '2f1155cb-3802-463a-95d3-dd352bafdc0c',
- key: 'new_software_quality_security_rating_distribution',
- type: 'DATA',
- name: 'Software Quality Security Rating Distribution on New Code',
- description: 'Software Quality Security rating distribution on new code',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- software_quality_security_rating_effort: {
- id: 'be673f93-1b72-418c-b134-b097dae65048',
- key: 'software_quality_security_rating_effort',
- type: 'DATA',
- name: 'Software Quality Security Rating Effort',
- domain: 'Security',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- statements: {
- id: 'AXJMbImPPAOIsUIE3gum',
- key: 'statements',
- type: 'INT',
- name: 'Statements',
- description: 'Number of statements',
- domain: 'Size',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- software_quality_maintainability_remediation_effort: {
- id: '24edda40-db1c-4acd-9c9b-66d5bcca8486',
- key: 'software_quality_maintainability_remediation_effort',
- type: 'WORK_DUR',
- name: 'Technical Debt',
- description:
- 'Total effort (in minutes) to fix all the maintainability issues on the component and therefore to comply to all the requirements.',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- sqale_index: {
- id: 'AXJMbIl_PAOIsUIE3guD',
- key: 'sqale_index',
- type: 'WORK_DUR',
- name: 'Technical Debt',
- description:
- 'Total effort (in minutes) to fix all the issues on the component and therefore to comply to all the requirements.',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_maintainability_debt_ratio: {
- id: '8a7a5279-9dfe-4fdf-9886-9203ae50be5c',
- key: 'software_quality_maintainability_debt_ratio',
- type: 'PERCENT',
- name: 'Technical Debt Ratio',
- description:
- 'Ratio of the actual technical debt compared to the estimated cost to develop the whole source code from scratch',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- sqale_debt_ratio: {
- id: 'AXJMbIl_PAOIsUIE3guK',
- key: 'sqale_debt_ratio',
- type: 'PERCENT',
- name: 'Technical Debt Ratio',
- description:
- 'Ratio of the actual technical debt compared to the estimated cost to develop the whole source code from scratch',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- new_software_quality_maintainability_debt_ratio: {
- id: '23330467-a21e-4254-a76a-2eb99aab6f0f',
- key: 'new_software_quality_maintainability_debt_ratio',
- type: 'PERCENT',
- name: 'Technical Debt Ratio on New Code',
- description: 'Technical Debt Ratio on New Code',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- new_sqale_debt_ratio: {
- id: 'AXJMbIl_PAOIsUIE3guL',
- key: 'new_sqale_debt_ratio',
- type: 'PERCENT',
- name: 'Technical Debt Ratio on New Code',
- description: 'Technical Debt Ratio of new/changed code.',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- maintainability_rating_effort: {
- id: 'AXJMbImPPAOIsUIE3gvD',
- key: 'maintainability_rating_effort',
- type: 'DATA',
- name: 'Total number of projects having worst maintainability rating',
- domain: 'Maintainability',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- reliability_rating_effort: {
- id: 'AXJMbImPPAOIsUIE3gvC',
- key: 'reliability_rating_effort',
- type: 'DATA',
- name: 'Total number of projects having worst reliability rating',
- domain: 'Reliability',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- security_rating_effort: {
- id: 'AXJMbImPPAOIsUIE3gvB',
- key: 'security_rating_effort',
- type: 'DATA',
- name: 'Total number of projects having worst security rating',
- domain: 'Security',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- security_review_rating_effort: {
- id: 'AXJMbIl9PAOIsUIE3gs6',
- key: 'security_review_rating_effort',
- type: 'DATA',
- name: 'Total number of projects having worst security review rating',
- domain: 'Security',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- releasability_effort: {
- id: 'AXJMbImPPAOIsUIE3gub',
- key: 'releasability_effort',
- type: 'INT',
- name: 'Total number of projects not production ready',
- domain: 'Releasability',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- uncovered_conditions: {
- id: 'AXJMbIl9PAOIsUIE3gs8',
- key: 'uncovered_conditions',
- type: 'INT',
- name: 'Uncovered Conditions',
- description: 'Uncovered conditions',
- domain: 'Coverage',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- new_uncovered_conditions: {
- id: 'AXJMbIl9PAOIsUIE3gs9',
- key: 'new_uncovered_conditions',
- type: 'INT',
- name: 'Uncovered Conditions on New Code',
- description: 'Uncovered conditions on new code',
- domain: 'Coverage',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- uncovered_lines: {
- id: 'AXJMbIl_PAOIsUIE3gtj',
- key: 'uncovered_lines',
- type: 'INT',
- name: 'Uncovered Lines',
- description: 'Uncovered lines',
- domain: 'Coverage',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- new_uncovered_lines: {
- id: 'AXJMbIl_PAOIsUIE3gtk',
- key: 'new_uncovered_lines',
- type: 'INT',
- name: 'Uncovered Lines on New Code',
- description: 'Uncovered lines on new code',
- domain: 'Coverage',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- test_execution_time: {
- id: 'AXJMbIl9PAOIsUIE3gtb',
- key: 'test_execution_time',
- type: 'MILLISEC',
- name: 'Unit Test Duration',
- description: 'Execution duration of unit tests',
- domain: 'Coverage',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- test_errors: {
- id: 'AXJMbIl9PAOIsUIE3gtc',
- key: 'test_errors',
- type: 'INT',
- name: 'Unit Test Errors',
- description: 'Number of unit test errors',
- domain: 'Coverage',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- test_failures: {
- id: 'AXJMbIl9PAOIsUIE3gte',
- key: 'test_failures',
- type: 'INT',
- name: 'Unit Test Failures',
- description: 'Number of unit test failures',
- domain: 'Coverage',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- tests: {
- id: 'AXJMbIl9PAOIsUIE3gta',
- key: 'tests',
- type: 'INT',
- name: 'Unit Tests',
- description: 'Number of unit tests',
- domain: 'Coverage',
- direction: 1,
- qualitative: false,
- hidden: false,
- },
- test_success_density: {
- id: 'AXJMbIl9PAOIsUIE3gtf',
- key: 'test_success_density',
- type: 'PERCENT',
- name: 'Unit Test Success (%)',
- description: 'Density of successful unit tests',
- domain: 'Coverage',
- direction: 1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- vulnerabilities: {
- id: 'AXJMbIl_PAOIsUIE3guB',
- key: 'vulnerabilities',
- type: 'INT',
- name: 'Vulnerabilities',
- description: 'Vulnerabilities',
- domain: 'Security',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
-};
diff --git a/server/sonar-web/src/main/js/helpers/mocks/new-code-definition.ts b/server/sonar-web/src/main/js/helpers/mocks/new-code-definition.ts
deleted file mode 100644
index 1a1bc1c140f..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/new-code-definition.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- NewCodeDefinition,
- NewCodeDefinitionBranch,
- NewCodeDefinitionType,
-} from '../../types/new-code-definition';
-
-export function mockNewCodePeriod(overrides: Partial<NewCodeDefinition> = {}): NewCodeDefinition {
- return {
- type: NewCodeDefinitionType.PreviousVersion,
- ...overrides,
- };
-}
-
-export function mockNewCodePeriodBranch(
- overrides: Partial<NewCodeDefinitionBranch> = {},
-): NewCodeDefinitionBranch {
- return {
- projectKey: 'pkey',
- branchKey: 'bKey',
- ...mockNewCodePeriod(),
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/permissions.ts b/server/sonar-web/src/main/js/helpers/mocks/permissions.ts
deleted file mode 100644
index 2a3bfe8f27f..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/permissions.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- Permission,
- PermissionGroup,
- PermissionTemplate,
- PermissionTemplateGroup,
- PermissionUser,
-} from '../../types/types';
-import { mockUser } from '../testMocks';
-
-export function mockPermissionGroup(overrides: Partial<PermissionGroup> = {}): PermissionGroup {
- return {
- name: 'sonar-admins',
- permissions: ['provisioning'],
- ...overrides,
- };
-}
-
-export function mockPermissionUser(overrides: Partial<PermissionUser> = {}): PermissionUser {
- return {
- ...mockUser(),
- active: true,
- name: 'johndoe',
- permissions: ['provisioning'],
- ...overrides,
- };
-}
-
-export function mockPermission(override: Partial<Permission> = {}) {
- return {
- key: 'admin',
- name: 'Admin',
- description: 'Can do anything he/she wants',
- ...override,
- };
-}
-
-export function mockPermissionTemplateGroup(override: Partial<PermissionTemplateGroup> = {}) {
- return {
- groupsCount: 1,
- usersCount: 1,
- key: 'admin',
- withProjectCreator: true,
- ...override,
- };
-}
-
-export function mockPermissionTemplate(override: Partial<PermissionTemplate> = {}) {
- return {
- id: 'template1',
- name: 'Permission Template 1',
- createdAt: '',
- defaultFor: [],
- permissions: [mockPermissionTemplateGroup()],
- ...override,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/plugins.ts b/server/sonar-web/src/main/js/helpers/mocks/plugins.ts
deleted file mode 100644
index 58fed3e5f84..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/plugins.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- AvailablePlugin,
- InstalledPlugin,
- PendingPlugin,
- Plugin,
- Release,
- Update,
-} from '../../types/plugins';
-
-export function mockPlugin(overrides: Partial<Plugin> = {}): Plugin {
- return {
- key: 'sonar-foo',
- name: 'Sonar Foo',
- ...overrides,
- };
-}
-
-export function mockPendingPlugin(overrides: Partial<PendingPlugin> = {}): PendingPlugin {
- return {
- key: 'sonar-foo',
- name: 'Sonar Foo',
- version: '1.0',
- implementationBuild: '1.0.0.1234',
- ...overrides,
- };
-}
-
-export function mockInstalledPlugin(overrides: Partial<InstalledPlugin> = {}): InstalledPlugin {
- return {
- key: 'sonar-bar',
- name: 'Sonar Bar',
- version: '1.0',
- implementationBuild: '1.0.0.1234',
- filename: 'sonar-bar-1.0.jar',
- hash: 'hash',
- sonarLintSupported: false,
- updatedAt: 100,
- ...overrides,
- };
-}
-
-export function mockAvailablePlugin(overrides: Partial<AvailablePlugin> = {}): AvailablePlugin {
- return {
- release: mockRelease(),
- update: mockUpdate(),
- ...mockPlugin(),
- ...overrides,
- };
-}
-
-export function mockRelease(overrides: Partial<Release> = {}): Release {
- return {
- date: '2020-01-01',
- version: '8.2',
- ...overrides,
- };
-}
-
-export function mockUpdate(overrides: Partial<Update> = {}): Update {
- return {
- status: 'available',
- requires: [],
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/project-activity.ts b/server/sonar-web/src/main/js/helpers/mocks/project-activity.ts
deleted file mode 100644
index f55aa81f76e..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/project-activity.ts
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import {
- Analysis,
- AnalysisEvent,
- HistoryItem,
- MeasureHistory,
- ParsedAnalysis,
- ProjectAnalysisEventCategory,
- Serie,
-} from '../../types/project-activity';
-import { parseDate } from '../dates';
-
-export function mockAnalysis(overrides: Partial<Analysis> = {}): Analysis {
- return {
- date: '2017-03-01T09:36:01+0100',
- events: [],
- key: 'foo',
- projectVersion: '1.0',
- ...overrides,
- };
-}
-
-export function mockParsedAnalysis(overrides: Partial<ParsedAnalysis> = {}): ParsedAnalysis {
- return {
- date: parseDate('2017-03-01T09:37:01+0100'),
- events: [],
- key: 'foo',
- projectVersion: '1.0',
- ...overrides,
- };
-}
-
-export function mockAnalysisEvent(overrides: Partial<AnalysisEvent> = {}): AnalysisEvent {
- return {
- category: ProjectAnalysisEventCategory.QualityGate,
- key: 'E11',
- description: 'Lorem ipsum dolor sit amet',
- name: 'Lorem ipsum',
- qualityGate: {
- status: 'ERROR',
- stillFailing: true,
- failing: [
- {
- key: 'foo',
- name: 'Foo',
- branch: 'master',
- },
- {
- key: 'bar',
- name: 'Bar',
- branch: 'feature/bar',
- },
- ],
- },
- ...overrides,
- };
-}
-
-export function mockMeasureHistory(overrides: Partial<MeasureHistory> = {}): MeasureHistory {
- return {
- metric: MetricKey.code_smells,
- history: [
- mockHistoryItem(),
- mockHistoryItem({ date: parseDate('2018-10-27T12:21:15+0200'), value: '1749' }),
- mockHistoryItem({ date: parseDate('2020-10-27T16:33:50+0200'), value: '500' }),
- ],
- ...overrides,
- };
-}
-
-export function mockHistoryItem(overrides: Partial<HistoryItem> = {}): HistoryItem {
- return {
- date: parseDate('2016-10-26T12:17:29+0200'),
- value: '2286',
- ...overrides,
- };
-}
-
-export function mockSerie(overrides: Partial<Serie> = {}): Serie {
- return {
- data: [
- { x: parseDate('2017-04-27T08:21:32.000Z'), y: 2 },
- { x: parseDate('2017-04-30T23:06:24.000Z'), y: 2 },
- ],
- name: 'foo',
- translatedName: 'foo',
- type: MetricType.Integer,
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/projects.ts b/server/sonar-web/src/main/js/helpers/mocks/projects.ts
deleted file mode 100644
index 23e4ac07145..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/projects.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentQualifier, Visibility } from '~sonar-aligned/types/component';
-import { Project } from '../../api/project-management';
-
-export function mockProject(overrides: Partial<Project> = {}): Project {
- return {
- key: 'foo',
- name: 'Foo',
- qualifier: ComponentQualifier.Project,
- visibility: Visibility.Public,
- lastAnalysisDate: '2019-01-04T09:51:48Z',
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/quality-gates.ts b/server/sonar-web/src/main/js/helpers/mocks/quality-gates.ts
deleted file mode 100644
index 0e631fc69ee..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/quality-gates.ts
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import {
- QualityGateApplicationStatus,
- QualityGateProjectStatus,
- QualityGateProjectStatusCondition,
- QualityGateStatus,
- QualityGateStatusCondition,
- QualityGateStatusConditionEnhanced,
-} from '../../types/quality-gates';
-import { CaycStatus, QualityGate } from '../../types/types';
-import { mockMeasureEnhanced, mockMetric } from '../testMocks';
-
-export function mockQualityGate(overrides: Partial<QualityGate> = {}): QualityGate {
- return {
- name: 'qualitygate',
- ...overrides,
- };
-}
-
-export function mockQualityGateStatus(
- overrides: Partial<QualityGateStatus> = {},
-): QualityGateStatus {
- const condition = mockQualityGateStatusConditionEnhanced();
- return {
- ignoredConditions: false,
- caycStatus: CaycStatus.Compliant,
- conditions: [condition],
- failedConditions: [condition],
- key: 'foo',
- name: 'Foo',
- status: 'ERROR',
- ...overrides,
- };
-}
-
-export function mockQualityGateProjectCondition(
- overrides: Partial<QualityGateProjectStatusCondition> = {},
-): QualityGateProjectStatusCondition {
- return {
- actualValue: '10',
- errorThreshold: '0',
- status: 'ERROR',
- metricKey: 'foo',
- comparator: 'GT',
- periodIndex: 1,
- ...overrides,
- };
-}
-
-export function mockQualityGateStatusCondition(
- overrides: Partial<QualityGateStatusCondition> = {},
-): QualityGateStatusCondition {
- return {
- actual: '10',
- error: '0',
- level: 'ERROR',
- metric: MetricKey.bugs,
- op: 'GT',
- ...overrides,
- };
-}
-
-export function mockQualityGateStatusConditionEnhanced(
- overrides: Partial<QualityGateStatusConditionEnhanced> = {},
-): QualityGateStatusConditionEnhanced {
- return {
- actual: '10',
- error: '0',
- level: 'ERROR',
- metric: MetricKey.bugs,
- op: 'GT',
- measure: mockMeasureEnhanced({ ...(overrides.measure || {}) }),
- ...overrides,
- };
-}
-
-export function mockQualityGateProjectStatus(
- overrides: Partial<QualityGateProjectStatus> = {},
-): QualityGateProjectStatus {
- return {
- conditions: [
- {
- actualValue: '0',
- comparator: 'GT',
- errorThreshold: '1.0',
- metricKey: 'new_bugs',
- periodIndex: 1,
- status: 'OK',
- },
- ],
- ignoredConditions: false,
- caycStatus: CaycStatus.Compliant,
- status: 'OK',
- ...overrides,
- };
-}
-
-export function mockQualityGateApplicationStatus(
- overrides: Partial<QualityGateApplicationStatus> = {},
-): QualityGateApplicationStatus {
- return {
- metrics: [mockMetric(), mockMetric({ name: 'new_bugs', key: 'new_bugs', type: 'INT' })],
- projects: [
- {
- key: 'foo',
- name: 'Foo',
- conditions: [
- {
- comparator: 'GT',
- errorThreshold: '1.0',
- metric: 'coverage',
- status: 'ERROR',
- value: '10',
- },
- {
- comparator: 'GT',
- errorThreshold: '1.0',
- metric: 'new_bugs',
- periodIndex: 1,
- status: 'ERROR',
- value: '5',
- },
- ],
- caycStatus: CaycStatus.Compliant,
- status: 'ERROR',
- },
- {
- key: 'bar',
- name: 'Bar',
- conditions: [
- {
- comparator: 'GT',
- errorThreshold: '5.0',
- metric: 'new_bugs',
- periodIndex: 1,
- status: 'ERROR',
- value: '15',
- },
- ],
- caycStatus: CaycStatus.Compliant,
- status: 'ERROR',
- },
- ],
- status: 'ERROR',
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/quality-profiles.ts b/server/sonar-web/src/main/js/helpers/mocks/quality-profiles.ts
deleted file mode 100644
index 95b6bd03b07..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/quality-profiles.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ProfileOption } from '../../apps/projectQualityProfiles/components/LanguageProfileSelectOption';
-
-export function mockProfileOption(overrides: Partial<ProfileOption> = {}): ProfileOption {
- return {
- value: 'profile-1',
- label: 'Profile 1',
- language: 'Java',
- isDisabled: false,
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/react-select.ts b/server/sonar-web/src/main/js/helpers/mocks/react-select.ts
deleted file mode 100644
index 8ce61866b69..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/react-select.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- ClearIndicatorProps,
- ControlProps,
- DropdownIndicatorProps,
- GroupBase,
- InputProps,
- OptionProps,
-} from 'react-select';
-
-export function mockReactSelectOptionProps<
- OptionType = unknown,
- IsMulti extends boolean = boolean,
- GroupType extends GroupBase<OptionType> = GroupBase<OptionType>,
->(
- data: OptionType,
- overrides?: OptionProps<OptionType, IsMulti, GroupType>,
-): OptionProps<OptionType, IsMulti, GroupType> {
- return {
- ...overrides,
- data,
- } as OptionProps<OptionType, IsMulti, GroupType>;
-}
-
-export function mockReactSelectInputProps(): InputProps {
- return {} as InputProps;
-}
-
-export function mockReactSelectControlProps<
- OptionType = unknown,
- IsMulti extends boolean = boolean,
- GroupType extends GroupBase<OptionType> = GroupBase<OptionType>,
->(): ControlProps<OptionType, IsMulti, GroupType> {
- return {} as ControlProps<OptionType, IsMulti, GroupType>;
-}
-
-export function mockReactSelectClearIndicatorProps<
- OptionType = unknown,
- IsMulti extends boolean = boolean,
- GroupType extends GroupBase<OptionType> = GroupBase<OptionType>,
->(_option: OptionType): ClearIndicatorProps<OptionType, IsMulti, GroupType> {
- return { getStyles: () => {} } as unknown as ClearIndicatorProps<OptionType, IsMulti, GroupType>;
-}
-
-export function mockReactSelectDropdownIndicatorProps<
- OptionType = unknown,
- IsMulti extends boolean = boolean,
- GroupType extends GroupBase<OptionType> = GroupBase<OptionType>,
->(_option: OptionType): DropdownIndicatorProps<OptionType, IsMulti, GroupType> {
- return {} as DropdownIndicatorProps<OptionType, IsMulti, GroupType>;
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/security-hotspots.ts b/server/sonar-web/src/main/js/helpers/mocks/security-hotspots.ts
deleted file mode 100644
index 4c04331dc70..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/security-hotspots.ts
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { HotspotRatingEnum } from '~design-system';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { Standards } from '../../types/security';
-import {
- Hotspot,
- HotspotComment,
- HotspotComponent,
- HotspotResolution,
- HotspotRule,
- HotspotStatus,
- RawHotspot,
- ReviewHistoryElement,
- ReviewHistoryType,
-} from '../../types/security-hotspots';
-import { mockFlowLocation, mockUser } from '../testMocks';
-
-export function mockRawHotspot(overrides: Partial<RawHotspot> = {}): RawHotspot {
- return {
- key: '01fc972e-2a3c-433e-bcae-0bd7f88f5123',
- component: 'com.github.kevinsawicki:http-request:com.github.kevinsawicki.http.HttpRequest',
- project: 'com.github.kevinsawicki:http-request',
- rule: 'checkstyle:com.puppycrawl.tools.checkstyle.checks.coding.MagicNumberCheck',
- status: HotspotStatus.TO_REVIEW,
- resolution: undefined,
- securityCategory: 'command-injection',
- vulnerabilityProbability: HotspotRatingEnum.HIGH,
- message: "'3' is a magic number.",
- line: 81,
- author: 'Developer 1',
- creationDate: '2013-05-13T17:55:39+0200',
- updateDate: '2013-05-13T17:55:39+0200',
- ...overrides,
- };
-}
-
-export function mockHotspot(overrides?: Partial<Hotspot>): Hotspot {
- const assigneeUser = mockUser({ login: 'assignee' });
- const authorUser = mockUser({ login: 'author' });
- return {
- assignee: 'assignee',
- assigneeUser,
- author: 'author',
- authorUser,
- canChangeStatus: true,
- changelog: [],
- comment: [],
- component: mockHotspotComponent({ qualifier: ComponentQualifier.File }),
- creationDate: '2013-05-13T17:55:41+0200',
- flows: [{ locations: [mockFlowLocation()] }],
- key: '01fc972e-2a3c-433e-bcae-0bd7f88f5123',
- line: 6,
- message: "'3' is a magic number.",
- project: mockHotspotComponent({ qualifier: ComponentQualifier.Project }),
- resolution: HotspotResolution.FIXED,
- rule: mockHotspotRule(),
- status: HotspotStatus.REVIEWED,
- textRange: {
- startLine: 6,
- endLine: 6,
- startOffset: 3,
- endOffset: 9,
- },
- updateDate: '2013-05-13T17:55:42+0200',
- users: [assigneeUser, authorUser],
- ...overrides,
- };
-}
-
-export function mockHotspotComponent(overrides?: Partial<HotspotComponent>): HotspotComponent {
- return {
- key: 'hotspot-component',
- name: 'Hotspot Component',
- longName: 'Hotspot component long name',
- qualifier: ComponentQualifier.File,
- path: 'path/to/component',
- ...overrides,
- };
-}
-
-export function mockHotspotComment(overrides?: Partial<HotspotComment>): HotspotComment {
- return {
- key: 'comment-1',
- createdAt: '2018-09-10',
- htmlText: '<strong>TEST</strong>',
- markdown: '*TEST*',
- updatable: false,
- login: 'dude-2',
- user: mockUser({ login: 'dude-2' }),
- ...overrides,
- };
-}
-
-export function mockHotspotRule(overrides?: Partial<HotspotRule>): HotspotRule {
- return {
- key: 'squid:S2077',
- name: 'That rule',
- vulnerabilityProbability: HotspotRatingEnum.HIGH,
- securityCategory: 'sql-injection',
- ...overrides,
- };
-}
-
-export function mockHotspotReviewHistoryElement(
- overrides?: Partial<ReviewHistoryElement>,
-): ReviewHistoryElement {
- return {
- date: '2019-09-13T17:55:42+0200',
- type: ReviewHistoryType.Creation,
- user: mockUser(),
- ...overrides,
- };
-}
-
-export function mockStandards(): Standards {
- return {
- cwe: {
- unknown: {
- title: 'No CWE associated',
- },
- '1004': {
- title: "Sensitive Cookie Without 'HttpOnly' Flag",
- },
- },
- owaspTop10: {
- a1: {
- title: 'Injection',
- },
- a2: {
- title: 'Broken Authentication',
- },
- a3: {
- title: 'Sensitive Data Exposure',
- },
- },
- 'owaspTop10-2021': {
- a1: {
- title: 'Injection',
- },
- a2: {
- title: 'Broken Authentication',
- },
- a3: {
- title: 'Sensitive Data Exposure',
- },
- },
- sonarsourceSecurity: {
- 'buffer-overflow': {
- title: 'Buffer Overflow',
- },
- 'sql-injection': {
- title: 'SQL Injection',
- },
- rce: {
- title: 'Code Injection (RCE)',
- },
- },
- 'pciDss-3.2': {
- '1': {
- title: ' Install and maintain a firewall configuration to protect cardholder data',
- },
- },
- 'pciDss-4.0': {
- '2': {
- title: 'This is useless...',
- },
- },
- 'owaspAsvs-4.0': {
- '1': {
- title: 'New OWASP ASVS cat 1',
- },
- },
- 'stig-ASD_V5R3': {
- 'V-123': {
- title: 'STIG requirement 123',
- },
- },
- casa: {
- '1': {
- title: 'New CASA cat 1',
- },
- },
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/settings.ts b/server/sonar-web/src/main/js/helpers/mocks/settings.ts
deleted file mode 100644
index fda49343e79..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/settings.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- ExtendedSettingDefinition,
- Setting,
- SettingFieldDefinition,
- SettingType,
- SettingValue,
- SettingWithCategory,
-} from '../../types/settings';
-
-export function mockDefinition(
- overrides: Partial<ExtendedSettingDefinition> = {},
-): ExtendedSettingDefinition {
- return {
- key: 'foo',
- category: 'foo category',
- fields: [],
- options: [],
- subCategory: 'foo subCat',
- ...overrides,
- };
-}
-
-export function mockSettingFieldDefinition(
- overrides: Partial<SettingFieldDefinition> = {},
-): SettingFieldDefinition {
- return { key: 'name', name: 'Name', options: [], ...overrides };
-}
-
-export function mockSetting(overrides: Partial<Setting> = {}): Setting {
- return {
- key: 'foo',
- value: '42',
- hasValue: true,
- inherited: true,
- definition: {
- key: 'foo',
- name: 'Foo setting',
- description: 'When Foo then Bar',
- type: SettingType.INTEGER,
- options: [],
- },
- ...overrides,
- };
-}
-
-export function mockSettingValue(overrides: Partial<SettingValue> = {}) {
- return {
- key: 'test',
- ...overrides,
- };
-}
-
-export function mockSettingWithCategory(
- overrides: Partial<SettingWithCategory> = {},
-): SettingWithCategory {
- return {
- key: 'foo',
- value: '42',
- hasValue: true,
- inherited: true,
- definition: {
- key: 'foo',
- name: 'Foo setting',
- description: 'When Foo then Bar',
- type: SettingType.INTEGER,
- options: [],
- category: 'general',
- fields: [],
- subCategory: 'email',
- },
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/sources.ts b/server/sonar-web/src/main/js/helpers/mocks/sources.ts
deleted file mode 100644
index 04c8e492dd9..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/sources.ts
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import {
- DuplicatedFile,
- Duplication,
- DuplicationBlock,
- SnippetsByComponent,
- SourceLine,
- SourceViewerFile,
-} from '../../types/types';
-
-export function mockSourceViewerFile(
- name = 'foo/bar.ts',
- project = 'project',
- override?: Partial<SourceViewerFile>,
-): SourceViewerFile {
- return {
- measures: {
- coverage: '85.2',
- duplicationDensity: '1.0',
- issues: '12',
- lines: '56',
- },
- project,
- projectName: 'MyProject',
- q: ComponentQualifier.File,
- uuid: 'foo-bar',
- key: `${project}:${name}`,
- path: name,
- name,
- longName: name,
- fav: false,
- canMarkAsFavorite: true,
- ...override,
- };
-}
-
-export function mockSourceLine(overrides: Partial<SourceLine> = {}): SourceLine {
- return {
- line: 16,
- code: '<span class="k">import</span> java.util.<span class="sym-9 sym">ArrayList</span>;',
- coverageStatus: 'covered',
- coveredConditions: 2,
- scmRevision: '80f564becc0c0a1c9abaa006eca83a4fd278c3f0',
- scmAuthor: 'simon.brandhof@sonarsource.com',
- scmDate: '2018-12-11T10:48:39+0100',
- duplicated: false,
- isNew: true,
- ...overrides,
- };
-}
-
-export function mockSnippetsByComponent(
- file = 'main.js',
- project = 'project',
- lines: number[] = [16],
-): SnippetsByComponent {
- const sources = lines.reduce((lines: { [key: number]: SourceLine }, line) => {
- lines[line] = mockSourceLine({ line });
- return lines;
- }, {});
- return {
- component: mockSourceViewerFile(file, project),
- sources,
- };
-}
-
-export function mockDuplicatedFile(overrides: Partial<DuplicatedFile> = {}): DuplicatedFile {
- return {
- key: 'file1.java',
- name: overrides.key || 'file1.java',
- project: 'foo',
- projectName: 'Foo',
- ...overrides,
- };
-}
-
-export function mockDuplication(overrides: Partial<Duplication> = {}): Duplication {
- return {
- blocks: [mockDuplicationBlock()],
- ...overrides,
- };
-}
-
-export function mockDuplicationBlock(overrides: Partial<DuplicationBlock> = {}): DuplicationBlock {
- return {
- from: 12,
- size: 5,
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/system-upgrades.ts b/server/sonar-web/src/main/js/helpers/mocks/system-upgrades.ts
deleted file mode 100644
index 80466d15fce..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/system-upgrades.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ProductNameForUpgrade, SystemUpgrade } from '../../types/system';
-
-export const mockSystemUpgrade = (override: Partial<SystemUpgrade> = {}) =>
- ({
- changeLogUrl: 'changelogurl',
- description: 'Version 5.6.7 description',
- downloadUrl: 'downloadurl',
- product: ProductNameForUpgrade.SonarQubeServer,
- releaseDate: '2017-03-01',
- version: '5.6.7',
- ...override,
- }) as SystemUpgrade;
diff --git a/server/sonar-web/src/main/js/helpers/mocks/system.ts b/server/sonar-web/src/main/js/helpers/mocks/system.ts
deleted file mode 100644
index df2ee9abf55..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/system.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { AuthMethod, EmailConfiguration } from '../../types/system';
-
-export function mockEmailConfiguration(
- authMethod: AuthMethod,
- overrides: Partial<EmailConfiguration> = {},
-): EmailConfiguration {
- const base: Partial<EmailConfiguration> = {
- fromAddress: 'from_address',
- fromName: 'from_name',
- host: 'host',
- id: '1',
- port: 'port',
- subjectPrefix: 'subject_prefix',
- securityProtocol: 'SSLTLS',
- username: 'username',
- };
-
- const mock =
- authMethod === AuthMethod.Basic
- ? {
- ...base,
- authMethod: AuthMethod.Basic,
- basicPassword: undefined,
- isBasicPasswordSet: true,
- }
- : {
- ...base,
- authMethod: AuthMethod.OAuth,
- isOauthClientIdSet: true,
- isOauthClientSecretSet: true,
- oauthAuthenticationHost: 'oauth_auth_host',
- oauthClientId: undefined,
- oauthClientSecret: undefined,
- oauthTenant: 'oauth_tenant',
- };
-
- return { ...mock, ...overrides } as EmailConfiguration;
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/tasks.ts b/server/sonar-web/src/main/js/helpers/mocks/tasks.ts
deleted file mode 100644
index 72a4d7b5b4c..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/tasks.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { uniqueId } from 'lodash';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { Task, TaskStatuses, TaskTypes, TaskWarning } from '../../types/tasks';
-
-export function mockTask(overrides: Partial<Task> = {}): Task {
- return {
- analysisId: 'x123',
- componentKey: 'foo',
- componentName: 'Foo',
- componentQualifier: ComponentQualifier.Project,
- id: 'AXR8jg_0mF2ZsYr8Wzs2',
- status: TaskStatuses.Pending,
- submittedAt: '2020-09-11T11:45:35+0200',
- type: TaskTypes.Report,
- ...overrides,
- };
-}
-
-export function mockTaskWarning(overrides: Partial<TaskWarning> = {}): TaskWarning {
- return {
- key: uniqueId('foo'),
- message: 'Lorem ipsum',
- dismissable: false,
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/token.ts b/server/sonar-web/src/main/js/helpers/mocks/token.ts
deleted file mode 100644
index 75bfb6d9d07..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/token.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { TokenType, UserToken } from '../../types/token';
-
-export function mockUserToken(overrides: Partial<UserToken> = {}): UserToken {
- return {
- name: 'Token name',
- createdAt: '2019-06-14T09:45:52+0200',
- type: TokenType.User,
- isExpired: false,
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/users.ts b/server/sonar-web/src/main/js/helpers/mocks/users.ts
deleted file mode 100644
index 5e227bb778f..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/users.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { UserBase } from '../../types/users';
-
-export function mockUserBase(overrides: Partial<UserBase> = {}): UserBase {
- return {
- login: 'userlogin',
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/webapi.ts b/server/sonar-web/src/main/js/helpers/mocks/webapi.ts
deleted file mode 100644
index a31b434d10b..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/webapi.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { WebApi } from '../../types/types';
-
-export function mockAction(overrides: Partial<WebApi.Action> = {}): WebApi.Action {
- return {
- key: 'action1',
- internal: false,
- changelog: [],
- description: 'Action 1',
- hasResponseExample: false,
- post: false,
- ...overrides,
- };
-}
-
-export function mockDomain(overrides: Partial<WebApi.Domain> = {}): WebApi.Domain {
- return {
- actions: [mockAction()],
- description: 'foo',
- path: 'foo/bar',
- since: '1.0',
- ...overrides,
- };
-}
-
-export function mockParam(overrides: Partial<WebApi.Param> = {}): WebApi.Param {
- return {
- key: 'p1',
- description: 'parameter 1',
- internal: false,
- required: false,
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/mocks/webhook.ts b/server/sonar-web/src/main/js/helpers/mocks/webhook.ts
deleted file mode 100644
index db0125258cc..00000000000
--- a/server/sonar-web/src/main/js/helpers/mocks/webhook.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { WebhookDelivery, WebhookResponse } from '../../types/webhook';
-import { HttpStatus } from '../request';
-
-export function mockWebhookDelivery(overrides: Partial<WebhookDelivery> = {}): WebhookDelivery {
- return {
- at: '2019-06-14T09:45:52+0200',
- durationMs: 20,
- httpStatus: HttpStatus.Ok,
- id: '1',
- success: true,
- ...overrides,
- };
-}
-
-export function mockWebhook(overrides: Partial<WebhookResponse> = {}): WebhookResponse {
- return {
- hasSecret: false,
- key: 'webhook1',
- name: 'name',
- url: 'http://example.com',
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/helpers/new-code-definition.ts b/server/sonar-web/src/main/js/helpers/new-code-definition.ts
deleted file mode 100644
index d3fd64cc022..00000000000
--- a/server/sonar-web/src/main/js/helpers/new-code-definition.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { NewCodeDefinition, NewCodeDefinitionType } from '../types/new-code-definition';
-
-export const DEFAULT_NEW_CODE_DEFINITION_TYPE: NewCodeDefinitionType =
- NewCodeDefinitionType.PreviousVersion;
-export const NUMBER_OF_DAYS_MIN_VALUE = 1;
-export const NUMBER_OF_DAYS_MAX_VALUE = 90;
-export const NUMBER_OF_DAYS_DEFAULT_VALUE = 30;
-
-export function isNewCodeDefinitionCompliant(newCodePeriod: NewCodeDefinition) {
- switch (newCodePeriod.type) {
- case NewCodeDefinitionType.NumberOfDays:
- if (!newCodePeriod.value) {
- return false;
- }
- return (
- /^\d+$/.test(newCodePeriod.value) &&
- NUMBER_OF_DAYS_MIN_VALUE <= +newCodePeriod.value &&
- +newCodePeriod.value <= NUMBER_OF_DAYS_MAX_VALUE
- );
- case NewCodeDefinitionType.SpecificAnalysis:
- return false;
- default:
- return true;
- }
-}
-
-export function getNumberOfDaysDefaultValue(
- globalNewCodeDefinition?: NewCodeDefinition | null,
- inheritedNewCodeDefinition?: NewCodeDefinition | null,
-) {
- if (
- inheritedNewCodeDefinition &&
- isNewCodeDefinitionCompliant(inheritedNewCodeDefinition) &&
- inheritedNewCodeDefinition.type === NewCodeDefinitionType.NumberOfDays &&
- inheritedNewCodeDefinition.value
- ) {
- return inheritedNewCodeDefinition.value;
- }
-
- if (
- globalNewCodeDefinition &&
- isNewCodeDefinitionCompliant(globalNewCodeDefinition) &&
- globalNewCodeDefinition.type === NewCodeDefinitionType.NumberOfDays &&
- globalNewCodeDefinition.value
- ) {
- return globalNewCodeDefinition.value;
- }
-
- return NUMBER_OF_DAYS_DEFAULT_VALUE.toString();
-}
diff --git a/server/sonar-web/src/main/js/helpers/new-code-period.ts b/server/sonar-web/src/main/js/helpers/new-code-period.ts
deleted file mode 100644
index 98ba6f58e4b..00000000000
--- a/server/sonar-web/src/main/js/helpers/new-code-period.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ApplicationPeriod } from '../types/application';
-import { NewCodeDefinitionType } from '../types/new-code-definition';
-import { Period } from '../types/types';
-import { parseDate } from './dates';
-import { translate, translateWithParameters } from './l10n';
-
-export function getNewCodePeriodDate(period?: { date?: string }): Date | undefined {
- return period?.date ? parseDate(period.date) : undefined;
-}
-
-export function getNewCodePeriodLabel(
- period: Period | undefined,
- dateFormatter: (date: string) => string,
-) {
- if (!period) {
- return undefined;
- }
-
- let parameter = period.modeParam || period.parameter || '';
-
- switch (period.mode) {
- case NewCodeDefinitionType.SpecificAnalysis:
- parameter = dateFormatter(period.date);
- break;
- case NewCodeDefinitionType.PreviousVersion:
- parameter = parameter || dateFormatter(period.date);
- break;
- /*
- * Handle legacy period modes, that predate MMF-1579
- */
- case 'previous_version':
- if (!parameter) {
- return translate('overview.period.previous_version_only_date');
- }
- break;
- case 'date':
- parameter = parameter && dateFormatter(parameter);
- break;
- case 'manual_baseline':
- parameter = parameter || dateFormatter(period.date);
- break;
- default: // No change in the parameter
- }
-
- return translateWithParameters(`overview.period.${period.mode.toLowerCase()}`, parameter);
-}
-
-export function isApplicationNewCodePeriod(
- period: Period | ApplicationPeriod,
-): period is ApplicationPeriod {
- return (period as ApplicationPeriod).project !== undefined;
-}
diff --git a/server/sonar-web/src/main/js/helpers/path.ts b/server/sonar-web/src/main/js/helpers/path.ts
deleted file mode 100644
index 4af5716726c..00000000000
--- a/server/sonar-web/src/main/js/helpers/path.ts
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export function collapsePath(path: string, limit = 30): string {
- if (typeof path !== 'string') {
- return '';
- }
-
- const tokens = path.split('/');
-
- if (tokens.length <= 2) {
- return path;
- }
-
- const head = tokens[0];
- const tail = tokens[tokens.length - 1];
- const middle = tokens.slice(1, -1);
- let cut = false;
-
- while (middle.join().length > limit && middle.length > 0) {
- middle.shift();
- cut = true;
- }
-
- const body = [head, ...(cut ? ['...'] : []), ...middle, tail];
- return body.join('/');
-}
-
-/**
- * Return a collapsed path without a file name
- * @example
- * // returns 'src/.../js/components/navigator/app/models/'
- * collapsedDirFromPath('src/main/js/components/navigator/app/models/state.js')
- */
-export function collapsedDirFromPath(path: string | null): string | null {
- const limit = 25;
- if (typeof path === 'string') {
- const tokens = path.split('/').slice(0, -1);
- if (tokens.length > 2) {
- const head = tokens[0];
- const tail = tokens[tokens.length - 1];
- const middle = tokens.slice(1, -1);
-
- let cut = false;
- while (middle.join().length > limit && middle.length > 0) {
- middle.shift();
- cut = true;
- }
- const body = [head, ...(cut ? ['...'] : []), ...middle, tail];
- return body.join('/') + '/';
- }
- return tokens.join('/') + '/';
- }
- return null;
-}
-
-/**
- * Return a file name for a given file path
- * * @example
- * // returns 'state.js'
- * collapsedDirFromPath('src/main/js/components/navigator/app/models/state.js')
- */
-export function fileFromPath(path: string | null): string | null {
- if (typeof path === 'string') {
- const tokens = path.split('/');
- return tokens[tokens.length - 1];
- }
- return null;
-}
-
-export function splitPath(path: string) {
- const tokens = path.split('/');
- return {
- head: tokens.slice(0, -1).join('/'),
- tail: tokens[tokens.length - 1],
- };
-}
-
-export function cutLongWords(str: string, limit = 30) {
- return str
- .split(' ')
- .map((word) => (word.length > limit ? word.substr(0, limit) + '...' : word))
- .join(' ');
-}
-
-export function limitComponentName(str: string, limit = 30): string {
- if (typeof str === 'string') {
- return str.length > limit ? str.substr(0, limit) + '...' : str;
- }
- return '';
-}
diff --git a/server/sonar-web/src/main/js/helpers/permissions.ts b/server/sonar-web/src/main/js/helpers/permissions.ts
deleted file mode 100644
index 212c7c655a8..00000000000
--- a/server/sonar-web/src/main/js/helpers/permissions.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Permissions } from '../types/permissions';
-import { Dict, PermissionDefinition, PermissionDefinitionGroup } from '../types/types';
-import { translate } from './l10n';
-
-export const PERMISSIONS_ORDER_FOR_PROJECT_TEMPLATE = [
- Permissions.Browse,
- Permissions.CodeViewer,
- Permissions.IssueAdmin,
- Permissions.SecurityHotspotAdmin,
- Permissions.Admin,
- Permissions.Scan,
-];
-
-export const PERMISSIONS_ORDER_GLOBAL = [
- Permissions.Admin,
- {
- category: 'administer',
- permissions: [Permissions.QualityGateAdmin, Permissions.QualityProfileAdmin],
- },
- Permissions.Scan,
- {
- category: 'creator',
- permissions: [
- Permissions.ProjectCreation,
- Permissions.ApplicationCreation,
- Permissions.PortfolioCreation,
- ],
- },
-];
-
-export const PERMISSIONS_ORDER_FOR_VIEW = [Permissions.Browse, Permissions.Admin];
-
-export const PERMISSIONS_ORDER_BY_QUALIFIER: Dict<string[]> = {
- TRK: PERMISSIONS_ORDER_FOR_PROJECT_TEMPLATE,
- VW: PERMISSIONS_ORDER_FOR_VIEW,
- SVW: PERMISSIONS_ORDER_FOR_VIEW,
- APP: PERMISSIONS_ORDER_FOR_VIEW,
-};
-
-function convertToPermissionDefinition(permission: string, l10nPrefix: string) {
- const name = translate(`${l10nPrefix}.${permission}`);
- const description = translate(`${l10nPrefix}.${permission}.desc`);
-
- return {
- key: permission,
- name,
- description,
- };
-}
-
-export function filterPermissions(
- permissions: Array<Permissions | { category: string; permissions: Permissions[] }>,
- hasApplicationsEnabled: boolean,
- hasPortfoliosEnabled: boolean,
-) {
- return permissions.map((permission) => {
- if (typeof permission === 'object' && permission.category === 'creator') {
- return {
- ...permission,
- permissions: permission.permissions.filter((p) => {
- return (
- p === Permissions.ProjectCreation ||
- (p === Permissions.PortfolioCreation && hasPortfoliosEnabled) ||
- (p === Permissions.ApplicationCreation && hasApplicationsEnabled)
- );
- }),
- };
- }
- return permission;
- });
-}
-
-export function convertToPermissionDefinitions(
- permissions: Array<string | { category: string; permissions: string[] }>,
- l10nPrefix: string,
-): Array<PermissionDefinition | PermissionDefinitionGroup> {
- return permissions.map((permission) => {
- if (typeof permission === 'object') {
- return {
- category: permission.category,
- permissions: permission.permissions.map((permission) =>
- convertToPermissionDefinition(permission, l10nPrefix),
- ),
- };
- }
- return convertToPermissionDefinition(permission, l10nPrefix);
- });
-}
-
-export function isPermissionDefinitionGroup(
- permission?: PermissionDefinition | PermissionDefinitionGroup,
-): permission is PermissionDefinitionGroup {
- return Boolean(permission && (permission as PermissionDefinitionGroup).category);
-}
diff --git a/server/sonar-web/src/main/js/helpers/preferences.ts b/server/sonar-web/src/main/js/helpers/preferences.ts
deleted file mode 100644
index 3cbefa2258d..00000000000
--- a/server/sonar-web/src/main/js/helpers/preferences.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { get, save } from './storage';
-
-export const KEYBOARD_SHORTCUTS_ENABLED = 'keyboard_shortcuts_enabled';
-
-export function getKeyboardShortcutEnabled() {
- // true by default, so null =~= true
- return get(`sonarqube.preferences.${KEYBOARD_SHORTCUTS_ENABLED}`) !== 'false';
-}
-
-export function setKeyboardShortcutEnabled(value: boolean) {
- save(`sonarqube.preferences.${KEYBOARD_SHORTCUTS_ENABLED}`, `${value}`);
-}
diff --git a/server/sonar-web/src/main/js/helpers/projectLinks.ts b/server/sonar-web/src/main/js/helpers/projectLinks.ts
deleted file mode 100644
index 6ab7547cc1c..00000000000
--- a/server/sonar-web/src/main/js/helpers/projectLinks.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { partition, sortBy } from 'lodash';
-import { translate } from '../helpers/l10n';
-import { ProjectLink } from '../types/types';
-
-const PROVIDED_TYPES = ['homepage', 'ci', 'issue', 'scm', 'scm_dev'];
-type NameAndType = Pick<ProjectLink, 'name' | 'type'>;
-
-export function isProvided(link: Pick<ProjectLink, 'type'>) {
- return PROVIDED_TYPES.includes(link.type);
-}
-
-export function orderLinks<T extends NameAndType>(links: T[]) {
- const [provided, unknown] = partition<T>(links, isProvided);
- return [
- ...sortBy(provided, (link) => PROVIDED_TYPES.indexOf(link.type)),
- ...sortBy(unknown, (link) => link.name?.toLowerCase()),
- ];
-}
-
-export function getLinkName(link: NameAndType) {
- return isProvided(link) ? translate('project_links', link.type) : link.name;
-}
diff --git a/server/sonar-web/src/main/js/helpers/projects.ts b/server/sonar-web/src/main/js/helpers/projects.ts
deleted file mode 100644
index 0ef593b2931..00000000000
--- a/server/sonar-web/src/main/js/helpers/projects.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ProjectKeyValidationResult } from '../types/component';
-import { PROJECT_KEY_MAX_LEN } from './constants';
-
-// This is the regex used on the backend:
-// [\p{Alnum}\-_.:]*[\p{Alpha}\-_.:]+[\p{Alnum}\-_.:]*
-// See sonar-core/src/main/java/org/sonar/core/component/ComponentKeys.java
-export const PROJECT_KEY_REGEX = /^[\w\-.:]*[a-z\-_.:]+[\w\-.:]*$/i;
-export const PROJECT_KEY_INVALID_CHARACTERS = /[^\w\-:.]+/gi;
-
-export function validateProjectKey(projectKey: string): ProjectKeyValidationResult {
- if (projectKey.length === 0) {
- return ProjectKeyValidationResult.Empty;
- } else if (projectKey.length > PROJECT_KEY_MAX_LEN) {
- return ProjectKeyValidationResult.TooLong;
- } else if (PROJECT_KEY_REGEX.test(projectKey)) {
- return ProjectKeyValidationResult.Valid;
- } else if (/^[0-9]+$/.test(projectKey)) {
- return ProjectKeyValidationResult.OnlyDigits;
- }
- return ProjectKeyValidationResult.InvalidChar;
-}
diff --git a/server/sonar-web/src/main/js/helpers/qualityGates.ts b/server/sonar-web/src/main/js/helpers/qualityGates.ts
deleted file mode 100644
index e402d31e81a..00000000000
--- a/server/sonar-web/src/main/js/helpers/qualityGates.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import {
- QualityGateApplicationStatusChildProject,
- QualityGateProjectStatus,
- QualityGateStatusCondition,
-} from '../types/quality-gates';
-import { Metric } from '../types/types';
-import { translate } from './l10n';
-
-export function getOperatorLabel(op: string, metric: Metric) {
- return metric.type === MetricType.Rating
- ? translate('quality_gates.operator', op, 'rating')
- : translate('quality_gates.operator', op);
-}
-
-export function extractStatusConditionsFromProjectStatus(
- projectStatus: QualityGateProjectStatus,
-): QualityGateStatusCondition[] {
- const { conditions } = projectStatus;
- return conditions
- ? conditions.map((c) => ({
- actual: c.actualValue,
- error: c.errorThreshold,
- level: c.status,
- metric: c.metricKey as MetricKey,
- op: c.comparator,
- period: c.periodIndex,
- }))
- : [];
-}
-
-export function extractStatusConditionsFromApplicationStatusChildProject(
- projectStatus: QualityGateApplicationStatusChildProject,
-): QualityGateStatusCondition[] {
- const { conditions } = projectStatus;
- return conditions
- ? conditions.map((c) => ({
- actual: c.value,
- error: c.errorThreshold,
- level: c.status,
- metric: c.metric as MetricKey,
- op: c.comparator,
- period: c.periodIndex,
- }))
- : [];
-}
diff --git a/server/sonar-web/src/main/js/helpers/query.ts b/server/sonar-web/src/main/js/helpers/query.ts
deleted file mode 100644
index b57b627d1b5..00000000000
--- a/server/sonar-web/src/main/js/helpers/query.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { isEqual, isNil, omitBy } from 'lodash';
-import { RawQuery } from '~sonar-aligned/types/router';
-import { isValidDate, parseDate, toISO8601WithOffsetString, toShortISO8601String } from './dates';
-
-export function queriesEqual(a: RawQuery, b: RawQuery): boolean {
- const keysA = Object.keys(a);
- const keysB = Object.keys(b);
-
- if (keysA.length !== keysB.length) {
- return false;
- }
-
- return keysA.every((key) =>
- isEqual(
- Array.isArray(a[key]) ? a[key].sort() : a[key],
- Array.isArray(b[key]) ? b[key].sort() : b[key],
- ),
- );
-}
-
-export function cleanQuery(query: RawQuery): RawQuery {
- return omitBy(query, isNil);
-}
-
-export function parseAsBoolean(value: string | undefined, defaultValue = true): boolean {
- if (value === 'false') {
- return false;
- }
- if (value === 'true') {
- return true;
- }
- return defaultValue;
-}
-
-export function parseAsOptionalBoolean(value: string | undefined): boolean | undefined {
- if (value === 'true') {
- return true;
- } else if (value === 'false') {
- return false;
- }
- return undefined;
-}
-
-export function parseAsDate(value?: string): Date | undefined {
- if (value) {
- /**
- * When the time zone offset is absent, date-only forms are interpreted as a UTC time
- * and date-time forms are interpreted as local time.
- * To ensure we always parse dates as date-time, we first try and add the time to the date,
- * and if it fails, we try and parse the date as is.
- * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
- */
- let date = parseDate(value + ' 00:00:00');
- if (isValidDate(date)) {
- return date;
- }
- date = parseDate(value);
- if (isValidDate(date)) {
- return date;
- }
- }
- return undefined;
-}
-
-export function parseAsString<T extends string>(value: string | undefined): T {
- return (value ?? '') as T;
-}
-
-export function parseAsOptionalString(value: string | undefined): string | undefined {
- return value || undefined;
-}
-
-export function parseAsArray<T>(value: string | undefined, itemParser: (x: string) => T): T[] {
- return value ? value.split(',').map(itemParser) : [];
-}
-
-export function parseAsOptionalArray<T>(
- value: string | undefined,
- itemParser: (x: string) => T,
-): T[] | undefined {
- return value ? parseAsArray(value, itemParser) : undefined;
-}
-
-export function serializeDate(
- value?: Date,
- serializer = toISO8601WithOffsetString,
-): string | undefined {
- if (value != null) {
- return serializer(value);
- }
- return undefined;
-}
-
-export function serializeDateShort(value: Date | undefined): string | undefined {
- return serializeDate(value, toShortISO8601String);
-}
-
-export function serializeString(value: string | undefined): string | undefined {
- return value || undefined;
-}
-
-export function serializeStringArray(value: string[] | undefined[]): string | undefined {
- return value && value.length ? value.join() : undefined;
-}
-
-export function serializeOptionalBoolean(value: boolean | undefined): string | undefined {
- if (value === true) {
- return 'true';
- } else if (value === false) {
- return 'false';
- }
- return undefined;
-}
diff --git a/server/sonar-web/src/main/js/helpers/ratings.ts b/server/sonar-web/src/main/js/helpers/ratings.ts
deleted file mode 100644
index 7fbd854b1b8..00000000000
--- a/server/sonar-web/src/main/js/helpers/ratings.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-const RATING_GRID_SIZE = 4;
-export const PERCENT_MULTIPLIER = 100;
-export const DIFF_METRIC_PREFIX_LENGTH = 4;
-export const GRID_INDEX_OFFSET = 2; // Rating of 2 should get index 0 (threshold between 1 and 2)
-
-function checkNumberRating(coverageRating: number): void {
- if (!(typeof coverageRating === 'number' && coverageRating > 0 && coverageRating < 6)) {
- throw new Error(`Unknown number rating: "${coverageRating}"`);
- }
-}
-
-export function getCoverageRatingLabel(rating: number): string {
- checkNumberRating(rating);
- const mapping = ['≥ 80%', '70% - 80%', '50% - 70%', '30% - 50%', '< 30%'];
- return mapping[rating - 1];
-}
-
-export function getCoverageRatingAverageValue(rating: number): number {
- checkNumberRating(rating);
- const mapping = [90, 75, 60, 40, 15];
- return mapping[rating - 1];
-}
-
-export function getDuplicationsRatingLabel(rating: number): string {
- checkNumberRating(rating);
- const mapping = ['< 3%', '3% - 5%', '5% - 10%', '10% - 20%', '> 20%'];
- return mapping[rating - 1];
-}
-
-export function getSizeRatingLabel(rating: number): string {
- checkNumberRating(rating);
- const mapping = ['< 1k', '1k - 10k', '10k - 100k', '100k - 500k', '> 500k'];
- return mapping[rating - 1];
-}
-
-export function getSizeRatingAverageValue(rating: number): number {
- checkNumberRating(rating);
- const mapping = [500, 5000, 50000, 250000, 750000];
- return mapping[rating - 1];
-}
-
-export const getMaintainabilityGrid = (ratingGridSetting: string) => {
- const numbers = ratingGridSetting
- .split(',')
- .map((s) => parseFloat(s))
- .filter((n) => !isNaN(n));
-
- return numbers.length === RATING_GRID_SIZE ? numbers : [0, 0, 0, 0];
-};
-
-const DUPLICATION_RATINGS: ['A', 'B', 'C', 'D', 'E', 'F'] = ['A', 'B', 'C', 'D', 'E', 'F'];
-export function duplicationValueToRating(val: number) {
- return DUPLICATION_RATINGS[val - 1];
-}
diff --git a/server/sonar-web/src/main/js/helpers/react-query.ts b/server/sonar-web/src/main/js/helpers/react-query.ts
deleted file mode 100644
index 7b96eb75eff..00000000000
--- a/server/sonar-web/src/main/js/helpers/react-query.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { UseQueryResult } from '@tanstack/react-query';
-import { Paging } from '../types/types';
-
-const notUndefined = <T>(x: T | undefined): x is T => x !== undefined;
-
-export const mapReactQueryResult = <T, R>(
- res: UseQueryResult<T>,
- mapper: (data: T) => R,
-): UseQueryResult<R> => {
- return {
- ...res,
- refetch: (...args: Parameters<typeof res.refetch>) =>
- res.refetch(...args).then((val) => mapReactQueryResult(val, mapper)),
- data: notUndefined(res.data) ? mapper(res.data) : res.data,
- } as UseQueryResult<R>;
-};
-
-export const getNextPageParam = <T extends { page: Paging }>(params: T) =>
- params.page.total <= params.page.pageIndex * params.page.pageSize
- ? undefined
- : params.page.pageIndex + 1;
-
-export const getPreviousPageParam = <T extends { page: Paging }>(params: T) =>
- params.page.pageIndex === 1 ? undefined : params.page.pageIndex - 1;
-
-export const getNextPagingParam = <T extends { paging: Paging }>(params: T) =>
- params.paging.total <= params.paging.pageIndex * params.paging.pageSize
- ? undefined
- : params.paging.pageIndex + 1;
-
-export const getPreviousPagingParam = <T extends { paging: Paging }>(params: T) =>
- params.paging.pageIndex === 1 ? undefined : params.paging.pageIndex - 1;
diff --git a/server/sonar-web/src/main/js/helpers/request.ts b/server/sonar-web/src/main/js/helpers/request.ts
deleted file mode 100644
index fbfa9facbb9..00000000000
--- a/server/sonar-web/src/main/js/helpers/request.ts
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import axios, { AxiosResponse } from 'axios';
-import { isNil, omitBy } from 'lodash';
-import { Dict } from '../types/types';
-import { getCookie } from './cookies';
-import handleRequiredAuthentication from './handleRequiredAuthentication';
-import { translate } from './l10n';
-import { stringify } from './stringify-queryparams';
-import { getBaseUrl } from './system';
-
-const FAST_RETRY_TIMEOUT = 500;
-const SLOW_RETRY_TIMEOUT = 3000;
-
-export function getCSRFTokenName(): string {
- return 'X-XSRF-TOKEN';
-}
-
-export function getCSRFTokenValue(): string {
- const cookieName = 'XSRF-TOKEN';
- const cookieValue = getCookie(cookieName);
- if (!cookieValue) {
- return '';
- }
- return cookieValue;
-}
-
-/**
- * Return an object containing a special http request header used to prevent CSRF attacks.
- */
-export function getCSRFToken(): Dict<string> {
- // Fetch API in Edge doesn't work with empty header,
- // so we ensure non-empty value
- const value = getCSRFTokenValue();
- return value ? { [getCSRFTokenName()]: value } : {};
-}
-
-export type RequestData = Dict<any>;
-
-export function omitNil(obj: RequestData): RequestData {
- return omitBy(obj, isNil);
-}
-
-/**
- * Default options for any request
- */
-const DEFAULT_OPTIONS: {
- credentials: RequestCredentials;
- method: string;
-} = {
- credentials: 'same-origin',
- method: 'GET',
-};
-
-/**
- * Default request headers
- */
-const DEFAULT_HEADERS = {
- Accept: 'application/json',
-};
-
-/**
- * Request
- */
-class Request {
- private data?: RequestData;
- private isJSON = false;
-
- // eslint-disable-next-line no-useless-constructor
- constructor(
- private readonly url: string,
- private readonly options: { method?: string } = {},
- ) {}
-
- getSubmitData(customHeaders: any = {}): { options: RequestInit; url: string } {
- let { url } = this;
- const options: RequestInit = { ...DEFAULT_OPTIONS, ...this.options };
-
- if (this.data) {
- if (this.data instanceof FormData) {
- options.body = this.data;
- } else if (this.isJSON) {
- customHeaders['Content-Type'] = 'application/json';
- options.body = JSON.stringify(this.data);
- } else {
- const strData = stringify(omitNil(this.data));
- if (options.method === 'GET') {
- url += '?' + strData;
- } else {
- customHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
- options.body = strData;
- }
- }
- }
-
- options.headers = {
- ...DEFAULT_HEADERS,
- ...customHeaders,
- };
- return { url, options };
- }
-
- submit(): Promise<Response> {
- const { url, options } = this.getSubmitData({ ...getCSRFToken() });
- return window.fetch(getBaseUrl() + url, options);
- }
-
- setMethod(method: string): this {
- this.options.method = method;
- return this;
- }
-
- setData(data?: RequestData, isJSON = false): this {
- if (data) {
- this.data = data;
- this.isJSON = isJSON;
- }
- return this;
- }
-}
-
-/**
- * Make a request
- */
-export function request(url: string): Request {
- return new Request(url);
-}
-
-/**
- * Make a cors request
- */
-export function corsRequest(url: string, mode: RequestMode = 'cors'): Request {
- const options: RequestInit = { mode };
- const request = new Request(url, options);
- request.submit = function () {
- const { url, options } = this.getSubmitData();
- return window.fetch(url, options);
- };
- return request;
-}
-
-/**
- * Check that response status is ok
- */
-export function checkStatus(response: Response, bypassRedirect = false): Promise<Response> {
- return new Promise((resolve, reject) => {
- if (response.status === HttpStatus.Unauthorized && !bypassRedirect) {
- handleRequiredAuthentication();
- reject(response);
- } else if (isSuccessStatus(response.status)) {
- resolve(response);
- } else {
- reject(response);
- }
- });
-}
-
-/**
- * Parse response as JSON
- */
-export function parseJSON(response: Response): Promise<any> {
- return response.json();
-}
-
-/**
- * Parse response as Text
- */
-export function parseText(response: Response): Promise<string> {
- return response.text();
-}
-
-/**
- * Parse error response of failed request
- */
-export function parseError(response: Response): Promise<string> {
- const DEFAULT_MESSAGE = translate('default_error_message');
- return parseJSON(response)
- .then(parseErrorResponse)
- .catch(() => DEFAULT_MESSAGE);
-}
-
-export function parseErrorResponse(response?: AxiosResponse | Response): string {
- const DEFAULT_MESSAGE = translate('default_error_message');
- let data;
- if (!response) {
- return DEFAULT_MESSAGE;
- }
- if ('data' in response) {
- ({ data } = response);
- } else {
- data = response;
- }
- const { message, errors } = data;
- return (
- message ?? errors?.map((error: { msg: string }) => error.msg).join('. ') ?? DEFAULT_MESSAGE
- );
-}
-
-/**
- * Shortcut to do a GET request and return a Response
- */
-export function get(url: string, data?: RequestData, bypassRedirect = false): Promise<Response> {
- return request(url)
- .setData(data)
- .submit()
- .then((response) => checkStatus(response, bypassRedirect));
-}
-
-/**
- * Shortcut to do a GET request and return response text
- */
-export function getText(url: string, data?: RequestData, bypassRedirect = false): Promise<string> {
- return get(url, data, bypassRedirect).then(parseText);
-}
-
-/**
- * Shortcut to do a CORS GET request and return response json
- */
-export function getCorsJSON(url: string, data?: RequestData): Promise<any> {
- return corsRequest(url)
- .setData(data)
- .submit()
- .then((response) => {
- if (isSuccessStatus(response.status)) {
- return parseJSON(response);
- }
- return Promise.reject(response);
- });
-}
-
-/**
- * Shortcut to do a POST request and return response json
- */
-export function postJSON(url: string, data?: RequestData, bypassRedirect = false): Promise<any> {
- return request(url)
- .setMethod('POST')
- .setData(data)
- .submit()
- .then((response) => checkStatus(response, bypassRedirect))
- .then(parseJSON);
-}
-
-/**
- * Shortcut to do a POST request with a json body and return response json
- */
-export function postJSONBody(
- url: string,
- data?: RequestData,
- bypassRedirect = false,
-): Promise<any> {
- return request(url)
- .setMethod('POST')
- .setData(data, true)
- .submit()
- .then((response) => checkStatus(response, bypassRedirect))
- .then(parseJSON);
-}
-
-/**
- * Shortcut to do a POST request
- */
-export function post(url: string, data?: RequestData, bypassRedirect = false): Promise<void> {
- return new Promise((resolve, reject) => {
- request(url)
- .setMethod('POST')
- .setData(data)
- .submit()
- .then((response) => checkStatus(response, bypassRedirect))
- .then(() => resolve(), reject);
- });
-}
-
-/**
- * Shortcut to do a DELETE request
- */
-export function deleteJSON(url: string, data?: RequestData): Promise<Response> {
- return request(url)
- .setMethod('DELETE')
- .setData(data)
- .submit()
- .then((response) => checkStatus(response));
-}
-
-function tryRequestAgain<T>(
- repeatAPICall: () => Promise<T>,
- tries: { max: number; slowThreshold: number },
- stopRepeat: (response: T) => boolean,
- repeatErrors: number[] = [],
- lastError?: Response,
-) {
- tries.max--;
- if (tries.max !== 0) {
- return new Promise<T>((resolve) => {
- setTimeout(
- () => resolve(requestTryAndRepeatUntil(repeatAPICall, tries, stopRepeat, repeatErrors)),
- tries.max > tries.slowThreshold ? FAST_RETRY_TIMEOUT : SLOW_RETRY_TIMEOUT,
- );
- });
- }
- return Promise.reject(lastError);
-}
-
-export function requestTryAndRepeatUntil<T>(
- repeatAPICall: () => Promise<T>,
- tries: { max: number; slowThreshold: number },
- stopRepeat: (response: T) => boolean,
- repeatErrors: number[] = [],
-) {
- return repeatAPICall().then(
- (r) => {
- if (stopRepeat(r)) {
- return r;
- }
- return tryRequestAgain(repeatAPICall, tries, stopRepeat, repeatErrors);
- },
- (error: Response) => {
- if (repeatErrors.length === 0 || repeatErrors.includes(error.status)) {
- return tryRequestAgain(repeatAPICall, tries, stopRepeat, repeatErrors, error);
- }
- return Promise.reject(error);
- },
- );
-}
-
-export function isSuccessStatus(status: number) {
- return status >= 200 && status < 300;
-}
-
-// Adapted from https://nodejs.org/api/http.html#http_http_HTTP_STATUS
-export enum HttpStatus {
- Ok = 200,
- Created = 201,
- NoContent = 204,
- MultipleChoices = 300,
- MovedPermanently = 301,
- Found = 302,
- BadRequest = 400,
- Unauthorized = 401,
- Forbidden = 403,
- NotFound = 404,
- InternalServerError = 500,
- NotImplemented = 501,
- BadGateway = 502,
- ServiceUnavailable = 503,
- GatewayTimeout = 504,
-}
-
-export const axiosToCatch = axios.create();
diff --git a/server/sonar-web/src/main/js/helpers/search.tsx b/server/sonar-web/src/main/js/helpers/search.tsx
deleted file mode 100644
index 768297bf6ae..00000000000
--- a/server/sonar-web/src/main/js/helpers/search.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export function highlightTerm(str: string, term: string) {
- const pos = str.toLowerCase().indexOf(term.toLowerCase());
- return pos !== -1 ? (
- <>
- {pos > 0 && str.substring(0, pos)}
- <mark>{str.substr(pos, term.length)}</mark>
- {pos + term.length < str.length && str.substring(pos + term.length)}
- </>
- ) : (
- str
- );
-}
-
-export interface LabelValueSelectOption<V = string> {
- label: string;
- value: V;
-}
diff --git a/server/sonar-web/src/main/js/helpers/security-standard.ts b/server/sonar-web/src/main/js/helpers/security-standard.ts
deleted file mode 100644
index 664286744be..00000000000
--- a/server/sonar-web/src/main/js/helpers/security-standard.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Standards } from '../types/security';
-
-export function getStandards(): Promise<Standards> {
- return import('./standards.json').then((x) => x.default);
-}
-
-export function renderCWECategory(standards: Standards, category: string): string {
- const record = standards.cwe[category];
- if (!record) {
- return `CWE-${category}`;
- } else if (category === 'unknown') {
- return record.title;
- }
- return `CWE-${category} - ${record.title}`;
-}
-
-export function renderOwaspTop10Category(
- standards: Standards,
- category: string,
- withPrefix = false,
-): string {
- return renderOwaspCategory('owaspTop10', standards, category, withPrefix);
-}
-
-export function renderOwaspTop102021Category(
- standards: Standards,
- category: string,
- withPrefix = false,
-): string {
- return renderOwaspCategory('owaspTop10-2021', standards, category, withPrefix);
-}
-
-function renderOwaspCategory(
- type: 'owaspTop10' | 'owaspTop10-2021',
- standards: Standards,
- category: string,
- withPrefix: boolean,
-) {
- const record = standards[type][category];
- if (!record) {
- return addPrefix(category.toUpperCase(), 'OWASP', withPrefix);
- }
- return addPrefix(`${category.toUpperCase()} - ${record.title}`, 'OWASP', withPrefix);
-}
-
-export function renderSonarSourceSecurityCategory(
- standards: Standards,
- category: string,
- withPrefix = false,
-): string {
- const record = standards.sonarsourceSecurity[category];
- if (!record) {
- return addPrefix(category.toUpperCase(), 'SONAR', withPrefix);
- } else if (category === 'others') {
- return record.title;
- }
- return addPrefix(record.title, 'SONAR', withPrefix);
-}
-
-export function renderPciDss32Category(standards: Standards, category: string): string {
- const record = standards['pciDss-3.2'][category];
- if (!record) {
- return category;
- }
- return `${category} - ${record.title}`;
-}
-
-export function renderPciDss40Category(standards: Standards, category: string): string {
- const record = standards['pciDss-4.0'][category];
- if (!record) {
- return category;
- }
- return `${category} - ${record.title}`;
-}
-
-export function renderOwaspAsvs40Category(standards: Standards, category: string): string {
- const record = standards['owaspAsvs-4.0'][category];
- if (!record) {
- return category;
- }
- const levelInfo = record.level ? ` (Level ${record.level})` : '';
- return `${category} - ${record.title}${levelInfo}`;
-}
-
-function addPrefix(title: string, prefix: string, withPrefix: boolean) {
- return withPrefix ? `${prefix} ${title}` : title;
-}
-
-export function renderCASACategory(standards: Standards, category: string): string {
- const record = standards['casa'][category];
- if (!record) {
- return category;
- }
- return `${category} - ${record.title}`;
-}
-
-export function renderStigCategory(standards: Standards, category: string) {
- const record = standards['stig-ASD_V5R3'][category];
- return record ? `${category} - ${record.title}` : category;
-}
diff --git a/server/sonar-web/src/main/js/helpers/sonarlint.ts b/server/sonar-web/src/main/js/helpers/sonarlint.ts
deleted file mode 100644
index 3a384f1d306..00000000000
--- a/server/sonar-web/src/main/js/helpers/sonarlint.ts
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { omit } from 'lodash';
-import { generateToken, getTokens } from '../api/user-tokens';
-import { getHostUrl } from '../helpers/urls';
-import { isBranch, isPullRequest } from '../sonar-aligned/helpers/branch-like';
-import { BranchLike } from '../types/branch-like';
-import { Fix, Ide } from '../types/sonarlint';
-import { NewUserToken, TokenExpiration } from '../types/token';
-import { UserBase } from '../types/users';
-import { checkStatus, isSuccessStatus } from './request';
-import {
- computeTokenExpirationDate,
- getAvailableExpirationOptions,
- getNextTokenName,
-} from './tokens';
-
-export const SONARLINT_PORT_START = 64120;
-export const SONARLINT_PORT_RANGE = 11;
-
-export async function probeSonarLintServers(): Promise<Array<Ide>> {
- const probedPorts = buildPortRange();
-
- const probeRequests = probedPorts.map((p) =>
- fetch(buildSonarLintEndpoint(p, '/status'))
- .then((r) => r.json())
- .then((json) => {
- return { port: p, ...omit(json, 'p') };
- })
- .catch(() => undefined),
- );
-
- const results = await Promise.all(probeRequests);
-
- return results.filter((r) => r !== undefined) as Ide[];
-}
-
-export function openHotspot(calledPort: number, projectKey: string, hotspotKey: string) {
- const showUrl = new URL(buildSonarLintEndpoint(calledPort, '/hotspots/show'));
-
- showUrl.searchParams.set('server', getHostUrl());
- showUrl.searchParams.set('project', projectKey);
- showUrl.searchParams.set('hotspot', hotspotKey);
-
- return fetch(showUrl.toString()).then((response: Response) => checkStatus(response, true));
-}
-
-const computeSonarLintTokenExpirationDate = async () => {
- const options = await getAvailableExpirationOptions();
- const maxOption = options[options.length - 1];
-
- return computeTokenExpirationDate(maxOption.value || TokenExpiration.OneYear);
-};
-
-const getNextAvailableSonarLintTokenName = async ({
- ideName,
- login,
-}: {
- ideName: string;
- login: string;
-}) => {
- const tokens = await getTokens(login);
-
- return getNextTokenName(`SonarLint-${ideName}`, tokens);
-};
-
-export const generateSonarLintUserToken = async ({
- ideName,
- login,
-}: {
- ideName: string;
- login: UserBase['login'];
-}) => {
- const name = await getNextAvailableSonarLintTokenName({ ideName, login });
- const expirationDate = await computeSonarLintTokenExpirationDate();
-
- return generateToken({ expirationDate, login, name });
-};
-
-export function openFixOrIssueInSonarLint({
- branchLike,
- calledPort,
- fix,
- issueKey,
- projectKey,
- token,
-}: {
- branchLike: BranchLike | undefined;
- calledPort: number;
- fix?: Fix;
- issueKey: string;
- projectKey: string;
- token?: NewUserToken;
-}) {
- const showUrl = new URL(
- buildSonarLintEndpoint(calledPort, fix === undefined ? '/issues/show' : '/fix/show'),
- );
-
- showUrl.searchParams.set('server', getHostUrl());
- showUrl.searchParams.set('project', projectKey);
- showUrl.searchParams.set('issue', issueKey);
-
- if (isBranch(branchLike)) {
- showUrl.searchParams.set('branch', branchLike.name);
- }
-
- if (isPullRequest(branchLike)) {
- showUrl.searchParams.set('branch', branchLike.branch);
- showUrl.searchParams.set('pullRequest', branchLike.key);
- }
-
- if (token !== undefined) {
- showUrl.searchParams.set('tokenName', token.name);
- showUrl.searchParams.set('tokenValue', token.token);
- }
-
- if (fix !== undefined) {
- return fetch(showUrl.toString(), { method: 'POST', body: JSON.stringify(fix) }).then(
- (response: Response) => checkStatus(response, true),
- );
- }
- return fetch(showUrl.toString()).then((response: Response) => checkStatus(response, true));
-}
-
-export function portIsValid(port: number) {
- return port >= SONARLINT_PORT_START && port < SONARLINT_PORT_START + SONARLINT_PORT_RANGE;
-}
-
-export async function sendUserToken(port: number, token: NewUserToken) {
- const tokenUrl = buildSonarLintEndpoint(port, '/token');
-
- const data = {
- login: token.login,
- name: token.name,
- createdAt: token.createdAt,
- expirationDate: token.expirationDate,
- token: token.token,
- type: token.type,
- };
-
- const response = await fetch(tokenUrl, { method: 'POST', body: JSON.stringify(data) });
-
- if (!isSuccessStatus(response.status)) {
- const content = await response.text();
-
- throw new Error(`${response.status} ${response.statusText}. ${content}`);
- }
-}
-
-/**
- * @returns [ start , ... , start + size - 1 ]
- */
-export function buildPortRange(start = SONARLINT_PORT_START, size = SONARLINT_PORT_RANGE) {
- return Array.from(Array(size).keys()).map((p) => start + p);
-}
-
-function buildSonarLintEndpoint(port: number, path: string) {
- return `http://localhost:${port}/sonarlint/api${path}`;
-}
diff --git a/server/sonar-web/src/main/js/helpers/standards.json b/server/sonar-web/src/main/js/helpers/standards.json
deleted file mode 100644
index c2957c689cd..00000000000
--- a/server/sonar-web/src/main/js/helpers/standards.json
+++ /dev/null
@@ -1,7312 +0,0 @@
-{
- "owaspTop10-2021": {
- "a1": {
- "title": "Broken Access Control",
- "description": "Restrictions on what authenticated users are allowed to do are often not properly enforced. Attackers can exploit these flaws to access unauthorized functionality and/or data, such as access other users' accounts, view sensitive files, modify other users' data, change access rights, etc."
- },
- "a2": {
- "title": "Cryptographic Failures",
- "description": "Many web applications and APIs do not properly protect sensitive data, such as financial, healthcare, and PII. Attackers may steal or modify such weakly protected data to conduct credit card fraud, identity theft, or other crimes. Sensitive data may be compromised without extra protection, such as encryption at rest or in transit, and requires special precautions when exchanged with the browser."
- },
- "a3": {
- "title": "Injection",
- "description": "Injection flaws, such as SQL, NoSQL, OS, and LDAP injection, occur when untrusted data is sent to an interpreter as part of a command or query. The attacker's hostile data can trick the interpreter into executing unintended commands or accessing data without proper authorization."
- },
- "a4": {
- "title": "Insecure Design",
- "description": "Insecure design is a broad category representing different weaknesses, expressed as “missing or ineffective control design.” An insecure design cannot be fixed by a perfect implementation as by definition, needed security controls were never created to defend against specific attacks."
- },
- "a5": {
- "title": "Security Misconfiguration",
- "description": "Security misconfiguration is the most commonly seen issue. This is commonly a result of insecure default configurations, incomplete or ad hoc configurations, open cloud storage, misconfigured HTTP headers, and verbose error messages containing sensitive information. Not only must all operating systems, frameworks, libraries, and applications be securely configured, but they must be patched and upgraded in a timely fashion."
- },
- "a6": {
- "title": "Vulnerable and Outdated Components",
- "description": "Components, such as libraries, frameworks, and other software modules, run with the same privileges as the application. If a vulnerable component is exploited, such an attack can facilitate serious data loss or server takeover. Applications and APIs using components with known vulnerabilities may undermine application defenses and enable various attacks and impacts."
- },
- "a7": {
- "title": "Identification and Authentication Failures",
- "description": "Application functions related to authentication and session management are often implemented incorrectly, allowing attackers to compromise passwords, keys, or session tokens, or to exploit other implementation flaws to assume other users' identities temporarily or permanently."
- },
- "a8": {
- "title": "Software and Data Integrity Failures",
- "description": "Software and data integrity failures relate to code and infrastructure that does not protect against integrity violations. An example of this is where an application relies upon plugins, libraries, or modules from untrusted sources, repositories, and content delivery networks (CDNs)."
- },
- "a9": {
- "title": "Security Logging and Monitoring Failures",
- "description": "Insufficient logging and monitoring, coupled with missing or ineffective integration with incident response, allows attackers to further attack systems, maintain persistence, pivot to more systems, and tamper, extract, or destroy data. Most breach studies show time to detect a breach is over 200 days, typically detected by external parties rather than internal processes or monitoring."
- },
- "a10": {
- "title": "Server-Side Request Forgery (SSRF)",
- "description": "SSRF flaws occur whenever a web application is fetching a remote resource without validating the user-supplied URL. It allows an attacker to coerce the application to send a crafted request to an unexpected destination, even when protected by a firewall, VPN, or another type of network access control list (ACL)."
- }
- },
- "owaspTop10": {
- "a1": {
- "title": "Injection",
- "description": "Injection flaws, such as SQL, NoSQL, OS, and LDAP injection, occur when untrusted data is sent to an interpreter as part of a command or query. The attacker's hostile data can trick the interpreter into executing unintended commands or accessing data without proper authorization."
- },
- "a2": {
- "title": "Broken Authentication",
- "description": "Application functions related to authentication and session management are often implemented incorrectly, allowing attackers to compromise passwords, keys, or session tokens, or to exploit other implementation flaws to assume other users' identities temporarily or permanently."
- },
- "a3": {
- "title": "Sensitive Data Exposure",
- "description": "Many web applications and APIs do not properly protect sensitive data, such as financial, healthcare, and PII. Attackers may steal or modify such weakly protected data to conduct credit card fraud, identity theft, or other crimes. Sensitive data may be compromised without extra protection, such as encryption at rest or in transit, and requires special precautions when exchanged with the browser."
- },
- "a4": {
- "title": "XML External Entities (XXE)",
- "description": "Many older or poorly configured XML processors evaluate external entity references within XML documents. External entities can be used to disclose internal files using the file URI handler, internal file shares, internal port scanning, remote code execution, and denial of service attacks."
- },
- "a5": {
- "title": "Broken Access Control",
- "description": "Restrictions on what authenticated users are allowed to do are often not properly enforced. Attackers can exploit these flaws to access unauthorized functionality and/or data, such as access other users' accounts, view sensitive files, modify other users' data, change access rights, etc."
- },
- "a6": {
- "title": "Security Misconfiguration",
- "description": "Security misconfiguration is the most commonly seen issue. This is commonly a result of insecure default configurations, incomplete or ad hoc configurations, open cloud storage, misconfigured HTTP headers, and verbose error messages containing sensitive information. Not only must all operating systems, frameworks, libraries, and applications be securely configured, but they must be patched and upgraded in a timely fashion."
- },
- "a7": {
- "title": "Cross-Site Scripting (XSS)",
- "description": "XSS flaws occur whenever an application includes untrusted data in a new web page without proper validation or escaping, or updates an existing web page with user-supplied data using a browser API that can create HTML or JavaScript. XSS allows attackers to execute scripts in the victim's browser which can hijack user sessions, deface web sites, or redirect the user to malicious sites."
- },
- "a8": {
- "title": "Insecure Deserialization",
- "description": "Insecure deserialization often leads to remote code execution. Even if deserialization flaws do not result in remote code execution, they can be used to perform attacks, including replay attacks, injection attacks, and privilege escalation attacks."
- },
- "a9": {
- "title": "Using Components with Known Vulnerabilities",
- "description": "Components, such as libraries, frameworks, and other software modules, run with the same privileges as the application. If a vulnerable component is exploited, such an attack can facilitate serious data loss or server takeover. Applications and APIs using components with known vulnerabilities may undermine application defenses and enable various attacks and impacts."
- },
- "a10": {
- "title": "Insufficient Logging & Monitoring",
- "description": "Insufficient logging and monitoring, coupled with missing or ineffective integration with incident response, allows attackers to further attack systems, maintain persistence, pivot to more systems, and tamper, extract, or destroy data. Most breach studies show time to detect a breach is over 200 days, typically detected by external parties rather than internal processes or monitoring."
- }
- },
- "cwe": {
- "5": {
- "title": "J2EE Misconfiguration: Data Transmission Without Encryption",
- "description": "Information sent over a network can be compromised while in transit. An attacker may be able to read or modify the contents if the data are sent in plaintext or are weakly encrypted."
- },
- "6": {
- "title": "J2EE Misconfiguration: Insufficient Session-ID Length",
- "description": "The J2EE application is configured to use an insufficient session ID length."
- },
- "7": {
- "title": "J2EE Misconfiguration: Missing Custom Error Page",
- "description": "The default error page of a web application should not display sensitive information about the product."
- },
- "8": {
- "title": "J2EE Misconfiguration: Entity Bean Declared Remote",
- "description": "When an application exposes a remote interface for an entity bean, it might also expose methods that get or set the bean's data. These methods could be leveraged to read sensitive information, or to change data in ways that violate the application's expectations, potentially leading to other vulnerabilities."
- },
- "9": {
- "title": "J2EE Misconfiguration: Weak Access Permissions for EJB Methods",
- "description": "If elevated access rights are assigned to EJB methods, then an attacker can take advantage of the permissions to exploit the product."
- },
- "11": {
- "title": "ASP.NET Misconfiguration: Creating Debug Binary",
- "description": "Debugging messages help attackers learn about the system and plan a form of attack."
- },
- "12": {
- "title": "ASP.NET Misconfiguration: Missing Custom Error Page",
- "description": "An ASP .NET application must enable custom error pages in order to prevent attackers from mining information from the framework's built-in responses."
- },
- "13": {
- "title": "ASP.NET Misconfiguration: Password in Configuration File",
- "description": "Storing a plaintext password in a configuration file allows anyone who can read the file access to the password-protected resource making them an easy target for attackers."
- },
- "14": {
- "title": "Compiler Removal of Code to Clear Buffers",
- "description": "Sensitive memory is cleared according to the source code, but compiler optimizations leave the memory untouched when it is not read from again, aka \"dead store removal.\""
- },
- "15": {
- "title": "External Control of System or Configuration Setting",
- "description": "One or more system settings or configuration elements can be externally controlled by a user."
- },
- "20": {
- "title": "Improper Input Validation",
- "description": "The product receives input or data, but it does\n not validate or incorrectly validates that the input has the\n properties that are required to process the data safely and\n correctly."
- },
- "22": {
- "title": "Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')",
- "description": "The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory."
- },
- "23": {
- "title": "Relative Path Traversal",
- "description": "The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize sequences such as \"..\" that can resolve to a location that is outside of that directory."
- },
- "24": {
- "title": "Path Traversal: '../filedir'",
- "description": "The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize \"../\" sequences that can resolve to a location that is outside of that directory."
- },
- "25": {
- "title": "Path Traversal: '/../filedir'",
- "description": "The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize \"/../\" sequences that can resolve to a location that is outside of that directory."
- },
- "26": {
- "title": "Path Traversal: '/dir/../filename'",
- "description": "The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize \"/dir/../filename\" sequences that can resolve to a location that is outside of that directory."
- },
- "27": {
- "title": "Path Traversal: 'dir/../../filename'",
- "description": "The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize multiple internal \"../\" sequences that can resolve to a location that is outside of that directory."
- },
- "28": {
- "title": "Path Traversal: '..\\filedir'",
- "description": "The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize \"..\\\" sequences that can resolve to a location that is outside of that directory."
- },
- "29": {
- "title": "Path Traversal: '\\..\\filename'",
- "description": "The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize '\\..\\filename' (leading backslash dot dot) sequences that can resolve to a location that is outside of that directory."
- },
- "30": {
- "title": "Path Traversal: '\\dir\\..\\filename'",
- "description": "The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize '\\dir\\..\\filename' (leading backslash dot dot) sequences that can resolve to a location that is outside of that directory."
- },
- "31": {
- "title": "Path Traversal: 'dir\\..\\..\\filename'",
- "description": "The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize 'dir\\..\\..\\filename' (multiple internal backslash dot dot) sequences that can resolve to a location that is outside of that directory."
- },
- "32": {
- "title": "Path Traversal: '...' (Triple Dot)",
- "description": "The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize '...' (triple dot) sequences that can resolve to a location that is outside of that directory."
- },
- "33": {
- "title": "Path Traversal: '....' (Multiple Dot)",
- "description": "The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize '....' (multiple dot) sequences that can resolve to a location that is outside of that directory."
- },
- "34": {
- "title": "Path Traversal: '....//'",
- "description": "The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize '....//' (doubled dot dot slash) sequences that can resolve to a location that is outside of that directory."
- },
- "35": {
- "title": "Path Traversal: '.../...//'",
- "description": "The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize '.../...//' (doubled triple dot slash) sequences that can resolve to a location that is outside of that directory."
- },
- "36": {
- "title": "Absolute Path Traversal",
- "description": "The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize absolute path sequences such as \"/abs/path\" that can resolve to a location that is outside of that directory."
- },
- "37": {
- "title": "Path Traversal: '/absolute/pathname/here'",
- "description": "The product accepts input in the form of a slash absolute path ('/absolute/pathname/here') without appropriate validation, which can allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "38": {
- "title": "Path Traversal: '\\absolute\\pathname\\here'",
- "description": "The product accepts input in the form of a backslash absolute path ('\\absolute\\pathname\\here') without appropriate validation, which can allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "39": {
- "title": "Path Traversal: 'C:dirname'",
- "description": "The product accepts input that contains a drive letter or Windows volume letter ('C:dirname') that potentially redirects access to an unintended location or arbitrary file."
- },
- "40": {
- "title": "Path Traversal: '\\\\UNC\\share\\name\\' (Windows UNC Share)",
- "description": "The product accepts input that identifies a Windows UNC share ('\\\\UNC\\share\\name') that potentially redirects access to an unintended location or arbitrary file."
- },
- "41": {
- "title": "Improper Resolution of Path Equivalence",
- "description": "The product is vulnerable to file system contents disclosure through path equivalence. Path equivalence involves the use of special characters in file and directory names. The associated manipulations are intended to generate multiple names for the same object."
- },
- "42": {
- "title": "Path Equivalence: 'filename.' (Trailing Dot)",
- "description": "The product accepts path input in the form of trailing dot ('filedir.') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "43": {
- "title": "Path Equivalence: 'filename....' (Multiple Trailing Dot)",
- "description": "The product accepts path input in the form of multiple trailing dot ('filedir....') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "44": {
- "title": "Path Equivalence: 'file.name' (Internal Dot)",
- "description": "The product accepts path input in the form of internal dot ('file.ordir') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "45": {
- "title": "Path Equivalence: 'file...name' (Multiple Internal Dot)",
- "description": "The product accepts path input in the form of multiple internal dot ('file...dir') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "46": {
- "title": "Path Equivalence: 'filename ' (Trailing Space)",
- "description": "The product accepts path input in the form of trailing space ('filedir ') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "47": {
- "title": "Path Equivalence: ' filename' (Leading Space)",
- "description": "The product accepts path input in the form of leading space (' filedir') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "48": {
- "title": "Path Equivalence: 'file name' (Internal Whitespace)",
- "description": "The product accepts path input in the form of internal space ('file(SPACE)name') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "49": {
- "title": "Path Equivalence: 'filename/' (Trailing Slash)",
- "description": "The product accepts path input in the form of trailing slash ('filedir/') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "50": {
- "title": "Path Equivalence: '//multiple/leading/slash'",
- "description": "The product accepts path input in the form of multiple leading slash ('//multiple/leading/slash') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "51": {
- "title": "Path Equivalence: '/multiple//internal/slash'",
- "description": "The product accepts path input in the form of multiple internal slash ('/multiple//internal/slash/') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "52": {
- "title": "Path Equivalence: '/multiple/trailing/slash//'",
- "description": "The product accepts path input in the form of multiple trailing slash ('/multiple/trailing/slash//') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "53": {
- "title": "Path Equivalence: '\\multiple\\\\internal\\backslash'",
- "description": "The product accepts path input in the form of multiple internal backslash ('\\multiple\\trailing\\\\slash') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "54": {
- "title": "Path Equivalence: 'filedir\\' (Trailing Backslash)",
- "description": "The product accepts path input in the form of trailing backslash ('filedir\\') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "55": {
- "title": "Path Equivalence: '/./' (Single Dot Directory)",
- "description": "The product accepts path input in the form of single dot directory exploit ('/./') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "56": {
- "title": "Path Equivalence: 'filedir*' (Wildcard)",
- "description": "The product accepts path input in the form of asterisk wildcard ('filedir*') without appropriate validation, which can lead to ambiguous path resolution and allow an attacker to traverse the file system to unintended locations or access arbitrary files."
- },
- "57": {
- "title": "Path Equivalence: 'fakedir/../realdir/filename'",
- "description": "The product contains protection mechanisms to restrict access to 'realdir/filename', but it constructs pathnames using external input in the form of 'fakedir/../realdir/filename' that are not handled by those mechanisms. This allows attackers to perform unauthorized actions against the targeted file."
- },
- "58": {
- "title": "Path Equivalence: Windows 8.3 Filename",
- "description": "The product contains a protection mechanism that restricts access to a long filename on a Windows operating system, but it does not properly restrict access to the equivalent short \"8.3\" filename."
- },
- "59": {
- "title": "Improper Link Resolution Before File Access ('Link Following')",
- "description": "The product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource."
- },
- "61": {
- "title": "UNIX Symbolic Link (Symlink) Following",
- "description": "The product, when opening a file or directory, does not sufficiently account for when the file is a symbolic link that resolves to a target outside of the intended control sphere. This could allow an attacker to cause the product to operate on unauthorized files."
- },
- "62": {
- "title": "UNIX Hard Link",
- "description": "The product, when opening a file or directory, does not sufficiently account for when the name is associated with a hard link to a target that is outside of the intended control sphere. This could allow an attacker to cause the product to operate on unauthorized files."
- },
- "64": {
- "title": "Windows Shortcut Following (.LNK)",
- "description": "The product, when opening a file or directory, does not sufficiently handle when the file is a Windows shortcut (.LNK) whose target is outside of the intended control sphere. This could allow an attacker to cause the product to operate on unauthorized files."
- },
- "65": {
- "title": "Windows Hard Link",
- "description": "The product, when opening a file or directory, does not sufficiently handle when the name is associated with a hard link to a target that is outside of the intended control sphere. This could allow an attacker to cause the product to operate on unauthorized files."
- },
- "66": {
- "title": "Improper Handling of File Names that Identify Virtual Resources",
- "description": "The product does not handle or incorrectly handles a file name that identifies a \"virtual\" resource that is not directly specified within the directory that is associated with the file name, causing the product to perform file-based operations on a resource that is not a file."
- },
- "67": {
- "title": "Improper Handling of Windows Device Names",
- "description": "The product constructs pathnames from user input, but it does not handle or incorrectly handles a pathname containing a Windows device name such as AUX or CON. This typically leads to denial of service or an information exposure when the application attempts to process the pathname as a regular file."
- },
- "69": {
- "title": "Improper Handling of Windows ::DATA Alternate Data Stream",
- "description": "The product does not properly prevent access to, or detect usage of, alternate data streams (ADS)."
- },
- "71": {
- "title": "DEPRECATED: Apple '.DS_Store'",
- "description": "This entry has been deprecated as it represents a specific observed example of a UNIX Hard Link weakness type rather than its own individual weakness type. Please refer to CWE-62."
- },
- "72": {
- "title": "Improper Handling of Apple HFS+ Alternate Data Stream Path",
- "description": "The product does not properly handle special paths that may identify the data or resource fork of a file on the HFS+ file system."
- },
- "73": {
- "title": "External Control of File Name or Path",
- "description": "The product allows user input to control or influence paths or file names that are used in filesystem operations."
- },
- "74": {
- "title": "Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')",
- "description": "The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component."
- },
- "75": {
- "title": "Failure to Sanitize Special Elements into a Different Plane (Special Element Injection)",
- "description": "The product does not adequately filter user-controlled input for special elements with control implications."
- },
- "76": {
- "title": "Improper Neutralization of Equivalent Special Elements",
- "description": "The product correctly neutralizes certain special elements, but it improperly neutralizes equivalent special elements."
- },
- "77": {
- "title": "Improper Neutralization of Special Elements used in a Command ('Command Injection')",
- "description": "The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component."
- },
- "78": {
- "title": "Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')",
- "description": "The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component."
- },
- "79": {
- "title": "Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')",
- "description": "The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users."
- },
- "80": {
- "title": "Improper Neutralization of Script-Related HTML Tags in a Web Page (Basic XSS)",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special characters such as \"<\", \">\", and \"&\" that could be interpreted as web-scripting elements when they are sent to a downstream component that processes web pages."
- },
- "81": {
- "title": "Improper Neutralization of Script in an Error Message Web Page",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special characters that could be interpreted as web-scripting elements when they are sent to an error page."
- },
- "82": {
- "title": "Improper Neutralization of Script in Attributes of IMG Tags in a Web Page",
- "description": "The web application does not neutralize or incorrectly neutralizes scripting elements within attributes of HTML IMG tags, such as the src attribute."
- },
- "83": {
- "title": "Improper Neutralization of Script in Attributes in a Web Page",
- "description": "The product does not neutralize or incorrectly neutralizes \"javascript:\" or other URIs from dangerous attributes within tags, such as onmouseover, onload, onerror, or style."
- },
- "84": {
- "title": "Improper Neutralization of Encoded URI Schemes in a Web Page",
- "description": "The web application improperly neutralizes user-controlled input for executable script disguised with URI encodings."
- },
- "85": {
- "title": "Doubled Character XSS Manipulations",
- "description": "The web application does not filter user-controlled input for executable script disguised using doubling of the involved characters."
- },
- "86": {
- "title": "Improper Neutralization of Invalid Characters in Identifiers in Web Pages",
- "description": "The product does not neutralize or incorrectly neutralizes invalid characters or byte sequences in the middle of tag names, URI schemes, and other identifiers."
- },
- "87": {
- "title": "Improper Neutralization of Alternate XSS Syntax",
- "description": "The product does not neutralize or incorrectly neutralizes user-controlled input for alternate script syntax."
- },
- "88": {
- "title": "Improper Neutralization of Argument Delimiters in a Command ('Argument Injection')",
- "description": "The product constructs a string for a command to executed by a separate component\nin another control sphere, but it does not properly delimit the\nintended arguments, options, or switches within that command string."
- },
- "89": {
- "title": "Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')",
- "description": "The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component."
- },
- "90": {
- "title": "Improper Neutralization of Special Elements used in an LDAP Query ('LDAP Injection')",
- "description": "The product constructs all or part of an LDAP query using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended LDAP query when it is sent to a downstream component."
- },
- "91": {
- "title": "XML Injection (aka Blind XPath Injection)",
- "description": "The product does not properly neutralize special elements that are used in XML, allowing attackers to modify the syntax, content, or commands of the XML before it is processed by an end system."
- },
- "92": {
- "title": "DEPRECATED: Improper Sanitization of Custom Special Characters",
- "description": "This entry has been deprecated. It originally came from PLOVER, which sometimes defined \"other\" and \"miscellaneous\" categories in order to satisfy exhaustiveness requirements for taxonomies. Within the context of CWE, the use of a more abstract entry is preferred in mapping situations. CWE-75 is a more appropriate mapping."
- },
- "93": {
- "title": "Improper Neutralization of CRLF Sequences ('CRLF Injection')",
- "description": "The product uses CRLF (carriage return line feeds) as a special element, e.g. to separate lines or records, but it does not neutralize or incorrectly neutralizes CRLF sequences from inputs."
- },
- "94": {
- "title": "Improper Control of Generation of Code ('Code Injection')",
- "description": "The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment."
- },
- "95": {
- "title": "Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes code syntax before using the input in a dynamic evaluation call (e.g. \"eval\")."
- },
- "96": {
- "title": "Improper Neutralization of Directives in Statically Saved Code ('Static Code Injection')",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes code syntax before inserting the input into an executable resource, such as a library, configuration file, or template."
- },
- "97": {
- "title": "Improper Neutralization of Server-Side Includes (SSI) Within a Web Page",
- "description": "The product generates a web page, but does not neutralize or incorrectly neutralizes user-controllable input that could be interpreted as a server-side include (SSI) directive."
- },
- "98": {
- "title": "Improper Control of Filename for Include/Require Statement in PHP Program ('PHP Remote File Inclusion')",
- "description": "The PHP application receives input from an upstream component, but it does not restrict or incorrectly restricts the input before its usage in \"require,\" \"include,\" or similar functions."
- },
- "99": {
- "title": "Improper Control of Resource Identifiers ('Resource Injection')",
- "description": "The product receives input from an upstream component, but it does not restrict or incorrectly restricts the input before it is used as an identifier for a resource that may be outside the intended sphere of control."
- },
- "102": {
- "title": "Struts: Duplicate Validation Forms",
- "description": "The product uses multiple validation forms with the same name, which might cause the Struts Validator to validate a form that the programmer does not expect."
- },
- "103": {
- "title": "Struts: Incomplete validate() Method Definition",
- "description": "The product has a validator form that either does not define a validate() method, or defines a validate() method but does not call super.validate()."
- },
- "104": {
- "title": "Struts: Form Bean Does Not Extend Validation Class",
- "description": "If a form bean does not extend an ActionForm subclass of the Validator framework, it can expose the application to other weaknesses related to insufficient input validation."
- },
- "105": {
- "title": "Struts: Form Field Without Validator",
- "description": "The product has a form field that is not validated by a corresponding validation form, which can introduce other weaknesses related to insufficient input validation."
- },
- "106": {
- "title": "Struts: Plug-in Framework not in Use",
- "description": "When an application does not use an input validation framework such as the Struts Validator, there is a greater risk of introducing weaknesses related to insufficient input validation."
- },
- "107": {
- "title": "Struts: Unused Validation Form",
- "description": "An unused validation form indicates that validation logic is not up-to-date."
- },
- "108": {
- "title": "Struts: Unvalidated Action Form",
- "description": "Every Action Form must have a corresponding validation form."
- },
- "109": {
- "title": "Struts: Validator Turned Off",
- "description": "Automatic filtering via a Struts bean has been turned off, which disables the Struts Validator and custom validation logic. This exposes the application to other weaknesses related to insufficient input validation."
- },
- "110": {
- "title": "Struts: Validator Without Form Field",
- "description": "Validation fields that do not appear in forms they are associated with indicate that the validation logic is out of date."
- },
- "111": {
- "title": "Direct Use of Unsafe JNI",
- "description": "When a Java application uses the Java Native Interface (JNI) to call code written in another programming language, it can expose the application to weaknesses in that code, even if those weaknesses cannot occur in Java."
- },
- "112": {
- "title": "Missing XML Validation",
- "description": "The product accepts XML from an untrusted source but does not validate the XML against the proper schema."
- },
- "113": {
- "title": "Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Request/Response Splitting')",
- "description": "The product receives data from an HTTP agent/component (e.g., web server, proxy, browser, etc.), but it does not neutralize or incorrectly neutralizes CR and LF characters before the data is included in outgoing HTTP headers."
- },
- "114": {
- "title": "Process Control",
- "description": "Executing commands or loading libraries from an untrusted source or in an untrusted environment can cause an application to execute malicious commands (and payloads) on behalf of an attacker."
- },
- "115": {
- "title": "Misinterpretation of Input",
- "description": "The product misinterprets an input, whether from an attacker or another product, in a security-relevant fashion."
- },
- "116": {
- "title": "Improper Encoding or Escaping of Output",
- "description": "The product prepares a structured message for communication with another component, but encoding or escaping of the data is either missing or done incorrectly. As a result, the intended structure of the message is not preserved."
- },
- "117": {
- "title": "Improper Output Neutralization for Logs",
- "description": "The product does not neutralize or incorrectly neutralizes output that is written to logs."
- },
- "118": {
- "title": "Incorrect Access of Indexable Resource ('Range Error')",
- "description": "The product does not restrict or incorrectly restricts operations within the boundaries of a resource that is accessed using an index or pointer, such as memory or files."
- },
- "119": {
- "title": "Improper Restriction of Operations within the Bounds of a Memory Buffer",
- "description": "The product performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer."
- },
- "120": {
- "title": "Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')",
- "description": "The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow."
- },
- "121": {
- "title": "Stack-based Buffer Overflow",
- "description": "A stack-based buffer overflow condition is a condition where the buffer being overwritten is allocated on the stack (i.e., is a local variable or, rarely, a parameter to a function)."
- },
- "122": {
- "title": "Heap-based Buffer Overflow",
- "description": "A heap overflow condition is a buffer overflow, where the buffer that can be overwritten is allocated in the heap portion of memory, generally meaning that the buffer was allocated using a routine such as malloc()."
- },
- "123": {
- "title": "Write-what-where Condition",
- "description": "Any condition where the attacker has the ability to write an arbitrary value to an arbitrary location, often as the result of a buffer overflow."
- },
- "124": {
- "title": "Buffer Underwrite ('Buffer Underflow')",
- "description": "The product writes to a buffer using an index or pointer that references a memory location prior to the beginning of the buffer."
- },
- "125": {
- "title": "Out-of-bounds Read",
- "description": "The product reads data past the end, or before the beginning, of the intended buffer."
- },
- "126": {
- "title": "Buffer Over-read",
- "description": "The product reads from a buffer using buffer access mechanisms such as indexes or pointers that reference memory locations after the targeted buffer."
- },
- "127": {
- "title": "Buffer Under-read",
- "description": "The product reads from a buffer using buffer access mechanisms such as indexes or pointers that reference memory locations prior to the targeted buffer."
- },
- "128": {
- "title": "Wrap-around Error",
- "description": "Wrap around errors occur whenever a value is incremented past the maximum value for its type and therefore \"wraps around\" to a very small, negative, or undefined value."
- },
- "129": {
- "title": "Improper Validation of Array Index",
- "description": "The product uses untrusted input when calculating or using an array index, but the product does not validate or incorrectly validates the index to ensure the index references a valid position within the array."
- },
- "130": {
- "title": "Improper Handling of Length Parameter Inconsistency",
- "description": "The product parses a formatted message or structure, but it does not handle or incorrectly handles a length field that is inconsistent with the actual length of the associated data."
- },
- "131": {
- "title": "Incorrect Calculation of Buffer Size",
- "description": "The product does not correctly calculate the size to be used when allocating a buffer, which could lead to a buffer overflow."
- },
- "132": {
- "title": "DEPRECATED: Miscalculated Null Termination",
- "description": "This entry has been deprecated because it was a duplicate of CWE-170. All content has been transferred to CWE-170."
- },
- "134": {
- "title": "Use of Externally-Controlled Format String",
- "description": "The product uses a function that accepts a format string as an argument, but the format string originates from an external source."
- },
- "135": {
- "title": "Incorrect Calculation of Multi-Byte String Length",
- "description": "The product does not correctly calculate the length of strings that can contain wide or multi-byte characters."
- },
- "138": {
- "title": "Improper Neutralization of Special Elements",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as control elements or syntactic markers when they are sent to a downstream component."
- },
- "140": {
- "title": "Improper Neutralization of Delimiters",
- "description": "The product does not neutralize or incorrectly neutralizes delimiters."
- },
- "141": {
- "title": "Improper Neutralization of Parameter/Argument Delimiters",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as parameter or argument delimiters when they are sent to a downstream component."
- },
- "142": {
- "title": "Improper Neutralization of Value Delimiters",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as value delimiters when they are sent to a downstream component."
- },
- "143": {
- "title": "Improper Neutralization of Record Delimiters",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as record delimiters when they are sent to a downstream component."
- },
- "144": {
- "title": "Improper Neutralization of Line Delimiters",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as line delimiters when they are sent to a downstream component."
- },
- "145": {
- "title": "Improper Neutralization of Section Delimiters",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as section delimiters when they are sent to a downstream component."
- },
- "146": {
- "title": "Improper Neutralization of Expression/Command Delimiters",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as expression or command delimiters when they are sent to a downstream component."
- },
- "147": {
- "title": "Improper Neutralization of Input Terminators",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as input terminators when they are sent to a downstream component."
- },
- "148": {
- "title": "Improper Neutralization of Input Leaders",
- "description": "The product does not properly handle when a leading character or sequence (\"leader\") is missing or malformed, or if multiple leaders are used when only one should be allowed."
- },
- "149": {
- "title": "Improper Neutralization of Quoting Syntax",
- "description": "Quotes injected into a product can be used to compromise a system. As data are parsed, an injected/absent/duplicate/malformed use of quotes may cause the process to take unexpected actions."
- },
- "150": {
- "title": "Improper Neutralization of Escape, Meta, or Control Sequences",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as escape, meta, or control character sequences when they are sent to a downstream component."
- },
- "151": {
- "title": "Improper Neutralization of Comment Delimiters",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as comment delimiters when they are sent to a downstream component."
- },
- "152": {
- "title": "Improper Neutralization of Macro Symbols",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as macro symbols when they are sent to a downstream component."
- },
- "153": {
- "title": "Improper Neutralization of Substitution Characters",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as substitution characters when they are sent to a downstream component."
- },
- "154": {
- "title": "Improper Neutralization of Variable Name Delimiters",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as variable name delimiters when they are sent to a downstream component."
- },
- "155": {
- "title": "Improper Neutralization of Wildcards or Matching Symbols",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as wildcards or matching symbols when they are sent to a downstream component."
- },
- "156": {
- "title": "Improper Neutralization of Whitespace",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as whitespace when they are sent to a downstream component."
- },
- "157": {
- "title": "Failure to Sanitize Paired Delimiters",
- "description": "The product does not properly handle the characters that are used to mark the beginning and ending of a group of entities, such as parentheses, brackets, and braces."
- },
- "158": {
- "title": "Improper Neutralization of Null Byte or NUL Character",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes NUL characters or null bytes when they are sent to a downstream component."
- },
- "159": {
- "title": "Improper Handling of Invalid Use of Special Elements",
- "description": "The product does not properly filter, remove, quote, or otherwise manage the invalid use of special elements in user-controlled input, which could cause adverse effect on its behavior and integrity."
- },
- "160": {
- "title": "Improper Neutralization of Leading Special Elements",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes leading special elements that could be interpreted in unexpected ways when they are sent to a downstream component."
- },
- "161": {
- "title": "Improper Neutralization of Multiple Leading Special Elements",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes multiple leading special elements that could be interpreted in unexpected ways when they are sent to a downstream component."
- },
- "162": {
- "title": "Improper Neutralization of Trailing Special Elements",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes trailing special elements that could be interpreted in unexpected ways when they are sent to a downstream component."
- },
- "163": {
- "title": "Improper Neutralization of Multiple Trailing Special Elements",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes multiple trailing special elements that could be interpreted in unexpected ways when they are sent to a downstream component."
- },
- "164": {
- "title": "Improper Neutralization of Internal Special Elements",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes internal special elements that could be interpreted in unexpected ways when they are sent to a downstream component."
- },
- "165": {
- "title": "Improper Neutralization of Multiple Internal Special Elements",
- "description": "The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes multiple internal special elements that could be interpreted in unexpected ways when they are sent to a downstream component."
- },
- "166": {
- "title": "Improper Handling of Missing Special Element",
- "description": "The product receives input from an upstream component, but it does not handle or incorrectly handles when an expected special element is missing."
- },
- "167": {
- "title": "Improper Handling of Additional Special Element",
- "description": "The product receives input from an upstream component, but it does not handle or incorrectly handles when an additional unexpected special element is provided."
- },
- "168": {
- "title": "Improper Handling of Inconsistent Special Elements",
- "description": "The product does not properly handle input in which an inconsistency exists between two or more special characters or reserved words."
- },
- "170": {
- "title": "Improper Null Termination",
- "description": "The product does not terminate or incorrectly terminates a string or array with a null character or equivalent terminator."
- },
- "172": {
- "title": "Encoding Error",
- "description": "The product does not properly encode or decode the data, resulting in unexpected values."
- },
- "173": {
- "title": "Improper Handling of Alternate Encoding",
- "description": "The product does not properly handle when an input uses an alternate encoding that is valid for the control sphere to which the input is being sent."
- },
- "174": {
- "title": "Double Decoding of the Same Data",
- "description": "The product decodes the same input twice, which can limit the effectiveness of any protection mechanism that occurs in between the decoding operations."
- },
- "175": {
- "title": "Improper Handling of Mixed Encoding",
- "description": "The product does not properly handle when the same input uses several different (mixed) encodings."
- },
- "176": {
- "title": "Improper Handling of Unicode Encoding",
- "description": "The product does not properly handle when an input contains Unicode encoding."
- },
- "177": {
- "title": "Improper Handling of URL Encoding (Hex Encoding)",
- "description": "The product does not properly handle when all or part of an input has been URL encoded."
- },
- "178": {
- "title": "Improper Handling of Case Sensitivity",
- "description": "The product does not properly account for differences in case sensitivity when accessing or determining the properties of a resource, leading to inconsistent results."
- },
- "179": {
- "title": "Incorrect Behavior Order: Early Validation",
- "description": "The product validates input before applying protection mechanisms that modify the input, which could allow an attacker to bypass the validation via dangerous inputs that only arise after the modification."
- },
- "180": {
- "title": "Incorrect Behavior Order: Validate Before Canonicalize",
- "description": "The product validates input before it is canonicalized, which prevents the product from detecting data that becomes invalid after the canonicalization step."
- },
- "181": {
- "title": "Incorrect Behavior Order: Validate Before Filter",
- "description": "The product validates data before it has been filtered, which prevents the product from detecting data that becomes invalid after the filtering step."
- },
- "182": {
- "title": "Collapse of Data into Unsafe Value",
- "description": "The product filters data in a way that causes it to be reduced or \"collapsed\" into an unsafe value that violates an expected security property."
- },
- "183": {
- "title": "Permissive List of Allowed Inputs",
- "description": "The product implements a protection mechanism that relies on a list of inputs (or properties of inputs) that are explicitly allowed by policy because the inputs are assumed to be safe, but the list is too permissive - that is, it allows an input that is unsafe, leading to resultant weaknesses."
- },
- "184": {
- "title": "Incomplete List of Disallowed Inputs",
- "description": "The product implements a protection mechanism that relies on a list of inputs (or properties of inputs) that are not allowed by policy or otherwise require other action to neutralize before additional processing takes place, but the list is incomplete, leading to resultant weaknesses."
- },
- "185": {
- "title": "Incorrect Regular Expression",
- "description": "The product specifies a regular expression in a way that causes data to be improperly matched or compared."
- },
- "186": {
- "title": "Overly Restrictive Regular Expression",
- "description": "A regular expression is overly restrictive, which prevents dangerous values from being detected."
- },
- "187": {
- "title": "Partial String Comparison",
- "description": "The product performs a comparison that only examines a portion of a factor before determining whether there is a match, such as a substring, leading to resultant weaknesses."
- },
- "188": {
- "title": "Reliance on Data/Memory Layout",
- "description": "The product makes invalid assumptions about how protocol data or memory is organized at a lower level, resulting in unintended program behavior."
- },
- "190": {
- "title": "Integer Overflow or Wraparound",
- "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control."
- },
- "191": {
- "title": "Integer Underflow (Wrap or Wraparound)",
- "description": "The product subtracts one value from another, such that the result is less than the minimum allowable integer value, which produces a value that is not equal to the correct result."
- },
- "192": {
- "title": "Integer Coercion Error",
- "description": "Integer coercion refers to a set of flaws pertaining to the type casting, extension, or truncation of primitive data types."
- },
- "193": {
- "title": "Off-by-one Error",
- "description": "A product calculates or uses an incorrect maximum or minimum value that is 1 more, or 1 less, than the correct value."
- },
- "194": {
- "title": "Unexpected Sign Extension",
- "description": "The product performs an operation on a number that causes it to be sign extended when it is transformed into a larger data type. When the original number is negative, this can produce unexpected values that lead to resultant weaknesses."
- },
- "195": {
- "title": "Signed to Unsigned Conversion Error",
- "description": "The product uses a signed primitive and performs a cast to an unsigned primitive, which can produce an unexpected value if the value of the signed primitive can not be represented using an unsigned primitive."
- },
- "196": {
- "title": "Unsigned to Signed Conversion Error",
- "description": "The product uses an unsigned primitive and performs a cast to a signed primitive, which can produce an unexpected value if the value of the unsigned primitive can not be represented using a signed primitive."
- },
- "197": {
- "title": "Numeric Truncation Error",
- "description": "Truncation errors occur when a primitive is cast to a primitive of a smaller size and data is lost in the conversion."
- },
- "198": {
- "title": "Use of Incorrect Byte Ordering",
- "description": "The product receives input from an upstream component, but it does not account for byte ordering (e.g. big-endian and little-endian) when processing the input, causing an incorrect number or value to be used."
- },
- "200": {
- "title": "Exposure of Sensitive Information to an Unauthorized Actor",
- "description": "The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information."
- },
- "201": {
- "title": "Insertion of Sensitive Information Into Sent Data",
- "description": "The code transmits data to another actor, but a portion of the data includes sensitive information that should not be accessible to that actor."
- },
- "202": {
- "title": "Exposure of Sensitive Information Through Data Queries",
- "description": "When trying to keep information confidential, an attacker can often infer some of the information by using statistics."
- },
- "203": {
- "title": "Observable Discrepancy",
- "description": "The product behaves differently or sends different responses under different circumstances in a way that is observable to an unauthorized actor, which exposes security-relevant information about the state of the product, such as whether a particular operation was successful or not."
- },
- "204": {
- "title": "Observable Response Discrepancy",
- "description": "The product provides different responses to incoming requests in a way that reveals internal state information to an unauthorized actor outside of the intended control sphere."
- },
- "205": {
- "title": "Observable Behavioral Discrepancy",
- "description": "The product's behaviors indicate important differences that may be observed by unauthorized actors in a way that reveals (1) its internal state or decision process, or (2) differences from other products with equivalent functionality."
- },
- "206": {
- "title": "Observable Internal Behavioral Discrepancy",
- "description": "The product performs multiple behaviors that are combined to produce a single result, but the individual behaviors are observable separately in a way that allows attackers to reveal internal state or internal decision points."
- },
- "207": {
- "title": "Observable Behavioral Discrepancy With Equivalent Products",
- "description": "The product operates in an environment in which its existence or specific identity should not be known, but it behaves differently than other products with equivalent functionality, in a way that is observable to an attacker."
- },
- "208": {
- "title": "Observable Timing Discrepancy",
- "description": "Two separate operations in a product require different amounts of time to complete, in a way that is observable to an actor and reveals security-relevant information about the state of the product, such as whether a particular operation was successful or not."
- },
- "209": {
- "title": "Generation of Error Message Containing Sensitive Information",
- "description": "The product generates an error message that includes sensitive information about its environment, users, or associated data."
- },
- "210": {
- "title": "Self-generated Error Message Containing Sensitive Information",
- "description": "The product identifies an error condition and creates its own diagnostic or error messages that contain sensitive information."
- },
- "211": {
- "title": "Externally-Generated Error Message Containing Sensitive Information",
- "description": "The product performs an operation that triggers an external diagnostic or error message that is not directly generated or controlled by the product, such as an error generated by the programming language interpreter that a software application uses. The error can contain sensitive system information."
- },
- "212": {
- "title": "Improper Removal of Sensitive Information Before Storage or Transfer",
- "description": "The product stores, transfers, or shares a resource that contains sensitive information, but it does not properly remove that information before the product makes the resource available to unauthorized actors."
- },
- "213": {
- "title": "Exposure of Sensitive Information Due to Incompatible Policies",
- "description": "The product's intended functionality exposes information to certain actors in accordance with the developer's security policy, but this information is regarded as sensitive according to the intended security policies of other stakeholders such as the product's administrator, users, or others whose information is being processed."
- },
- "214": {
- "title": "Invocation of Process Using Visible Sensitive Information",
- "description": "A process is invoked with sensitive command-line arguments, environment variables, or other elements that can be seen by other processes on the operating system."
- },
- "215": {
- "title": "Insertion of Sensitive Information Into Debugging Code",
- "description": "The product inserts sensitive information into debugging code, which could expose this information if the debugging code is not disabled in production."
- },
- "216": {
- "title": "DEPRECATED: Containment Errors (Container Errors)",
- "description": "This entry has been deprecated, as it was not effective as a weakness and was structured more like a category. In addition, the name is inappropriate, since the \"container\" term is widely understood by developers in different ways than originally intended by PLOVER, the original source for this entry."
- },
- "217": {
- "title": "DEPRECATED: Failure to Protect Stored Data from Modification",
- "description": "This entry has been deprecated because it incorporated and confused multiple weaknesses. The issues formerly covered in this entry can be found at CWE-766 and CWE-767."
- },
- "218": {
- "title": "DEPRECATED: Failure to provide confidentiality for stored data",
- "description": "This weakness has been deprecated because it was a duplicate of CWE-493. All content has been transferred to CWE-493."
- },
- "219": {
- "title": "Storage of File with Sensitive Data Under Web Root",
- "description": "The product stores sensitive data under the web document root with insufficient access control, which might make it accessible to untrusted parties."
- },
- "220": {
- "title": "Storage of File With Sensitive Data Under FTP Root",
- "description": "The product stores sensitive data under the FTP server root with insufficient access control, which might make it accessible to untrusted parties."
- },
- "221": {
- "title": "Information Loss or Omission",
- "description": "The product does not record, or improperly records, security-relevant information that leads to an incorrect decision or hampers later analysis."
- },
- "222": {
- "title": "Truncation of Security-relevant Information",
- "description": "The product truncates the display, recording, or processing of security-relevant information in a way that can obscure the source or nature of an attack."
- },
- "223": {
- "title": "Omission of Security-relevant Information",
- "description": "The product does not record or display information that would be important for identifying the source or nature of an attack, or determining if an action is safe."
- },
- "224": {
- "title": "Obscured Security-relevant Information by Alternate Name",
- "description": "The product records security-relevant information according to an alternate name of the affected entity, instead of the canonical name."
- },
- "225": {
- "title": "DEPRECATED: General Information Management Problems",
- "description": "This weakness can be found at CWE-199."
- },
- "226": {
- "title": "Sensitive Information in Resource Not Removed Before Reuse",
- "description": "The product releases a resource such as memory or a file so that it can be made available for reuse, but it does not clear or \"zeroize\" the information contained in the resource before the product performs a critical state transition or makes the resource available for reuse by other entities."
- },
- "228": {
- "title": "Improper Handling of Syntactically Invalid Structure",
- "description": "The product does not handle or incorrectly handles input that is not syntactically well-formed with respect to the associated specification."
- },
- "229": {
- "title": "Improper Handling of Values",
- "description": "The product does not properly handle when the expected number of values for parameters, fields, or arguments is not provided in input, or if those values are undefined."
- },
- "230": {
- "title": "Improper Handling of Missing Values",
- "description": "The product does not handle or incorrectly handles when a parameter, field, or argument name is specified, but the associated value is missing, i.e. it is empty, blank, or null."
- },
- "231": {
- "title": "Improper Handling of Extra Values",
- "description": "The product does not handle or incorrectly handles when more values are provided than expected."
- },
- "232": {
- "title": "Improper Handling of Undefined Values",
- "description": "The product does not handle or incorrectly handles when a value is not defined or supported for the associated parameter, field, or argument name."
- },
- "233": {
- "title": "Improper Handling of Parameters",
- "description": "The product does not properly handle when the expected number of parameters, fields, or arguments is not provided in input, or if those parameters are undefined."
- },
- "234": {
- "title": "Failure to Handle Missing Parameter",
- "description": "If too few arguments are sent to a function, the function will still pop the expected number of arguments from the stack. Potentially, a variable number of arguments could be exhausted in a function as well."
- },
- "235": {
- "title": "Improper Handling of Extra Parameters",
- "description": "The product does not handle or incorrectly handles when the number of parameters, fields, or arguments with the same name exceeds the expected amount."
- },
- "236": {
- "title": "Improper Handling of Undefined Parameters",
- "description": "The product does not handle or incorrectly handles when a particular parameter, field, or argument name is not defined or supported by the product."
- },
- "237": {
- "title": "Improper Handling of Structural Elements",
- "description": "The product does not handle or incorrectly handles inputs that are related to complex structures."
- },
- "238": {
- "title": "Improper Handling of Incomplete Structural Elements",
- "description": "The product does not handle or incorrectly handles when a particular structural element is not completely specified."
- },
- "239": {
- "title": "Failure to Handle Incomplete Element",
- "description": "The product does not properly handle when a particular element is not completely specified."
- },
- "240": {
- "title": "Improper Handling of Inconsistent Structural Elements",
- "description": "The product does not handle or incorrectly handles when two or more structural elements should be consistent, but are not."
- },
- "241": {
- "title": "Improper Handling of Unexpected Data Type",
- "description": "The product does not handle or incorrectly handles when a particular element is not the expected type, e.g. it expects a digit (0-9) but is provided with a letter (A-Z)."
- },
- "242": {
- "title": "Use of Inherently Dangerous Function",
- "description": "The product calls a function that can never be guaranteed to work safely."
- },
- "243": {
- "title": "Creation of chroot Jail Without Changing Working Directory",
- "description": "The product uses the chroot() system call to create a jail, but does not change the working directory afterward. This does not prevent access to files outside of the jail."
- },
- "244": {
- "title": "Improper Clearing of Heap Memory Before Release ('Heap Inspection')",
- "description": "Using realloc() to resize buffers that store sensitive information can leave the sensitive information exposed to attack, because it is not removed from memory."
- },
- "245": {
- "title": "J2EE Bad Practices: Direct Management of Connections",
- "description": "The J2EE application directly manages connections, instead of using the container's connection management facilities."
- },
- "246": {
- "title": "J2EE Bad Practices: Direct Use of Sockets",
- "description": "The J2EE application directly uses sockets instead of using framework method calls."
- },
- "247": {
- "title": "DEPRECATED: Reliance on DNS Lookups in a Security Decision",
- "description": "This entry has been deprecated because it was a duplicate of CWE-350. All content has been transferred to CWE-350."
- },
- "248": {
- "title": "Uncaught Exception",
- "description": "An exception is thrown from a function, but it is not caught."
- },
- "249": {
- "title": "DEPRECATED: Often Misused: Path Manipulation",
- "description": "This entry has been deprecated because of name\n\tconfusion and an accidental combination of multiple\n\tweaknesses. Most of its content has been transferred to\n\tCWE-785."
- },
- "250": {
- "title": "Execution with Unnecessary Privileges",
- "description": "The product performs an operation at a privilege level that is higher than the minimum level required, which creates new weaknesses or amplifies the consequences of other weaknesses."
- },
- "252": {
- "title": "Unchecked Return Value",
- "description": "The product does not check the return value from a method or function, which can prevent it from detecting unexpected states and conditions."
- },
- "253": {
- "title": "Incorrect Check of Function Return Value",
- "description": "The product incorrectly checks a return value from a function, which prevents it from detecting errors or exceptional conditions."
- },
- "256": {
- "title": "Plaintext Storage of a Password",
- "description": "Storing a password in plaintext may result in a system compromise."
- },
- "257": {
- "title": "Storing Passwords in a Recoverable Format",
- "description": "The storage of passwords in a recoverable format makes them subject to password reuse attacks by malicious users. In fact, it should be noted that recoverable encrypted passwords provide no significant benefit over plaintext passwords since they are subject not only to reuse by malicious attackers but also by malicious insiders. If a system administrator can recover a password directly, or use a brute force search on the available information, the administrator can use the password on other accounts."
- },
- "258": {
- "title": "Empty Password in Configuration File",
- "description": "Using an empty string as a password is insecure."
- },
- "259": {
- "title": "Use of Hard-coded Password",
- "description": "The product contains a hard-coded password, which it uses for its own inbound authentication or for outbound communication to external components."
- },
- "260": {
- "title": "Password in Configuration File",
- "description": "The product stores a password in a configuration file that might be accessible to actors who do not know the password."
- },
- "261": {
- "title": "Weak Encoding for Password",
- "description": "Obscuring a password with a trivial encoding does not protect the password."
- },
- "262": {
- "title": "Not Using Password Aging",
- "description": "The product does not have a mechanism in place for managing password aging."
- },
- "263": {
- "title": "Password Aging with Long Expiration",
- "description": "The product supports password aging, but the expiration period is too long."
- },
- "266": {
- "title": "Incorrect Privilege Assignment",
- "description": "A product incorrectly assigns a privilege to a particular actor, creating an unintended sphere of control for that actor."
- },
- "267": {
- "title": "Privilege Defined With Unsafe Actions",
- "description": "A particular privilege, role, capability, or right can be used to perform unsafe actions that were not intended, even when it is assigned to the correct entity."
- },
- "268": {
- "title": "Privilege Chaining",
- "description": "Two distinct privileges, roles, capabilities, or rights can be combined in a way that allows an entity to perform unsafe actions that would not be allowed without that combination."
- },
- "269": {
- "title": "Improper Privilege Management",
- "description": "The product does not properly assign, modify, track, or check privileges for an actor, creating an unintended sphere of control for that actor."
- },
- "270": {
- "title": "Privilege Context Switching Error",
- "description": "The product does not properly manage privileges while it is switching between different contexts that have different privileges or spheres of control."
- },
- "271": {
- "title": "Privilege Dropping / Lowering Errors",
- "description": "The product does not drop privileges before passing control of a resource to an actor that does not have those privileges."
- },
- "272": {
- "title": "Least Privilege Violation",
- "description": "The elevated privilege level required to perform operations such as chroot() should be dropped immediately after the operation is performed."
- },
- "273": {
- "title": "Improper Check for Dropped Privileges",
- "description": "The product attempts to drop privileges but does not check or incorrectly checks to see if the drop succeeded."
- },
- "274": {
- "title": "Improper Handling of Insufficient Privileges",
- "description": "The product does not handle or incorrectly handles when it has insufficient privileges to perform an operation, leading to resultant weaknesses."
- },
- "276": {
- "title": "Incorrect Default Permissions",
- "description": "During installation, installed file permissions are set to allow anyone to modify those files."
- },
- "277": {
- "title": "Insecure Inherited Permissions",
- "description": "A product defines a set of insecure permissions that are inherited by objects that are created by the program."
- },
- "278": {
- "title": "Insecure Preserved Inherited Permissions",
- "description": "A product inherits a set of insecure permissions for an object, e.g. when copying from an archive file, without user awareness or involvement."
- },
- "279": {
- "title": "Incorrect Execution-Assigned Permissions",
- "description": "While it is executing, the product sets the permissions of an object in a way that violates the intended permissions that have been specified by the user."
- },
- "280": {
- "title": "Improper Handling of Insufficient Permissions or Privileges ",
- "description": "The product does not handle or incorrectly handles when it has insufficient privileges to access resources or functionality as specified by their permissions. This may cause it to follow unexpected code paths that may leave the product in an invalid state."
- },
- "281": {
- "title": "Improper Preservation of Permissions",
- "description": "The product does not preserve permissions or incorrectly preserves permissions when copying, restoring, or sharing objects, which can cause them to have less restrictive permissions than intended."
- },
- "282": {
- "title": "Improper Ownership Management",
- "description": "The product assigns the wrong ownership, or does not properly verify the ownership, of an object or resource."
- },
- "283": {
- "title": "Unverified Ownership",
- "description": "The product does not properly verify that a critical resource is owned by the proper entity."
- },
- "284": {
- "title": "Improper Access Control",
- "description": "The product does not restrict or incorrectly restricts access to a resource from an unauthorized actor."
- },
- "285": {
- "title": "Improper Authorization",
- "description": "The product does not perform or incorrectly performs an authorization check when an actor attempts to access a resource or perform an action."
- },
- "286": {
- "title": "Incorrect User Management",
- "description": "The product does not properly manage a user within its environment."
- },
- "287": {
- "title": "Improper Authentication",
- "description": "When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct."
- },
- "288": {
- "title": "Authentication Bypass Using an Alternate Path or Channel",
- "description": "A product requires authentication, but the product has an alternate path or channel that does not require authentication."
- },
- "289": {
- "title": "Authentication Bypass by Alternate Name",
- "description": "The product performs authentication based on the name of a resource being accessed, or the name of the actor performing the access, but it does not properly check all possible names for that resource or actor."
- },
- "290": {
- "title": "Authentication Bypass by Spoofing",
- "description": "This attack-focused weakness is caused by incorrectly implemented authentication schemes that are subject to spoofing attacks."
- },
- "291": {
- "title": "Reliance on IP Address for Authentication",
- "description": "The product uses an IP address for authentication."
- },
- "292": {
- "title": "DEPRECATED: Trusting Self-reported DNS Name",
- "description": "This entry has been deprecated because it was a duplicate of CWE-350. All content has been transferred to CWE-350."
- },
- "293": {
- "title": "Using Referer Field for Authentication",
- "description": "The referer field in HTTP requests can be easily modified and, as such, is not a valid means of message integrity checking."
- },
- "294": {
- "title": "Authentication Bypass by Capture-replay",
- "description": "A capture-replay flaw exists when the design of the product makes it possible for a malicious user to sniff network traffic and bypass authentication by replaying it to the server in question to the same effect as the original message (or with minor changes)."
- },
- "295": {
- "title": "Improper Certificate Validation",
- "description": "The product does not validate, or incorrectly validates, a certificate."
- },
- "296": {
- "title": "Improper Following of a Certificate's Chain of Trust",
- "description": "The product does not follow, or incorrectly follows, the chain of trust for a certificate back to a trusted root certificate, resulting in incorrect trust of any resource that is associated with that certificate."
- },
- "297": {
- "title": "Improper Validation of Certificate with Host Mismatch",
- "description": "The product communicates with a host that provides a certificate, but the product does not properly ensure that the certificate is actually associated with that host."
- },
- "298": {
- "title": "Improper Validation of Certificate Expiration",
- "description": "A certificate expiration is not validated or is incorrectly validated, so trust may be assigned to certificates that have been abandoned due to age."
- },
- "299": {
- "title": "Improper Check for Certificate Revocation",
- "description": "The product does not check or incorrectly checks the revocation status of a certificate, which may cause it to use a certificate that has been compromised."
- },
- "300": {
- "title": "Channel Accessible by Non-Endpoint",
- "description": "The product does not adequately verify the identity of actors at both ends of a communication channel, or does not adequately ensure the integrity of the channel, in a way that allows the channel to be accessed or influenced by an actor that is not an endpoint."
- },
- "301": {
- "title": "Reflection Attack in an Authentication Protocol",
- "description": "Simple authentication protocols are subject to reflection attacks if a malicious user can use the target machine to impersonate a trusted user."
- },
- "302": {
- "title": "Authentication Bypass by Assumed-Immutable Data",
- "description": "The authentication scheme or implementation uses key data elements that are assumed to be immutable, but can be controlled or modified by the attacker."
- },
- "303": {
- "title": "Incorrect Implementation of Authentication Algorithm",
- "description": "The requirements for the product dictate the use of an established authentication algorithm, but the implementation of the algorithm is incorrect."
- },
- "304": {
- "title": "Missing Critical Step in Authentication",
- "description": "The product implements an authentication technique, but it skips a step that weakens the technique."
- },
- "305": {
- "title": "Authentication Bypass by Primary Weakness",
- "description": "The authentication algorithm is sound, but the implemented mechanism can be bypassed as the result of a separate weakness that is primary to the authentication error."
- },
- "306": {
- "title": "Missing Authentication for Critical Function",
- "description": "The product does not perform any authentication for functionality that requires a provable user identity or consumes a significant amount of resources."
- },
- "307": {
- "title": "Improper Restriction of Excessive Authentication Attempts",
- "description": "The product does not implement sufficient measures to prevent multiple failed authentication attempts within a short time frame, making it more susceptible to brute force attacks."
- },
- "308": {
- "title": "Use of Single-factor Authentication",
- "description": "The use of single-factor authentication can lead to unnecessary risk of compromise when compared with the benefits of a dual-factor authentication scheme."
- },
- "309": {
- "title": "Use of Password System for Primary Authentication",
- "description": "The use of password systems as the primary means of authentication may be subject to several flaws or shortcomings, each reducing the effectiveness of the mechanism."
- },
- "311": {
- "title": "Missing Encryption of Sensitive Data",
- "description": "The product does not encrypt sensitive or critical information before storage or transmission."
- },
- "312": {
- "title": "Cleartext Storage of Sensitive Information",
- "description": "The product stores sensitive information in cleartext within a resource that might be accessible to another control sphere."
- },
- "313": {
- "title": "Cleartext Storage in a File or on Disk",
- "description": "The product stores sensitive information in cleartext in a file, or on disk."
- },
- "314": {
- "title": "Cleartext Storage in the Registry",
- "description": "The product stores sensitive information in cleartext in the registry."
- },
- "315": {
- "title": "Cleartext Storage of Sensitive Information in a Cookie",
- "description": "The product stores sensitive information in cleartext in a cookie."
- },
- "316": {
- "title": "Cleartext Storage of Sensitive Information in Memory",
- "description": "The product stores sensitive information in cleartext in memory."
- },
- "317": {
- "title": "Cleartext Storage of Sensitive Information in GUI",
- "description": "The product stores sensitive information in cleartext within the GUI."
- },
- "318": {
- "title": "Cleartext Storage of Sensitive Information in Executable",
- "description": "The product stores sensitive information in cleartext in an executable."
- },
- "319": {
- "title": "Cleartext Transmission of Sensitive Information",
- "description": "The product transmits sensitive or security-critical data in cleartext in a communication channel that can be sniffed by unauthorized actors."
- },
- "321": {
- "title": "Use of Hard-coded Cryptographic Key",
- "description": "The use of a hard-coded cryptographic key significantly increases the possibility that encrypted data may be recovered."
- },
- "322": {
- "title": "Key Exchange without Entity Authentication",
- "description": "The product performs a key exchange with an actor without verifying the identity of that actor."
- },
- "323": {
- "title": "Reusing a Nonce, Key Pair in Encryption",
- "description": "Nonces should be used for the present occasion and only once."
- },
- "324": {
- "title": "Use of a Key Past its Expiration Date",
- "description": "The product uses a cryptographic key or password past its expiration date, which diminishes its safety significantly by increasing the timing window for cracking attacks against that key."
- },
- "325": {
- "title": "Missing Cryptographic Step",
- "description": "The product does not implement a required step in a cryptographic algorithm, resulting in weaker encryption than advertised by the algorithm."
- },
- "326": {
- "title": "Inadequate Encryption Strength",
- "description": "The product stores or transmits sensitive data using an encryption scheme that is theoretically sound, but is not strong enough for the level of protection required."
- },
- "327": {
- "title": "Use of a Broken or Risky Cryptographic Algorithm",
- "description": "The product uses a broken or risky cryptographic algorithm or protocol."
- },
- "328": {
- "title": "Use of Weak Hash",
- "description": "The product uses an algorithm that produces a digest (output value) that does not meet security expectations for a hash function that allows an adversary to reasonably determine the original input (preimage attack), find another input that can produce the same hash (2nd preimage attack), or find multiple inputs that evaluate to the same hash (birthday attack)."
- },
- "329": {
- "title": "Generation of Predictable IV with CBC Mode",
- "description": "The product generates and uses a predictable initialization Vector (IV) with Cipher Block Chaining (CBC) Mode, which causes algorithms to be susceptible to dictionary attacks when they are encrypted under the same key."
- },
- "330": {
- "title": "Use of Insufficiently Random Values",
- "description": "The product uses insufficiently random numbers or values in a security context that depends on unpredictable numbers."
- },
- "331": {
- "title": "Insufficient Entropy",
- "description": "The product uses an algorithm or scheme that produces insufficient entropy, leaving patterns or clusters of values that are more likely to occur than others."
- },
- "332": {
- "title": "Insufficient Entropy in PRNG",
- "description": "The lack of entropy available for, or used by, a Pseudo-Random Number Generator (PRNG) can be a stability and security threat."
- },
- "333": {
- "title": "Improper Handling of Insufficient Entropy in TRNG",
- "description": "True random number generators (TRNG) generally have a limited source of entropy and therefore can fail or block."
- },
- "334": {
- "title": "Small Space of Random Values",
- "description": "The number of possible random values is smaller than needed by the product, making it more susceptible to brute force attacks."
- },
- "335": {
- "title": "Incorrect Usage of Seeds in Pseudo-Random Number Generator (PRNG)",
- "description": "The product uses a Pseudo-Random Number Generator (PRNG) but does not correctly manage seeds."
- },
- "336": {
- "title": "Same Seed in Pseudo-Random Number Generator (PRNG)",
- "description": "A Pseudo-Random Number Generator (PRNG) uses the same seed each time the product is initialized."
- },
- "337": {
- "title": "Predictable Seed in Pseudo-Random Number Generator (PRNG)",
- "description": "A Pseudo-Random Number Generator (PRNG) is initialized from a predictable seed, such as the process ID or system time."
- },
- "338": {
- "title": "Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)",
- "description": "The product uses a Pseudo-Random Number Generator (PRNG) in a security context, but the PRNG's algorithm is not cryptographically strong."
- },
- "339": {
- "title": "Small Seed Space in PRNG",
- "description": "A Pseudo-Random Number Generator (PRNG) uses a relatively small seed space, which makes it more susceptible to brute force attacks."
- },
- "340": {
- "title": "Generation of Predictable Numbers or Identifiers",
- "description": "The product uses a scheme that generates numbers or identifiers that are more predictable than required."
- },
- "341": {
- "title": "Predictable from Observable State",
- "description": "A number or object is predictable based on observations that the attacker can make about the state of the system or network, such as time, process ID, etc."
- },
- "342": {
- "title": "Predictable Exact Value from Previous Values",
- "description": "An exact value or random number can be precisely predicted by observing previous values."
- },
- "343": {
- "title": "Predictable Value Range from Previous Values",
- "description": "The product's random number generator produces a series of values which, when observed, can be used to infer a relatively small range of possibilities for the next value that could be generated."
- },
- "344": {
- "title": "Use of Invariant Value in Dynamically Changing Context",
- "description": "The product uses a constant value, name, or reference, but this value can (or should) vary across different environments."
- },
- "345": {
- "title": "Insufficient Verification of Data Authenticity",
- "description": "The product does not sufficiently verify the origin or authenticity of data, in a way that causes it to accept invalid data."
- },
- "346": {
- "title": "Origin Validation Error",
- "description": "The product does not properly verify that the source of data or communication is valid."
- },
- "347": {
- "title": "Improper Verification of Cryptographic Signature",
- "description": "The product does not verify, or incorrectly verifies, the cryptographic signature for data."
- },
- "348": {
- "title": "Use of Less Trusted Source",
- "description": "The product has two different sources of the same data or information, but it uses the source that has less support for verification, is less trusted, or is less resistant to attack."
- },
- "349": {
- "title": "Acceptance of Extraneous Untrusted Data With Trusted Data",
- "description": "The product, when processing trusted data, accepts any untrusted data that is also included with the trusted data, treating the untrusted data as if it were trusted."
- },
- "350": {
- "title": "Reliance on Reverse DNS Resolution for a Security-Critical Action",
- "description": "The product performs reverse DNS resolution on an IP address to obtain the hostname and make a security decision, but it does not properly ensure that the IP address is truly associated with the hostname."
- },
- "351": {
- "title": "Insufficient Type Distinction",
- "description": "The product does not properly distinguish between different types of elements in a way that leads to insecure behavior."
- },
- "352": {
- "title": "Cross-Site Request Forgery (CSRF)",
- "description": "The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request."
- },
- "353": {
- "title": "Missing Support for Integrity Check",
- "description": "The product uses a transmission protocol that does not include a mechanism for verifying the integrity of the data during transmission, such as a checksum."
- },
- "354": {
- "title": "Improper Validation of Integrity Check Value",
- "description": "The product does not validate or incorrectly validates the integrity check values or \"checksums\" of a message. This may prevent it from detecting if the data has been modified or corrupted in transmission."
- },
- "356": {
- "title": "Product UI does not Warn User of Unsafe Actions",
- "description": "The product's user interface does not warn the user before undertaking an unsafe action on behalf of that user. This makes it easier for attackers to trick users into inflicting damage to their system."
- },
- "357": {
- "title": "Insufficient UI Warning of Dangerous Operations",
- "description": "The user interface provides a warning to a user regarding dangerous or sensitive operations, but the warning is not noticeable enough to warrant attention."
- },
- "358": {
- "title": "Improperly Implemented Security Check for Standard",
- "description": "The product does not implement or incorrectly implements one or more security-relevant checks as specified by the design of a standardized algorithm, protocol, or technique."
- },
- "359": {
- "title": "Exposure of Private Personal Information to an Unauthorized Actor",
- "description": "The product does not properly prevent a person's private, personal information from being accessed by actors who either (1) are not explicitly authorized to access the information or (2) do not have the implicit consent of the person about whom the information is collected."
- },
- "360": {
- "title": "Trust of System Event Data",
- "description": "Security based on event locations are insecure and can be spoofed."
- },
- "362": {
- "title": "Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')",
- "description": "The product contains a code sequence that can run concurrently with other code, and the code sequence requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence that is operating concurrently."
- },
- "363": {
- "title": "Race Condition Enabling Link Following",
- "description": "The product checks the status of a file or directory before accessing it, which produces a race condition in which the file can be replaced with a link before the access is performed, causing the product to access the wrong file."
- },
- "364": {
- "title": "Signal Handler Race Condition",
- "description": "The product uses a signal handler that introduces a race condition."
- },
- "365": {
- "title": "DEPRECATED: Race Condition in Switch",
- "description": "This entry has been deprecated. There are no documented cases in which a switch's control expression is evaluated more than once."
- },
- "366": {
- "title": "Race Condition within a Thread",
- "description": "If two threads of execution use a resource simultaneously, there exists the possibility that resources may be used while invalid, in turn making the state of execution undefined."
- },
- "367": {
- "title": "Time-of-check Time-of-use (TOCTOU) Race Condition",
- "description": "The product checks the state of a resource before using that resource, but the resource's state can change between the check and the use in a way that invalidates the results of the check. This can cause the product to perform invalid actions when the resource is in an unexpected state."
- },
- "368": {
- "title": "Context Switching Race Condition",
- "description": "A product performs a series of non-atomic actions to switch between contexts that cross privilege or other security boundaries, but a race condition allows an attacker to modify or misrepresent the product's behavior during the switch."
- },
- "369": {
- "title": "Divide By Zero",
- "description": "The product divides a value by zero."
- },
- "370": {
- "title": "Missing Check for Certificate Revocation after Initial Check",
- "description": "The product does not check the revocation status of a certificate after its initial revocation check, which can cause the product to perform privileged actions even after the certificate is revoked at a later time."
- },
- "372": {
- "title": "Incomplete Internal State Distinction",
- "description": "The product does not properly determine which state it is in, causing it to assume it is in state X when in fact it is in state Y, causing it to perform incorrect operations in a security-relevant manner."
- },
- "373": {
- "title": "DEPRECATED: State Synchronization Error",
- "description": "This entry was deprecated because it overlapped the same concepts as race condition (CWE-362) and Improper Synchronization (CWE-662)."
- },
- "374": {
- "title": "Passing Mutable Objects to an Untrusted Method",
- "description": "The product sends non-cloned mutable data as an argument to a method or function."
- },
- "375": {
- "title": "Returning a Mutable Object to an Untrusted Caller",
- "description": "Sending non-cloned mutable data as a return value may result in that data being altered or deleted by the calling function."
- },
- "377": {
- "title": "Insecure Temporary File",
- "description": "Creating and using insecure temporary files can leave application and system data vulnerable to attack."
- },
- "378": {
- "title": "Creation of Temporary File With Insecure Permissions",
- "description": "Opening temporary files without appropriate measures or controls can leave the file, its contents and any function that it impacts vulnerable to attack."
- },
- "379": {
- "title": "Creation of Temporary File in Directory with Insecure Permissions",
- "description": "The product creates a temporary file in a directory whose permissions allow unintended actors to determine the file's existence or otherwise access that file."
- },
- "382": {
- "title": "J2EE Bad Practices: Use of System.exit()",
- "description": "A J2EE application uses System.exit(), which also shuts down its container."
- },
- "383": {
- "title": "J2EE Bad Practices: Direct Use of Threads",
- "description": "Thread management in a Web application is forbidden in some circumstances and is always highly error prone."
- },
- "384": {
- "title": "Session Fixation",
- "description": "Authenticating a user, or otherwise establishing a new user session, without invalidating any existing session identifier gives an attacker the opportunity to steal authenticated sessions."
- },
- "385": {
- "title": "Covert Timing Channel",
- "description": "Covert timing channels convey information by modulating some aspect of system behavior over time, so that the program receiving the information can observe system behavior and infer protected information."
- },
- "386": {
- "title": "Symbolic Name not Mapping to Correct Object",
- "description": "A constant symbolic reference to an object is used, even though the reference can resolve to a different object over time."
- },
- "390": {
- "title": "Detection of Error Condition Without Action",
- "description": "The product detects a specific error, but takes no actions to handle the error."
- },
- "391": {
- "title": "Unchecked Error Condition",
- "description": "[PLANNED FOR DEPRECATION. SEE MAINTENANCE NOTES AND CONSIDER CWE-252, CWE-248, OR CWE-1069.] Ignoring exceptions and other error conditions may allow an attacker to induce unexpected behavior unnoticed."
- },
- "392": {
- "title": "Missing Report of Error Condition",
- "description": "The product encounters an error but does not provide a status code or return value to indicate that an error has occurred."
- },
- "393": {
- "title": "Return of Wrong Status Code",
- "description": "A function or operation returns an incorrect return value or status code that does not indicate an error, but causes the product to modify its behavior based on the incorrect result."
- },
- "394": {
- "title": "Unexpected Status Code or Return Value",
- "description": "The product does not properly check when a function or operation returns a value that is legitimate for the function, but is not expected by the product."
- },
- "395": {
- "title": "Use of NullPointerException Catch to Detect NULL Pointer Dereference",
- "description": "Catching NullPointerException should not be used as an alternative to programmatic checks to prevent dereferencing a null pointer."
- },
- "396": {
- "title": "Declaration of Catch for Generic Exception",
- "description": "Catching overly broad exceptions promotes complex error handling code that is more likely to contain security vulnerabilities."
- },
- "397": {
- "title": "Declaration of Throws for Generic Exception",
- "description": "Throwing overly broad exceptions promotes complex error handling code that is more likely to contain security vulnerabilities."
- },
- "400": {
- "title": "Uncontrolled Resource Consumption",
- "description": "The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources."
- },
- "401": {
- "title": "Missing Release of Memory after Effective Lifetime",
- "description": "The product does not sufficiently track and release allocated memory after it has been used, which slowly consumes remaining memory."
- },
- "402": {
- "title": "Transmission of Private Resources into a New Sphere ('Resource Leak')",
- "description": "The product makes resources available to untrusted parties when those resources are only intended to be accessed by the product."
- },
- "403": {
- "title": "Exposure of File Descriptor to Unintended Control Sphere ('File Descriptor Leak')",
- "description": "A process does not close sensitive file descriptors before invoking a child process, which allows the child to perform unauthorized I/O operations using those descriptors."
- },
- "404": {
- "title": "Improper Resource Shutdown or Release",
- "description": "The product does not release or incorrectly releases a resource before it is made available for re-use."
- },
- "405": {
- "title": "Asymmetric Resource Consumption (Amplification)",
- "description": "The product does not properly control situations in which an adversary can cause the product to consume or produce excessive resources without requiring the adversary to invest equivalent work or otherwise prove authorization, i.e., the adversary's influence is \"asymmetric.\""
- },
- "406": {
- "title": "Insufficient Control of Network Message Volume (Network Amplification)",
- "description": "The product does not sufficiently monitor or control transmitted network traffic volume, so that an actor can cause the product to transmit more traffic than should be allowed for that actor."
- },
- "407": {
- "title": "Inefficient Algorithmic Complexity",
- "description": "An algorithm in a product has an inefficient worst-case computational complexity that may be detrimental to system performance and can be triggered by an attacker, typically using crafted manipulations that ensure that the worst case is being reached."
- },
- "408": {
- "title": "Incorrect Behavior Order: Early Amplification",
- "description": "The product allows an entity to perform a legitimate but expensive operation before authentication or authorization has taken place."
- },
- "409": {
- "title": "Improper Handling of Highly Compressed Data (Data Amplification)",
- "description": "The product does not handle or incorrectly handles a compressed input with a very high compression ratio that produces a large output."
- },
- "410": {
- "title": "Insufficient Resource Pool",
- "description": "The product's resource pool is not large enough to handle peak demand, which allows an attacker to prevent others from accessing the resource by using a (relatively) large number of requests for resources."
- },
- "412": {
- "title": "Unrestricted Externally Accessible Lock",
- "description": "The product properly checks for the existence of a lock, but the lock can be externally controlled or influenced by an actor that is outside of the intended sphere of control."
- },
- "413": {
- "title": "Improper Resource Locking",
- "description": "The product does not lock or does not correctly lock a resource when the product must have exclusive access to the resource."
- },
- "414": {
- "title": "Missing Lock Check",
- "description": "A product does not check to see if a lock is present before performing sensitive operations on a resource."
- },
- "415": {
- "title": "Double Free",
- "description": "The product calls free() twice on the same memory address, potentially leading to modification of unexpected memory locations."
- },
- "416": {
- "title": "Use After Free",
- "description": "Referencing memory after it has been freed can cause a program to crash, use unexpected values, or execute code."
- },
- "419": {
- "title": "Unprotected Primary Channel",
- "description": "The product uses a primary channel for administration or restricted functionality, but it does not properly protect the channel."
- },
- "420": {
- "title": "Unprotected Alternate Channel",
- "description": "The product protects a primary channel, but it does not use the same level of protection for an alternate channel."
- },
- "421": {
- "title": "Race Condition During Access to Alternate Channel",
- "description": "The product opens an alternate channel to communicate with an authorized user, but the channel is accessible to other actors."
- },
- "422": {
- "title": "Unprotected Windows Messaging Channel ('Shatter')",
- "description": "The product does not properly verify the source of a message in the Windows Messaging System while running at elevated privileges, creating an alternate channel through which an attacker can directly send a message to the product."
- },
- "423": {
- "title": "DEPRECATED: Proxied Trusted Channel",
- "description": "This entry has been deprecated because it was a duplicate of CWE-441. All content has been transferred to CWE-441."
- },
- "424": {
- "title": "Improper Protection of Alternate Path",
- "description": "The product does not sufficiently protect all possible paths that a user can take to access restricted functionality or resources."
- },
- "425": {
- "title": "Direct Request ('Forced Browsing')",
- "description": "The web application does not adequately enforce appropriate authorization on all restricted URLs, scripts, or files."
- },
- "426": {
- "title": "Untrusted Search Path",
- "description": "The product searches for critical resources using an externally-supplied search path that can point to resources that are not under the product's direct control."
- },
- "427": {
- "title": "Uncontrolled Search Path Element",
- "description": "The product uses a fixed or controlled search path to find resources, but one or more locations in that path can be under the control of unintended actors."
- },
- "428": {
- "title": "Unquoted Search Path or Element",
- "description": "The product uses a search path that contains an unquoted element, in which the element contains whitespace or other separators. This can cause the product to access resources in a parent path."
- },
- "430": {
- "title": "Deployment of Wrong Handler",
- "description": "The wrong \"handler\" is assigned to process an object."
- },
- "431": {
- "title": "Missing Handler",
- "description": "A handler is not available or implemented."
- },
- "432": {
- "title": "Dangerous Signal Handler not Disabled During Sensitive Operations",
- "description": "The product uses a signal handler that shares state with other signal handlers, but it does not properly mask or prevent those signal handlers from being invoked while the original signal handler is still running."
- },
- "433": {
- "title": "Unparsed Raw Web Content Delivery",
- "description": "The product stores raw content or supporting code under the web document root with an extension that is not specifically handled by the server."
- },
- "434": {
- "title": "Unrestricted Upload of File with Dangerous Type",
- "description": "The product allows the attacker to upload or transfer files of dangerous types that can be automatically processed within the product's environment."
- },
- "435": {
- "title": "Improper Interaction Between Multiple Correctly-Behaving Entities",
- "description": "An interaction error occurs when two entities have correct behavior when running independently of each other, but when they are integrated as components in a larger system or process, they introduce incorrect behaviors that may cause resultant weaknesses."
- },
- "436": {
- "title": "Interpretation Conflict",
- "description": "Product A handles inputs or steps differently than Product B, which causes A to perform incorrect actions based on its perception of B's state."
- },
- "437": {
- "title": "Incomplete Model of Endpoint Features",
- "description": "A product acts as an intermediary or monitor between two or more endpoints, but it does not have a complete model of an endpoint's features, behaviors, or state, potentially causing the product to perform incorrect actions based on this incomplete model."
- },
- "439": {
- "title": "Behavioral Change in New Version or Environment",
- "description": "A's behavior or functionality changes with a new version of A, or a new environment, which is not known (or manageable) by B."
- },
- "440": {
- "title": "Expected Behavior Violation",
- "description": "A feature, API, or function does not perform according to its specification."
- },
- "441": {
- "title": "Unintended Proxy or Intermediary ('Confused Deputy')",
- "description": "The product receives a request, message, or directive from an upstream component, but the product does not sufficiently preserve the original source of the request before forwarding the request to an external actor that is outside of the product's control sphere. This causes the product to appear to be the source of the request, leading it to act as a proxy or other intermediary between the upstream component and the external actor."
- },
- "443": {
- "title": "DEPRECATED: HTTP response splitting",
- "description": "This weakness can be found at CWE-113."
- },
- "444": {
- "title": "Inconsistent Interpretation of HTTP Requests ('HTTP Request/Response Smuggling')",
- "description": "The product acts as an intermediary HTTP agent\n (such as a proxy or firewall) in the data flow between two\n entities such as a client and server, but it does not\n interpret malformed HTTP requests or responses in ways that\n are consistent with how the messages will be processed by\n those entities that are at the ultimate destination."
- },
- "446": {
- "title": "UI Discrepancy for Security Feature",
- "description": "The user interface does not correctly enable or configure a security feature, but the interface provides feedback that causes the user to believe that the feature is in a secure state."
- },
- "447": {
- "title": "Unimplemented or Unsupported Feature in UI",
- "description": "A UI function for a security feature appears to be supported and gives feedback to the user that suggests that it is supported, but the underlying functionality is not implemented."
- },
- "448": {
- "title": "Obsolete Feature in UI",
- "description": "A UI function is obsolete and the product does not warn the user."
- },
- "449": {
- "title": "The UI Performs the Wrong Action",
- "description": "The UI performs the wrong action with respect to the user's request."
- },
- "450": {
- "title": "Multiple Interpretations of UI Input",
- "description": "The UI has multiple interpretations of user input but does not prompt the user when it selects the less secure interpretation."
- },
- "451": {
- "title": "User Interface (UI) Misrepresentation of Critical Information",
- "description": "The user interface (UI) does not properly represent critical information to the user, allowing the information - or its source - to be obscured or spoofed. This is often a component in phishing attacks."
- },
- "453": {
- "title": "Insecure Default Variable Initialization",
- "description": "The product, by default, initializes an internal variable with an insecure or less secure value than is possible."
- },
- "454": {
- "title": "External Initialization of Trusted Variables or Data Stores",
- "description": "The product initializes critical internal variables or data stores using inputs that can be modified by untrusted actors."
- },
- "455": {
- "title": "Non-exit on Failed Initialization",
- "description": "The product does not exit or otherwise modify its operation when security-relevant errors occur during initialization, such as when a configuration file has a format error or a hardware security module (HSM) cannot be activated, which can cause the product to execute in a less secure fashion than intended by the administrator."
- },
- "456": {
- "title": "Missing Initialization of a Variable",
- "description": "The product does not initialize critical variables, which causes the execution environment to use unexpected values."
- },
- "457": {
- "title": "Use of Uninitialized Variable",
- "description": "The code uses a variable that has not been initialized, leading to unpredictable or unintended results."
- },
- "458": {
- "title": "DEPRECATED: Incorrect Initialization",
- "description": "This weakness has been deprecated because its name and description did not match. The description duplicated CWE-454, while the name suggested a more abstract initialization problem. Please refer to CWE-665 for the more abstract problem."
- },
- "459": {
- "title": "Incomplete Cleanup",
- "description": "The product does not properly \"clean up\" and remove temporary or supporting resources after they have been used."
- },
- "460": {
- "title": "Improper Cleanup on Thrown Exception",
- "description": "The product does not clean up its state or incorrectly cleans up its state when an exception is thrown, leading to unexpected state or control flow."
- },
- "462": {
- "title": "Duplicate Key in Associative List (Alist)",
- "description": "Duplicate keys in associative lists can lead to non-unique keys being mistaken for an error."
- },
- "463": {
- "title": "Deletion of Data Structure Sentinel",
- "description": "The accidental deletion of a data-structure sentinel can cause serious programming logic problems."
- },
- "464": {
- "title": "Addition of Data Structure Sentinel",
- "description": "The accidental addition of a data-structure sentinel can cause serious programming logic problems."
- },
- "466": {
- "title": "Return of Pointer Value Outside of Expected Range",
- "description": "A function can return a pointer to memory that is outside of the buffer that the pointer is expected to reference."
- },
- "467": {
- "title": "Use of sizeof() on a Pointer Type",
- "description": "The code calls sizeof() on a malloced pointer type, which always returns the wordsize/8. This can produce an unexpected result if the programmer intended to determine how much memory has been allocated."
- },
- "468": {
- "title": "Incorrect Pointer Scaling",
- "description": "In C and C++, one may often accidentally refer to the wrong memory due to the semantics of when math operations are implicitly scaled."
- },
- "469": {
- "title": "Use of Pointer Subtraction to Determine Size",
- "description": "The product subtracts one pointer from another in order to determine size, but this calculation can be incorrect if the pointers do not exist in the same memory chunk."
- },
- "470": {
- "title": "Use of Externally-Controlled Input to Select Classes or Code ('Unsafe Reflection')",
- "description": "The product uses external input with reflection to select which classes or code to use, but it does not sufficiently prevent the input from selecting improper classes or code."
- },
- "471": {
- "title": "Modification of Assumed-Immutable Data (MAID)",
- "description": "The product does not properly protect an assumed-immutable element from being modified by an attacker."
- },
- "472": {
- "title": "External Control of Assumed-Immutable Web Parameter",
- "description": "The web application does not sufficiently verify inputs that are assumed to be immutable but are actually externally controllable, such as hidden form fields."
- },
- "473": {
- "title": "PHP External Variable Modification",
- "description": "A PHP application does not properly protect against the modification of variables from external sources, such as query parameters or cookies. This can expose the application to numerous weaknesses that would not exist otherwise."
- },
- "474": {
- "title": "Use of Function with Inconsistent Implementations",
- "description": "The code uses a function that has inconsistent implementations across operating systems and versions."
- },
- "475": {
- "title": "Undefined Behavior for Input to API",
- "description": "The behavior of this function is undefined unless its control parameter is set to a specific value."
- },
- "476": {
- "title": "NULL Pointer Dereference",
- "description": "A NULL pointer dereference occurs when the application dereferences a pointer that it expects to be valid, but is NULL, typically causing a crash or exit."
- },
- "477": {
- "title": "Use of Obsolete Function",
- "description": "The code uses deprecated or obsolete functions, which suggests that the code has not been actively reviewed or maintained."
- },
- "478": {
- "title": "Missing Default Case in Multiple Condition Expression",
- "description": "The code does not have a default case in an expression with multiple conditions, such as a switch statement."
- },
- "479": {
- "title": "Signal Handler Use of a Non-reentrant Function",
- "description": "The product defines a signal handler that calls a non-reentrant function."
- },
- "480": {
- "title": "Use of Incorrect Operator",
- "description": "The product accidentally uses the wrong operator, which changes the logic in security-relevant ways."
- },
- "481": {
- "title": "Assigning instead of Comparing",
- "description": "The code uses an operator for assignment when the intention was to perform a comparison."
- },
- "482": {
- "title": "Comparing instead of Assigning",
- "description": "The code uses an operator for comparison when the intention was to perform an assignment."
- },
- "483": {
- "title": "Incorrect Block Delimitation",
- "description": "The code does not explicitly delimit a block that is intended to contain 2 or more statements, creating a logic error."
- },
- "484": {
- "title": "Omitted Break Statement in Switch",
- "description": "The product omits a break statement within a switch or similar construct, causing code associated with multiple conditions to execute. This can cause problems when the programmer only intended to execute code associated with one condition."
- },
- "486": {
- "title": "Comparison of Classes by Name",
- "description": "The product compares classes by name, which can cause it to use the wrong class when multiple classes can have the same name."
- },
- "487": {
- "title": "Reliance on Package-level Scope",
- "description": "Java packages are not inherently closed; therefore, relying on them for code security is not a good practice."
- },
- "488": {
- "title": "Exposure of Data Element to Wrong Session",
- "description": "The product does not sufficiently enforce boundaries between the states of different sessions, causing data to be provided to, or used by, the wrong session."
- },
- "489": {
- "title": "Active Debug Code",
- "description": "The product is deployed to unauthorized actors with debugging code still enabled or active, which can create unintended entry points or expose sensitive information."
- },
- "491": {
- "title": "Public cloneable() Method Without Final ('Object Hijack')",
- "description": "A class has a cloneable() method that is not declared final, which allows an object to be created without calling the constructor. This can cause the object to be in an unexpected state."
- },
- "492": {
- "title": "Use of Inner Class Containing Sensitive Data",
- "description": "Inner classes are translated into classes that are accessible at package scope and may expose code that the programmer intended to keep private to attackers."
- },
- "493": {
- "title": "Critical Public Variable Without Final Modifier",
- "description": "The product has a critical public variable that is not final, which allows the variable to be modified to contain unexpected values."
- },
- "494": {
- "title": "Download of Code Without Integrity Check",
- "description": "The product downloads source code or an executable from a remote location and executes the code without sufficiently verifying the origin and integrity of the code."
- },
- "495": {
- "title": "Private Data Structure Returned From A Public Method",
- "description": "The product has a method that is declared public, but returns a reference to a private data structure, which could then be modified in unexpected ways."
- },
- "496": {
- "title": "Public Data Assigned to Private Array-Typed Field",
- "description": "Assigning public data to a private array is equivalent to giving public access to the array."
- },
- "497": {
- "title": "Exposure of Sensitive System Information to an Unauthorized Control Sphere",
- "description": "The product does not properly prevent sensitive system-level information from being accessed by unauthorized actors who do not have the same level of access to the underlying system as the product does."
- },
- "498": {
- "title": "Cloneable Class Containing Sensitive Information",
- "description": "The code contains a class with sensitive data, but the class is cloneable. The data can then be accessed by cloning the class."
- },
- "499": {
- "title": "Serializable Class Containing Sensitive Data",
- "description": "The code contains a class with sensitive data, but the class does not explicitly deny serialization. The data can be accessed by serializing the class through another class."
- },
- "500": {
- "title": "Public Static Field Not Marked Final",
- "description": "An object contains a public static field that is not marked final, which might allow it to be modified in unexpected ways."
- },
- "501": {
- "title": "Trust Boundary Violation",
- "description": "The product mixes trusted and untrusted data in the same data structure or structured message."
- },
- "502": {
- "title": "Deserialization of Untrusted Data",
- "description": "The product deserializes untrusted data without sufficiently verifying that the resulting data will be valid."
- },
- "506": {
- "title": "Embedded Malicious Code",
- "description": "The product contains code that appears to be malicious in nature."
- },
- "507": {
- "title": "Trojan Horse",
- "description": "The product appears to contain benign or useful functionality, but it also contains code that is hidden from normal operation that violates the intended security policy of the user or the system administrator."
- },
- "508": {
- "title": "Non-Replicating Malicious Code",
- "description": "Non-replicating malicious code only resides on the target system or product that is attacked; it does not attempt to spread to other systems."
- },
- "509": {
- "title": "Replicating Malicious Code (Virus or Worm)",
- "description": "Replicating malicious code, including viruses and worms, will attempt to attack other systems once it has successfully compromised the target system or the product."
- },
- "510": {
- "title": "Trapdoor",
- "description": "A trapdoor is a hidden piece of code that responds to a special input, allowing its user access to resources without passing through the normal security enforcement mechanism."
- },
- "511": {
- "title": "Logic/Time Bomb",
- "description": "The product contains code that is designed to disrupt the legitimate operation of the product (or its environment) when a certain time passes, or when a certain logical condition is met."
- },
- "512": {
- "title": "Spyware",
- "description": "The product collects personally identifiable information about a human user or the user's activities, but the product accesses this information using other resources besides itself, and it does not require that user's explicit approval or direct input into the product."
- },
- "514": {
- "title": "Covert Channel",
- "description": "A covert channel is a path that can be used to transfer information in a way not intended by the system's designers."
- },
- "515": {
- "title": "Covert Storage Channel",
- "description": "A covert storage channel transfers information through the setting of bits by one program and the reading of those bits by another. What distinguishes this case from that of ordinary operation is that the bits are used to convey encoded information."
- },
- "516": {
- "title": "DEPRECATED: Covert Timing Channel",
- "description": "This weakness can be found at CWE-385."
- },
- "520": {
- "title": ".NET Misconfiguration: Use of Impersonation",
- "description": "Allowing a .NET application to run at potentially escalated levels of access to the underlying operating and file systems can be dangerous and result in various forms of attacks."
- },
- "521": {
- "title": "Weak Password Requirements",
- "description": "The product does not require that users should have strong passwords, which makes it easier for attackers to compromise user accounts."
- },
- "522": {
- "title": "Insufficiently Protected Credentials",
- "description": "The product transmits or stores authentication credentials, but it uses an insecure method that is susceptible to unauthorized interception and/or retrieval."
- },
- "523": {
- "title": "Unprotected Transport of Credentials",
- "description": "Login pages do not use adequate measures to protect the user name and password while they are in transit from the client to the server."
- },
- "524": {
- "title": "Use of Cache Containing Sensitive Information",
- "description": "The code uses a cache that contains sensitive information, but the cache can be read by an actor outside of the intended control sphere."
- },
- "525": {
- "title": "Use of Web Browser Cache Containing Sensitive Information",
- "description": "The web application does not use an appropriate caching policy that specifies the extent to which each web page and associated form fields should be cached."
- },
- "526": {
- "title": "Cleartext Storage of Sensitive Information in an Environment Variable",
- "description": "The product uses an environment variable to store unencrypted sensitive information."
- },
- "527": {
- "title": "Exposure of Version-Control Repository to an Unauthorized Control Sphere",
- "description": "The product stores a CVS, git, or other repository in a directory, archive, or other resource that is stored, transferred, or otherwise made accessible to unauthorized actors."
- },
- "528": {
- "title": "Exposure of Core Dump File to an Unauthorized Control Sphere",
- "description": "The product generates a core dump file in a directory, archive, or other resource that is stored, transferred, or otherwise made accessible to unauthorized actors."
- },
- "529": {
- "title": "Exposure of Access Control List Files to an Unauthorized Control Sphere",
- "description": "The product stores access control list files in a directory or other container that is accessible to actors outside of the intended control sphere."
- },
- "530": {
- "title": "Exposure of Backup File to an Unauthorized Control Sphere",
- "description": "A backup file is stored in a directory or archive that is made accessible to unauthorized actors."
- },
- "531": {
- "title": "Inclusion of Sensitive Information in Test Code",
- "description": "Accessible test applications can pose a variety of security risks. Since developers or administrators rarely consider that someone besides themselves would even know about the existence of these applications, it is common for them to contain sensitive information or functions."
- },
- "532": {
- "title": "Insertion of Sensitive Information into Log File",
- "description": "Information written to log files can be of a sensitive nature and give valuable guidance to an attacker or expose sensitive user information."
- },
- "533": {
- "title": "DEPRECATED: Information Exposure Through Server Log Files",
- "description": "This entry has been deprecated because its abstraction was too low-level. See CWE-532."
- },
- "534": {
- "title": "DEPRECATED: Information Exposure Through Debug Log Files",
- "description": "This entry has been deprecated because its abstraction was too low-level. See CWE-532."
- },
- "535": {
- "title": "Exposure of Information Through Shell Error Message",
- "description": "A command shell error message indicates that there exists an unhandled exception in the web application code. In many cases, an attacker can leverage the conditions that cause these errors in order to gain unauthorized access to the system."
- },
- "536": {
- "title": "Servlet Runtime Error Message Containing Sensitive Information",
- "description": "A servlet error message indicates that there exists an unhandled exception in your web application code and may provide useful information to an attacker."
- },
- "537": {
- "title": "Java Runtime Error Message Containing Sensitive Information",
- "description": "In many cases, an attacker can leverage the conditions that cause unhandled exception errors in order to gain unauthorized access to the system."
- },
- "538": {
- "title": "Insertion of Sensitive Information into Externally-Accessible File or Directory",
- "description": "The product places sensitive information into files or directories that are accessible to actors who are allowed to have access to the files, but not to the sensitive information."
- },
- "539": {
- "title": "Use of Persistent Cookies Containing Sensitive Information",
- "description": "The web application uses persistent cookies, but the cookies contain sensitive information."
- },
- "540": {
- "title": "Inclusion of Sensitive Information in Source Code",
- "description": "Source code on a web server or repository often contains sensitive information and should generally not be accessible to users."
- },
- "541": {
- "title": "Inclusion of Sensitive Information in an Include File",
- "description": "If an include file source is accessible, the file can contain usernames and passwords, as well as sensitive information pertaining to the application and system."
- },
- "542": {
- "title": "DEPRECATED: Information Exposure Through Cleanup Log Files",
- "description": "This entry has been deprecated because its abstraction was too low-level. See CWE-532."
- },
- "543": {
- "title": "Use of Singleton Pattern Without Synchronization in a Multithreaded Context",
- "description": "The product uses the singleton pattern when creating a resource within a multithreaded environment."
- },
- "544": {
- "title": "Missing Standardized Error Handling Mechanism",
- "description": "The product does not use a standardized method for handling errors throughout the code, which might introduce inconsistent error handling and resultant weaknesses."
- },
- "545": {
- "title": "DEPRECATED: Use of Dynamic Class Loading",
- "description": "This weakness has been deprecated because it partially overlaps CWE-470, it describes legitimate programmer behavior, and other portions will need to be integrated into other entries."
- },
- "546": {
- "title": "Suspicious Comment",
- "description": "The code contains comments that suggest the presence of bugs, incomplete functionality, or weaknesses."
- },
- "547": {
- "title": "Use of Hard-coded, Security-relevant Constants",
- "description": "The product uses hard-coded constants instead of symbolic names for security-critical values, which increases the likelihood of mistakes during code maintenance or security policy change."
- },
- "548": {
- "title": "Exposure of Information Through Directory Listing",
- "description": "A directory listing is inappropriately exposed, yielding potentially sensitive information to attackers."
- },
- "549": {
- "title": "Missing Password Field Masking",
- "description": "The product does not mask passwords during entry, increasing the potential for attackers to observe and capture passwords."
- },
- "550": {
- "title": "Server-generated Error Message Containing Sensitive Information",
- "description": "Certain conditions, such as network failure, will cause a server error message to be displayed."
- },
- "551": {
- "title": "Incorrect Behavior Order: Authorization Before Parsing and Canonicalization",
- "description": "If a web server does not fully parse requested URLs before it examines them for authorization, it may be possible for an attacker to bypass authorization protection."
- },
- "552": {
- "title": "Files or Directories Accessible to External Parties",
- "description": "The product makes files or directories accessible to unauthorized actors, even though they should not be."
- },
- "553": {
- "title": "Command Shell in Externally Accessible Directory",
- "description": "A possible shell file exists in /cgi-bin/ or other accessible directories. This is extremely dangerous and can be used by an attacker to execute commands on the web server."
- },
- "554": {
- "title": "ASP.NET Misconfiguration: Not Using Input Validation Framework",
- "description": "The ASP.NET application does not use an input validation framework."
- },
- "555": {
- "title": "J2EE Misconfiguration: Plaintext Password in Configuration File",
- "description": "The J2EE application stores a plaintext password in a configuration file."
- },
- "556": {
- "title": "ASP.NET Misconfiguration: Use of Identity Impersonation",
- "description": "Configuring an ASP.NET application to run with impersonated credentials may give the application unnecessary privileges."
- },
- "558": {
- "title": "Use of getlogin() in Multithreaded Application",
- "description": "The product uses the getlogin() function in a multithreaded context, potentially causing it to return incorrect values."
- },
- "560": {
- "title": "Use of umask() with chmod-style Argument",
- "description": "The product calls umask() with an incorrect argument that is specified as if it is an argument to chmod()."
- },
- "561": {
- "title": "Dead Code",
- "description": "The product contains dead code, which can never be executed."
- },
- "562": {
- "title": "Return of Stack Variable Address",
- "description": "A function returns the address of a stack variable, which will cause unintended program behavior, typically in the form of a crash."
- },
- "563": {
- "title": "Assignment to Variable without Use",
- "description": "The variable's value is assigned but never used, making it a dead store."
- },
- "564": {
- "title": "SQL Injection: Hibernate",
- "description": "Using Hibernate to execute a dynamic SQL statement built with user-controlled input can allow an attacker to modify the statement's meaning or to execute arbitrary SQL commands."
- },
- "565": {
- "title": "Reliance on Cookies without Validation and Integrity Checking",
- "description": "The product relies on the existence or values of cookies when performing security-critical operations, but it does not properly ensure that the setting is valid for the associated user."
- },
- "566": {
- "title": "Authorization Bypass Through User-Controlled SQL Primary Key",
- "description": "The product uses a database table that includes records that should not be accessible to an actor, but it executes a SQL statement with a primary key that can be controlled by that actor."
- },
- "567": {
- "title": "Unsynchronized Access to Shared Data in a Multithreaded Context",
- "description": "The product does not properly synchronize shared data, such as static variables across threads, which can lead to undefined behavior and unpredictable data changes."
- },
- "568": {
- "title": "finalize() Method Without super.finalize()",
- "description": "The product contains a finalize() method that does not call super.finalize()."
- },
- "570": {
- "title": "Expression is Always False",
- "description": "The product contains an expression that will always evaluate to false."
- },
- "571": {
- "title": "Expression is Always True",
- "description": "The product contains an expression that will always evaluate to true."
- },
- "572": {
- "title": "Call to Thread run() instead of start()",
- "description": "The product calls a thread's run() method instead of calling start(), which causes the code to run in the thread of the caller instead of the callee."
- },
- "573": {
- "title": "Improper Following of Specification by Caller",
- "description": "The product does not follow or incorrectly follows the specifications as required by the implementation language, environment, framework, protocol, or platform."
- },
- "574": {
- "title": "EJB Bad Practices: Use of Synchronization Primitives",
- "description": "The product violates the Enterprise JavaBeans (EJB) specification by using thread synchronization primitives."
- },
- "575": {
- "title": "EJB Bad Practices: Use of AWT Swing",
- "description": "The product violates the Enterprise JavaBeans (EJB) specification by using AWT/Swing."
- },
- "576": {
- "title": "EJB Bad Practices: Use of Java I/O",
- "description": "The product violates the Enterprise JavaBeans (EJB) specification by using the java.io package."
- },
- "577": {
- "title": "EJB Bad Practices: Use of Sockets",
- "description": "The product violates the Enterprise JavaBeans (EJB) specification by using sockets."
- },
- "578": {
- "title": "EJB Bad Practices: Use of Class Loader",
- "description": "The product violates the Enterprise JavaBeans (EJB) specification by using the class loader."
- },
- "579": {
- "title": "J2EE Bad Practices: Non-serializable Object Stored in Session",
- "description": "The product stores a non-serializable object as an HttpSession attribute, which can hurt reliability."
- },
- "580": {
- "title": "clone() Method Without super.clone()",
- "description": "The product contains a clone() method that does not call super.clone() to obtain the new object."
- },
- "581": {
- "title": "Object Model Violation: Just One of Equals and Hashcode Defined",
- "description": "The product does not maintain equal hashcodes for equal objects."
- },
- "582": {
- "title": "Array Declared Public, Final, and Static",
- "description": "The product declares an array public, final, and static, which is not sufficient to prevent the array's contents from being modified."
- },
- "583": {
- "title": "finalize() Method Declared Public",
- "description": "The product violates secure coding principles for mobile code by declaring a finalize() method public."
- },
- "584": {
- "title": "Return Inside Finally Block",
- "description": "The code has a return statement inside a finally block, which will cause any thrown exception in the try block to be discarded."
- },
- "585": {
- "title": "Empty Synchronized Block",
- "description": "The product contains an empty synchronized block."
- },
- "586": {
- "title": "Explicit Call to Finalize()",
- "description": "The product makes an explicit call to the finalize() method from outside the finalizer."
- },
- "587": {
- "title": "Assignment of a Fixed Address to a Pointer",
- "description": "The product sets a pointer to a specific address other than NULL or 0."
- },
- "588": {
- "title": "Attempt to Access Child of a Non-structure Pointer",
- "description": "Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption."
- },
- "589": {
- "title": "Call to Non-ubiquitous API",
- "description": "The product uses an API function that does not exist on all versions of the target platform. This could cause portability problems or inconsistencies that allow denial of service or other consequences."
- },
- "590": {
- "title": "Free of Memory not on the Heap",
- "description": "The product calls free() on a pointer to memory that was not allocated using associated heap allocation functions such as malloc(), calloc(), or realloc()."
- },
- "591": {
- "title": "Sensitive Data Storage in Improperly Locked Memory",
- "description": "The product stores sensitive data in memory that is not locked, or that has been incorrectly locked, which might cause the memory to be written to swap files on disk by the virtual memory manager. This can make the data more accessible to external actors."
- },
- "592": {
- "title": "DEPRECATED: Authentication Bypass Issues",
- "description": "This weakness has been deprecated because it covered redundant concepts already described in CWE-287."
- },
- "593": {
- "title": "Authentication Bypass: OpenSSL CTX Object Modified after SSL Objects are Created",
- "description": "The product modifies the SSL context after connection creation has begun."
- },
- "594": {
- "title": "J2EE Framework: Saving Unserializable Objects to Disk",
- "description": "When the J2EE container attempts to write unserializable objects to disk there is no guarantee that the process will complete successfully."
- },
- "595": {
- "title": "Comparison of Object References Instead of Object Contents",
- "description": "The product compares object references instead of the contents of the objects themselves, preventing it from detecting equivalent objects."
- },
- "596": {
- "title": "DEPRECATED: Incorrect Semantic Object Comparison",
- "description": "This weakness has been deprecated. It was poorly described and difficult to distinguish from other entries. It was also inappropriate to assign a separate ID solely because of domain-specific considerations. Its closest equivalent is CWE-1023."
- },
- "597": {
- "title": "Use of Wrong Operator in String Comparison",
- "description": "The product uses the wrong operator when comparing a string, such as using \"==\" when the .equals() method should be used instead."
- },
- "598": {
- "title": "Use of GET Request Method With Sensitive Query Strings",
- "description": "The web application uses the HTTP GET method to process a request and includes sensitive information in the query string of that request."
- },
- "599": {
- "title": "Missing Validation of OpenSSL Certificate",
- "description": "The product uses OpenSSL and trusts or uses a certificate without using the SSL_get_verify_result() function to ensure that the certificate satisfies all necessary security requirements."
- },
- "600": {
- "title": "Uncaught Exception in Servlet ",
- "description": "The Servlet does not catch all exceptions, which may reveal sensitive debugging information."
- },
- "601": {
- "title": "URL Redirection to Untrusted Site ('Open Redirect')",
- "description": "A web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a Redirect. This simplifies phishing attacks."
- },
- "602": {
- "title": "Client-Side Enforcement of Server-Side Security",
- "description": "The product is composed of a server that relies on the client to implement a mechanism that is intended to protect the server."
- },
- "603": {
- "title": "Use of Client-Side Authentication",
- "description": "A client/server product performs authentication within client code but not in server code, allowing server-side authentication to be bypassed via a modified client that omits the authentication check."
- },
- "605": {
- "title": "Multiple Binds to the Same Port",
- "description": "When multiple sockets are allowed to bind to the same port, other services on that port may be stolen or spoofed."
- },
- "606": {
- "title": "Unchecked Input for Loop Condition",
- "description": "The product does not properly check inputs that are used for loop conditions, potentially leading to a denial of service or other consequences because of excessive looping."
- },
- "607": {
- "title": "Public Static Final Field References Mutable Object",
- "description": "A public or protected static final field references a mutable object, which allows the object to be changed by malicious code, or accidentally from another package."
- },
- "608": {
- "title": "Struts: Non-private Field in ActionForm Class",
- "description": "An ActionForm class contains a field that has not been declared private, which can be accessed without using a setter or getter."
- },
- "609": {
- "title": "Double-Checked Locking",
- "description": "The product uses double-checked locking to access a resource without the overhead of explicit synchronization, but the locking is insufficient."
- },
- "610": {
- "title": "Externally Controlled Reference to a Resource in Another Sphere",
- "description": "The product uses an externally controlled name or reference that resolves to a resource that is outside of the intended control sphere."
- },
- "611": {
- "title": "Improper Restriction of XML External Entity Reference",
- "description": "The product processes an XML document that can contain XML entities with URIs that resolve to documents outside of the intended sphere of control, causing the product to embed incorrect documents into its output."
- },
- "612": {
- "title": "Improper Authorization of Index Containing Sensitive Information",
- "description": "The product creates a search index of private or sensitive documents, but it does not properly limit index access to actors who are authorized to see the original information."
- },
- "613": {
- "title": "Insufficient Session Expiration",
- "description": "According to WASC, \"Insufficient Session Expiration is when a web site permits an attacker to reuse old session credentials or session IDs for authorization.\""
- },
- "614": {
- "title": "Sensitive Cookie in HTTPS Session Without 'Secure' Attribute",
- "description": "The Secure attribute for sensitive cookies in HTTPS sessions is not set, which could cause the user agent to send those cookies in plaintext over an HTTP session."
- },
- "615": {
- "title": "Inclusion of Sensitive Information in Source Code Comments",
- "description": "While adding general comments is very useful, some programmers tend to leave important data, such as: filenames related to the web application, old links or links which were not meant to be browsed by users, old code fragments, etc."
- },
- "616": {
- "title": "Incomplete Identification of Uploaded File Variables (PHP)",
- "description": "The PHP application uses an old method for processing uploaded files by referencing the four global variables that are set for each file (e.g. $varname, $varname_size, $varname_name, $varname_type). These variables could be overwritten by attackers, causing the application to process unauthorized files."
- },
- "617": {
- "title": "Reachable Assertion",
- "description": "The product contains an assert() or similar statement that can be triggered by an attacker, which leads to an application exit or other behavior that is more severe than necessary."
- },
- "618": {
- "title": "Exposed Unsafe ActiveX Method",
- "description": "An ActiveX control is intended for use in a web browser, but it exposes dangerous methods that perform actions that are outside of the browser's security model (e.g. the zone or domain)."
- },
- "619": {
- "title": "Dangling Database Cursor ('Cursor Injection')",
- "description": "If a database cursor is not closed properly, then it could become accessible to other users while retaining the same privileges that were originally assigned, leaving the cursor \"dangling.\""
- },
- "620": {
- "title": "Unverified Password Change",
- "description": "When setting a new password for a user, the product does not require knowledge of the original password, or using another form of authentication."
- },
- "621": {
- "title": "Variable Extraction Error",
- "description": "The product uses external input to determine the names of variables into which information is extracted, without verifying that the names of the specified variables are valid. This could cause the program to overwrite unintended variables."
- },
- "622": {
- "title": "Improper Validation of Function Hook Arguments",
- "description": "The product adds hooks to user-accessible API functions, but it does not properly validate the arguments. This could lead to resultant vulnerabilities."
- },
- "623": {
- "title": "Unsafe ActiveX Control Marked Safe For Scripting",
- "description": "An ActiveX control is intended for restricted use, but it has been marked as safe-for-scripting."
- },
- "624": {
- "title": "Executable Regular Expression Error",
- "description": "The product uses a regular expression that either (1) contains an executable component with user-controlled inputs, or (2) allows a user to enable execution by inserting pattern modifiers."
- },
- "625": {
- "title": "Permissive Regular Expression",
- "description": "The product uses a regular expression that does not sufficiently restrict the set of allowed values."
- },
- "626": {
- "title": "Null Byte Interaction Error (Poison Null Byte)",
- "description": "The product does not properly handle null bytes or NUL characters when passing data between different representations or components."
- },
- "627": {
- "title": "Dynamic Variable Evaluation",
- "description": "In a language where the user can influence the name of a variable at runtime, if the variable names are not controlled, an attacker can read or write to arbitrary variables, or access arbitrary functions."
- },
- "628": {
- "title": "Function Call with Incorrectly Specified Arguments",
- "description": "The product calls a function, procedure, or routine with arguments that are not correctly specified, leading to always-incorrect behavior and resultant weaknesses."
- },
- "636": {
- "title": "Not Failing Securely ('Failing Open')",
- "description": "When the product encounters an error condition or failure, its design requires it to fall back to a state that is less secure than other options that are available, such as selecting the weakest encryption algorithm or using the most permissive access control restrictions."
- },
- "637": {
- "title": "Unnecessary Complexity in Protection Mechanism (Not Using 'Economy of Mechanism')",
- "description": "The product uses a more complex mechanism than necessary, which could lead to resultant weaknesses when the mechanism is not correctly understood, modeled, configured, implemented, or used."
- },
- "638": {
- "title": "Not Using Complete Mediation",
- "description": "The product does not perform access checks on a resource every time the resource is accessed by an entity, which can create resultant weaknesses if that entity's rights or privileges change over time."
- },
- "639": {
- "title": "Authorization Bypass Through User-Controlled Key",
- "description": "The system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data."
- },
- "640": {
- "title": "Weak Password Recovery Mechanism for Forgotten Password",
- "description": "The product contains a mechanism for users to recover or change their passwords without knowing the original password, but the mechanism is weak."
- },
- "641": {
- "title": "Improper Restriction of Names for Files and Other Resources",
- "description": "The product constructs the name of a file or other resource using input from an upstream component, but it does not restrict or incorrectly restricts the resulting name."
- },
- "642": {
- "title": "External Control of Critical State Data",
- "description": "The product stores security-critical state information about its users, or the product itself, in a location that is accessible to unauthorized actors."
- },
- "643": {
- "title": "Improper Neutralization of Data within XPath Expressions ('XPath Injection')",
- "description": "The product uses external input to dynamically construct an XPath expression used to retrieve data from an XML database, but it does not neutralize or incorrectly neutralizes that input. This allows an attacker to control the structure of the query."
- },
- "644": {
- "title": "Improper Neutralization of HTTP Headers for Scripting Syntax",
- "description": "The product does not neutralize or incorrectly neutralizes web scripting syntax in HTTP headers that can be used by web browser components that can process raw headers, such as Flash."
- },
- "645": {
- "title": "Overly Restrictive Account Lockout Mechanism",
- "description": "The product contains an account lockout protection mechanism, but the mechanism is too restrictive and can be triggered too easily, which allows attackers to deny service to legitimate users by causing their accounts to be locked out."
- },
- "646": {
- "title": "Reliance on File Name or Extension of Externally-Supplied File",
- "description": "The product allows a file to be uploaded, but it relies on the file name or extension of the file to determine the appropriate behaviors. This could be used by attackers to cause the file to be misclassified and processed in a dangerous fashion."
- },
- "647": {
- "title": "Use of Non-Canonical URL Paths for Authorization Decisions",
- "description": "The product defines policy namespaces and makes authorization decisions based on the assumption that a URL is canonical. This can allow a non-canonical URL to bypass the authorization."
- },
- "648": {
- "title": "Incorrect Use of Privileged APIs",
- "description": "The product does not conform to the API requirements for a function call that requires extra privileges. This could allow attackers to gain privileges by causing the function to be called incorrectly."
- },
- "649": {
- "title": "Reliance on Obfuscation or Encryption of Security-Relevant Inputs without Integrity Checking",
- "description": "The product uses obfuscation or encryption of inputs that should not be mutable by an external actor, but the product does not use integrity checks to detect if those inputs have been modified."
- },
- "650": {
- "title": "Trusting HTTP Permission Methods on the Server Side",
- "description": "The server contains a protection mechanism that assumes that any URI that is accessed using HTTP GET will not cause a state change to the associated resource. This might allow attackers to bypass intended access restrictions and conduct resource modification and deletion attacks, since some applications allow GET to modify state."
- },
- "651": {
- "title": "Exposure of WSDL File Containing Sensitive Information",
- "description": "The Web services architecture may require exposing a Web Service Definition Language (WSDL) file that contains information on the publicly accessible services and how callers of these services should interact with them (e.g. what parameters they expect and what types they return)."
- },
- "652": {
- "title": "Improper Neutralization of Data within XQuery Expressions ('XQuery Injection')",
- "description": "The product uses external input to dynamically construct an XQuery expression used to retrieve data from an XML database, but it does not neutralize or incorrectly neutralizes that input. This allows an attacker to control the structure of the query."
- },
- "653": {
- "title": "Improper Isolation or Compartmentalization",
- "description": "The product does not properly compartmentalize or isolate functionality, processes, or resources that require different privilege levels, rights, or permissions."
- },
- "654": {
- "title": "Reliance on a Single Factor in a Security Decision",
- "description": "A protection mechanism relies exclusively, or to a large extent, on the evaluation of a single condition or the integrity of a single object or entity in order to make a decision about granting access to restricted resources or functionality."
- },
- "655": {
- "title": "Insufficient Psychological Acceptability",
- "description": "The product has a protection mechanism that is too difficult or inconvenient to use, encouraging non-malicious users to disable or bypass the mechanism, whether by accident or on purpose."
- },
- "656": {
- "title": "Reliance on Security Through Obscurity",
- "description": "The product uses a protection mechanism whose strength depends heavily on its obscurity, such that knowledge of its algorithms or key data is sufficient to defeat the mechanism."
- },
- "657": {
- "title": "Violation of Secure Design Principles",
- "description": "The product violates well-established principles for secure design."
- },
- "662": {
- "title": "Improper Synchronization",
- "description": "The product utilizes multiple threads or processes to allow temporary access to a shared resource that can only be exclusive to one process at a time, but it does not properly synchronize these actions, which might cause simultaneous accesses of this resource by multiple threads or processes."
- },
- "663": {
- "title": "Use of a Non-reentrant Function in a Concurrent Context",
- "description": "The product calls a non-reentrant function in a concurrent context in which a competing code sequence (e.g. thread or signal handler) may have an opportunity to call the same function or otherwise influence its state."
- },
- "664": {
- "title": "Improper Control of a Resource Through its Lifetime",
- "description": "The product does not maintain or incorrectly maintains control over a resource throughout its lifetime of creation, use, and release."
- },
- "665": {
- "title": "Improper Initialization",
- "description": "The product does not initialize or incorrectly initializes a resource, which might leave the resource in an unexpected state when it is accessed or used."
- },
- "666": {
- "title": "Operation on Resource in Wrong Phase of Lifetime",
- "description": "The product performs an operation on a resource at the wrong phase of the resource's lifecycle, which can lead to unexpected behaviors."
- },
- "667": {
- "title": "Improper Locking",
- "description": "The product does not properly acquire or release a lock on a resource, leading to unexpected resource state changes and behaviors."
- },
- "668": {
- "title": "Exposure of Resource to Wrong Sphere",
- "description": "The product exposes a resource to the wrong control sphere, providing unintended actors with inappropriate access to the resource."
- },
- "669": {
- "title": "Incorrect Resource Transfer Between Spheres",
- "description": "The product does not properly transfer a resource/behavior to another sphere, or improperly imports a resource/behavior from another sphere, in a manner that provides unintended control over that resource."
- },
- "670": {
- "title": "Always-Incorrect Control Flow Implementation",
- "description": "The code contains a control flow path that does not reflect the algorithm that the path is intended to implement, leading to incorrect behavior any time this path is navigated."
- },
- "671": {
- "title": "Lack of Administrator Control over Security",
- "description": "The product uses security features in a way that prevents the product's administrator from tailoring security settings to reflect the environment in which the product is being used. This introduces resultant weaknesses or prevents it from operating at a level of security that is desired by the administrator."
- },
- "672": {
- "title": "Operation on a Resource after Expiration or Release",
- "description": "The product uses, accesses, or otherwise operates on a resource after that resource has been expired, released, or revoked."
- },
- "673": {
- "title": "External Influence of Sphere Definition",
- "description": "The product does not prevent the definition of control spheres from external actors."
- },
- "674": {
- "title": "Uncontrolled Recursion",
- "description": "The product does not properly control the amount of recursion that takes place, consuming excessive resources, such as allocated memory or the program stack."
- },
- "675": {
- "title": "Multiple Operations on Resource in Single-Operation Context",
- "description": "The product performs the same operation on a resource two or more times, when the operation should only be applied once."
- },
- "676": {
- "title": "Use of Potentially Dangerous Function",
- "description": "The product invokes a potentially dangerous function that could introduce a vulnerability if it is used incorrectly, but the function can also be used safely."
- },
- "680": {
- "title": "Integer Overflow to Buffer Overflow",
- "description": "The product performs a calculation to determine how much memory to allocate, but an integer overflow can occur that causes less memory to be allocated than expected, leading to a buffer overflow."
- },
- "681": {
- "title": "Incorrect Conversion between Numeric Types",
- "description": "When converting from one data type to another, such as long to integer, data can be omitted or translated in a way that produces unexpected values. If the resulting values are used in a sensitive context, then dangerous behaviors may occur."
- },
- "682": {
- "title": "Incorrect Calculation",
- "description": "The product performs a calculation that generates incorrect or unintended results that are later used in security-critical decisions or resource management."
- },
- "683": {
- "title": "Function Call With Incorrect Order of Arguments",
- "description": "The product calls a function, procedure, or routine, but the caller specifies the arguments in an incorrect order, leading to resultant weaknesses."
- },
- "684": {
- "title": "Incorrect Provision of Specified Functionality",
- "description": "The code does not function according to its published specifications, potentially leading to incorrect usage."
- },
- "685": {
- "title": "Function Call With Incorrect Number of Arguments",
- "description": "The product calls a function, procedure, or routine, but the caller specifies too many arguments, or too few arguments, which may lead to undefined behavior and resultant weaknesses."
- },
- "686": {
- "title": "Function Call With Incorrect Argument Type",
- "description": "The product calls a function, procedure, or routine, but the caller specifies an argument that is the wrong data type, which may lead to resultant weaknesses."
- },
- "687": {
- "title": "Function Call With Incorrectly Specified Argument Value",
- "description": "The product calls a function, procedure, or routine, but the caller specifies an argument that contains the wrong value, which may lead to resultant weaknesses."
- },
- "688": {
- "title": "Function Call With Incorrect Variable or Reference as Argument",
- "description": "The product calls a function, procedure, or routine, but the caller specifies the wrong variable or reference as one of the arguments, which may lead to undefined behavior and resultant weaknesses."
- },
- "689": {
- "title": "Permission Race Condition During Resource Copy",
- "description": "The product, while copying or cloning a resource, does not set the resource's permissions or access control until the copy is complete, leaving the resource exposed to other spheres while the copy is taking place."
- },
- "690": {
- "title": "Unchecked Return Value to NULL Pointer Dereference",
- "description": "The product does not check for an error after calling a function that can return with a NULL pointer if the function fails, which leads to a resultant NULL pointer dereference."
- },
- "691": {
- "title": "Insufficient Control Flow Management",
- "description": "The code does not sufficiently manage its control flow during execution, creating conditions in which the control flow can be modified in unexpected ways."
- },
- "692": {
- "title": "Incomplete Denylist to Cross-Site Scripting",
- "description": "The product uses a denylist-based protection mechanism to defend against XSS attacks, but the denylist is incomplete, allowing XSS variants to succeed."
- },
- "693": {
- "title": "Protection Mechanism Failure",
- "description": "The product does not use or incorrectly uses a protection mechanism that provides sufficient defense against directed attacks against the product."
- },
- "694": {
- "title": "Use of Multiple Resources with Duplicate Identifier",
- "description": "The product uses multiple resources that can have the same identifier, in a context in which unique identifiers are required."
- },
- "695": {
- "title": "Use of Low-Level Functionality",
- "description": "The product uses low-level functionality that is explicitly prohibited by the framework or specification under which the product is supposed to operate."
- },
- "696": {
- "title": "Incorrect Behavior Order",
- "description": "The product performs multiple related behaviors, but the behaviors are performed in the wrong order in ways which may produce resultant weaknesses."
- },
- "697": {
- "title": "Incorrect Comparison",
- "description": "The product compares two entities in a security-relevant context, but the comparison is incorrect, which may lead to resultant weaknesses."
- },
- "698": {
- "title": "Execution After Redirect (EAR)",
- "description": "The web application sends a redirect to another location, but instead of exiting, it executes additional code."
- },
- "703": {
- "title": "Improper Check or Handling of Exceptional Conditions",
- "description": "The product does not properly anticipate or handle exceptional conditions that rarely occur during normal operation of the product."
- },
- "704": {
- "title": "Incorrect Type Conversion or Cast",
- "description": "The product does not correctly convert an object, resource, or structure from one type to a different type."
- },
- "705": {
- "title": "Incorrect Control Flow Scoping",
- "description": "The product does not properly return control flow to the proper location after it has completed a task or detected an unusual condition."
- },
- "706": {
- "title": "Use of Incorrectly-Resolved Name or Reference",
- "description": "The product uses a name or reference to access a resource, but the name/reference resolves to a resource that is outside of the intended control sphere."
- },
- "707": {
- "title": "Improper Neutralization",
- "description": "The product does not ensure or incorrectly ensures that structured messages or data are well-formed and that certain security properties are met before being read from an upstream component or sent to a downstream component."
- },
- "708": {
- "title": "Incorrect Ownership Assignment",
- "description": "The product assigns an owner to a resource, but the owner is outside of the intended control sphere."
- },
- "710": {
- "title": "Improper Adherence to Coding Standards",
- "description": "The product does not follow certain coding rules for development, which can lead to resultant weaknesses or increase the severity of the associated vulnerabilities."
- },
- "732": {
- "title": "Incorrect Permission Assignment for Critical Resource",
- "description": "The product specifies permissions for a security-critical resource in a way that allows that resource to be read or modified by unintended actors."
- },
- "733": {
- "title": "Compiler Optimization Removal or Modification of Security-critical Code",
- "description": "The developer builds a security-critical protection mechanism into the software, but the compiler optimizes the program such that the mechanism is removed or modified."
- },
- "749": {
- "title": "Exposed Dangerous Method or Function",
- "description": "The product provides an Applications Programming Interface (API) or similar interface for interaction with external actors, but the interface includes a dangerous method or function that is not properly restricted."
- },
- "754": {
- "title": "Improper Check for Unusual or Exceptional Conditions",
- "description": "The product does not check or incorrectly checks for unusual or exceptional conditions that are not expected to occur frequently during day to day operation of the product."
- },
- "755": {
- "title": "Improper Handling of Exceptional Conditions",
- "description": "The product does not handle or incorrectly handles an exceptional condition."
- },
- "756": {
- "title": "Missing Custom Error Page",
- "description": "The product does not return custom error pages to the user, possibly exposing sensitive information."
- },
- "757": {
- "title": "Selection of Less-Secure Algorithm During Negotiation ('Algorithm Downgrade')",
- "description": "A protocol or its implementation supports interaction between multiple actors and allows those actors to negotiate which algorithm should be used as a protection mechanism such as encryption or authentication, but it does not select the strongest algorithm that is available to both parties."
- },
- "758": {
- "title": "Reliance on Undefined, Unspecified, or Implementation-Defined Behavior",
- "description": "The product uses an API function, data structure, or other entity in a way that relies on properties that are not always guaranteed to hold for that entity."
- },
- "759": {
- "title": "Use of a One-Way Hash without a Salt",
- "description": "The product uses a one-way cryptographic hash against an input that should not be reversible, such as a password, but the product does not also use a salt as part of the input."
- },
- "760": {
- "title": "Use of a One-Way Hash with a Predictable Salt",
- "description": "The product uses a one-way cryptographic hash against an input that should not be reversible, such as a password, but the product uses a predictable salt as part of the input."
- },
- "761": {
- "title": "Free of Pointer not at Start of Buffer",
- "description": "The product calls free() on a pointer to a memory resource that was allocated on the heap, but the pointer is not at the start of the buffer."
- },
- "762": {
- "title": "Mismatched Memory Management Routines",
- "description": "The product attempts to return a memory resource to the system, but it calls a release function that is not compatible with the function that was originally used to allocate that resource."
- },
- "763": {
- "title": "Release of Invalid Pointer or Reference",
- "description": "The product attempts to return a memory resource to the system, but it calls the wrong release function or calls the appropriate release function incorrectly."
- },
- "764": {
- "title": "Multiple Locks of a Critical Resource",
- "description": "The product locks a critical resource more times than intended, leading to an unexpected state in the system."
- },
- "765": {
- "title": "Multiple Unlocks of a Critical Resource",
- "description": "The product unlocks a critical resource more times than intended, leading to an unexpected state in the system."
- },
- "766": {
- "title": "Critical Data Element Declared Public",
- "description": "The product declares a critical variable, field, or member to be public when intended security policy requires it to be private."
- },
- "767": {
- "title": "Access to Critical Private Variable via Public Method",
- "description": "The product defines a public method that reads or modifies a private variable."
- },
- "768": {
- "title": "Incorrect Short Circuit Evaluation",
- "description": "The product contains a conditional statement with multiple logical expressions in which one of the non-leading expressions may produce side effects. This may lead to an unexpected state in the program after the execution of the conditional, because short-circuiting logic may prevent the side effects from occurring."
- },
- "769": {
- "title": "DEPRECATED: Uncontrolled File Descriptor Consumption",
- "description": "This entry has been deprecated because it was a duplicate of CWE-774. All content has been transferred to CWE-774."
- },
- "770": {
- "title": "Allocation of Resources Without Limits or Throttling",
- "description": "The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor."
- },
- "771": {
- "title": "Missing Reference to Active Allocated Resource",
- "description": "The product does not properly maintain a reference to a resource that has been allocated, which prevents the resource from being reclaimed."
- },
- "772": {
- "title": "Missing Release of Resource after Effective Lifetime",
- "description": "The product does not release a resource after its effective lifetime has ended, i.e., after the resource is no longer needed."
- },
- "773": {
- "title": "Missing Reference to Active File Descriptor or Handle",
- "description": "The product does not properly maintain references to a file descriptor or handle, which prevents that file descriptor/handle from being reclaimed."
- },
- "774": {
- "title": "Allocation of File Descriptors or Handles Without Limits or Throttling",
- "description": "The product allocates file descriptors or handles on behalf of an actor without imposing any restrictions on how many descriptors can be allocated, in violation of the intended security policy for that actor."
- },
- "775": {
- "title": "Missing Release of File Descriptor or Handle after Effective Lifetime",
- "description": "The product does not release a file descriptor or handle after its effective lifetime has ended, i.e., after the file descriptor/handle is no longer needed."
- },
- "776": {
- "title": "Improper Restriction of Recursive Entity References in DTDs ('XML Entity Expansion')",
- "description": "The product uses XML documents and allows their structure to be defined with a Document Type Definition (DTD), but it does not properly control the number of recursive definitions of entities."
- },
- "777": {
- "title": "Regular Expression without Anchors",
- "description": "The product uses a regular expression to perform neutralization, but the regular expression is not anchored and may allow malicious or malformed data to slip through."
- },
- "778": {
- "title": "Insufficient Logging",
- "description": "When a security-critical event occurs, the product either does not record the event or omits important details about the event when logging it."
- },
- "779": {
- "title": "Logging of Excessive Data",
- "description": "The product logs too much information, making log files hard to process and possibly hindering recovery efforts or forensic analysis after an attack."
- },
- "780": {
- "title": "Use of RSA Algorithm without OAEP",
- "description": "The product uses the RSA algorithm but does not incorporate Optimal Asymmetric Encryption Padding (OAEP), which might weaken the encryption."
- },
- "781": {
- "title": "Improper Address Validation in IOCTL with METHOD_NEITHER I/O Control Code",
- "description": "The product defines an IOCTL that uses METHOD_NEITHER for I/O, but it does not validate or incorrectly validates the addresses that are provided."
- },
- "782": {
- "title": "Exposed IOCTL with Insufficient Access Control",
- "description": "The product implements an IOCTL with functionality that should be restricted, but it does not properly enforce access control for the IOCTL."
- },
- "783": {
- "title": "Operator Precedence Logic Error",
- "description": "The product uses an expression in which operator precedence causes incorrect logic to be used."
- },
- "784": {
- "title": "Reliance on Cookies without Validation and Integrity Checking in a Security Decision",
- "description": "The product uses a protection mechanism that relies on the existence or values of a cookie, but it does not properly ensure that the cookie is valid for the associated user."
- },
- "785": {
- "title": "Use of Path Manipulation Function without Maximum-sized Buffer",
- "description": "The product invokes a function for normalizing paths or file names, but it provides an output buffer that is smaller than the maximum possible size, such as PATH_MAX."
- },
- "786": {
- "title": "Access of Memory Location Before Start of Buffer",
- "description": "The product reads or writes to a buffer using an index or pointer that references a memory location prior to the beginning of the buffer."
- },
- "787": {
- "title": "Out-of-bounds Write",
- "description": "The product writes data past the end, or before the beginning, of the intended buffer."
- },
- "788": {
- "title": "Access of Memory Location After End of Buffer",
- "description": "The product reads or writes to a buffer using an index or pointer that references a memory location after the end of the buffer."
- },
- "789": {
- "title": "Memory Allocation with Excessive Size Value",
- "description": "The product allocates memory based on an untrusted, large size value, but it does not ensure that the size is within expected limits, allowing arbitrary amounts of memory to be allocated."
- },
- "790": {
- "title": "Improper Filtering of Special Elements",
- "description": "The product receives data from an upstream component, but does not filter or incorrectly filters special elements before sending it to a downstream component."
- },
- "791": {
- "title": "Incomplete Filtering of Special Elements",
- "description": "The product receives data from an upstream component, but does not completely filter special elements before sending it to a downstream component."
- },
- "792": {
- "title": "Incomplete Filtering of One or More Instances of Special Elements",
- "description": "The product receives data from an upstream component, but does not completely filter one or more instances of special elements before sending it to a downstream component."
- },
- "793": {
- "title": "Only Filtering One Instance of a Special Element",
- "description": "The product receives data from an upstream component, but only filters a single instance of a special element before sending it to a downstream component."
- },
- "794": {
- "title": "Incomplete Filtering of Multiple Instances of Special Elements",
- "description": "The product receives data from an upstream component, but does not filter all instances of a special element before sending it to a downstream component."
- },
- "795": {
- "title": "Only Filtering Special Elements at a Specified Location",
- "description": "The product receives data from an upstream component, but only accounts for special elements at a specified location, thereby missing remaining special elements that may exist before sending it to a downstream component."
- },
- "796": {
- "title": "Only Filtering Special Elements Relative to a Marker",
- "description": "The product receives data from an upstream component, but only accounts for special elements positioned relative to a marker (e.g. \"at the beginning/end of a string; the second argument\"), thereby missing remaining special elements that may exist before sending it to a downstream component."
- },
- "797": {
- "title": "Only Filtering Special Elements at an Absolute Position",
- "description": "The product receives data from an upstream component, but only accounts for special elements at an absolute position (e.g. \"byte number 10\"), thereby missing remaining special elements that may exist before sending it to a downstream component."
- },
- "798": {
- "title": "Use of Hard-coded Credentials",
- "description": "The product contains hard-coded credentials, such as a password or cryptographic key, which it uses for its own inbound authentication, outbound communication to external components, or encryption of internal data."
- },
- "799": {
- "title": "Improper Control of Interaction Frequency",
- "description": "The product does not properly limit the number or frequency of interactions that it has with an actor, such as the number of incoming requests."
- },
- "804": {
- "title": "Guessable CAPTCHA",
- "description": "The product uses a CAPTCHA challenge, but the challenge can be guessed or automatically recognized by a non-human actor."
- },
- "805": {
- "title": "Buffer Access with Incorrect Length Value",
- "description": "The product uses a sequential operation to read or write a buffer, but it uses an incorrect length value that causes it to access memory that is outside of the bounds of the buffer."
- },
- "806": {
- "title": "Buffer Access Using Size of Source Buffer",
- "description": "The product uses the size of a source buffer when reading from or writing to a destination buffer, which may cause it to access memory that is outside of the bounds of the buffer."
- },
- "807": {
- "title": "Reliance on Untrusted Inputs in a Security Decision",
- "description": "The product uses a protection mechanism that relies on the existence or values of an input, but the input can be modified by an untrusted actor in a way that bypasses the protection mechanism."
- },
- "820": {
- "title": "Missing Synchronization",
- "description": "The product utilizes a shared resource in a concurrent manner but does not attempt to synchronize access to the resource."
- },
- "821": {
- "title": "Incorrect Synchronization",
- "description": "The product utilizes a shared resource in a concurrent manner, but it does not correctly synchronize access to the resource."
- },
- "822": {
- "title": "Untrusted Pointer Dereference",
- "description": "The product obtains a value from an untrusted source, converts this value to a pointer, and dereferences the resulting pointer."
- },
- "823": {
- "title": "Use of Out-of-range Pointer Offset",
- "description": "The product performs pointer arithmetic on a valid pointer, but it uses an offset that can point outside of the intended range of valid memory locations for the resulting pointer."
- },
- "824": {
- "title": "Access of Uninitialized Pointer",
- "description": "The product accesses or uses a pointer that has not been initialized."
- },
- "825": {
- "title": "Expired Pointer Dereference",
- "description": "The product dereferences a pointer that contains a location for memory that was previously valid, but is no longer valid."
- },
- "826": {
- "title": "Premature Release of Resource During Expected Lifetime",
- "description": "The product releases a resource that is still intended to be used by itself or another actor."
- },
- "827": {
- "title": "Improper Control of Document Type Definition",
- "description": "The product does not restrict a reference to a Document Type Definition (DTD) to the intended control sphere. This might allow attackers to reference arbitrary DTDs, possibly causing the product to expose files, consume excessive system resources, or execute arbitrary http requests on behalf of the attacker."
- },
- "828": {
- "title": "Signal Handler with Functionality that is not Asynchronous-Safe",
- "description": "The product defines a signal handler that contains code sequences that are not asynchronous-safe, i.e., the functionality is not reentrant, or it can be interrupted."
- },
- "829": {
- "title": "Inclusion of Functionality from Untrusted Control Sphere",
- "description": "The product imports, requires, or includes executable functionality (such as a library) from a source that is outside of the intended control sphere."
- },
- "830": {
- "title": "Inclusion of Web Functionality from an Untrusted Source",
- "description": "The product includes web functionality (such as a web widget) from another domain, which causes it to operate within the domain of the product, potentially granting total access and control of the product to the untrusted source."
- },
- "831": {
- "title": "Signal Handler Function Associated with Multiple Signals",
- "description": "The product defines a function that is used as a handler for more than one signal."
- },
- "832": {
- "title": "Unlock of a Resource that is not Locked",
- "description": "The product attempts to unlock a resource that is not locked."
- },
- "833": {
- "title": "Deadlock",
- "description": "The product contains multiple threads or executable segments that are waiting for each other to release a necessary lock, resulting in deadlock."
- },
- "834": {
- "title": "Excessive Iteration",
- "description": "The product performs an iteration or loop without sufficiently limiting the number of times that the loop is executed."
- },
- "835": {
- "title": "Loop with Unreachable Exit Condition ('Infinite Loop')",
- "description": "The product contains an iteration or loop with an exit condition that cannot be reached, i.e., an infinite loop."
- },
- "836": {
- "title": "Use of Password Hash Instead of Password for Authentication",
- "description": "The product records password hashes in a data store, receives a hash of a password from a client, and compares the supplied hash to the hash obtained from the data store."
- },
- "837": {
- "title": "Improper Enforcement of a Single, Unique Action",
- "description": "The product requires that an actor should only be able to perform an action once, or to have only one unique action, but the product does not enforce or improperly enforces this restriction."
- },
- "838": {
- "title": "Inappropriate Encoding for Output Context",
- "description": "The product uses or specifies an encoding when generating output to a downstream component, but the specified encoding is not the same as the encoding that is expected by the downstream component."
- },
- "839": {
- "title": "Numeric Range Comparison Without Minimum Check",
- "description": "The product checks a value to ensure that it is less than or equal to a maximum, but it does not also verify that the value is greater than or equal to the minimum."
- },
- "841": {
- "title": "Improper Enforcement of Behavioral Workflow",
- "description": "The product supports a session in which more than one behavior must be performed by an actor, but it does not properly ensure that the actor performs the behaviors in the required sequence."
- },
- "842": {
- "title": "Placement of User into Incorrect Group",
- "description": "The product or the administrator places a user into an incorrect group."
- },
- "843": {
- "title": "Access of Resource Using Incompatible Type ('Type Confusion')",
- "description": "The product allocates or initializes a resource such as a pointer, object, or variable using one type, but it later accesses that resource using a type that is incompatible with the original type."
- },
- "862": {
- "title": "Missing Authorization",
- "description": "The product does not perform an authorization check when an actor attempts to access a resource or perform an action."
- },
- "863": {
- "title": "Incorrect Authorization",
- "description": "The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. This allows attackers to bypass intended access restrictions."
- },
- "908": {
- "title": "Use of Uninitialized Resource",
- "description": "The product uses or accesses a resource that has not been initialized."
- },
- "909": {
- "title": "Missing Initialization of Resource",
- "description": "The product does not initialize a critical resource."
- },
- "910": {
- "title": "Use of Expired File Descriptor",
- "description": "The product uses or accesses a file descriptor after it has been closed."
- },
- "911": {
- "title": "Improper Update of Reference Count",
- "description": "The product uses a reference count to manage a resource, but it does not update or incorrectly updates the reference count."
- },
- "912": {
- "title": "Hidden Functionality",
- "description": "The product contains functionality that is not documented, not part of the specification, and not accessible through an interface or command sequence that is obvious to the product's users or administrators."
- },
- "913": {
- "title": "Improper Control of Dynamically-Managed Code Resources",
- "description": "The product does not properly restrict reading from or writing to dynamically-managed code resources such as variables, objects, classes, attributes, functions, or executable instructions or statements."
- },
- "914": {
- "title": "Improper Control of Dynamically-Identified Variables",
- "description": "The product does not properly restrict reading from or writing to dynamically-identified variables."
- },
- "915": {
- "title": "Improperly Controlled Modification of Dynamically-Determined Object Attributes",
- "description": "The product receives input from an upstream component that specifies multiple attributes, properties, or fields that are to be initialized or updated in an object, but it does not properly control which attributes can be modified."
- },
- "916": {
- "title": "Use of Password Hash With Insufficient Computational Effort",
- "description": "The product generates a hash for a password, but it uses a scheme that does not provide a sufficient level of computational effort that would make password cracking attacks infeasible or expensive."
- },
- "917": {
- "title": "Improper Neutralization of Special Elements used in an Expression Language Statement ('Expression Language Injection')",
- "description": "The product constructs all or part of an expression language (EL) statement in a framework such as a Java Server Page (JSP) using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended EL statement before it is executed."
- },
- "918": {
- "title": "Server-Side Request Forgery (SSRF)",
- "description": "The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination."
- },
- "920": {
- "title": "Improper Restriction of Power Consumption",
- "description": "The product operates in an environment in which power is a limited resource that cannot be automatically replenished, but the product does not properly restrict the amount of power that its operation consumes."
- },
- "921": {
- "title": "Storage of Sensitive Data in a Mechanism without Access Control",
- "description": "The product stores sensitive information in a file system or device that does not have built-in access control."
- },
- "922": {
- "title": "Insecure Storage of Sensitive Information",
- "description": "The product stores sensitive information without properly limiting read or write access by unauthorized actors."
- },
- "923": {
- "title": "Improper Restriction of Communication Channel to Intended Endpoints",
- "description": "The product establishes a communication channel to (or from) an endpoint for privileged or protected operations, but it does not properly ensure that it is communicating with the correct endpoint."
- },
- "924": {
- "title": "Improper Enforcement of Message Integrity During Transmission in a Communication Channel",
- "description": "The product establishes a communication channel with an endpoint and receives a message from that endpoint, but it does not sufficiently ensure that the message was not modified during transmission."
- },
- "925": {
- "title": "Improper Verification of Intent by Broadcast Receiver",
- "description": "The Android application uses a Broadcast Receiver that receives an Intent but does not properly verify that the Intent came from an authorized source."
- },
- "926": {
- "title": "Improper Export of Android Application Components",
- "description": "The Android application exports a component for use by other applications, but does not properly restrict which applications can launch the component or access the data it contains."
- },
- "927": {
- "title": "Use of Implicit Intent for Sensitive Communication",
- "description": "The Android application uses an implicit intent for transmitting sensitive data to other applications."
- },
- "939": {
- "title": "Improper Authorization in Handler for Custom URL Scheme",
- "description": "The product uses a handler for a custom URL scheme, but it does not properly restrict which actors can invoke the handler using the scheme."
- },
- "940": {
- "title": "Improper Verification of Source of a Communication Channel",
- "description": "The product establishes a communication channel to handle an incoming request that has been initiated by an actor, but it does not properly verify that the request is coming from the expected origin."
- },
- "941": {
- "title": "Incorrectly Specified Destination in a Communication Channel",
- "description": "The product creates a communication channel to initiate an outgoing request to an actor, but it does not correctly specify the intended destination for that actor."
- },
- "942": {
- "title": "Permissive Cross-domain Policy with Untrusted Domains",
- "description": "The product uses a cross-domain policy file that includes domains that should not be trusted."
- },
- "943": {
- "title": "Improper Neutralization of Special Elements in Data Query Logic",
- "description": "The product generates a query intended to access or manipulate data in a data store such as a database, but it does not neutralize or incorrectly neutralizes special elements that can modify the intended logic of the query."
- },
- "1004": {
- "title": "Sensitive Cookie Without 'HttpOnly' Flag",
- "description": "The product uses a cookie to store sensitive information, but the cookie is not marked with the HttpOnly flag."
- },
- "1007": {
- "title": "Insufficient Visual Distinction of Homoglyphs Presented to User",
- "description": "The product displays information or identifiers to a user, but the display mechanism does not make it easy for the user to distinguish between visually similar or identical glyphs (homoglyphs), which may cause the user to misinterpret a glyph and perform an unintended, insecure action."
- },
- "1021": {
- "title": "Improper Restriction of Rendered UI Layers or Frames",
- "description": "The web application does not restrict or incorrectly restricts frame objects or UI layers that belong to another application or domain, which can lead to user confusion about which interface the user is interacting with."
- },
- "1022": {
- "title": "Use of Web Link to Untrusted Target with window.opener Access",
- "description": "The web application produces links to untrusted external sites outside of its sphere of control, but it does not properly prevent the external site from modifying security-critical properties of the window.opener object, such as the location property."
- },
- "1023": {
- "title": "Incomplete Comparison with Missing Factors",
- "description": "The product performs a comparison between entities that must consider multiple factors or characteristics of each entity, but the comparison does not include one or more of these factors."
- },
- "1024": {
- "title": "Comparison of Incompatible Types",
- "description": "The product performs a comparison between two entities, but the entities are of different, incompatible types that cannot be guaranteed to provide correct results when they are directly compared."
- },
- "1025": {
- "title": "Comparison Using Wrong Factors",
- "description": "The code performs a comparison between two entities, but the comparison examines the wrong factors or characteristics of the entities, which can lead to incorrect results and resultant weaknesses."
- },
- "1037": {
- "title": "Processor Optimization Removal or Modification of Security-critical Code",
- "description": "The developer builds a security-critical protection mechanism into the software, but the processor optimizes the execution of the program such that the mechanism is removed or modified."
- },
- "1038": {
- "title": "Insecure Automated Optimizations",
- "description": "The product uses a mechanism that automatically optimizes code, e.g. to improve a characteristic such as performance, but the optimizations can have an unintended side effect that might violate an intended security assumption."
- },
- "1039": {
- "title": "Automated Recognition Mechanism with Inadequate Detection or Handling of Adversarial Input Perturbations",
- "description": "The product uses an automated mechanism such as machine learning to recognize complex data inputs (e.g. image or audio) as a particular concept or category, but it does not properly detect or handle inputs that have been modified or constructed in a way that causes the mechanism to detect a different, incorrect concept."
- },
- "1041": {
- "title": "Use of Redundant Code",
- "description": "The product has multiple functions, methods, procedures, macros, etc. that\n\t\t\t\t\tcontain the same code."
- },
- "1042": {
- "title": "Static Member Data Element outside of a Singleton Class Element",
- "description": "The code contains a member element that is declared as static (but not final), in which\n\t\t\t\t\tits parent class element \n\t\t\t\t\tis not a singleton class - that is, a class element that can be used only once in\n\t\t\t\t\tthe 'to' association of a Create action."
- },
- "1043": {
- "title": "Data Element Aggregating an Excessively Large Number of Non-Primitive Elements",
- "description": "The product uses a data element that has an excessively large\n\t\t\t\t\tnumber of sub-elements with non-primitive data types such as structures or aggregated objects."
- },
- "1044": {
- "title": "Architecture with Number of Horizontal Layers Outside of Expected Range",
- "description": "The product's architecture contains too many - or too few -\n\t\t\t\t\thorizontal layers."
- },
- "1045": {
- "title": "Parent Class with a Virtual Destructor and a Child Class without a Virtual Destructor",
- "description": "A parent class has a virtual destructor method, but the parent has a child class that does not have a virtual destructor."
- },
- "1046": {
- "title": "Creation of Immutable Text Using String Concatenation",
- "description": "The product creates an immutable text string using string concatenation operations."
- },
- "1047": {
- "title": "Modules with Circular Dependencies",
- "description": "The product contains modules in which one module has references that cycle back to itself, i.e., there are circular dependencies."
- },
- "1048": {
- "title": "Invokable Control Element with Large Number of Outward Calls",
- "description": "The code contains callable control elements that\n contain an excessively large number of references to other\n application objects external to the context of the callable,\n i.e. a Fan-Out value that is excessively large."
- },
- "1049": {
- "title": "Excessive Data Query Operations in a Large Data Table",
- "description": "The product performs a data query with a large number of joins\n\t\t\t\t\tand sub-queries on a large data table."
- },
- "1050": {
- "title": "Excessive Platform Resource Consumption within a Loop",
- "description": "The product has a loop body or loop condition that contains a control element that directly or\n\t\t\t\t\tindirectly consumes platform resources, e.g. messaging, sessions, locks, or file\n\t\t\t\t\tdescriptors."
- },
- "1051": {
- "title": "Initialization with Hard-Coded Network Resource Configuration Data",
- "description": "The product initializes data using hard-coded values that act as network resource identifiers."
- },
- "1052": {
- "title": "Excessive Use of Hard-Coded Literals in Initialization",
- "description": "The product initializes a data element using a hard-coded\n\t\t\t\t\tliteral that is not a simple integer or static constant element."
- },
- "1053": {
- "title": "Missing Documentation for Design",
- "description": "The product does not have documentation that represents how it is designed."
- },
- "1054": {
- "title": "Invocation of a Control Element at an Unnecessarily Deep Horizontal Layer",
- "description": "The code at one architectural layer invokes code that resides\n\t\t\t\t\tat a deeper layer than the adjacent layer, i.e., the invocation skips at least one\n\t\t\t\t\tlayer, and the invoked code is not part of a vertical utility layer that can be referenced from any horizontal layer."
- },
- "1055": {
- "title": "Multiple Inheritance from Concrete Classes",
- "description": "The product contains a class with inheritance from more than\n\t\t\t\t\tone concrete class."
- },
- "1056": {
- "title": "Invokable Control Element with Variadic Parameters",
- "description": "A named-callable or method control element has a signature that\n\t\t\t\t\tsupports a variable (variadic) number of parameters or arguments."
- },
- "1057": {
- "title": "Data Access Operations Outside of Expected Data Manager Component",
- "description": "The product uses a dedicated, central data manager component as required by design, but it contains code that performs data-access operations that do not use this data manager."
- },
- "1058": {
- "title": "Invokable Control Element in Multi-Thread Context with non-Final Static Storable or Member Element",
- "description": "The code contains a function or method that\n\t\t operates in a multi-threaded environment but owns an unsafe non-final\n\t\t static storable or member data element."
- },
- "1059": {
- "title": "Insufficient Technical Documentation",
- "description": "The product does not contain sufficient\n technical or engineering documentation (whether on paper or\n in electronic form) that contains descriptions of all the\n relevant software/hardware elements of the product, such as\n its usage, structure, architectural components, interfaces, design, implementation,\n configuration, operation, etc."
- },
- "1060": {
- "title": "Excessive Number of Inefficient Server-Side Data Accesses",
- "description": "The product performs too many data queries without using efficient data processing functionality such as stored procedures."
- },
- "1061": {
- "title": "Insufficient Encapsulation",
- "description": "The product does not sufficiently hide the internal representation and implementation details of data or methods, which might allow external components or modules to modify data unexpectedly, invoke unexpected functionality, or introduce dependencies that the programmer did not intend."
- },
- "1062": {
- "title": "Parent Class with References to Child Class",
- "description": "The code has a parent class that contains references to a child class, its methods, or its members."
- },
- "1063": {
- "title": "Creation of Class Instance within a Static Code Block",
- "description": "A static code block creates an instance of a class."
- },
- "1064": {
- "title": "Invokable Control Element with Signature Containing an Excessive Number of Parameters",
- "description": "The product contains a function, subroutine, or method whose signature has an unnecessarily large number of\n\t\t\t\t\tparameters/arguments."
- },
- "1065": {
- "title": "Runtime Resource Management Control Element in a Component Built to Run on Application Servers",
- "description": "The product uses deployed components from application servers, but it also uses low-level functions/methods for management of resources, instead of the API provided by the application server."
- },
- "1066": {
- "title": "Missing Serialization Control Element",
- "description": "The product contains a serializable data element that does not\n\t\t\t\t\thave an associated serialization method."
- },
- "1067": {
- "title": "Excessive Execution of Sequential Searches of Data Resource",
- "description": "The product contains a data query against an SQL table or view\n\t\t\t\t\tthat is configured in a way that does not utilize an index and may cause\n\t\t\t\t\tsequential searches to be performed."
- },
- "1068": {
- "title": "Inconsistency Between Implementation and Documented Design",
- "description": "The implementation of the product is not consistent with the\n\t\t\t\t\tdesign as described within the relevant documentation."
- },
- "1069": {
- "title": "Empty Exception Block",
- "description": "An invokable code block contains an exception handling block that does not contain any code, i.e. is empty."
- },
- "1070": {
- "title": "Serializable Data Element Containing non-Serializable Item Elements",
- "description": "The product contains a serializable, storable data element such as a field or member,\n\t\t\t\t\tbut the data element contains member elements that are not\n\t\t\t\t\tserializable."
- },
- "1071": {
- "title": "Empty Code Block",
- "description": "The source code contains a block that does not contain any code, i.e., the block is empty."
- },
- "1072": {
- "title": "Data Resource Access without Use of Connection Pooling",
- "description": "The product accesses a data resource through a database without using a\n\t\t\t\t\tconnection pooling capability."
- },
- "1073": {
- "title": "Non-SQL Invokable Control Element with Excessive Number of Data Resource Accesses",
- "description": "The product contains a client with a function or method that contains a large number of data accesses/queries that are sent through a data manager, i.e., does not use efficient database capabilities."
- },
- "1074": {
- "title": "Class with Excessively Deep Inheritance",
- "description": "A class has an inheritance level that is too high, i.e., it\n\t\t\t\t\thas a large number of parent classes."
- },
- "1075": {
- "title": "Unconditional Control Flow Transfer outside of Switch Block",
- "description": "The product performs unconditional control transfer (such as a\n\t\t\t\t\t\"goto\") in code outside of a branching structure such as a switch\n\t\t\t\t\tblock."
- },
- "1076": {
- "title": "Insufficient Adherence to Expected Conventions",
- "description": "The product's architecture, source code, design, documentation,\n\t\t\t\t\tor other artifact does not follow required conventions."
- },
- "1077": {
- "title": "Floating Point Comparison with Incorrect Operator",
- "description": "The code performs a comparison such as an\n equality test between two float (floating point) values, but\n it uses comparison operators that do not account for the\n possibility of loss of precision."
- },
- "1078": {
- "title": "Inappropriate Source Code Style or Formatting",
- "description": "The source code does not follow\n\t\t\t\tdesired style or formatting for indentation, white\n\t\t\t\tspace, comments, etc."
- },
- "1079": {
- "title": "Parent Class without Virtual Destructor Method",
- "description": "A parent class contains one or more child classes, but the parent class does not have a virtual destructor method."
- },
- "1080": {
- "title": "Source Code File with Excessive Number of Lines of Code",
- "description": "A source code file has too many lines of\n\t\t\t\t\tcode."
- },
- "1082": {
- "title": "Class Instance Self Destruction Control Element",
- "description": "The code contains a class instance that calls the method or function to delete or destroy itself."
- },
- "1083": {
- "title": "Data Access from Outside Expected Data Manager Component",
- "description": "The product is intended to manage data access through a particular data manager component such as a relational or non-SQL database, but it contains code that performs data access operations without using that component."
- },
- "1084": {
- "title": "Invokable Control Element with Excessive File or Data Access Operations",
- "description": "A function or method contains too many\n\t\t\t\t\toperations that utilize a data manager or file resource."
- },
- "1085": {
- "title": "Invokable Control Element with Excessive Volume of Commented-out Code",
- "description": "A function, method, procedure, etc. contains an excessive amount of code that has been\n\t\t\t\t\tcommented out within its body."
- },
- "1086": {
- "title": "Class with Excessive Number of Child Classes",
- "description": "A class contains an unnecessarily large number of\n\t\t\t\t\tchildren."
- },
- "1087": {
- "title": "Class with Virtual Method without a Virtual Destructor",
- "description": "A class contains a virtual method, but the method does not have an associated virtual destructor."
- },
- "1088": {
- "title": "Synchronous Access of Remote Resource without Timeout",
- "description": "The code has a synchronous call to a remote resource, but there is no timeout for the call, or the timeout is set to infinite."
- },
- "1089": {
- "title": "Large Data Table with Excessive Number of Indices",
- "description": "The product uses a large data table that contains an excessively large number of\n\t\t\t\t\tindices."
- },
- "1090": {
- "title": "Method Containing Access of a Member Element from Another Class",
- "description": "A method for a class performs an operation that directly\n\t\t\t\t\taccesses a member element from another class."
- },
- "1091": {
- "title": "Use of Object without Invoking Destructor Method",
- "description": "The product contains a method that accesses an object but does not later invoke\n\t\t\t\t\tthe element's associated finalize/destructor method."
- },
- "1092": {
- "title": "Use of Same Invokable Control Element in Multiple Architectural Layers",
- "description": "The product uses the same control element across multiple\n\t\t\t\t\tarchitectural layers."
- },
- "1093": {
- "title": "Excessively Complex Data Representation",
- "description": "The product uses an unnecessarily complex internal representation for its data structures or interrelationships between those structures."
- },
- "1094": {
- "title": "Excessive Index Range Scan for a Data Resource",
- "description": "The product contains an index range scan for a large data table,\n\t\t\t\t\tbut the scan can cover a large number of rows."
- },
- "1095": {
- "title": "Loop Condition Value Update within the Loop",
- "description": "The product uses a loop with a control flow condition based on\n\t\t\t\t\ta value that is updated within the body of the loop."
- },
- "1096": {
- "title": "Singleton Class Instance Creation without Proper Locking or Synchronization",
- "description": "The product implements a Singleton design pattern but does not use appropriate locking or other synchronization mechanism to ensure that the singleton class is only instantiated once."
- },
- "1097": {
- "title": "Persistent Storable Data Element without Associated Comparison Control Element",
- "description": "The product uses a storable data element that does not have\n\t\t\t\t\tall of the associated functions or methods that are necessary to support\n\t\t\t\t\tcomparison."
- },
- "1098": {
- "title": "Data Element containing Pointer Item without Proper Copy Control Element",
- "description": "The code contains a data element with a pointer that does not have an associated copy or constructor method."
- },
- "1099": {
- "title": "Inconsistent Naming Conventions for Identifiers",
- "description": "The product's code, documentation, or other artifacts do not\n\t\t\t\t\tconsistently use the same naming conventions for variables, callables, groups of\n\t\t\t\t\trelated callables, I/O capabilities, data types, file names, or similar types of\n\t\t\t\t\telements."
- },
- "1100": {
- "title": "Insufficient Isolation of System-Dependent Functions",
- "description": "The product or code does not isolate system-dependent\n\t\t\t\t\tfunctionality into separate standalone modules."
- },
- "1101": {
- "title": "Reliance on Runtime Component in Generated Code",
- "description": "The product uses automatically-generated code that cannot be\n\t\t\t\t\texecuted without a specific runtime support component."
- },
- "1102": {
- "title": "Reliance on Machine-Dependent Data Representation",
- "description": "The code uses a data representation that relies on low-level\n\t\t\t\t\tdata representation or constructs that may vary across different processors,\n\t\t\t\t\tphysical machines, OSes, or other physical components."
- },
- "1103": {
- "title": "Use of Platform-Dependent Third Party Components",
- "description": "The product relies on third-party components that do\n\t\t\t\t\tnot provide equivalent functionality across all desirable\n\t\t\t\t\tplatforms."
- },
- "1104": {
- "title": "Use of Unmaintained Third Party Components",
- "description": "The product relies on third-party components that are not\n\t\t\t\t\tactively supported or maintained by the original developer or a trusted proxy\n\t\t\t\t\tfor the original developer."
- },
- "1105": {
- "title": "Insufficient Encapsulation of Machine-Dependent Functionality",
- "description": "The product or code uses machine-dependent functionality, but\n\t\t\t\t\tit does not sufficiently encapsulate or isolate this functionality from\n\t\t\t\t\tthe rest of the code."
- },
- "1106": {
- "title": "Insufficient Use of Symbolic Constants",
- "description": "The source code uses literal constants that may need to change\n\t\t\t\t\tor evolve over time, instead of using symbolic constants."
- },
- "1107": {
- "title": "Insufficient Isolation of Symbolic Constant Definitions",
- "description": "The source code uses symbolic constants, but it does not\n\t\t\t\t\tsufficiently place the definitions of these constants into a more centralized or\n\t\t\t\t\tisolated location."
- },
- "1108": {
- "title": "Excessive Reliance on Global Variables",
- "description": "The code is structured in a way that relies too much on using\n\t\t\t\t\tor setting global variables throughout various points in the code, instead of\n\t\t\t\t\tpreserving the associated information in a narrower, more local\n\t\t\t\t\tcontext."
- },
- "1109": {
- "title": "Use of Same Variable for Multiple Purposes",
- "description": "The code contains a callable, block, or other code element in\n\t\t\t\t\twhich the same variable is used to control more than one unique task or store\n\t\t\t\t\tmore than one instance of data."
- },
- "1110": {
- "title": "Incomplete Design Documentation",
- "description": "The product's design documentation does not adequately describe\n\t\t\t\t\tcontrol flow, data flow, system initialization, relationships between tasks,\n\t\t\t\t\tcomponents, rationales, or other important aspects of the\n\t\t\t\t\tdesign."
- },
- "1111": {
- "title": "Incomplete I/O Documentation",
- "description": "The product's documentation does not adequately define inputs,\n\t\t\t\t\toutputs, or system/software interfaces."
- },
- "1112": {
- "title": "Incomplete Documentation of Program Execution",
- "description": "The document does not fully define all mechanisms that are used\n\t\t\t\t\tto control or influence how product-specific programs are\n\t\t\t\t\texecuted."
- },
- "1113": {
- "title": "Inappropriate Comment Style",
- "description": "The source code uses comment styles or formats that are\n\t\t\t\t\tinconsistent or do not follow expected standards for the\n\t\t\t\t\tproduct."
- },
- "1114": {
- "title": "Inappropriate Whitespace Style",
- "description": "The source code contains whitespace that is inconsistent across\n\t\t\t\t\tthe code or does not follow expected standards for the\n\t\t\t\t\tproduct."
- },
- "1115": {
- "title": "Source Code Element without Standard Prologue",
- "description": "The source code contains elements such as source files \n\t\t\t\t\tthat do not consistently provide a prologue or header that has been\n\t\t\t\t\tstandardized for the project."
- },
- "1116": {
- "title": "Inaccurate Comments",
- "description": "The source code contains comments that do not accurately\n\t\t\t\t\tdescribe or explain aspects of the portion of the code with which the comment is\n\t\t\t\t\tassociated."
- },
- "1117": {
- "title": "Callable with Insufficient Behavioral Summary",
- "description": "The code contains a function or method whose signature and/or associated\n\t\t\t\t\tinline documentation does not sufficiently describe the callable's inputs, outputs,\n\t\t\t\t\tside effects, assumptions, or return codes."
- },
- "1118": {
- "title": "Insufficient Documentation of Error Handling Techniques",
- "description": "The documentation does not sufficiently describe the techniques\n\t\t\t\t\tthat are used for error handling, exception processing, or similar\n\t\t\t\t\tmechanisms."
- },
- "1119": {
- "title": "Excessive Use of Unconditional Branching",
- "description": "The code uses too many unconditional branches (such as\n\t\t\t\t\t\"goto\")."
- },
- "1120": {
- "title": "Excessive Code Complexity",
- "description": "The code is too complex, as calculated using a well-defined,\n\t\t\t\t\tquantitative measure."
- },
- "1121": {
- "title": "Excessive McCabe Cyclomatic Complexity",
- "description": "The code contains McCabe cyclomatic complexity that exceeds a\n\tdesirable maximum."
- },
- "1122": {
- "title": "Excessive Halstead Complexity",
- "description": "The code is structured in a way that a Halstead complexity\n\t\t\t\t\tmeasure exceeds a desirable maximum."
- },
- "1123": {
- "title": "Excessive Use of Self-Modifying Code",
- "description": "The product uses too much self-modifying\n\t\t\t\t\tcode."
- },
- "1124": {
- "title": "Excessively Deep Nesting",
- "description": "The code contains a callable or other code grouping in which\n\t\t\t\t\tthe nesting / branching is too deep."
- },
- "1125": {
- "title": "Excessive Attack Surface",
- "description": "The product has an attack surface whose quantitative\n\t\t\t\t\tmeasurement exceeds a desirable maximum."
- },
- "1126": {
- "title": "Declaration of Variable with Unnecessarily Wide Scope",
- "description": "The source code declares a variable in one scope, but the\n\t\t\t\t\tvariable is only used within a narrower scope."
- },
- "1127": {
- "title": "Compilation with Insufficient Warnings or Errors",
- "description": "The code is compiled without sufficient warnings enabled, which\n\t\t\t\t\tmay prevent the detection of subtle bugs or quality\n\t\t\t\t\tissues."
- },
- "1164": {
- "title": "Irrelevant Code",
- "description": "The product contains code that is not essential for execution,\n\t i.e. makes no state changes and has no side effects that alter\n\t data or control flow, such that removal of the code would have no impact\n\t to functionality or correctness."
- },
- "1173": {
- "title": "Improper Use of Validation Framework",
- "description": "The product does not use, or incorrectly uses, an input validation framework that is provided by the source language or an independent library."
- },
- "1174": {
- "title": "ASP.NET Misconfiguration: Improper Model Validation",
- "description": "The ASP.NET application does not use, or incorrectly uses, the model validation framework."
- },
- "1176": {
- "title": "Inefficient CPU Computation",
- "description": "The product performs CPU computations using\n algorithms that are not as efficient as they could be for the\n needs of the developer, i.e., the computations can be\n optimized further."
- },
- "1177": {
- "title": "Use of Prohibited Code",
- "description": "The product uses a function, library, or third party component\n\t that has been explicitly prohibited, whether by the developer or\n\t the customer."
- },
- "1187": {
- "title": "DEPRECATED: Use of Uninitialized Resource",
- "description": "This entry has been deprecated because it was a duplicate of CWE-908. All content has been transferred to CWE-908."
- },
- "1188": {
- "title": "Insecure Default Initialization of Resource",
- "description": "The product initializes or sets a resource with a default that is intended to be changed by the administrator, but the default is not secure."
- },
- "1189": {
- "title": "Improper Isolation of Shared Resources on System-on-a-Chip (SoC)",
- "description": "The System-On-a-Chip (SoC) does not properly isolate shared resources between trusted and untrusted agents."
- },
- "1190": {
- "title": "DMA Device Enabled Too Early in Boot Phase",
- "description": "The product enables a Direct Memory Access (DMA) capable device before the security configuration settings are established, which allows an attacker to extract data from or gain privileges on the product."
- },
- "1191": {
- "title": "On-Chip Debug and Test Interface With Improper Access Control",
- "description": "The chip does not implement or does not correctly perform access control to check whether users are authorized to access internal registers and test modes through the physical debug/test interface."
- },
- "1192": {
- "title": "System-on-Chip (SoC) Using Components without Unique, Immutable Identifiers",
- "description": "The System-on-Chip (SoC) does not have unique, immutable identifiers for each of its components."
- },
- "1193": {
- "title": "Power-On of Untrusted Execution Core Before Enabling Fabric Access Control",
- "description": "The product enables components that contain untrusted firmware before memory and fabric access controls have been enabled."
- },
- "1204": {
- "title": "Generation of Weak Initialization Vector (IV)",
- "description": "The product uses a cryptographic primitive that uses an Initialization\n\t\t\tVector (IV), but the product does not generate IVs that are\n\t\t\tsufficiently unpredictable or unique according to the expected\n\t\t\tcryptographic requirements for that primitive."
- },
- "1209": {
- "title": "Failure to Disable Reserved Bits",
- "description": "The reserved bits in a hardware design are not disabled prior to production. Typically, reserved bits are used for future capabilities and should not support any functional logic in the design. However, designers might covertly use these bits to debug or further develop new capabilities in production hardware. Adversaries with access to these bits will write to them in hopes of compromising hardware state."
- },
- "1220": {
- "title": "Insufficient Granularity of Access Control",
- "description": "The product implements access controls via a policy or other feature with the intention to disable or restrict accesses (reads and/or writes) to assets in a system from untrusted agents. However, implemented access controls lack required granularity, which renders the control policy too broad because it allows accesses from unauthorized agents to the security-sensitive assets."
- },
- "1221": {
- "title": "Incorrect Register Defaults or Module Parameters",
- "description": "Hardware description language code incorrectly defines register defaults or hardware IP parameters to insecure values."
- },
- "1222": {
- "title": "Insufficient Granularity of Address Regions Protected by Register Locks",
- "description": "The product defines a large address region protected from modification by the same register lock control bit. This results in a conflict between the functional requirement that some addresses need to be writable by software during operation and the security requirement that the system configuration lock bit must be set during the boot process."
- },
- "1223": {
- "title": "Race Condition for Write-Once Attributes",
- "description": "A write-once register in hardware design is programmable by an untrusted software component earlier than the trusted software component, resulting in a race condition issue."
- },
- "1224": {
- "title": "Improper Restriction of Write-Once Bit Fields",
- "description": "The hardware design control register \"sticky bits\" or write-once bit fields are improperly implemented, such that they can be reprogrammed by software."
- },
- "1229": {
- "title": "Creation of Emergent Resource",
- "description": "The product manages resources or behaves in a way that indirectly creates a new, distinct resource that can be used by attackers in violation of the intended policy."
- },
- "1230": {
- "title": "Exposure of Sensitive Information Through Metadata",
- "description": "The product prevents direct access to a resource containing sensitive information, but it does not sufficiently limit access to metadata that is derived from the original, sensitive information."
- },
- "1231": {
- "title": "Improper Prevention of Lock Bit Modification",
- "description": "The product uses a trusted lock bit for restricting access to registers, address regions, or other resources, but the product does not prevent the value of the lock bit from being modified after it has been set."
- },
- "1232": {
- "title": "Improper Lock Behavior After Power State Transition",
- "description": "Register lock bit protection disables changes to system configuration once the bit is set. Some of the protected registers or lock bits become programmable after power state transitions (e.g., Entry and wake from low power sleep modes) causing the system configuration to be changeable."
- },
- "1233": {
- "title": "Security-Sensitive Hardware Controls with Missing Lock Bit Protection",
- "description": "The product uses a register lock bit protection mechanism, but it does not ensure that the lock bit prevents modification of system registers or controls that perform changes to important hardware system configuration."
- },
- "1234": {
- "title": "Hardware Internal or Debug Modes Allow Override of Locks",
- "description": "System configuration protection may be bypassed during debug mode."
- },
- "1235": {
- "title": "Incorrect Use of Autoboxing and Unboxing for Performance Critical Operations",
- "description": "The code uses boxed primitives, which may introduce inefficiencies into performance-critical operations."
- },
- "1236": {
- "title": "Improper Neutralization of Formula Elements in a CSV File",
- "description": "The product saves user-provided information into a Comma-Separated Value (CSV) file, but it does not neutralize or incorrectly neutralizes special elements that could be interpreted as a command when the file is opened by a spreadsheet product."
- },
- "1239": {
- "title": "Improper Zeroization of Hardware Register",
- "description": "The hardware product does not properly clear sensitive information from built-in registers when the user of the hardware block changes."
- },
- "1240": {
- "title": "Use of a Cryptographic Primitive with a Risky Implementation",
- "description": "To fulfill the need for a cryptographic primitive, the product implements a cryptographic algorithm using a non-standard, unproven, or disallowed/non-compliant cryptographic implementation."
- },
- "1241": {
- "title": "Use of Predictable Algorithm in Random Number Generator",
- "description": "The device uses an algorithm that is predictable and generates a pseudo-random number."
- },
- "1242": {
- "title": "Inclusion of Undocumented Features or Chicken Bits",
- "description": "The device includes chicken bits or undocumented features that can create entry points for unauthorized actors."
- },
- "1243": {
- "title": "Sensitive Non-Volatile Information Not Protected During Debug",
- "description": "Access to security-sensitive information stored in fuses is not limited during debug."
- },
- "1244": {
- "title": "Internal Asset Exposed to Unsafe Debug Access Level or State",
- "description": "The product uses physical debug or test\n interfaces with support for multiple access levels, but it\n assigns the wrong debug access level to an internal asset,\n providing unintended access to the asset from untrusted debug\n agents."
- },
- "1245": {
- "title": "Improper Finite State Machines (FSMs) in Hardware Logic",
- "description": "Faulty finite state machines (FSMs) in the hardware logic allow an attacker to put the system in an undefined state, to cause a denial of service (DoS) or gain privileges on the victim's system."
- },
- "1246": {
- "title": "Improper Write Handling in Limited-write Non-Volatile Memories",
- "description": "The product does not implement or incorrectly implements wear leveling operations in limited-write non-volatile memories."
- },
- "1247": {
- "title": "Improper Protection Against Voltage and Clock Glitches",
- "description": "The device does not contain or contains incorrectly implemented circuitry or sensors to detect and mitigate voltage and clock glitches and protect sensitive information or software contained on the device."
- },
- "1248": {
- "title": "Semiconductor Defects in Hardware Logic with Security-Sensitive Implications",
- "description": "The security-sensitive hardware module contains semiconductor defects."
- },
- "1249": {
- "title": "Application-Level Admin Tool with Inconsistent View of Underlying Operating System",
- "description": "The product provides an application for administrators to manage parts of the underlying operating system, but the application does not accurately identify all of the relevant entities or resources that exist in the OS; that is, the application's model of the OS's state is inconsistent with the OS's actual state."
- },
- "1250": {
- "title": "Improper Preservation of Consistency Between Independent Representations of Shared State",
- "description": "The product has or supports multiple distributed components or sub-systems that are each required to keep their own local copy of shared data - such as state or cache - but the product does not ensure that all local copies remain consistent with each other."
- },
- "1251": {
- "title": "Mirrored Regions with Different Values",
- "description": "The product's architecture mirrors regions without ensuring that their contents always stay in sync."
- },
- "1252": {
- "title": "CPU Hardware Not Configured to Support Exclusivity of Write and Execute Operations",
- "description": "The CPU is not configured to provide hardware support for exclusivity of write and execute operations on memory. This allows an attacker to execute data from all of memory."
- },
- "1253": {
- "title": "Incorrect Selection of Fuse Values",
- "description": "The logic level used to set a system to a secure state relies on a fuse being unblown. An attacker can set the system to an insecure state merely by blowing the fuse."
- },
- "1254": {
- "title": "Incorrect Comparison Logic Granularity",
- "description": "The product's comparison logic is performed over a series of steps rather than across the entire string in one operation. If there is a comparison logic failure on one of these steps, the operation may be vulnerable to a timing attack that can result in the interception of the process for nefarious purposes."
- },
- "1255": {
- "title": "Comparison Logic is Vulnerable to Power Side-Channel Attacks",
- "description": "A device's real time power consumption may be monitored during security token evaluation and the information gleaned may be used to determine the value of the reference token."
- },
- "1256": {
- "title": "Improper Restriction of Software Interfaces to Hardware Features",
- "description": "The product provides software-controllable\n\t\t\tdevice functionality for capabilities such as power and\n\t\t\tclock management, but it does not properly limit\n\t\t\tfunctionality that can lead to modification of\n\t\t\thardware memory or register bits, or the ability to\n\t\t\tobserve physical side channels."
- },
- "1257": {
- "title": "Improper Access Control Applied to Mirrored or Aliased Memory Regions",
- "description": "Aliased or mirrored memory regions in hardware designs may have inconsistent read/write permissions enforced by the hardware. A possible result is that an untrusted agent is blocked from accessing a memory region but is not blocked from accessing the corresponding aliased memory region."
- },
- "1258": {
- "title": "Exposure of Sensitive System Information Due to Uncleared Debug Information",
- "description": "The hardware does not fully clear security-sensitive values, such as keys and intermediate values in cryptographic operations, when debug mode is entered."
- },
- "1259": {
- "title": "Improper Restriction of Security Token Assignment",
- "description": "The System-On-A-Chip (SoC) implements a Security Token mechanism to differentiate what actions are allowed or disallowed when a transaction originates from an entity. However, the Security Tokens are improperly protected."
- },
- "1260": {
- "title": "Improper Handling of Overlap Between Protected Memory Ranges",
- "description": "The product allows address regions to overlap, which can result in the bypassing of intended memory protection."
- },
- "1261": {
- "title": "Improper Handling of Single Event Upsets",
- "description": "The hardware logic does not effectively handle when single-event upsets (SEUs) occur."
- },
- "1262": {
- "title": "Improper Access Control for Register Interface",
- "description": "The product uses memory-mapped I/O registers that act as an interface to hardware functionality from software, but there is improper access control to those registers."
- },
- "1263": {
- "title": "Improper Physical Access Control",
- "description": "The product is designed with access restricted to certain information, but it does not sufficiently protect against an unauthorized actor with physical access to these areas."
- },
- "1264": {
- "title": "Hardware Logic with Insecure De-Synchronization between Control and Data Channels",
- "description": "The hardware logic for error handling and security checks can incorrectly forward data before the security check is complete."
- },
- "1265": {
- "title": "Unintended Reentrant Invocation of Non-reentrant Code Via Nested Calls",
- "description": "During execution of non-reentrant code, the product performs a call that unintentionally produces a nested invocation of the non-reentrant code."
- },
- "1266": {
- "title": "Improper Scrubbing of Sensitive Data from Decommissioned Device",
- "description": "The product does not properly provide a capability for the product administrator to remove sensitive data at the time the product is decommissioned. A scrubbing capability could be missing, insufficient, or incorrect."
- },
- "1267": {
- "title": "Policy Uses Obsolete Encoding",
- "description": "The product uses an obsolete encoding mechanism to implement access controls."
- },
- "1268": {
- "title": "Policy Privileges are not Assigned Consistently Between Control and Data Agents",
- "description": "The product's hardware-enforced access control for a particular resource improperly accounts for privilege discrepancies between control and write policies."
- },
- "1269": {
- "title": "Product Released in Non-Release Configuration",
- "description": "The product released to market is released in pre-production or manufacturing configuration."
- },
- "1270": {
- "title": "Generation of Incorrect Security Tokens",
- "description": "The product implements a Security Token mechanism to differentiate what actions are allowed or disallowed when a transaction originates from an entity. However, the Security Tokens generated in the system are incorrect."
- },
- "1271": {
- "title": "Uninitialized Value on Reset for Registers Holding Security Settings",
- "description": "Security-critical logic is not set to a known value on reset."
- },
- "1272": {
- "title": "Sensitive Information Uncleared Before Debug/Power State Transition",
- "description": "The product performs a power or debug state transition, but it does not clear sensitive information that should no longer be accessible due to changes to information access restrictions."
- },
- "1273": {
- "title": "Device Unlock Credential Sharing",
- "description": "The credentials necessary for unlocking a device are shared across multiple parties and may expose sensitive information."
- },
- "1274": {
- "title": "Improper Access Control for Volatile Memory Containing Boot Code",
- "description": "The product conducts a secure-boot process that transfers bootloader code from Non-Volatile Memory (NVM) into Volatile Memory (VM), but it does not have sufficient access control or other protections for the Volatile Memory."
- },
- "1275": {
- "title": "Sensitive Cookie with Improper SameSite Attribute",
- "description": "The SameSite attribute for sensitive cookies is not set, or an insecure value is used."
- },
- "1276": {
- "title": "Hardware Child Block Incorrectly Connected to Parent System",
- "description": "Signals between a hardware IP and the parent system design are incorrectly connected causing security risks."
- },
- "1277": {
- "title": "Firmware Not Updateable",
- "description": "The product does not provide its\n\t\t\tusers with the ability to update or patch its\n\t\t\tfirmware to address any vulnerabilities or\n\t\t\tweaknesses that may be present."
- },
- "1278": {
- "title": "Missing Protection Against Hardware Reverse Engineering Using Integrated Circuit (IC) Imaging Techniques",
- "description": "Information stored in hardware may be recovered by an attacker with the capability to capture and analyze images of the integrated circuit using techniques such as scanning electron microscopy."
- },
- "1279": {
- "title": "Cryptographic Operations are run Before Supporting Units are Ready",
- "description": "Performing cryptographic operations without ensuring that the supporting inputs are ready to supply valid data may compromise the cryptographic result."
- },
- "1280": {
- "title": "Access Control Check Implemented After Asset is Accessed",
- "description": "A product's hardware-based access control check occurs after the asset has been accessed."
- },
- "1281": {
- "title": "Sequence of Processor Instructions Leads to Unexpected Behavior",
- "description": "Specific combinations of processor instructions lead to undesirable behavior such as locking the processor until a hard reset performed."
- },
- "1282": {
- "title": "Assumed-Immutable Data is Stored in Writable Memory",
- "description": "Immutable data, such as a first-stage bootloader, device identifiers, and \"write-once\" configuration settings are stored in writable memory that can be re-programmed or updated in the field."
- },
- "1283": {
- "title": "Mutable Attestation or Measurement Reporting Data",
- "description": "The register contents used for attestation or measurement reporting data to verify boot flow are modifiable by an adversary."
- },
- "1284": {
- "title": "Improper Validation of Specified Quantity in Input",
- "description": "The product receives input that is expected to specify a quantity (such as size or length), but it does not validate or incorrectly validates that the quantity has the required properties."
- },
- "1285": {
- "title": "Improper Validation of Specified Index, Position, or Offset in Input",
- "description": "The product receives input that is expected to specify an index, position, or offset into an indexable resource such as a buffer or file, but it does not validate or incorrectly validates that the specified index/position/offset has the required properties."
- },
- "1286": {
- "title": "Improper Validation of Syntactic Correctness of Input",
- "description": "The product receives input that is expected to be well-formed - i.e., to comply with a certain syntax - but it does not validate or incorrectly validates that the input complies with the syntax."
- },
- "1287": {
- "title": "Improper Validation of Specified Type of Input",
- "description": "The product receives input that is expected to be of a certain type, but it does not validate or incorrectly validates that the input is actually of the expected type."
- },
- "1288": {
- "title": "Improper Validation of Consistency within Input",
- "description": "The product receives a complex input with multiple elements or fields that must be consistent with each other, but it does not validate or incorrectly validates that the input is actually consistent."
- },
- "1289": {
- "title": "Improper Validation of Unsafe Equivalence in Input",
- "description": "The product receives an input value that is used as a resource identifier or other type of reference, but it does not validate or incorrectly validates that the input is equivalent to a potentially-unsafe value."
- },
- "1290": {
- "title": "Incorrect Decoding of Security Identifiers ",
- "description": "The product implements a decoding mechanism to decode certain bus-transaction signals to security identifiers. If the decoding is implemented incorrectly, then untrusted agents can now gain unauthorized access to the asset."
- },
- "1291": {
- "title": "Public Key Re-Use for Signing both Debug and Production Code",
- "description": "The same public key is used for signing both debug and production code."
- },
- "1292": {
- "title": "Incorrect Conversion of Security Identifiers",
- "description": "The product implements a conversion mechanism to map certain bus-transaction signals to security identifiers. However, if the conversion is incorrectly implemented, untrusted agents can gain unauthorized access to the asset."
- },
- "1293": {
- "title": "Missing Source Correlation of Multiple Independent Data",
- "description": "The product relies on one source of data, preventing the ability to detect if an adversary has compromised a data source."
- },
- "1294": {
- "title": "Insecure Security Identifier Mechanism",
- "description": "The System-on-Chip (SoC) implements a Security Identifier mechanism to differentiate what actions are allowed or disallowed when a transaction originates from an entity. However, the Security Identifiers are not correctly implemented."
- },
- "1295": {
- "title": "Debug Messages Revealing Unnecessary Information",
- "description": "The product fails to adequately prevent the revealing of unnecessary and potentially sensitive system information within debugging messages."
- },
- "1296": {
- "title": "Incorrect Chaining or Granularity of Debug Components",
- "description": "The product's debug components contain incorrect chaining or granularity of debug components."
- },
- "1297": {
- "title": "Unprotected Confidential Information on Device is Accessible by OSAT Vendors",
- "description": "The product does not adequately protect confidential information on the device from being accessed by Outsourced Semiconductor Assembly and Test (OSAT) vendors."
- },
- "1298": {
- "title": "Hardware Logic Contains Race Conditions",
- "description": "A race condition in the hardware logic results in undermining security guarantees of the system."
- },
- "1299": {
- "title": "Missing Protection Mechanism for Alternate Hardware Interface",
- "description": "The lack of protections on alternate paths to access\n control-protected assets (such as unprotected shadow registers\n and other external facing unguarded interfaces) allows an\n attacker to bypass existing protections to the asset that are\n\t\tonly performed against the primary path."
- },
- "1300": {
- "title": "Improper Protection of Physical Side Channels",
- "description": "The device does not contain sufficient protection\n\tmechanisms to prevent physical side channels from exposing\n\tsensitive information due to patterns in physically observable\n\tphenomena such as variations in power consumption,\n\telectromagnetic emissions (EME), or acoustic emissions."
- },
- "1301": {
- "title": "Insufficient or Incomplete Data Removal within Hardware Component",
- "description": "The product's data removal process does not completely delete all data and potentially sensitive information within hardware components."
- },
- "1302": {
- "title": "Missing Security Identifier",
- "description": "The product implements a security identifier mechanism to differentiate what actions are allowed or disallowed when a transaction originates from an entity. A transaction is sent without a security identifier."
- },
- "1303": {
- "title": "Non-Transparent Sharing of Microarchitectural Resources",
- "description": "Hardware structures shared across execution contexts (e.g., caches and branch predictors) can violate the expected architecture isolation between contexts."
- },
- "1304": {
- "title": "Improperly Preserved Integrity of Hardware Configuration State During a Power Save/Restore Operation",
- "description": "The product performs a power save/restore\n operation, but it does not ensure that the integrity of\n the configuration state is maintained and/or verified between\n\t the beginning and ending of the operation."
- },
- "1310": {
- "title": "Missing Ability to Patch ROM Code",
- "description": "Missing an ability to patch ROM code may leave a System or System-on-Chip (SoC) in a vulnerable state."
- },
- "1311": {
- "title": "Improper Translation of Security Attributes by Fabric Bridge",
- "description": "The bridge incorrectly translates security attributes from either trusted to untrusted or from untrusted to trusted when converting from one fabric protocol to another."
- },
- "1312": {
- "title": "Missing Protection for Mirrored Regions in On-Chip Fabric Firewall",
- "description": "The firewall in an on-chip fabric protects the main addressed region, but it does not protect any mirrored memory or memory-mapped-IO (MMIO) regions."
- },
- "1313": {
- "title": "Hardware Allows Activation of Test or Debug Logic at Runtime",
- "description": "During runtime, the hardware allows for test or debug logic (feature) to be activated, which allows for changing the state of the hardware. This feature can alter the intended behavior of the system and allow for alteration and leakage of sensitive data by an adversary."
- },
- "1314": {
- "title": "Missing Write Protection for Parametric Data Values",
- "description": "The device does not write-protect the parametric data values for sensors that scale the sensor value, allowing untrusted software to manipulate the apparent result and potentially damage hardware or cause operational failure."
- },
- "1315": {
- "title": "Improper Setting of Bus Controlling Capability in Fabric End-point",
- "description": "The bus controller enables bits in the fabric end-point to allow responder devices to control transactions on the fabric."
- },
- "1316": {
- "title": "Fabric-Address Map Allows Programming of Unwarranted Overlaps of Protected and Unprotected Ranges",
- "description": "The address map of the on-chip fabric has protected and unprotected regions overlapping, allowing an attacker to bypass access control to the overlapping portion of the protected region."
- },
- "1317": {
- "title": "Improper Access Control in Fabric Bridge",
- "description": "The product uses a fabric bridge for transactions between two Intellectual Property (IP) blocks, but the bridge does not properly perform the expected privilege, identity, or other access control checks between those IP blocks."
- },
- "1318": {
- "title": "Missing Support for Security Features in On-chip Fabrics or Buses",
- "description": "On-chip fabrics or buses either do not support or are not configured to support privilege separation or other security features, such as access control."
- },
- "1319": {
- "title": "Improper Protection against Electromagnetic Fault Injection (EM-FI)",
- "description": "The device is susceptible to electromagnetic fault injection attacks, causing device internal information to be compromised or security mechanisms to be bypassed."
- },
- "1320": {
- "title": "Improper Protection for Outbound Error Messages and Alert Signals",
- "description": "Untrusted agents can disable alerts about signal conditions exceeding limits or the response mechanism that handles such alerts."
- },
- "1321": {
- "title": "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')",
- "description": "The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype."
- },
- "1322": {
- "title": "Use of Blocking Code in Single-threaded, Non-blocking Context",
- "description": "The product uses a non-blocking model that relies on a single threaded process\n\t\t\tfor features such as scalability, but it contains code that can block when it is invoked."
- },
- "1323": {
- "title": "Improper Management of Sensitive Trace Data",
- "description": "Trace data collected from several sources on the\n System-on-Chip (SoC) is stored in unprotected locations or\n transported to untrusted agents."
- },
- "1324": {
- "title": "DEPRECATED: Sensitive Information Accessible by Physical Probing of JTAG Interface",
- "description": "This entry has been deprecated because it was at a lower level of abstraction than supported by CWE. All relevant content has been integrated into CWE-319."
- },
- "1325": {
- "title": "Improperly Controlled Sequential Memory Allocation",
- "description": "The product manages a group of objects or resources and performs a separate memory allocation for each object, but it does not properly limit the total amount of memory that is consumed by all of the combined objects."
- },
- "1326": {
- "title": "Missing Immutable Root of Trust in Hardware",
- "description": "A missing immutable root of trust in the hardware results in the ability to bypass secure boot or execute untrusted or adversarial boot code."
- },
- "1327": {
- "title": "Binding to an Unrestricted IP Address",
- "description": "The product assigns the address 0.0.0.0 for a database server, a cloud service/instance, or any computing resource that communicates remotely."
- },
- "1328": {
- "title": "Security Version Number Mutable to Older Versions",
- "description": "Security-version number in hardware is mutable, resulting in the ability to downgrade (roll-back) the boot firmware to vulnerable code versions."
- },
- "1329": {
- "title": "Reliance on Component That is Not Updateable",
- "description": "The product contains a component that cannot be updated or patched in order to remove vulnerabilities or significant bugs."
- },
- "1330": {
- "title": "Remanent Data Readable after Memory Erase",
- "description": "Confidential information stored in memory circuits is readable or recoverable after being cleared or erased."
- },
- "1331": {
- "title": "Improper Isolation of Shared Resources in Network On Chip (NoC)",
- "description": "The Network On Chip (NoC) does not isolate or incorrectly isolates its on-chip-fabric and internal resources such that they are shared between trusted and untrusted agents, creating timing channels."
- },
- "1332": {
- "title": "Improper Handling of Faults that Lead to Instruction Skips",
- "description": "The device is missing or incorrectly implements circuitry or sensors that detect and mitigate the skipping of security-critical CPU instructions when they occur."
- },
- "1333": {
- "title": "Inefficient Regular Expression Complexity",
- "description": "The product uses a regular expression with an inefficient, possibly exponential worst-case computational complexity that consumes excessive CPU cycles."
- },
- "1334": {
- "title": "Unauthorized Error Injection Can Degrade Hardware Redundancy",
- "description": "An unauthorized agent can inject errors into a redundant block to deprive the system of redundancy or put the system in a degraded operating mode."
- },
- "1335": {
- "title": "Incorrect Bitwise Shift of Integer",
- "description": "An integer value is specified to be shifted by a negative amount or an amount greater than or equal to the number of bits contained in the value causing an unexpected or indeterminate result."
- },
- "1336": {
- "title": "Improper Neutralization of Special Elements Used in a Template Engine",
- "description": "The product uses a template engine to insert or process externally-influenced input, but it does not neutralize or incorrectly neutralizes special elements or syntax that can be interpreted as template expressions or other code directives when processed by the engine."
- },
- "1338": {
- "title": "Improper Protections Against Hardware Overheating",
- "description": "A hardware device is missing or has inadequate protection features to prevent overheating."
- },
- "1339": {
- "title": "Insufficient Precision or Accuracy of a Real Number",
- "description": "The product processes a real number with an implementation in which the number's representation does not preserve required accuracy and precision in its fractional part, causing an incorrect result."
- },
- "1341": {
- "title": "Multiple Releases of Same Resource or Handle",
- "description": "The product attempts to close or release a resource or handle more than once, without any successful open between the close operations."
- },
- "1342": {
- "title": "Information Exposure through Microarchitectural State after Transient Execution",
- "description": "The processor does not properly clear microarchitectural state after incorrect microcode assists or speculative execution, resulting in transient execution."
- },
- "1351": {
- "title": "Improper Handling of Hardware Behavior in Exceptionally Cold Environments",
- "description": "A hardware device, or the firmware running on it, is\n missing or has incorrect protection features to maintain\n goals of security primitives when the device is cooled below\n standard operating temperatures."
- },
- "1357": {
- "title": "Reliance on Insufficiently Trustworthy Component",
- "description": "The product is built from multiple separate components, but it uses a component that is not sufficiently trusted to meet expectations for security, reliability, updateability, and maintainability."
- },
- "1384": {
- "title": "Improper Handling of Physical or Environmental Conditions",
- "description": "The product does not properly handle unexpected physical or environmental conditions that occur naturally or are artificially induced."
- },
- "1385": {
- "title": "Missing Origin Validation in WebSockets",
- "description": "The product uses a WebSocket, but it does not properly verify that the source of data or communication is valid."
- },
- "1386": {
- "title": "Insecure Operation on Windows Junction / Mount Point",
- "description": "The product opens a file or directory, but it does not properly prevent the name from being associated with a junction or mount point to a destination that is outside of the intended control sphere."
- },
- "1389": {
- "title": "Incorrect Parsing of Numbers with Different Radices",
- "description": "The product parses numeric input assuming base 10 (decimal) values, but it does not account for inputs that use a different base number (radix)."
- },
- "1390": {
- "title": "Weak Authentication",
- "description": "The product uses an authentication mechanism to restrict access to specific users or identities, but the mechanism does not sufficiently prove that the claimed identity is correct."
- },
- "1391": {
- "title": "Use of Weak Credentials",
- "description": "The product uses weak credentials (such as a default key or hard-coded password) that can be calculated, derived, reused, or guessed by an attacker."
- },
- "1392": {
- "title": "Use of Default Credentials",
- "description": "The product uses default credentials (such as passwords or cryptographic keys) for potentially critical functionality."
- },
- "1393": {
- "title": "Use of Default Password",
- "description": "The product uses default passwords for potentially critical functionality."
- },
- "1394": {
- "title": "Use of Default Cryptographic Key",
- "description": "The product uses a default cryptographic key for potentially critical functionality."
- },
- "1395": {
- "title": "Dependency on Vulnerable Third-Party Component",
- "description": "The product has a dependency on a third-party component that contains one or more known vulnerabilities."
- },
- "unknown": {
- "title": "No CWE associated"
- }
- },
- "sonarsourceSecurity": {
- "buffer-overflow": {
- "title": "Buffer Overflow"
- },
- "sql-injection": {
- "title": "SQL Injection"
- },
- "rce": {
- "title": "Code Injection (RCE)"
- },
- "object-injection": {
- "title": "Object Injection"
- },
- "command-injection": {
- "title": "Command Injection"
- },
- "path-traversal-injection": {
- "title": "Path Traversal Injection"
- },
- "ldap-injection": {
- "title": "LDAP Injection"
- },
- "xpath-injection": {
- "title": "XPath Injection"
- },
- "expression-lang-injection": {
- "title": "Expression Language Injection"
- },
- "log-injection": {
- "title": "Log Injection"
- },
- "xxe": {
- "title": "XML External Entity (XXE)"
- },
- "xss": {
- "title": "Cross-Site Scripting (XSS)"
- },
- "dos": {
- "title": "Denial of Service (DoS)"
- },
- "ssrf": {
- "title": "Server-Side Request Forgery (SSRF)"
- },
- "csrf": {
- "title": "Cross-Site Request Forgery (CSRF)"
- },
- "http-response-splitting": {
- "title": "HTTP Response Splitting"
- },
- "open-redirect": {
- "title": "Open Redirect"
- },
- "weak-cryptography": {
- "title": "Weak Cryptography"
- },
- "auth": {
- "title": "Authentication"
- },
- "insecure-conf": {
- "title": "Insecure Configuration"
- },
- "file-manipulation": {
- "title": "File Manipulation"
- },
- "encrypt-data": {
- "title": "Encryption of Sensitive Data"
- },
- "traceability": {
- "title": "Traceability"
- },
- "permission": {
- "title": "Permission"
- },
- "others": {
- "title": "Others"
- }
- },
- "pciDss-3.2": {
- "1": {
- "title": "Install and maintain a firewall configuration to protect cardholder data"
- },
- "2": {
- "title": "Do not use vendor-supplied defaults for system passwords and other security parameters"
- },
- "3": {
- "title": "Protect stored cardholder data"
- },
- "4": {
- "title": "Encrypt transmission of cardholder data across open, public networks"
- },
- "5": {
- "title": "Protect all systems against malware and regularly update anti-virus software or programs"
- },
- "6": {
- "title": "Develop and maintain secure systems and applications"
- },
- "7": {
- "title": "Restrict access to cardholder data by business need to know"
- },
- "8": {
- "title": "Identify and authenticate access to system components"
- },
- "9": {
- "title": "Restrict physical access to cardholder data"
- },
- "10": {
- "title": "Track and monitor all access to network resources and cardholder data"
- },
- "11": {
- "title": "Regularly test security systems and processes"
- },
- "12": {
- "title": "Maintain a policy that addresses information security for all personnel"
- }
- },
- "pciDss-4.0": {
- "1": {
- "title": "Install and Maintain Network Security Controls"
- },
- "2": {
- "title": "Apply Secure Configurations to All System Components"
- },
- "3": {
- "title": "Protect Stored Account Data"
- },
- "4": {
- "title": "Protect Cardholder Data with Strong Cryptography During Transmission Over Open, Public Networks"
- },
- "5": {
- "title": "Protect All Systems and Networks from Malicious Software Sections"
- },
- "6": {
- "title": "Develop and Maintain Secure Systems and Software"
- },
- "7": {
- "title": "Restrict Access to System Components and Cardholder Data by Business Need to Know"
- },
- "8": {
- "title": "Identify Users and Authenticate Access to System Components"
- },
- "9": {
- "title": "Restrict Physical Access to Cardholder Data"
- },
- "10": {
- "title": "Log and Monitor All Access to System Components and Cardholder Data"
- },
- "11": {
- "title": "Test Security of Systems and Networks Regularly"
- },
- "12": {
- "title": "Support Information Security with Organizational Policies and Programs"
- }
- },
- "owaspAsvs-4.0": {
- "1": {
- "title": "Architecture, Design And Threat Modelling"
- },
- "2": {
- "title": "Authentication"
- },
- "3": {
- "title": "Session Management"
- },
- "4": {
- "title": "Access Control"
- },
- "5": {
- "title": "Malicious Input Handling"
- },
- "6": {
- "title": "Cryptography At Rest"
- },
- "7": {
- "title": "Error Handling And Logging"
- },
- "8": {
- "title": "Data Protection"
- },
- "9": {
- "title": "Communications Security"
- },
- "10": {
- "title": "Malicious Controls"
- },
- "11": {
- "title": "Business Logic"
- },
- "12": {
- "title": "Files And Resources"
- },
- "13": {
- "title": "Web Services"
- },
- "14": {
- "title": "Configuration"
- },
- "1.1.1": {
- "title": "Verify the use of a secure software development lifecycle that addresses security in all stages of development.",
- "level": "2"
- },
- "1.1.2": {
- "title": "Verify the use of threat modeling for every design change or sprint planning to identify threats, plan for countermeasures, facilitate appropriate risk responses, and guide security testing.",
- "level": "2"
- },
- "1.1.3": {
- "title": "Verify that all user stories and features contain functional security constraints, such as \"As a user,I should be able to view and edit my profile.I should not be able to view or edit anyone else 's profile\"",
- "level": "2"
- },
- "1.1.4": {
- "title": "Verify documentation and justification of all the application's trust boundaries, components, and significant data flows.",
- "level": "2"
- },
- "1.1.5": {
- "title": "Verify definition and security analysis of the application's high-level architecture and all connected remote services.",
- "level": "2"
- },
- "1.1.6": {
- "title": "Verify implementation of centralized, simple (economy of design), vetted, secure, and reusable security controls to avoid duplicate, missing, ineffective, or insecure controls.",
- "level": "2"
- },
- "1.1.7": {
- "title": "Verify availability of a secure coding checklist, security requirements, guideline, or policy to all developers and testers.",
- "level": "2"
- },
- "1.10.1": {
- "title": "Verify that a source code control system is in use, with procedures to ensure that check-ins are accompanied by issues or change tickets. The source code control system should have access control and identifiable users to allow traceability of any changes.",
- "level": "2"
- },
- "1.11.1": {
- "title": "Verify the definition and documentation of all application components in terms of the business or security functions they provide.",
- "level": "2"
- },
- "1.11.2": {
- "title": "Verify that all high-value business logic flows, including authentication, session management and access control, do not share unsynchronized state.",
- "level": "2"
- },
- "1.11.3": {
- "title": "Verify that all high-value business logic flows, including authentication, session management and access control are thread safe and resistant to time-of-check and time-of-use race conditions.",
- "level": "3"
- },
- "1.12.1": {
- "title": "Verify that user-uploaded files are stored outside of the web root.",
- "level": "2"
- },
- "1.12.2": {
- "title": "Verify that user-uploaded files - if required to be displayed or downloaded from the application - are served by either octet stream downloads, or from an unrelated domain, such as a cloud file storage bucket. Implement a suitable content security policy to reduce the risk from XSS vectors or other attacks from the uploaded file.",
- "level": "2"
- },
- "1.14.1": {
- "title": "Verify the segregation of components of differing trust levels through well-defined security controls, firewall rules, API gateways, reverse proxies, cloud-based security groups, or similar mechanisms.",
- "level": "2"
- },
- "1.14.2": {
- "title": "Verify that if deploying binaries to untrusted devices makes use of binary signatures, trusted connections, and verified endpoints.",
- "level": "2"
- },
- "1.14.3": {
- "title": "Verify that the build pipeline warns of out-of-date or insecure components and takes appropriate actions.",
- "level": "2"
- },
- "1.14.4": {
- "title": "Verify that the build pipeline contains a build step to automatically build and verify the secure deployment of the application, particularly if the application infrastructure is software defined, such as cloud environment build scripts.",
- "level": "2"
- },
- "1.14.5": {
- "title": "Verify that application deployments adequately sandbox, containerize and/or isolate at the network level to delay and deter attackers from attacking other applications, especially when they are performing sensitive or dangerous actions such as deserialization.",
- "level": "2"
- },
- "1.14.6": {
- "title": "Verify the application does not use unsupported, insecure, or deprecated client-side technologies such as NSAPI plugins, Flash, Shockwave, ActiveX, Silverlight, NACL, or client-side Java applets.",
- "level": "2"
- },
- "1.2.1": {
- "title": "Verify the use of unique or special low-privilege operating system accounts for all application components, services, and servers.",
- "level": "2"
- },
- "1.2.2": {
- "title": "Verify that communications between application components, including APIs, middleware and data layers, are authenticated. Components should have the least necessary privileges needed.",
- "level": "2"
- },
- "1.2.3": {
- "title": "Verify that the application uses a single vetted authentication mechanism that is known to be secure, can be extended to include strong authentication, and has sufficient logging and monitoring to detect account abuse or breaches.",
- "level": "2"
- },
- "1.2.4": {
- "title": "Verify that all authentication pathways and identity management APIs implement consistent authentication security control strength, such that there are no weaker alternatives per the risk of the application.",
- "level": "2"
- },
- "1.4.1": {
- "title": "Verify that trusted enforcement points such as at access control gateways, servers, and serverless functions enforce access controls. Never enforce access controls on the client.",
- "level": "2"
- },
- "1.4.2": {
- "title": "Verify that the chosen access control solution is flexible enough to meet the application's needs.",
- "level": "2"
- },
- "1.4.3": {
- "title": "Verify enforcement of the principle of least privilege in functions, data files, URLs, controllers, services, and other resources. This implies protection against spoofing and elevation of privilege.",
- "level": "2"
- },
- "1.4.4": {
- "title": "Verify the application uses a single and well-vetted access control mechanism for accessing protected data and resources. All requests must pass through this single mechanism to avoid copy and paste or insecure alternative paths.",
- "level": "2"
- },
- "1.4.5": {
- "title": "Verify that attribute or feature-based access control is used whereby the code checks the user's authorization for a feature/data item rather than just their role. Permissions should still be allocated using roles.",
- "level": "2"
- },
- "1.5.1": {
- "title": "Verify that input and output requirements clearly define how to handle and process data based on type, content, and applicable laws, regulations, and other policy compliance.",
- "level": "2"
- },
- "1.5.2": {
- "title": "Verify that serialization is not used when communicating with untrusted clients. If this is not possible, ensure that adequate integrity controls (and possibly encryption if sensitive data is sent) are enforced to prevent deserialization attacks including object injection.",
- "level": "2"
- },
- "1.5.3": {
- "title": "Verify that input validation is enforced on a trusted service layer.",
- "level": "2"
- },
- "1.5.4": {
- "title": "Verify that output encoding occurs close to or by the interpreter for which it is intended.",
- "level": "2"
- },
- "1.6.1": {
- "title": "Verify that there is an explicit policy for management of cryptographic keys and that a cryptographic key lifecycle follows a key management standard such as NIST SP 800-57.",
- "level": "2"
- },
- "1.6.2": {
- "title": "Verify that consumers of cryptographic services protect key material and other secrets by using key vaults or API based alternatives.",
- "level": "2"
- },
- "1.6.3": {
- "title": "Verify that all keys and passwords are replaceable and are part of a well-defined process to re-encrypt sensitive data.",
- "level": "2"
- },
- "1.6.4": {
- "title": "Verify that symmetric keys, passwords, or API secrets generated by or shared with clients are used only in protecting low risk secrets, such as encrypting local storage, or temporary ephemeral uses such as parameter obfuscation. Sharing secrets with clients is clear-text equivalent and architecturally should be treated as such.",
- "level": "2"
- },
- "1.7.1": {
- "title": "Verify that a common logging format and approach is used across the system. ",
- "level": "2"
- },
- "1.7.2": {
- "title": "Verify that logs are securely transmitted to a preferably remote system for analysis, detection, alerting, and escalation.",
- "level": "2"
- },
- "1.8.1": {
- "title": "Verify that all sensitive data is identified and classified into protection levels.",
- "level": "2"
- },
- "1.8.2": {
- "title": "Verify that all protection levels have an associated set of protection requirements, such as encryption requirements, integrity requirements, retention, privacy and other confidentiality requirements, and that these are applied in the architecture.",
- "level": "2"
- },
- "1.9.1": {
- "title": "Verify the application encrypts communications between components, particularly when these components are in different containers, systems, sites, or cloud providers.",
- "level": "2"
- },
- "1.9.2": {
- "title": "Verify that application components verify the authenticity of each side in a communication link to prevent person-in-the-middle attacks. For example, application components should validate TLS certificates and chains.",
- "level": "2"
- },
- "2.1.1": {
- "title": "Verify that user set passwords are at least 12 characters in length.",
- "level": "1"
- },
- "2.1.10": {
- "title": "Verify that there are no periodic credential rotation or password history requirements.",
- "level": "1"
- },
- "2.1.11": {
- "title": "Verify that \"paste\" functionality, browser password helpers, and external password managers are permitted.",
- "level": "1"
- },
- "2.1.12": {
- "title": "Verify that the user can choose to either temporarily view the entire masked password, or temporarily view the last typed character of the password on platforms that do not have this as native functionality.",
- "level": "1"
- },
- "2.1.2": {
- "title": "Verify that passwords 64 characters or longer are permitted.",
- "level": "1"
- },
- "2.1.3": {
- "title": "Verify that passwords can contain spaces and truncation is not performed. Consecutive multiple spaces MAY optionally be coalesced.",
- "level": "1"
- },
- "2.1.4": {
- "title": "Verify that Unicode characters are permitted in passwords. A single Unicode code point is considered a character, so 12 emoji or 64 kanji characters should be valid and permitted.",
- "level": "1"
- },
- "2.1.5": {
- "title": "Verify users can change their password.",
- "level": "1"
- },
- "2.1.6": {
- "title": "Verify that password change functionality requires the user's current and new password.",
- "level": "1"
- },
- "2.1.7": {
- "title": "Verify that passwords submitted during account registration, login, and password change are checked against a set of breached passwords either locally (such as the top 1,000 or 10,000 most common passwords which match the system's password policy) or using an external API. If using an API a zero knowledge proof or other mechanism should be used to ensure that the plain text password is not sent or used in verifying the breach status of the password. If the password is breached, the application must require the user to set a new non-breached password.",
- "level": "1"
- },
- "2.1.8": {
- "title": "Verify that a password strength meter is provided to help users set a stronger password.",
- "level": "1"
- },
- "2.1.9": {
- "title": "Verify that there are no password composition rules limiting the type of characters permitted. There should be no requirement for upper or lower case or numbers or special characters.",
- "level": "1"
- },
- "2.10.1": {
- "title": "Verify that integration secrets do not rely on unchanging passwords, such as API keys or shared privileged accounts.",
- "level": "1"
- },
- "2.10.2": {
- "title": "Verify that if passwords are required, the credentials are not a default account.",
- "level": "1"
- },
- "2.10.3": {
- "title": "Verify that passwords are stored with sufficient protection to prevent offline recovery attacks, including local system access.",
- "level": "1"
- },
- "2.10.4": {
- "title": "Verify passwords, integrations with databases and third-party systems, seeds and internal secrets, and API keys are managed securely and not included in the source code or stored within source code repositories. Such storage SHOULD resist offline attacks. The use of a secure software key store (L1), hardware trusted platform module (TPM), or a hardware security module (L3) is recommended for password storage.",
- "level": "1"
- },
- "2.2.1": {
- "title": "Verify that anti-automation controls are effective at mitigating breached credential testing, brute force, and account lockout attacks. Such controls include blocking the most common breached passwords, soft lockouts, rate limiting, CAPTCHA, ever increasing delays between attempts, IP address restrictions, or risk-based restrictions such as location, first login on a device, recent attempts to unlock the account, or similar. Verify that no more than 100 failed attempts per hour is possible on a single account.",
- "level": "1"
- },
- "2.2.2": {
- "title": "Verify that the use of weak authenticators (such as SMS and email) is limited to secondary verification and transaction approval and not as a replacement for more secure authentication methods. Verify that stronger methods are offered before weak methods, users are aware of the risks, or that proper measures are in place to limit the risks of account compromise.",
- "level": "1"
- },
- "2.2.3": {
- "title": "Verify that secure notifications are sent to users after updates to authentication details, such as credential resets, email or address changes, logging in from unknown or risky locations. The use of push notifications - rather than SMS or email - is preferred, but in the absence of push notifications, SMS or email is acceptable as long as no sensitive information is disclosed in the notification.",
- "level": "1"
- },
- "2.2.4": {
- "title": "Verify impersonation resistance against phishing, such as the use of multi-factor authentication, cryptographic devices with intent (such as connected keys with a push to authenticate), or at higher AAL levels, client-side certificates.",
- "level": "3"
- },
- "2.2.5": {
- "title": "Verify that where a credential service provider (CSP) and the application verifying authentication are separated, mutually authenticated TLS is in place between the two endpoints.",
- "level": "3"
- },
- "2.2.6": {
- "title": "Verify replay resistance through the mandated use of OTP devices, cryptographic authenticators, or lookup codes.",
- "level": "3"
- },
- "2.2.7": {
- "title": "Verify intent to authenticate by requiring the entry of an OTP token or user-initiated action such as a button press on a FIDO hardware key.",
- "level": "3"
- },
- "2.3.1": {
- "title": "Verify system generated initial passwords or activation codes SHOULD be securely randomly generated, SHOULD be at least 6 characters long, and MAY contain letters and numbers, and expire after a short period of time. These initial secrets must not be permitted to become the long term password.",
- "level": "1"
- },
- "2.3.2": {
- "title": "Verify that enrollment and use of subscriber-provided authentication devices are supported, such as a U2F or FIDO tokens.",
- "level": "2"
- },
- "2.3.3": {
- "title": "Verify that renewal instructions are sent with sufficient time to renew time bound authenticators.",
- "level": "2"
- },
- "2.4.1": {
- "title": "Verify that passwords are stored in a form that is resistant to offline attacks. Passwords SHALL be salted and hashed using an approved one-way key derivation or password hashing function. Key derivation and password hashing functions take a password, a salt, and a cost factor as inputs when generating a password hash.",
- "level": "2"
- },
- "2.4.2": {
- "title": "Verify that the salt is at least 32 bits in length and be chosen arbitrarily to minimize salt value collisions among stored hashes. For each credential, a unique salt value and the resulting hash SHALL be stored.",
- "level": "2"
- },
- "2.4.3": {
- "title": "Verify that if PBKDF2 is used, the iteration count SHOULD be as large as verification server performance will allow, typically at least 100,000 iterations.",
- "level": "2"
- },
- "2.4.4": {
- "title": "Verify that if bcrypt is used, the work factor SHOULD be as large as verification server performance will allow, typically at least 13.",
- "level": "2"
- },
- "2.4.5": {
- "title": "Verify that an additional iteration of a key derivation function is performed, using a salt value that is secret and known only to the verifier. Generate the salt value using an approved random bit generator [SP 800-90Ar1] and provide at least the minimum security strength specified in the latest revision of SP 800-131A. The secret salt value SHALL be stored separately from the hashed passwords (e.g., in a specialized device like a hardware security module).",
- "level": "2"
- },
- "2.5.1": {
- "title": "Verify that a system generated initial activation or recovery secret is not sent in clear text to the user.",
- "level": "1"
- },
- "2.5.2": {
- "title": "Verify password hints or knowledge-based authentication (so-called \"secret questions\") are not present.",
- "level": "1"
- },
- "2.5.3": {
- "title": "Verify password credential recovery does not reveal the current password in any way.",
- "level": "1"
- },
- "2.5.4": {
- "title": "Verify shared or default accounts are not present (e.g. \"root\", \"admin\", or \"sa\").",
- "level": "1"
- },
- "2.5.5": {
- "title": "Verify that if an authentication factor is changed or replaced, that the user is notified of this event.",
- "level": "1"
- },
- "2.5.6": {
- "title": "Verify forgotten password, and other recovery paths use a secure recovery mechanism, such as TOTP or other soft token, mobile push, or another offline recovery mechanism.",
- "level": "1"
- },
- "2.5.7": {
- "title": "Verify that if OTP or multi-factor authentication factors are lost, that evidence of identity proofing is performed at the same level as during enrollment.",
- "level": "2"
- },
- "2.6.1": {
- "title": "Verify that lookup secrets can be used only once.",
- "level": "2"
- },
- "2.6.2": {
- "title": "Verify that lookup secrets have sufficient randomness (112 bits of entropy), or if less than 112 bits of entropy, salted with a unique and random 32-bit salt and hashed with an approved one-way hash.",
- "level": "2"
- },
- "2.6.3": {
- "title": "Verify that lookup secrets are resistant to offline attacks, such as predictable values.",
- "level": "2"
- },
- "2.7.1": {
- "title": "Verify that clear text out of band (NIST \"restricted\") authenticators, such as SMS or PSTN, are not offered by default, and stronger alternatives such as push notifications are offered first.",
- "level": "1"
- },
- "2.7.2": {
- "title": "Verify that the out of band verifier expires out of band authentication requests, codes, or tokens after 10 minutes.",
- "level": "1"
- },
- "2.7.3": {
- "title": "Verify that the out of band verifier authentication requests, codes, or tokens are only usable once, and only for the original authentication request.",
- "level": "1"
- },
- "2.7.4": {
- "title": "Verify that the out of band authenticator and verifier communicates over a secure independent channel.",
- "level": "1"
- },
- "2.7.5": {
- "title": "Verify that the out of band verifier retains only a hashed version of the authentication code.",
- "level": "2"
- },
- "2.7.6": {
- "title": "Verify that the initial authentication code is generated by a secure random number generator, containing at least 20 bits of entropy (typically a six digital random number is sufficient).",
- "level": "2"
- },
- "2.8.1": {
- "title": "Verify that time-based OTPs have a defined lifetime before expiring.",
- "level": "1"
- },
- "2.8.2": {
- "title": "Verify that symmetric keys used to verify submitted OTPs are highly protected, such as by using a hardware security module or secure operating system based key storage.",
- "level": "2"
- },
- "2.8.3": {
- "title": "Verify that approved cryptographic algorithms are used in the generation, seeding, and verification.",
- "level": "2"
- },
- "2.8.4": {
- "title": "Verify that time-based OTP can be used only once within the validity period.",
- "level": "2"
- },
- "2.8.5": {
- "title": "Verify that if a time-based multi factor OTP token is re-used during the validity period, it is logged and rejected with secure notifications being sent to the holder of the device.",
- "level": "2"
- },
- "2.8.6": {
- "title": "Verify physical single factor OTP generator can be revoked in case of theft or other loss. Ensure that revocation is immediately effective across logged in sessions, regardless of location.",
- "level": "2"
- },
- "2.8.7": {
- "title": "Verify that biometric authenticators are limited to use only as secondary factors in conjunction with either something you have and something you know.",
- "level": "3"
- },
- "2.9.1": {
- "title": "Verify that cryptographic keys used in verification are stored securely and protected against disclosure, such as using a TPM or HSM, or an OS service that can use this secure storage.",
- "level": "2"
- },
- "2.9.2": {
- "title": "Verify that the challenge nonce is at least 64 bits in length, and statistically unique or unique over the lifetime of the cryptographic device.",
- "level": "2"
- },
- "2.9.3": {
- "title": "Verify that approved cryptographic algorithms are used in the generation, seeding, and verification.",
- "level": "2"
- },
- "3.1.1": {
- "title": "Verify the application never reveals session tokens in URL parameters or error messages.",
- "level": "1"
- },
- "3.2.1": {
- "title": "Verify the application generates a new session token on user authentication.",
- "level": "1"
- },
- "3.2.2": {
- "title": "Verify that session tokens possess at least 64 bits of entropy.",
- "level": "1"
- },
- "3.2.3": {
- "title": "Verify the application only stores session tokens in the browser using secure methods such as appropriately secured cookies (see section 3.4) or HTML 5 session storage.",
- "level": "1"
- },
- "3.2.4": {
- "title": "Verify that session token are generated using approved cryptographic algorithms.",
- "level": "2"
- },
- "3.3.1": {
- "title": "Verify that logout and expiration invalidate the session token, such that the back button or a downstream relying party does not resume an authenticated session, including across relying parties.",
- "level": "1"
- },
- "3.3.2": {
- "title": "If authenticators permit users to remain logged in, verify that re-authentication occurs periodically both when actively used or after an idle period.",
- "level": "1"
- },
- "3.3.3": {
- "title": "Verify that the application terminates all other active sessions after a successful password change, and that this is effective across the application, federated login (if present), and any relying parties.",
- "level": "2"
- },
- "3.3.4": {
- "title": "Verify that users are able to view and log out of any or all currently active sessions and devices.",
- "level": "2"
- },
- "3.4.1": {
- "title": "Verify that cookie-based session tokens have the 'Secure' attribute set.",
- "level": "1"
- },
- "3.4.2": {
- "title": "Verify that cookie-based session tokens have the 'HttpOnly' attribute set.",
- "level": "1"
- },
- "3.4.3": {
- "title": "Verify that cookie-based session tokens utilize the 'SameSite' attribute to limit exposure to cross-site request forgery attacks.",
- "level": "1"
- },
- "3.4.4": {
- "title": "Verify that cookie-based session tokens use \"__Host-\" prefix (see references) to provide session cookie confidentiality.",
- "level": "1"
- },
- "3.4.5": {
- "title": "Verify that if the application is published under a domain name with other applications that set or use session cookies that might override or disclose the session cookies, set the path attribute in cookie-based session tokens using the most precise path possible.",
- "level": "1"
- },
- "3.5.1": {
- "title": "Verify the application does not treat OAuth and refresh tokens &mdash; on their own &mdash; as the presence of the subscriber and allows users to terminate trust relationships with linked applications.",
- "level": "2"
- },
- "3.5.2": {
- "title": "Verify the application uses session tokens rather than static API secrets and keys, except with legacy implementations.",
- "level": "2"
- },
- "3.5.3": {
- "title": "Verify that stateless session tokens use digital signatures, encryption, and other countermeasures to protect against tampering, enveloping, replay, null cipher, and key substitution attacks.",
- "level": "2"
- },
- "3.6.1": {
- "title": "Verify that relying parties specify the maximum authentication time to CSPs and that CSPs re-authenticate the subscriber if they haven't used a session within that period.",
- "level": "3"
- },
- "3.6.2": {
- "title": "Verify that CSPs inform relying parties of the last authentication event, to allow RPs to determine if they need to re-authenticate the user.",
- "level": "3"
- },
- "3.7.1": {
- "title": "Verify the application ensures a valid login session or requires re-authentication or secondary verification before allowing any sensitive transactions or account modifications.",
- "level": "1"
- },
- "4.1.1": {
- "title": "Verify that the application enforces access control rules on a trusted service layer, especially if client-side access control is present and could be bypassed.",
- "level": "1"
- },
- "4.1.2": {
- "title": "Verify that all user and data attributes and policy information used by access controls cannot be manipulated by end users unless specifically authorized.",
- "level": "1"
- },
- "4.1.3": {
- "title": "Verify that the principle of least privilege exists - users should only be able to access functions, data files, URLs, controllers, services, and other resources, for which they possess specific authorization. This implies protection against spoofing and elevation of privilege.",
- "level": "1"
- },
- "4.1.4": {
- "title": "Verify that the principle of deny by default exists whereby new users/roles start with minimal or no permissions and users/roles do not receive access to new features until access is explicitly assigned. ",
- "level": "1"
- },
- "4.1.5": {
- "title": "Verify that access controls fail securely including when an exception occurs.",
- "level": "1"
- },
- "4.2.1": {
- "title": "Verify that sensitive data and APIs are protected against direct object attacks targeting creation, reading, updating and deletion of records, such as creating or updating someone else's record, viewing everyone's records, or deleting all records.",
- "level": "1"
- },
- "4.2.2": {
- "title": "Verify that the application or framework enforces a strong anti-CSRF mechanism to protect authenticated functionality, and effective anti-automation or anti-CSRF protects unauthenticated functionality.",
- "level": "1"
- },
- "4.3.1": {
- "title": "Verify administrative interfaces use appropriate multi-factor authentication to prevent unauthorized use.",
- "level": "1"
- },
- "4.3.2": {
- "title": "Verify that directory browsing is disabled unless deliberately desired. Additionally, applications should not allow discovery or disclosure of file or directory metadata, such as Thumbs.db, .DS_Store, .git or .svn folders.",
- "level": "1"
- },
- "4.3.3": {
- "title": "Verify the application has additional authorization (such as step up or adaptive authentication) for lower value systems, and / or segregation of duties for high value applications to enforce anti-fraud controls as per the risk of application and past fraud.",
- "level": "2"
- },
- "5.1.1": {
- "title": "Verify that the application has defenses against HTTP parameter pollution attacks, particularly if the application framework makes no distinction about the source of request parameters (GET, POST, cookies, headers, or environment variables).",
- "level": "1"
- },
- "5.1.2": {
- "title": "Verify that frameworks protect against mass parameter assignment attacks, or that the application has countermeasures to protect against unsafe parameter assignment, such as marking fields private or similar.",
- "level": "1"
- },
- "5.1.3": {
- "title": "Verify that all input (HTML form fields, REST requests, URL parameters, HTTP headers, cookies, batch files, RSS feeds, etc) is validated using positive validation (whitelisting).",
- "level": "1"
- },
- "5.1.4": {
- "title": "Verify that structured data is strongly typed and validated against a defined schema including allowed characters, length and pattern (e.g. credit card numbers or telephone, or validating that two related fields are reasonable, such as checking that suburb and zip/postcode match).",
- "level": "1"
- },
- "5.1.5": {
- "title": "Verify that URL redirects and forwards only allow whitelisted destinations, or show a warning when redirecting to potentially untrusted content.",
- "level": "1"
- },
- "5.2.1": {
- "title": "Verify that all untrusted HTML input from WYSIWYG editors or similar is properly sanitized with an HTML sanitizer library or framework feature.",
- "level": "1"
- },
- "5.2.2": {
- "title": "Verify that unstructured data is sanitized to enforce safety measures such as allowed characters and length.",
- "level": "1"
- },
- "5.2.3": {
- "title": "Verify that the application sanitizes user input before passing to mail systems to protect against SMTP or IMAP injection.",
- "level": "1"
- },
- "5.2.4": {
- "title": "Verify that the application avoids the use of eval() or other dynamic code execution features. Where there is no alternative, any user input being included must be sanitized or sandboxed before being executed.",
- "level": "1"
- },
- "5.2.5": {
- "title": "Verify that the application protects against template injection attacks by ensuring that any user input being included is sanitized or sandboxed.",
- "level": "1"
- },
- "5.2.6": {
- "title": "Verify that the application protects against SSRF attacks, by validating or sanitizing untrusted data or HTTP file metadata, such as filenames and URL input fields, use whitelisting of protocols, domains, paths and ports.",
- "level": "1"
- },
- "5.2.7": {
- "title": "Verify that the application sanitizes, disables, or sandboxes user-supplied SVG scriptable content, especially as they relate to XSS resulting from inline scripts, and foreignObject.",
- "level": "1"
- },
- "5.2.8": {
- "title": "Verify that the application sanitizes, disables, or sandboxes user-supplied scriptable or expression template language content, such as Markdown, CSS or XSL stylesheets, BBCode, or similar.",
- "level": "1"
- },
- "5.3.1": {
- "title": "Verify that output encoding is relevant for the interpreter and context required. For example, use encoders specifically for HTML values, HTML attributes, JavaScript, URL Parameters, HTTP headers, SMTP, and others as the context requires, especially from untrusted inputs (e.g. names with Unicode or apostrophes, such as ねこ or O'Hara).",
- "level": "1"
- },
- "5.3.10": {
- "title": "Verify that the application protects against XPath injection or XML injection attacks.",
- "level": "1"
- },
- "5.3.2": {
- "title": "Verify that output encoding preserves the user's chosen character set and locale, such that any Unicode character point is valid and safely handled.",
- "level": "1"
- },
- "5.3.3": {
- "title": "Verify that context-aware, preferably automated - or at worst, manual - output escaping protects against reflected, stored, and DOM based XSS.",
- "level": "1"
- },
- "5.3.4": {
- "title": "Verify that data selection or database queries (e.g. SQL, HQL, ORM, NoSQL) use parameterized queries, ORMs, entity frameworks, or are otherwise protected from database injection attacks.",
- "level": "1"
- },
- "5.3.5": {
- "title": "Verify that where parameterized or safer mechanisms are not present, context-specific output encoding is used to protect against injection attacks, such as the use of SQL escaping to protect against SQL injection.",
- "level": "1"
- },
- "5.3.6": {
- "title": "Verify that the application projects against JavaScript or JSON injection attacks, including for eval attacks, remote JavaScript includes, CSP bypasses, DOM XSS, and JavaScript expression evaluation.",
- "level": "1"
- },
- "5.3.7": {
- "title": "Verify that the application protects against LDAP Injection vulnerabilities, or that specific security controls to prevent LDAP Injection have been implemented.",
- "level": "1"
- },
- "5.3.8": {
- "title": "Verify that the application protects against OS command injection and that operating system calls use parameterized OS queries or use contextual command line output encoding.",
- "level": "1"
- },
- "5.3.9": {
- "title": "Verify that the application protects against Local File Inclusion (LFI) or Remote File Inclusion (RFI) attacks.",
- "level": "1"
- },
- "5.4.1": {
- "title": "Verify that the application uses memory-safe string, safer memory copy and pointer arithmetic to detect or prevent stack, buffer, or heap overflows.",
- "level": "2"
- },
- "5.4.2": {
- "title": "Verify that format strings do not take potentially hostile input, and are constant.",
- "level": "2"
- },
- "5.4.3": {
- "title": "Verify that sign, range, and input validation techniques are used to prevent integer overflows.",
- "level": "2"
- },
- "5.5.1": {
- "title": "Verify that serialized objects use integrity checks or are encrypted to prevent hostile object creation or data tampering.",
- "level": "1"
- },
- "5.5.2": {
- "title": "Verify that the application correctly restricts XML parsers to only use the most restrictive configuration possible and to ensure that unsafe features such as resolving external entities are disabled to prevent XXE.",
- "level": "1"
- },
- "5.5.3": {
- "title": "Verify that deserialization of untrusted data is avoided or is protected in both custom code and third-party libraries (such as JSON, XML and YAML parsers).",
- "level": "1"
- },
- "5.5.4": {
- "title": "Verify that when parsing JSON in browsers or JavaScript-based backends, JSON.parse is used to parse the JSON document. Do not use eval() to parse JSON.",
- "level": "1"
- },
- "6.1.1": {
- "title": "Verify that regulated private data is stored encrypted while at rest, such as personally identifiable information (PII), sensitive personal information, or data assessed likely to be subject to EU's GDPR.",
- "level": "2"
- },
- "6.1.2": {
- "title": "Verify that regulated health data is stored encrypted while at rest, such as medical records, medical device details, or de-anonymized research records.",
- "level": "2"
- },
- "6.1.3": {
- "title": "Verify that regulated financial data is stored encrypted while at rest, such as financial accounts, defaults or credit history, tax records, pay history, beneficiaries, or de-anonymized market or research records.",
- "level": "2"
- },
- "6.2.1": {
- "title": "Verify that all cryptographic modules fail securely, and errors are handled in a way that does not enable Padding Oracle attacks.",
- "level": "1"
- },
- "6.2.2": {
- "title": "Verify that industry proven or government approved cryptographic algorithms, modes, and libraries are used, instead of custom coded cryptography.",
- "level": "2"
- },
- "6.2.3": {
- "title": "Verify that encryption initialization vector, cipher configuration, and block modes are configured securely using the latest advice.",
- "level": "2"
- },
- "6.2.4": {
- "title": "Verify that random number, encryption or hashing algorithms, key lengths, rounds, ciphers or modes, can be reconfigured, upgraded, or swapped at any time, to protect against cryptographic breaks.",
- "level": "2"
- },
- "6.2.5": {
- "title": "Verify that known insecure block modes (i.e. ECB, etc.), padding modes (i.e. PKCS#1 v1.5, etc.), ciphers with small block sizes (i.e. Triple-DES, Blowfish, etc.), and weak hashing algorithms (i.e. MD5, SHA1, etc.) are not used unless required for backwards compatibility.",
- "level": "2"
- },
- "6.2.6": {
- "title": "Verify that nonces, initialization vectors, and other single use numbers must not be used more than once with a given encryption key. The method of generation must be appropriate for the algorithm being used.",
- "level": "2"
- },
- "6.2.7": {
- "title": "Verify that encrypted data is authenticated via signatures, authenticated cipher modes, or HMAC to ensure that ciphertext is not altered by an unauthorized party.",
- "level": "3"
- },
- "6.2.8": {
- "title": "Verify that all cryptographic operations are constant-time, with no 'short-circuit' operations in comparisons, calculations, or returns, to avoid leaking information.",
- "level": "3"
- },
- "6.3.1": {
- "title": "Verify that all random numbers, random file names, random GUIDs, and random strings are generated using the cryptographic module's approved cryptographically secure random number generator when these random values are intended to be not guessable by an attacker.",
- "level": "2"
- },
- "6.3.2": {
- "title": "Verify that random GUIDs are created using the GUID v4 algorithm, and a cryptographically-secure pseudo-random number generator (CSPRNG). GUIDs created using other pseudo-random number generators may be predictable.",
- "level": "2"
- },
- "6.3.3": {
- "title": "Verify that random numbers are created with proper entropy even when the application is under heavy load, or that the application degrades gracefully in such circumstances.",
- "level": "3"
- },
- "6.4.1": {
- "title": "Verify that a secrets management solution such as a key vault is used to securely create, store, control access to and destroy secrets.",
- "level": "2"
- },
- "6.4.2": {
- "title": "Verify that key material is not exposed to the application but instead uses an isolated security module like a vault for cryptographic operations.",
- "level": "2"
- },
- "7.1.1": {
- "title": "Verify that the application does not log credentials or payment details. Session tokens should only be stored in logs in an irreversible, hashed form.",
- "level": "1"
- },
- "7.1.2": {
- "title": "Verify that the application does not log other sensitive data as defined under local privacy laws or relevant security policy.",
- "level": "1"
- },
- "7.1.3": {
- "title": "Verify that the application logs security relevant events including successful and failed authentication events, access control failures, deserialization failures and input validation failures.",
- "level": "2"
- },
- "7.1.4": {
- "title": "Verify that each log event includes necessary information that would allow for a detailed investigation of the timeline when an event happens.",
- "level": "2"
- },
- "7.2.1": {
- "title": "Verify that all authentication decisions are logged, without storing sensitive session identifiers or passwords. This should include requests with relevant metadata needed for security investigations.",
- "level": "2"
- },
- "7.2.2": {
- "title": "Verify that all access control decisions can be logged and all failed decisions are logged. This should include requests with relevant metadata needed for security investigations.",
- "level": "2"
- },
- "7.3.1": {
- "title": "Verify that the application appropriately encodes user-supplied data to prevent log injection.",
- "level": "2"
- },
- "7.3.2": {
- "title": "Verify that all events are protected from injection when viewed in log viewing software.",
- "level": "2"
- },
- "7.3.3": {
- "title": "Verify that security logs are protected from unauthorized access and modification.",
- "level": "2"
- },
- "7.3.4": {
- "title": "Verify that time sources are synchronized to the correct time and time zone. Strongly consider logging only in UTC if systems are global to assist with post-incident forensic analysis.",
- "level": "2"
- },
- "7.4.1": {
- "title": "Verify that a generic message is shown when an unexpected or security sensitive error occurs, potentially with a unique ID which support personnel can use to investigate.",
- "level": "1"
- },
- "7.4.2": {
- "title": "Verify that exception handling (or a functional equivalent) is used across the codebase to account for expected and unexpected error conditions.",
- "level": "2"
- },
- "7.4.3": {
- "title": "Verify that a \"last resort\" error handler is defined which will catch all unhandled exceptions.",
- "level": "2"
- },
- "8.1.1": {
- "title": "Verify the application protects sensitive data from being cached in server components such as load balancers and application caches.",
- "level": "2"
- },
- "8.1.2": {
- "title": "Verify that all cached or temporary copies of sensitive data stored on the server are protected from unauthorized access or purged/invalidated after the authorized user accesses the sensitive data.",
- "level": "2"
- },
- "8.1.3": {
- "title": "Verify the application minimizes the number of parameters in a request, such as hidden fields, Ajax variables, cookies and header values.",
- "level": "2"
- },
- "8.1.4": {
- "title": "Verify the application can detect and alert on abnormal numbers of requests, such as by IP, user, total per hour or day, or whatever makes sense for the application.",
- "level": "2"
- },
- "8.1.5": {
- "title": "Verify that regular backups of important data are performed and that test restoration of data is performed.",
- "level": "3"
- },
- "8.1.6": {
- "title": "Verify that backups are stored securely to prevent data from being stolen or corrupted.",
- "level": "3"
- },
- "8.2.1": {
- "title": "Verify the application sets sufficient anti-caching headers so that sensitive data is not cached in modern browsers.",
- "level": "1"
- },
- "8.2.2": {
- "title": "Verify that data stored in client side storage (such as HTML5 local storage, session storage, IndexedDB, regular cookies or Flash cookies) does not contain sensitive data or PII.",
- "level": "1"
- },
- "8.2.3": {
- "title": "Verify that authenticated data is cleared from client storage, such as the browser DOM, after the client or session is terminated.",
- "level": "1"
- },
- "8.3.1": {
- "title": "Verify that sensitive data is sent to the server in the HTTP message body or headers, and that query string parameters from any HTTP verb do not contain sensitive data.",
- "level": "1"
- },
- "8.3.2": {
- "title": "Verify that users have a method to remove or export their data on demand.",
- "level": "1"
- },
- "8.3.3": {
- "title": "Verify that users are provided clear language regarding collection and use of supplied personal information and that users have provided opt-in consent for the use of that data before it is used in any way.",
- "level": "1"
- },
- "8.3.4": {
- "title": "Verify that all sensitive data created and processed by the application has been identified, and ensure that a policy is in place on how to deal with sensitive data.",
- "level": "1"
- },
- "8.3.5": {
- "title": "Verify accessing sensitive data is audited (without logging the sensitive data itself), if the data is collected under relevant data protection directives or where logging of access is required.",
- "level": "2"
- },
- "8.3.6": {
- "title": "Verify that sensitive information contained in memory is overwritten as soon as it is no longer required to mitigate memory dumping attacks, using zeroes or random data.",
- "level": "2"
- },
- "8.3.7": {
- "title": "Verify that sensitive or private information that is required to be encrypted, is encrypted using approved algorithms that provide both confidentiality and integrity.",
- "level": "2"
- },
- "8.3.8": {
- "title": "Verify that sensitive personal information is subject to data retention classification, such that old or out of date data is deleted automatically, on a schedule, or as the situation requires.",
- "level": "2"
- },
- "9.1.1": {
- "title": "Verify that secured TLS is used for all client connectivity, and does not fall back to insecure or unencrypted protocols.",
- "level": "1"
- },
- "9.1.2": {
- "title": "Verify using online or up to date TLS testing tools that only strong algorithms, ciphers, and protocols are enabled, with the strongest algorithms and ciphers set as preferred.",
- "level": "1"
- },
- "9.1.3": {
- "title": "Verify that old versions of SSL and TLS protocols, algorithms, ciphers, and configuration are disabled, such as SSLv2, SSLv3, or TLS 1.0 and TLS 1.1. The latest version of TLS should be the preferred cipher suite.",
- "level": "1"
- },
- "9.2.1": {
- "title": "Verify that connections to and from the server use trusted TLS certificates. Where internally generated or self-signed certificates are used, the server must be configured to only trust specific internal CAs and specific self-signed certificates. All others should be rejected.",
- "level": "2"
- },
- "9.2.2": {
- "title": "Verify that encrypted communications such as TLS is used for all inbound and outbound connections, including for management ports, monitoring, authentication, API, or web service calls, database, cloud, serverless, mainframe, external, and partner connections. The server must not fall back to insecure or unencrypted protocols.",
- "level": "2"
- },
- "9.2.3": {
- "title": "Verify that all encrypted connections to external systems that involve sensitive information or functions are authenticated.",
- "level": "2"
- },
- "9.2.4": {
- "title": "Verify that proper certification revocation, such as Online Certificate Status Protocol (OCSP) Stapling, is enabled and configured.",
- "level": "2"
- },
- "9.2.5": {
- "title": "Verify that backend TLS connection failures are logged.",
- "level": "3"
- },
- "10.1.1": {
- "title": "Verify that a code analysis tool is in use that can detect potentially malicious code, such as time functions, unsafe file operations and network connections.",
- "level": "3"
- },
- "10.2.1": {
- "title": "Verify that the application source code and third party libraries do not contain unauthorized phone home or data collection capabilities. Where such functionality exists, obtain the user's permission for it to operate before collecting any data.",
- "level": "2"
- },
- "10.2.2": {
- "title": "Verify that the application does not ask for unnecessary or excessive permissions to privacy related features or sensors, such as contacts, cameras, microphones, or location.",
- "level": "2"
- },
- "10.2.3": {
- "title": "Verify that the application source code and third party libraries do not contain back doors, such as hard-coded or additional undocumented accounts or keys, code obfuscation, undocumented binary blobs, rootkits, or anti-debugging, insecure debugging features, or otherwise out of date, insecure, or hidden functionality that could be used maliciously if discovered.",
- "level": "3"
- },
- "10.2.4": {
- "title": "Verify that the application source code and third party libraries does not contain time bombs by searching for date and time related functions.",
- "level": "3"
- },
- "10.2.5": {
- "title": "Verify that the application source code and third party libraries does not contain malicious code, such as salami attacks, logic bypasses, or logic bombs.",
- "level": "3"
- },
- "10.2.6": {
- "title": "Verify that the application source code and third party libraries do not contain Easter eggs or any other potentially unwanted functionality.",
- "level": "3"
- },
- "10.3.1": {
- "title": "Verify that if the application has a client or server auto-update feature, updates should be obtained over secure channels and digitally signed. The update code must validate the digital signature of the update before installing or executing the update.",
- "level": "1"
- },
- "10.3.2": {
- "title": "Verify that the application employs integrity protections, such as code signing or sub-resource integrity. The application must not load or execute code from untrusted sources, such as loading includes, modules, plugins, code, or libraries from untrusted sources or the Internet.",
- "level": "1"
- },
- "10.3.3": {
- "title": "Verify that the application has protection from sub-domain takeovers if the application relies upon DNS entries or DNS sub-domains, such as expired domain names, out of date DNS pointers or CNAMEs, expired projects at public source code repos, or transient cloud APIs, serverless functions, or storage buckets (autogen-bucket-id.cloud.example.com) or similar. Protections can include ensuring that DNS names used by applications are regularly checked for expiry or change.",
- "level": "1"
- },
- "11.1.1": {
- "title": "Verify the application will only process business logic flows for the same user in sequential step order and without skipping steps.",
- "level": "1"
- },
- "11.1.2": {
- "title": "Verify the application will only process business logic flows with all steps being processed in realistic human time, i.e. transactions are not submitted too quickly.",
- "level": "1"
- },
- "11.1.3": {
- "title": "Verify the application has appropriate limits for specific business actions or transactions which are correctly enforced on a per user basis.",
- "level": "1"
- },
- "11.1.4": {
- "title": "Verify the application has sufficient anti-automation controls to detect and protect against data exfiltration, excessive business logic requests, excessive file uploads or denial of service attacks.",
- "level": "1"
- },
- "11.1.5": {
- "title": "Verify the application has business logic limits or validation to protect against likely business risks or threats, identified using threat modelling or similar methodologies.",
- "level": "1"
- },
- "11.1.6": {
- "title": "Verify the application does not suffer from \"time of check to time of use\" (TOCTOU) issues or other race conditions for sensitive operations.",
- "level": "2"
- },
- "11.1.7": {
- "title": "Verify the application monitors for unusual events or activity from a business logic perspective. For example, attempts to perform actions out of order or actions which a normal user would never attempt.",
- "level": "2"
- },
- "11.1.8": {
- "title": "Verify the application has configurable alerting when automated attacks or unusual activity is detected.",
- "level": "2"
- },
- "12.1.1": {
- "title": "Verify that the application will not accept large files that could fill up storage or cause a denial of service attack.",
- "level": "1"
- },
- "12.1.2": {
- "title": "Verify that compressed files are checked for \"zip bombs\" - small input files that will decompress into huge files thus exhausting file storage limits.",
- "level": "2"
- },
- "12.1.3": {
- "title": "Verify that a file size quota and maximum number of files per user is enforced to ensure that a single user cannot fill up the storage with too many files, or excessively large files.",
- "level": "2"
- },
- "12.2.1": {
- "title": "Verify that files obtained from untrusted sources are validated to be of expected type based on the file's content.",
- "level": "2"
- },
- "12.3.1": {
- "title": "Verify that user-submitted filename metadata is not used directly with system or framework file and URL API to protect against path traversal.",
- "level": "1"
- },
- "12.3.2": {
- "title": "Verify that user-submitted filename metadata is validated or ignored to prevent the disclosure, creation, updating or removal of local files (LFI).",
- "level": "1"
- },
- "12.3.3": {
- "title": "Verify that user-submitted filename metadata is validated or ignored to prevent the disclosure or execution of remote files (RFI), which may also lead to SSRF.",
- "level": "1"
- },
- "12.3.4": {
- "title": "Verify that the application protects against reflective file download (RFD) by validating or ignoring user-submitted filenames in a JSON, JSONP, or URL parameter, the response Content-Type header should be set to text/plain, and the Content-Disposition header should have a fixed filename.",
- "level": "1"
- },
- "12.3.5": {
- "title": "Verify that untrusted file metadata is not used directly with system API or libraries, to protect against OS command injection.",
- "level": "1"
- },
- "12.3.6": {
- "title": "Verify that the application does not include and execute functionality from untrusted sources, such as unverified content distribution networks, JavaScript libraries, node npm libraries, or server-side DLLs.",
- "level": "2"
- },
- "12.4.1": {
- "title": "Verify that files obtained from untrusted sources are stored outside the web root, with limited permissions, preferably with strong validation.",
- "level": "1"
- },
- "12.4.2": {
- "title": "Verify that files obtained from untrusted sources are scanned by antivirus scanners to prevent upload of known malicious content.",
- "level": "1"
- },
- "12.5.1": {
- "title": "Verify that the web tier is configured to serve only files with specific file extensions to prevent unintentional information and source code leakage. For example, backup files (e.g. .bak), temporary working files (e.g. .swp), compressed files (.zip, .tar.gz, etc) and other extensions commonly used by editors should be blocked unless required.",
- "level": "1"
- },
- "12.5.2": {
- "title": "Verify that direct requests to uploaded files will never be executed as HTML/JavaScript content.",
- "level": "1"
- },
- "12.6.1": {
- "title": "Verify that the web or application server is configured with a whitelist of resources or systems to which the server can send requests or load data/files from.",
- "level": "1"
- },
- "13.1.1": {
- "title": "Verify that all application components use the same encodings and parsers to avoid parsing attacks that exploit different URI or file parsing behavior that could be used in SSRF and RFI attacks.",
- "level": "1"
- },
- "13.1.2": {
- "title": "Verify that access to administration and management functions is limited to authorized administrators.",
- "level": "1"
- },
- "13.1.3": {
- "title": "Verify API URLs do not expose sensitive information, such as the API key, session tokens etc.",
- "level": "1"
- },
- "13.1.4": {
- "title": "Verify that authorization decisions are made at both the URI, enforced by programmatic or declarative security at the controller or router, and at the resource level, enforced by model-based permissions.",
- "level": "2"
- },
- "13.1.5": {
- "title": "Verify that requests containing unexpected or missing content types are rejected with appropriate headers (HTTP response status 406 Unacceptable or 415 Unsupported Media Type).",
- "level": "2"
- },
- "13.2.1": {
- "title": "Verify that enabled RESTful HTTP methods are a valid choice for the user or action, such as preventing normal users using DELETE or PUT on protected API or resources.",
- "level": "1"
- },
- "13.2.2": {
- "title": "Verify that JSON schema validation is in place and verified before accepting input.",
- "level": "1"
- },
- "13.2.3": {
- "title": "Verify that RESTful web services that utilize cookies are protected from Cross-Site Request Forgery via the use of at least one or more of the following: triple or double submit cookie pattern",
- "level": "1"
- },
- "13.2.4": {
- "title": "Verify that REST services have anti-automation controls to protect against excessive calls, especially if the API is unauthenticated.",
- "level": "2"
- },
- "13.2.5": {
- "title": "Verify that REST services explicitly check the incoming Content-Type to be the expected one, such as application/xml or application/JSON.",
- "level": "2"
- },
- "13.2.6": {
- "title": "Verify that the message headers and payload are trustworthy and not modified in transit. Requiring strong encryption for transport (TLS only) may be sufficient in many cases as it provides both confidentiality and integrity protection. Per-message digital signatures can provide additional assurance on top of the transport protections for high-security applications but bring with them additional complexity and risks to weigh against the benefits.",
- "level": "2"
- },
- "13.3.1": {
- "title": "Verify that XSD schema validation takes place to ensure a properly formed XML document, followed by validation of each input field before any processing of that data takes place.",
- "level": "1"
- },
- "13.3.2": {
- "title": "Verify that the message payload is signed using WS-Security to ensure reliable transport between client and service.",
- "level": "2"
- },
- "13.4.1": {
- "title": "Verify that query whitelisting or a combination of depth limiting and amount limiting should be used to prevent GraphQL or data layer expression denial of service (DoS) as a result of expensive, nested queries. For more advanced scenarios, query cost analysis should be used.",
- "level": "2"
- },
- "13.4.2": {
- "title": "Verify that GraphQL or other data layer authorization logic should be implemented at the business logic layer instead of the GraphQL layer.",
- "level": "2"
- },
- "14.1.1": {
- "title": "Verify that the application build and deployment processes are performed in a secure and repeatable way, such as CI / CD automation, automated configuration management, and automated deployment scripts.",
- "level": "2"
- },
- "14.1.2": {
- "title": "Verify that compiler flags are configured to enable all available buffer overflow protections and warnings, including stack randomization, data execution prevention, and to break the build if an unsafe pointer, memory, format string, integer, or string operations are found.",
- "level": "2"
- },
- "14.1.3": {
- "title": "Verify that server configuration is hardened as per the recommendations of the application server and frameworks in use.",
- "level": "2"
- },
- "14.1.4": {
- "title": "Verify that the application, configuration, and all dependencies can be re-deployed using automated deployment scripts, built from a documented and tested runbook in a reasonable time, or restored from backups in a timely fashion.",
- "level": "2"
- },
- "14.1.5": {
- "title": "Verify that authorized administrators can verify the integrity of all security-relevant configurations to detect tampering.",
- "level": "3"
- },
- "14.2.1": {
- "title": "Verify that all components are up to date, preferably using a dependency checker during build or compile time.",
- "level": "1"
- },
- "14.2.2": {
- "title": "Verify that all unneeded features, documentation, samples, configurations are removed, such as sample applications, platform documentation, and default or example users.",
- "level": "1"
- },
- "14.2.3": {
- "title": "Verify that if application assets, such as JavaScript libraries, CSS stylesheets or web fonts, are hosted externally on a content delivery network (CDN) or external provider, Subresource Integrity (SRI) is used to validate the integrity of the asset.",
- "level": "1"
- },
- "14.2.4": {
- "title": "Verify that third party components come from pre-defined, trusted and continually maintained repositories.",
- "level": "2"
- },
- "14.2.5": {
- "title": "Verify that an inventory catalog is maintained of all third party libraries in use.",
- "level": "2"
- },
- "14.2.6": {
- "title": "Verify that the attack surface is reduced by sandboxing or encapsulating third party libraries to expose only the required behaviour into the application.",
- "level": "2"
- },
- "14.3.1": {
- "title": "Verify that web or application server and framework error messages are configured to deliver user actionable, customized responses to eliminate any unintended security disclosures.",
- "level": "1"
- },
- "14.3.2": {
- "title": "Verify that web or application server and application framework debug modes are disabled in production to eliminate debug features, developer consoles, and unintended security disclosures.",
- "level": "1"
- },
- "14.3.3": {
- "title": "Verify that the HTTP headers or any part of the HTTP response do not expose detailed version information of system components.",
- "level": "1"
- },
- "14.4.1": {
- "title": "Verify that every HTTP response contains a content type header specifying a safe character set (e.g., UTF-8, ISO 8859-1).",
- "level": "1"
- },
- "14.4.2": {
- "title": "Verify that all API responses contain Content-Disposition: attachment; filename=\"api.json\" (or other appropriate filename for the content type).",
- "level": "1"
- },
- "14.4.3": {
- "title": "Verify that a content security policy (CSPv2) is in place that helps mitigate impact for XSS attacks like HTML, DOM, JSON, and JavaScript injection vulnerabilities.",
- "level": "1"
- },
- "14.4.4": {
- "title": "Verify that all responses contain X-Content-Type-Options: nosniff.",
- "level": "1"
- },
- "14.4.5": {
- "title": "Verify that HTTP Strict Transport Security headers are included on all responses and for all subdomains, such as Strict-Transport-Security: max-age=15724800; includeSubdomains.",
- "level": "1"
- },
- "14.4.6": {
- "title": "Verify that a suitable \"Referrer-Policy\" header is included, such as \"no-referrer\" or \"same-origin\".",
- "level": "1"
- },
- "14.4.7": {
- "title": "Verify that a suitable X-Frame-Options or Content-Security-Policy: frame-ancestors header is in use for sites where content should not be embedded in a third-party site.",
- "level": "1"
- },
- "14.5.1": {
- "title": "Verify that the application server only accepts the HTTP methods in use by the application or API, including pre-flight OPTIONS.",
- "level": "1"
- },
- "14.5.2": {
- "title": "Verify that the supplied Origin header is not used for authentication or access control decisions, as the Origin header can easily be changed by an attacker.",
- "level": "1"
- },
- "14.5.3": {
- "title": "Verify that the cross-domain resource sharing (CORS) Access-Control-Allow-Origin header uses a strict white-list of trusted domains to match against and does not support the \"null\" origin.",
- "level": "1"
- },
- "14.5.4": {
- "title": "Verify that HTTP headers added by a trusted proxy or SSO devices, such as a bearer token, are authenticated by the application.",
- "level": "2"
- }
- },
- "stig-ASD_V5R3": {
- "V-222387": {
- "title": "The application must provide a capability to limit the number of logon sessions per user."
- },
- "V-222388": {
- "title": "The application must clear temporary storage and cookies when the session is terminated."
- },
- "V-222389": {
- "title": "The application must automatically terminate the non-privileged user session and log off non-privileged users after a 15 minute idle time period has elapsed."
- },
- "V-222390": {
- "title": "The application must automatically terminate the admin user session and log off admin users after a 10 minute idle time period is exceeded."
- },
- "V-222391": {
- "title": "Applications requiring user access authentication must provide a logoff capability for user initiated communication session."
- },
- "V-222392": {
- "title": "The application must display an explicit logoff message to users indicating the reliable termination of authenticated communications sessions."
- },
- "V-222393": {
- "title": "The application must associate organization-defined types of security attributes having organization-defined security attribute values with information in storage."
- },
- "V-222394": {
- "title": "The application must associate organization-defined types of security attributes having organization-defined security attribute values with information in process."
- },
- "V-222395": {
- "title": "The application must associate organization-defined types of security attributes having organization-defined security attribute values with information in transmission."
- },
- "V-222396": {
- "title": "The application must implement DoD-approved encryption to protect the confidentiality of remote access sessions."
- },
- "V-222397": {
- "title": "The application must implement cryptographic mechanisms to protect the integrity of remote access sessions."
- },
- "V-222398": {
- "title": "Applications with SOAP messages requiring integrity must include the following message elements:-Message ID-Service Request-Timestamp-SAML Assertion (optionally included in messages) and all elements of the message must be digitally signed."
- },
- "V-222399": {
- "title": "Messages protected with WS_Security must use time stamps with creation and expiration times."
- },
- "V-222400": {
- "title": "Validity periods must be verified on all application messages using WS-Security or SAML assertions."
- },
- "V-222401": {
- "title": "The application must ensure each unique asserting party provides unique assertion ID references for each SAML assertion."
- },
- "V-222402": {
- "title": "The application must ensure encrypted assertions, or equivalent confidentiality protections are used when assertion data is passed through an intermediary, and confidentiality of the assertion data is required when passing through the intermediary."
- },
- "V-222403": {
- "title": "The application must use the NotOnOrAfter condition when using the SubjectConfirmation element in a SAML assertion."
- },
- "V-222404": {
- "title": "The application must use both the NotBefore and NotOnOrAfter elements or OneTimeUse element when using the Conditions element in a SAML assertion."
- },
- "V-222405": {
- "title": "The application must ensure if a OneTimeUse element is used in an assertion, there is only one of the same used in the Conditions element portion of an assertion."
- },
- "V-222406": {
- "title": "The application must ensure messages are encrypted when the SessionIndex is tied to privacy data."
- },
- "V-222407": {
- "title": "The application must provide automated mechanisms for supporting account management functions."
- },
- "V-222408": {
- "title": "Shared/group account credentials must be terminated when members leave the group."
- },
- "V-222409": {
- "title": "The application must automatically remove or disable temporary user accounts 72 hours after account creation."
- },
- "V-222410": {
- "title": "The application must have a process, feature or function that prevents removal or disabling of emergency accounts. "
- },
- "V-222411": {
- "title": "The application must automatically disable accounts after a 35 day period of account inactivity."
- },
- "V-222412": {
- "title": "Unnecessary application accounts must be disabled, or deleted."
- },
- "V-222413": {
- "title": "The application must automatically audit account creation."
- },
- "V-222414": {
- "title": "The application must automatically audit account modification."
- },
- "V-222415": {
- "title": "The application must automatically audit account disabling actions."
- },
- "V-222416": {
- "title": "The application must automatically audit account removal actions."
- },
- "V-222417": {
- "title": "The application must notify System Administrators and Information System Security Officers when accounts are created."
- },
- "V-222418": {
- "title": "The application must notify System Administrators and Information System Security Officers when accounts are modified."
- },
- "V-222419": {
- "title": "The application must notify System Administrators and Information System Security Officers of account disabling actions."
- },
- "V-222420": {
- "title": "The application must notify System Administrators and Information System Security Officers of account removal actions."
- },
- "V-222421": {
- "title": "The application must automatically audit account enabling actions."
- },
- "V-222422": {
- "title": "The application must notify System Administrators and Information System Security Officers of account enabling actions."
- },
- "V-222423": {
- "title": "Application data protection requirements must be identified and documented."
- },
- "V-222424": {
- "title": "The application must utilize organization-defined data mining detection techniques for organization-defined data storage objects to adequately detect data mining attempts."
- },
- "V-222425": {
- "title": "The application must enforce approved authorizations for logical access to information and system resources in accordance with applicable access control policies."
- },
- "V-222426": {
- "title": "The application must enforce organization-defined discretionary access control policies over defined subjects and objects."
- },
- "V-222427": {
- "title": "The application must enforce approved authorizations for controlling the flow of information within the system based on organization-defined information flow control policies."
- },
- "V-222428": {
- "title": "The application must enforce approved authorizations for controlling the flow of information between interconnected systems based on organization-defined information flow control policies."
- },
- "V-222429": {
- "title": "The application must prevent non-privileged users from executing privileged functions to include disabling, circumventing, or altering implemented security safeguards/countermeasures."
- },
- "V-222430": {
- "title": "The application must execute without excessive account permissions."
- },
- "V-222431": {
- "title": "The application must audit the execution of privileged functions."
- },
- "V-222432": {
- "title": "The application must enforce the limit of three consecutive invalid logon attempts by a user during a 15 minute time period."
- },
- "V-222433": {
- "title": "The application administrator must follow an approved process to unlock locked user accounts."
- },
- "V-222434": {
- "title": "The application must display the Standard Mandatory DoD Notice and Consent Banner before granting access to the application."
- },
- "V-222435": {
- "title": "The application must retain the Standard Mandatory DoD Notice and Consent Banner on the screen until users acknowledge the usage conditions and take explicit actions to log on for further access."
- },
- "V-222436": {
- "title": "The publicly accessible application must display the Standard Mandatory DoD Notice and Consent Banner before granting access to the application."
- },
- "V-222437": {
- "title": "The application must display the time and date of the users last successful logon."
- },
- "V-222438": {
- "title": "The application must protect against an individual (or process acting on behalf of an individual) falsely denying having performed organization-defined actions to be covered by non-repudiation."
- },
- "V-222439": {
- "title": "For applications providing audit record aggregation, the application must compile audit records from organization-defined information system components into a system-wide audit trail that is time-correlated with an organization-defined level of tolerance for the relationship between time stamps of individual records in the audit trail."
- },
- "V-222441": {
- "title": "The application must provide audit record generation capability for the creation of session IDs."
- },
- "V-222442": {
- "title": "The application must provide audit record generation capability for the destruction of session IDs."
- },
- "V-222443": {
- "title": "The application must provide audit record generation capability for the renewal of session IDs."
- },
- "V-222444": {
- "title": "The application must not write sensitive data into the application logs."
- },
- "V-222445": {
- "title": "The application must provide audit record generation capability for session timeouts."
- },
- "V-222446": {
- "title": "The application must record a time stamp indicating when the event occurred."
- },
- "V-222447": {
- "title": "The application must provide audit record generation capability for HTTP headers including User-Agent, Referer, GET, and POST."
- },
- "V-222448": {
- "title": "The application must provide audit record generation capability for connecting system IP addresses."
- },
- "V-222449": {
- "title": "The application must record the username or user ID of the user associated with the event."
- },
- "V-222450": {
- "title": "The application must generate audit records when successful/unsuccessful attempts to grant privileges occur."
- },
- "V-222451": {
- "title": "The application must generate audit records when successful/unsuccessful attempts to access security objects occur."
- },
- "V-222452": {
- "title": "The application must generate audit records when successful/unsuccessful attempts to access security levels occur."
- },
- "V-222453": {
- "title": "The application must generate audit records when successful/unsuccessful attempts to access categories of information (e.g., classification levels) occur."
- },
- "V-222454": {
- "title": "The application must generate audit records when successful/unsuccessful attempts to modify privileges occur."
- },
- "V-222455": {
- "title": "The application must generate audit records when successful/unsuccessful attempts to modify security objects occur."
- },
- "V-222456": {
- "title": "The application must generate audit records when successful/unsuccessful attempts to modify security levels occur."
- },
- "V-222457": {
- "title": "The application must generate audit records when successful/unsuccessful attempts to modify categories of information (e.g., classification levels) occur."
- },
- "V-222458": {
- "title": "The application must generate audit records when successful/unsuccessful attempts to delete privileges occur."
- },
- "V-222459": {
- "title": "The application must generate audit records when successful/unsuccessful attempts to delete security levels occur."
- },
- "V-222460": {
- "title": "The application must generate audit records when successful/unsuccessful attempts to delete application database security objects occur."
- },
- "V-222461": {
- "title": "The application must generate audit records when successful/unsuccessful attempts to delete categories of information (e.g., classification levels) occur."
- },
- "V-222462": {
- "title": "The application must generate audit records when successful/unsuccessful logon attempts occur."
- },
- "V-222463": {
- "title": "The application must generate audit records for privileged activities or other system-level access."
- },
- "V-222464": {
- "title": "The application must generate audit records showing starting and ending time for user access to the system."
- },
- "V-222465": {
- "title": "The application must generate audit records when successful/unsuccessful accesses to objects occur."
- },
- "V-222466": {
- "title": "The application must generate audit records for all direct access to the information system."
- },
- "V-222467": {
- "title": "The application must generate audit records for all account creations, modifications, disabling, and termination events."
- },
- "V-222468": {
- "title": "The application must initiate session auditing upon startup."
- },
- "V-222469": {
- "title": "The application must log application shutdown events."
- },
- "V-222470": {
- "title": "The application must log destination IP addresses."
- },
- "V-222471": {
- "title": "The application must log user actions involving access to data."
- },
- "V-222472": {
- "title": "The application must log user actions involving changes to data."
- },
- "V-222473": {
- "title": "The application must produce audit records containing information to establish when (date and time) the events occurred."
- },
- "V-222474": {
- "title": "The application must produce audit records containing enough information to establish which component, feature or function of the application triggered the audit event."
- },
- "V-222475": {
- "title": "When using centralized logging; the application must include a unique identifier in order to distinguish itself from other application logs."
- },
- "V-222476": {
- "title": "The application must produce audit records that contain information to establish the outcome of the events."
- },
- "V-222477": {
- "title": "The application must generate audit records containing information that establishes the identity of any individual or process associated with the event."
- },
- "V-222478": {
- "title": "The application must generate audit records containing the full-text recording of privileged commands or the individual identities of group account users."
- },
- "V-222479": {
- "title": "The application must implement transaction recovery logs when transaction based."
- },
- "V-222480": {
- "title": "The application must provide centralized management and configuration of the content to be captured in audit records generated by all application components."
- },
- "V-222481": {
- "title": "The application must off-load audit records onto a different system or media than the system being audited."
- },
- "V-222482": {
- "title": "The application must be configured to write application logs to a centralized log repository."
- },
- "V-222483": {
- "title": "The application must provide an immediate warning to the SA and ISSO (at a minimum) when allocated audit record storage volume reaches 75% of repository maximum audit record storage capacity."
- },
- "V-222484": {
- "title": "Applications categorized as having a moderate or high impact must provide an immediate real-time alert to the SA and ISSO (at a minimum) for all audit failure events."
- },
- "V-222485": {
- "title": "The application must alert the ISSO and SA (at a minimum) in the event of an audit processing failure."
- },
- "V-222486": {
- "title": "The application must shut down by default upon audit failure (unless availability is an overriding concern)."
- },
- "V-222487": {
- "title": "The application must provide the capability to centrally review and analyze audit records from multiple components within the system."
- },
- "V-222488": {
- "title": "The application must provide the capability to filter audit records for events of interest based upon organization-defined criteria."
- },
- "V-222489": {
- "title": "The application must provide an audit reduction capability that supports on-demand reporting requirements."
- },
- "V-222490": {
- "title": "The application must provide an audit reduction capability that supports on-demand audit review and analysis."
- },
- "V-222491": {
- "title": "The application must provide an audit reduction capability that supports after-the-fact investigations of security incidents."
- },
- "V-222492": {
- "title": "The application must provide a report generation capability that supports on-demand audit review and analysis."
- },
- "V-222493": {
- "title": "The application must provide a report generation capability that supports on-demand reporting requirements."
- },
- "V-222494": {
- "title": "The application must provide a report generation capability that supports after-the-fact investigations of security incidents."
- },
- "V-222495": {
- "title": "The application must provide an audit reduction capability that does not alter original content or time ordering of audit records."
- },
- "V-222496": {
- "title": "The application must provide a report generation capability that does not alter original content or time ordering of audit records."
- },
- "V-222497": {
- "title": "The applications must use internal system clocks to generate time stamps for audit records."
- },
- "V-222498": {
- "title": "The application must record time stamps for audit records that can be mapped to Coordinated Universal Time (UTC) or Greenwich Mean Time (GMT)."
- },
- "V-222499": {
- "title": "The application must record time stamps for audit records that meet a granularity of one second for a minimum degree of precision."
- },
- "V-222500": {
- "title": "The application must protect audit information from any type of unauthorized read access."
- },
- "V-222501": {
- "title": "The application must protect audit information from unauthorized modification."
- },
- "V-222502": {
- "title": "The application must protect audit information from unauthorized deletion."
- },
- "V-222503": {
- "title": "The application must protect audit tools from unauthorized access."
- },
- "V-222504": {
- "title": "The application must protect audit tools from unauthorized modification."
- },
- "V-222505": {
- "title": "The application must protect audit tools from unauthorized deletion."
- },
- "V-222506": {
- "title": "The application must back up audit records at least every seven days onto a different system or system component than the system or component being audited."
- },
- "V-222507": {
- "title": "The application must use cryptographic mechanisms to protect the integrity of audit information."
- },
- "V-222508": {
- "title": "Application audit tools must be cryptographically hashed."
- },
- "V-222509": {
- "title": "The integrity of the audit tools must be validated by checking the files for changes in the cryptographic hash value."
- },
- "V-222510": {
- "title": "The application must prohibit user installation of software without explicit privileged status."
- },
- "V-222511": {
- "title": "The application must enforce access restrictions associated with changes to application configuration."
- },
- "V-222512": {
- "title": "The application must audit who makes configuration changes to the application."
- },
- "V-222513": {
- "title": "The application must have the capability to prevent the installation of patches, service packs, or application components without verification the software component has been digitally signed using a certificate that is recognized and approved by the organization."
- },
- "V-222514": {
- "title": "The applications must limit privileges to change the software resident within software libraries."
- },
- "V-222515": {
- "title": "An application vulnerability assessment must be conducted."
- },
- "V-222516": {
- "title": "The application must prevent program execution in accordance with organization-defined policies regarding software program usage and restrictions, and/or rules authorizing the terms and conditions of software program usage."
- },
- "V-222517": {
- "title": "The application must employ a deny-all, permit-by-exception (whitelist) policy to allow the execution of authorized software programs."
- },
- "V-222518": {
- "title": "The application must be configured to disable non-essential capabilities."
- },
- "V-222519": {
- "title": "The application must be configured to use only functions, ports, and protocols permitted to it in the PPSM CAL."
- },
- "V-222520": {
- "title": "The application must require users to reauthenticate when organization-defined circumstances or situations require reauthentication."
- },
- "V-222521": {
- "title": "The application must require devices to reauthenticate when organization-defined circumstances or situations requiring reauthentication."
- },
- "V-222522": {
- "title": "The application must uniquely identify and authenticate organizational users (or processes acting on behalf of organizational users)."
- },
- "V-222523": {
- "title": "The application must use multifactor (Alt. Token) authentication for network access to privileged accounts."
- },
- "V-222524": {
- "title": "The application must accept Personal Identity Verification (PIV) credentials."
- },
- "V-222525": {
- "title": "The application must electronically verify Personal Identity Verification (PIV) credentials."
- },
- "V-222526": {
- "title": "The application must use multifactor (e.g., CAC, Alt. Token) authentication for network access to non-privileged accounts."
- },
- "V-222527": {
- "title": "The application must use multifactor (Alt. Token) authentication for local access to privileged accounts."
- },
- "V-222528": {
- "title": "The application must use multifactor (e.g., CAC, Alt. Token) authentication for local access to non-privileged accounts."
- },
- "V-222529": {
- "title": "The application must ensure users are authenticated with an individual authenticator prior to using a group authenticator."
- },
- "V-222530": {
- "title": "The application must implement replay-resistant authentication mechanisms for network access to privileged accounts."
- },
- "V-222531": {
- "title": "The application must implement replay-resistant authentication mechanisms for network access to non-privileged accounts."
- },
- "V-222532": {
- "title": "The application must utilize mutual authentication when endpoint device non-repudiation protections are required by DoD policy or by the data owner."
- },
- "V-222533": {
- "title": "The application must authenticate all network connected endpoint devices before establishing any connection."
- },
- "V-222534": {
- "title": "Service-Oriented Applications handling non-releasable data must authenticate endpoint devices via mutual SSL/TLS."
- },
- "V-222535": {
- "title": "The application must disable device identifiers after 35 days of inactivity unless a cryptographic certificate is used for authentication."
- },
- "V-222536": {
- "title": "The application must enforce a minimum 15-character password length."
- },
- "V-222537": {
- "title": "The application must enforce password complexity by requiring that at least one upper-case character be used."
- },
- "V-222538": {
- "title": "The application must enforce password complexity by requiring that at least one lower-case character be used."
- },
- "V-222539": {
- "title": "The application must enforce password complexity by requiring that at least one numeric character be used."
- },
- "V-222540": {
- "title": "The application must enforce password complexity by requiring that at least one special character be used."
- },
- "V-222541": {
- "title": "The application must require the change of at least 8 of the total number of characters when passwords are changed."
- },
- "V-222542": {
- "title": "The application must only store cryptographic representations of passwords."
- },
- "V-222543": {
- "title": "The application must transmit only cryptographically-protected passwords."
- },
- "V-222544": {
- "title": "The application must enforce 24 hours/1 day as the minimum password lifetime."
- },
- "V-222545": {
- "title": "The application must enforce a 60-day maximum password lifetime restriction."
- },
- "V-222546": {
- "title": "The application must prohibit password reuse for a minimum of five generations."
- },
- "V-222547": {
- "title": "The application must allow the use of a temporary password for system logons with an immediate change to a permanent password."
- },
- "V-222548": {
- "title": "The application password must not be changeable by users other than the administrator or the user with which the password is associated."
- },
- "V-222549": {
- "title": "The application must terminate existing user sessions upon account deletion."
- },
- "V-222550": {
- "title": "The application, when utilizing PKI-based authentication, must validate certificates by constructing a certification path (which includes status information) to an accepted trust anchor."
- },
- "V-222551": {
- "title": "The application, when using PKI-based authentication, must enforce authorized access to the corresponding private key."
- },
- "V-222552": {
- "title": "The application must map the authenticated identity to the individual user or group account for PKI-based authentication."
- },
- "V-222553": {
- "title": "The application, for PKI-based authentication, must implement a local cache of revocation data to support path discovery and validation in case of the inability to access revocation information via the network."
- },
- "V-222554": {
- "title": "The application must not display passwords/PINs as clear text."
- },
- "V-222555": {
- "title": "The application must use mechanisms meeting the requirements of applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance for authentication to a cryptographic module."
- },
- "V-222556": {
- "title": "The application must uniquely identify and authenticate non-organizational users (or processes acting on behalf of non-organizational users)."
- },
- "V-222557": {
- "title": "The application must accept Personal Identity Verification (PIV) credentials from other federal agencies."
- },
- "V-222558": {
- "title": "The application must electronically verify Personal Identity Verification (PIV) credentials from other federal agencies."
- },
- "V-222559": {
- "title": "The application must accept FICAM-approved third-party credentials."
- },
- "V-222560": {
- "title": "The application must conform to FICAM-issued profiles."
- },
- "V-222561": {
- "title": "Applications used for non-local maintenance sessions must audit non-local maintenance and diagnostic sessions for organization-defined auditable events."
- },
- "V-222562": {
- "title": "Applications used for non-local maintenance sessions must implement cryptographic mechanisms to protect the integrity of non-local maintenance and diagnostic communications."
- },
- "V-222563": {
- "title": "Applications used for non-local maintenance sessions must implement cryptographic mechanisms to protect the confidentiality of non-local maintenance and diagnostic communications."
- },
- "V-222564": {
- "title": "Applications used for non-local maintenance sessions must verify remote disconnection at the termination of non-local maintenance and diagnostic sessions."
- },
- "V-222565": {
- "title": "The application must employ strong authenticators in the establishment of non-local maintenance and diagnostic sessions."
- },
- "V-222566": {
- "title": "The application must terminate all sessions and network connections when non-local maintenance is completed."
- },
- "V-222567": {
- "title": "The application must not be vulnerable to race conditions."
- },
- "V-222568": {
- "title": "The application must terminate all network connections associated with a communications session at the end of the session."
- },
- "V-222570": {
- "title": "The application must utilize FIPS-validated cryptographic modules when signing application components."
- },
- "V-222571": {
- "title": "The application must utilize FIPS-validated cryptographic modules when generating cryptographic hashes."
- },
- "V-222572": {
- "title": "The application must utilize FIPS-validated cryptographic modules when protecting unclassified information that requires cryptographic protection."
- },
- "V-222573": {
- "title": "Applications making SAML assertions must use FIPS-approved random numbers in the generation of SessionIndex in the SAML element AuthnStatement."
- },
- "V-222574": {
- "title": "The application user interface must be either physically or logically separated from data storage and management interfaces."
- },
- "V-222575": {
- "title": "The application must set the HTTPOnly flag on session cookies."
- },
- "V-222576": {
- "title": "The application must set the secure flag on session cookies."
- },
- "V-222577": {
- "title": "The application must not expose session IDs."
- },
- "V-222578": {
- "title": "The application must destroy the session ID value and/or cookie on logoff or browser close."
- },
- "V-222579": {
- "title": "Applications must use system-generated session identifiers that protect against session fixation."
- },
- "V-222580": {
- "title": "Applications must validate session identifiers."
- },
- "V-222581": {
- "title": "Applications must not use URL embedded session IDs."
- },
- "V-222582": {
- "title": "The application must not re-use or recycle session IDs."
- },
- "V-222583": {
- "title": "The application must use the Federal Information Processing Standard (FIPS) 140-2-validated cryptographic modules and random number generator if the application implements encryption, key exchange, digital signature, and hash functionality."
- },
- "V-222584": {
- "title": "The application must only allow the use of DoD-approved certificate authorities for verification of the establishment of protected sessions."
- },
- "V-222585": {
- "title": "The application must fail to a secure state if system initialization fails, shutdown fails, or aborts fail."
- },
- "V-222586": {
- "title": "In the event of a system failure, applications must preserve any information necessary to determine cause of failure and any information necessary to return to operations with least disruption to mission processes."
- },
- "V-222587": {
- "title": "The application must protect the confidentiality and integrity of stored information when required by DoD policy or the information owner."
- },
- "V-222588": {
- "title": "The application must implement approved cryptographic mechanisms to prevent unauthorized modification of organization-defined information at rest on organization-defined information system components."
- },
- "V-222589": {
- "title": "The application must use appropriate cryptography in order to protect stored DoD information when required by the information owner or DoD policy."
- },
- "V-222590": {
- "title": "The application must isolate security functions from non-security functions."
- },
- "V-222591": {
- "title": "The application must maintain a separate execution domain for each executing process."
- },
- "V-222592": {
- "title": "Applications must prevent unauthorized and unintended information transfer via shared system resources."
- },
- "V-222593": {
- "title": "XML-based applications must mitigate DoS attacks by using XML filters, parser options, or gateways."
- },
- "V-222594": {
- "title": "The application must restrict the ability to launch Denial of Service (DoS) attacks against itself or other information systems."
- },
- "V-222595": {
- "title": "The web service design must include redundancy mechanisms when used with high-availability systems."
- },
- "V-222596": {
- "title": "The application must protect the confidentiality and integrity of transmitted information."
- },
- "V-222597": {
- "title": "The application must implement cryptographic mechanisms to prevent unauthorized disclosure of information and/or detect changes to information during transmission unless otherwise protected by alternative physical safeguards, such as, at a minimum, a Protected Distribution System (PDS)."
- },
- "V-222598": {
- "title": "The application must maintain the confidentiality and integrity of information during preparation for transmission."
- },
- "V-222599": {
- "title": "The application must maintain the confidentiality and integrity of information during reception."
- },
- "V-222600": {
- "title": "The application must not disclose unnecessary information to users."
- },
- "V-222601": {
- "title": "The application must not store sensitive information in hidden fields."
- },
- "V-222602": {
- "title": "The application must protect from Cross-Site Scripting (XSS) vulnerabilities."
- },
- "V-222603": {
- "title": "The application must protect from Cross-Site Request Forgery (CSRF) vulnerabilities."
- },
- "V-222604": {
- "title": "The application must protect from command injection."
- },
- "V-222605": {
- "title": "The application must protect from canonical representation vulnerabilities."
- },
- "V-222606": {
- "title": "The application must validate all input."
- },
- "V-222607": {
- "title": "The application must not be vulnerable to SQL Injection."
- },
- "V-222608": {
- "title": "The application must not be vulnerable to XML-oriented attacks."
- },
- "V-222609": {
- "title": "The application must not be subject to input handling vulnerabilities."
- },
- "V-222610": {
- "title": "The application must generate error messages that provide information necessary for corrective actions without revealing information that could be exploited by adversaries."
- },
- "V-222611": {
- "title": "The application must reveal error messages only to the ISSO, ISSM, or SA."
- },
- "V-222612": {
- "title": "The application must not be vulnerable to overflow attacks."
- },
- "V-222613": {
- "title": "The application must remove organization-defined software components after updated versions have been installed."
- },
- "V-222614": {
- "title": "Security-relevant software updates and patches must be kept up to date."
- },
- "V-222615": {
- "title": "The application performing organization-defined security functions must verify correct operation of security functions."
- },
- "V-222616": {
- "title": "The application must perform verification of the correct operation of security functions: upon system startup and/or restart; upon command by a user with privileged access; and/or every 30 days."
- },
- "V-222617": {
- "title": "The application must notify the ISSO and ISSM of failed security verification tests."
- },
- "V-222618": {
- "title": "Unsigned Category 1A mobile code must not be used in the application in accordance with DoD policy."
- },
- "V-222619": {
- "title": "The ISSO must ensure an account management process is implemented, verifying only authorized users can gain access to the application, and individual accounts designated as inactive, suspended, or terminated are promptly removed."
- },
- "V-222620": {
- "title": "Application web servers must be on a separate network segment from the application and database servers if it is a tiered application operating in the DoD DMZ."
- },
- "V-222621": {
- "title": "The ISSO must ensure application audit trails are retained for at least 1 year for applications without SAMI data, and 5 years for applications including SAMI data."
- },
- "V-222622": {
- "title": "The ISSO must review audit trails periodically based on system documentation recommendations or immediately upon system security events."
- },
- "V-222623": {
- "title": "The ISSO must report all suspected violations of IA policies in accordance with DoD information system IA procedures."
- },
- "V-222624": {
- "title": "The ISSO must ensure active vulnerability testing is performed."
- },
- "V-222625": {
- "title": "Execution flow diagrams and design documents must be created to show how deadlock and recursion issues in web services are being mitigated."
- },
- "V-222626": {
- "title": "The designer must ensure the application does not store configuration and control files in the same directory as user data."
- },
- "V-222627": {
- "title": "The ISSO must ensure if a DoD STIG or NSA guide is not available, a third-party product will be configured by following available guidance."
- },
- "V-222628": {
- "title": "New IP addresses, data services, and associated ports used by the application must be submitted to the appropriate approving authority for the organization, which in turn will be submitted through the DoD Ports, Protocols, and Services Management (DoD PPSM)"
- },
- "V-222629": {
- "title": "The application must be registered with the DoD Ports and Protocols Database."
- },
- "V-222630": {
- "title": "The Configuration Management (CM) repository must be properly patched and STIG compliant."
- },
- "V-222631": {
- "title": "Access privileges to the Configuration Management (CM) repository must be reviewed every three months."
- },
- "V-222632": {
- "title": "A Software Configuration Management (SCM) plan describing the configuration control and change management process of application objects developed by the organization and the roles and responsibilities of the organization must be created and maintained."
- },
- "V-222633": {
- "title": "A Configuration Control Board (CCB) that meets at least every release cycle, for managing the Configuration Management (CM) process must be established."
- },
- "V-222634": {
- "title": "The application services and interfaces must be compatible with and ready for IPv6 networks."
- },
- "V-222635": {
- "title": "The application must not be hosted on a general purpose machine if the application is designated as critical or high availability by the ISSO."
- },
- "V-222636": {
- "title": "A disaster recovery/continuity plan must exist in accordance with DoD policy based on the applications availability requirements."
- },
- "V-222637": {
- "title": "Recovery procedures and technical system features must exist so recovery is performed in a secure and verifiable manner. The ISSO will document circumstances inhibiting a trusted recovery."
- },
- "V-222638": {
- "title": "Data backup must be performed at required intervals in accordance with DoD policy."
- },
- "V-222639": {
- "title": "Back-up copies of the application software or source code must be stored in a fire-rated container or stored separately (offsite)."
- },
- "V-222640": {
- "title": "Procedures must be in place to assure the appropriate physical and technical protection of the backup and restoration of the application."
- },
- "V-222641": {
- "title": "The application must use encryption to implement key exchange and authenticate endpoints prior to establishing a communication channel for key exchange."
- },
- "V-222642": {
- "title": "The application must not contain embedded authentication data."
- },
- "V-222643": {
- "title": "The application must have the capability to mark sensitive/classified output when required."
- },
- "V-222644": {
- "title": "Prior to each release of the application, updates to system, or applying patches; tests plans and procedures must be created and executed."
- },
- "V-222645": {
- "title": "Application files must be cryptographically hashed prior to deploying to DoD operational networks."
- },
- "V-222646": {
- "title": "At least one tester must be designated to test for security flaws in addition to functional testing."
- },
- "V-222647": {
- "title": "Test procedures must be created and at least annually executed to ensure system initialization, shutdown, and aborts are configured to verify the system remains in a secure state."
- },
- "V-222648": {
- "title": "An application code review must be performed on the application."
- },
- "V-222649": {
- "title": "Code coverage statistics must be maintained for each release of the application."
- },
- "V-222650": {
- "title": "Flaws found during a code review must be tracked in a defect tracking system."
- },
- "V-222651": {
- "title": "The changes to the application must be assessed for IA and accreditation impact prior to implementation."
- },
- "V-222652": {
- "title": "Security flaws must be fixed or addressed in the project plan."
- },
- "V-222653": {
- "title": "The application development team must follow a set of coding standards."
- },
- "V-222654": {
- "title": "The designer must create and update the Design Document for each release of the application."
- },
- "V-222655": {
- "title": "Threat models must be documented and reviewed for each application release and updated as required by design and functionality changes or when new threats are discovered."
- },
- "V-222656": {
- "title": "The application must not be subject to error handling vulnerabilities."
- },
- "V-222657": {
- "title": "The application development team must provide an application incident response plan."
- },
- "V-222658": {
- "title": "All products must be supported by the vendor or the development team."
- },
- "V-222659": {
- "title": "The application must be decommissioned when maintenance or support is no longer available."
- },
- "V-222660": {
- "title": "Procedures must be in place to notify users when an application is decommissioned."
- },
- "V-222661": {
- "title": "Unnecessary built-in application accounts must be disabled."
- },
- "V-222662": {
- "title": "Default passwords must be changed."
- },
- "V-222663": {
- "title": "An Application Configuration Guide must be created and included with the application."
- },
- "V-222664": {
- "title": "If the application contains classified data, a Security Classification Guide must exist containing data elements and their classification."
- },
- "V-222665": {
- "title": "The designer must ensure uncategorized or emerging mobile code is not used in applications."
- },
- "V-222666": {
- "title": "Production database exports must have database administration credentials and sensitive data removed before releasing the export."
- },
- "V-222667": {
- "title": "Protections against DoS attacks must be implemented."
- },
- "V-222668": {
- "title": "The system must alert an administrator when low resource conditions are encountered."
- },
- "V-222669": {
- "title": "At least one application administrator must be registered to receive update notifications, or security alerts, when automated alerts are available."
- },
- "V-222670": {
- "title": "The application must provide notifications or alerts when product update and security related patches are available."
- },
- "V-222671": {
- "title": "Connections between the DoD enclave and the Internet or other public or commercial wide area networks must require a DMZ."
- },
- "V-222672": {
- "title": "The application must generate audit records when concurrent logons from different workstations occur."
- },
- "V-222673": {
- "title": "The Program Manager must verify all levels of program management, designers, developers, and testers receive annual security training pertaining to their job function."
- },
- "V-254803": {
- "title": "The application must implement NSA-approved cryptography to protect classified information in accordance with applicable federal laws, Executive Orders, directives, policies, regulations, and standards."
- }
- },
- "casa": {
- "1": {
- "title": "Architecture, Design And Threat Modelling"
- },
- "2": {
- "title": "Authentication"
- },
- "3": {
- "title": "Session Management"
- },
- "4": {
- "title": "Access Control"
- },
- "5": {
- "title": "Malicious Input Handling"
- },
- "6": {
- "title": "Cryptography At Rest"
- },
- "7": {
- "title": "Error Handling And Logging"
- },
- "8": {
- "title": "Data Protection"
- },
- "9": {
- "title": "Communications Security"
- },
- "10": {
- "title": "Malicious Controls"
- },
- "11": {
- "title": "Business Logic"
- },
- "12": {
- "title": "Files And Resources"
- },
- "13": {
- "title": "Web Services"
- },
- "14": {
- "title": "Configuration"
- },
- "1.1.1": {
- "title": "Verify the use of a secure software development lifecycle that addresses security in all stages of development.",
- "level": "2"
- },
- "1.1.2": {
- "title": "Verify the use of threat modeling for every design change or sprint planning to identify threats, plan for countermeasures, facilitate appropriate risk responses, and guide security testing.",
- "level": "2"
- },
- "1.1.3": {
- "title": "Verify that all user stories and features contain functional security constraints, such as \"As a user,I should be able to view and edit my profile.I should not be able to view or edit anyone else 's profile\"",
- "level": "2"
- },
- "1.1.4": {
- "title": "Verify documentation and justification of all the application's trust boundaries, components, and significant data flows.",
- "level": "2"
- },
- "1.1.5": {
- "title": "Verify definition and security analysis of the application's high-level architecture and all connected remote services.",
- "level": "2"
- },
- "1.1.6": {
- "title": "Verify implementation of centralized, simple (economy of design), vetted, secure, and reusable security controls to avoid duplicate, missing, ineffective, or insecure controls.",
- "level": "2"
- },
- "1.1.7": {
- "title": "Verify availability of a secure coding checklist, security requirements, guideline, or policy to all developers and testers.",
- "level": "2"
- },
- "1.10.1": {
- "title": "Verify that a source code control system is in use, with procedures to ensure that check-ins are accompanied by issues or change tickets. The source code control system should have access control and identifiable users to allow traceability of any changes.",
- "level": "2"
- },
- "1.11.1": {
- "title": "Verify the definition and documentation of all application components in terms of the business or security functions they provide.",
- "level": "2"
- },
- "1.11.2": {
- "title": "Verify that all high-value business logic flows, including authentication, session management and access control, do not share unsynchronized state.",
- "level": "2"
- },
- "1.11.3": {
- "title": "Verify that all high-value business logic flows, including authentication, session management and access control are thread safe and resistant to time-of-check and time-of-use race conditions.",
- "level": "3"
- },
- "1.12.1": {
- "title": "Verify that user-uploaded files are stored outside of the web root.",
- "level": "2"
- },
- "1.12.2": {
- "title": "Verify that user-uploaded files - if required to be displayed or downloaded from the application - are served by either octet stream downloads, or from an unrelated domain, such as a cloud file storage bucket. Implement a suitable content security policy to reduce the risk from XSS vectors or other attacks from the uploaded file.",
- "level": "2"
- },
- "1.14.1": {
- "title": "Verify the segregation of components of differing trust levels through well-defined security controls, firewall rules, API gateways, reverse proxies, cloud-based security groups, or similar mechanisms.",
- "level": "2"
- },
- "1.14.2": {
- "title": "Verify that if deploying binaries to untrusted devices makes use of binary signatures, trusted connections, and verified endpoints.",
- "level": "2"
- },
- "1.14.3": {
- "title": "Verify that the build pipeline warns of out-of-date or insecure components and takes appropriate actions.",
- "level": "2"
- },
- "1.14.4": {
- "title": "Verify that the build pipeline contains a build step to automatically build and verify the secure deployment of the application, particularly if the application infrastructure is software defined, such as cloud environment build scripts.",
- "level": "2"
- },
- "1.14.5": {
- "title": "Verify that application deployments adequately sandbox, containerize and/or isolate at the network level to delay and deter attackers from attacking other applications, especially when they are performing sensitive or dangerous actions such as deserialization.",
- "level": "2"
- },
- "1.14.6": {
- "title": "Verify the application does not use unsupported, insecure, or deprecated client-side technologies such as NSAPI plugins, Flash, Shockwave, ActiveX, Silverlight, NACL, or client-side Java applets.",
- "level": "2"
- },
- "1.2.1": {
- "title": "Verify the use of unique or special low-privilege operating system accounts for all application components, services, and servers.",
- "level": "2"
- },
- "1.2.2": {
- "title": "Verify that communications between application components, including APIs, middleware and data layers, are authenticated. Components should have the least necessary privileges needed.",
- "level": "2"
- },
- "1.2.3": {
- "title": "Verify that the application uses a single vetted authentication mechanism that is known to be secure, can be extended to include strong authentication, and has sufficient logging and monitoring to detect account abuse or breaches.",
- "level": "2"
- },
- "1.2.4": {
- "title": "Verify that all authentication pathways and identity management APIs implement consistent authentication security control strength, such that there are no weaker alternatives per the risk of the application.",
- "level": "2"
- },
- "1.4.1": {
- "title": "Verify that trusted enforcement points such as at access control gateways, servers, and serverless functions enforce access controls. Never enforce access controls on the client.",
- "level": "2"
- },
- "1.4.2": {
- "title": "Verify that the chosen access control solution is flexible enough to meet the application's needs.",
- "level": "2"
- },
- "1.4.3": {
- "title": "Verify enforcement of the principle of least privilege in functions, data files, URLs, controllers, services, and other resources. This implies protection against spoofing and elevation of privilege.",
- "level": "2"
- },
- "1.4.4": {
- "title": "Verify the application uses a single and well-vetted access control mechanism for accessing protected data and resources. All requests must pass through this single mechanism to avoid copy and paste or insecure alternative paths.",
- "level": "2"
- },
- "1.4.5": {
- "title": "Verify that attribute or feature-based access control is used whereby the code checks the user's authorization for a feature/data item rather than just their role. Permissions should still be allocated using roles.",
- "level": "2"
- },
- "1.5.1": {
- "title": "Verify that input and output requirements clearly define how to handle and process data based on type, content, and applicable laws, regulations, and other policy compliance.",
- "level": "2"
- },
- "1.5.2": {
- "title": "Verify that serialization is not used when communicating with untrusted clients. If this is not possible, ensure that adequate integrity controls (and possibly encryption if sensitive data is sent) are enforced to prevent deserialization attacks including object injection.",
- "level": "2"
- },
- "1.5.3": {
- "title": "Verify that input validation is enforced on a trusted service layer.",
- "level": "2"
- },
- "1.5.4": {
- "title": "Verify that output encoding occurs close to or by the interpreter for which it is intended.",
- "level": "2"
- },
- "1.6.1": {
- "title": "Verify that there is an explicit policy for management of cryptographic keys and that a cryptographic key lifecycle follows a key management standard such as NIST SP 800-57.",
- "level": "2"
- },
- "1.6.2": {
- "title": "Verify that consumers of cryptographic services protect key material and other secrets by using key vaults or API based alternatives.",
- "level": "2"
- },
- "1.6.3": {
- "title": "Verify that all keys and passwords are replaceable and are part of a well-defined process to re-encrypt sensitive data.",
- "level": "2"
- },
- "1.6.4": {
- "title": "Verify that symmetric keys, passwords, or API secrets generated by or shared with clients are used only in protecting low risk secrets, such as encrypting local storage, or temporary ephemeral uses such as parameter obfuscation. Sharing secrets with clients is clear-text equivalent and architecturally should be treated as such.",
- "level": "2"
- },
- "1.7.1": {
- "title": "Verify that a common logging format and approach is used across the system. ",
- "level": "2"
- },
- "1.7.2": {
- "title": "Verify that logs are securely transmitted to a preferably remote system for analysis, detection, alerting, and escalation.",
- "level": "2"
- },
- "1.8.1": {
- "title": "Verify that all sensitive data is identified and classified into protection levels.",
- "level": "2"
- },
- "1.8.2": {
- "title": "Verify that all protection levels have an associated set of protection requirements, such as encryption requirements, integrity requirements, retention, privacy and other confidentiality requirements, and that these are applied in the architecture.",
- "level": "2"
- },
- "1.9.1": {
- "title": "Verify the application encrypts communications between components, particularly when these components are in different containers, systems, sites, or cloud providers.",
- "level": "2"
- },
- "1.9.2": {
- "title": "Verify that application components verify the authenticity of each side in a communication link to prevent person-in-the-middle attacks. For example, application components should validate TLS certificates and chains.",
- "level": "2"
- },
- "2.1.1": {
- "title": "Verify that user set passwords are at least 12 characters in length.",
- "level": "1"
- },
- "2.1.10": {
- "title": "Verify that there are no periodic credential rotation or password history requirements.",
- "level": "1"
- },
- "2.1.11": {
- "title": "Verify that \"paste\" functionality, browser password helpers, and external password managers are permitted.",
- "level": "1"
- },
- "2.1.12": {
- "title": "Verify that the user can choose to either temporarily view the entire masked password, or temporarily view the last typed character of the password on platforms that do not have this as native functionality.",
- "level": "1"
- },
- "2.1.2": {
- "title": "Verify that passwords 64 characters or longer are permitted.",
- "level": "1"
- },
- "2.1.3": {
- "title": "Verify that passwords can contain spaces and truncation is not performed. Consecutive multiple spaces MAY optionally be coalesced.",
- "level": "1"
- },
- "2.1.4": {
- "title": "Verify that Unicode characters are permitted in passwords. A single Unicode code point is considered a character, so 12 emoji or 64 kanji characters should be valid and permitted.",
- "level": "1"
- },
- "2.1.5": {
- "title": "Verify users can change their password.",
- "level": "1"
- },
- "2.1.6": {
- "title": "Verify that password change functionality requires the user's current and new password.",
- "level": "1"
- },
- "2.1.7": {
- "title": "Verify that passwords submitted during account registration, login, and password change are checked against a set of breached passwords either locally (such as the top 1,000 or 10,000 most common passwords which match the system's password policy) or using an external API. If using an API a zero knowledge proof or other mechanism should be used to ensure that the plain text password is not sent or used in verifying the breach status of the password. If the password is breached, the application must require the user to set a new non-breached password.",
- "level": "1"
- },
- "2.1.8": {
- "title": "Verify that a password strength meter is provided to help users set a stronger password.",
- "level": "1"
- },
- "2.1.9": {
- "title": "Verify that there are no password composition rules limiting the type of characters permitted. There should be no requirement for upper or lower case or numbers or special characters.",
- "level": "1"
- },
- "2.10.1": {
- "title": "Verify that integration secrets do not rely on unchanging passwords, such as API keys or shared privileged accounts.",
- "level": "1"
- },
- "2.10.2": {
- "title": "Verify that if passwords are required, the credentials are not a default account.",
- "level": "1"
- },
- "2.10.3": {
- "title": "Verify that passwords are stored with sufficient protection to prevent offline recovery attacks, including local system access.",
- "level": "1"
- },
- "2.10.4": {
- "title": "Verify passwords, integrations with databases and third-party systems, seeds and internal secrets, and API keys are managed securely and not included in the source code or stored within source code repositories. Such storage SHOULD resist offline attacks. The use of a secure software key store (L1), hardware trusted platform module (TPM), or a hardware security module (L3) is recommended for password storage.",
- "level": "1"
- },
- "2.2.1": {
- "title": "Verify that anti-automation controls are effective at mitigating breached credential testing, brute force, and account lockout attacks. Such controls include blocking the most common breached passwords, soft lockouts, rate limiting, CAPTCHA, ever increasing delays between attempts, IP address restrictions, or risk-based restrictions such as location, first login on a device, recent attempts to unlock the account, or similar. Verify that no more than 100 failed attempts per hour is possible on a single account.",
- "level": "1"
- },
- "2.2.2": {
- "title": "Verify that the use of weak authenticators (such as SMS and email) is limited to secondary verification and transaction approval and not as a replacement for more secure authentication methods. Verify that stronger methods are offered before weak methods, users are aware of the risks, or that proper measures are in place to limit the risks of account compromise.",
- "level": "1"
- },
- "2.2.3": {
- "title": "Verify that secure notifications are sent to users after updates to authentication details, such as credential resets, email or address changes, logging in from unknown or risky locations. The use of push notifications - rather than SMS or email - is preferred, but in the absence of push notifications, SMS or email is acceptable as long as no sensitive information is disclosed in the notification.",
- "level": "1"
- },
- "2.2.4": {
- "title": "Verify impersonation resistance against phishing, such as the use of multi-factor authentication, cryptographic devices with intent (such as connected keys with a push to authenticate), or at higher AAL levels, client-side certificates.",
- "level": "3"
- },
- "2.2.5": {
- "title": "Verify that where a credential service provider (CSP) and the application verifying authentication are separated, mutually authenticated TLS is in place between the two endpoints.",
- "level": "3"
- },
- "2.2.6": {
- "title": "Verify replay resistance through the mandated use of OTP devices, cryptographic authenticators, or lookup codes.",
- "level": "3"
- },
- "2.2.7": {
- "title": "Verify intent to authenticate by requiring the entry of an OTP token or user-initiated action such as a button press on a FIDO hardware key.",
- "level": "3"
- },
- "2.3.1": {
- "title": "Verify system generated initial passwords or activation codes SHOULD be securely randomly generated, SHOULD be at least 6 characters long, and MAY contain letters and numbers, and expire after a short period of time. These initial secrets must not be permitted to become the long term password.",
- "level": "1"
- },
- "2.3.2": {
- "title": "Verify that enrollment and use of subscriber-provided authentication devices are supported, such as a U2F or FIDO tokens.",
- "level": "2"
- },
- "2.3.3": {
- "title": "Verify that renewal instructions are sent with sufficient time to renew time bound authenticators.",
- "level": "2"
- },
- "2.4.1": {
- "title": "Verify that passwords are stored in a form that is resistant to offline attacks. Passwords SHALL be salted and hashed using an approved one-way key derivation or password hashing function. Key derivation and password hashing functions take a password, a salt, and a cost factor as inputs when generating a password hash.",
- "level": "2"
- },
- "2.4.2": {
- "title": "Verify that the salt is at least 32 bits in length and be chosen arbitrarily to minimize salt value collisions among stored hashes. For each credential, a unique salt value and the resulting hash SHALL be stored.",
- "level": "2"
- },
- "2.4.3": {
- "title": "Verify that if PBKDF2 is used, the iteration count SHOULD be as large as verification server performance will allow, typically at least 100,000 iterations.",
- "level": "2"
- },
- "2.4.4": {
- "title": "Verify that if bcrypt is used, the work factor SHOULD be as large as verification server performance will allow, typically at least 13.",
- "level": "2"
- },
- "2.4.5": {
- "title": "Verify that an additional iteration of a key derivation function is performed, using a salt value that is secret and known only to the verifier. Generate the salt value using an approved random bit generator [SP 800-90Ar1] and provide at least the minimum security strength specified in the latest revision of SP 800-131A. The secret salt value SHALL be stored separately from the hashed passwords (e.g., in a specialized device like a hardware security module).",
- "level": "2"
- },
- "2.5.1": {
- "title": "Verify that a system generated initial activation or recovery secret is not sent in clear text to the user.",
- "level": "1"
- },
- "2.5.2": {
- "title": "Verify password hints or knowledge-based authentication (so-called \"secret questions\") are not present.",
- "level": "1"
- },
- "2.5.3": {
- "title": "Verify password credential recovery does not reveal the current password in any way.",
- "level": "1"
- },
- "2.5.4": {
- "title": "Verify shared or default accounts are not present (e.g. \"root\", \"admin\", or \"sa\").",
- "level": "1"
- },
- "2.5.5": {
- "title": "Verify that if an authentication factor is changed or replaced, that the user is notified of this event.",
- "level": "1"
- },
- "2.5.6": {
- "title": "Verify forgotten password, and other recovery paths use a secure recovery mechanism, such as TOTP or other soft token, mobile push, or another offline recovery mechanism.",
- "level": "1"
- },
- "2.5.7": {
- "title": "Verify that if OTP or multi-factor authentication factors are lost, that evidence of identity proofing is performed at the same level as during enrollment.",
- "level": "2"
- },
- "2.6.1": {
- "title": "Verify that lookup secrets can be used only once.",
- "level": "2"
- },
- "2.6.2": {
- "title": "Verify that lookup secrets have sufficient randomness (112 bits of entropy), or if less than 112 bits of entropy, salted with a unique and random 32-bit salt and hashed with an approved one-way hash.",
- "level": "2"
- },
- "2.6.3": {
- "title": "Verify that lookup secrets are resistant to offline attacks, such as predictable values.",
- "level": "2"
- },
- "2.7.1": {
- "title": "Verify that clear text out of band (NIST \"restricted\") authenticators, such as SMS or PSTN, are not offered by default, and stronger alternatives such as push notifications are offered first.",
- "level": "1"
- },
- "2.7.2": {
- "title": "Verify that the out of band verifier expires out of band authentication requests, codes, or tokens after 10 minutes.",
- "level": "1"
- },
- "2.7.3": {
- "title": "Verify that the out of band verifier authentication requests, codes, or tokens are only usable once, and only for the original authentication request.",
- "level": "1"
- },
- "2.7.4": {
- "title": "Verify that the out of band authenticator and verifier communicates over a secure independent channel.",
- "level": "1"
- },
- "2.7.5": {
- "title": "Verify that the out of band verifier retains only a hashed version of the authentication code.",
- "level": "2"
- },
- "2.7.6": {
- "title": "Verify that the initial authentication code is generated by a secure random number generator, containing at least 20 bits of entropy (typically a six digital random number is sufficient).",
- "level": "2"
- },
- "2.8.1": {
- "title": "Verify that time-based OTPs have a defined lifetime before expiring.",
- "level": "1"
- },
- "2.8.2": {
- "title": "Verify that symmetric keys used to verify submitted OTPs are highly protected, such as by using a hardware security module or secure operating system based key storage.",
- "level": "2"
- },
- "2.8.3": {
- "title": "Verify that approved cryptographic algorithms are used in the generation, seeding, and verification.",
- "level": "2"
- },
- "2.8.4": {
- "title": "Verify that time-based OTP can be used only once within the validity period.",
- "level": "2"
- },
- "2.8.5": {
- "title": "Verify that if a time-based multi factor OTP token is re-used during the validity period, it is logged and rejected with secure notifications being sent to the holder of the device.",
- "level": "2"
- },
- "2.8.6": {
- "title": "Verify physical single factor OTP generator can be revoked in case of theft or other loss. Ensure that revocation is immediately effective across logged in sessions, regardless of location.",
- "level": "2"
- },
- "2.8.7": {
- "title": "Verify that biometric authenticators are limited to use only as secondary factors in conjunction with either something you have and something you know.",
- "level": "3"
- },
- "2.9.1": {
- "title": "Verify that cryptographic keys used in verification are stored securely and protected against disclosure, such as using a TPM or HSM, or an OS service that can use this secure storage.",
- "level": "2"
- },
- "2.9.2": {
- "title": "Verify that the challenge nonce is at least 64 bits in length, and statistically unique or unique over the lifetime of the cryptographic device.",
- "level": "2"
- },
- "2.9.3": {
- "title": "Verify that approved cryptographic algorithms are used in the generation, seeding, and verification.",
- "level": "2"
- },
- "3.1.1": {
- "title": "Verify the application never reveals session tokens in URL parameters or error messages.",
- "level": "1"
- },
- "3.2.1": {
- "title": "Verify the application generates a new session token on user authentication.",
- "level": "1"
- },
- "3.2.2": {
- "title": "Verify that session tokens possess at least 64 bits of entropy.",
- "level": "1"
- },
- "3.2.3": {
- "title": "Verify the application only stores session tokens in the browser using secure methods such as appropriately secured cookies (see section 3.4) or HTML 5 session storage.",
- "level": "1"
- },
- "3.2.4": {
- "title": "Verify that session token are generated using approved cryptographic algorithms.",
- "level": "2"
- },
- "3.3.1": {
- "title": "Verify that logout and expiration invalidate the session token, such that the back button or a downstream relying party does not resume an authenticated session, including across relying parties.",
- "level": "1"
- },
- "3.3.2": {
- "title": "If authenticators permit users to remain logged in, verify that re-authentication occurs periodically both when actively used or after an idle period.",
- "level": "1"
- },
- "3.3.3": {
- "title": "Verify that the application terminates all other active sessions after a successful password change, and that this is effective across the application, federated login (if present), and any relying parties.",
- "level": "2"
- },
- "3.3.4": {
- "title": "Verify that users are able to view and log out of any or all currently active sessions and devices.",
- "level": "2"
- },
- "3.4.1": {
- "title": "Verify that cookie-based session tokens have the 'Secure' attribute set.",
- "level": "1"
- },
- "3.4.2": {
- "title": "Verify that cookie-based session tokens have the 'HttpOnly' attribute set.",
- "level": "1"
- },
- "3.4.3": {
- "title": "Verify that cookie-based session tokens utilize the 'SameSite' attribute to limit exposure to cross-site request forgery attacks.",
- "level": "1"
- },
- "3.4.4": {
- "title": "Verify that cookie-based session tokens use \"__Host-\" prefix (see references) to provide session cookie confidentiality.",
- "level": "1"
- },
- "3.4.5": {
- "title": "Verify that if the application is published under a domain name with other applications that set or use session cookies that might override or disclose the session cookies, set the path attribute in cookie-based session tokens using the most precise path possible.",
- "level": "1"
- },
- "3.5.1": {
- "title": "Verify the application does not treat OAuth and refresh tokens &mdash; on their own &mdash; as the presence of the subscriber and allows users to terminate trust relationships with linked applications.",
- "level": "2"
- },
- "3.5.2": {
- "title": "Verify the application uses session tokens rather than static API secrets and keys, except with legacy implementations.",
- "level": "2"
- },
- "3.5.3": {
- "title": "Verify that stateless session tokens use digital signatures, encryption, and other countermeasures to protect against tampering, enveloping, replay, null cipher, and key substitution attacks.",
- "level": "2"
- },
- "3.6.1": {
- "title": "Verify that relying parties specify the maximum authentication time to CSPs and that CSPs re-authenticate the subscriber if they haven't used a session within that period.",
- "level": "3"
- },
- "3.6.2": {
- "title": "Verify that CSPs inform relying parties of the last authentication event, to allow RPs to determine if they need to re-authenticate the user.",
- "level": "3"
- },
- "3.7.1": {
- "title": "Verify the application ensures a valid login session or requires re-authentication or secondary verification before allowing any sensitive transactions or account modifications.",
- "level": "1"
- },
- "4.1.1": {
- "title": "Verify that the application enforces access control rules on a trusted service layer, especially if client-side access control is present and could be bypassed.",
- "level": "1"
- },
- "4.1.2": {
- "title": "Verify that all user and data attributes and policy information used by access controls cannot be manipulated by end users unless specifically authorized.",
- "level": "1"
- },
- "4.1.3": {
- "title": "Verify that the principle of least privilege exists - users should only be able to access functions, data files, URLs, controllers, services, and other resources, for which they possess specific authorization. This implies protection against spoofing and elevation of privilege.",
- "level": "1"
- },
- "4.1.4": {
- "title": "Verify that the principle of deny by default exists whereby new users/roles start with minimal or no permissions and users/roles do not receive access to new features until access is explicitly assigned. ",
- "level": "1"
- },
- "4.1.5": {
- "title": "Verify that access controls fail securely including when an exception occurs.",
- "level": "1"
- },
- "4.2.1": {
- "title": "Verify that sensitive data and APIs are protected against direct object attacks targeting creation, reading, updating and deletion of records, such as creating or updating someone else's record, viewing everyone's records, or deleting all records.",
- "level": "1"
- },
- "4.2.2": {
- "title": "Verify that the application or framework enforces a strong anti-CSRF mechanism to protect authenticated functionality, and effective anti-automation or anti-CSRF protects unauthenticated functionality.",
- "level": "1"
- },
- "4.3.1": {
- "title": "Verify administrative interfaces use appropriate multi-factor authentication to prevent unauthorized use.",
- "level": "1"
- },
- "4.3.2": {
- "title": "Verify that directory browsing is disabled unless deliberately desired. Additionally, applications should not allow discovery or disclosure of file or directory metadata, such as Thumbs.db, .DS_Store, .git or .svn folders.",
- "level": "1"
- },
- "4.3.3": {
- "title": "Verify the application has additional authorization (such as step up or adaptive authentication) for lower value systems, and / or segregation of duties for high value applications to enforce anti-fraud controls as per the risk of application and past fraud.",
- "level": "2"
- },
- "5.1.1": {
- "title": "Verify that the application has defenses against HTTP parameter pollution attacks, particularly if the application framework makes no distinction about the source of request parameters (GET, POST, cookies, headers, or environment variables).",
- "level": "1"
- },
- "5.1.2": {
- "title": "Verify that frameworks protect against mass parameter assignment attacks, or that the application has countermeasures to protect against unsafe parameter assignment, such as marking fields private or similar.",
- "level": "1"
- },
- "5.1.3": {
- "title": "Verify that all input (HTML form fields, REST requests, URL parameters, HTTP headers, cookies, batch files, RSS feeds, etc) is validated using positive validation (whitelisting).",
- "level": "1"
- },
- "5.1.4": {
- "title": "Verify that structured data is strongly typed and validated against a defined schema including allowed characters, length and pattern (e.g. credit card numbers or telephone, or validating that two related fields are reasonable, such as checking that suburb and zip/postcode match).",
- "level": "1"
- },
- "5.1.5": {
- "title": "Verify that URL redirects and forwards only allow whitelisted destinations, or show a warning when redirecting to potentially untrusted content.",
- "level": "1"
- },
- "5.2.1": {
- "title": "Verify that all untrusted HTML input from WYSIWYG editors or similar is properly sanitized with an HTML sanitizer library or framework feature.",
- "level": "1"
- },
- "5.2.2": {
- "title": "Verify that unstructured data is sanitized to enforce safety measures such as allowed characters and length.",
- "level": "1"
- },
- "5.2.3": {
- "title": "Verify that the application sanitizes user input before passing to mail systems to protect against SMTP or IMAP injection.",
- "level": "1"
- },
- "5.2.4": {
- "title": "Verify that the application avoids the use of eval() or other dynamic code execution features. Where there is no alternative, any user input being included must be sanitized or sandboxed before being executed.",
- "level": "1"
- },
- "5.2.5": {
- "title": "Verify that the application protects against template injection attacks by ensuring that any user input being included is sanitized or sandboxed.",
- "level": "1"
- },
- "5.2.6": {
- "title": "Verify that the application protects against SSRF attacks, by validating or sanitizing untrusted data or HTTP file metadata, such as filenames and URL input fields, use whitelisting of protocols, domains, paths and ports.",
- "level": "1"
- },
- "5.2.7": {
- "title": "Verify that the application sanitizes, disables, or sandboxes user-supplied SVG scriptable content, especially as they relate to XSS resulting from inline scripts, and foreignObject.",
- "level": "1"
- },
- "5.2.8": {
- "title": "Verify that the application sanitizes, disables, or sandboxes user-supplied scriptable or expression template language content, such as Markdown, CSS or XSL stylesheets, BBCode, or similar.",
- "level": "1"
- },
- "5.3.1": {
- "title": "Verify that output encoding is relevant for the interpreter and context required. For example, use encoders specifically for HTML values, HTML attributes, JavaScript, URL Parameters, HTTP headers, SMTP, and others as the context requires, especially from untrusted inputs (e.g. names with Unicode or apostrophes, such as ねこ or O'Hara).",
- "level": "1"
- },
- "5.3.10": {
- "title": "Verify that the application protects against XPath injection or XML injection attacks.",
- "level": "1"
- },
- "5.3.2": {
- "title": "Verify that output encoding preserves the user's chosen character set and locale, such that any Unicode character point is valid and safely handled.",
- "level": "1"
- },
- "5.3.3": {
- "title": "Verify that context-aware, preferably automated - or at worst, manual - output escaping protects against reflected, stored, and DOM based XSS.",
- "level": "1"
- },
- "5.3.4": {
- "title": "Verify that data selection or database queries (e.g. SQL, HQL, ORM, NoSQL) use parameterized queries, ORMs, entity frameworks, or are otherwise protected from database injection attacks.",
- "level": "1"
- },
- "5.3.5": {
- "title": "Verify that where parameterized or safer mechanisms are not present, context-specific output encoding is used to protect against injection attacks, such as the use of SQL escaping to protect against SQL injection.",
- "level": "1"
- },
- "5.3.6": {
- "title": "Verify that the application projects against JavaScript or JSON injection attacks, including for eval attacks, remote JavaScript includes, CSP bypasses, DOM XSS, and JavaScript expression evaluation.",
- "level": "1"
- },
- "5.3.7": {
- "title": "Verify that the application protects against LDAP Injection vulnerabilities, or that specific security controls to prevent LDAP Injection have been implemented.",
- "level": "1"
- },
- "5.3.8": {
- "title": "Verify that the application protects against OS command injection and that operating system calls use parameterized OS queries or use contextual command line output encoding.",
- "level": "1"
- },
- "5.3.9": {
- "title": "Verify that the application protects against Local File Inclusion (LFI) or Remote File Inclusion (RFI) attacks.",
- "level": "1"
- },
- "5.4.1": {
- "title": "Verify that the application uses memory-safe string, safer memory copy and pointer arithmetic to detect or prevent stack, buffer, or heap overflows.",
- "level": "2"
- },
- "5.4.2": {
- "title": "Verify that format strings do not take potentially hostile input, and are constant.",
- "level": "2"
- },
- "5.4.3": {
- "title": "Verify that sign, range, and input validation techniques are used to prevent integer overflows.",
- "level": "2"
- },
- "5.5.1": {
- "title": "Verify that serialized objects use integrity checks or are encrypted to prevent hostile object creation or data tampering.",
- "level": "1"
- },
- "5.5.2": {
- "title": "Verify that the application correctly restricts XML parsers to only use the most restrictive configuration possible and to ensure that unsafe features such as resolving external entities are disabled to prevent XXE.",
- "level": "1"
- },
- "5.5.3": {
- "title": "Verify that deserialization of untrusted data is avoided or is protected in both custom code and third-party libraries (such as JSON, XML and YAML parsers).",
- "level": "1"
- },
- "5.5.4": {
- "title": "Verify that when parsing JSON in browsers or JavaScript-based backends, JSON.parse is used to parse the JSON document. Do not use eval() to parse JSON.",
- "level": "1"
- },
- "6.1.1": {
- "title": "Verify that regulated private data is stored encrypted while at rest, such as personally identifiable information (PII), sensitive personal information, or data assessed likely to be subject to EU's GDPR.",
- "level": "2"
- },
- "6.1.2": {
- "title": "Verify that regulated health data is stored encrypted while at rest, such as medical records, medical device details, or de-anonymized research records.",
- "level": "2"
- },
- "6.1.3": {
- "title": "Verify that regulated financial data is stored encrypted while at rest, such as financial accounts, defaults or credit history, tax records, pay history, beneficiaries, or de-anonymized market or research records.",
- "level": "2"
- },
- "6.2.1": {
- "title": "Verify that all cryptographic modules fail securely, and errors are handled in a way that does not enable Padding Oracle attacks.",
- "level": "1"
- },
- "6.2.2": {
- "title": "Verify that industry proven or government approved cryptographic algorithms, modes, and libraries are used, instead of custom coded cryptography.",
- "level": "2"
- },
- "6.2.3": {
- "title": "Verify that encryption initialization vector, cipher configuration, and block modes are configured securely using the latest advice.",
- "level": "2"
- },
- "6.2.4": {
- "title": "Verify that random number, encryption or hashing algorithms, key lengths, rounds, ciphers or modes, can be reconfigured, upgraded, or swapped at any time, to protect against cryptographic breaks.",
- "level": "2"
- },
- "6.2.5": {
- "title": "Verify that known insecure block modes (i.e. ECB, etc.), padding modes (i.e. PKCS#1 v1.5, etc.), ciphers with small block sizes (i.e. Triple-DES, Blowfish, etc.), and weak hashing algorithms (i.e. MD5, SHA1, etc.) are not used unless required for backwards compatibility.",
- "level": "2"
- },
- "6.2.6": {
- "title": "Verify that nonces, initialization vectors, and other single use numbers must not be used more than once with a given encryption key. The method of generation must be appropriate for the algorithm being used.",
- "level": "2"
- },
- "6.2.7": {
- "title": "Verify that encrypted data is authenticated via signatures, authenticated cipher modes, or HMAC to ensure that ciphertext is not altered by an unauthorized party.",
- "level": "3"
- },
- "6.2.8": {
- "title": "Verify that all cryptographic operations are constant-time, with no 'short-circuit' operations in comparisons, calculations, or returns, to avoid leaking information.",
- "level": "3"
- },
- "6.3.1": {
- "title": "Verify that all random numbers, random file names, random GUIDs, and random strings are generated using the cryptographic module's approved cryptographically secure random number generator when these random values are intended to be not guessable by an attacker.",
- "level": "2"
- },
- "6.3.2": {
- "title": "Verify that random GUIDs are created using the GUID v4 algorithm, and a cryptographically-secure pseudo-random number generator (CSPRNG). GUIDs created using other pseudo-random number generators may be predictable.",
- "level": "2"
- },
- "6.3.3": {
- "title": "Verify that random numbers are created with proper entropy even when the application is under heavy load, or that the application degrades gracefully in such circumstances.",
- "level": "3"
- },
- "6.4.1": {
- "title": "Verify that a secrets management solution such as a key vault is used to securely create, store, control access to and destroy secrets.",
- "level": "2"
- },
- "6.4.2": {
- "title": "Verify that key material is not exposed to the application but instead uses an isolated security module like a vault for cryptographic operations.",
- "level": "2"
- },
- "7.1.1": {
- "title": "Verify that the application does not log credentials or payment details. Session tokens should only be stored in logs in an irreversible, hashed form.",
- "level": "1"
- },
- "7.1.2": {
- "title": "Verify that the application does not log other sensitive data as defined under local privacy laws or relevant security policy.",
- "level": "1"
- },
- "7.1.3": {
- "title": "Verify that the application logs security relevant events including successful and failed authentication events, access control failures, deserialization failures and input validation failures.",
- "level": "2"
- },
- "7.1.4": {
- "title": "Verify that each log event includes necessary information that would allow for a detailed investigation of the timeline when an event happens.",
- "level": "2"
- },
- "7.2.1": {
- "title": "Verify that all authentication decisions are logged, without storing sensitive session identifiers or passwords. This should include requests with relevant metadata needed for security investigations.",
- "level": "2"
- },
- "7.2.2": {
- "title": "Verify that all access control decisions can be logged and all failed decisions are logged. This should include requests with relevant metadata needed for security investigations.",
- "level": "2"
- },
- "7.3.1": {
- "title": "Verify that the application appropriately encodes user-supplied data to prevent log injection.",
- "level": "2"
- },
- "7.3.2": {
- "title": "Verify that all events are protected from injection when viewed in log viewing software.",
- "level": "2"
- },
- "7.3.3": {
- "title": "Verify that security logs are protected from unauthorized access and modification.",
- "level": "2"
- },
- "7.3.4": {
- "title": "Verify that time sources are synchronized to the correct time and time zone. Strongly consider logging only in UTC if systems are global to assist with post-incident forensic analysis.",
- "level": "2"
- },
- "7.4.1": {
- "title": "Verify that a generic message is shown when an unexpected or security sensitive error occurs, potentially with a unique ID which support personnel can use to investigate.",
- "level": "1"
- },
- "7.4.2": {
- "title": "Verify that exception handling (or a functional equivalent) is used across the codebase to account for expected and unexpected error conditions.",
- "level": "2"
- },
- "7.4.3": {
- "title": "Verify that a \"last resort\" error handler is defined which will catch all unhandled exceptions.",
- "level": "2"
- },
- "8.1.1": {
- "title": "Verify the application protects sensitive data from being cached in server components such as load balancers and application caches.",
- "level": "2"
- },
- "8.1.2": {
- "title": "Verify that all cached or temporary copies of sensitive data stored on the server are protected from unauthorized access or purged/invalidated after the authorized user accesses the sensitive data.",
- "level": "2"
- },
- "8.1.3": {
- "title": "Verify the application minimizes the number of parameters in a request, such as hidden fields, Ajax variables, cookies and header values.",
- "level": "2"
- },
- "8.1.4": {
- "title": "Verify the application can detect and alert on abnormal numbers of requests, such as by IP, user, total per hour or day, or whatever makes sense for the application.",
- "level": "2"
- },
- "8.1.5": {
- "title": "Verify that regular backups of important data are performed and that test restoration of data is performed.",
- "level": "3"
- },
- "8.1.6": {
- "title": "Verify that backups are stored securely to prevent data from being stolen or corrupted.",
- "level": "3"
- },
- "8.2.1": {
- "title": "Verify the application sets sufficient anti-caching headers so that sensitive data is not cached in modern browsers.",
- "level": "1"
- },
- "8.2.2": {
- "title": "Verify that data stored in client side storage (such as HTML5 local storage, session storage, IndexedDB, regular cookies or Flash cookies) does not contain sensitive data or PII.",
- "level": "1"
- },
- "8.2.3": {
- "title": "Verify that authenticated data is cleared from client storage, such as the browser DOM, after the client or session is terminated.",
- "level": "1"
- },
- "8.3.1": {
- "title": "Verify that sensitive data is sent to the server in the HTTP message body or headers, and that query string parameters from any HTTP verb do not contain sensitive data.",
- "level": "1"
- },
- "8.3.2": {
- "title": "Verify that users have a method to remove or export their data on demand.",
- "level": "1"
- },
- "8.3.3": {
- "title": "Verify that users are provided clear language regarding collection and use of supplied personal information and that users have provided opt-in consent for the use of that data before it is used in any way.",
- "level": "1"
- },
- "8.3.4": {
- "title": "Verify that all sensitive data created and processed by the application has been identified, and ensure that a policy is in place on how to deal with sensitive data.",
- "level": "1"
- },
- "8.3.5": {
- "title": "Verify accessing sensitive data is audited (without logging the sensitive data itself), if the data is collected under relevant data protection directives or where logging of access is required.",
- "level": "2"
- },
- "8.3.6": {
- "title": "Verify that sensitive information contained in memory is overwritten as soon as it is no longer required to mitigate memory dumping attacks, using zeroes or random data.",
- "level": "2"
- },
- "8.3.7": {
- "title": "Verify that sensitive or private information that is required to be encrypted, is encrypted using approved algorithms that provide both confidentiality and integrity.",
- "level": "2"
- },
- "8.3.8": {
- "title": "Verify that sensitive personal information is subject to data retention classification, such that old or out of date data is deleted automatically, on a schedule, or as the situation requires.",
- "level": "2"
- },
- "9.1.1": {
- "title": "Verify that secured TLS is used for all client connectivity, and does not fall back to insecure or unencrypted protocols.",
- "level": "1"
- },
- "9.1.2": {
- "title": "Verify using online or up to date TLS testing tools that only strong algorithms, ciphers, and protocols are enabled, with the strongest algorithms and ciphers set as preferred.",
- "level": "1"
- },
- "9.1.3": {
- "title": "Verify that old versions of SSL and TLS protocols, algorithms, ciphers, and configuration are disabled, such as SSLv2, SSLv3, or TLS 1.0 and TLS 1.1. The latest version of TLS should be the preferred cipher suite.",
- "level": "1"
- },
- "9.2.1": {
- "title": "Verify that connections to and from the server use trusted TLS certificates. Where internally generated or self-signed certificates are used, the server must be configured to only trust specific internal CAs and specific self-signed certificates. All others should be rejected.",
- "level": "2"
- },
- "9.2.2": {
- "title": "Verify that encrypted communications such as TLS is used for all inbound and outbound connections, including for management ports, monitoring, authentication, API, or web service calls, database, cloud, serverless, mainframe, external, and partner connections. The server must not fall back to insecure or unencrypted protocols.",
- "level": "2"
- },
- "9.2.3": {
- "title": "Verify that all encrypted connections to external systems that involve sensitive information or functions are authenticated.",
- "level": "2"
- },
- "9.2.4": {
- "title": "Verify that proper certification revocation, such as Online Certificate Status Protocol (OCSP) Stapling, is enabled and configured.",
- "level": "2"
- },
- "9.2.5": {
- "title": "Verify that backend TLS connection failures are logged.",
- "level": "3"
- },
- "10.1.1": {
- "title": "Verify that a code analysis tool is in use that can detect potentially malicious code, such as time functions, unsafe file operations and network connections.",
- "level": "3"
- },
- "10.2.1": {
- "title": "Verify that the application source code and third party libraries do not contain unauthorized phone home or data collection capabilities. Where such functionality exists, obtain the user's permission for it to operate before collecting any data.",
- "level": "2"
- },
- "10.2.2": {
- "title": "Verify that the application does not ask for unnecessary or excessive permissions to privacy related features or sensors, such as contacts, cameras, microphones, or location.",
- "level": "2"
- },
- "10.2.3": {
- "title": "Verify that the application source code and third party libraries do not contain back doors, such as hard-coded or additional undocumented accounts or keys, code obfuscation, undocumented binary blobs, rootkits, or anti-debugging, insecure debugging features, or otherwise out of date, insecure, or hidden functionality that could be used maliciously if discovered.",
- "level": "3"
- },
- "10.2.4": {
- "title": "Verify that the application source code and third party libraries does not contain time bombs by searching for date and time related functions.",
- "level": "3"
- },
- "10.2.5": {
- "title": "Verify that the application source code and third party libraries does not contain malicious code, such as salami attacks, logic bypasses, or logic bombs.",
- "level": "3"
- },
- "10.2.6": {
- "title": "Verify that the application source code and third party libraries do not contain Easter eggs or any other potentially unwanted functionality.",
- "level": "3"
- },
- "10.3.1": {
- "title": "Verify that if the application has a client or server auto-update feature, updates should be obtained over secure channels and digitally signed. The update code must validate the digital signature of the update before installing or executing the update.",
- "level": "1"
- },
- "10.3.2": {
- "title": "Verify that the application employs integrity protections, such as code signing or sub-resource integrity. The application must not load or execute code from untrusted sources, such as loading includes, modules, plugins, code, or libraries from untrusted sources or the Internet.",
- "level": "1"
- },
- "10.3.3": {
- "title": "Verify that the application has protection from sub-domain takeovers if the application relies upon DNS entries or DNS sub-domains, such as expired domain names, out of date DNS pointers or CNAMEs, expired projects at public source code repos, or transient cloud APIs, serverless functions, or storage buckets (autogen-bucket-id.cloud.example.com) or similar. Protections can include ensuring that DNS names used by applications are regularly checked for expiry or change.",
- "level": "1"
- },
- "11.1.1": {
- "title": "Verify the application will only process business logic flows for the same user in sequential step order and without skipping steps.",
- "level": "1"
- },
- "11.1.2": {
- "title": "Verify the application will only process business logic flows with all steps being processed in realistic human time, i.e. transactions are not submitted too quickly.",
- "level": "1"
- },
- "11.1.3": {
- "title": "Verify the application has appropriate limits for specific business actions or transactions which are correctly enforced on a per user basis.",
- "level": "1"
- },
- "11.1.4": {
- "title": "Verify the application has sufficient anti-automation controls to detect and protect against data exfiltration, excessive business logic requests, excessive file uploads or denial of service attacks.",
- "level": "1"
- },
- "11.1.5": {
- "title": "Verify the application has business logic limits or validation to protect against likely business risks or threats, identified using threat modelling or similar methodologies.",
- "level": "1"
- },
- "11.1.6": {
- "title": "Verify the application does not suffer from \"time of check to time of use\" (TOCTOU) issues or other race conditions for sensitive operations.",
- "level": "2"
- },
- "11.1.7": {
- "title": "Verify the application monitors for unusual events or activity from a business logic perspective. For example, attempts to perform actions out of order or actions which a normal user would never attempt.",
- "level": "2"
- },
- "11.1.8": {
- "title": "Verify the application has configurable alerting when automated attacks or unusual activity is detected.",
- "level": "2"
- },
- "12.1.1": {
- "title": "Verify that the application will not accept large files that could fill up storage or cause a denial of service attack.",
- "level": "1"
- },
- "12.1.2": {
- "title": "Verify that compressed files are checked for \"zip bombs\" - small input files that will decompress into huge files thus exhausting file storage limits.",
- "level": "2"
- },
- "12.1.3": {
- "title": "Verify that a file size quota and maximum number of files per user is enforced to ensure that a single user cannot fill up the storage with too many files, or excessively large files.",
- "level": "2"
- },
- "12.2.1": {
- "title": "Verify that files obtained from untrusted sources are validated to be of expected type based on the file's content.",
- "level": "2"
- },
- "12.3.1": {
- "title": "Verify that user-submitted filename metadata is not used directly with system or framework file and URL API to protect against path traversal.",
- "level": "1"
- },
- "12.3.2": {
- "title": "Verify that user-submitted filename metadata is validated or ignored to prevent the disclosure, creation, updating or removal of local files (LFI).",
- "level": "1"
- },
- "12.3.3": {
- "title": "Verify that user-submitted filename metadata is validated or ignored to prevent the disclosure or execution of remote files (RFI), which may also lead to SSRF.",
- "level": "1"
- },
- "12.3.4": {
- "title": "Verify that the application protects against reflective file download (RFD) by validating or ignoring user-submitted filenames in a JSON, JSONP, or URL parameter, the response Content-Type header should be set to text/plain, and the Content-Disposition header should have a fixed filename.",
- "level": "1"
- },
- "12.3.5": {
- "title": "Verify that untrusted file metadata is not used directly with system API or libraries, to protect against OS command injection.",
- "level": "1"
- },
- "12.3.6": {
- "title": "Verify that the application does not include and execute functionality from untrusted sources, such as unverified content distribution networks, JavaScript libraries, node npm libraries, or server-side DLLs.",
- "level": "2"
- },
- "12.4.1": {
- "title": "Verify that files obtained from untrusted sources are stored outside the web root, with limited permissions, preferably with strong validation.",
- "level": "1"
- },
- "12.4.2": {
- "title": "Verify that files obtained from untrusted sources are scanned by antivirus scanners to prevent upload of known malicious content.",
- "level": "1"
- },
- "12.5.1": {
- "title": "Verify that the web tier is configured to serve only files with specific file extensions to prevent unintentional information and source code leakage. For example, backup files (e.g. .bak), temporary working files (e.g. .swp), compressed files (.zip, .tar.gz, etc) and other extensions commonly used by editors should be blocked unless required.",
- "level": "1"
- },
- "12.5.2": {
- "title": "Verify that direct requests to uploaded files will never be executed as HTML/JavaScript content.",
- "level": "1"
- },
- "12.6.1": {
- "title": "Verify that the web or application server is configured with a whitelist of resources or systems to which the server can send requests or load data/files from.",
- "level": "1"
- },
- "13.1.1": {
- "title": "Verify that all application components use the same encodings and parsers to avoid parsing attacks that exploit different URI or file parsing behavior that could be used in SSRF and RFI attacks.",
- "level": "1"
- },
- "13.1.2": {
- "title": "Verify that access to administration and management functions is limited to authorized administrators.",
- "level": "1"
- },
- "13.1.3": {
- "title": "Verify API URLs do not expose sensitive information, such as the API key, session tokens etc.",
- "level": "1"
- },
- "13.1.4": {
- "title": "Verify that authorization decisions are made at both the URI, enforced by programmatic or declarative security at the controller or router, and at the resource level, enforced by model-based permissions.",
- "level": "2"
- },
- "13.1.5": {
- "title": "Verify that requests containing unexpected or missing content types are rejected with appropriate headers (HTTP response status 406 Unacceptable or 415 Unsupported Media Type).",
- "level": "2"
- },
- "13.2.1": {
- "title": "Verify that enabled RESTful HTTP methods are a valid choice for the user or action, such as preventing normal users using DELETE or PUT on protected API or resources.",
- "level": "1"
- },
- "13.2.2": {
- "title": "Verify that JSON schema validation is in place and verified before accepting input.",
- "level": "1"
- },
- "13.2.3": {
- "title": "Verify that RESTful web services that utilize cookies are protected from Cross-Site Request Forgery via the use of at least one or more of the following: triple or double submit cookie pattern",
- "level": "1"
- },
- "13.2.4": {
- "title": "Verify that REST services have anti-automation controls to protect against excessive calls, especially if the API is unauthenticated.",
- "level": "2"
- },
- "13.2.5": {
- "title": "Verify that REST services explicitly check the incoming Content-Type to be the expected one, such as application/xml or application/JSON.",
- "level": "2"
- },
- "13.2.6": {
- "title": "Verify that the message headers and payload are trustworthy and not modified in transit. Requiring strong encryption for transport (TLS only) may be sufficient in many cases as it provides both confidentiality and integrity protection. Per-message digital signatures can provide additional assurance on top of the transport protections for high-security applications but bring with them additional complexity and risks to weigh against the benefits.",
- "level": "2"
- },
- "13.3.1": {
- "title": "Verify that XSD schema validation takes place to ensure a properly formed XML document, followed by validation of each input field before any processing of that data takes place.",
- "level": "1"
- },
- "13.3.2": {
- "title": "Verify that the message payload is signed using WS-Security to ensure reliable transport between client and service.",
- "level": "2"
- },
- "13.4.1": {
- "title": "Verify that query whitelisting or a combination of depth limiting and amount limiting should be used to prevent GraphQL or data layer expression denial of service (DoS) as a result of expensive, nested queries. For more advanced scenarios, query cost analysis should be used.",
- "level": "2"
- },
- "13.4.2": {
- "title": "Verify that GraphQL or other data layer authorization logic should be implemented at the business logic layer instead of the GraphQL layer.",
- "level": "2"
- },
- "14.1.1": {
- "title": "Verify that the application build and deployment processes are performed in a secure and repeatable way, such as CI / CD automation, automated configuration management, and automated deployment scripts.",
- "level": "2"
- },
- "14.1.2": {
- "title": "Verify that compiler flags are configured to enable all available buffer overflow protections and warnings, including stack randomization, data execution prevention, and to break the build if an unsafe pointer, memory, format string, integer, or string operations are found.",
- "level": "2"
- },
- "14.1.3": {
- "title": "Verify that server configuration is hardened as per the recommendations of the application server and frameworks in use.",
- "level": "2"
- },
- "14.1.4": {
- "title": "Verify that the application, configuration, and all dependencies can be re-deployed using automated deployment scripts, built from a documented and tested runbook in a reasonable time, or restored from backups in a timely fashion.",
- "level": "2"
- },
- "14.1.5": {
- "title": "Verify that authorized administrators can verify the integrity of all security-relevant configurations to detect tampering.",
- "level": "3"
- },
- "14.2.1": {
- "title": "Verify that all components are up to date, preferably using a dependency checker during build or compile time.",
- "level": "1"
- },
- "14.2.2": {
- "title": "Verify that all unneeded features, documentation, samples, configurations are removed, such as sample applications, platform documentation, and default or example users.",
- "level": "1"
- },
- "14.2.3": {
- "title": "Verify that if application assets, such as JavaScript libraries, CSS stylesheets or web fonts, are hosted externally on a content delivery network (CDN) or external provider, Subresource Integrity (SRI) is used to validate the integrity of the asset.",
- "level": "1"
- },
- "14.2.4": {
- "title": "Verify that third party components come from pre-defined, trusted and continually maintained repositories.",
- "level": "2"
- },
- "14.2.5": {
- "title": "Verify that an inventory catalog is maintained of all third party libraries in use.",
- "level": "2"
- },
- "14.2.6": {
- "title": "Verify that the attack surface is reduced by sandboxing or encapsulating third party libraries to expose only the required behaviour into the application.",
- "level": "2"
- },
- "14.3.1": {
- "title": "Verify that web or application server and framework error messages are configured to deliver user actionable, customized responses to eliminate any unintended security disclosures.",
- "level": "1"
- },
- "14.3.2": {
- "title": "Verify that web or application server and application framework debug modes are disabled in production to eliminate debug features, developer consoles, and unintended security disclosures.",
- "level": "1"
- },
- "14.3.3": {
- "title": "Verify that the HTTP headers or any part of the HTTP response do not expose detailed version information of system components.",
- "level": "1"
- },
- "14.4.1": {
- "title": "Verify that every HTTP response contains a content type header specifying a safe character set (e.g., UTF-8, ISO 8859-1).",
- "level": "1"
- },
- "14.4.2": {
- "title": "Verify that all API responses contain Content-Disposition: attachment; filename=\"api.json\" (or other appropriate filename for the content type).",
- "level": "1"
- },
- "14.4.3": {
- "title": "Verify that a content security policy (CSPv2) is in place that helps mitigate impact for XSS attacks like HTML, DOM, JSON, and JavaScript injection vulnerabilities.",
- "level": "1"
- },
- "14.4.4": {
- "title": "Verify that all responses contain X-Content-Type-Options: nosniff.",
- "level": "1"
- },
- "14.4.5": {
- "title": "Verify that HTTP Strict Transport Security headers are included on all responses and for all subdomains, such as Strict-Transport-Security: max-age=15724800; includeSubdomains.",
- "level": "1"
- },
- "14.4.6": {
- "title": "Verify that a suitable \"Referrer-Policy\" header is included, such as \"no-referrer\" or \"same-origin\".",
- "level": "1"
- },
- "14.4.7": {
- "title": "Verify that a suitable X-Frame-Options or Content-Security-Policy: frame-ancestors header is in use for sites where content should not be embedded in a third-party site.",
- "level": "1"
- },
- "14.5.1": {
- "title": "Verify that the application server only accepts the HTTP methods in use by the application or API, including pre-flight OPTIONS.",
- "level": "1"
- },
- "14.5.2": {
- "title": "Verify that the supplied Origin header is not used for authentication or access control decisions, as the Origin header can easily be changed by an attacker.",
- "level": "1"
- },
- "14.5.3": {
- "title": "Verify that the cross-domain resource sharing (CORS) Access-Control-Allow-Origin header uses a strict white-list of trusted domains to match against and does not support the \"null\" origin.",
- "level": "1"
- },
- "14.5.4": {
- "title": "Verify that HTTP headers added by a trusted proxy or SSO devices, such as a bearer token, are authenticated by the application.",
- "level": "2"
- }
- }
-}
diff --git a/server/sonar-web/src/main/js/helpers/storage.ts b/server/sonar-web/src/main/js/helpers/storage.ts
deleted file mode 100644
index 511e1a8f263..00000000000
--- a/server/sonar-web/src/main/js/helpers/storage.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export function save(key: string, value?: string, suffix?: string): void {
- try {
- const finalKey = suffix ? `${key}.${suffix}` : key;
- if (value) {
- window.localStorage.setItem(finalKey, value);
- } else {
- window.localStorage.removeItem(finalKey);
- }
- } catch (e) {
- // usually that means the storage is full
- // just do nothing in this case
- }
-}
-
-export function remove(key: string, suffix?: string): void {
- try {
- window.localStorage.removeItem(suffix ? `${key}.${suffix}` : key);
- } catch {
- // Fail silently
- }
-}
-
-export function get(key: string, suffix?: string): string | null {
- try {
- return window.localStorage.getItem(suffix ? `${key}.${suffix}` : key);
- } catch {
- return null;
- }
-}
diff --git a/server/sonar-web/src/main/js/helpers/stringify-queryparams.ts b/server/sonar-web/src/main/js/helpers/stringify-queryparams.ts
deleted file mode 100644
index 903f12debbe..00000000000
--- a/server/sonar-web/src/main/js/helpers/stringify-queryparams.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-function stringifyPrimitive(v: any) {
- switch (typeof v) {
- case 'string':
- return v;
-
- case 'boolean':
- return v ? 'true' : 'false';
-
- case 'number':
- return isFinite(v) ? v : '';
-
- default:
- return '';
- }
-}
-
-export function stringify(obj: any, sep?: any, eq?: any, name?: any) {
- sep = sep || '&';
- eq = eq || '=';
- if (obj === null) {
- obj = undefined;
- }
-
- if (typeof obj === 'object') {
- return Object.keys(obj)
- .map((k) => {
- const ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
- if (Array.isArray(obj[k])) {
- return obj[k]
- .map((v: any) => {
- return ks + encodeURIComponent(stringifyPrimitive(v));
- })
- .join(sep);
- }
-
- return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
- })
- .filter(Boolean)
- .join(sep);
- }
-
- if (!name) {
- return '';
- }
-
- return (
- encodeURIComponent(stringifyPrimitive(name)) + eq + encodeURIComponent(stringifyPrimitive(obj))
- );
-}
diff --git a/server/sonar-web/src/main/js/helpers/strings.ts b/server/sonar-web/src/main/js/helpers/strings.ts
deleted file mode 100644
index f4a7d4b8d02..00000000000
--- a/server/sonar-web/src/main/js/helpers/strings.ts
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Dict } from '../types/types';
-
-/*
- * Latinize string by removing all diacritics
- * From http://stackoverflow.com/questions/990904/javascript-remove-accents-in-strings
- */
-const defaultDiacriticsRemovalap = [
- {
- base: 'A',
- letters:
- '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F',
- },
- {
- base: 'AA',
- letters: '\uA732',
- },
- {
- base: 'AE',
- letters: '\u00C6\u01FC\u01E2',
- },
- {
- base: 'AO',
- letters: '\uA734',
- },
- {
- base: 'AU',
- letters: '\uA736',
- },
- {
- base: 'AV',
- letters: '\uA738\uA73A',
- },
- {
- base: 'AY',
- letters: '\uA73C',
- },
- {
- base: 'B',
- letters: '\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181',
- },
- {
- base: 'C',
- letters: '\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E',
- },
- {
- base: 'D',
- letters: '\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779',
- },
- {
- base: 'DZ',
- letters: '\u01F1\u01C4',
- },
- {
- base: 'Dz',
- letters: '\u01F2\u01C5',
- },
- {
- base: 'E',
- letters:
- '\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E',
- },
- {
- base: 'F',
- letters: '\u0046\u24BB\uFF26\u1E1E\u0191\uA77B',
- },
- {
- base: 'G',
- letters:
- '\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E',
- },
- {
- base: 'H',
- letters: '\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D',
- },
- {
- base: 'I',
- letters:
- '\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197',
- },
- {
- base: 'J',
- letters: '\u004A\u24BF\uFF2A\u0134\u0248',
- },
- {
- base: 'K',
- letters: '\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2',
- },
- {
- base: 'L',
- letters:
- '\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780',
- },
- {
- base: 'LJ',
- letters: '\u01C7',
- },
- {
- base: 'Lj',
- letters: '\u01C8',
- },
- {
- base: 'M',
- letters: '\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C',
- },
- {
- base: 'N',
- letters:
- '\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4',
- },
- {
- base: 'NJ',
- letters: '\u01CA',
- },
- {
- base: 'Nj',
- letters: '\u01CB',
- },
- {
- base: 'O',
- letters:
- '\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C',
- },
- {
- base: 'OI',
- letters: '\u01A2',
- },
- {
- base: 'OO',
- letters: '\uA74E',
- },
- {
- base: 'OU',
- letters: '\u0222',
- },
- {
- base: 'OE',
- letters: '\u008C\u0152',
- },
- {
- base: 'oe',
- letters: '\u009C\u0153',
- },
- {
- base: 'P',
- letters: '\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754',
- },
- {
- base: 'Q',
- letters: '\u0051\u24C6\uFF31\uA756\uA758\u024A',
- },
- {
- base: 'R',
- letters:
- '\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782',
- },
- {
- base: 'S',
- letters:
- '\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784',
- },
- {
- base: 'T',
- letters:
- '\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786',
- },
- {
- base: 'TZ',
- letters: '\uA728',
- },
- {
- base: 'U',
- letters:
- '\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244',
- },
- {
- base: 'V',
- letters: '\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245',
- },
- {
- base: 'VY',
- letters: '\uA760',
- },
- {
- base: 'W',
- letters: '\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72',
- },
- {
- base: 'X',
- letters: '\u0058\u24CD\uFF38\u1E8A\u1E8C',
- },
- {
- base: 'Y',
- letters:
- '\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE',
- },
- {
- base: 'Z',
- letters: '\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762',
- },
- {
- base: 'a',
- letters:
- '\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250',
- },
- {
- base: 'aa',
- letters: '\uA733',
- },
- {
- base: 'ae',
- letters: '\u00E6\u01FD\u01E3',
- },
- {
- base: 'ao',
- letters: '\uA735',
- },
- {
- base: 'au',
- letters: '\uA737',
- },
- {
- base: 'av',
- letters: '\uA739\uA73B',
- },
- {
- base: 'ay',
- letters: '\uA73D',
- },
- {
- base: 'b',
- letters: '\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253',
- },
- {
- base: 'c',
- letters: '\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184',
- },
- {
- base: 'd',
- letters: '\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A',
- },
- {
- base: 'dz',
- letters: '\u01F3\u01C6',
- },
- {
- base: 'e',
- letters:
- '\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD',
- },
- {
- base: 'f',
- letters: '\u0066\u24D5\uFF46\u1E1F\u0192\uA77C',
- },
- {
- base: 'g',
- letters:
- '\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F',
- },
- {
- base: 'h',
- letters:
- '\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265',
- },
- {
- base: 'hv',
- letters: '\u0195',
- },
- {
- base: 'i',
- letters:
- '\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131',
- },
- {
- base: 'j',
- letters: '\u006A\u24D9\uFF4A\u0135\u01F0\u0249',
- },
- {
- base: 'k',
- letters: '\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3',
- },
- {
- base: 'l',
- letters:
- '\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747',
- },
- {
- base: 'lj',
- letters: '\u01C9',
- },
- {
- base: 'm',
- letters: '\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F',
- },
- {
- base: 'n',
- letters:
- '\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5',
- },
- {
- base: 'nj',
- letters: '\u01CC',
- },
- {
- base: 'o',
- letters:
- '\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275',
- },
- {
- base: 'oi',
- letters: '\u01A3',
- },
- {
- base: 'ou',
- letters: '\u0223',
- },
- {
- base: 'oo',
- letters: '\uA74F',
- },
- {
- base: 'p',
- letters: '\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755',
- },
- {
- base: 'q',
- letters: '\u0071\u24E0\uFF51\u024B\uA757\uA759',
- },
- {
- base: 'r',
- letters:
- '\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783',
- },
- {
- base: 's',
- letters:
- '\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B',
- },
- {
- base: 't',
- letters:
- '\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787',
- },
- {
- base: 'tz',
- letters: '\uA729',
- },
- {
- base: 'u',
- letters:
- '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289',
- },
- {
- base: 'v',
- letters: '\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C',
- },
- {
- base: 'vy',
- letters: '\uA761',
- },
- {
- base: 'w',
- letters: '\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73',
- },
- {
- base: 'x',
- letters: '\u0078\u24E7\uFF58\u1E8B\u1E8D',
- },
- {
- base: 'y',
- letters:
- '\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF',
- },
- {
- base: 'z',
- letters: '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763',
- },
-];
-
-const diacriticsMap: Dict<string> = {};
-defaultDiacriticsRemovalap.forEach((defaultDiacritic) =>
- defaultDiacritic.letters.split('').forEach((letter) => {
- diacriticsMap[letter] = defaultDiacritic.base;
- }),
-);
-
-// "what?" version ... http://jsperf.com/diacritics/12
-export function latinize(str: string): string {
- // eslint-disable-next-line no-control-regex
- return str.replace(/[^\u0000-\u007E]/g, (a) => diacriticsMap[a] || a);
-}
-
-export function decodeJwt(token: string) {
- const segments = token.split('.');
- const base64Url = segments.length > 1 ? segments[1] : segments[0];
- const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
- return JSON.parse(window.atob(base64));
-}
-
-const VERSION_BUILD = 'build ';
-export function getInstanceVersionNumber(version: string) {
- // e.g. "10.5 (build 12345)" => "10.5 (12345)"
- return version.replace(VERSION_BUILD, '');
-}
diff --git a/server/sonar-web/src/main/js/helpers/system.ts b/server/sonar-web/src/main/js/helpers/system.ts
deleted file mode 100644
index f48c50c0206..00000000000
--- a/server/sonar-web/src/main/js/helpers/system.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { isAfter } from 'date-fns';
-import { AppVariablesElement } from '../types/browser';
-import { getEnhancedWindow } from './browser';
-import { parseDate } from './dates';
-
-export function getBaseUrl() {
- return getEnhancedWindow().baseUrl;
-}
-
-export function getSystemStatus() {
- return getEnhancedWindow().serverStatus;
-}
-
-export function getInstance() {
- return getEnhancedWindow().instance;
-}
-
-export function isOfficial() {
- return getEnhancedWindow().official;
-}
-
-export function getReactDomContainerSelector() {
- return '#content';
-}
-
-export function initAppVariables() {
- const appVariablesDiv = document.querySelector<AppVariablesElement>(
- getReactDomContainerSelector(),
- );
- if (appVariablesDiv === null) {
- throw new Error('Failed to get app variables');
- }
-
- getEnhancedWindow().baseUrl = appVariablesDiv.dataset.baseUrl;
- getEnhancedWindow().serverStatus = appVariablesDiv.dataset.serverStatus;
- getEnhancedWindow().instance = appVariablesDiv.dataset.instance;
- getEnhancedWindow().official = Boolean(appVariablesDiv.dataset.official);
-}
-
-export function isCurrentVersionEOLActive(versionEOL: string) {
- return isAfter(parseDate(versionEOL), new Date());
-}
diff --git a/server/sonar-web/src/main/js/helpers/testMocks.ts b/server/sonar-web/src/main/js/helpers/testMocks.ts
deleted file mode 100644
index c1ffa322c1e..00000000000
--- a/server/sonar-web/src/main/js/helpers/testMocks.ts
+++ /dev/null
@@ -1,933 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { omit } from 'lodash';
-import { To } from 'react-router-dom';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import { Location, Router } from '~sonar-aligned/types/router';
-import { CompareResponse } from '../api/quality-profiles';
-import { RuleDescriptionSections } from '../apps/coding-rules/rule';
-import { REST_RULE_KEYS_TO_OLD_KEYS } from '../apps/coding-rules/utils';
-import { Exporter, Profile, ProfileChangelogEvent } from '../apps/quality-profiles/types';
-import { LogsLevels } from '../apps/system/utils';
-import { AppState } from '../types/appstate';
-import {
- CleanCodeAttribute,
- CleanCodeAttributeCategory,
- SoftwareImpactSeverity,
- SoftwareQuality,
-} from '../types/clean-code-taxonomy';
-import { RuleRepository } from '../types/coding-rules';
-import { Cve } from '../types/cves';
-import { EditionKey } from '../types/editions';
-import {
- IssueDeprecatedStatus,
- IssueScope,
- IssueSeverity,
- IssueStatus,
- IssueType,
- RawIssue,
-} from '../types/issues';
-import { Language } from '../types/languages';
-import { Notification } from '../types/notifications';
-import { DumpStatus, DumpTask } from '../types/project-dump';
-import { TaskStatuses } from '../types/tasks';
-import {
- AlmApplication,
- Condition,
- FlowLocation,
- Group,
- GroupMembership,
- HealthTypes,
- IdentityProvider,
- Issue,
- Measure,
- MeasureEnhanced,
- Metric,
- Paging,
- Period,
- RestRuleDetails,
- Rule,
- RuleActivation,
- RuleDetails,
- RuleParameter,
- SysInfoBase,
- SysInfoCluster,
- SysInfoLogging,
- SysInfoStandalone,
- UserGroupMember,
- UserSelected,
-} from '../types/types';
-import { CurrentUser, LoggedInUser, RestUserDetailed, User } from '../types/users';
-
-export function mockAlmApplication(overrides: Partial<AlmApplication> = {}): AlmApplication {
- return {
- backgroundColor: '#444444',
- iconPath: '/images/alm/github.svg',
- installationUrl: 'https://github.com/apps/greg-sonarcloud/installations/new',
- key: 'github',
- name: 'GitHub',
- ...overrides,
- };
-}
-
-export function mockAppState(overrides: Partial<AppState> = {}): AppState {
- return {
- edition: EditionKey.community,
- productionDatabase: true,
- qualifiers: [ComponentQualifier.Project],
- settings: {},
- version: '1.0',
- versionEOL: '2020-01-01',
- documentationUrl: 'https://docs.sonarsource.com/sonarqube/10.0',
- ...overrides,
- };
-}
-
-export function mockBaseSysInfo(overrides: Partial<any> = {}): SysInfoBase {
- return {
- Health: HealthTypes.GREEN,
- 'Health Causes': [],
- System: {
- Version: '7.8',
- },
- Database: {
- Database: 'PostgreSQL',
- 'Database Version': '10.3',
- Username: 'sonar',
- URL: 'jdbc:postgresql://localhost/sonar',
- Driver: 'PostgreSQL JDBC Driver',
- 'Driver Version': '42.2.5',
- },
- 'Compute Engine Tasks': {
- 'Total Pending': 0,
- 'Total In Progress': 0,
- },
- 'Search State': { State: 'GREEN', Nodes: 3 },
- 'Search Indexes': {
- 'Index components - Docs': 30445,
- 'Index components - Shards': 10,
- },
- ...overrides,
- };
-}
-
-export function mockClusterSysInfo(overrides: Partial<any> = {}): SysInfoCluster {
- const baseInfo = mockBaseSysInfo(overrides);
- return {
- ...baseInfo,
- System: {
- ...baseInfo.System,
- 'High Availability': true,
- 'Server ID': 'asd564-asd54a-5dsfg45',
- },
- Settings: {
- 'sonar.cluster.enabled': 'true',
- 'sonar.cluster.node.name': 'server9.example.com',
- },
- 'Application Nodes': [
- {
- Name: 'server1.example.com',
- Host: '10.0.0.0',
- Health: HealthTypes.RED,
- 'Health Causes': ['Something is wrong'],
- System: {
- Version: '7.8',
- },
- Plugins: {
- java: '5.13.0.17924 [SonarJava]',
- },
- 'Web JVM State': {
- 'Max Memory (MB)': 1024,
- 'Free Memory (MB)': 122,
- },
- 'Web Database Connection': {
- 'Pool Active Connections': 1,
- },
- 'Web Logging': { 'Logs Level': 'DEBUG' },
- 'Web JVM Properties': {
- 'file.encoding': 'UTF-8',
- 'file.separator': '/',
- },
- 'Compute Engine Tasks': {
- Pending: 0,
- 'In Progress': 0,
- },
- 'Compute Engine JVM State': {
- 'Max Memory (MB)': 1024,
- 'Free Memory (MB)': 78,
- },
- 'Compute Engine Database Connection': {
- 'Pool Initial Size': 0,
- 'Pool Active Connections': 0,
- },
- 'Compute Engine Logging': {
- 'Logs Level': 'INFO',
- },
- 'Compute Engine JVM Properties': {
- 'file.encoding': 'UTF-8',
- 'file.separator': '/',
- },
- },
- {
- Name: 'server2.example.com',
- Host: '10.0.0.0',
- Health: HealthTypes.YELLOW,
- 'Health Causes': ['Friendly warning'],
- System: {
- Version: '7.8',
- },
- Plugins: {
- java: '5.13.0.17924 [SonarJava]',
- },
- 'Web JVM State': {
- 'Max Memory (MB)': 1024,
- 'Free Memory (MB)': 111,
- },
- 'Web Database Connection': {
- 'Pool Active Connections': 0,
- 'Pool Max Connections': 60,
- },
- 'Web Logging': { 'Logs Level': 'INFO' },
- 'Web JVM Properties': {
- 'file.encoding': 'UTF-8',
- 'file.separator': '/',
- },
- 'Compute Engine Tasks': {
- Pending: 0,
- 'In Progress': 0,
- },
- 'Compute Engine JVM State': {
- 'Max Memory (MB)': 1024,
- 'Free Memory (MB)': 89,
- },
- 'Compute Engine Database Connection': {
- 'Pool Initial Size': 0,
- 'Pool Active Connections': 0,
- },
- 'Compute Engine Logging': {
- 'Logs Level': 'INFO',
- },
- 'Compute Engine JVM Properties': {
- 'file.encoding': 'UTF-8',
- 'file.separator': '/',
- },
- },
- ],
- 'Search Nodes': [
- {
- Name: 'server1.example.com',
- Host: '10.0.0.0',
- 'Search State': {
- 'CPU Usage (%)': 0,
- 'Disk Available': '93 GB',
- },
- },
- {
- Name: 'server2.example.com',
- Host: '10.0.0.0',
- 'Search State': {
- 'CPU Usage (%)': 0,
- 'Disk Available': '93 GB',
- },
- },
- {
- Name: 'server3.example.com',
- Host: '10.0.0.0',
- 'Search State': {
- 'CPU Usage (%)': 0,
- 'Disk Available': '93 GB',
- },
- },
- ],
- Statistics: {
- ncloc: 989880,
- },
- ...overrides,
- };
-}
-
-export function mockCondition(overrides: Partial<Condition> = {}): Condition {
- return {
- error: '10',
- id: '1',
- metric: 'coverage',
- op: 'LT',
- ...overrides,
- };
-}
-
-export function mockCurrentUser(overrides: Partial<CurrentUser> = {}): CurrentUser {
- return {
- isLoggedIn: false,
- dismissedNotices: {
- educationPrinciples: false,
- },
- ...overrides,
- };
-}
-
-export function mockLoggedInUser(overrides: Partial<LoggedInUser> = {}): LoggedInUser {
- return {
- groups: [],
- isLoggedIn: true,
- login: 'luke',
- name: 'Skywalker',
- scmAccounts: [],
- dismissedNotices: {
- educationPrinciples: false,
- },
- ...overrides,
- };
-}
-
-export function mockGroup(overrides: Partial<Group> = {}): Group {
- return {
- id: Math.random().toString(),
- name: 'Foo',
- managed: false,
- ...overrides,
- };
-}
-
-export function mockGroupMembership(overrides: Partial<GroupMembership> = {}): GroupMembership {
- return {
- id: Math.random().toString(),
- userId: Math.random().toString(),
- groupId: Math.random().toString(),
- ...overrides,
- };
-}
-
-export function mockRawIssue(withLocations = false, overrides: Partial<RawIssue> = {}): RawIssue {
- const rawIssue: RawIssue = {
- actions: [],
- component: 'main.js',
- key: 'AVsae-CQS-9G3txfbFN2',
- creationDate: '2023-01-15T09:36:01+0100',
- line: 25,
- project: 'myproject',
- rule: 'javascript:S1067',
- severity: IssueSeverity.Major,
- textRange: { startLine: 25, endLine: 26, startOffset: 0, endOffset: 15 },
- type: IssueType.CodeSmell,
- status: IssueDeprecatedStatus.Open,
- issueStatus: IssueStatus.Open,
- transitions: [],
- scope: IssueScope.Main,
- cleanCodeAttributeCategory: CleanCodeAttributeCategory.Responsible,
- cleanCodeAttribute: CleanCodeAttribute.Respectful,
- impacts: [
- { softwareQuality: SoftwareQuality.Maintainability, severity: SoftwareImpactSeverity.Medium },
- ],
- prioritizedRule: false,
- ...overrides,
- };
-
- if (withLocations) {
- const loc = mockFlowLocation;
-
- rawIssue.flows = [
- {
- locations: [
- loc({ component: overrides.component }),
- loc({ component: overrides.component }),
- ],
- },
- ];
- }
-
- return {
- ...rawIssue,
- ...overrides,
- };
-}
-
-export function mockIssue(withLocations = false, overrides: Partial<Issue> = {}): Issue {
- const issue: Issue = {
- actions: [],
- component: 'main.js',
- componentEnabled: true,
- componentLongName: 'main.js',
- componentQualifier: 'FIL',
- componentUuid: 'foo1234',
- creationDate: '2017-03-01T09:36:01+0100',
- flows: [],
- flowsWithType: [],
- key: 'AVsae-CQS-9G3txfbFN2',
- line: 25,
- message: 'Reduce the number of conditional operators (4) used in the expression',
- project: 'myproject',
- projectKey: 'foo',
- projectName: 'Foo',
- rule: 'javascript:S1067',
- ruleName: 'foo',
- scope: IssueScope.Main,
- secondaryLocations: [],
- severity: IssueSeverity.Major,
- status: IssueDeprecatedStatus.Open,
- issueStatus: IssueStatus.Open,
- textRange: { startLine: 25, endLine: 26, startOffset: 0, endOffset: 15 },
- transitions: [],
- type: IssueType.Bug,
- cleanCodeAttributeCategory: CleanCodeAttributeCategory.Responsible,
- cleanCodeAttribute: CleanCodeAttribute.Respectful,
- impacts: [
- { softwareQuality: SoftwareQuality.Maintainability, severity: SoftwareImpactSeverity.Medium },
- ],
- };
-
- const loc = mockFlowLocation;
-
- if (withLocations) {
- issue.flows = [
- [loc(), loc(), loc()],
- [loc(), loc()],
- ];
- issue.secondaryLocations = [loc(), loc()];
- }
-
- return {
- ...issue,
- ...overrides,
- };
-}
-
-export function mockCve(overrides: Partial<Cve> = {}): Cve {
- return {
- id: 'CVE-2021-12345',
- epssPercentile: 0.56051,
- cvssScore: 0.31051,
- description: 'description',
- cwes: ['CWE-79', 'CWE-89'],
- epssScore: 0.2,
- lastModifiedAt: '2021-10-04T14:00:00Z',
- publishedAt: '2021-10-04T14:00:00Z',
- ...overrides,
- };
-}
-
-export function mockLocation(overrides: Partial<Location> = {}): Location {
- return {
- hash: '',
- key: 'key',
- pathname: '/path',
- query: {},
- search: '',
- state: {},
- ...overrides,
- };
-}
-
-export function mockMetric(
- overrides: Partial<Pick<Metric, 'key' | 'name' | 'type' | 'domain'>> = {},
-): Metric {
- const key = overrides.key || MetricKey.coverage;
- const name = overrides.name || key;
- const type = overrides.type || MetricType.Percent;
- return {
- ...overrides,
- key,
- name,
- type,
- };
-}
-
-export function mockMeasure(overrides: Partial<Measure> = {}): Measure {
- return {
- bestValue: true,
- metric: 'bugs',
- period: {
- bestValue: true,
- index: 1,
- value: '1.0',
- },
- value: '1.0',
- ...overrides,
- };
-}
-
-export function mockMeasureEnhanced(overrides: Partial<MeasureEnhanced> = {}): MeasureEnhanced {
- return {
- bestValue: true,
- leak: '1',
- metric: mockMetric({ ...(overrides.metric || {}) }),
- period: {
- bestValue: true,
- index: 1,
- value: '1.0',
- },
- value: '1.0',
- ...overrides,
- };
-}
-
-export function mockNotification(overrides: Partial<Notification> = {}): Notification {
- return {
- channel: 'channel1',
- type: 'type-global',
- project: 'foo',
- projectName: 'Foo',
- ...overrides,
- };
-}
-
-export function mockPeriod(overrides: Partial<Period> = {}): Period {
- return {
- date: '2019-04-23T02:12:32+0100',
- index: 0,
- mode: 'previous_version',
- ...overrides,
- };
-}
-
-export function mockQualityProfile(overrides: Partial<Profile> = {}): Profile {
- return {
- activeDeprecatedRuleCount: 2,
- activeRuleCount: 10,
- childrenCount: 0,
- depth: 1,
- isBuiltIn: false,
- isDefault: false,
- isInherited: false,
- key: 'key',
- language: 'js',
- languageName: 'JavaScript',
- name: 'name',
- projectCount: 3,
- ...overrides,
- };
-}
-
-export function mockCompareResult(overrides: Partial<CompareResponse> = {}): CompareResponse {
- return {
- left: { name: 'Profile A' },
- right: { name: 'Profile B' },
- inLeft: [
- {
- key: 'java:S4604',
- name: 'Rule in left',
- cleanCodeAttributeCategory: CleanCodeAttributeCategory.Adaptable,
- impacts: [
- {
- softwareQuality: SoftwareQuality.Maintainability,
- severity: SoftwareImpactSeverity.Medium,
- },
- ],
- },
- ],
- inRight: [
- {
- key: 'java:S5128',
- name: 'Rule in right',
- cleanCodeAttributeCategory: CleanCodeAttributeCategory.Responsible,
- impacts: [
- {
- softwareQuality: SoftwareQuality.Security,
- severity: SoftwareImpactSeverity.Medium,
- },
- ],
- },
- ],
- modified: [
- {
- impacts: [],
- key: 'java:S1698',
- name: '== and != should not be used when equals is overridden',
- left: {
- params: {},
- severity: 'MINOR',
- impacts: [
- {
- softwareQuality: SoftwareQuality.Security,
- severity: SoftwareImpactSeverity.Blocker,
- },
- ],
- },
- right: {
- params: {},
- severity: 'CRITICAL',
- impacts: [
- {
- softwareQuality: SoftwareQuality.Security,
- severity: SoftwareImpactSeverity.Low,
- },
- ],
- },
- },
- ],
- ...overrides,
- };
-}
-
-export function mockQualityProfileChangelogEvent(
- eventOverride?: Partial<ProfileChangelogEvent>,
-): ProfileChangelogEvent {
- return {
- action: 'ACTIVATED',
- date: '2019-04-23T02:12:32+0100',
- params: {
- severity: IssueSeverity.Major,
- },
- cleanCodeAttributeCategory: CleanCodeAttributeCategory.Responsible,
- impacts: [
- {
- softwareQuality: SoftwareQuality.Maintainability,
- severity: SoftwareImpactSeverity.Low,
- },
- {
- softwareQuality: SoftwareQuality.Security,
- severity: SoftwareImpactSeverity.High,
- },
- ],
- ruleKey: 'rule-key',
- ruleName: 'rule-name',
- sonarQubeVersion: '10.3',
- ...eventOverride,
- };
-}
-
-export function mockQualityProfileExporter(override?: Partial<Exporter>): Exporter {
- return {
- key: 'exporter-key',
- name: 'exporter-name',
- languages: ['first-lang', 'second-lang'],
- ...override,
- };
-}
-
-export function mockRouter(
- overrides: {
- push?: (loc: To) => void;
- replace?: (loc: To) => void;
- } = {},
-) {
- return {
- createHref: jest.fn(),
- createPath: jest.fn(),
- go: jest.fn(),
- goBack: jest.fn(),
- goForward: jest.fn(),
- isActive: jest.fn(),
- navigate: jest.fn(),
- push: jest.fn(),
- replace: jest.fn(),
- searchParams: new URLSearchParams(),
- setRouteLeaveHook: jest.fn(),
- setSearchParams: jest.fn(),
- ...overrides,
- } as Router;
-}
-
-export function mockRule(overrides: Partial<Rule> = {}): Rule {
- return {
- key: 'javascript:S1067',
- lang: 'js',
- langName: 'JavaScript',
- name: 'Use foo',
- severity: 'MAJOR',
- status: 'READY',
- sysTags: ['a', 'b'],
- tags: ['x'],
- type: 'CODE_SMELL',
- ...overrides,
- } as Rule;
-}
-
-export function mockRuleActivation(overrides: Partial<RuleActivation> = {}): RuleActivation {
- return {
- createdAt: '2020-02-01',
- inherit: 'NONE',
- params: [{ key: 'foo', value: 'Bar' }],
- qProfile: 'baz',
- severity: 'MAJOR',
- prioritizedRule: false,
- impacts: [
- { softwareQuality: SoftwareQuality.Maintainability, severity: SoftwareImpactSeverity.Medium },
- ],
- ...overrides,
- };
-}
-
-export function mockRuleDetails(overrides: Partial<RuleDetails> = {}): RuleDetails {
- return {
- cleanCodeAttributeCategory: CleanCodeAttributeCategory.Intentional,
- cleanCodeAttribute: CleanCodeAttribute.Clear,
- key: 'squid:S1337',
- repo: 'squid',
- name: '".equals()" should not be used to test the values of "Atomic" classes',
- createdAt: '2014-12-16T17:26:54+0100',
- descriptionSections: [
- {
- key: RuleDescriptionSections.DEFAULT,
- content: '<b>Why</b> Because',
- },
- ],
- htmlDesc: '',
- mdDesc: '',
- severity: 'MAJOR',
- status: 'READY',
- isTemplate: false,
- impacts: [
- { softwareQuality: SoftwareQuality.Maintainability, severity: SoftwareImpactSeverity.High },
- ],
- tags: [],
- sysTags: ['multi-threading'],
- lang: 'java',
- langName: 'Java',
- params: [],
- defaultRemFnType: 'CONSTANT_ISSUE',
- defaultRemFnBaseEffort: '5min',
- remFnType: 'CONSTANT_ISSUE',
- remFnBaseEffort: '5min',
- remFnOverloaded: false,
- scope: 'MAIN',
- isExternal: false,
- type: 'BUG',
- ...overrides,
- };
-}
-
-export function mockRestRuleDetails(overrides: Partial<RestRuleDetails> = {}): RestRuleDetails {
- const ruleDetails = mockRuleDetails(overrides);
- return {
- ...omit(ruleDetails, Object.values(REST_RULE_KEYS_TO_OLD_KEYS)),
- ...Object.entries(REST_RULE_KEYS_TO_OLD_KEYS).reduce(
- (obj, [key, value]: [keyof RestRuleDetails, keyof RuleDetails]) => {
- obj[key] = ruleDetails[value] as never;
- return obj;
- },
- {} as RestRuleDetails,
- ),
- ...overrides,
- };
-}
-
-export function mockRuleDetailsParameter(overrides: Partial<RuleParameter> = {}): RuleParameter {
- return {
- defaultValue: '1',
- htmlDesc: 'description',
- key: '1',
- type: 'number',
- ...overrides,
- };
-}
-
-export function mockLogs(logsLevel: LogsLevels = LogsLevels.INFO): SysInfoLogging {
- return { 'Logs Level': logsLevel, 'Logs Dir': '/logs' };
-}
-
-export function mockStandaloneSysInfo(overrides: Partial<any> = {}): SysInfoStandalone {
- const baseInfo = mockBaseSysInfo(overrides);
- return {
- ...baseInfo,
- System: {
- ...baseInfo.System,
- 'High Availability': false,
- 'Server ID': 'asd564-asd54a-5dsfg45',
- },
- Settings: {
- 'sonar.cluster.enabled': 'true',
- 'sonar.cluster.node.name': 'server9.example.com',
- },
- 'Web JVM State': {
- 'Max Memory (MB)': 1024,
- 'Free Memory (MB)': 111,
- },
- 'Web Database Connection': {
- 'Pool Active Connections': 0,
- 'Pool Max Connections': 60,
- },
- 'Web Logging': mockLogs(),
- 'Web JVM Properties': {
- 'file.encoding': 'UTF-8',
- 'file.separator': '/',
- },
- 'Compute Engine Tasks': {
- Pending: 0,
- 'In Progress': 0,
- },
- 'Compute Engine JVM State': {
- 'Max Memory (MB)': 1024,
- 'Free Memory (MB)': 89,
- },
- 'Compute Engine Database Connection': {
- 'Pool Initial Size': 0,
- 'Pool Active Connections': 0,
- },
- 'Compute Engine Logging': mockLogs(),
- 'Compute Engine JVM Properties': {
- 'file.encoding': 'UTF-8',
- 'file.separator': '/',
- },
- ALMs: {},
- Bundled: {},
- Plugins: {},
- ...overrides,
- };
-}
-
-export function mockUser(overrides: Partial<User> = {}): User {
- return {
- active: true,
- local: true,
- login: 'john.doe',
- name: 'John Doe',
- managed: false,
- ...overrides,
- };
-}
-
-export function mockRestUser(overrides: Partial<RestUserDetailed> = {}): RestUserDetailed {
- return {
- id: Math.random().toString(),
- login: 'buzz.aldrin',
- name: 'Buzz Aldrin',
- email: 'buzz.aldrin@nasa.com',
- active: true,
- local: true,
- managed: false,
- externalProvider: '',
- externalLogin: '',
- sonarQubeLastConnectionDate: null,
- sonarLintLastConnectionDate: null,
- scmAccounts: [],
- avatar: 'buzzonthemoon',
- ...overrides,
- };
-}
-
-export function mockUserSelected(overrides: Partial<UserSelected> = {}): UserSelected {
- return {
- active: true,
- login: 'john.doe',
- name: 'John Doe',
- selected: true,
- ...overrides,
- };
-}
-
-export function mockUserGroupMember(overrides: Partial<UserGroupMember> = {}): UserGroupMember {
- return {
- login: 'john.doe',
- name: 'John Doe',
- managed: false,
- selected: true,
- ...overrides,
- };
-}
-
-export function mockDocumentationMarkdown(
- overrides: Partial<{ content: string; key: string; title: string }> = {},
-): string {
- const content =
- overrides.content ||
- `
-## Lorem Ipsum
-
-Donec at est elit. In finibus justo ut augue rhoncus, vitae consequat mauris mattis.
-Nunc ante est, volutpat ac volutpat ac, pharetra in libero.
-`;
-
- const frontMatter = `
----
-${overrides.title ? 'title: ' + overrides.title : ''}
-${overrides.key ? 'key: ' + overrides.key : ''}
----`;
-
- return `${frontMatter}
-${content}`;
-}
-
-export function mockLanguage(overrides: Partial<Language> = {}): Language {
- return {
- key: 'css',
- name: 'CSS',
- ...overrides,
- };
-}
-
-export function mockFlowLocation(overrides: Partial<FlowLocation> = {}): FlowLocation {
- return {
- component: 'main.js',
- textRange: {
- startLine: 1,
- startOffset: 1,
- endLine: 2,
- endOffset: 2,
- },
- ...overrides,
- };
-}
-
-export function mockIdentityProvider(overrides: Partial<IdentityProvider> = {}): IdentityProvider {
- return {
- backgroundColor: '#000000',
- iconPath: '/path/icon.svg',
- key: 'github',
- name: 'Github',
- ...overrides,
- };
-}
-
-export function mockRef(
- overrides: Partial<React.RefObject<Partial<HTMLElement>>> = {},
-): React.RefObject<HTMLElement> {
- return {
- current: {
- getBoundingClientRect: jest.fn(),
- ...overrides.current,
- },
- } as React.RefObject<HTMLElement>;
-}
-
-export function mockPaging(overrides: Partial<Paging> = {}): Paging {
- return {
- pageIndex: 1,
- pageSize: 100,
- total: 1000,
- ...overrides,
- };
-}
-
-export function mockDumpTask(props: Partial<DumpTask> = {}): DumpTask {
- return {
- status: TaskStatuses.Success,
- startedAt: '2020-03-12T12:20:20Z',
- submittedAt: '2020-03-12T12:15:20Z',
- executedAt: '2020-03-12T12:22:20Z',
- ...props,
- };
-}
-
-export function mockDumpStatus(props: Partial<DumpStatus> = {}): DumpStatus {
- return {
- canBeExported: true,
- canBeImported: true,
- dumpToImport: '',
- exportedDump: '',
- ...props,
- };
-}
-
-export function mockRuleRepository(override: Partial<RuleRepository> = {}) {
- return { key: 'css', language: 'css', name: 'SonarQube', ...override };
-}
diff --git a/server/sonar-web/src/main/js/helpers/testReactTestingUtils.tsx b/server/sonar-web/src/main/js/helpers/testReactTestingUtils.tsx
deleted file mode 100644
index e1ae1ff0c0a..00000000000
--- a/server/sonar-web/src/main/js/helpers/testReactTestingUtils.tsx
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { EchoesProvider } from '@sonarsource/echoes-react';
-import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
-import { Matcher, RenderResult, render, screen, within } from '@testing-library/react';
-import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup';
-import { omit } from 'lodash';
-import * as React from 'react';
-import { HelmetProvider } from 'react-helmet-async';
-import { IntlProvider, ReactIntlErrorCode } from 'react-intl';
-import {
- MemoryRouter,
- Outlet,
- Route,
- RouterProvider,
- Routes,
- createMemoryRouter,
- createRoutesFromElements,
- parsePath,
-} from 'react-router-dom';
-import { ToastMessageContainer } from '~design-system';
-import { useLocation } from '~sonar-aligned/components/hoc/withRouter';
-import AdminContext from '../app/components/AdminContext';
-import AppStateContextProvider from '../app/components/app-state/AppStateContextProvider';
-import { AvailableFeaturesContext } from '../app/components/available-features/AvailableFeaturesContext';
-import { ComponentContext } from '../app/components/componentContext/ComponentContext';
-import CurrentUserContextProvider from '../app/components/current-user/CurrentUserContextProvider';
-import IndexationContextProvider from '../app/components/indexation/IndexationContextProvider';
-import { LanguagesContext } from '../app/components/languages/LanguagesContext';
-import { MetricsContext } from '../app/components/metrics/MetricsContext';
-import { AppState } from '../types/appstate';
-import { ComponentContextShape } from '../types/component';
-import { Feature } from '../types/features';
-import { Component, Dict, Extension, Languages, Metric, SysStatus } from '../types/types';
-import { CurrentUser } from '../types/users';
-import { mockComponent } from './mocks/component';
-import { DEFAULT_METRICS } from './mocks/metrics';
-import { mockAppState, mockCurrentUser } from './testMocks';
-
-export interface RenderContext {
- appState?: AppState;
- currentUser?: CurrentUser;
- featureList?: Feature[];
- languages?: Languages;
- metrics?: Dict<Metric>;
- navigateTo?: string;
-}
-
-export function renderAppWithAdminContext(
- indexPath: string,
- routes: () => JSX.Element,
- context: RenderContext = {},
- overrides: { adminPages?: Extension[]; systemStatus?: SysStatus } = {},
-): RenderResult {
- function MockAdminContainer() {
- return (
- <AdminContext.Provider
- value={{
- fetchSystemStatus: () => {
- /*noop*/
- },
- fetchPendingPlugins: () => {
- /*noop*/
- },
- pendingPlugins: { installing: [], removing: [], updating: [] },
- systemStatus: overrides.systemStatus ?? 'UP',
- }}
- >
- <Outlet
- context={{
- adminPages: overrides.adminPages ?? [],
- }}
- />
- </AdminContext.Provider>
- );
- }
-
- return renderRoutedApp(
- <Route element={<MockAdminContainer />} path="admin">
- {routes()}
- </Route>,
- indexPath,
- context,
- );
-}
-
-export function renderComponent(
- component: React.ReactElement,
- pathname = '/',
- {
- appState = mockAppState(),
- featureList = [],
- currentUser = mockCurrentUser(),
- }: RenderContext = {},
-) {
- function Wrapper({ children }: { children: React.ReactElement }) {
- const queryClient = new QueryClient({
- defaultOptions: {
- queries: {
- retry: false,
- },
- },
- });
-
- return (
- <IntlWrapper>
- <QueryClientProvider client={queryClient}>
- <HelmetProvider>
- <AvailableFeaturesContext.Provider value={featureList}>
- <CurrentUserContextProvider currentUser={currentUser}>
- <AppStateContextProvider appState={appState}>
- <EchoesProvider tooltipsDelayDuration={0}>
- <MemoryRouter initialEntries={[pathname]}>
- <Routes>
- <Route path="*" element={children} />
- </Routes>
- </MemoryRouter>
- </EchoesProvider>
- </AppStateContextProvider>
- </CurrentUserContextProvider>
- </AvailableFeaturesContext.Provider>
- </HelmetProvider>
- </QueryClientProvider>
- </IntlWrapper>
- );
- }
-
- return render(component, { wrapper: Wrapper });
-}
-
-export function renderAppWithComponentContext(
- indexPath: string,
- routes: () => JSX.Element,
- context: RenderContext = {},
- componentContext: Partial<ComponentContextShape> = {},
-) {
- function MockComponentContainer() {
- const [realComponent, setRealComponent] = React.useState(
- componentContext?.component ?? mockComponent(),
- );
- return (
- <ComponentContext.Provider
- value={{
- onComponentChange: (changes: Partial<Component>) => {
- setRealComponent({ ...realComponent, ...changes });
- },
- fetchComponent: jest.fn(),
- component: realComponent,
- ...omit(componentContext, 'component'),
- }}
- >
- <Outlet />
- </ComponentContext.Provider>
- );
- }
-
- return renderRoutedApp(
- <Route element={<MockComponentContainer />}>{routes()}</Route>,
- indexPath,
- context,
- );
-}
-
-export function renderApp(
- indexPath: string,
- component: JSX.Element,
- context: RenderContext = {},
-): RenderResult {
- return renderRoutedApp(<Route path={indexPath} element={component} />, indexPath, context);
-}
-
-export function renderAppRoutes(
- indexPath: string,
- routes: () => JSX.Element,
- context?: RenderContext,
-): RenderResult {
- return renderRoutedApp(routes(), indexPath, context);
-}
-
-export function CatchAll() {
- const location = useLocation();
-
- return <div>{`${location.pathname}${location.search}`}</div>;
-}
-
-function renderRoutedApp(
- children: React.ReactElement,
- indexPath: string,
- {
- currentUser = mockCurrentUser(),
- navigateTo = indexPath,
- metrics = DEFAULT_METRICS,
- appState = mockAppState(),
- featureList = [],
- languages = {},
- }: RenderContext = {},
-): RenderResult {
- const path = parsePath(navigateTo);
- if (!path.pathname?.startsWith('/')) {
- path.pathname = `/${path.pathname}`;
- }
- const queryClient = new QueryClient();
-
- const router = createMemoryRouter(
- createRoutesFromElements(
- <Route
- element={
- <>
- <Outlet />
- <ToastMessageContainer />
- </>
- }
- >
- {children}
- <Route path="*" element={<CatchAll />} />
- </Route>,
- ),
- { initialEntries: [path] },
- );
-
- return render(
- <HelmetProvider context={{}}>
- <IntlWrapper>
- <MetricsContext.Provider value={metrics}>
- <LanguagesContext.Provider value={languages}>
- <AvailableFeaturesContext.Provider value={featureList}>
- <CurrentUserContextProvider currentUser={currentUser}>
- <AppStateContextProvider appState={appState}>
- <IndexationContextProvider>
- <QueryClientProvider client={queryClient}>
- <EchoesProvider tooltipsDelayDuration={0}>
- <RouterProvider router={router} />
- </EchoesProvider>
- </QueryClientProvider>
- </IndexationContextProvider>
- </AppStateContextProvider>
- </CurrentUserContextProvider>
- </AvailableFeaturesContext.Provider>
- </LanguagesContext.Provider>
- </MetricsContext.Provider>
- </IntlWrapper>
- </HelmetProvider>,
- );
-}
-
-export function dateInputEvent(user: UserEvent) {
- return {
- async pickDate(element: HTMLElement, date: Date) {
- await user.click(element);
-
- const formatter = new Intl.DateTimeFormat('en', { month: 'long' });
-
- await user.selectOptions(
- await screen.findByRole('combobox', { name: 'Month:' }),
- formatter.format(date),
- );
- await user.selectOptions(
- screen.getByRole('combobox', { name: 'Year:' }),
- String(date.getFullYear()),
- );
-
- await user.click(screen.getByRole('gridcell', { name: String(date.getDate()) }));
- },
- };
-}
-/* eslint-enable testing-library/no-node-access */
-
-/**
- * @deprecated Use our custom toHaveATooltipWithContent() matcher instead.
- */
-export function findTooltipWithContent(
- text: Matcher,
- target?: HTMLElement,
- selector = 'svg > desc',
-) {
- // eslint-disable-next-line no-console
- console.warn(`The usage of findTooltipWithContent() is deprecated; use expect.toHaveATooltipWithContent() instead.
-Example:
- await expect(node).toHaveATooltipWithContent('foo.bar');`);
- return target
- ? within(target).getByText(text, { selector })
- : screen.getByText(text, { selector });
-}
-
-export function IntlWrapper({
- children,
- messages = {},
-}: {
- children: React.ReactNode;
- messages?: Record<string, string>;
-}) {
- return (
- <IntlProvider
- defaultLocale="en"
- locale="en"
- messages={messages}
- onError={(e) => {
- // ignore missing translations, there are none!
- if (e.code !== ReactIntlErrorCode.MISSING_TRANSLATION) {
- // eslint-disable-next-line no-console
- console.error(e);
- }
- }}
- >
- {children}
- </IntlProvider>
- );
-}
diff --git a/server/sonar-web/src/main/js/helpers/testUtils.ts b/server/sonar-web/src/main/js/helpers/testUtils.ts
deleted file mode 100644
index 86f18620903..00000000000
--- a/server/sonar-web/src/main/js/helpers/testUtils.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentClass, FunctionComponent } from 'react';
-
-export type ComponentPropsType<
- T extends ComponentClass | FunctionComponent<React.PropsWithChildren<any>>,
-> =
- T extends ComponentClass<infer P>
- ? P
- : T extends FunctionComponent<React.PropsWithChildren<infer P>>
- ? P
- : never;
-
-export function mockIntersectionObserver(): Function {
- let callback: Function;
-
- // @ts-ignore
- global.IntersectionObserver = jest.fn((cb: Function) => {
- const instance = {
- observe: jest.fn(),
- unobserve: jest.fn(),
- disconnect: jest.fn(),
- };
-
- callback = cb;
-
- callback([
- {
- isIntersecting: true,
- intersectionRatio: 1,
- boundingClientRect: { top: 0 },
- intersectionRect: { top: 0 },
- },
- ]);
- return instance;
- });
-
- return (entry: IntersectionObserverEntry) => callback([entry]);
-}
diff --git a/server/sonar-web/src/main/js/helpers/tokens.ts b/server/sonar-web/src/main/js/helpers/tokens.ts
deleted file mode 100644
index e61ed92a25a..00000000000
--- a/server/sonar-web/src/main/js/helpers/tokens.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getAllValues } from '../api/settings';
-import { SettingsKey } from '../types/settings';
-import { TokenExpiration, UserToken } from '../types/token';
-import { now, toShortISO8601String } from './dates';
-import { translate } from './l10n';
-
-export const EXPIRATION_OPTIONS = [
- TokenExpiration.OneMonth,
- TokenExpiration.ThreeMonths,
- TokenExpiration.OneYear,
- TokenExpiration.NoExpiration,
-].map((value) => {
- return {
- value,
- label: translate('users.tokens.expiration', value.toString()),
- };
-});
-
-const SETTINGS_EXPIRATION_MAP: { [key: string]: TokenExpiration } = {
- '30 days': TokenExpiration.OneMonth,
- '90 days': TokenExpiration.ThreeMonths,
- '1 year': TokenExpiration.OneYear,
- 'No expiration': TokenExpiration.NoExpiration,
-};
-
-export async function getAvailableExpirationOptions() {
- /*
- * We intentionally fetch all settings, because fetching a specific setting will
- * return it from the DB as a fallback, even if the setting is not defined at startup.
- */
- const setting = (await getAllValues()).find((v) => v.key === SettingsKey.TokenMaxAllowedLifetime);
- if (setting === undefined || setting.value === undefined) {
- return EXPIRATION_OPTIONS;
- }
-
- const maxTokenLifetime = setting.value;
- if (SETTINGS_EXPIRATION_MAP[maxTokenLifetime] !== TokenExpiration.NoExpiration) {
- return EXPIRATION_OPTIONS.filter(
- (option) =>
- option.value <= SETTINGS_EXPIRATION_MAP[maxTokenLifetime] &&
- option.value !== TokenExpiration.NoExpiration,
- );
- }
-
- return EXPIRATION_OPTIONS;
-}
-
-export function computeTokenExpirationDate(days: number) {
- const expirationDate = now();
- expirationDate.setDate(expirationDate.getDate() + days);
- return toShortISO8601String(expirationDate);
-}
-
-export function getNextTokenName(tokenNameBase: string, tokens: UserToken[]) {
- let tokenName = tokenNameBase;
- let counter = 1;
- let existingToken = tokens.find(({ name }) => name === tokenName);
- while (existingToken !== undefined) {
- tokenName = `${tokenNameBase}-${counter}`;
- counter += 1;
- // eslint-disable-next-line no-loop-func
- existingToken = tokens.find(({ name }) => name === tokenName);
- }
-
- return tokenName;
-}
diff --git a/server/sonar-web/src/main/js/helpers/types.ts b/server/sonar-web/src/main/js/helpers/types.ts
deleted file mode 100644
index 563a2c152d6..00000000000
--- a/server/sonar-web/src/main/js/helpers/types.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export function isDefined<T>(x: T | undefined | null): x is T {
- return x !== undefined && x !== null;
-}
diff --git a/server/sonar-web/src/main/js/helpers/urls.ts b/server/sonar-web/src/main/js/helpers/urls.ts
deleted file mode 100644
index 3bd4c1e484e..00000000000
--- a/server/sonar-web/src/main/js/helpers/urls.ts
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Path, To } from 'react-router-dom';
-import {
- getBranchLikeQuery,
- isBranch,
- isMainBranch,
- isPullRequest,
-} from '~sonar-aligned/helpers/branch-like';
-import { isPortfolioLike } from '~sonar-aligned/helpers/component';
-import { queryToSearchString } from '~sonar-aligned/helpers/urls';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { getProfilePath } from '../apps/quality-profiles/utils';
-import { DEFAULT_ISSUES_QUERY } from '../components/shared/utils';
-import { BranchLike } from '../types/branch-like';
-import { isApplication } from '../types/component';
-import { MeasurePageView } from '../types/measures';
-import { GraphType } from '../types/project-activity';
-import { Dict } from '../types/types';
-import { HomePage } from '../types/users';
-import { serializeOptionalBoolean } from './query';
-import { getBaseUrl } from './system';
-
-export interface Location {
- pathname: string;
- query?: Dict<string | undefined | number>;
-}
-
-export enum CodeScope {
- Overall = 'overall',
- New = 'new',
-}
-
-type CodeScopeType = CodeScope.Overall | CodeScope.New;
-
-export type Query = Location['query'];
-
-const PROJECT_BASE_URL = '/dashboard';
-const SONARSOURCE_COM_URL = 'https://www.sonarsource.com';
-
-export function getComponentOverviewUrl(
- componentKey: string,
- componentQualifier: ComponentQualifier | string,
- branchParameters?: BranchParameters,
- codeScope?: CodeScopeType,
-) {
- return isPortfolioLike(componentQualifier)
- ? getPortfolioUrl(componentKey)
- : getProjectQueryUrl(componentKey, branchParameters, codeScope);
-}
-
-export function getComponentAdminUrl(
- componentKey: string,
- componentQualifier: ComponentQualifier | string,
-) {
- if (isPortfolioLike(componentQualifier)) {
- return getPortfolioAdminUrl(componentKey);
- } else if (isApplication(componentQualifier)) {
- return getApplicationAdminUrl(componentKey);
- }
- return getProjectUrl(componentKey);
-}
-
-export function getProjectUrl(
- project: string,
- branch?: string,
- codeScope?: CodeScopeType,
-): Partial<Path> {
- return {
- pathname: PROJECT_BASE_URL,
- search: queryToSearchString({
- id: project,
- branch,
- ...(codeScope && { codeScope }),
- }),
- };
-}
-
-export function getProjectSecurityHotspots(project: string): To {
- return {
- pathname: '/security_hotspots',
- search: queryToSearchString({ id: project }),
- };
-}
-
-export function getProjectQueryUrl(
- project: string,
- branchParameters?: BranchParameters,
- codeScope?: CodeScopeType,
-): To {
- return {
- pathname: PROJECT_BASE_URL,
- search: queryToSearchString({
- id: project,
- ...branchParameters,
- ...(codeScope && { codeScope }),
- }),
- };
-}
-
-export function getPortfolioUrl(key: string): To {
- return { pathname: '/portfolio', search: queryToSearchString({ id: key }) };
-}
-
-export function getPortfolioAdminUrl(key: string): To {
- return {
- pathname: '/project/admin/extension/governance/console',
- search: queryToSearchString({ id: key, qualifier: ComponentQualifier.Portfolio }),
- };
-}
-
-export function getApplicationAdminUrl(key: string): To {
- return {
- pathname: '/project/admin/extension/developer-server/application-console',
- search: queryToSearchString({ id: key }),
- };
-}
-
-export function getComponentBackgroundTaskUrl(
- componentKey: string,
- status?: string,
- taskType?: string,
-): Partial<Path> {
- return {
- pathname: '/project/background_tasks',
- search: queryToSearchString({ id: componentKey, status, taskType }),
- hash: '',
- };
-}
-
-export function getBranchLikeUrl(project: string, branchLike?: BranchLike): Partial<Path> {
- if (isPullRequest(branchLike)) {
- return getPullRequestUrl(project, branchLike.key);
- } else if (isBranch(branchLike) && !isMainBranch(branchLike)) {
- return getBranchUrl(project, branchLike.name);
- }
- return getProjectUrl(project);
-}
-
-export function getBranchUrl(project: string, branch: string): Partial<Path> {
- return { pathname: PROJECT_BASE_URL, search: queryToSearchString({ branch, id: project }) };
-}
-
-export function getPullRequestUrl(project: string, pullRequest: string): Partial<Path> {
- return { pathname: PROJECT_BASE_URL, search: queryToSearchString({ id: project, pullRequest }) };
-}
-
-/**
- * Generate URL for a global issues page
- */
-export function getIssuesUrl(query: Query): To {
- const pathname = '/issues';
- return { pathname, search: queryToSearchString(query) };
-}
-
-/**
- * Generate URL for a component's drilldown page
- */
-export function getComponentDrilldownUrl(options: {
- asc?: boolean;
- branchLike?: BranchLike;
- componentKey: string;
- listView?: boolean;
- metric: string;
- selectionKey?: string;
- treemapView?: boolean;
-}): To {
- const { componentKey, metric, branchLike, selectionKey, treemapView, listView, asc } = options;
- const query: Query = { id: componentKey, metric, ...getBranchLikeQuery(branchLike) };
- if (treemapView) {
- query.view = 'treemap';
- }
- if (listView) {
- query.view = 'list';
- query.asc = serializeOptionalBoolean(asc);
- }
- if (selectionKey) {
- query.selected = selectionKey;
- }
- return { pathname: '/component_measures', search: queryToSearchString(query) };
-}
-
-export function getComponentDrilldownUrlWithSelection(
- componentKey: string,
- selectionKey: string,
- metric: string,
- branchLike?: BranchLike,
- view?: MeasurePageView,
-): To {
- return getComponentDrilldownUrl({
- componentKey,
- selectionKey,
- metric,
- branchLike,
- treemapView: view === MeasurePageView.treemap,
- listView: view === MeasurePageView.list,
- });
-}
-
-export function getMeasureTreemapUrl(componentKey: string, metric: string) {
- return getComponentDrilldownUrl({ componentKey, metric, treemapView: true });
-}
-
-export function getActivityUrl(component: string, branchLike?: BranchLike, graph?: GraphType) {
- return {
- pathname: '/project/activity',
- search: queryToSearchString({ id: component, graph, ...getBranchLikeQuery(branchLike) }),
- };
-}
-
-/**
- * Generate URL for a component's measure history
- */
-export function getMeasureHistoryUrl(component: string, metric: string, branchLike?: BranchLike) {
- return {
- pathname: '/project/activity',
- search: queryToSearchString({
- id: component,
- graph: 'custom',
- custom_metrics: metric,
- ...getBranchLikeQuery(branchLike),
- }),
- };
-}
-
-/**
- * Generate URL for a component's permissions page
- */
-export function getComponentPermissionsUrl(componentKey: string): To {
- return { pathname: '/project_roles', search: queryToSearchString({ id: componentKey }) };
-}
-
-/**
- * Generate URL for a quality profile
- */
-export function getQualityProfileUrl(name: string, language: string): To {
- return getProfilePath(name, language);
-}
-
-export function getQualityGateUrl(name: string): To {
- return {
- pathname: '/quality_gates/show/' + encodeURIComponent(name),
- };
-}
-
-/**
- * Generate URL for the project tutorial page
- */
-export function getProjectTutorialLocation(
- project: string,
- selectedTutorial?: string,
-): Partial<Path> {
- return {
- pathname: '/tutorials',
- search: queryToSearchString({ id: project, selectedTutorial }),
- };
-}
-
-/**
- * Generate URL for the project creation page
- */
-export function getCreateProjectModeLocation(mode?: string): Partial<Path> {
- return {
- search: queryToSearchString({ mode }),
- };
-}
-
-export function getQualityGatesUrl(): To {
- return {
- pathname: '/quality_gates',
- };
-}
-
-export function getGlobalSettingsUrl(
- category?: string,
- query?: Dict<string | undefined | number>,
-): Partial<Path> {
- return {
- pathname: '/admin/settings',
- search: queryToSearchString({ category, ...query }),
- };
-}
-
-export function getProjectSettingsUrl(id: string, category?: string): Partial<Path> {
- return {
- pathname: '/project/settings',
- search: queryToSearchString({ id, category }),
- };
-}
-
-/**
- * Generate URL for the rules page
- */
-export function getRulesUrl(query: Query): Partial<Path> {
- return { pathname: '/coding_rules', search: queryToSearchString(query) };
-}
-
-/**
- * Generate URL for the rules page filtering only active deprecated rules
- */
-export function getDeprecatedActiveRulesUrl(query: Query = {}): To {
- const baseQuery = { activation: 'true', statuses: 'DEPRECATED' };
- return getRulesUrl({ ...query, ...baseQuery });
-}
-
-export function getRuleUrl(rule: string) {
- return getRulesUrl({ open: rule, rule_key: rule });
-}
-
-export function getFormattingHelpUrl(): string {
- return '/formatting/help';
-}
-
-export function getCodeUrl(
- project: string,
- branchLike?: BranchLike,
- selected?: string,
- line?: number,
-): Partial<Path> {
- return {
- pathname: '/code',
- search: queryToSearchString({
- id: project,
- ...getBranchLikeQuery(branchLike),
- selected,
- line: line?.toFixed(),
- }),
- };
-}
-
-export function getHomePageUrl(homepage: HomePage) {
- switch (homepage.type) {
- case 'APPLICATION':
- return homepage.branch
- ? getProjectUrl(homepage.component, homepage.branch)
- : getProjectUrl(homepage.component);
- case 'PROJECT':
- return homepage.branch
- ? getBranchUrl(homepage.component, homepage.branch)
- : getProjectUrl(homepage.component);
- case 'PORTFOLIO':
- return getPortfolioUrl(homepage.component);
- case 'PORTFOLIOS':
- return '/portfolios';
- case 'MY_PROJECTS':
- return '/projects';
- case 'ISSUES':
- case 'MY_ISSUES':
- return { pathname: '/issues', query: DEFAULT_ISSUES_QUERY };
- }
-
- // should never happen, but just in case...
- return '/projects';
-}
-
-export function convertGithubApiUrlToLink(url: string) {
- return url
- .replace(/^https?:\/\/api\.github\.com/, 'https://github.com') // GH.com
- .replace(/\/api\/v\d+\/?$/, ''); // GH Enterprise
-}
-
-export function stripTrailingSlash(url: string) {
- return url.replace(/\/$/, '');
-}
-
-export function getHostUrl(): string {
- return window.location.origin + getBaseUrl();
-}
-
-export function getPathUrlAsString(path: Partial<Path>, internal = true): string {
- return `${internal ? getBaseUrl() : getHostUrl()}${path.pathname ?? '/'}${path.search ?? ''}`;
-}
-
-export function getReturnUrl(location: { hash?: string; query?: { return_to?: string } }) {
- const returnTo = location.query && location.query['return_to'];
-
- if (isRelativeUrl(returnTo)) {
- return returnTo + (location.hash ? location.hash : '');
- }
- return `${getBaseUrl()}/`;
-}
-
-export function isRelativeUrl(url?: string): boolean {
- const regex = new RegExp(/^\/[^/\\]/);
- return Boolean(url && regex.test(url));
-}
-
-export function convertToTo(link: string | Location) {
- if (linkIsLocation(link)) {
- return { pathname: link.pathname, search: queryToSearchString(link.query) } as Partial<Path>;
- }
- return link;
-}
-
-function linkIsLocation(link: string | Location): link is Location {
- return (link as Location).query !== undefined;
-}
-
-export function getAiCodeFixTermsOfServiceUrl(): string {
- return `${SONARSOURCE_COM_URL}/legal/ai-codefix-terms/`;
-}
diff --git a/server/sonar-web/src/main/js/helpers/users.ts b/server/sonar-web/src/main/js/helpers/users.ts
deleted file mode 100644
index 21b7664c62f..00000000000
--- a/server/sonar-web/src/main/js/helpers/users.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { CurrentUser, HomePage } from '../types/users';
-
-export function hasGlobalPermission(user: CurrentUser, permission: string): boolean {
- if (!user.permissions) {
- return false;
- }
- return user.permissions.global.includes(permission);
-}
-
-export function isSameHomePage(a: HomePage, b: HomePage) {
- return (
- a.type === b.type &&
- (a as any).branch === (b as any).branch &&
- (a as any).component === (b as any).component
- );
-}
diff --git a/server/sonar-web/src/main/js/hooks/__tests__/useLocalStorage-test.tsx b/server/sonar-web/src/main/js/hooks/__tests__/useLocalStorage-test.tsx
deleted file mode 100644
index 474b9b76023..00000000000
--- a/server/sonar-web/src/main/js/hooks/__tests__/useLocalStorage-test.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { renderComponent } from '../../helpers/testReactTestingUtils';
-import { FCProps } from '../../types/misc';
-import useLocalStorage from '../useLocalStorage';
-
-describe('useLocalStorage hook', () => {
- it('gets/sets boolean value', async () => {
- const user = userEvent.setup();
- renderLSComponent();
-
- expect(screen.getByRole('button', { name: 'show' })).toBeInTheDocument();
- user.click(screen.getByRole('button', { name: 'show' }));
- expect(await screen.findByText('text')).toBeInTheDocument();
- });
-
- it('gets/sets string value', async () => {
- const user = userEvent.setup();
- const props = { condition: (value: string) => value === 'ok', valueToSet: 'wow' };
- const { rerender } = renderLSComponent(props);
-
- expect(screen.getByRole('button', { name: 'show' })).toBeInTheDocument();
- user.click(screen.getByRole('button', { name: 'show' }));
- expect(screen.queryByText('text')).not.toBeInTheDocument();
-
- rerender(<LSComponent lsKey="test_ls" {...props} valueToSet="ok" />);
- user.click(screen.getByRole('button', { name: 'show' }));
- expect(await screen.findByText('text')).toBeInTheDocument();
- });
-});
-
-function renderLSComponent(props: Partial<FCProps<typeof LSComponent>> = {}) {
- return renderComponent(
- <LSComponent lsKey="test_ls" valueToSet condition={(value) => Boolean(value)} {...props} />,
- );
-}
-
-function LSComponent({
- lsKey,
- condition,
- initialValue,
- valueToSet,
-}: Readonly<{
- condition: (value: boolean | string) => boolean;
- initialValue?: boolean | string;
- lsKey: string;
- valueToSet: boolean | string;
-}>) {
- const [value, setValue] = useLocalStorage(lsKey, initialValue);
-
- return (
- <div>
- <button type="button" onClick={() => setValue(valueToSet)}>
- show
- </button>
- {condition(value) && <span>text</span>}
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/hooks/useFollowScroll.ts b/server/sonar-web/src/main/js/hooks/useFollowScroll.ts
deleted file mode 100644
index abb50d586d2..00000000000
--- a/server/sonar-web/src/main/js/hooks/useFollowScroll.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { throttle } from 'lodash';
-import { useEffect, useState } from 'react';
-
-const THROTTLE_DELAY = 10;
-
-export default function useFollowScroll() {
- const [left, setLeft] = useState(0);
- const [top, setTop] = useState(0);
- const [scrolledOnce, setScrolledOnce] = useState(false);
-
- useEffect(() => {
- const followScroll = throttle(() => {
- if (document.documentElement) {
- setLeft(document.documentElement.scrollLeft);
- setTop(document.documentElement.scrollTop);
- setScrolledOnce(true);
- }
- }, THROTTLE_DELAY);
-
- document.addEventListener('scroll', followScroll);
- return () => document.removeEventListener('scroll', followScroll);
- }, []);
-
- return { left, top, scrolledOnce };
-}
diff --git a/server/sonar-web/src/main/js/hooks/useIntersectionObserver.ts b/server/sonar-web/src/main/js/hooks/useIntersectionObserver.ts
deleted file mode 100644
index efee17c5aba..00000000000
--- a/server/sonar-web/src/main/js/hooks/useIntersectionObserver.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { RefObject, useEffect, useState } from 'react';
-import { isDefined } from '../helpers/types';
-
-interface Options extends IntersectionObserverInit {
- freezeOnceVisible?: boolean;
-}
-
-export default function useIntersectionObserver<T extends Element>(
- ref: RefObject<T>,
- options: Options = {},
-) {
- const { root = null, rootMargin = '0px', threshold = 0, freezeOnceVisible = false } = options;
- const [entry, setEntry] = useState<IntersectionObserverEntry>();
-
- const frozen = (entry?.isIntersecting || false) && freezeOnceVisible;
-
- useEffect(() => {
- if (!isDefined(IntersectionObserver) || !isDefined(ref.current) || frozen) {
- return;
- }
-
- const observer = new IntersectionObserver(
- ([entry]) => setEntry(entry),
-
- { root, rootMargin, threshold },
- );
-
- observer.observe(ref.current);
- return () => observer.disconnect();
- }, [ref, frozen, root, rootMargin, threshold]);
-
- return entry;
-}
diff --git a/server/sonar-web/src/main/js/hooks/useKeydown.ts b/server/sonar-web/src/main/js/hooks/useKeydown.ts
deleted file mode 100644
index 5f75af9d50c..00000000000
--- a/server/sonar-web/src/main/js/hooks/useKeydown.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useCallback, useEffect } from 'react';
-import { KeyboardKeys } from '../helpers/keycodes';
-
-export default function useKeyDown(callback: Function, keys: Array<KeyboardKeys>) {
- const onKeyDown = useCallback(
- (event: KeyboardEvent) => {
- const wasAnyKeyPressed = keys.some((key) => event.key === key);
- if (wasAnyKeyPressed) {
- event.preventDefault();
- callback(event);
- }
- },
- [callback, keys],
- );
-
- useEffect(() => {
- document.addEventListener('keydown', onKeyDown);
- return () => {
- document.removeEventListener('keydown', onKeyDown);
- };
- }, [onKeyDown]);
-}
diff --git a/server/sonar-web/src/main/js/hooks/useLocalStorage.ts b/server/sonar-web/src/main/js/hooks/useLocalStorage.ts
deleted file mode 100644
index 7077a536e2e..00000000000
--- a/server/sonar-web/src/main/js/hooks/useLocalStorage.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React from 'react';
-import { get, save } from '../helpers/storage';
-
-export default function useLocalStorage<T>(key: string, initialValue?: T) {
- const lsValue = React.useCallback(() => {
- const v = get(key);
- try {
- return JSON.parse(v as string);
- } catch {
- return v;
- }
- }, [key]);
-
- const [storedValue, setStoredValue] = React.useState(lsValue() ?? initialValue);
-
- const changeValue = React.useCallback(
- (value: T) => {
- save(key, JSON.stringify(value));
- setStoredValue(lsValue());
- },
- [key, lsValue],
- );
-
- React.useEffect(() => {
- setStoredValue(lsValue() ?? initialValue);
- }, [lsValue, initialValue]);
-
- return [storedValue, changeValue];
-}
diff --git a/server/sonar-web/src/main/js/queries/__tests__/queryClient-test.ts b/server/sonar-web/src/main/js/queries/__tests__/queryClient-test.ts
deleted file mode 100644
index 670fe0f0e4c..00000000000
--- a/server/sonar-web/src/main/js/queries/__tests__/queryClient-test.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { QueryClient } from '@tanstack/react-query';
-import { queryClient } from '../queryClient';
-
-jest.mock('@tanstack/react-query');
-
-it('should return the queryClient and not retry on 4xx errors', () => {
- expect(queryClient).toBeDefined();
-
- expect(jest.mocked(QueryClient)).toHaveBeenCalledWith({
- defaultOptions: { queries: { retry: expect.any(Function) } },
- });
-
- const retryFunction = jest.mocked(QueryClient).mock.calls[0][0]?.defaultOptions?.queries
- ?.retry as Function;
-
- expect(retryFunction(0, undefined)).toEqual(true);
- expect(retryFunction(1, undefined)).toEqual(true);
- expect(retryFunction(2, undefined)).toEqual(false);
-
- expect(retryFunction(0, null)).toEqual(true);
- expect(retryFunction(0, {})).toEqual(true);
- expect(retryFunction(0, { status: 200 })).toEqual(true);
-
- expect(retryFunction(0, { status: 400 })).toEqual(false);
- expect(retryFunction(0, { status: 404 })).toEqual(false);
- expect(retryFunction(0, { status: 500 })).toEqual(true);
-});
diff --git a/server/sonar-web/src/main/js/queries/ai-code-assurance.ts b/server/sonar-web/src/main/js/queries/ai-code-assurance.ts
deleted file mode 100644
index 97ecb807d1d..00000000000
--- a/server/sonar-web/src/main/js/queries/ai-code-assurance.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions } from '@tanstack/react-query';
-import { getProjectAiCodeAssuranceStatus } from '../api/ai-code-assurance';
-import { createQueryHook } from './common';
-
-export const AI_CODE_ASSURANCE_QUERY_PREFIX = 'ai-code-assurance';
-
-export const useProjectAiCodeAssuranceStatusQuery = createQueryHook(
- ({ project }: { project: string }) => {
- return queryOptions({
- queryKey: [AI_CODE_ASSURANCE_QUERY_PREFIX, project], // - or _ ?
- queryFn: ({ queryKey: [_, project] }) => getProjectAiCodeAssuranceStatus(project),
- enabled: project !== undefined,
- });
- },
-);
diff --git a/server/sonar-web/src/main/js/queries/applications.ts b/server/sonar-web/src/main/js/queries/applications.ts
deleted file mode 100644
index 13b20809900..00000000000
--- a/server/sonar-web/src/main/js/queries/applications.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useMutation, useQueryClient } from '@tanstack/react-query';
-import { deleteApplication, getApplicationLeak } from '../api/application';
-import { createQueryHook } from './common';
-import { invalidateMeasuresByComponentKey } from './measures';
-
-export const useApplicationLeakQuery = createQueryHook((application: string) => {
- return queryOptions({
- queryKey: ['application', 'leak', application],
- queryFn: () => getApplicationLeak(application),
- });
-});
-
-export function useDeleteApplicationMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: (key: string) => deleteApplication(key),
- onSuccess: (_, key) => {
- invalidateMeasuresByComponentKey(key, queryClient);
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/badges.ts b/server/sonar-web/src/main/js/queries/badges.ts
deleted file mode 100644
index 117689a7852..00000000000
--- a/server/sonar-web/src/main/js/queries/badges.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { uniq } from 'lodash';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { getProjectBadgesToken, renewProjectBadgesToken } from '../api/project-badges';
-import { MQR_CONDITIONS_MAP, STANDARD_CONDITIONS_MAP } from '../apps/quality-gates/utils';
-import { localizeMetric } from '../helpers/measures';
-import { useStandardExperienceModeQuery } from './mode';
-import { useWebApiQuery } from './web-api';
-
-export function useRenewBagdeTokenMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: async (key: string) => {
- await renewProjectBadgesToken(key);
- },
- onSuccess: (_, key) => {
- queryClient.invalidateQueries({ queryKey: ['badges-token', key], refetchType: 'all' });
- },
- });
-}
-
-export function useBadgeMetrics() {
- const { data: webservices = [], isLoading: isLoadingWebApi } = useWebApiQuery();
- const { data: isStandardExperience, isLoading: isLoadingMode } = useStandardExperienceModeQuery();
- const domain = webservices.find((d) => d.path === 'api/project_badges');
- const ws = domain?.actions.find((w) => w.key === 'measure');
- const param = ws?.params?.find((p) => p.key === 'metric');
- if (param?.possibleValues && !isLoadingMode) {
- return {
- isLoading: false,
- data: uniq(
- param.possibleValues.map((metric: MetricKey) => {
- return (
- (isStandardExperience ? MQR_CONDITIONS_MAP[metric] : STANDARD_CONDITIONS_MAP[metric]) ??
- metric
- );
- }),
- ).map((metric) => ({
- value: metric,
- label: localizeMetric(metric),
- })),
- };
- }
- return { isLoading: isLoadingWebApi || isLoadingMode, data: [] };
-}
-
-export function useBadgeTokenQuery(componentKey: string) {
- return useQuery({
- queryKey: ['badges-token', componentKey] as const,
- queryFn: ({ queryKey: [_, key] }) => getProjectBadgesToken(key),
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/branch.tsx b/server/sonar-web/src/main/js/queries/branch.tsx
deleted file mode 100644
index 8acc97b5e68..00000000000
--- a/server/sonar-web/src/main/js/queries/branch.tsx
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { debounce, flatten } from 'lodash';
-import * as React from 'react';
-import { useCallback, useContext } from 'react';
-import { useSearchParams } from 'react-router-dom';
-import { useLocation } from '~sonar-aligned/components/hoc/withRouter';
-import { isBranch, isPullRequest } from '~sonar-aligned/helpers/branch-like';
-import { isPortfolioLike } from '~sonar-aligned/helpers/component';
-import { searchParamsToQuery } from '~sonar-aligned/helpers/router';
-import { LightComponent } from '~sonar-aligned/types/component';
-import {
- deleteBranch,
- deletePullRequest,
- excludeBranchFromPurge,
- getBranches,
- getPullRequests,
- renameBranch,
- setMainBranch,
-} from '../api/branches';
-import { dismissAnalysisWarning, getAnalysisStatus } from '../api/ce';
-import { getQualityGateProjectStatus } from '../api/quality-gates';
-import { AvailableFeaturesContext } from '../app/components/available-features/AvailableFeaturesContext';
-import { useComponent } from '../app/components/componentContext/withComponentContext';
-import { extractStatusConditionsFromProjectStatus } from '../helpers/qualityGates';
-import { isDefined } from '../helpers/types';
-import { Branch, BranchLike } from '../types/branch-like';
-import { isApplication, isProject } from '../types/component';
-import { Feature } from '../types/features';
-import { Component } from '../types/types';
-import { StaleTime } from './common';
-
-enum InnerState {
- Details = 'details',
- Warning = 'warning',
- Status = 'status',
-}
-
-/**
- * @deprecated This is a legacy way of organizing branch keys
- * It was introduced as a step to remove branch fetching from ComponentContainer.
- */
-function useBranchesQueryKey(innerState: InnerState, componentKey?: string) {
- // Currently, we do not have the component in a react-state ready
- // Once we refactor we will be able to fetch it from query state.
- // We will be able to make sure that the component is not a portfolio.
- // Mixing query param and react-state is dangerous.
- // It should be avoided as much as possible.
- const { search } = useLocation();
- const searchParams = new URLSearchParams(search);
-
- if (!isDefined(componentKey)) {
- return ['branches'];
- }
-
- if (searchParams.has('pullRequest')) {
- return [
- 'branches',
- componentKey,
- 'pull-request',
- searchParams.get('pullRequest') as string,
- innerState,
- ] as const;
- }
-
- if (searchParams.has('branch')) {
- return [
- 'branches',
- componentKey,
- 'branch',
- searchParams.get('branch') as string,
- innerState,
- ] as const;
- }
-
- if (searchParams.has('fixedInPullRequest')) {
- return [
- 'branches',
- componentKey,
- 'fixedInPullRequest',
- searchParams.get('fixedInPullRequest') as string,
- innerState,
- ] as const;
- }
-
- return ['branches', componentKey, innerState] as const;
-}
-
-function branchesQuery(
- component: LightComponent | undefined,
- branchSupportFeatureEnabled: boolean,
-) {
- return queryOptions({
- // we don't care about branchSupportFeatureEnabled in the key, as it never changes during a user session
- queryKey: ['branches', 'list', component?.key],
- queryFn: async ({ queryKey: [, , key] }) => {
- if (component === undefined || key === undefined || isPortfolioLike(component.qualifier)) {
- return [] as BranchLike[];
- }
-
- // Pull Requests exist only for projects and if [branch-support] is enabled
- const branchLikesPromise =
- isProject(component.qualifier) && branchSupportFeatureEnabled
- ? [getBranches(key), getPullRequests(key)]
- : [getBranches(key)];
- const branchLikes = await Promise.all(branchLikesPromise).then(flatten<BranchLike>);
-
- return branchLikes;
- },
- enabled: isDefined(component),
- });
-}
-
-/**
- * @deprecated This is a legacy way of organizing branch keys
- * It was introduce as a step to remove branch fetching from ComponentContainer.
- */
-function useMutateBranchQueryKey() {
- const { search } = useLocation();
- const searchParams = new URLSearchParams(search);
-
- if (searchParams.has('id')) {
- return ['branches', searchParams.get('id') as string] as const;
- }
- return ['branches'];
-}
-
-function getContext(key: ReturnType<typeof useBranchesQueryKey>, branchLike?: BranchLike) {
- const [_b, componentKey, prOrBranch, branchKey] = key;
- if (prOrBranch === 'pull-request') {
- return { componentKey, query: { pullRequest: branchKey } };
- }
- if (prOrBranch === 'branch') {
- return { componentKey, query: { branch: branchKey } };
- }
- if (prOrBranch === 'fixedInPullRequest') {
- return { componentKey, query: { branch: (branchLike as Branch)?.name } };
- }
- return { componentKey, query: {} };
-}
-
-export function useBranchesQuery(component: LightComponent | undefined) {
- const features = useContext(AvailableFeaturesContext);
-
- return useQuery({
- ...branchesQuery(component, features.includes(Feature.BranchSupport)),
- initialData: [],
- staleTime: StaleTime.SHORT,
- });
-}
-
-export function useCurrentBranchQuery(
- component: LightComponent | undefined,
- staleTime = StaleTime.LIVE,
-) {
- const features = useContext(AvailableFeaturesContext);
- const { search } = useLocation();
-
- const select = useCallback(
- (branchLikes: BranchLike[]) => {
- const searchParams = new URLSearchParams(search);
- if (searchParams.has('branch')) {
- return branchLikes.find((b) => isBranch(b) && b.name === searchParams.get('branch'));
- } else if (searchParams.has('pullRequest')) {
- return branchLikes.find(
- (b) => isPullRequest(b) && b.key === searchParams.get('pullRequest'),
- );
- } else if (searchParams.has('fixedInPullRequest')) {
- const targetBranch = branchLikes
- .filter(isPullRequest)
- .find((b) => b.key === searchParams.get('fixedInPullRequest'))?.target;
- return branchLikes.find((b) => isBranch(b) && b.name === targetBranch);
- }
-
- return branchLikes.find((b) => isBranch(b) && b.isMain);
- },
- [search],
- );
-
- return useQuery({
- ...branchesQuery(component, features.includes(Feature.BranchSupport)),
- select,
- staleTime,
- });
-}
-
-export function useBranchStatusQuery(component: Component) {
- const { data: branchLike } = useCurrentBranchQuery(component);
- const key = useBranchesQueryKey(InnerState.Status, component.key);
- return useQuery({
- queryKey: key,
- queryFn: async ({ queryKey }) => {
- const { query } = getContext(queryKey, branchLike);
- if (!isProject(component.qualifier)) {
- return {};
- }
- const projectStatus = await getQualityGateProjectStatus({
- projectKey: component.key,
- ...query,
- }).catch(() => undefined);
- if (projectStatus === undefined) {
- return {};
- }
-
- const { ignoredConditions, status } = projectStatus;
- const conditions = extractStatusConditionsFromProjectStatus(projectStatus);
- return {
- conditions,
- ignoredConditions,
- status,
- };
- },
- enabled: isProject(component.qualifier) || isApplication(component.qualifier),
- staleTime: StaleTime.SHORT,
- });
-}
-
-export function useBranchWarningQuery(component: Component) {
- const { data: branchLike } = useCurrentBranchQuery(component);
- const key = useBranchesQueryKey(InnerState.Warning, component.key);
- return useQuery({
- queryKey: key,
- queryFn: async ({ queryKey }) => {
- const { query, componentKey } = getContext(queryKey, branchLike);
- const { component: branchStatus } = await getAnalysisStatus({
- component: componentKey,
- ...query,
- });
- return branchStatus.warnings;
- },
- enabled: !!branchLike && isProject(component.qualifier) && component.key === key[1],
- staleTime: StaleTime.SHORT,
- });
-}
-
-export function useDismissBranchWarningMutation(componentKey: string | undefined) {
- type DismissArg = { component: Component; key: string };
- const queryClient = useQueryClient();
- const invalidateKey = useBranchesQueryKey(InnerState.Warning, componentKey);
-
- return useMutation({
- mutationFn: async ({ component, key }: DismissArg) => {
- await dismissAnalysisWarning(component.key, key);
- },
- onSuccess(_1, { component }) {
- queryClient.invalidateQueries({ queryKey: ['branches', 'list', component.key] });
- queryClient.invalidateQueries({ queryKey: invalidateKey });
- },
- });
-}
-
-export function useExcludeFromPurgeMutation() {
- const queryClient = useQueryClient();
- const invalidateKey = useMutateBranchQueryKey();
-
- type ExcludeFromPurgeArg = { component: Component; exclude: boolean; key: string };
-
- return useMutation({
- mutationFn: async ({ component, key, exclude }: ExcludeFromPurgeArg) => {
- await excludeBranchFromPurge(component.key, key, exclude);
- },
- onSuccess(_1, { component }) {
- queryClient.invalidateQueries({ queryKey: ['branches', 'list', component.key] });
- queryClient.invalidateQueries({ queryKey: invalidateKey });
- },
- });
-}
-
-export function useDeletBranchMutation() {
- type DeleteArg = { branchLike: BranchLike; component: Component };
- const queryClient = useQueryClient();
- const [params, setSearhParam] = useSearchParams();
- const invalidateKey = useMutateBranchQueryKey();
-
- return useMutation({
- mutationFn: async ({ branchLike, component }: DeleteArg) => {
- await (isPullRequest(branchLike)
- ? deletePullRequest({
- project: component.key,
- pullRequest: branchLike.key,
- })
- : deleteBranch({
- branch: branchLike.name,
- project: component.key,
- }));
-
- if (
- isBranch(branchLike) &&
- params.has('branch') &&
- params.get('branch') === branchLike.name
- ) {
- setSearhParam(searchParamsToQuery(params, ['branch']));
- return { navigate: true };
- }
-
- if (
- isPullRequest(branchLike) &&
- params.has('pullRequest') &&
- params.get('pullRequest') === branchLike.key
- ) {
- setSearhParam(searchParamsToQuery(params, ['pullRequest']));
- return { navigate: true };
- }
- return { navigate: false };
- },
- onSuccess({ navigate }, { component }) {
- if (!navigate) {
- queryClient.invalidateQueries({ queryKey: ['branches', 'list', component.key] });
- queryClient.invalidateQueries({ queryKey: invalidateKey });
- }
- },
- });
-}
-
-export function useRenameMainBranchMutation() {
- type RenameMainBranchArg = { component: Component; name: string };
- const queryClient = useQueryClient();
- const invalidateKey = useMutateBranchQueryKey();
-
- return useMutation({
- mutationFn: async ({ component, name }: RenameMainBranchArg) => {
- await renameBranch(component.key, name);
- },
- onSuccess(_1, { component }) {
- queryClient.invalidateQueries({ queryKey: ['branches', 'list', component.key] });
- queryClient.invalidateQueries({ queryKey: invalidateKey });
- },
- });
-}
-
-export function useSetMainBranchMutation() {
- type SetAsMainBranchArg = { branchName: string; component: Component };
- const queryClient = useQueryClient();
- const invalidateKey = useMutateBranchQueryKey();
-
- return useMutation({
- mutationFn: async ({ component, branchName }: SetAsMainBranchArg) => {
- await setMainBranch(component.key, branchName);
- },
- onSuccess(_1, { component }) {
- queryClient.invalidateQueries({ queryKey: ['branches', 'list', component.key] });
- queryClient.invalidateQueries({ queryKey: invalidateKey });
- },
- });
-}
-
-/**
- * Helper functions that sould be avoided. Instead convert the component into a functional one
- * and/or use proper react-query
- */
-const REFRESH_INTERVAL = 1_000;
-
-export function useRefreshBranchStatus(componentKey: string | undefined): () => void {
- const queryClient = useQueryClient();
- const invalidateStatusKey = useBranchesQueryKey(InnerState.Status, componentKey);
- const invalidateDetailsKey = useBranchesQueryKey(InnerState.Details, componentKey);
-
- return useCallback(
- debounce(() => {
- queryClient.invalidateQueries({ queryKey: ['branches', 'list', componentKey] });
- queryClient.invalidateQueries({
- queryKey: invalidateStatusKey,
- });
- queryClient.invalidateQueries({
- queryKey: invalidateDetailsKey,
- });
- }, REFRESH_INTERVAL),
- [invalidateDetailsKey, invalidateStatusKey],
- );
-}
-
-export function useRefreshBranches(componentKey: string | undefined) {
- const queryClient = useQueryClient();
- const invalidateKey = useMutateBranchQueryKey();
-
- return () => {
- queryClient.invalidateQueries({ queryKey: ['branches', 'list', componentKey] });
- queryClient.invalidateQueries({ queryKey: invalidateKey });
- };
-}
-
-export interface WithBranchLikesProps {
- branchLike?: BranchLike;
- branchLikes?: BranchLike[];
- isFetchingBranch?: boolean;
-}
-
-export function withBranchLikes<P extends { component?: Component }>(
- WrappedComponent: React.ComponentType<React.PropsWithChildren<P & WithBranchLikesProps>>,
-): React.ComponentType<React.PropsWithChildren<Omit<P, 'branchLike' | 'branchLikes'>>> {
- return function WithBranchLike(p: P) {
- const { data: branchLikes, isLoading } = useBranchesQuery(p.component);
- const { data: branchLike, isFetching } = useCurrentBranchQuery(p.component);
- return (
- <WrappedComponent
- branchLikes={branchLikes ?? []}
- branchLike={branchLike}
- isFetchingBranch={!isPortfolioLike(p.component?.qualifier) && (isFetching || isLoading)}
- {...p}
- />
- );
- };
-}
-
-export function withBranchStatusRefresh<
- P extends { refreshBranchStatus: ReturnType<typeof useRefreshBranchStatus> },
->(
- WrappedComponent: React.ComponentType<React.PropsWithChildren<P>>,
-): React.ComponentType<React.PropsWithChildren<Omit<P, 'refreshBranchStatus'>>> {
- return function WithBranchStatusRefresh(props: P) {
- const { component } = useComponent();
- const refresh = useRefreshBranchStatus(component?.key);
-
- return <WrappedComponent {...props} refreshBranchStatus={refresh} />;
- };
-}
diff --git a/server/sonar-web/src/main/js/queries/ce.ts b/server/sonar-web/src/main/js/queries/ce.ts
deleted file mode 100644
index 384f613a3d9..00000000000
--- a/server/sonar-web/src/main/js/queries/ce.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions } from '@tanstack/react-query';
-import { getActivity } from '../api/ce';
-import { ActivityRequestParameters } from '../types/tasks';
-import { createQueryHook } from './common';
-
-export const useLastActivityQuery = createQueryHook((data: ActivityRequestParameters) => {
- return queryOptions({
- queryKey: ['ce', 'activity', data.component, data.type, data.status],
- queryFn: () => getActivity(data).then(({ tasks }) => (tasks.length > 0 ? tasks[0] : null)),
- });
-});
diff --git a/server/sonar-web/src/main/js/queries/common.ts b/server/sonar-web/src/main/js/queries/common.ts
deleted file mode 100644
index 203f173d423..00000000000
--- a/server/sonar-web/src/main/js/queries/common.ts
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- InfiniteData,
- QueryKey,
- UseInfiniteQueryOptions,
- UseInfiniteQueryResult,
- UseQueryOptions,
- UseQueryResult,
- useInfiniteQuery,
- useQuery,
-} from '@tanstack/react-query';
-
-const isFnWithoutParams = <T>(fn: ((data: any) => T) | (() => T)): fn is () => T => fn.length === 0;
-
-export function createQueryHook<
- T = unknown,
- TQueryData = unknown,
- TError extends Error = Error,
- TData = TQueryData,
- TQueryKey extends QueryKey = QueryKey,
->(
- fn:
- | ((data: T) => UseQueryOptions<TQueryData, TError, TData, TQueryKey>)
- | (() => UseQueryOptions<TQueryData, TError, TData, TQueryKey>),
-): unknown extends T
- ? <SelectType = TQueryData>(
- options?: Omit<
- UseQueryOptions<TQueryData, TError, SelectType, TQueryKey>,
- 'queryKey' | 'queryFn'
- >,
- ) => UseQueryResult<SelectType, TError>
- : <SelectType = TQueryData>(
- data: T,
- options?: Omit<
- UseQueryOptions<TQueryData, TError, SelectType, TQueryKey>,
- 'queryKey' | 'queryFn'
- >,
- ) => UseQueryResult<SelectType, TError>;
-
-export function createQueryHook(fn: ((data: any) => UseQueryOptions) | (() => UseQueryOptions)) {
- if (isFnWithoutParams(fn)) {
- return (options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>) =>
- useQuery({ ...fn(), ...options });
- }
- return (data: any, options?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'>) =>
- useQuery({ ...fn(data), ...options });
-}
-
-export function createInfiniteQueryHook<
- T = unknown,
- TQueryFnData = unknown,
- TError = Error,
- TData = InfiniteData<TQueryFnData>,
- TQueryData = TQueryFnData,
- TQueryKey extends QueryKey = QueryKey,
- TPageParam = unknown,
->(
- fn:
- | ((
- data: T,
- ) => UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey, TPageParam>)
- | (() => UseInfiniteQueryOptions<
- TQueryFnData,
- TError,
- TData,
- TQueryData,
- TQueryKey,
- TPageParam
- >),
-): unknown extends T
- ? <SelectType = TData>(
- options?: Omit<
- UseInfiniteQueryOptions<
- TQueryFnData,
- TError,
- SelectType,
- TQueryData,
- TQueryKey,
- TPageParam
- >,
- 'queryKey' | 'queryFn' | 'getNextPageParam' | 'getPreviousPageParam' | 'initialPageParam'
- >,
- ) => UseInfiniteQueryResult<SelectType, TError>
- : <SelectType = TData>(
- data: T,
- options?: Omit<
- UseInfiniteQueryOptions<
- TQueryFnData,
- TError,
- SelectType,
- TQueryData,
- TQueryKey,
- TPageParam
- >,
- 'queryKey' | 'queryFn' | 'getNextPageParam' | 'getPreviousPageParam' | 'initialPageParam'
- >,
- ) => UseInfiniteQueryResult<SelectType, TError>;
-
-export function createInfiniteQueryHook(
- fn: ((data?: any) => UseInfiniteQueryOptions) | (() => UseInfiniteQueryOptions),
-) {
- if (isFnWithoutParams(fn)) {
- return (
- options?: Omit<
- UseInfiniteQueryOptions,
- 'queryKey' | 'queryFn' | 'getNextPageParam' | 'getPreviousPageParam' | 'initialPageParam'
- >,
- ) => useInfiniteQuery({ ...fn(), ...options });
- }
- return (
- data: any,
- options?: Omit<
- UseInfiniteQueryOptions,
- 'queryKey' | 'queryFn' | 'getNextPageParam' | 'getPreviousPageParam' | 'initialPageParam'
- >,
- ) => useInfiniteQuery({ ...fn(data), ...options });
-}
-
-export enum StaleTime {
- /** Use it when the data doesn't change during the user's session or the data doesn't need to be update-to-date in the UI. */
- NEVER = Infinity,
- /** Use it when the data can change at any time because of user interactions or background tasks, and it's critical to reflect it live in the UI. */
- LIVE = 0,
- /** Use it when the data changes often and you want to be able to see it refreshed quickly but it's critical to see it live. */
- SHORT = 10000,
- /** Use it when the data rarely changes, anything bigger than 60s doesn't change much in term of network load or UX. */
- LONG = 60000,
- /** Use it for ambiguous cases where you can't decide between {@link StaleTime.SHORT} or {@link StaleTime.LONG}. It should rarely be used. */
- MEDIUM = 30000,
-}
diff --git a/server/sonar-web/src/main/js/queries/component.ts b/server/sonar-web/src/main/js/queries/component.ts
deleted file mode 100644
index f678b1ec045..00000000000
--- a/server/sonar-web/src/main/js/queries/component.ts
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useQuery, useQueryClient } from '@tanstack/react-query';
-import { groupBy, omit } from 'lodash';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { getTasksForComponent } from '../api/ce';
-import {
- getBreadcrumbs,
- getComponent,
- getComponentData,
- getComponentForSourceViewer,
-} from '../api/components';
-import { getBranchLikeQuery } from '../sonar-aligned/helpers/branch-like';
-import { BranchLike } from '../types/branch-like';
-import { Component, Measure } from '../types/types';
-import { StaleTime, createQueryHook } from './common';
-
-const TASK_RETRY = 10_000;
-
-type QueryKeyData = {
- branchParameters: BranchParameters;
- metricKeys: string[];
-};
-
-function extractQueryKeyData(queryKey: string[]): { data?: QueryKeyData; key: string } {
- const [, key, , data] = queryKey;
- return { key, data: JSON.parse(data ?? 'null') };
-}
-
-export function useTaskForComponentQuery(component: Component) {
- return useQuery({
- queryKey: ['component', component.key, 'tasks'],
- queryFn: ({ queryKey }) => {
- const { key } = extractQueryKeyData(queryKey);
- return getTasksForComponent(key);
- },
- refetchInterval: TASK_RETRY,
- });
-}
-
-export const useComponentQuery = createQueryHook(
- ({ component, metricKeys, ...params }: Parameters<typeof getComponent>[0]) => {
- const queryClient = useQueryClient();
-
- return queryOptions({
- queryKey: ['component', component, 'measures', { metricKeys, params }],
- queryFn: async () => {
- const result = await getComponent({
- component,
- metricKeys,
- ...params,
- });
- const measuresMapByMetricKey = groupBy(result.component.measures, 'metric');
- metricKeys.split(',').forEach((metricKey) => {
- const measure = measuresMapByMetricKey[metricKey]?.[0] ?? null;
- queryClient.setQueryData<Measure>(
- ['measures', 'details', result.component.key, metricKey],
- measure,
- );
- });
- return result;
- },
- staleTime: StaleTime.LONG,
- });
- },
-);
-
-export const useComponentBreadcrumbsQuery = createQueryHook(
- ({ component, ...params }: Parameters<typeof getBreadcrumbs>[0]) => {
- return queryOptions({
- queryKey: ['component', component, 'breadcrumbs', params],
- queryFn: () => getBreadcrumbs({ component, ...params }),
- staleTime: StaleTime.LONG,
- });
- },
-);
-
-export const useComponentDataQuery = createQueryHook(
- (data: Parameters<typeof getComponentData>[0]) => {
- return queryOptions({
- queryKey: ['component', data.component, 'component_data', omit(data, 'component')],
- queryFn: () => getComponentData(data),
- staleTime: StaleTime.LONG,
- });
- },
-);
-
-export function useComponentForSourceViewer(
- fileKey: string,
- branchLike?: BranchLike,
- enabled = true,
-) {
- return useQuery({
- queryKey: ['component', 'source-viewer', fileKey, branchLike] as const,
- queryFn: ({ queryKey: [_1, _2, fileKey, branchLike] }) =>
- getComponentForSourceViewer({ component: fileKey, ...getBranchLikeQuery(branchLike) }),
- staleTime: Infinity,
- enabled,
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/cves.ts b/server/sonar-web/src/main/js/queries/cves.ts
deleted file mode 100644
index c168e478403..00000000000
--- a/server/sonar-web/src/main/js/queries/cves.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions } from '@tanstack/react-query';
-import { getCve } from '../api/cves';
-import { createQueryHook, StaleTime } from './common';
-
-const KEY_PREFIX = 'cve';
-
-export const useCveQuery = createQueryHook(({ cveId }: { cveId?: string }) => {
- return queryOptions({
- queryKey: [KEY_PREFIX, cveId],
- queryFn: () => getCve(cveId!),
- staleTime: StaleTime.NEVER,
- enabled: !!cveId,
- });
-});
diff --git a/server/sonar-web/src/main/js/queries/dependencies.ts b/server/sonar-web/src/main/js/queries/dependencies.ts
deleted file mode 100644
index 37d2f1ca606..00000000000
--- a/server/sonar-web/src/main/js/queries/dependencies.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { infiniteQueryOptions } from '@tanstack/react-query';
-import { getDependencies } from '../api/dependencies';
-import { BranchLikeParameters } from '../sonar-aligned/types/branch-like';
-import { createInfiniteQueryHook } from './common';
-
-export const useDependenciesQuery = createInfiniteQueryHook(
- (data: {
- branchParameters: BranchLikeParameters;
- pageIndex?: number;
- projectKey: string;
- q?: string;
- }) => {
- return infiniteQueryOptions({
- queryKey: ['dependencies', data.projectKey, data.branchParameters, data.q, data.pageIndex],
- queryFn: ({ pageParam }) => {
- return getDependencies({
- projectKey: data.projectKey,
- q: data.q,
- ...data.branchParameters,
- pageParam,
- });
- },
- initialPageParam: 1,
- getNextPageParam: (lastPage) => {
- return lastPage.page.pageIndex + 1;
- },
- });
- },
-);
diff --git a/server/sonar-web/src/main/js/queries/devops-integration.ts b/server/sonar-web/src/main/js/queries/devops-integration.ts
deleted file mode 100644
index 54570683331..00000000000
--- a/server/sonar-web/src/main/js/queries/devops-integration.ts
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useMutation, useQueryClient } from '@tanstack/react-query';
-import { useLocation } from 'react-router-dom';
-import {
- deleteProjectAlmBinding,
- getProjectAlmBinding,
- setProjectAzureBinding,
- setProjectBitbucketBinding,
- setProjectBitbucketCloudBinding,
- setProjectGithubBinding,
- setProjectGitlabBinding,
-} from '../api/alm-settings';
-import { HttpStatus } from '../helpers/request';
-import { AlmKeys, ProjectAlmBindingParams, ProjectAlmBindingResponse } from '../types/alm-settings';
-import { createQueryHook } from './common';
-
-function useProjectKeyFromLocation() {
- const location = useLocation();
- // Permissions Templates page uses id in query for template id, so to avoid conflict and unwanted fetching we don't search for project there
- if (location.pathname.includes('permission_templates')) {
- return null;
- }
- const search = new URLSearchParams(location.search);
- const id = search.get('id');
- return id as string;
-}
-
-export const useProjectBindingQuery = createQueryHook((project?: string) => {
- const keyFromUrl = useProjectKeyFromLocation();
-
- const projectKey = project ?? keyFromUrl;
-
- return queryOptions({
- queryKey: ['devops_integration', projectKey ?? '_blank_', 'binding'],
- queryFn: ({ queryKey: [_, key] }) =>
- getProjectAlmBinding(key).catch((e: Response) => {
- if (e.status === HttpStatus.NotFound) {
- return null;
- }
- return e as unknown as ProjectAlmBindingResponse;
- }),
- staleTime: 60_000,
- enabled: projectKey !== null,
- });
-});
-
-export function useIsGitHubProjectQuery(project?: string) {
- return useProjectBindingQuery(project, {
- select: (data) => data?.alm === AlmKeys.GitHub,
- });
-}
-
-export function useIsGitLabProjectQuery(project?: string) {
- return useProjectBindingQuery<boolean>(project, {
- select: (data) => data?.alm === AlmKeys.GitLab,
- });
-}
-
-export function useDeleteProjectAlmBindingMutation(project?: string) {
- const keyFromUrl = useProjectKeyFromLocation();
- const client = useQueryClient();
- return useMutation({
- mutationFn: () => {
- const key = project ?? keyFromUrl;
- if (key === null) {
- throw new Error('No project key');
- }
- return deleteProjectAlmBinding(key);
- },
- onSuccess: () => {
- client.invalidateQueries({
- queryKey: ['devops_integration', project ?? keyFromUrl, 'binding'],
- });
- },
- });
-}
-
-const getSetProjectBindingFn = (data: SetBindingParams) => {
- const { alm, almSetting, project, monorepo, slug, repository, summaryCommentEnabled } = data;
- switch (alm) {
- case AlmKeys.Azure: {
- return setProjectAzureBinding({
- almSetting,
- project,
- projectName: slug,
- repositoryName: repository,
- monorepo,
- });
- }
- case AlmKeys.BitbucketServer: {
- return setProjectBitbucketBinding({
- almSetting,
- project,
- repository,
- slug,
- monorepo,
- });
- }
- case AlmKeys.BitbucketCloud: {
- return setProjectBitbucketCloudBinding({
- almSetting,
- project,
- repository,
- monorepo,
- });
- }
- case AlmKeys.GitHub: {
- return setProjectGithubBinding({
- almSetting,
- project,
- repository,
- summaryCommentEnabled,
- monorepo,
- });
- }
-
- case AlmKeys.GitLab: {
- return setProjectGitlabBinding({
- almSetting,
- project,
- repository,
- monorepo,
- });
- }
-
- default:
- return Promise.reject();
- }
-};
-
-type SetBindingParams = ProjectAlmBindingParams & {
- repository: string;
-} & (
- | { alm: AlmKeys.Azure | AlmKeys.BitbucketServer; slug: string; summaryCommentEnabled?: never }
- | { alm: AlmKeys.GitHub; slug?: never; summaryCommentEnabled: boolean }
- | {
- alm: Exclude<AlmKeys, AlmKeys.Azure | AlmKeys.GitHub | AlmKeys.BitbucketServer>;
- slug?: never;
- summaryCommentEnabled?: never;
- }
- );
-
-export function useSetProjectBindingMutation() {
- const client = useQueryClient();
- return useMutation({
- mutationFn: (data: SetBindingParams) => getSetProjectBindingFn(data),
- onSuccess: (_, variables) => {
- client.invalidateQueries({ queryKey: ['devops_integration', variables.project, 'binding'] });
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/dismissed-messages.ts b/server/sonar-web/src/main/js/queries/dismissed-messages.ts
deleted file mode 100644
index 471824fde75..00000000000
--- a/server/sonar-web/src/main/js/queries/dismissed-messages.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useMutation, useQueryClient } from '@tanstack/react-query';
-import { checkMessageDismissed, MessageDismissParams, setMessageDismissed } from '../api/messages';
-import { useCurrentUser } from '../app/components/current-user/CurrentUserContext';
-import { isLoggedIn } from '../types/users';
-import { createQueryHook } from './common';
-
-export const useMessageDismissedQuery = createQueryHook(
- ({ messageType, projectKey }: MessageDismissParams) => {
- const { currentUser } = useCurrentUser();
- return queryOptions({
- queryKey: ['message-dismissed', projectKey, messageType],
- queryFn: () => checkMessageDismissed({ projectKey, messageType }),
- enabled: isLoggedIn(currentUser),
- });
- },
-);
-
-export function useMessageDismissedMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: setMessageDismissed,
- onSuccess: (_, { messageType, projectKey }) => {
- queryClient.setQueryData(['message-dismissed', projectKey, messageType], { dismiss: true });
- queryClient.invalidateQueries({ queryKey: ['message-dismissed', projectKey, messageType] });
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/dop-translation.ts b/server/sonar-web/src/main/js/queries/dop-translation.ts
deleted file mode 100644
index 8a5ffb48635..00000000000
--- a/server/sonar-web/src/main/js/queries/dop-translation.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { addGlobalSuccessMessage } from '~design-system';
-import {
- createGitHubConfiguration,
- deleteGitHubConfiguration,
- fetchGitHubConfiguration,
- getProjectBindings,
- searchGitHubConfigurations,
- updateGitHubConfiguration,
-} from '../api/dop-translation';
-import { translate } from '../helpers/l10n';
-import { ProvisioningType } from '../types/provisioning';
-import { useSyncWithGitHubNow } from './identity-provider/github';
-
-/*
- * Project bindings
- */
-export function useProjectBindingsQuery(
- data: {
- dopSettingId?: string;
- pageIndex?: number;
- pageSize?: number;
- repository?: string;
- },
- enabled = true,
-) {
- return useQuery({
- enabled,
- queryKey: ['dop-translation', 'project-bindings', data],
- queryFn: () => getProjectBindings(data),
- });
-}
-
-/*
- * GitHub configurations
- */
-export function useSearchGitHubConfigurationsQuery() {
- return useQuery({
- queryKey: ['dop-translation', 'github-configs', 'search'],
- queryFn: searchGitHubConfigurations,
- });
-}
-
-export function useFetchGitHubConfigurationQuery(id: string) {
- return useQuery({
- queryKey: ['dop-translation', 'github-configs', 'fetch'],
- queryFn: () => fetchGitHubConfiguration(id),
- });
-}
-
-export function useCreateGitHubConfigurationMutation() {
- const client = useQueryClient();
- return useMutation({
- mutationFn: (gitHubConfiguration: Parameters<typeof createGitHubConfiguration>[0]) =>
- createGitHubConfiguration(gitHubConfiguration),
- onSuccess(gitHubConfiguration) {
- client.setQueryData(['dop-translation', 'github-configs', 'search'], {
- githubConfigurations: [gitHubConfiguration],
- page: {
- pageIndex: 1,
- pageSize: 1,
- total: 1,
- },
- });
- client.setQueryData(['dop-translation', 'github-configs', 'fetch'], gitHubConfiguration);
- },
- });
-}
-
-export function useUpdateGitHubConfigurationMutation() {
- const client = useQueryClient();
- const { canSyncNow, synchronizeNow } = useSyncWithGitHubNow();
- return useMutation({
- mutationFn: ({
- gitHubConfiguration,
- id,
- }: {
- gitHubConfiguration: Parameters<typeof updateGitHubConfiguration>[1];
- id: Parameters<typeof updateGitHubConfiguration>[0];
- }) => updateGitHubConfiguration(id, gitHubConfiguration),
- onSuccess(gitHubConfiguration) {
- client.setQueryData(['dop-translation', 'github-configs', 'search'], {
- githubConfigurations: [gitHubConfiguration],
- page: {
- pageIndex: 1,
- pageSize: 1,
- total: 1,
- },
- });
- client.setQueryData(['dop-translation', 'github-configs', 'fetch'], gitHubConfiguration);
- client.invalidateQueries({ queryKey: ['identity_provider'] });
- if (canSyncNow && gitHubConfiguration.provisioningType === ProvisioningType.auto) {
- synchronizeNow();
- }
- addGlobalSuccessMessage(translate('settings.authentication.form.settings.save_success'));
- },
- });
-}
-
-export function useDeleteGitHubConfigurationMutation() {
- const client = useQueryClient();
- return useMutation({
- mutationFn: (id: Parameters<typeof deleteGitHubConfiguration>[0]) =>
- deleteGitHubConfiguration(id),
- onSuccess() {
- client.setQueryData(['dop-translation', 'github-configs', 'search'], {
- githubConfigurations: [],
- page: {
- pageIndex: 1,
- pageSize: 1,
- total: 1,
- },
- });
- client.setQueryData(['dop-translation', 'github-configs', 'fetch'], undefined);
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/emails.ts b/server/sonar-web/src/main/js/queries/emails.ts
deleted file mode 100644
index d80917e985a..00000000000
--- a/server/sonar-web/src/main/js/queries/emails.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useMutation } from '@tanstack/react-query';
-import { sendTestEmail } from '../api/settings';
-
-export function useSendTestEmailMutation() {
- return useMutation<
- void,
- Response,
- {
- message: string;
- recipient: string;
- subject: string;
- },
- unknown
- >({
- mutationFn: ({ message, recipient, subject }) => sendTestEmail(recipient, subject, message),
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/favorites.ts b/server/sonar-web/src/main/js/queries/favorites.ts
deleted file mode 100644
index ac62eae409c..00000000000
--- a/server/sonar-web/src/main/js/queries/favorites.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { InfiniteData, useMutation, useQueryClient } from '@tanstack/react-query';
-import { ComponentRaw } from '../api/components';
-import { addFavorite, removeFavorite } from '../api/favorites';
-import { projectsQueryKeys } from './projects';
-
-export function useToggleFavoriteMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: ({ component, addToFavorites }: { addToFavorites: boolean; component: string }) =>
- addToFavorites ? addFavorite(component) : removeFavorite(component),
- onSuccess: (_, { component, addToFavorites }) => {
- // Update the list cache to reflect the new favorite status
- queryClient.setQueriesData(
- { queryKey: projectsQueryKeys.allList() },
- getProjectsFavoritesHandler(component, addToFavorites),
- );
- queryClient.invalidateQueries({
- queryKey: projectsQueryKeys.allList(),
- refetchType: 'none',
- });
-
- // Silently update component details cache
- queryClient.setQueryData(
- projectsQueryKeys.details(component),
- (oldData: { components: ComponentRaw[] }) => {
- if (!oldData) {
- return oldData;
- }
- return {
- ...oldData,
- components: [{ ...oldData.components[0], isFavorite: addToFavorites }],
- };
- },
- );
- },
- });
-}
-
-function getProjectsFavoritesHandler(projectKey: string, addedToFavorites: boolean) {
- return (oldData: InfiniteData<{ components: ComponentRaw[] }>) => {
- if (!oldData) {
- return oldData;
- }
-
- return {
- ...oldData,
- pages: oldData.pages.map((page) => ({
- ...page,
- components: page.components.map((component) => {
- if (component.key === projectKey) {
- return {
- ...component,
- isFavorite: addedToFavorites,
- };
- }
-
- return component;
- }),
- })),
- };
- };
-}
diff --git a/server/sonar-web/src/main/js/queries/fix-suggestions.tsx b/server/sonar-web/src/main/js/queries/fix-suggestions.tsx
deleted file mode 100644
index 4a125384e82..00000000000
--- a/server/sonar-web/src/main/js/queries/fix-suggestions.tsx
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { AxiosError } from 'axios';
-import { some } from 'lodash';
-import React, { useContext } from 'react';
-import {
- getFixSuggestionServiceInfo,
- getFixSuggestionsIssues,
- getSuggestions,
- ServiceInfo,
- updateFeatureEnablement,
-} from '../api/fix-suggestions';
-import { useAvailableFeatures } from '../app/components/available-features/withAvailableFeatures';
-import { CurrentUserContext } from '../app/components/current-user/CurrentUserContext';
-import { Feature } from '../types/features';
-import { Issue } from '../types/types';
-import { isLoggedIn } from '../types/users';
-import { useComponentDataQuery } from './component';
-import { useRawSourceQuery } from './sources';
-
-const UNKNOWN = -1;
-
-export enum LineTypeEnum {
- CODE = 'code',
- ADDED = 'added',
- REMOVED = 'removed',
-}
-
-export type DisplayedLine = {
- code: string;
- copy?: string;
- lineAfter: number;
- lineBefore: number;
- type: LineTypeEnum;
-};
-
-export type CodeSuggestion = {
- changes: Array<{ endLine: number; newCode: string; startLine: number }>;
- explanation: string;
- suggestionId: string;
- unifiedLines: DisplayedLine[];
-};
-
-export function usePrefetchSuggestion(issueKey: string) {
- const queryClient = useQueryClient();
- return () => {
- queryClient.prefetchQuery({ queryKey: ['code-suggestions', issueKey] });
- };
-}
-
-export function useUnifiedSuggestionsQuery(issue: Issue, enabled = true) {
- const branchLikeParam = issue.pullRequest
- ? { pullRequest: issue.pullRequest }
- : issue.branch
- ? { branch: issue.branch }
- : {};
-
- const { data: code } = useRawSourceQuery(
- { ...branchLikeParam, key: issue.component },
- { enabled },
- );
-
- return useQuery({
- queryKey: ['code-suggestions', issue.key],
- queryFn: ({ queryKey: [_1, issueId] }) => getSuggestions({ issueId }),
- enabled: enabled && code !== undefined,
- refetchOnMount: false,
- refetchOnWindowFocus: false,
- staleTime: Infinity,
- retry: false,
- select: (suggestedCode) => {
- if (code !== undefined && suggestedCode.changes) {
- const originalCodes = code.split(/\r?\n|\r|\n/g).map((line, index) => {
- const lineNumber = index + 1;
- const isRemoved = some(
- suggestedCode.changes,
- ({ startLine, endLine }) => startLine <= lineNumber && lineNumber <= endLine,
- );
- return {
- code: line,
- lineNumber,
- type: isRemoved ? LineTypeEnum.REMOVED : LineTypeEnum.CODE,
- };
- });
-
- const unifiedLines = originalCodes.flatMap<DisplayedLine>((line) => {
- const change = suggestedCode.changes.find(
- ({ endLine }) => endLine === line.lineNumber - 1,
- );
- if (change) {
- return [
- ...change.newCode.split(/\r?\n|\r|\n/g).map((newLine, index) => ({
- code: newLine,
- type: LineTypeEnum.ADDED,
- lineBefore: UNKNOWN,
- lineAfter: UNKNOWN,
- copy: index === 0 ? change.newCode : undefined,
- })),
- { code: line.code, type: line.type, lineBefore: line.lineNumber, lineAfter: UNKNOWN },
- ];
- }
-
- return [
- { code: line.code, type: line.type, lineBefore: line.lineNumber, lineAfter: UNKNOWN },
- ];
- });
- let lineAfterCount = 1;
- unifiedLines.forEach((line) => {
- if (line.type !== LineTypeEnum.REMOVED) {
- line.lineAfter = lineAfterCount;
- lineAfterCount += 1;
- }
- });
- return {
- unifiedLines,
- explanation: suggestedCode.explanation,
- changes: suggestedCode.changes,
- suggestionId: suggestedCode.id,
- };
- }
- return {
- unifiedLines: [],
- explanation: suggestedCode.explanation,
- changes: [],
- suggestionId: suggestedCode.id,
- };
- },
- });
-}
-
-export function useGetFixSuggestionsIssuesQuery(issue: Issue) {
- const { currentUser } = useContext(CurrentUserContext);
- const { hasFeature } = useAvailableFeatures();
-
- const isCodeFixEnabled =
- useComponentDataQuery({ component: issue.project }).data?.component?.isAiCodeFixEnabled ||
- false;
-
- return useQuery({
- queryKey: ['code-suggestions', 'issues', 'details', issue.key],
- queryFn: () =>
- getFixSuggestionsIssues({
- issueId: issue.key,
- }),
- enabled: hasFeature(Feature.FixSuggestions) && isLoggedIn(currentUser) && isCodeFixEnabled,
- staleTime: Infinity,
- });
-}
-
-export function useRemoveCodeSuggestionsCache() {
- const queryClient = useQueryClient();
- return () => {
- queryClient.removeQueries({ queryKey: ['code-suggestions'] });
- };
-}
-
-export function withUseGetFixSuggestionsIssues<P extends { issue: Issue }>(
- Component: React.ComponentType<
- Omit<P, 'aiSuggestionAvailable'> & { aiSuggestionAvailable: boolean }
- >,
-) {
- return function WithGetFixSuggestion(props: Omit<P, 'aiSuggestionAvailable'>) {
- const { data } = useGetFixSuggestionsIssuesQuery(props.issue);
- return <Component aiSuggestionAvailable={data?.aiSuggestion === 'AVAILABLE'} {...props} />;
- };
-}
-
-export function useGetServiceInfoQuery() {
- return useQuery<ServiceInfo, AxiosError>({
- queryKey: ['fix-suggestions', 'service-info'],
- queryFn: getFixSuggestionServiceInfo,
- });
-}
-
-export function useUpdateFeatureEnablementMutation() {
- return useMutation({
- mutationFn: updateFeatureEnablement,
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/group-memberships.ts b/server/sonar-web/src/main/js/queries/group-memberships.ts
deleted file mode 100644
index c1a4c5b1ed2..00000000000
--- a/server/sonar-web/src/main/js/queries/group-memberships.ts
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import {
- addGroupMembership,
- getGroupMemberships,
- removeGroupMembership,
-} from '../api/group-memberships';
-import { getUsers } from '../api/users';
-import { SelectListFilter } from '../components/controls/SelectList';
-import { translateWithParameters } from '../helpers/l10n';
-import { getNextPageParam, getPreviousPageParam } from '../helpers/react-query';
-import { RestUserDetailed } from '../types/users';
-import { useGroupsQueries } from './groups';
-
-const DOMAIN = 'group-memberships';
-const GROUP_SUB_DOMAIN = 'users-of-group';
-const USER_SUB_DOMAIN = 'groups-of-user';
-
-export function useGroupMembersQuery(params: {
- filter?: SelectListFilter;
- groupId: string;
- pageIndex?: number;
- q?: string;
-}) {
- return useInfiniteQuery({
- queryKey: [DOMAIN, GROUP_SUB_DOMAIN, 'list', params],
- queryFn: async ({ pageParam }) => {
- if (params.filter === SelectListFilter.All) {
- const result = await getUsers<RestUserDetailed>({
- q: params.q ?? '',
- pageIndex: pageParam,
- });
- const isSelected = async (userId: string, groupId: string) => {
- const memberships = await getGroupMemberships({ userId, groupId, pageSize: 0 });
- return memberships.page.total > 0;
- };
- return {
- users: await Promise.all(
- result.users.map(async (u) => ({
- ...u,
- selected: await isSelected(u.id, params.groupId),
- })),
- ),
- page: result.page,
- };
- }
- const isSelected = params.filter === SelectListFilter.Selected || params.filter === undefined;
- return getUsers<RestUserDetailed>({
- q: params.q ?? '',
- [isSelected ? 'groupId' : 'groupId!']: params.groupId,
- pageIndex: pageParam,
- }).then((res) => ({
- users: res.users.map((u) => ({
- ...u,
- selected: isSelected,
- })),
- page: res.page,
- }));
- },
- getNextPageParam,
- getPreviousPageParam,
- initialPageParam: 1,
- });
-}
-
-export function useRemoveGroupMembersQueryFromCache() {
- const queryClient = useQueryClient();
- return () => {
- queryClient.removeQueries({ queryKey: [DOMAIN, GROUP_SUB_DOMAIN, 'list'] });
- };
-}
-
-export function useUserGroupsQuery(params: {
- filter?: SelectListFilter;
- q?: string;
- userId: string;
-}) {
- const { q, filter, userId } = params;
- const {
- data: groupsPages,
- isPending: loadingGroups,
- fetchNextPage: fetchNextPageGroups,
- hasNextPage: hasNextPageGroups,
- } = useGroupsQueries({});
- const {
- data: membershipsPages,
- isPending: loadingMemberships,
- fetchNextPage: fetchNextPageMemberships,
- hasNextPage: hasNextPageMemberships,
- } = useInfiniteQuery({
- queryKey: [DOMAIN, USER_SUB_DOMAIN, 'memberships', userId],
- queryFn: ({ pageParam }) =>
- getGroupMemberships({ userId, pageSize: 100, pageIndex: pageParam }),
- getNextPageParam,
- getPreviousPageParam,
- initialPageParam: 1,
- });
- if (hasNextPageGroups) {
- fetchNextPageGroups();
- }
- if (hasNextPageMemberships) {
- fetchNextPageMemberships();
- }
- return useQuery({
- queryKey: [DOMAIN, USER_SUB_DOMAIN, params],
- queryFn: () => {
- const memberships =
- membershipsPages?.pages.flatMap((page) => page.groupMemberships).flat() ?? [];
- const groups = (groupsPages?.pages.flatMap((page) => page.groups).flat() ?? [])
- .filter(
- (group) =>
- q === undefined ||
- group.name.toLowerCase().includes(q.toLowerCase()) ||
- group.description?.toLowerCase().includes(q.toLowerCase()),
- )
- .map((group) => ({
- ...group,
- selected: memberships.some((membership) => membership.groupId === group.id),
- }));
- switch (filter) {
- case SelectListFilter.All:
- return groups;
- case SelectListFilter.Unselected:
- return groups.filter((group) => !group.selected);
- default:
- return groups.filter((group) => group.selected);
- }
- },
- enabled: !loadingGroups && !hasNextPageGroups && !loadingMemberships && !hasNextPageMemberships,
- });
-}
-
-export function useGroupMembersCountQuery(groupId: string) {
- return useQuery({
- queryKey: [DOMAIN, GROUP_SUB_DOMAIN, 'count', groupId],
- queryFn: () => getGroupMemberships({ groupId, pageSize: 0 }).then((r) => r.page.total),
- });
-}
-
-export function useUserGroupsCountQuery(userId: string) {
- return useQuery({
- queryKey: [DOMAIN, USER_SUB_DOMAIN, 'count', userId],
- queryFn: () => getGroupMemberships({ userId, pageSize: 0 }).then((r) => r.page.total),
- });
-}
-
-export function useAddGroupMembershipMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (data: Parameters<typeof addGroupMembership>[0]) => addGroupMembership(data),
- onSuccess(_, data) {
- queryClient.setQueryData<number>(
- [DOMAIN, GROUP_SUB_DOMAIN, 'count', data.groupId],
- (oldData) => (oldData !== undefined ? oldData + 1 : undefined),
- );
- queryClient.setQueryData<number>(
- [DOMAIN, USER_SUB_DOMAIN, 'count', data.userId],
- (oldData) => (oldData !== undefined ? oldData + 1 : undefined),
- );
- queryClient.invalidateQueries({
- queryKey: [DOMAIN, USER_SUB_DOMAIN, 'memberships', data.userId],
- });
- },
- });
-}
-
-export function useRemoveGroupMembershipMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: async ({ userId, groupId }: { groupId: string; userId: string }) => {
- const memberships = await getGroupMemberships({ userId, groupId, pageSize: 1 });
- if (!memberships.page.total) {
- throw new Error(
- translateWithParameters('group_membership.remove_user.error', userId, groupId),
- );
- }
- return removeGroupMembership(memberships.groupMemberships[0].id);
- },
- onSuccess(_, data) {
- queryClient.setQueryData<number>(
- [DOMAIN, GROUP_SUB_DOMAIN, 'count', data.groupId],
- (oldData) => (oldData !== undefined ? oldData - 1 : undefined),
- );
- queryClient.setQueryData<number>(
- [DOMAIN, USER_SUB_DOMAIN, 'count', data.userId],
- (oldData) => (oldData !== undefined ? oldData - 1 : undefined),
- );
- queryClient.invalidateQueries({
- queryKey: [DOMAIN, USER_SUB_DOMAIN, 'memberships', data.userId],
- });
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/groups.ts b/server/sonar-web/src/main/js/queries/groups.ts
deleted file mode 100644
index 749ec870b48..00000000000
--- a/server/sonar-web/src/main/js/queries/groups.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { infiniteQueryOptions, useMutation, useQueryClient } from '@tanstack/react-query';
-import { createGroup, deleteGroup, getUsersGroups, updateGroup } from '../api/user_groups';
-import { getNextPageParam, getPreviousPageParam } from '../helpers/react-query';
-import { createInfiniteQueryHook } from './common';
-
-export const useGroupsQueries = createInfiniteQueryHook(
- (getParams: Omit<Parameters<typeof getUsersGroups>[0], 'pageSize' | 'pageIndex'>) => {
- return infiniteQueryOptions({
- queryKey: ['group', 'list', getParams],
- queryFn: ({ pageParam }) => getUsersGroups({ ...getParams, pageIndex: pageParam }),
- getNextPageParam,
- getPreviousPageParam,
- initialPageParam: 1,
- });
- },
-);
-
-export function useCreateGroupMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (data: Parameters<typeof createGroup>[0]) => createGroup(data),
- onSuccess() {
- queryClient.invalidateQueries({ queryKey: ['group', 'list'] });
- },
- });
-}
-
-export function useUpdateGroupMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: ({
- id,
- data,
- }: {
- data: Parameters<typeof updateGroup>[1];
- id: Parameters<typeof updateGroup>[0];
- }) => updateGroup(id, data),
- onSuccess() {
- queryClient.invalidateQueries({ queryKey: ['group', 'list'] });
- },
- });
-}
-
-export function useDeleteGroupMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (data: Parameters<typeof deleteGroup>[0]) => deleteGroup(data),
- onSuccess() {
- queryClient.invalidateQueries({ queryKey: ['group', 'list'] });
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/hotspots.ts b/server/sonar-web/src/main/js/queries/hotspots.ts
deleted file mode 100644
index 9a7d2ce02c2..00000000000
--- a/server/sonar-web/src/main/js/queries/hotspots.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions } from '@tanstack/react-query';
-import { getSecurityHotspotDetails } from '../api/security-hotspots';
-import { createQueryHook, StaleTime } from './common';
-
-export const useSecurityHotspotDetailsQuery = createQueryHook((param: { key: string }) =>
- queryOptions({
- queryKey: ['hotspot', 'details', param.key],
- queryFn: () => getSecurityHotspotDetails(param.key),
- // For now no mutation is migrate, later it can be set to never
- staleTime: StaleTime.LIVE,
- }),
-);
diff --git a/server/sonar-web/src/main/js/queries/identity-provider/common.ts b/server/sonar-web/src/main/js/queries/identity-provider/common.ts
deleted file mode 100644
index 3363d95e103..00000000000
--- a/server/sonar-web/src/main/js/queries/identity-provider/common.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { UseQueryOptions, useQuery } from '@tanstack/react-query';
-import { getSystemInfo } from '../../api/system';
-import { Provider, SysInfoCluster } from '../../types/types';
-
-export function useIdentityProviderQuery<T = { provider: Provider }>(
- options?: Omit<UseQueryOptions<{ provider: Provider }, Error, T>, 'queryKey' | 'queryFn'>,
-) {
- return useQuery({
- queryKey: ['identity_provider', 'users_and_groups_provider'],
- queryFn: async () => {
- const info = (await getSystemInfo()) as SysInfoCluster;
- return { provider: info.System['External Users and Groups Provisioning'] };
- },
- ...options,
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/identity-provider/github.ts b/server/sonar-web/src/main/js/queries/identity-provider/github.ts
deleted file mode 100644
index 4afb1964e01..00000000000
--- a/server/sonar-web/src/main/js/queries/identity-provider/github.ts
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { isEqual, keyBy, partition, pick, unionBy } from 'lodash';
-import { useContext } from 'react';
-import { addGlobalSuccessMessage } from '~design-system';
-import {
- addGithubRolesMapping,
- checkConfigurationValidity,
- deleteGithubRolesMapping,
- fetchGithubProvisioningStatus,
- fetchGithubRolesMapping,
- syncNowGithubProvisioning,
- updateGithubRolesMapping,
-} from '../../api/github-provisioning';
-import { AvailableFeaturesContext } from '../../app/components/available-features/AvailableFeaturesContext';
-import { translate } from '../../helpers/l10n';
-import { mapReactQueryResult } from '../../helpers/react-query';
-import { Feature } from '../../types/features';
-import { DevopsRolesMapping } from '../../types/provisioning';
-import { StaleTime, createQueryHook } from '../common';
-
-export const useCheckGitHubConfigQuery = (githubEnabled: boolean) => {
- return useQuery({
- queryKey: ['identity_provider', 'github_check'],
- queryFn: checkConfigurationValidity,
- enabled: githubEnabled,
- });
-};
-
-interface GithubSyncStatusOptions {
- noRefetch?: boolean;
-}
-
-export function useGitHubSyncStatusQuery(options: GithubSyncStatusOptions = {}) {
- const hasGithubProvisioning = useContext(AvailableFeaturesContext).includes(
- Feature.GithubProvisioning,
- );
- return useQuery({
- queryKey: ['identity_provider', 'github_sync', 'status'],
- queryFn: fetchGithubProvisioningStatus,
- enabled: hasGithubProvisioning,
- refetchInterval: options.noRefetch ? undefined : 10_000,
- });
-}
-
-export function useGithubProvisioningEnabledQuery() {
- const res = useGitHubSyncStatusQuery({ noRefetch: true });
-
- return mapReactQueryResult(res, (data) => {
- return data.enabled;
- });
-}
-
-export function useSyncWithGitHubNow() {
- const queryClient = useQueryClient();
- const { data } = useGitHubSyncStatusQuery();
- const mutation = useMutation({
- mutationFn: syncNowGithubProvisioning,
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['identity_provider', 'github_sync'] });
- },
- });
-
- return {
- synchronizeNow: mutation.mutate,
- canSyncNow: data?.enabled && !data.nextSync && !mutation.isPending,
- };
-}
-
-// Order is reversed to put custom roles at the end (their index is -1)
-const defaultRoleOrder = ['admin', 'maintain', 'write', 'triage', 'read'];
-
-function sortGithubRoles(data: DevopsRolesMapping[]) {
- return [...data].sort((a, b) => {
- if (defaultRoleOrder.includes(a.id) || defaultRoleOrder.includes(b.id)) {
- return defaultRoleOrder.indexOf(b.id) - defaultRoleOrder.indexOf(a.id);
- }
- return a.role.localeCompare(b.role);
- });
-}
-
-export const useGithubRolesMappingQuery = createQueryHook(() => {
- return queryOptions({
- queryKey: ['identity_provider', 'github_mapping'],
- queryFn: fetchGithubRolesMapping,
- staleTime: StaleTime.LONG,
- select: sortGithubRoles, // uses a stable function reference
- });
-});
-
-export function useGithubRolesMappingMutation() {
- const client = useQueryClient();
- const queryKey = ['identity_provider', 'github_mapping'];
- return useMutation({
- mutationFn: async (mapping: DevopsRolesMapping[]) => {
- const state = keyBy(client.getQueryData<DevopsRolesMapping[]>(queryKey), (m) => m.id);
-
- const [maybeChangedRoles, newRoles] = partition(mapping, (m) => state[m.id]);
- const changedRoles = maybeChangedRoles.filter((item) => !isEqual(item, state[item.id]));
- const deletedRoles = Object.values(state).filter(
- (m) => !m.baseRole && !mapping.some((cm) => m.id === cm.id),
- );
-
- return {
- addedOrChanged: await Promise.all([
- ...changedRoles.map((data) =>
- updateGithubRolesMapping(data.id, pick(data, 'permissions')),
- ),
- ...newRoles.map((m) => addGithubRolesMapping(m)),
- ]),
- deleted: await Promise.all([
- deletedRoles.map((dm) => deleteGithubRolesMapping(dm.id)),
- ]).then(() => deletedRoles.map((dm) => dm.id)),
- };
- },
- onSuccess: ({ addedOrChanged, deleted }) => {
- const state = client.getQueryData<DevopsRolesMapping[]>(queryKey);
- if (state) {
- const newData = unionBy(
- addedOrChanged,
- state.filter((s) => deleted.find((id) => id === s.id) === undefined),
- (el) => el.id,
- );
- client.setQueryData(queryKey, newData);
- }
- addGlobalSuccessMessage(
- translate('settings.authentication.github.configuration.roles_mapping.save_success'),
- );
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/identity-provider/gitlab.ts b/server/sonar-web/src/main/js/queries/identity-provider/gitlab.ts
deleted file mode 100644
index 73130695f07..00000000000
--- a/server/sonar-web/src/main/js/queries/identity-provider/gitlab.ts
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { isEqual, keyBy, partition, pick, unionBy } from 'lodash';
-import { addGlobalSuccessMessage } from '~design-system';
-import { getActivity } from '../../api/ce';
-import {
- addGitlabRolesMapping,
- createGitLabConfiguration,
- deleteGitLabConfiguration,
- deleteGitlabRolesMapping,
- fetchGitLabConfigurations,
- fetchGitlabRolesMapping,
- syncNowGitLabProvisioning,
- updateGitLabConfiguration,
- updateGitlabRolesMapping,
-} from '../../api/gitlab-provisioning';
-import { translate } from '../../helpers/l10n';
-import { mapReactQueryResult } from '../../helpers/react-query';
-import { AlmSyncStatus, DevopsRolesMapping, ProvisioningType } from '../../types/provisioning';
-import { TaskStatuses, TaskTypes } from '../../types/tasks';
-import { StaleTime, createQueryHook } from '../common';
-
-export function useGitLabConfigurationsQuery() {
- return useQuery({
- queryKey: ['identity_provider', 'gitlab_config', 'list'],
- queryFn: fetchGitLabConfigurations,
- });
-}
-
-export function useCreateGitLabConfigurationMutation() {
- const client = useQueryClient();
- return useMutation({
- mutationFn: (data: Parameters<typeof createGitLabConfiguration>[0]) =>
- createGitLabConfiguration(data),
- onSuccess(data) {
- client.setQueryData(['identity_provider', 'gitlab_config', 'list'], {
- gitlabConfigurations: [data],
- page: {
- pageIndex: 1,
- pageSize: 1,
- total: 1,
- },
- });
- },
- });
-}
-
-export function useUpdateGitLabConfigurationMutation() {
- const client = useQueryClient();
- const { canSyncNow, synchronizeNow } = useSyncWithGitLabNow();
-
- return useMutation({
- mutationFn: ({
- id,
- data,
- }: {
- data: Parameters<typeof updateGitLabConfiguration>[1];
- id: Parameters<typeof updateGitLabConfiguration>[0];
- }) => updateGitLabConfiguration(id, data),
- onSuccess(data) {
- client.invalidateQueries({ queryKey: ['identity_provider', 'users_and_groups_provider'] });
- client.setQueryData(['identity_provider', 'gitlab_config', 'list'], {
- gitlabConfigurations: [data],
- page: {
- pageIndex: 1,
- pageSize: 1,
- total: 1,
- },
- });
- if (canSyncNow && data.provisioningType === ProvisioningType.auto) {
- synchronizeNow();
- }
- addGlobalSuccessMessage(translate('settings.authentication.form.settings.save_success'));
- },
- });
-}
-
-export function useDeleteGitLabConfigurationMutation() {
- const client = useQueryClient();
- return useMutation({
- mutationFn: (id: Parameters<typeof deleteGitLabConfiguration>[0]) =>
- deleteGitLabConfiguration(id),
- onSuccess() {
- client.setQueryData(['identity_provider', 'gitlab_config', 'list'], {
- gitlabConfigurations: [],
- page: {
- pageIndex: 1,
- pageSize: 1,
- total: 0,
- },
- });
- },
- });
-}
-
-export function useGilabProvisioningEnabledQuery() {
- const res = useGitLabConfigurationsQuery();
-
- return mapReactQueryResult(res, (data) =>
- data.gitlabConfigurations?.some(
- (configuration) =>
- configuration.enabled && configuration.provisioningType === ProvisioningType.auto,
- ),
- );
-}
-
-export function useGitLabSyncStatusQuery() {
- const getLastSync = async () => {
- const lastSyncTasks = await getActivity({
- type: TaskTypes.GitlabProvisioning,
- p: 1,
- ps: 1,
- status: [TaskStatuses.Success, TaskStatuses.Failed, TaskStatuses.Canceled].join(','),
- });
- const lastSync = lastSyncTasks?.tasks[0];
- if (!lastSync) {
- return undefined;
- }
- const summary = lastSync.infoMessages ? lastSync.infoMessages?.join(', ') : '';
- const errorMessage = lastSync.errorMessage ?? '';
- return {
- executionTimeMs: lastSync?.executionTimeMs ?? 0,
- startedAt: +new Date(lastSync?.startedAt ?? 0),
- finishedAt: +new Date(lastSync?.startedAt ?? 0) + (lastSync?.executionTimeMs ?? 0),
- warningMessage:
- lastSync.warnings && lastSync.warnings.length > 0
- ? lastSync.warnings?.join(', ')
- : undefined,
- status: lastSync?.status as
- | TaskStatuses.Success
- | TaskStatuses.Failed
- | TaskStatuses.Canceled,
- ...(lastSync.status === TaskStatuses.Success ? { summary } : {}),
- ...(lastSync.status !== TaskStatuses.Success ? { errorMessage } : {}),
- };
- };
-
- const getNextSync = async () => {
- const nextSyncTasks = await getActivity({
- type: TaskTypes.GitlabProvisioning,
- p: 1,
- ps: 1,
- status: [TaskStatuses.Pending, TaskStatuses.InProgress].join(','),
- });
- const nextSync = nextSyncTasks?.tasks[0];
- if (!nextSync) {
- return undefined;
- }
- return { status: nextSync.status as TaskStatuses.Pending | TaskStatuses.InProgress };
- };
-
- return useQuery({
- queryKey: ['identity_provider', 'gitlab_sync', 'status'],
- queryFn: async () => {
- const [lastSync, nextSync] = await Promise.all([getLastSync(), getNextSync()]);
- return {
- lastSync,
- nextSync,
- } as AlmSyncStatus;
- },
- refetchInterval: 10_000,
- });
-}
-
-export function useSyncWithGitLabNow() {
- const queryClient = useQueryClient();
- const { data: syncStatus } = useGitLabSyncStatusQuery();
- const { data: gitlabConfigurations } = useGitLabConfigurationsQuery();
- const autoProvisioningEnabled = gitlabConfigurations?.gitlabConfigurations.some(
- (configuration) =>
- configuration.enabled && configuration.provisioningType === ProvisioningType.auto,
- );
- const mutation = useMutation({
- mutationFn: syncNowGitLabProvisioning,
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['identity_provider', 'gitlab_sync'] });
- },
- });
-
- return {
- synchronizeNow: mutation.mutate,
- canSyncNow: autoProvisioningEnabled && !syncStatus?.nextSync && !mutation.isPending,
- };
-}
-
-// Order is reversed to put custom roles at the end (their index is -1)
-const defaultRoleOrder = ['owner', 'maintainer', 'developer', 'reporter', 'guest'];
-
-function sortGitlabRoles(data: DevopsRolesMapping[]) {
- return [...data].sort((a, b) => {
- if (defaultRoleOrder.includes(a.id) || defaultRoleOrder.includes(b.id)) {
- return defaultRoleOrder.indexOf(b.id) - defaultRoleOrder.indexOf(a.id);
- }
- return a.role.localeCompare(b.role);
- });
-}
-
-export const useGitlabRolesMappingQuery = createQueryHook(() => {
- return queryOptions({
- queryKey: ['identity_provider', 'gitlab_mapping'],
- queryFn: fetchGitlabRolesMapping,
- staleTime: StaleTime.LONG,
- select: sortGitlabRoles,
- });
-});
-
-export function useGitlabRolesMappingMutation() {
- const client = useQueryClient();
- const queryKey = ['identity_provider', 'gitlab_mapping'];
- return useMutation({
- mutationFn: async (mapping: DevopsRolesMapping[]) => {
- const state = keyBy(client.getQueryData<DevopsRolesMapping[]>(queryKey), (m) => m.id);
-
- const [maybeChangedRoles, newRoles] = partition(mapping, (m) => state[m.id]);
- const changedRoles = maybeChangedRoles.filter((item) => !isEqual(item, state[item.id]));
- const deletedRoles = Object.values(state).filter(
- (m) => !m.baseRole && !mapping.some((cm) => m.id === cm.id),
- );
-
- return {
- addedOrChanged: await Promise.all([
- ...changedRoles.map((data) =>
- updateGitlabRolesMapping(data.id, pick(data, 'permissions')),
- ),
- ...newRoles.map((m) => addGitlabRolesMapping(m)),
- ]),
- deleted: await Promise.all([
- deletedRoles.map((dm) => deleteGitlabRolesMapping(dm.id)),
- ]).then(() => deletedRoles.map((dm) => dm.id)),
- };
- },
- onSuccess: ({ addedOrChanged, deleted }) => {
- const state = client.getQueryData<DevopsRolesMapping[]>(queryKey);
- if (state) {
- const newData = unionBy(
- addedOrChanged,
- state.filter((s) => deleted.find((id) => id === s.id) === undefined),
- (el) => el.id,
- );
- client.setQueryData(queryKey, newData);
- }
- addGlobalSuccessMessage(
- translate('settings.authentication.gitlab.configuration.roles_mapping.save_success'),
- );
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/identity-provider/scim.ts b/server/sonar-web/src/main/js/queries/identity-provider/scim.ts
deleted file mode 100644
index 423f9b5a022..00000000000
--- a/server/sonar-web/src/main/js/queries/identity-provider/scim.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { useContext } from 'react';
-import { activateScim, deactivateScim, fetchIsScimEnabled } from '../../api/scim-provisioning';
-import { AvailableFeaturesContext } from '../../app/components/available-features/AvailableFeaturesContext';
-import { Feature } from '../../types/features';
-
-export function useScimStatusQuery() {
- const hasScim = useContext(AvailableFeaturesContext).includes(Feature.Scim);
-
- return useQuery({
- queryKey: ['identity_provider', 'scim_status'],
- queryFn: () => {
- if (!hasScim) {
- return false;
- }
- return fetchIsScimEnabled();
- },
- });
-}
-
-export function useToggleScimMutation() {
- const client = useQueryClient();
- return useMutation({
- mutationFn: (activate: boolean) => (activate ? activateScim() : deactivateScim()),
- onSuccess: () => {
- client.invalidateQueries({ queryKey: ['identity_provider'] });
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/import-projects.ts b/server/sonar-web/src/main/js/queries/import-projects.ts
deleted file mode 100644
index 9919446ef81..00000000000
--- a/server/sonar-web/src/main/js/queries/import-projects.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useIsMutating, useMutation } from '@tanstack/react-query';
-import {
- importAzureRepository,
- importBitbucketCloudRepository,
- importBitbucketServerProject,
- importGithubRepository,
- importGitlabProject,
-} from '../api/alm-integrations';
-import { createBoundProject } from '../api/dop-translation';
-import { createProject } from '../api/project-management';
-import { ImportProjectParam } from '../apps/create/project/CreateProjectPage';
-import { CreateProjectModes } from '../apps/create/project/types';
-
-export type MutationArg<AlmImport extends ImportProjectParam = ImportProjectParam> =
- AlmImport extends {
- almSetting: string;
- creationMode: infer A;
- monorepo: false;
- projects: (infer R)[];
- }
- ? { almSetting: string; creationMode: A; monorepo: false } & R
- :
- | {
- creationMode: CreateProjectModes.Manual;
- mainBranch: string;
- monorepo: false;
- name: string;
- project: string;
- }
- | {
- creationMode: CreateProjectModes;
- devOpsPlatformSettingId: string;
- monorepo: true;
- projectKey: string;
- projectName: string;
- repositoryIdentifier: string;
- };
-
-export function useImportProjectMutation() {
- return useMutation({
- mutationFn: (
- data: {
- newCodeDefinitionType?: string;
- newCodeDefinitionValue?: string;
- } & MutationArg,
- ) => {
- if (data.monorepo === true) {
- return createBoundProject(data);
- }
-
- switch (data.creationMode) {
- case CreateProjectModes.GitHub:
- return importGithubRepository(data);
- case CreateProjectModes.AzureDevOps:
- return importAzureRepository(data);
- case CreateProjectModes.BitbucketCloud:
- return importBitbucketCloudRepository(data);
- case CreateProjectModes.BitbucketServer:
- return importBitbucketServerProject(data);
- case CreateProjectModes.GitLab:
- return importGitlabProject(data);
- }
-
- return createProject(data);
- },
- mutationKey: ['import'],
- });
-}
-
-export function useImportProjectProgress() {
- return useIsMutating({ mutationKey: ['import'] });
-}
diff --git a/server/sonar-web/src/main/js/queries/issues.ts b/server/sonar-web/src/main/js/queries/issues.ts
deleted file mode 100644
index ceda4430021..00000000000
--- a/server/sonar-web/src/main/js/queries/issues.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { QueryClient, queryOptions, useMutation, useQueryClient } from '@tanstack/react-query';
-import { addIssueComment, getIssueChangelog, setIssueTransition } from '../api/issues';
-import { createQueryHook } from './common';
-
-const issuesQuery = {
- changelog: (issueKey: string) => ['issue', issueKey, 'changelog'] as const,
-};
-
-export const useIssueChangelogQuery = createQueryHook((issueKey: string) => {
- return queryOptions({
- queryKey: issuesQuery.changelog(issueKey),
- queryFn: () => getIssueChangelog(issueKey),
- });
-});
-
-export function useIssueTransitionMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: (data: { issue: string; transition: string }) => setIssueTransition(data),
- onSuccess: ({ issue }) => {
- invalidateIssueChangelog(issue.key, queryClient);
- },
- });
-}
-
-export function useIssueCommentMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: (data: { issue: string; text: string }) => addIssueComment(data),
- onSuccess: ({ issue }) => {
- invalidateIssueChangelog(issue.key, queryClient);
- },
- });
-}
-
-function invalidateIssueChangelog(issueKey: string, queryClient: QueryClient) {
- queryClient.invalidateQueries({ queryKey: issuesQuery.changelog(issueKey) });
-}
diff --git a/server/sonar-web/src/main/js/queries/measures.ts b/server/sonar-web/src/main/js/queries/measures.ts
deleted file mode 100644
index 5ff455ad7f8..00000000000
--- a/server/sonar-web/src/main/js/queries/measures.ts
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- infiniteQueryOptions,
- Query,
- QueryClient,
- queryOptions,
- useQueries,
- useQueryClient,
-} from '@tanstack/react-query';
-import { chunk, groupBy, isUndefined, omitBy } from 'lodash';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import { getComponentTree } from '../api/components';
-import {
- getMeasures,
- getMeasuresForProjects,
- getMeasuresWithPeriodAndMetrics,
-} from '../api/measures';
-import { getAllTimeMachineData } from '../api/time-machine';
-import { getNextPageParam, getPreviousPageParam } from '../helpers/react-query';
-import { getBranchLikeQuery } from '../sonar-aligned/helpers/branch-like';
-import { BranchLike } from '../types/branch-like';
-import { Measure } from '../types/types';
-import { createInfiniteQueryHook, createQueryHook, StaleTime } from './common';
-import { PROJECTS_PAGE_SIZE } from './projects';
-
-const measureQueryKeys = {
- all: () => ['measures'] as const,
- history: (componentKey: string) => [...measureQueryKeys.all(), 'history', componentKey] as const,
- component: (componentKey: string) =>
- [...measureQueryKeys.all(), 'component', componentKey] as const,
- details: (componentKey: string) => [...measureQueryKeys.all(), 'details', componentKey] as const,
- list: (componentKey: string) => [...measureQueryKeys.all(), 'list', componentKey] as const,
-};
-
-const projectsListPredicate = (query: Query, componentKey: string) =>
- query.queryKey[0] === 'measures' &&
- query.queryKey[1] === 'list' &&
- query.queryKey[2] === 'projects' &&
- Array.isArray(query.queryKey[3]) &&
- query.queryKey[3].includes(componentKey);
-
-export const invalidateMeasuresByComponentKey = (
- componentKey: string,
- queryClient: QueryClient,
-) => {
- queryClient.invalidateQueries({ queryKey: measureQueryKeys.history(componentKey) });
- queryClient.invalidateQueries({ queryKey: measureQueryKeys.component(componentKey) });
- queryClient.invalidateQueries({ queryKey: measureQueryKeys.details(componentKey) });
- queryClient.invalidateQueries({ queryKey: measureQueryKeys.list(componentKey) });
- queryClient.invalidateQueries({
- predicate: (query) => projectsListPredicate(query, componentKey),
- });
-};
-
-export const removeMeasuresByComponentKey = (componentKey: string, queryClient: QueryClient) => {
- queryClient.removeQueries({ queryKey: measureQueryKeys.history(componentKey) });
- queryClient.removeQueries({ queryKey: measureQueryKeys.component(componentKey) });
- queryClient.removeQueries({ queryKey: measureQueryKeys.details(componentKey) });
- queryClient.removeQueries({ queryKey: measureQueryKeys.list(componentKey) });
- queryClient.removeQueries({
- predicate: (query) => projectsListPredicate(query, componentKey),
- });
-};
-
-export const invalidateAllMeasures = (queryClient: QueryClient) => {
- queryClient.invalidateQueries({ queryKey: ['measures'] });
-};
-
-export const useAllMeasuresHistoryQuery = createQueryHook(
- ({
- component,
- branchParams,
- metrics,
- }: Omit<Parameters<typeof getAllTimeMachineData>[0], 'to' | 'from' | 'p'> & {
- branchParams?: BranchParameters;
- }) => {
- return queryOptions({
- queryKey: ['measures', 'history', component, branchParams, metrics],
- queryFn: () => {
- if (metrics.length <= 0) {
- return Promise.resolve({
- measures: [],
- paging: { pageIndex: 1, pageSize: 1, total: 0 },
- });
- }
- return getAllTimeMachineData({ component, metrics, ...branchParams, p: 1 });
- },
- });
- },
-);
-
-export const useMeasuresComponentQuery = createQueryHook(
- ({
- componentKey,
- metricKeys,
- branchLike,
- }: {
- branchLike?: BranchLike;
- componentKey: string;
- metricKeys: string[];
- }) => {
- const queryClient = useQueryClient();
- const branchLikeQuery = getBranchLikeQuery(branchLike);
-
- return queryOptions({
- queryKey: [
- 'measures',
- 'component',
- componentKey,
- 'branchLike',
- { ...branchLikeQuery },
- metricKeys,
- ],
- queryFn: async () => {
- const data = await getMeasuresWithPeriodAndMetrics(
- componentKey,
- metricKeys,
- branchLikeQuery,
- );
- metricKeys.forEach((metricKey) => {
- const measure =
- data.component.measures?.find((measure) => measure.metric === metricKey) ?? null;
- queryClient.setQueryData<Measure | null>(
- ['measures', 'details', componentKey, 'branchLike', { ...branchLikeQuery }, metricKey],
- measure,
- );
- });
-
- return data;
- },
- });
- },
-);
-
-export const useComponentTreeQuery = createInfiniteQueryHook(
- ({
- strategy,
- component,
- metrics,
- additionalData,
- }: {
- additionalData: Parameters<typeof getComponentTree>[3];
- component: Parameters<typeof getComponentTree>[1];
- metrics: Parameters<typeof getComponentTree>[2];
- strategy: 'children' | 'leaves';
- }) => {
- const branchLikeQuery = omitBy(
- {
- branch: additionalData?.branch,
- pullRequest: additionalData?.pullRequest,
- },
- isUndefined,
- );
-
- const queryClient = useQueryClient();
- return infiniteQueryOptions({
- queryKey: ['measures', 'component', component, 'tree', strategy, { metrics, additionalData }],
- queryFn: async ({ pageParam }) => {
- const result = await getComponentTree(strategy, component, metrics, {
- ...additionalData,
- p: pageParam,
- ...branchLikeQuery,
- });
-
- if (result.baseComponent.measures && result.baseComponent.measures.length > 0) {
- const measuresMapByMetricKeyForBaseComponent = groupBy(
- result.baseComponent.measures,
- 'metric',
- );
- metrics?.forEach((metricKey) => {
- const measure = measuresMapByMetricKeyForBaseComponent[metricKey]?.[0] ?? null;
- queryClient.setQueryData<Measure>(
- [
- 'measures',
- 'details',
- result.baseComponent.key,
- 'branchLike',
- { ...branchLikeQuery },
- metricKey,
- ],
- measure,
- );
- });
- }
-
- result.components.forEach((childComponent) => {
- const measuresMapByMetricKeyForChildComponent = groupBy(
- childComponent.measures,
- 'metric',
- );
-
- metrics?.forEach((metricKey) => {
- const measure = measuresMapByMetricKeyForChildComponent[metricKey]?.[0] ?? null;
- queryClient.setQueryData<Measure>(
- [
- 'measures',
- 'details',
- childComponent.key,
- 'branchLike',
- { ...branchLikeQuery },
- metricKey,
- ],
- measure,
- );
- });
- });
- return result;
- },
- getNextPageParam: (data) => getNextPageParam({ page: data.paging }),
- getPreviousPageParam: (data) => getPreviousPageParam({ page: data.paging }),
- initialPageParam: 1,
- staleTime: 60_000,
- });
- },
-);
-
-export function useMeasuresForProjectsQuery({
- projectKeys,
- metricKeys,
-}: {
- metricKeys: string[];
- projectKeys: string[];
-}) {
- const queryClient = useQueryClient();
- return useQueries({
- queries: chunk(projectKeys, PROJECTS_PAGE_SIZE).map((projectsChunk) =>
- queryOptions({
- queryKey: ['measures', 'list', 'projects', projectsChunk, metricKeys],
- staleTime: StaleTime.SHORT,
- queryFn: async () => {
- const measures = await getMeasuresForProjects(projectsChunk, metricKeys);
- const measuresMapByProjectKey = groupBy(measures, 'component');
- projectsChunk.forEach((projectKey) => {
- const measuresForProject = measuresMapByProjectKey[projectKey] ?? [];
- const measuresMapByMetricKey = groupBy(measuresForProject, 'metric');
- metricKeys.forEach((metricKey) => {
- const measure = measuresMapByMetricKey[metricKey]?.[0] ?? null;
- queryClient.setQueryData<Measure>(
- ['measures', 'details', projectKey, 'branchLike', {}, metricKey],
- measure,
- );
- });
- });
- return measures;
- },
- }),
- ),
- });
-}
-
-export const useMeasuresAndLeakQuery = createQueryHook(
- ({
- componentKey,
- metricKeys,
- branchLike,
- }: {
- branchLike?: BranchLike;
- componentKey: string;
- metricKeys: string[];
- }) => {
- const queryClient = useQueryClient();
- const branchParameters = getBranchLikeQuery(branchLike);
- return queryOptions({
- queryKey: [
- 'measures',
- 'details',
- componentKey,
- 'branchLike',
- { ...branchParameters },
- metricKeys,
- ],
- queryFn: async () => {
- const { component, metrics, period } = await getMeasuresWithPeriodAndMetrics(
- componentKey,
- metricKeys,
- branchParameters,
- );
- const measuresMapByMetricKey = groupBy(component.measures, 'metric');
- metricKeys.forEach((metricKey) => {
- const measure = measuresMapByMetricKey[metricKey]?.[0] ?? null;
- queryClient.setQueryData<Measure>(
- ['measures', 'details', componentKey, 'branchLike', { ...branchParameters }, metricKey],
- measure,
- );
- });
- return { component, metrics, period };
- },
- });
- },
-);
-
-export const useMeasureQuery = createQueryHook(
- ({
- componentKey,
- metricKey,
- branchLike,
- }: {
- branchLike?: BranchLike;
- componentKey: string;
- metricKey: string;
- }) => {
- const branchLikeQuery = getBranchLikeQuery(branchLike);
-
- return queryOptions({
- queryKey: [
- 'measures',
- 'details',
- componentKey,
- 'branchLike',
- { ...branchLikeQuery },
- metricKey,
- ],
- queryFn: () =>
- getMeasures({ component: componentKey, metricKeys: metricKey }).then(
- (measures) => measures[0] ?? null,
- ),
- staleTime: Infinity,
- });
- },
-);
-
-export const useMeasuresQuery = createQueryHook(
- ({
- componentKey,
- metricKeys,
- branchLike,
- }: {
- branchLike?: BranchLike;
- componentKey: string;
- metricKeys: string;
- }) => {
- const queryClient = useQueryClient();
- const branchLikeQuery = getBranchLikeQuery(branchLike);
-
- return queryOptions({
- queryKey: [
- 'measures',
- 'list',
- componentKey,
- 'branchLike',
- { ...branchLikeQuery },
- metricKeys,
- ],
- queryFn: async () => {
- const measures = await getMeasures({
- component: componentKey,
- metricKeys,
- });
-
- const measuresMapByMetricKey = groupBy(measures, 'metric');
- metricKeys.split(',').forEach((metricKey) => {
- const measure = measuresMapByMetricKey[metricKey]?.[0] ?? null;
- queryClient.setQueryData<Measure>(
- ['measures', 'details', componentKey, 'branchLike', { ...branchLikeQuery }, metricKey],
- measure,
- );
- });
- return measures;
- },
- });
- },
-);
diff --git a/server/sonar-web/src/main/js/queries/mode.ts b/server/sonar-web/src/main/js/queries/mode.ts
deleted file mode 100644
index 37aa45804eb..00000000000
--- a/server/sonar-web/src/main/js/queries/mode.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useMutation, useQueryClient } from '@tanstack/react-query';
-import { useIntl } from 'react-intl';
-import { addGlobalSuccessMessage } from '~design-system';
-import { getMode, updateMode } from '../api/mode';
-import { Mode, ModeResponse } from '../types/mode';
-import { createQueryHook } from './common';
-
-const useModeQuery = createQueryHook(() => {
- return queryOptions({
- queryKey: ['mode'] as const,
- queryFn: getMode,
- staleTime: Infinity,
- });
-});
-
-export const useStandardExperienceModeQuery = ({ enabled }: { enabled?: boolean } = {}) => {
- return useModeQuery({ select: (data) => data.mode === Mode.Standard, enabled });
-};
-
-export const useModeModifiedQuery = () => {
- return useModeQuery({ select: (data) => data.modified });
-};
-
-export function useUpdateModeMutation() {
- const queryClient = useQueryClient();
- const intl = useIntl();
- return useMutation({
- mutationFn: (mode: Mode) => updateMode(mode),
- onSuccess: (res) => {
- // This can have a broader side effect on the backend
- // Let's remove all frontend cache.
- queryClient.invalidateQueries();
- queryClient.setQueryData<ModeResponse>(['mode'], res);
-
- addGlobalSuccessMessage(
- intl.formatMessage(
- {
- id: 'settings.mode.save.success',
- },
- { isStandardMode: res.mode === Mode.Standard },
- ),
- );
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/newCodeDefinition.ts b/server/sonar-web/src/main/js/queries/newCodeDefinition.ts
deleted file mode 100644
index 81941f47a21..00000000000
--- a/server/sonar-web/src/main/js/queries/newCodeDefinition.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-// React-query component for new code definition
-
-import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import {
- getNewCodeDefinition,
- resetNewCodeDefinition,
- setNewCodeDefinition,
-} from '../api/newCodeDefinition';
-import { NewCodeDefinitionType } from '../types/new-code-definition';
-
-function getNewCodeDefinitionQueryKey(projectKey?: string, branchName?: string) {
- return ['new-code-definition', { projectKey, branchName }];
-}
-
-export function useNewCodeDefinitionQuery(params?: {
- branchName?: string;
- enabled?: boolean;
- projectKey?: string;
-}) {
- return useQuery({
- queryKey: getNewCodeDefinitionQueryKey(params?.projectKey, params?.branchName),
- queryFn: () =>
- getNewCodeDefinition({ branch: params?.branchName, project: params?.projectKey }),
- enabled: params?.enabled ?? true,
- refetchOnWindowFocus: false,
- });
-}
-
-export function useNewCodeDefinitionMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (newCodeDefinition: {
- branch?: string;
- project?: string;
- type?: NewCodeDefinitionType;
- value?: string;
- }) => {
- const { branch, project, type, value } = newCodeDefinition;
-
- if (type === undefined) {
- return resetNewCodeDefinition({
- branch,
- project,
- });
- }
-
- return setNewCodeDefinition({ branch, project, type, value });
- },
- onSuccess(_, { branch, project }) {
- queryClient.invalidateQueries({
- queryKey: getNewCodeDefinitionQueryKey(project, branch),
- });
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/notifications.ts b/server/sonar-web/src/main/js/queries/notifications.ts
deleted file mode 100644
index 8fc7ef935c2..00000000000
--- a/server/sonar-web/src/main/js/queries/notifications.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useMutation, useQueryClient } from '@tanstack/react-query';
-import { uniqWith } from 'lodash';
-import { addNotification, getNotifications, removeNotification } from '../api/notifications';
-import { Notification } from '../types/notifications';
-import { createQueryHook, StaleTime } from './common';
-
-const KEY_PREFIX = 'notifications';
-
-const notificationQuery = queryOptions({
- queryKey: [KEY_PREFIX],
- queryFn: () => getNotifications(),
- staleTime: StaleTime.NEVER,
-});
-
-function areNotificationsEqual(a: Notification, b: Notification) {
- return a.channel === b.channel && a.type === b.type && a.project === b.project;
-}
-
-export const useNotificationsQuery = createQueryHook(() => notificationQuery);
-
-export function useAddNotificationMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: addNotification,
- onSuccess: (_, { channel, type, project }) => {
- queryClient.setQueryData(notificationQuery.queryKey, (previous) => {
- if (previous === undefined) {
- return previous;
- }
- return {
- ...previous,
- notifications: uniqWith(
- [...previous.notifications, { channel, type, project }],
- areNotificationsEqual,
- ),
- };
- });
- queryClient.invalidateQueries({ queryKey: [KEY_PREFIX] });
- },
- });
-}
-
-export function useRemoveNotificationMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: removeNotification,
- onSuccess: (_, removed) => {
- queryClient.setQueryData(notificationQuery.queryKey, (previous) => {
- if (previous === undefined) {
- return previous;
- }
- return {
- ...previous,
- notifications: previous.notifications.filter(
- (notification) => !areNotificationsEqual(notification, removed),
- ),
- };
- });
- queryClient.invalidateQueries({ queryKey: [KEY_PREFIX] });
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/portfolios.ts b/server/sonar-web/src/main/js/queries/portfolios.ts
deleted file mode 100644
index 553f805df8f..00000000000
--- a/server/sonar-web/src/main/js/queries/portfolios.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useMutation, useQueryClient } from '@tanstack/react-query';
-import { deletePortfolio } from '../api/project-management';
-import { invalidateMeasuresByComponentKey } from './measures';
-
-export function useDeletePortfolioMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: (key: string) => deletePortfolio(key),
- onSuccess: (_, key) => {
- invalidateMeasuresByComponentKey(key, queryClient);
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/project-analyses.ts b/server/sonar-web/src/main/js/queries/project-analyses.ts
deleted file mode 100644
index c7edf3eb132..00000000000
--- a/server/sonar-web/src/main/js/queries/project-analyses.ts
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useMutation, useQueryClient } from '@tanstack/react-query';
-import { getBranchLikeQuery } from '~sonar-aligned/helpers/branch-like';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import {
- CreateEventResponse,
- ProjectActivityStatuses,
- changeEvent,
- createEvent,
- deleteAnalysis,
- deleteEvent,
- getAllTimeProjectActivity,
-} from '../api/projectActivity';
-import {
- useComponent,
- useTopLevelComponentKey,
-} from '../app/components/componentContext/withComponentContext';
-import { parseDate } from '../helpers/dates';
-import { serializeStringArray } from '../helpers/query';
-import { ParsedAnalysis } from '../types/project-activity';
-import { useCurrentBranchQuery } from './branch';
-import { createQueryHook } from './common';
-
-const ACTIVITY_PAGE_SIZE = 500;
-
-function useProjectActivityQueryKey() {
- const { component } = useComponent();
- const componentKey = useTopLevelComponentKey();
- const { data: branchLike } = useCurrentBranchQuery(component);
- const branchParams = getBranchLikeQuery(branchLike);
-
- return ['activity', 'list', componentKey, branchParams] as [
- string,
- string,
- string | undefined,
- BranchParameters,
- ];
-}
-
-export const useAllProjectAnalysesQuery = createQueryHook(() => {
- const queryKey = useProjectActivityQueryKey();
-
- return queryOptions({
- queryKey,
- queryFn: ({ queryKey: [_0, _1, project, branchParams] }) =>
- getAllTimeProjectActivity({
- ...branchParams,
- project,
- statuses: serializeStringArray([
- ProjectActivityStatuses.STATUS_PROCESSED,
- ProjectActivityStatuses.STATUS_LIVE_MEASURE_COMPUTE,
- ]),
- p: 1,
- ps: ACTIVITY_PAGE_SIZE,
- }).then(({ analyses }) =>
- analyses.map((analysis) => ({
- ...analysis,
- date: parseDate(analysis.date),
- })),
- ),
- });
-});
-
-export function useDeleteAnalysisMutation(successCb?: () => void) {
- const queryClient = useQueryClient();
- const queryKey = useProjectActivityQueryKey();
-
- return useMutation({
- mutationFn: (analysis: string) => deleteAnalysis(analysis),
- onSuccess: (_, analysis) => {
- queryClient.setQueryData(queryKey, (oldData: ParsedAnalysis[]) =>
- oldData.filter((a) => a.key !== analysis),
- );
- queryClient.invalidateQueries({ queryKey: ['measures', 'history', queryKey[2]] });
- successCb?.();
- },
- });
-}
-
-export function useCreateEventMutation(successCb?: () => void) {
- const queryClient = useQueryClient();
- const queryKey = useProjectActivityQueryKey();
-
- return useMutation({
- mutationFn: (data: Parameters<typeof createEvent>[0]) => createEvent(data),
- onSuccess: (event) => {
- queryClient.setQueryData(queryKey, (oldData: ParsedAnalysis[]) => {
- return oldData.map((analysis) => {
- if (analysis.key !== event.analysis) {
- return analysis;
- }
- return { ...analysis, events: [...analysis.events, event] };
- });
- });
- successCb?.();
- },
- });
-}
-
-export function useChangeEventMutation(successCb?: () => void) {
- const queryClient = useQueryClient();
- const queryKey = useProjectActivityQueryKey();
-
- return useMutation({
- mutationFn: (data: Parameters<typeof changeEvent>[0]) => changeEvent(data),
- onSuccess: (event) => {
- queryClient.setQueryData(queryKey, updateQueryDataOnChangeEvent(event));
- successCb?.();
- },
- });
-}
-
-const updateQueryDataOnChangeEvent =
- (event: CreateEventResponse) => (oldData: ParsedAnalysis[]) => {
- return oldData.map((a) => {
- if (a.key !== event.analysis) {
- return a;
- }
- return {
- ...a,
- events: a.events.map((e) => (e.key === event.key ? event : e)),
- };
- });
- };
-
-export function useDeleteEventMutation(successCb?: () => void) {
- const queryClient = useQueryClient();
- const queryKey = useProjectActivityQueryKey();
-
- return useMutation({
- mutationFn: ({ event }: { analysis: string; event: string }) => deleteEvent(event),
- onSuccess: (_, variables) => {
- queryClient.setQueryData(queryKey, updateQueryDataOnDeleteEvent(variables));
- successCb?.();
- },
- });
-}
-
-const updateQueryDataOnDeleteEvent =
- ({ analysis, event }: { analysis: string; event: string }) =>
- (oldData: ParsedAnalysis[]) => {
- return oldData.map((a) => {
- if (a.key !== analysis) {
- return a;
- }
- return {
- ...a,
- events: a.events.filter((ev) => ev.key !== event),
- };
- });
- };
diff --git a/server/sonar-web/src/main/js/queries/project-dump.ts b/server/sonar-web/src/main/js/queries/project-dump.ts
deleted file mode 100644
index c9a17ef0cbc..00000000000
--- a/server/sonar-web/src/main/js/queries/project-dump.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useMutation } from '@tanstack/react-query';
-import { doExport, doImport, getStatus } from '../api/project-dump';
-import { createQueryHook } from './common';
-
-export const useProjectDumpStatusQuery = createQueryHook((componentKey: string) => {
- return queryOptions({
- queryKey: ['project-dump', componentKey],
- queryFn: () => getStatus(componentKey),
- });
-});
-
-export const useProjectExportMutation = () =>
- useMutation({
- mutationFn: (componentKey: string) => doExport(componentKey),
- });
-
-export const useProjectImportMutation = () =>
- useMutation({
- mutationFn: (componentKey: string) => doImport(componentKey),
- });
diff --git a/server/sonar-web/src/main/js/queries/projects.ts b/server/sonar-web/src/main/js/queries/projects.ts
deleted file mode 100644
index a24dcc4395d..00000000000
--- a/server/sonar-web/src/main/js/queries/projects.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- infiniteQueryOptions,
- QueryClient,
- queryOptions,
- useMutation,
- useQueryClient,
-} from '@tanstack/react-query';
-import { getScannableProjects, searchProjects } from '../api/components';
-import { deleteProject } from '../api/project-management';
-import { Query } from '../apps/projects/query';
-import { convertToQueryData, defineFacets } from '../apps/projects/utils';
-import { getNextPagingParam } from '../helpers/react-query';
-import { RequestData } from '../helpers/request';
-import { createInfiniteQueryHook, createQueryHook, StaleTime } from './common';
-import { removeMeasuresByComponentKey } from './measures';
-
-export const PROJECTS_PAGE_SIZE = 50;
-
-export const projectsQueryKeys = {
- all: () => ['project'] as const,
- allList: () => [...projectsQueryKeys.all(), 'list'] as const,
- list: (data?: RequestData) => [...projectsQueryKeys.allList(), data] as const,
- details: (key: string) => [...projectsQueryKeys.all(), 'details', key] as const,
- scannable: () => [...projectsQueryKeys.all(), 'my-scannable'] as const,
-};
-
-export const useProjectsQuery = createInfiniteQueryHook(
- ({
- isFavorite,
- query,
- pageIndex = 1,
- isStandardMode,
- }: {
- isFavorite: boolean;
- isStandardMode: boolean;
- pageIndex?: number;
- query: Query;
- }) => {
- const queryClient = useQueryClient();
- const data = convertToQueryData(query, isFavorite, isStandardMode, {
- ps: PROJECTS_PAGE_SIZE,
- facets: defineFacets(query, isStandardMode).join(),
- f: 'analysisDate,leakPeriodDate',
- });
-
- return infiniteQueryOptions({
- queryKey: projectsQueryKeys.list(data),
- queryFn: ({ pageParam: pageIndex }) => {
- return searchProjects({ ...data, p: pageIndex }).then((response) => {
- response.components.forEach((project) => {
- queryClient.setQueryData(['project', 'details', project.key], project);
- });
- return response;
- });
- },
- staleTime: StaleTime.LONG,
- getNextPageParam: getNextPagingParam,
- getPreviousPageParam: getNextPagingParam,
- initialPageParam: pageIndex,
- });
- },
-);
-
-export const useProjectQuery = createQueryHook((key: string) => {
- return queryOptions({
- queryKey: projectsQueryKeys.details(key),
- queryFn: ({ queryKey: [_1, _2, key] }) => searchProjects({ filter: `query=${key}` }),
- });
-});
-
-export const useMyScannableProjectsQuery = createQueryHook(() => {
- return queryOptions({
- queryKey: projectsQueryKeys.scannable(),
- queryFn: () => getScannableProjects(),
- staleTime: StaleTime.NEVER,
- });
-});
-
-export function useDeleteProjectMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: (key: string) => deleteProject(key),
- onSuccess: (_, key) => {
- resetProjectsListQuery(queryClient);
- removeMeasuresByComponentKey(key, queryClient);
- },
- });
-}
-
-export function invalidateProjectsListQuery(queryClient: QueryClient) {
- queryClient.invalidateQueries({ queryKey: projectsQueryKeys.allList() });
-}
-
-function resetProjectsListQuery(queryClient: QueryClient) {
- queryClient.resetQueries({ queryKey: projectsQueryKeys.allList() });
-}
diff --git a/server/sonar-web/src/main/js/queries/quality-gates.ts b/server/sonar-web/src/main/js/queries/quality-gates.ts
deleted file mode 100644
index f4c5c5838ee..00000000000
--- a/server/sonar-web/src/main/js/queries/quality-gates.ts
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { useIntl } from 'react-intl';
-import { addGlobalSuccessMessage } from '~design-system';
-import { BranchParameters } from '~sonar-aligned/types/branch-like';
-import {
- associateGateWithProject,
- copyQualityGate,
- createCondition,
- createQualityGate,
- deleteCondition,
- deleteQualityGate,
- dissociateGateWithProject,
- fetchQualityGate,
- fetchQualityGates,
- getAllQualityGateProjects,
- getApplicationQualityGate,
- getGateForProject,
- getQualityGateProjectStatus,
- renameQualityGate,
- setQualityGateAiQualified,
- setQualityGateAsDefault,
- updateCondition,
-} from '../api/quality-gates';
-import { getCorrectCaycCondition } from '../apps/quality-gates/utils';
-import { translate } from '../helpers/l10n';
-import { Condition, QualityGate } from '../types/types';
-import { createQueryHook, StaleTime } from './common';
-import { invalidateProjectsListQuery } from './projects';
-
-const QUERY_STALE_TIME = 5 * 60 * 1000;
-
-const qualityQuery = {
- all: () => ['quality-gate'] as const,
- list: () => [...qualityQuery.all(), 'list'] as const,
- details: () => [...qualityQuery.all(), 'details'] as const,
- detail: (name?: string) => [...qualityQuery.details(), name ?? ''] as const,
- projectsAssoc: () => [...qualityQuery.all(), 'project-assoc'] as const,
- projectAssoc: (project: string) => [...qualityQuery.projectsAssoc(), project] as const,
- allProjectsSearch: (qualityGate: string) =>
- [...qualityQuery.all(), 'all-project-search', qualityGate] as const,
-};
-
-// This is internal to "enable" query when searching from the project page
-function useQualityGateQueryInner(name?: string) {
- return useQuery({
- queryKey: qualityQuery.detail(name),
- queryFn: ({ queryKey: [, , name] }) => {
- return fetchQualityGate({ name });
- },
- enabled: name !== undefined,
- staleTime: QUERY_STALE_TIME,
- });
-}
-
-export function useQualityGateQuery(name: string) {
- return useQualityGateQueryInner(name);
-}
-
-export function useQualityGateForProjectQuery(project: string) {
- return useQuery({
- queryKey: qualityQuery.projectAssoc(project),
- queryFn: async ({ queryKey: [, , project] }) => {
- const qualityGatePreview = await getGateForProject({ project });
- return qualityGatePreview.name;
- },
- });
-}
-
-export function useComponentQualityGateQuery(project: string) {
- const { data: name } = useQualityGateForProjectQuery(project);
- return useQualityGateQueryInner(name);
-}
-
-export const useQualityGatesQuery = createQueryHook(() => {
- return queryOptions({
- queryKey: qualityQuery.list(),
- queryFn: () => {
- return fetchQualityGates();
- },
- staleTime: StaleTime.LONG,
- });
-});
-
-export const useGetAllQualityGateProjectsQuery = createQueryHook(
- (data: Parameters<typeof getAllQualityGateProjects>[0]) => {
- return queryOptions({
- queryKey: qualityQuery.allProjectsSearch(data?.gateName ?? ''),
- queryFn: () => {
- return getAllQualityGateProjects(data);
- },
- });
- },
-);
-
-export function useCreateQualityGateMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (name: string) => {
- return createQualityGate({ name });
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: qualityQuery.list() });
- },
- });
-}
-
-export function useSetQualityGateAsDefaultMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (qualityGate: QualityGate) => {
- return setQualityGateAsDefault({ name: qualityGate.name });
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: qualityQuery.list() });
- queryClient.invalidateQueries({ queryKey: qualityQuery.details() });
- },
- });
-}
-
-export function useRenameQualityGateMutation(currentName: string) {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (newName: string) => {
- return renameQualityGate({ currentName, name: newName });
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: qualityQuery.list() });
- queryClient.invalidateQueries({ queryKey: qualityQuery.projectsAssoc() });
- queryClient.removeQueries({ queryKey: qualityQuery.detail(currentName) });
- },
- });
-}
-
-export function useCopyQualityGateMutation(sourceName: string) {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (newName: string) => {
- return copyQualityGate({ sourceName, name: newName });
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: qualityQuery.list() });
- },
- });
-}
-
-export function useDeleteQualityGateMutation(name: string) {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: () => {
- return deleteQualityGate({ name });
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: qualityQuery.list() });
- queryClient.invalidateQueries({ queryKey: qualityQuery.projectsAssoc() });
- queryClient.removeQueries({ queryKey: qualityQuery.detail(name) });
- },
- });
-}
-
-export function useSetAiSupportedQualityGateMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: ({
- name,
- isQualityGateAiSupported,
- }: {
- isQualityGateAiSupported: boolean;
- name: string;
- }) => {
- return setQualityGateAiQualified(name, isQualityGateAiSupported);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: qualityQuery.all() });
- },
- });
-}
-
-export function useAssociateGateWithProjectMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (data: { gateName: string; projectKey: string }) => {
- return associateGateWithProject(data);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: qualityQuery.projectsAssoc() });
- invalidateProjectsListQuery(queryClient);
- },
- });
-}
-
-export function useDissociateGateWithProjectMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (data: { projectKey: string }) => {
- return dissociateGateWithProject(data);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: qualityQuery.projectsAssoc() });
- invalidateProjectsListQuery(queryClient);
- },
- });
-}
-
-export function useFixQualityGateMutation(gateName: string) {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: ({
- weakConditions,
- missingConditions,
- }: {
- missingConditions: Condition[];
- weakConditions: Condition[];
- }) => {
- const promiseArr = weakConditions
- .map((condition) => {
- return updateCondition({
- ...getCorrectCaycCondition(condition),
- id: condition.id,
- });
- })
- .concat(
- missingConditions.map((condition) => {
- return createCondition({
- ...getCorrectCaycCondition(condition),
- gateName,
- });
- }),
- );
-
- return Promise.all(promiseArr);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: qualityQuery.detail(gateName) });
- queryClient.invalidateQueries({ queryKey: qualityQuery.list() });
- addGlobalSuccessMessage(translate('quality_gates.conditions_updated'));
- },
- });
-}
-
-export function useCreateConditionMutation(gateName: string) {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (condition: Omit<Condition, 'id'>) => {
- return createCondition({ ...condition, gateName });
- },
- onSuccess: (_, condition) => {
- queryClient.setQueryData(qualityQuery.detail(gateName), (oldData?: QualityGate) => {
- return oldData?.conditions
- ? {
- ...oldData,
- conditions: [...oldData.conditions, condition],
- }
- : undefined;
- });
- queryClient.invalidateQueries({ queryKey: qualityQuery.detail(gateName) });
- queryClient.invalidateQueries({ queryKey: qualityQuery.list() });
- addGlobalSuccessMessage(translate('quality_gates.condition_added'));
- },
- });
-}
-
-export function useUpdateConditionMutation(gateName: string) {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (condition: Condition) => {
- return updateCondition(condition);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: qualityQuery.list() });
- queryClient.invalidateQueries({ queryKey: qualityQuery.detail(gateName) });
- addGlobalSuccessMessage(translate('quality_gates.condition_updated'));
- },
- });
-}
-
-export function useUpdateOrDeleteConditionsMutation(gateName: string, isSingleMetric = false) {
- const queryClient = useQueryClient();
- const intl = useIntl();
-
- return useMutation({
- mutationFn: (
- conditions: (Omit<Condition, 'metric'> & { metric: string | null | undefined })[],
- ) => {
- const promiseArr = conditions.map((condition) =>
- condition.metric
- ? updateCondition(condition as Condition)
- : deleteCondition({ id: condition.id }),
- );
-
- return Promise.all(promiseArr);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: qualityQuery.list() });
- queryClient.invalidateQueries({ queryKey: qualityQuery.detail(gateName) });
- addGlobalSuccessMessage(
- intl.formatMessage(
- {
- id: isSingleMetric
- ? 'quality_gates.condition_updated'
- : 'quality_gates.conditions_updated_to_the_mode',
- },
- { qualityGateName: gateName },
- ),
- );
- },
- onError: () => {
- queryClient.invalidateQueries({ queryKey: qualityQuery.detail(gateName) });
- },
- });
-}
-
-export function useDeleteConditionMutation(gateName: string) {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (condition: Condition) => {
- return deleteCondition({
- id: condition.id,
- });
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: qualityQuery.list() });
- queryClient.invalidateQueries({ queryKey: qualityQuery.detail(gateName) });
- addGlobalSuccessMessage(translate('quality_gates.condition_deleted'));
- },
- });
-}
-
-export const useProjectQualityGateStatus = createQueryHook(
- ({
- projectId,
- projectKey,
- branchParameters,
- }: {
- branchParameters?: BranchParameters;
- projectId?: string;
- projectKey?: string;
- }) => {
- return queryOptions({
- queryKey: ['quality-gate', 'status', 'project', projectId, projectKey, branchParameters],
- queryFn: () => getQualityGateProjectStatus({ projectId, projectKey, ...branchParameters }),
- });
- },
-);
-
-export const useApplicationQualityGateStatus = createQueryHook(
- ({ application, branch }: { application: string; branch?: string }) => {
- return queryOptions({
- queryKey: ['quality-gate', 'status', 'application', application, branch],
- queryFn: () => getApplicationQualityGate({ application, branch }),
- });
- },
-);
-
-/**
- * @deprecated This is only for component that has not been migrated to react-query
- */
-export function useInvalidateQualityGateQuery() {
- const queryClient = useQueryClient();
- return () => {
- queryClient.invalidateQueries({ queryKey: qualityQuery.all() });
- };
-}
diff --git a/server/sonar-web/src/main/js/queries/quality-profiles.ts b/server/sonar-web/src/main/js/queries/quality-profiles.ts
deleted file mode 100644
index a50032a8af7..00000000000
--- a/server/sonar-web/src/main/js/queries/quality-profiles.ts
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- infiniteQueryOptions,
- queryOptions,
- useMutation,
- useQuery,
- useQueryClient,
-} from '@tanstack/react-query';
-import {
- ActivateRuleParameters,
- AddRemoveGroupParameters,
- AddRemoveUserParameters,
- DeactivateRuleParameters,
- Profile,
- activateRule,
- addGroup,
- addUser,
- compareProfiles,
- deactivateRule,
- getProfileChangelog,
- getProfileInheritance,
- getQualityProfile,
-} from '../api/quality-profiles';
-import { getNextPageParam, getPreviousPageParam } from '../helpers/react-query';
-import { isDefined } from '../helpers/types';
-import { QualityProfileChangelogFilterMode } from '../types/quality-profiles';
-import { createInfiniteQueryHook, createQueryHook } from './common';
-
-const qualityProfileQueryKeys = {
- all: () => ['quality-profiles'],
- inheritance: (language?: string, name?: string, parentKey?: string) => [
- ...qualityProfileQueryKeys.all(),
- 'inheritance',
- language,
- name,
- parentKey,
- ],
- profile: (profile: Profile, compareToSonarWay = false) => [
- ...qualityProfileQueryKeys.all(),
- 'details',
- profile,
- compareToSonarWay,
- ],
- changelog: (
- language: string,
- name: string,
- since: string,
- to: string,
- filterMode: QualityProfileChangelogFilterMode,
- ) => [...qualityProfileQueryKeys.all(), 'changelog', language, name, since, to, filterMode],
- compare: (leftKey: string, rightKey: string) => [
- ...qualityProfileQueryKeys.all(),
- 'compare',
- leftKey,
- rightKey,
- ],
-};
-
-export const useProfileInheritanceQuery = createQueryHook(
- (profile?: Pick<Profile, 'language' | 'name' | 'parentKey'>) => {
- const { language, name, parentKey } = profile ?? {};
- return queryOptions({
- queryKey: qualityProfileQueryKeys.inheritance(language, name, parentKey),
- queryFn: () => {
- if (!isDefined(language) || !isDefined(name)) {
- return { ancestors: [], children: [], profile: null };
- }
- return getProfileInheritance({ language, name });
- },
- });
- },
-);
-
-export const useGetQualityProfile = createQueryHook(
- (data: Parameters<typeof getQualityProfile>[0]) => {
- return queryOptions({
- queryKey: qualityProfileQueryKeys.profile(data.profile, data.compareToSonarWay),
- queryFn: () => {
- return getQualityProfile(data);
- },
- });
- },
-);
-
-export const useGetQualityProfileChangelog = createInfiniteQueryHook(
- (data: Parameters<typeof getProfileChangelog>[0]) => {
- return infiniteQueryOptions({
- queryKey: qualityProfileQueryKeys.changelog(
- data.profile.language,
- data.profile.name,
- data.since,
- data.to,
- data.filterMode,
- ),
- queryFn: ({ pageParam }) => {
- return getProfileChangelog({ ...data, page: pageParam });
- },
- getNextPageParam: (data) => getNextPageParam({ page: data.paging }),
- getPreviousPageParam: (data) => getPreviousPageParam({ page: data.paging }),
- initialPageParam: 1,
- });
- },
-);
-
-export function useProfilesCompareQuery(leftKey: string, rightKey: string) {
- return useQuery({
- queryKey: qualityProfileQueryKeys.compare(leftKey, rightKey),
- queryFn: ({ queryKey: [_1, _2, leftKey, rightKey] }) => {
- if (!isDefined(leftKey) || !isDefined(rightKey)) {
- return null;
- }
-
- return compareProfiles(leftKey, rightKey);
- },
- });
-}
-
-export function useActivateRuleMutation(onSuccess: (data: ActivateRuleParameters) => unknown) {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: activateRule,
- onSuccess: (_, data) => {
- queryClient.invalidateQueries({ queryKey: ['rules', 'details', data.rule] });
- onSuccess(data);
- },
- });
-}
-
-export function useDeactivateRuleMutation(onSuccess: (data: DeactivateRuleParameters) => unknown) {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: deactivateRule,
- onSuccess: (_, data) => {
- queryClient.invalidateQueries({ queryKey: ['rules', 'details', data.rule] });
- onSuccess(data);
- },
- });
-}
-
-export function useAddUserMutation(onSuccess: () => unknown) {
- return useMutation({
- mutationFn: (data: AddRemoveUserParameters) => addUser(data),
- onSuccess,
- });
-}
-
-export function useAddGroupMutation(onSuccess: () => unknown) {
- return useMutation({
- mutationFn: (data: AddRemoveGroupParameters) => addGroup(data),
- onSuccess,
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/queryClient.ts b/server/sonar-web/src/main/js/queries/queryClient.ts
deleted file mode 100644
index 96dbef139d2..00000000000
--- a/server/sonar-web/src/main/js/queries/queryClient.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { QueryClient, QueryOptions } from '@tanstack/react-query';
-
-export const queryClientDefaultRetryFn: QueryOptions['retry'] = (failureCount, error) => {
- if (typeof error === 'object' && error !== null && 'status' in error) {
- const { status } = error as unknown as Response;
-
- if (status >= 400 && status < 500) {
- // no point in retrying on 4xx errors
- return false;
- }
- }
-
- return failureCount < 2;
-};
-
-export const queryClient = new QueryClient({
- defaultOptions: {
- queries: {
- retry: queryClientDefaultRetryFn,
- },
- },
-});
diff --git a/server/sonar-web/src/main/js/queries/rules.ts b/server/sonar-web/src/main/js/queries/rules.ts
deleted file mode 100644
index 8a3bd00a07a..00000000000
--- a/server/sonar-web/src/main/js/queries/rules.ts
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useMutation, useQueryClient } from '@tanstack/react-query';
-import { createRule, deleteRule, getRuleDetails, searchRules, updateRule } from '../api/rules';
-import { mapRestRuleToRule } from '../apps/coding-rules/utils';
-import { SearchRulesResponse } from '../types/coding-rules';
-import { SearchRulesQuery } from '../types/rules';
-import { RuleActivation, RuleDetails } from '../types/types';
-import { createQueryHook, StaleTime } from './common';
-
-function getRulesQueryKey(type: 'search' | 'details', data?: SearchRulesQuery | string) {
- const key = ['rules', type] as (string | SearchRulesQuery)[];
- if (data) {
- key.push(data);
- }
- return key;
-}
-
-export const useSearchRulesQuery = createQueryHook((data: SearchRulesQuery) => {
- return queryOptions({
- queryKey: getRulesQueryKey('search', data),
- queryFn: ({ queryKey: [, , query] }) => {
- if (!query) {
- return null;
- }
-
- return searchRules(data);
- },
- staleTime: StaleTime.NEVER,
- });
-});
-
-export const useRuleDetailsQuery = createQueryHook((data: { actives?: boolean; key: string }) => {
- return queryOptions({
- queryKey: getRulesQueryKey('details', data.key),
- queryFn: () => getRuleDetails(data),
- staleTime: StaleTime.NEVER,
- });
-});
-
-export function useCreateRuleMutation(
- searchQuery?: SearchRulesQuery,
- onSuccess?: (rule: RuleDetails) => unknown,
- onError?: (error: Response) => unknown,
-) {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: createRule,
- onError,
- onSuccess: (rule) => {
- const mappedRule = mapRestRuleToRule(rule);
- onSuccess?.(mappedRule);
- queryClient.setQueryData<SearchRulesResponse>(
- getRulesQueryKey('search', searchQuery),
- (oldData) => {
- return oldData ? { ...oldData, rules: [mappedRule, ...oldData.rules] } : undefined;
- },
- );
- },
- });
-}
-
-export function useUpdateRuleMutation(
- searchQuery?: SearchRulesQuery,
- onSuccess?: (rule: RuleDetails) => unknown,
-) {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: updateRule,
- onSuccess: (rule) => {
- onSuccess?.(rule);
- queryClient.setQueryData<SearchRulesResponse>(
- getRulesQueryKey('search', searchQuery),
- (oldData) => {
- return oldData ? { ...oldData, rules: [rule, ...oldData.rules] } : undefined;
- },
- );
- queryClient.setQueryData<{ actives?: RuleActivation[]; rule: RuleDetails }>(
- getRulesQueryKey('details', rule.key),
- (oldData) => {
- return {
- ...oldData,
- rule,
- };
- },
- );
- },
- });
-}
-
-export function useDeleteRuleMutation(
- searchQuery?: SearchRulesQuery,
- onSuccess?: (key: string) => unknown,
-) {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (params: { key: string }) => deleteRule(params),
- onSuccess: (_, data) => {
- onSuccess?.(data.key);
- queryClient.setQueryData<SearchRulesResponse>(
- getRulesQueryKey('search', searchQuery),
- (oldData) => {
- return oldData
- ? { ...oldData, rules: oldData.rules.filter((rule) => rule.key !== data.key) }
- : undefined;
- },
- );
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/settings.ts b/server/sonar-web/src/main/js/queries/settings.ts
deleted file mode 100644
index 378e325c532..00000000000
--- a/server/sonar-web/src/main/js/queries/settings.ts
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { addGlobalSuccessMessage } from '~design-system';
-import {
- getValue,
- getValues,
- resetSettingValue,
- setSettingValue,
- setSimpleSettingValue,
-} from '../api/settings';
-import { translate } from '../helpers/l10n';
-import { ExtendedSettingDefinition, SettingValue } from '../types/settings';
-import { createQueryHook } from './common';
-import { invalidateAllMeasures } from './measures';
-
-const SETTINGS_SAVE_SUCCESS_MESSAGE = translate(
- 'settings.authentication.form.settings.save_success',
-);
-
-type SettingFinalValue = string | boolean | string[];
-
-export function useGetValuesQuery(keys: string[]) {
- return useQuery({
- queryKey: ['settings', 'values', keys] as const,
- queryFn: ({ queryKey: [_a, _b, keys] }) => {
- return getValues({ keys });
- },
- });
-}
-
-export const useGetValueQuery = createQueryHook(
- ({ key, component }: { component?: string; key: string }) => {
- return queryOptions({
- queryKey: ['settings', 'details', key] as const,
- queryFn: ({ queryKey: [_a, _b, key] }) => {
- return getValue({ key, component }).then((v) => v ?? null);
- },
- });
- },
-);
-
-export function useResetSettingsMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: ({ keys, component }: { component?: string; keys: string[] }) =>
- resetSettingValue({ keys: keys.join(','), component }),
- onSuccess: (_, { keys }) => {
- keys.forEach((key) => {
- queryClient.invalidateQueries({ queryKey: ['settings', 'details', key] });
- });
- queryClient.invalidateQueries({ queryKey: ['settings', 'values'] });
- },
- });
-}
-
-export function useSaveValuesMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: (
- values: {
- definition: ExtendedSettingDefinition;
- newValue?: SettingFinalValue;
- }[],
- ) => {
- return Promise.all(
- values
- .filter((v) => v.newValue !== undefined)
- .map(async ({ newValue, definition }) => {
- try {
- if (isDefaultValue(newValue as string | boolean | string[], definition)) {
- await resetSettingValue({ keys: definition.key });
- } else {
- await setSettingValue(definition, newValue);
- }
- return { key: definition.key, success: true };
- } catch (error) {
- return { key: definition.key, success: false };
- }
- }),
- );
- },
- onSuccess: (data) => {
- if (data.length > 0) {
- data.forEach(({ key }) => {
- queryClient.invalidateQueries({ queryKey: ['settings', 'details', key] });
- });
- queryClient.invalidateQueries({ queryKey: ['settings', 'values'] });
- addGlobalSuccessMessage(SETTINGS_SAVE_SUCCESS_MESSAGE);
- }
- },
- });
-}
-
-export function useSaveValueMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: ({
- newValue,
- definition,
- component,
- }: {
- component?: string;
- definition: ExtendedSettingDefinition;
- newValue: SettingFinalValue;
- }) => {
- if (isDefaultValue(newValue, definition)) {
- return resetSettingValue({ keys: definition.key, component });
- }
- return setSettingValue(definition, newValue, component);
- },
- onSuccess: (_, { definition }) => {
- queryClient.invalidateQueries({ queryKey: ['settings', 'details', definition.key] });
- queryClient.invalidateQueries({ queryKey: ['settings', 'values'] });
- invalidateAllMeasures(queryClient);
- addGlobalSuccessMessage(SETTINGS_SAVE_SUCCESS_MESSAGE);
- },
- });
-}
-
-export function useSaveSimpleValueMutation(
- updateCache = false,
- successMessage = SETTINGS_SAVE_SUCCESS_MESSAGE,
-) {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: ({ key, value }: { key: string; value: string }) => {
- return setSimpleSettingValue({ key, value });
- },
- onSuccess: (_, { value, key }) => {
- if (updateCache) {
- queryClient.setQueryData<SettingValue>(['settings', 'details', key], (oldData) =>
- oldData
- ? {
- ...oldData,
- value: oldData.value !== undefined ? String(value) : undefined,
- }
- : oldData,
- );
- } else {
- queryClient.invalidateQueries({ queryKey: ['settings', 'details', key] });
- }
- queryClient.invalidateQueries({ queryKey: ['settings', 'values', [key]] });
- addGlobalSuccessMessage(successMessage);
- },
- });
-}
-
-function isDefaultValue(value: SettingFinalValue, definition: ExtendedSettingDefinition) {
- const defaultValue = definition.defaultValue ?? '';
- if (definition.multiValues) {
- return defaultValue === (value as string[]).join(',');
- }
-
- return defaultValue === String(value);
-}
diff --git a/server/sonar-web/src/main/js/queries/sonarlint.ts b/server/sonar-web/src/main/js/queries/sonarlint.ts
deleted file mode 100644
index defd65f3fdf..00000000000
--- a/server/sonar-web/src/main/js/queries/sonarlint.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useMutation } from '@tanstack/react-query';
-import { addGlobalErrorMessage, addGlobalSuccessMessage } from '~design-system';
-import { useCurrentUser } from '../app/components/current-user/CurrentUserContext';
-import { translate } from '../helpers/l10n';
-import { generateSonarLintUserToken, openFixOrIssueInSonarLint } from '../helpers/sonarlint';
-import { BranchLike } from '../types/branch-like';
-import { Fix, Ide } from '../types/sonarlint';
-import { Issue } from '../types/types';
-import { isLoggedIn } from '../types/users';
-
-export function useOpenFixOrIssueInIdeMutation() {
- const { currentUser } = useCurrentUser();
- const login: string | undefined = isLoggedIn(currentUser) ? currentUser.login : undefined;
-
- return useMutation({
- mutationFn: async (data: {
- branchLike: BranchLike | undefined;
- fix?: Fix;
- ide: Ide;
- issue: Issue;
- }) => {
- const { ide, branchLike, issue, fix } = data;
-
- const { key: issueKey, projectKey } = issue;
-
- let token;
- if (ide.needsToken && login !== undefined) {
- token = await generateSonarLintUserToken({ ideName: ide.ideName, login });
- }
-
- return openFixOrIssueInSonarLint({
- branchLike,
- calledPort: ide.port,
- issueKey,
- projectKey,
- token,
- fix,
- });
- },
- onSuccess: (_, arg) => {
- if (arg.fix) {
- addGlobalSuccessMessage(translate('fix_in_ide.report_success'));
- } else {
- addGlobalSuccessMessage(translate('open_in_ide.report_success'));
- }
- },
- onError: (_, arg) => {
- if (arg.fix) {
- addGlobalErrorMessage(translate('fix_in_ide.report_error'));
- } else {
- addGlobalErrorMessage(translate('open_in_ide.report_error'));
- }
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/sources.ts b/server/sonar-web/src/main/js/queries/sources.ts
deleted file mode 100644
index 813b9500332..00000000000
--- a/server/sonar-web/src/main/js/queries/sources.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions } from '@tanstack/react-query';
-import { getRawSource } from '../api/sources';
-import { BranchParameters } from '../sonar-aligned/types/branch-like';
-import { createQueryHook } from './common';
-
-// This will prevent refresh when navigating from page to page.
-const SOURCES_STALE_TIME = 60_000;
-
-function getSourcesQueryKey(key: string, branchParameters: BranchParameters) {
- return ['sources', 'details', key, branchParameters];
-}
-
-export const useRawSourceQuery = createQueryHook((data: BranchParameters & { key: string }) => {
- return queryOptions({
- queryKey: getSourcesQueryKey(data.key, data),
- queryFn: () => getRawSource(data),
- staleTime: SOURCES_STALE_TIME,
- });
-});
diff --git a/server/sonar-web/src/main/js/queries/system.ts b/server/sonar-web/src/main/js/queries/system.ts
deleted file mode 100644
index 9e0a84983e4..00000000000
--- a/server/sonar-web/src/main/js/queries/system.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { queryOptions, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { addGlobalSuccessMessage } from '~design-system';
-import {
- getEmailConfigurations,
- getSystemUpgrades,
- patchEmailConfiguration,
- postEmailConfiguration,
-} from '../api/system';
-import { translate } from '../helpers/l10n';
-import { EmailConfiguration } from '../types/system';
-import { createQueryHook } from './common';
-
-export const useSystemUpgrades = createQueryHook(() => {
- return queryOptions({
- queryKey: ['system', 'upgrades'],
- queryFn: () => getSystemUpgrades(),
- staleTime: Infinity,
- });
-});
-
-export function useGetEmailConfiguration() {
- return useQuery({
- queryKey: ['email_configuration'] as const,
- queryFn: async () => {
- const { emailConfigurations } = await getEmailConfigurations();
- return emailConfigurations && emailConfigurations.length > 0 ? emailConfigurations[0] : null;
- },
- });
-}
-
-export function useSaveEmailConfigurationMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: (data: EmailConfiguration) => {
- return postEmailConfiguration(data);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['email_configuration'] });
- addGlobalSuccessMessage(
- translate('email_notification.form.save_configuration.create_success'),
- );
- },
- });
-}
-
-export function useUpdateEmailConfigurationMutation() {
- const queryClient = useQueryClient();
- return useMutation({
- mutationFn: ({
- emailConfiguration,
- id,
- }: {
- emailConfiguration: EmailConfiguration;
- id: string;
- }) => {
- return patchEmailConfiguration(id, emailConfiguration);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['email_configuration'] });
- addGlobalSuccessMessage(
- translate('email_notification.form.save_configuration.update_success'),
- );
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/users.ts b/server/sonar-web/src/main/js/queries/users.ts
deleted file mode 100644
index bc62ee5ea22..00000000000
--- a/server/sonar-web/src/main/js/queries/users.ts
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { generateToken, getTokens, revokeToken } from '../api/user-tokens';
-import { deleteUser, dismissNotice, getUsers, postUser, updateUser } from '../api/users';
-import { useCurrentUser } from '../app/components/current-user/CurrentUserContext';
-import { getNextPageParam, getPreviousPageParam } from '../helpers/react-query';
-import { UserToken } from '../types/token';
-import { NoticeType, RestUserBase } from '../types/users';
-
-const STALE_TIME = 4 * 60 * 1000;
-
-export function useUsersQueries<U extends RestUserBase>(
- getParams: Omit<Parameters<typeof getUsers>[0], 'pageSize' | 'pageIndex'>,
- enabled = true,
-) {
- return useInfiniteQuery({
- queryKey: ['user', 'list', getParams],
- queryFn: ({ pageParam }) => getUsers<U>({ ...getParams, pageIndex: pageParam }),
- getNextPageParam,
- getPreviousPageParam,
- enabled,
- initialPageParam: 1,
- });
-}
-
-export function useUserTokensQuery(login: string) {
- return useQuery({
- queryKey: ['user', login, 'tokens'],
- queryFn: () => getTokens(login),
- staleTime: STALE_TIME,
- });
-}
-
-export function usePostUserMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (data: Parameters<typeof postUser>[0]) => postUser(data),
- onSuccess() {
- queryClient.invalidateQueries({ queryKey: ['user', 'list'] });
- },
- });
-}
-
-export function useUpdateUserMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: ({
- id,
- data,
- }: {
- data: Parameters<typeof updateUser>[1];
- id: Parameters<typeof updateUser>[0];
- }) => updateUser(id, data),
- onSuccess() {
- queryClient.invalidateQueries({ queryKey: ['user', 'list'] });
- },
- });
-}
-
-export function useDeactivateUserMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (data: Parameters<typeof deleteUser>[0]) => deleteUser(data),
- onSuccess() {
- queryClient.invalidateQueries({ queryKey: ['user', 'list'] });
- },
- });
-}
-
-export function useGenerateTokenMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (data: Parameters<typeof generateToken>[0] & { projectName?: string }) =>
- generateToken(data),
- onSuccess(data, variables) {
- queryClient.setQueryData<UserToken[]>(['user', data.login, 'tokens'], (oldData) => {
- const newData = {
- ...data,
- project:
- variables.projectKey && variables.projectName
- ? { key: variables.projectKey, name: variables.projectName }
- : undefined,
- };
- return oldData ? [...oldData, newData] : [newData];
- });
- },
- });
-}
-
-export function useRevokeTokenMutation() {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: (data: Parameters<typeof revokeToken>[0]) => revokeToken(data),
- onSuccess(_, data) {
- queryClient.setQueryData<UserToken[]>(['user', data.login, 'tokens'], (oldData) =>
- oldData ? oldData.filter((token) => token.name !== data.name) : undefined,
- );
- },
- });
-}
-
-export function useDismissNoticeMutation() {
- const { updateDismissedNotices } = useCurrentUser();
-
- return useMutation({
- mutationFn: (data: NoticeType) => dismissNotice(data),
- onSuccess(_, data) {
- updateDismissedNotices(data, true);
- },
- });
-}
diff --git a/server/sonar-web/src/main/js/queries/web-api.ts b/server/sonar-web/src/main/js/queries/web-api.ts
deleted file mode 100644
index a3e0e66ced8..00000000000
--- a/server/sonar-web/src/main/js/queries/web-api.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { useQuery } from '@tanstack/react-query';
-import { fetchOpenAPI, fetchWebApi } from '../api/web-api';
-
-export function useWebApiQuery() {
- return useQuery({ queryKey: ['web-api'], queryFn: () => fetchWebApi(false) });
-}
-
-export const useOpenAPI = () => {
- return useQuery({
- queryKey: ['open_api'],
- queryFn: fetchOpenAPI,
- staleTime: Infinity,
- gcTime: Infinity,
- });
-};
diff --git a/server/sonar-web/src/main/js/queries/withQueryClientHoc.tsx b/server/sonar-web/src/main/js/queries/withQueryClientHoc.tsx
deleted file mode 100644
index 26880b0a382..00000000000
--- a/server/sonar-web/src/main/js/queries/withQueryClientHoc.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { QueryClient, useQueryClient } from '@tanstack/react-query';
-import { ComponentClass, VFC } from 'react';
-
-export function withQueryClient<P>(
- Component:
- | ComponentClass<P & { queryClient: QueryClient }>
- | VFC<P & { queryClient: QueryClient }>,
-): VFC<Omit<P, 'queryClient'>> {
- return function WithQueryClient(props: P) {
- const queryClient = useQueryClient();
- return <Component {...props} queryClient={queryClient} />;
- };
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/SourceViewer/JupyterNotebookViewer.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/SourceViewer/JupyterNotebookViewer.tsx
deleted file mode 100644
index 580338be33b..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/SourceViewer/JupyterNotebookViewer.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- IMarkdownCell,
- IOutput,
- isDisplayData,
- isExecuteResult,
- isStream,
-} from '@jupyterlab/nbformat';
-import classNames from 'classnames';
-import { isArray } from 'lodash';
-import Markdown from 'react-markdown';
-import { CodeSnippet } from '~design-system';
-import { translate } from '../../../helpers/l10n';
-import { Image } from '../common/Image';
-
-export function JupyterMarkdownCell({ cell }: Readonly<{ cell: IMarkdownCell }>) {
- const markdown = isArray(cell.source) ? cell.source.join('') : cell.source;
- return (
- <div className="sw-m-4 sw-ml-0">
- <Markdown>{markdown}</Markdown>
- </div>
- );
-}
-
-function CellOutput({ output }: Readonly<{ output: IOutput }>) {
- if (isExecuteResult(output) || isDisplayData(output)) {
- const components = Object.entries(output.data).map(([mimeType, dataValue], index) => {
- if (mimeType === 'image/png') {
- return (
- <Image
- src={`data:image/png;base64,${dataValue}`}
- alt={translate('source_viewer.jupyter.output.image')}
- key={`${mimeType}_${index}`}
- />
- );
- } else if (mimeType === 'text/plain') {
- const bundle = isArray(dataValue) ? dataValue.join('') : dataValue;
-
- return (
- <pre key={`${mimeType}_${index}`}>
- {typeof bundle === 'string' ? bundle : JSON.stringify(bundle)}
- </pre>
- );
- }
- return null;
- });
- return <>{components}</>;
- } else if (isStream(output)) {
- const text = isArray(output.text) ? output.text.join('') : output.text;
- return <pre>{text}</pre>;
- }
- return null;
-}
-
-export function JupyterCodeCell(
- props: Readonly<{ className?: string; outputs?: IOutput[]; source: string[] }>,
-) {
- const { source, outputs, className } = props;
-
- return (
- <div className={classNames('sw-m-4 sw-ml-0', className)}>
- <div>
- <CodeSnippet language="python" noCopy snippet={source.join('')} wrap className="sw-p-4" />
- </div>
- <div>
- {outputs?.map((output: IOutput, outputIndex: number) => (
- <CellOutput key={`${output.output_type}-output-${outputIndex}`} output={output} />
- ))}
- </div>
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11yContext.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11yContext.tsx
deleted file mode 100644
index 1b9ecdb249c..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11yContext.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { createContext } from 'react';
-import { A11ySkipLink } from '../../../types/types';
-
-export interface A11yContextShape {
- addA11ySkipLink: (link: A11ySkipLink) => void;
- links: A11ySkipLink[];
- removeA11ySkipLink: (link: A11ySkipLink) => void;
-}
-
-export const A11yContext = createContext<A11yContextShape>({
- addA11ySkipLink: () => {
- /* Implemented by Provider */
- },
- removeA11ySkipLink: () => {
- /* Implemented by Provider */
- },
- links: [],
-});
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11yProvider.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11yProvider.tsx
deleted file mode 100644
index 3a33cd76e3b..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11yProvider.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { sortBy } from 'lodash';
-import * as React from 'react';
-import { A11ySkipLink } from '../../../types/types';
-import { A11yContext } from './A11yContext';
-
-interface State {
- links: A11ySkipLink[];
-}
-
-export default class A11yProvider extends React.Component<React.PropsWithChildren, State> {
- keys: string[] = [];
- state: State = { links: [] };
-
- addA11ySkipLink = (link: A11ySkipLink) => {
- this.setState((prevState) => {
- const links = [...prevState.links];
- links.push({ ...link, weight: link.weight || 0 });
- return { links };
- });
- };
-
- removeA11ySkipLink = (link: A11ySkipLink) => {
- this.setState((prevState) => {
- const links = prevState.links.filter((l) => l.key !== link.key);
- return { links };
- });
- };
-
- render() {
- const links = sortBy(this.state.links, 'weight');
- return (
- <A11yContext.Provider
- value={{
- addA11ySkipLink: this.addA11ySkipLink,
- links,
- removeA11ySkipLink: this.removeA11ySkipLink,
- }}
- >
- {this.props.children}
- </A11yContext.Provider>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11ySkipLinks.css b/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11ySkipLinks.css
deleted file mode 100644
index 7c8b873dc94..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11ySkipLinks.css
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-.a11y-skip-link {
- width: 0;
- height: 0;
- padding: 8px;
- position: absolute;
- left: -9999px;
- top: -9999px;
- border: 0;
- font-size: 1rem;
- text-align: center;
- z-index: 999;
-}
-
-.a11y-skip-link:focus {
- width: auto;
- height: auto;
- left: 6px;
- top: 6px;
- color: white;
- background-color: #262626;
- text-decoration: underline;
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11ySkipLinks.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11ySkipLinks.tsx
deleted file mode 100644
index 1e89bf1392b..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11ySkipLinks.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { A11yContext } from './A11yContext';
-import './A11ySkipLinks.css';
-
-export default function A11ySkipLinks() {
- return (
- <A11yContext.Consumer>
- {({ links }) =>
- links.map((link) => (
- <a className="a11y-skip-link" href={`#a11y_target__${link.key}`} key={link.key}>
- {link.label}
- </a>
- ))
- }
- </A11yContext.Consumer>
- );
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11ySkipTarget.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11ySkipTarget.tsx
deleted file mode 100644
index f36236b0c19..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/a11y/A11ySkipTarget.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { translate } from '../../../helpers/l10n';
-import { A11ySkipLink } from '../../../types/types';
-import { A11yContext } from './A11yContext';
-
-interface Props {
- anchor: string;
- label?: string;
- weight?: number;
-}
-
-export default function A11ySkipTarget(props: Props) {
- return (
- <A11yContext.Consumer>
- {({ addA11ySkipLink, removeA11ySkipLink }) => (
- <A11ySkipTargetInner
- addA11ySkipLink={addA11ySkipLink}
- removeA11ySkipLink={removeA11ySkipLink}
- {...props}
- />
- )}
- </A11yContext.Consumer>
- );
-}
-
-interface InnerProps {
- addA11ySkipLink: (link: A11ySkipLink) => void;
- removeA11ySkipLink: (link: A11ySkipLink) => void;
-}
-
-export class A11ySkipTargetInner extends React.PureComponent<Props & InnerProps> {
- componentDidMount() {
- this.props.addA11ySkipLink(this.getLink());
- }
-
- componentWillUnmount() {
- this.props.removeA11ySkipLink(this.getLink());
- }
-
- getLink = (): A11ySkipLink => {
- const { anchor: key, label = translate('skip_to_content'), weight } = this.props;
- return { key, label, weight };
- };
-
- render() {
- const { anchor } = this.props;
- return <span id={`a11y_target__${anchor}`} />;
- }
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/a11y/__tests__/A11yLinks-test.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/a11y/__tests__/A11yLinks-test.tsx
deleted file mode 100644
index e9bd38b0693..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/a11y/__tests__/A11yLinks-test.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import * as React from 'react';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { byRole } from '../../../helpers/testSelector';
-import { A11yContext } from '../A11yContext';
-import A11yProvider from '../A11yProvider';
-import A11ySkipLinks from '../A11ySkipLinks';
-
-const ui = {
- links: byRole('link'),
-
- // specific to test
- addButton: byRole('button', { name: 'Add' }),
- removeButton: byRole('button', { name: 'Remove' }),
-};
-
-it('should render correctly', async () => {
- const user = userEvent.setup();
-
- renderA11ySkipLinks();
-
- expect(ui.links.queryAll()).toHaveLength(0);
-
- await user.click(ui.addButton.get());
- expect(ui.links.getAll()).toHaveLength(1);
-
- await user.click(ui.addButton.get());
- expect(ui.links.getAll()).toHaveLength(2);
-
- await user.click(ui.removeButton.get());
- expect(ui.links.getAll()).toHaveLength(1);
-});
-
-function renderA11ySkipLinks() {
- return renderComponent(
- <A11yProvider>
- <A11ySkipLinks />
-
- <LinkTester />
- </A11yProvider>,
- '/',
- {},
- );
-}
-
-let count = 0;
-
-function LinkTester() {
- const { addA11ySkipLink, removeA11ySkipLink } = React.useContext(A11yContext);
-
- return (
- <>
- <button
- onClick={() => {
- count += 1;
- addA11ySkipLink({ key: `${count}`, label: `link #${count}` });
- }}
- type="button"
- >
- Add
- </button>
- <button
- onClick={() => {
- removeA11ySkipLink({ key: `${count}`, label: `link #${count}` });
- count -= 1;
- }}
- type="button"
- >
- Remove
- </button>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/common/Image.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/common/Image.tsx
deleted file mode 100644
index c30655c5343..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/common/Image.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { getBaseUrl } from '../../../helpers/system';
-
-export function Image(props: Readonly<JSX.IntrinsicElements['img']>) {
- const { alt, src: source, ...rest } = props;
-
- const baseUrl = getBaseUrl();
-
- let src = source;
-
- if (
- src !== undefined &&
- !src.startsWith(baseUrl) &&
- !src.startsWith('http') &&
- !src.startsWith('data:')
- ) {
- src = `${baseUrl}/${src}`.replace(/(?<!:)\/+/g, '/');
- }
-
- // eslint-disable-next-line react/forbid-elements
- return <img alt={alt} src={src} {...rest} />;
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/common/__tests__/Image-test.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/common/__tests__/Image-test.tsx
deleted file mode 100644
index 1860446ea31..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/common/__tests__/Image-test.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { screen } from '@testing-library/react';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { Image } from '../Image';
-
-describe('should render correctly', () => {
- it('with a src', () => {
- setupWithProps({
- src: 'foo.png',
- });
-
- expect(screen.getByRole('img').outerHTML).toEqual('<img src="foo.png">');
- });
-
- it('with a src and alt', () => {
- setupWithProps({
- src: 'foo.png',
- alt: 'bar',
- });
-
- expect(screen.getByRole('img').outerHTML).toEqual('<img alt="bar" src="foo.png">');
- });
-
- it('should strip beginning slashes', () => {
- setupWithProps({
- src: '/foo.png',
- });
-
- expect(screen.getByRole('img').outerHTML).toEqual('<img src="/foo.png">');
- });
-});
-
-function setupWithProps(props: Partial<Readonly<JSX.IntrinsicElements['img']>> = {}) {
- return renderComponent(<Image {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/controls/DocHelpTooltip.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/controls/DocHelpTooltip.tsx
deleted file mode 100644
index 48735048533..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/controls/DocHelpTooltip.tsx
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { first, last } from 'lodash';
-import * as React from 'react';
-import { HelperHintIcon } from '~design-system';
-import DocumentationLink from '../../../components/common/DocumentationLink';
-import Link from '../../../components/common/Link';
-import Tooltip, { Placement } from '../../../components/controls/Tooltip';
-import { DocLink } from '../../../helpers/doc-links';
-import { KeyboardKeys } from '../../../helpers/keycodes';
-import { translate } from '../../../helpers/l10n';
-
-export interface DocHelpTooltipProps {
- children?: React.ReactNode;
- className?: string;
- content?: React.ReactNode;
- linkTextLabel?: string;
- links?: Array<
- { inPlace?: boolean; label?: string } & (
- | { doc?: true; href: DocLink }
- | { doc: false; href: string }
- )
- >;
- placement?: Placement;
- title?: string;
-}
-
-export default function DocHelpTooltip(props: Readonly<DocHelpTooltipProps>) {
- const nextSelectableNode = React.useRef<HTMLElement | undefined | null>();
- const linksRef = React.useRef<Array<HTMLAnchorElement | null>>([]);
- const helpRef = React.useRef<HTMLElement>(null);
- const { className, children, content, links, title, placement, linkTextLabel } = props;
-
- function handleShowTooltip() {
- document.addEventListener('keydown', handleTabPress);
- }
-
- function handleHideTooltip() {
- document.removeEventListener('keydown', handleTabPress);
- nextSelectableNode.current = undefined;
- }
-
- function handleTabPress(event: KeyboardEvent) {
- if (event.code === KeyboardKeys.Tab) {
- if (event.shiftKey) {
- if (event.target === first(linksRef.current)) {
- helpRef.current?.focus();
- }
- return;
- }
- if (event.target === last(linksRef.current)) {
- event.preventDefault();
- nextSelectableNode.current?.focus();
- return;
- }
- if (nextSelectableNode.current === undefined) {
- nextSelectableNode.current = event.target as HTMLElement;
- event.preventDefault();
- linksRef.current[0]?.focus();
- }
- }
- }
-
- const overlay = (
- <div className="sw-py-4">
- {title !== undefined && (
- <div className="sw-mb-2">
- <strong>{title}</strong>
- </div>
- )}
-
- {content && <div>{content}</div>}
-
- {links && (
- <>
- <hr className="sw-my-4" />
-
- {links.map(({ href, label = translate('learn_more'), inPlace, doc = true }, index) => (
- <div className="sw-mb-1" key={label}>
- {index === 0 && linkTextLabel && `${linkTextLabel}: `}
- {doc ? (
- <DocumentationLink
- to={href as DocLink} // the map above messed up type inference
- innerRef={(ref) => (linksRef.current[index] = ref)}
- >
- {label}
- </DocumentationLink>
- ) : (
- <Link
- to={href}
- ref={(ref) => (linksRef.current[index] = ref)}
- target={inPlace ? undefined : '_blank'}
- >
- {label}
- </Link>
- )}
- </div>
- ))}
- </>
- )}
- </div>
- );
-
- return (
- <div
- className={classNames(
- 'it__help-tooltip sw-inline-flex sw-items-center sw-align-middle',
- className,
- )}
- >
- <Tooltip
- mouseLeaveDelay={0.25}
- onShow={handleShowTooltip}
- onHide={handleHideTooltip}
- content={overlay}
- side={placement}
- isInteractive
- >
- <span
- className="sw-inline-flex sw-items-center"
- data-testid="help-tooltip-activator"
- ref={helpRef}
- >
- {children ?? (
- <HelperHintIcon
- aria-label={translate('tooltip_is_interactive')}
- description={
- <>
- {translate('tooltip_is_interactive')}
- {overlay}
- </>
- }
- />
- )}
- </span>
- </Tooltip>
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/controls/HelpTooltip.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/controls/HelpTooltip.tsx
deleted file mode 100644
index 74be6c84567..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/controls/HelpTooltip.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import * as React from 'react';
-import { HelperHintIcon } from '~design-system';
-import Tooltip, { Placement } from '../../../components/controls/Tooltip';
-import { translate } from '../../../helpers/l10n';
-
-interface Props {
- 'aria-label'?: string;
- children?: React.ReactNode;
- className?: string;
- 'data-testid'?: string;
- overlay: React.ReactNode;
- placement?: Placement;
-}
-
-const DEFAULT_SIZE = 12;
-
-export default function HelpTooltip(props: Readonly<Props>) {
- const { overlay, placement, children } = props;
- return (
- <div
- className={classNames(
- 'it__help-tooltip sw-inline-flex sw-items-center sw-align-middle',
- props.className,
- )}
- >
- <Tooltip mouseLeaveDelay={0.25} content={overlay} side={placement}>
- <span
- aria-label={props['aria-label']}
- className="sw-inline-flex sw-items-center"
- data-testid={props['data-testid'] ?? 'help-tooltip-activator'}
- >
- {children ?? (
- <HelperHintIcon
- aria-label={translate('help')}
- description={overlay}
- height={DEFAULT_SIZE}
- width={DEFAULT_SIZE}
- />
- )}
- </span>
- </Tooltip>
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/controls/__tests__/DocHelpTooltip-test.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/controls/__tests__/DocHelpTooltip-test.tsx
deleted file mode 100644
index 31186bca1b1..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/controls/__tests__/DocHelpTooltip-test.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import userEvent from '@testing-library/user-event';
-import { byRole, byTestId } from '../../../helpers/testSelector';
-
-import Link from '../../../../components/common/Link';
-import { DocLink } from '../../../../helpers/doc-links';
-import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import DocHelpTooltip, { DocHelpTooltipProps } from '../DocHelpTooltip';
-
-const ui = {
- body: byRole('body'),
- beforeLink: byRole('link', { name: 'Interactive element before' }),
- helpIcon: byTestId('help-tooltip-activator'),
- helpLink: byRole('link', { name: 'Icon' }),
- linkInTooltip: byRole('link', { name: 'Label' }),
- linkInTooltip2: byRole('link', { name: /^Label2\b/ }),
- afterLink: byRole('link', { name: 'Interactive element after' }),
-};
-
-it('should correctly navigate through TAB', async () => {
- const user = userEvent.setup();
- renderDocHelpTooltip();
-
- await user.tab();
- expect(await ui.beforeLink.find()).toHaveFocus();
- await user.tab();
- expect(ui.helpIcon.get()).toHaveFocus();
- await user.tab();
- expect(ui.linkInTooltip.get()).toHaveFocus();
- await user.tab();
- expect(ui.linkInTooltip2.get()).toHaveFocus();
- // Looks like RTL tab event ignores any custom focuses during the events phase,
- // unless preventDefault is specified
- await user.tab();
- expect(ui.helpIcon.get()).toHaveFocus();
- await user.tab({ shift: true });
- await user.tab({ shift: true });
- await user.tab();
- await user.tab();
- await user.tab({ shift: true });
- expect(await ui.beforeLink.find()).toHaveFocus();
-});
-
-function renderDocHelpTooltip(props: Partial<DocHelpTooltipProps> = {}) {
- return renderComponent(
- <>
- <Link to="/" target="_blank">
- Interactive element before
- </Link>
- <DocHelpTooltip
- title="Tooltip title"
- content="Tooltip content"
- links={[
- {
- doc: false,
- href: '/user-guide/clean-as-you-code2/',
- label: 'Label',
- },
- {
- doc: true,
- href: DocLink.CaYC,
- inPlace: true,
- label: 'Label2',
- },
- ]}
- {...props}
- >
- <Link to="/" target="_blank">
- Icon
- </Link>
- </DocHelpTooltip>
- <Link to="/" target="_blank">
- Interactive element after
- </Link>
- </>,
- );
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/hoc/__tests__/utils-test.ts b/server/sonar-web/src/main/js/sonar-aligned/components/hoc/__tests__/utils-test.ts
deleted file mode 100644
index 970797bdd34..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/hoc/__tests__/utils-test.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { getWrappedDisplayName } from '../utils';
-
-it('should compute the name correctly', () => {
- expect(getWrappedDisplayName({} as any, 'myName')).toBe('myName(Component)');
-
- class DummyWrapper extends React.Component {}
-
- expect(getWrappedDisplayName(DummyWrapper, 'myName')).toBe('myName(DummyWrapper)');
-
- class DummyWrapper2 extends React.Component {
- static displayName = 'Foo';
- }
-
- expect(getWrappedDisplayName(DummyWrapper2, 'myName')).toBe('myName(Foo)');
-});
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/hoc/utils.ts b/server/sonar-web/src/main/js/sonar-aligned/components/hoc/utils.ts
deleted file mode 100644
index 7a4980f84eb..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/hoc/utils.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React from 'react';
-
-export function getWrappedDisplayName<P>(
- WrappedComponent: React.ComponentType<React.PropsWithChildren<P>>,
- hocName: string,
-) {
- const wrappedDisplayName = WrappedComponent.displayName ?? WrappedComponent.name ?? 'Component';
- return `${hocName}(${wrappedDisplayName})`;
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/hoc/withRouter.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/hoc/withRouter.tsx
deleted file mode 100644
index 2923d44ae60..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/hoc/withRouter.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { useMemo } from 'react';
-import {
- Params,
- useLocation as useLocationRouter,
- useNavigate,
- useParams,
- useSearchParams,
-} from 'react-router-dom';
-import { searchParamsToQuery } from '../../helpers/router';
-import { queryToSearchString } from '../../helpers/urls';
-import { Location, Router } from '../../types/router';
-import { getWrappedDisplayName } from './utils';
-
-export interface WithRouterProps {
- location: Location;
- params: Params;
- router: Router;
-}
-
-export function withRouter<P extends Partial<WithRouterProps>>(
- WrappedComponent: React.ComponentType<React.PropsWithChildren<P>>,
-): React.ComponentType<React.PropsWithChildren<Omit<P, keyof WithRouterProps>>> {
- function ComponentWithRouterProp(props: Readonly<P>) {
- const router = useRouter();
- const params = useParams();
- const location = useLocation();
-
- return <WrappedComponent {...props} location={location} params={params} router={router} />;
- }
-
- (ComponentWithRouterProp as React.FC<React.PropsWithChildren<P>>).displayName =
- getWrappedDisplayName(WrappedComponent, 'withRouter');
-
- return ComponentWithRouterProp;
-}
-
-export function useRouter() {
- const navigate = useNavigate();
- const [searchParams, setSearchParams] = useSearchParams();
-
- return React.useMemo(
- () => ({
- replace: (path: string | Partial<Location>) => {
- if ((path as Location).query) {
- path.search = queryToSearchString((path as Location).query);
- }
- navigate(path, { replace: true });
- },
- push: (path: string | Partial<Location>) => {
- if ((path as Location).query) {
- path.search = queryToSearchString((path as Location).query);
- }
- navigate(path);
- },
- navigate,
- searchParams,
- setSearchParams,
- }),
- [navigate, searchParams, setSearchParams],
- );
-}
-
-export function useLocation() {
- const location = useLocationRouter();
-
- return useMemo(
- () => ({ ...location, query: searchParamsToQuery(new URLSearchParams(location.search)) }),
- [location],
- );
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/measure/Measure.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/measure/Measure.tsx
deleted file mode 100644
index ea096ab16b6..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/components/measure/Measure.tsx
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import classNames from 'classnames';
-import { useCallback } from 'react';
-import { useIntl } from 'react-intl';
-import { QualityGateIndicator, RatingEnum } from '~design-system';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { Status } from '~sonar-aligned/types/common';
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import RatingComponent from '../../../app/components/metrics/RatingComponent';
-import RatingTooltipContent from '../../../components/measure/RatingTooltipContent';
-import { BranchLike } from '../../../types/branch-like';
-
-type FontClass =
- | 'sw-heading-xs'
- | 'sw-heading-sm'
- | 'sw-heading-md'
- | 'sw-heading-lg'
- | 'sw-heading-xl'
- | 'sw-typo-default'
- | 'sw-typo-semibold'
- | 'sw-typo-bold'
- | 'sw-typo-sm'
- | 'sw-typo-sm-semibold'
- | 'sw-typo-lg'
- | 'sw-typo-lg-semibold'
- | 'sw-typo-label'
- | 'sw-typo-helper-text'
- | 'sw-typo-display';
-
-interface Props {
- badgeSize?: 'xs' | 'sm' | 'md';
- branchLike?: BranchLike;
- className?: string;
- componentKey: string;
- decimals?: number;
- fontClassName?: FontClass;
- forceRatingMetric?: boolean;
- metricKey: string;
- metricType: string;
- small?: boolean;
- value: string | number | undefined;
-}
-
-export default function Measure({
- className,
- componentKey,
- badgeSize,
- decimals,
- fontClassName,
- metricKey,
- branchLike,
- metricType,
- forceRatingMetric,
- small,
- value,
-}: Readonly<Props>) {
- const intl = useIntl();
- const classNameWithFont = classNames(className, fontClassName);
-
- const getTooltip = useCallback(
- (_: RatingEnum, value: string | undefined, metric?: MetricKey) =>
- value !== undefined &&
- metric !== undefined && <RatingTooltipContent metricKey={metric} value={value} />,
- [],
- );
-
- const getLabel = useCallback(
- (rating: RatingEnum) =>
- rating
- ? intl.formatMessage({ id: 'metric.has_rating_X' }, { '0': rating })
- : intl.formatMessage({ id: 'metric.no_rating' }),
- [intl],
- );
-
- if (value === undefined) {
- return (
- <span
- className={classNameWithFont}
- aria-label={
- metricType === MetricType.Rating ? intl.formatMessage({ id: 'metric.no_rating' }) : ''
- }
- >
- —
- </span>
- );
- }
-
- if (metricType === MetricType.Level) {
- const formatted = formatMeasure(value, MetricType.Level);
-
- return (
- <>
- <QualityGateIndicator
- status={(value as Status) ?? 'NONE'}
- className="sw-mr-2"
- size={small ? 'sm' : 'md'}
- />
- <span className={small ? '' : 'sw-typo-lg'}>{formatted}</span>
- </>
- );
- }
-
- if (metricType !== MetricType.Rating) {
- const formattedValue = formatMeasure(value, metricType, {
- decimals,
- omitExtraDecimalZeros: metricType === MetricType.Percent,
- });
- return <span className={classNameWithFont}>{formattedValue ?? '—'}</span>;
- }
-
- const rating = (
- <RatingComponent
- forceMetric={forceRatingMetric}
- branchLike={branchLike}
- size={badgeSize ?? (small ? 'sm' : 'md')}
- getLabel={getLabel}
- getTooltip={getTooltip}
- componentKey={componentKey}
- ratingMetric={metricKey as MetricKey}
- />
- );
-
- return (
- <>
- {/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */}
- <span className={className} tabIndex={0}>
- {rating}
- </span>
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/__snapshots__/component-test.ts.snap b/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/__snapshots__/component-test.ts.snap
deleted file mode 100644
index 8c0c1bfd06d..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/__snapshots__/component-test.ts.snap
+++ /dev/null
@@ -1,15 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`[Function isPortfolioLike] should work properly 1`] = `
-{
- "APP": false,
- "BRC": false,
- "DEV": false,
- "DIR": false,
- "FIL": false,
- "SVW": true,
- "TRK": false,
- "UTS": false,
- "VW": true,
-}
-`;
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/component-test.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/component-test.ts
deleted file mode 100644
index ed85b0526b6..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/component-test.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { isJupyterNotebookFile, isPortfolioLike } from '../component';
-
-it.each([[isPortfolioLike]])(
- '%p should work properly',
- (utilityMethod: (componentQualifier: ComponentQualifier) => void) => {
- const results = Object.values(ComponentQualifier).reduce(
- (prev, qualifier) => ({ ...prev, [qualifier]: utilityMethod(qualifier) }),
- {},
- );
- expect(results).toMatchSnapshot();
- },
-);
-
-it.each([
- ['foo.ipynb', true],
- ['foo.py', false],
- ['foo.ipynb.py', false],
-])('%s is a Jupyter notebook file: %p', (componentKey, expected) => {
- expect(isJupyterNotebookFile(componentKey)).toBe(expected);
-});
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/json-issue-mapper-test.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/json-issue-mapper-test.ts
deleted file mode 100644
index 472ab8f5177..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/json-issue-mapper-test.ts
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import fs from 'fs';
-import path from 'path';
-import { JsonIssueMapper } from '../json-issue-mapper';
-
-const FIXTURES_PATH = path.join(__dirname, '..', 'mocks', 'fixtures', 'json');
-
-// Load all json files in fixtures and save them with their file names
-function loadFixtures() {
- const fixtureFiles = fs.readdirSync(FIXTURES_PATH);
- const fixtures: { [filename: string]: string } = {};
- fixtureFiles.forEach((file: string) => {
- fixtures[file] = fs.readFileSync(path.join(FIXTURES_PATH, file), 'utf8');
- });
- return fixtures;
-}
-
-const fixtures = loadFixtures();
-
-describe('JsonIssueMapper', () => {
- it('should return cursor position in file from line offset', () => {
- const parser = new JsonIssueMapper(fixtures['00-object-simple.json']);
- expect(parser.lineOffsetToCursorPosition(12, 31)).toEqual(225);
- });
-
- describe('should not fail on invalid json', () => {
- it('should not fail on invalid json', () => {
- expect(new JsonIssueMapper(`This { is ] not " JSON :`).get(3)).toEqual([]);
- expect(new JsonIssueMapper(`AAAAAAAAAAAAAAAAAAA`).get(3)).toEqual([]);
- });
-
- it('should not fail on non-terminated literals', () => {
- const parser = new JsonIssueMapper(`{"key": nul`);
- expect(parser.get(150)).toEqual([]);
- });
- });
-
- describe('should return correct path in strings', () => {
- it('gets cursor path in a string value', () => {
- const parser = new JsonIssueMapper(fixtures['00-object-simple.json']);
- for (const cursor of [20, 21]) {
- expect(parser.get(cursor)).toEqual([
- { type: 'object', key: 'first-key' },
- { type: 'string', index: 2 },
- ]);
- }
- });
-
- it('ignores false-flag characters in strings', () => {
- const parser = new JsonIssueMapper(fixtures['01-object-false-flags.json']);
- const cursor = 111;
- const path = parser.get(cursor);
- expect(path).toEqual([
- { type: 'object', key: '\\"{}}[]]].:-]\\\\\\\\' },
- { type: 'array', index: 0 },
- { type: 'array', index: 0 },
- { type: 'object', key: '\\"{}}[]]].:-]\\\\\\\\' },
- { type: 'string', index: 17 },
- ]);
-
- const object = JSON.parse(fixtures['01-object-false-flags.json']);
- const value = object['"{}}[]]].:-]\\\\'][0][0]['"{}}[]]].:-]\\\\'];
- expect(value[17]).toEqual('u');
- });
-
- it('detects cursor in empty strings', () => {
- const parser = new JsonIssueMapper(fixtures['01-object-false-flags.json']);
- for (let cursor = 180; cursor < 186; cursor++) {
- expect(parser.get(cursor)).toEqual([
- { type: 'object', key: 'empty-key-values' },
- { type: 'object', key: '' },
- ]);
- }
- });
-
- it('detects cursor in empty strings in arrays', () => {
- const parser = new JsonIssueMapper(fixtures['01-object-false-flags.json']);
- for (const cursor of [209, 210, 211, 212]) {
- expect(parser.get(cursor)).toEqual([
- { type: 'object', key: 'empty-key-values' },
- { type: 'object', key: 'list' },
- { type: 'array', index: 1 },
- { type: 'array', index: 0 },
- ]);
- }
- });
-
- it('beautify stringified path when key is alphanum', () => {
- const parser = new JsonIssueMapper(fixtures['02-object-jupyter-notebook.json']);
- const cursor = 233331;
- expect(parser.get(cursor)).toEqual([
- { type: 'object', key: 'cells' },
- { type: 'array', index: 21 },
- { type: 'object', key: 'outputs' },
- { type: 'array', index: 1 },
- { type: 'object', key: 'data' },
- { type: 'object', key: 'image/png' },
- { type: 'string', index: 23 },
- ]);
- });
-
- it('gets cursor in minified jupyter notebook files', () => {
- const parser = new JsonIssueMapper(fixtures['04-object-jupyter-notebook-oneline.json']);
- const cursor = 77354;
- expect(parser.get(cursor)).toEqual([
- { type: 'object', key: 'cells' },
- { type: 'array', index: 1 },
- { type: 'object', key: 'source' },
- { type: 'array', index: 8 },
- { type: 'string', index: 14 },
- ]);
- });
- });
-
- describe('should return correct path in numbers', () => {
- it('gets cursor path in a number value', () => {
- const parser = new JsonIssueMapper(fixtures['00-object-simple.json']);
- for (let cursor = 126; cursor < 138; cursor++) {
- expect(parser.get(cursor)).toEqual([
- { type: 'object', key: 'nested-object' },
- { type: 'object', key: 'second-nested-object' },
- { type: 'object', key: 'foo' },
- ]);
- }
- });
-
- it('gets cursor path in a number value in arrays', () => {
- const parser = new JsonIssueMapper(fixtures['03-array-simple.json']);
- for (let cursor = 78; cursor < 79; cursor++) {
- expect(parser.get(cursor)).toEqual([
- { type: 'array', index: 0 },
- { type: 'array', index: 3 },
- { type: 'array', index: 2 },
- ]);
- }
- });
- });
-});
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/measures-test.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/measures-test.ts
deleted file mode 100644
index 8cfe648bb77..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/measures-test.ts
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { IntlShape } from 'react-intl';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import { getIntl, getMessages } from '../../../helpers/l10nBundle';
-import { Dict } from '../../../types/types';
-import { formatMeasure } from '../measures';
-
-const HOURS_IN_DAY = 8;
-const ONE_MINUTE = 1;
-const ONE_HOUR = ONE_MINUTE * 60;
-const ONE_DAY = HOURS_IN_DAY * ONE_HOUR;
-
-jest.unmock('../../../helpers/l10n');
-
-jest.mock('../../../helpers/l10nBundle', () => ({
- getCurrentLocale: jest.fn().mockReturnValue('en'),
- getMessages: jest.fn().mockReturnValue({}),
- getIntl: jest.fn().mockReturnValue({ formatMessage: jest.fn(({ id }) => `${id}`) }),
-}));
-
-const resetMessages = (messages: Dict<string>) => {
- jest.mocked(getMessages).mockReturnValue(messages);
-
- jest.mocked(getIntl).mockReturnValue({
- formatMessage: jest.fn(({ id }) => {
- return id ? (messages[id] ?? id) : `${id}`;
- }),
- } as unknown as IntlShape);
-};
-
-beforeAll(() => {
- resetMessages({
- 'work_duration.x_days': '{0}d',
- 'work_duration.x_hours': '{0}h',
- 'work_duration.x_minutes': '{0}min',
- 'work_duration.about': '~ {0}',
- 'metric.level.ERROR': 'Error',
- 'metric.level.WARN': 'Warning',
- 'metric.level.OK': 'Ok',
- 'short_number_suffix.g': 'G',
- 'short_number_suffix.k': 'k',
- 'short_number_suffix.m': 'M',
- });
-});
-
-describe('#formatMeasure()', () => {
- it('should format INT', () => {
- expect(formatMeasure(0, MetricType.Integer)).toBe('0');
- expect(formatMeasure(1, MetricType.Integer)).toBe('1');
- expect(formatMeasure(-5, MetricType.Integer)).toBe('-5');
- expect(formatMeasure(999, MetricType.Integer)).toBe('999');
- expect(formatMeasure(1000, MetricType.Integer)).toBe('1,000');
- expect(formatMeasure(1529, MetricType.Integer)).toBe('1,529');
- expect(formatMeasure(10000, MetricType.Integer)).toBe('10,000');
- expect(formatMeasure(1234567890, MetricType.Integer)).toBe('1,234,567,890');
- });
-
- it('should format SHORT_INT', () => {
- expect(formatMeasure(0, MetricType.ShortInteger)).toBe('0');
- expect(formatMeasure(1, MetricType.ShortInteger)).toBe('1');
- expect(formatMeasure(999, MetricType.ShortInteger)).toBe('999');
- expect(formatMeasure(1000, MetricType.ShortInteger)).toBe('1k');
- expect(formatMeasure(1529, MetricType.ShortInteger)).toBe('1.5k');
- expect(formatMeasure(10000, MetricType.ShortInteger)).toBe('10k');
- expect(formatMeasure(10678, MetricType.ShortInteger)).toBe('11k');
- expect(formatMeasure(9467890, MetricType.ShortInteger)).toBe('9.5M');
- expect(formatMeasure(994567890, MetricType.ShortInteger)).toBe('995M');
- expect(formatMeasure(999000001, MetricType.ShortInteger)).toBe('999M');
- expect(formatMeasure(999567890, MetricType.ShortInteger)).toBe('1G');
- expect(formatMeasure(1234567890, MetricType.ShortInteger)).toBe('1.2G');
- expect(formatMeasure(11234567890, MetricType.ShortInteger)).toBe('11G');
- });
-
- it('should format FLOAT', () => {
- expect(formatMeasure(0, 'FLOAT')).toBe('0.0');
- expect(formatMeasure(1, 'FLOAT')).toBe('1.0');
- expect(formatMeasure(1.3, 'FLOAT')).toBe('1.3');
- expect(formatMeasure(1.34, 'FLOAT')).toBe('1.34');
- expect(formatMeasure(50.89, 'FLOAT')).toBe('50.89');
- expect(formatMeasure(100, 'FLOAT')).toBe('100.0');
- expect(formatMeasure(123.456, 'FLOAT')).toBe('123.456');
- expect(formatMeasure(123456.7, 'FLOAT')).toBe('123,456.7');
- expect(formatMeasure(1234567890, 'FLOAT')).toBe('1,234,567,890.0');
- });
-
- it('should respect FLOAT precision', () => {
- expect(formatMeasure(0.1, 'FLOAT')).toBe('0.1');
- expect(formatMeasure(0.12, 'FLOAT')).toBe('0.12');
- expect(formatMeasure(0.12345, 'FLOAT')).toBe('0.12345');
- expect(formatMeasure(0.123456, 'FLOAT')).toBe('0.12346');
- });
-
- it('should format PERCENT', () => {
- expect(formatMeasure(0, MetricType.Percent)).toBe('0.0%');
- expect(formatMeasure(1, MetricType.Percent)).toBe('1.0%');
- expect(formatMeasure(1.3, MetricType.Percent)).toBe('1.3%');
- expect(formatMeasure(1.34, MetricType.Percent)).toBe('1.3%');
- expect(formatMeasure(50.89, MetricType.Percent)).toBe('50.9%');
- expect(formatMeasure(100, MetricType.Percent)).toBe('100%');
- expect(formatMeasure(50.89, MetricType.Percent, { decimals: 0 })).toBe('50.9%');
- expect(formatMeasure(50.89, MetricType.Percent, { decimals: 1 })).toBe('50.9%');
- expect(formatMeasure(50.89, MetricType.Percent, { decimals: 2 })).toBe('50.89%');
- expect(formatMeasure(50.89, MetricType.Percent, { decimals: 3 })).toBe('50.890%');
- expect(
- formatMeasure(50, MetricType.Percent, { decimals: 0, omitExtraDecimalZeros: true }),
- ).toBe('50.0%');
- expect(
- formatMeasure(50, MetricType.Percent, { decimals: 1, omitExtraDecimalZeros: true }),
- ).toBe('50.0%');
- expect(
- formatMeasure(50, MetricType.Percent, { decimals: 3, omitExtraDecimalZeros: true }),
- ).toBe('50.0%');
- expect(
- formatMeasure(50.89, MetricType.Percent, { decimals: 3, omitExtraDecimalZeros: true }),
- ).toBe('50.89%');
- });
-
- it('should format WORK_DUR', () => {
- expect(formatMeasure(0, 'WORK_DUR')).toBe('0');
- expect(formatMeasure(5 * ONE_DAY, 'WORK_DUR')).toBe('5d');
- expect(formatMeasure(2 * ONE_HOUR, 'WORK_DUR')).toBe('2h');
- expect(formatMeasure(40 * ONE_MINUTE, 'WORK_DUR')).toBe('40min');
- expect(formatMeasure(ONE_MINUTE, 'WORK_DUR')).toBe('1min');
- expect(formatMeasure(5 * ONE_DAY + 2 * ONE_HOUR, 'WORK_DUR')).toBe('5d 2h');
- expect(formatMeasure(2 * ONE_HOUR + ONE_MINUTE, 'WORK_DUR')).toBe('2h 1min');
- expect(formatMeasure(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'WORK_DUR')).toBe('5d 2h');
- expect(formatMeasure(15 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'WORK_DUR')).toBe('15d');
- expect(formatMeasure(-5 * ONE_DAY, 'WORK_DUR')).toBe('-5d');
- expect(formatMeasure(-2 * ONE_HOUR, 'WORK_DUR')).toBe('-2h');
- expect(formatMeasure(-1 * ONE_MINUTE, 'WORK_DUR')).toBe('-1min');
- });
-
- it('should format SHORT_WORK_DUR', () => {
- expect(formatMeasure(0, MetricType.ShortWorkDuration)).toBe('0');
- expect(formatMeasure(5 * ONE_DAY, MetricType.ShortWorkDuration)).toBe('5d');
- expect(formatMeasure(2 * ONE_HOUR, MetricType.ShortWorkDuration)).toBe('2h');
- expect(formatMeasure(ONE_MINUTE, MetricType.ShortWorkDuration)).toBe('1min');
- expect(formatMeasure(40 * ONE_MINUTE, MetricType.ShortWorkDuration)).toBe('40min');
- expect(formatMeasure(58 * ONE_MINUTE, MetricType.ShortWorkDuration)).toBe('1h');
- expect(formatMeasure(5 * ONE_DAY + 2 * ONE_HOUR, MetricType.ShortWorkDuration)).toBe('5d');
- expect(formatMeasure(2 * ONE_HOUR + ONE_MINUTE, MetricType.ShortWorkDuration)).toBe('2h');
- expect(formatMeasure(ONE_HOUR + 55 * ONE_MINUTE, MetricType.ShortWorkDuration)).toBe('2h');
- expect(formatMeasure(3 * ONE_DAY + 6 * ONE_HOUR, MetricType.ShortWorkDuration)).toBe('4d');
- expect(formatMeasure(7 * ONE_HOUR + 59 * ONE_MINUTE, MetricType.ShortWorkDuration)).toBe('1d');
- expect(
- formatMeasure(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, MetricType.ShortWorkDuration),
- ).toBe('5d');
- expect(
- formatMeasure(15 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, MetricType.ShortWorkDuration),
- ).toBe('15d');
- expect(formatMeasure(7 * ONE_MINUTE, MetricType.ShortWorkDuration)).toBe('7min');
- expect(formatMeasure(-5 * ONE_DAY, MetricType.ShortWorkDuration)).toBe('-5d');
- expect(formatMeasure(-2 * ONE_HOUR, MetricType.ShortWorkDuration)).toBe('-2h');
- expect(formatMeasure(-1 * ONE_MINUTE, MetricType.ShortWorkDuration)).toBe('-1min');
-
- expect(formatMeasure(1529 * ONE_DAY, MetricType.ShortWorkDuration)).toBe('1.5kd');
- expect(formatMeasure(1234567 * ONE_DAY, MetricType.ShortWorkDuration)).toBe('1.2Md');
- expect(formatMeasure(12345670 * ONE_DAY + 4 * ONE_HOUR, MetricType.ShortWorkDuration)).toBe(
- '12Md',
- );
- });
-
- it('should format RATING', () => {
- expect(formatMeasure(1, MetricType.Rating)).toBe('A');
- expect(formatMeasure(2, MetricType.Rating)).toBe('B');
- expect(formatMeasure(3, MetricType.Rating)).toBe('C');
- expect(formatMeasure(4, MetricType.Rating)).toBe('D');
- expect(formatMeasure(5, MetricType.Rating)).toBe('E');
- });
-
- it('should format LEVEL', () => {
- expect(formatMeasure('ERROR', MetricType.Level)).toBe('Error');
- expect(formatMeasure('WARN', MetricType.Level)).toBe('Warning');
- expect(formatMeasure('OK', MetricType.Level)).toBe('Ok');
- expect(formatMeasure('UNKNOWN', MetricType.Level)).toBe('UNKNOWN');
- });
-
- it('should format MILLISEC', () => {
- expect(formatMeasure(0, 'MILLISEC')).toBe('0ms');
- expect(formatMeasure(1, 'MILLISEC')).toBe('1ms');
- expect(formatMeasure(173, 'MILLISEC')).toBe('173ms');
- expect(formatMeasure(3649, 'MILLISEC')).toBe('4s');
- expect(formatMeasure(893481, 'MILLISEC')).toBe('15min');
- expect(formatMeasure(17862325, 'MILLISEC')).toBe('298min');
- });
-
- it('should not format unknown type', () => {
- expect(formatMeasure('random value', 'RANDOM_TYPE')).toBe('random value');
- });
-
- it('should return null if value is empty string', () => {
- expect(formatMeasure('', MetricType.Percent)).toBe('');
- });
-
- it('should not fail with undefined', () => {
- expect(formatMeasure(undefined, MetricType.Integer)).toBe('');
- });
-});
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/request-test.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/request-test.ts
deleted file mode 100644
index ef91d50fd21..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/request-test.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { setImmediate } from 'timers';
-import { HttpStatus } from '../../../helpers/request';
-import { Dict } from '../../../types/types';
-import { getJSON } from '../request';
-
-const url = '/my-url';
-
-beforeEach(() => {
- jest.clearAllMocks();
- window.fetch = jest.fn().mockResolvedValue(mockResponse({}, HttpStatus.Ok, {}));
-});
-
-describe('getJSON', () => {
- it('should get json without parameters', async () => {
- const response = mockResponse({}, HttpStatus.Ok, {});
- window.fetch = jest.fn().mockResolvedValue(response);
- getJSON(url);
- await new Promise(setImmediate);
-
- expect(window.fetch).toHaveBeenCalledWith(url, expect.objectContaining({ method: 'GET' }));
- expect(response.json).toHaveBeenCalled();
- });
-
- it('should get json with parameters', () => {
- getJSON(url, { data: 'test' });
- expect(window.fetch).toHaveBeenCalledWith(
- url + '?data=test',
- expect.objectContaining({ method: 'GET' }),
- );
- });
-});
-
-function mockResponse(headers: Dict<string> = {}, status = HttpStatus.Ok, value?: any): Response {
- const body = value && value instanceof Object ? JSON.stringify(value) : value;
- const response = new Response(body, { headers, status });
- response.json = jest.fn().mockResolvedValue(value);
- response.text = jest.fn().mockResolvedValue(value);
- return response;
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/testSelector-test.tsx b/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/testSelector-test.tsx
deleted file mode 100644
index 28d3c34b96e..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/testSelector-test.tsx
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { render } from '@testing-library/react';
-import {
- byDisplayValue,
- byLabelText,
- byPlaceholderText,
- byRole,
- byTestId,
- byText,
- byTitle,
-} from '../testSelector';
-
-describe('byText', () => {
- it('should find', async () => {
- renderByRTL();
- expect(await byText('test').find()).toBeVisible();
- });
-
- it('should find all', async () => {
- renderByRTL();
- expect(await byText('repeated').findAll()).toHaveLength(2);
- });
-
- it('should get', () => {
- renderByRTL();
- expect(byText('test').get()).toBeVisible();
- });
-
- it('should get all', () => {
- renderByRTL();
- expect(byText('repeated').getAll()).toHaveLength(2);
- });
-
- it('should query', () => {
- renderByRTL();
- expect(byText('test').query()).toBeVisible();
- });
-
- it('should query all', () => {
- renderByRTL();
- expect(byText('repeated').queryAll()).toHaveLength(2);
- });
-});
-
-describe('byRole', () => {
- it('should find', async () => {
- renderByRTL();
- expect(await byRole('button').find()).toBeVisible();
- });
-
- it('should find all', async () => {
- renderByRTL();
- expect(await byRole('alert').findAll()).toHaveLength(2);
- });
-
- it('should get', () => {
- renderByRTL();
- expect(byRole('button').get()).toBeVisible();
- });
-
- it('should get all', () => {
- renderByRTL();
- expect(byRole('alert').getAll()).toHaveLength(2);
- });
-
- it('should query', () => {
- renderByRTL();
- expect(byRole('button').query()).toBeVisible();
- });
-
- it('should query all', () => {
- renderByRTL();
- expect(byRole('alert').queryAll()).toHaveLength(2);
- });
-});
-
-describe('byPlaceholderText', () => {
- it('should find', async () => {
- renderByRTL();
- expect(await byPlaceholderText('placeholder').find()).toBeVisible();
- });
-
- it('should find all', async () => {
- renderByRTL();
- expect(await byPlaceholderText('repeated').findAll()).toHaveLength(2);
- });
-
- it('should get', () => {
- renderByRTL();
- expect(byPlaceholderText('placeholder').get()).toBeVisible();
- });
-
- it('should get all', () => {
- renderByRTL();
- expect(byPlaceholderText('repeated').getAll()).toHaveLength(2);
- });
-
- it('should query', () => {
- renderByRTL();
- expect(byPlaceholderText('placeholder').query()).toBeVisible();
- });
-
- it('should query all', () => {
- renderByRTL();
- expect(byPlaceholderText('repeated').queryAll()).toHaveLength(2);
- });
-});
-
-describe('byLabelText', () => {
- it('should find', async () => {
- renderByRTL();
- expect(await byLabelText('test').find()).toBeVisible();
- });
-
- it('should find all', async () => {
- renderByRTL();
- expect(await byLabelText('alert').findAll()).toHaveLength(2);
- });
-
- it('should get', () => {
- renderByRTL();
- expect(byLabelText('test').get()).toBeVisible();
- });
-
- it('should get all', () => {
- renderByRTL();
- expect(byLabelText('alert').getAll()).toHaveLength(2);
- });
-
- it('should query', () => {
- renderByRTL();
- expect(byLabelText('test').query()).toBeVisible();
- });
-
- it('should query all', () => {
- renderByRTL();
- expect(byLabelText('alert').queryAll()).toHaveLength(2);
- });
-});
-
-describe('byTestId', () => {
- it('should find', async () => {
- renderByRTL();
- expect(await byTestId('test').find()).toBeVisible();
- });
-
- it('should find all', async () => {
- renderByRTL();
- expect(await byTestId('alert').findAll()).toHaveLength(2);
- });
-
- it('should get', () => {
- renderByRTL();
- expect(byTestId('test').get()).toBeVisible();
- });
-
- it('should get all', () => {
- renderByRTL();
- expect(byTestId('alert').getAll()).toHaveLength(2);
- });
-
- it('should query', () => {
- renderByRTL();
- expect(byTestId('test').query()).toBeVisible();
- });
-
- it('should query all', () => {
- renderByRTL();
- expect(byTestId('alert').queryAll()).toHaveLength(2);
- });
-});
-
-describe('byDisplayValue', () => {
- it('should find', async () => {
- renderByRTL();
- expect(await byDisplayValue('one').find()).toBeVisible();
- });
-
- it('should find all', async () => {
- renderByRTL();
- expect(await byDisplayValue('two').findAll()).toHaveLength(2);
- });
-
- it('should get', () => {
- renderByRTL();
- expect(byDisplayValue('one').get()).toBeVisible();
- });
-
- it('should get all', () => {
- renderByRTL();
- expect(byDisplayValue('two').getAll()).toHaveLength(2);
- });
-
- it('should query', () => {
- renderByRTL();
- expect(byDisplayValue('one').query()).toBeVisible();
- });
-
- it('should query all', () => {
- renderByRTL();
- expect(byDisplayValue('two').queryAll()).toHaveLength(2);
- });
-});
-
-describe('byTitle', () => {
- it('should find', async () => {
- renderByRTL();
- expect(await byTitle('test').find()).toBeVisible();
- });
-
- it('should find all', async () => {
- renderByRTL();
- expect(await byTitle('alert').findAll()).toHaveLength(2);
- });
-
- it('should get', () => {
- renderByRTL();
- expect(byTitle('test').get()).toBeVisible();
- });
-
- it('should get all', () => {
- renderByRTL();
- expect(byTitle('alert').getAll()).toHaveLength(2);
- });
-
- it('should query', () => {
- renderByRTL();
- expect(byTitle('test').query()).toBeVisible();
- });
-
- it('should query all', () => {
- renderByRTL();
- expect(byTitle('alert').queryAll()).toHaveLength(2);
- });
-});
-
-function renderByRTL() {
- return render(
- <div>
- <p aria-label="test" data-testid="test" title="test">
- test
- </p>
- <div aria-label="alert" data-testid="alert" role="alert" title="alert">
- repeated
- </div>
- <div aria-label="alert" data-testid="alert" role="alert" title="alert">
- repeated
- </div>
- <button type="submit">click me</button>
- <input name="name" placeholder="placeholder" />
- <input name="repeated" placeholder="repeated" />
- <input name="repeated2" placeholder="repeated" />
- <select>
- <option value="1">one</option>
- <option value="2">two</option>
- </select>
- <textarea defaultValue="two" />
- <textarea defaultValue="two" />
- </div>,
- );
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/urls-test.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/urls-test.ts
deleted file mode 100644
index 29e033bc98a..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/__tests__/urls-test.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { DEFAULT_ISSUES_QUERY } from '../../../components/shared/utils';
-import { SecurityStandard } from '../../../types/security';
-import {
- getComponentIssuesUrl,
- getComponentSecurityHotspotsUrl,
- queryToSearchString,
-} from '../urls';
-
-const SIMPLE_COMPONENT_KEY = 'sonarqube';
-
-describe('#queryToSearchString', () => {
- it('should handle query as array', () => {
- expect(
- queryToSearchString([
- ['key1', 'value1'],
- ['key1', 'value2'],
- ['key2', 'value1'],
- ]),
- ).toBe('?key1=value1&key1=value2&key2=value1');
- });
-
- it('should handle query as string', () => {
- expect(queryToSearchString('a=1')).toBe('?a=1');
- });
-
- it('should handle query as URLSearchParams', () => {
- expect(queryToSearchString(new URLSearchParams({ a: '1', b: '2' }))).toBe('?a=1&b=2');
- });
-
- it('should handle all types', () => {
- const query = {
- author: ['GRRM', 'JKR', 'Stross'],
- b1: true,
- b2: false,
- number: 0,
- emptyArray: [],
- normalString: 'hello',
- undef: undefined,
- };
-
- expect(queryToSearchString(query)).toBe(
- '?author=GRRM&author=JKR&author=Stross&b1=true&b2=false&number=0&normalString=hello',
- );
- });
-
- it('should handle an missing query', () => {
- expect(queryToSearchString()).toBeUndefined();
- });
-});
-
-describe('#getComponentIssuesUrl', () => {
- it('should work without parameters', () => {
- expect(getComponentIssuesUrl(SIMPLE_COMPONENT_KEY)).toEqual(
- expect.objectContaining({
- pathname: '/project/issues',
- search: queryToSearchString({ id: SIMPLE_COMPONENT_KEY }),
- }),
- );
- });
-
- it('should work with parameters', () => {
- expect(getComponentIssuesUrl(SIMPLE_COMPONENT_KEY, DEFAULT_ISSUES_QUERY)).toEqual(
- expect.objectContaining({
- pathname: '/project/issues',
- search: queryToSearchString({ ...DEFAULT_ISSUES_QUERY, id: SIMPLE_COMPONENT_KEY }),
- }),
- );
- });
-});
-
-describe('#getComponentSecurityHotspotsUrl', () => {
- it('should work with no extra parameters', () => {
- expect(getComponentSecurityHotspotsUrl(SIMPLE_COMPONENT_KEY)).toEqual(
- expect.objectContaining({
- pathname: '/security_hotspots',
- search: queryToSearchString({ id: SIMPLE_COMPONENT_KEY }),
- }),
- );
- });
-
- it('should forward some query parameters', () => {
- expect(
- getComponentSecurityHotspotsUrl(SIMPLE_COMPONENT_KEY, undefined, {
- inNewCodePeriod: 'true',
- [SecurityStandard.OWASP_TOP10_2021]: 'a1',
- [SecurityStandard.CWE]: '213',
- [SecurityStandard.OWASP_TOP10]: 'a1',
- [SecurityStandard.SONARSOURCE]: 'command-injection',
- [SecurityStandard.PCI_DSS_3_2]: '4.2',
- [SecurityStandard.PCI_DSS_4_0]: '4.1',
- ignoredParam: '1234',
- }),
- ).toEqual(
- expect.objectContaining({
- pathname: '/security_hotspots',
- search: queryToSearchString({
- id: SIMPLE_COMPONENT_KEY,
- inNewCodePeriod: 'true',
- [SecurityStandard.OWASP_TOP10_2021]: 'a1',
- [SecurityStandard.OWASP_TOP10]: 'a1',
- [SecurityStandard.SONARSOURCE]: 'command-injection',
- [SecurityStandard.CWE]: '213',
- [SecurityStandard.PCI_DSS_3_2]: '4.2',
- [SecurityStandard.PCI_DSS_4_0]: '4.1',
- }),
- }),
- );
- });
-});
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/branch-like.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/branch-like.ts
deleted file mode 100644
index b114a1805ed..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/branch-like.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- BranchBase,
- BranchLikeBase,
- BranchParameters,
- PullRequestBase,
-} from '~sonar-aligned/types/branch-like';
-
-export function getBranchLikeQuery<T extends BranchLikeBase>(
- branchLike?: T,
- withMainBranch = false,
-): BranchParameters {
- if (isBranch(branchLike) && (withMainBranch || !isMainBranch(branchLike))) {
- return { branch: branchLike.name };
- } else if (isPullRequest(branchLike)) {
- return { pullRequest: branchLike.key };
- }
- return {};
-}
-
-export function isBranch<T extends BranchBase>(branchLike?: T | PullRequestBase): branchLike is T {
- return branchLike !== undefined && (branchLike as T).isMain !== undefined;
-}
-
-export function isMainBranch<T extends BranchBase>(
- branchLike?: T | PullRequestBase,
-): branchLike is T & { isMain: true } {
- return isBranch(branchLike) && branchLike.isMain;
-}
-
-export function isPullRequest<T extends PullRequestBase>(
- branchLike?: T | BranchBase,
-): branchLike is T {
- return branchLike !== undefined && (branchLike as T).key !== undefined;
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/component.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/component.ts
deleted file mode 100644
index dd16696c200..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/component.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-
-export function isPortfolioLike(
- componentQualifier?: string | ComponentQualifier,
-): componentQualifier is ComponentQualifier.Portfolio | ComponentQualifier.SubPortfolio {
- return (
- componentQualifier === ComponentQualifier.Portfolio ||
- componentQualifier === ComponentQualifier.SubPortfolio
- );
-}
-
-export function isJupyterNotebookFile(componentKey: string) {
- return componentKey.endsWith('.ipynb');
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/error.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/error.ts
deleted file mode 100644
index 875028a0b7b..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/error.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { addGlobalErrorMessage } from '~design-system';
-import handleRequiredAuthentication from '../../helpers/handleRequiredAuthentication';
-import { HttpStatus, parseError } from '../../helpers/request';
-
-interface ThrowGlobalErrorOptions {
- redirectUnauthorizedNoReasons?: boolean;
- returnErrorReasons?: boolean; // used only in SC
-}
-
-export function throwGlobalError(
- param: Response | any,
- options: ThrowGlobalErrorOptions = {},
-): Promise<Response | any> {
- if (param.response instanceof Response) {
- /* eslint-disable-next-line no-console */
- console.warn('DEPRECATED: response should not be wrapped, pass it directly.');
- param = param.response;
- }
-
- if (param instanceof Response) {
- return parseError(param)
- .then(
- (...args) => {
- addGlobalErrorMessage(...args);
- if (options.redirectUnauthorizedNoReasons && param.status === HttpStatus.Unauthorized) {
- handleRequiredAuthentication();
- }
- },
- () => {
- /* ignore parsing errors */
- },
- )
- .then(() => Promise.reject(param));
- }
-
- // Axios response object
- if (param.data?.message) {
- addGlobalErrorMessage(param.data?.message);
-
- return Promise.reject(param);
- }
-
- return Promise.reject(param);
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/json-issue-mapper.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/json-issue-mapper.ts
deleted file mode 100644
index 3292e20c6b8..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/json-issue-mapper.ts
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Issue } from '../../types/types';
-
-export type PathEntry =
- | {
- key: string;
- type: 'object';
- }
- | {
- index: number;
- type: 'array';
- }
- | {
- index: number;
- type: 'string';
- };
-
-export type PathToCursor = PathEntry[];
-
-type ParseStepResult = {
- endIndex: number;
- found: boolean;
- path?: PathToCursor;
-};
-
-export class JsonIssueMapper {
- /**
- * Stop-character for literals (first chars of true, false, null, undefined)
- */
- static readonly TOKEN_LITERAL = 'tfnu'.split('');
-
- static readonly TOKEN_SCOPE_ENTRY = `{["0123456789${JsonIssueMapper.TOKEN_LITERAL}`.split('');
-
- static readonly TOKEN_SCOPE_EXIT = ',}]'.split('');
-
- private readonly code: string;
-
- private splitCode: string[] | undefined;
-
- /**
- * Internal cursor position, used during parsing
- */
- private cursorPosition = 0;
-
- /**
- * Current path to the cursor. used during parsing
- */
- private path: PathToCursor = [];
-
- constructor(code: string) {
- this.code = code;
- }
-
- lineOffsetToCursorPosition(startLine: number, startOffset: number): number {
- if (!this.splitCode) {
- this.splitCode = this.code.split('\n');
- }
- const charsBeforeStartLine = this.splitCode.slice(0, startLine - 1).join('\n').length;
- return charsBeforeStartLine + startOffset + (startLine > 1 ? 1 : 0);
- }
-
- get(cursorPosition: number): PathToCursor {
- this.cursorPosition = cursorPosition;
- this.path = [];
-
- const result = this.parseValue(0);
-
- if (!result.found) {
- return [];
- }
-
- const path = [...this.path];
-
- // Reset internal state for cleanup
- this.cursorPosition = 0;
- this.path = [];
-
- return path;
- }
-
- /**
- * Parse an array. Place the index at the end square bracket or stop as soon as the cursor is found.
- */
- private parseArray(startIndex: number, index = 0): ParseStepResult {
- // Check whether the array is empty
- if (index === 0) {
- const firstTokenIndex = this.parseUntilToken(startIndex + 1, [
- ...JsonIssueMapper.TOKEN_SCOPE_ENTRY,
- ']',
- ]);
- if (this.code[firstTokenIndex] === ']') {
- return {
- endIndex: firstTokenIndex,
- found: this.cursorWithin(startIndex, firstTokenIndex),
- };
- }
- }
-
- this.path.push({
- type: 'array',
- index,
- });
-
- // Parse a single value in the array
- const result = this.parseValue(startIndex + 1);
- if (result.found || this.cursorWithin(startIndex, result.endIndex)) {
- return result;
- }
-
- this.path.pop();
-
- if (this.code[result.endIndex] === ']') {
- return result;
- }
-
- // Parse next value if there is one
- return this.parseArray(result.endIndex, index + 1);
- }
-
- /**
- * Parse an object. Place the index at the end curly bracket or stop as soon as the cursor is found.
- */
- private parseObject(openBracketIndex: number): ParseStepResult {
- const keyResult = this.parseObjectKey(openBracketIndex);
- if (typeof keyResult.key === 'undefined') {
- return keyResult;
- }
-
- this.path.push({
- type: 'object',
- key: keyResult.key,
- });
-
- if (keyResult.found) {
- return keyResult;
- }
-
- const result = this.parseValue(keyResult.endIndex + 1);
- if (result.found) {
- return result;
- }
-
- this.path.pop();
-
- if (this.code[result.endIndex] === '}') {
- return result;
- }
-
- // Handle next key or stop if there are no more
- return this.parseObject(result.endIndex + 1);
- }
-
- /**
- * Parse an object key. Place the index at the `:` before the value.
- */
- private parseObjectKey(startIndex: number): ParseStepResult & { key?: string } {
- const keyStart = this.parseUntilToken(startIndex, '"}'.split(''));
- if (this.code[keyStart] === '}' || keyStart >= this.code.length) {
- // No entries in the object
- return {
- endIndex: keyStart,
- found: this.cursorWithin(startIndex, keyStart),
- };
- }
- const keyEnd = this.parseUntilToken(keyStart + 1, '"', true);
- const key = this.code.slice(keyStart + 1, keyEnd);
-
- const colonIndex = this.parseUntilToken(keyEnd, ':');
-
- return {
- key,
- endIndex: colonIndex,
- found: this.cursorWithin(keyStart, colonIndex),
- };
- }
-
- /**
- * Parse any JSON value. Place the cursor at the separator after the value (could be one of `,]}`).
- */
- private parseValue(index: number): ParseStepResult {
- // Then, it's either an object, a number or a string
- const valueStart = this.parseUntilToken(index, JsonIssueMapper.TOKEN_SCOPE_ENTRY);
- const valueChar = this.code[valueStart];
- let valueEnd: number;
- if (valueChar === '{') {
- // Object
- const result = this.parseObject(valueStart);
- valueEnd = result.endIndex;
- if (result.found) {
- return result;
- }
- } else if (valueChar === '[') {
- // Array
- const result = this.parseArray(valueStart);
- valueEnd = result.endIndex;
- if (result.found) {
- return result;
- }
- } else if (valueChar === '"') {
- // String
- const result = this.parseString(valueStart);
- valueEnd = result.endIndex;
- if (result.found) {
- return result;
- }
- } else if (JsonIssueMapper.TOKEN_LITERAL.includes(valueChar)) {
- // Literal
- valueEnd = this.parseAnyLiteral(valueStart);
- } else {
- // Number
- valueEnd =
- this.parseUntilToken(valueStart + 1, [...JsonIssueMapper.TOKEN_SCOPE_EXIT, ' ', '\n']) - 1;
- }
-
- // Find the next key or end of object/array
- const separatorIndex = this.parseUntilToken(valueEnd + 1, JsonIssueMapper.TOKEN_SCOPE_EXIT);
-
- // Cursor somewhere within the value?
- const found = this.cursorWithin(index, valueEnd);
- return {
- found,
- endIndex: separatorIndex,
- };
- }
-
- private getStringCursorIndex(firstQuoteIndex: number, endQuoteIndex: number): number {
- const index = this.cursorPosition - firstQuoteIndex;
-
- // We make it such that if the cursor is on a quote, it is considered to be within the string
- if (index <= 0) {
- return 0;
- }
-
- let count = -1;
- let i = 0;
- while (i < index) {
- // Ignore escaped characters
- if (this.code[firstQuoteIndex + 1 + i] === '\\') {
- i += 2;
- } else {
- i += 1;
- }
- count++;
- }
-
- return Math.min(count, endQuoteIndex - firstQuoteIndex - 2);
- }
-
- /**
- * Parse a string value. Place the cursor at the end quote.
- */
- private parseString(firstQuoteIndex: number): ParseStepResult {
- const endQuoteIndex = this.parseUntilToken(firstQuoteIndex + 1, '"', true);
-
- // Cursor within string value
- if (this.cursorWithin(firstQuoteIndex, endQuoteIndex)) {
- if (endQuoteIndex - firstQuoteIndex > 1) {
- this.path.push({
- type: 'string',
- index: this.getStringCursorIndex(firstQuoteIndex, endQuoteIndex),
- });
- }
-
- return {
- found: true,
- endIndex: endQuoteIndex,
- };
- }
-
- return {
- found: this.cursorWithin(firstQuoteIndex, endQuoteIndex),
- endIndex: endQuoteIndex,
- };
- }
-
- /**
- * Parse any literal. Place the cursor at the end of the literal (last char).
- */
- private parseAnyLiteral(index: number): number {
- while (index < this.code.length - 1) {
- ++index;
-
- const char = this.code[index];
- if (!/[a-zA-Z]/.test(char)) {
- return index - 1;
- }
- }
- return index;
- }
-
- /**
- * Return the first index of the next/prev specified token.
- * If not found, return the index of the end of the code (code.length) or -1 depending on the direction.
- */
- private parseUntilToken(index: number, token: string | string[], ignoreEscaped = false): number {
- const tokens = Array.isArray(token) ? token : [token];
-
- while (index < this.code.length && index >= 0) {
- if (tokens.includes(this.code[index])) {
- if (!ignoreEscaped) {
- return index;
- }
- // Count number of `\` before the token. If there is an even number, the token is not escaped
- // eg \\\\" -> 4 slashes, not escaped
- // eg \\\" -> 3 slashes, escaped
- let escapeCount = 0;
- while (this.code[index - 1 - escapeCount] === '\\') {
- escapeCount += 1;
- }
- if (escapeCount % 2 === 0) {
- return index;
- }
- }
-
- index += 1;
- }
-
- return index;
- }
-
- /**
- * Whether the cursor position in within the specified bounds (includes these bounds)
- */
- private cursorWithin(startIndex: number, endIndex: number) {
- return startIndex <= this.cursorPosition && this.cursorPosition <= endIndex;
- }
-}
-
-export function pathToCursorInCell(path: PathToCursor): {
- cell: number;
- cursorOffset: number;
- line: number;
-} | null {
- const [, cellEntry, , lineEntry, stringEntry] = path;
- if (
- cellEntry?.type !== 'array' ||
- lineEntry?.type !== 'array' ||
- stringEntry?.type !== 'string'
- ) {
- return null;
- }
- return {
- cell: cellEntry.index,
- line: lineEntry.index,
- cursorOffset: stringEntry.index,
- };
-}
-
-export function getOffsetsForIssue(issue: Issue, data: string) {
- if (!issue.textRange) {
- return { startOffset: null, endOffset: null };
- }
-
- const mapper = new JsonIssueMapper(data);
-
- const startOffset = pathToCursorInCell(
- mapper.get(
- mapper.lineOffsetToCursorPosition(issue.textRange.startLine, issue.textRange.startOffset),
- ),
- );
- const endOffset = pathToCursorInCell(
- mapper.get(
- mapper.lineOffsetToCursorPosition(issue.textRange.endLine, issue.textRange.endOffset),
- ),
- );
-
- return { startOffset, endOffset };
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/lazyLoadComponent.tsx b/server/sonar-web/src/main/js/sonar-aligned/helpers/lazyLoadComponent.tsx
deleted file mode 100644
index 9553d038960..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/lazyLoadComponent.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import React, { Component, lazy, Suspense } from 'react';
-import { FlagMessage } from '~design-system';
-import { translate } from '../../helpers/l10n';
-import { requestTryAndRepeatUntil } from '../../helpers/request';
-
-export function lazyLoadComponent<T extends React.ComponentType<any>>(
- factory: () => Promise<{ default: T }>,
- displayName?: string,
-) {
- const LazyComponent = lazy(() =>
- requestTryAndRepeatUntil(factory, { max: 2, slowThreshold: 2 }, () => true),
- );
-
- function LazyComponentWrapper(props: React.ComponentProps<T>) {
- return (
- <LazyErrorBoundary>
- <Suspense fallback={null}>
- <LazyComponent {...props} />
- </Suspense>
- </LazyErrorBoundary>
- );
- }
-
- LazyComponentWrapper.displayName = displayName;
- return LazyComponentWrapper;
-}
-
-interface ErrorBoundaryProps {
- children: React.ReactNode;
-}
-
-interface ErrorBoundaryState {
- hasError: boolean;
-}
-
-export class LazyErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
- state: ErrorBoundaryState = { hasError: false };
-
- static getDerivedStateFromError() {
- // Update state so the next render will show the fallback UI.
- return { hasError: true };
- }
-
- render() {
- if (this.state.hasError) {
- return (
- <FlagMessage variant="error">{translate('default_component_error_message')}</FlagMessage>
- );
- }
- return this.props.children;
- }
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/measures.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/measures.ts
deleted file mode 100644
index 5632bb16be7..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/measures.ts
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { MetricType } from '~sonar-aligned/types/metrics';
-import { ONE_SECOND } from '../../helpers/constants';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import { getCurrentLocale } from '../../helpers/l10nBundle';
-
-import { Dict } from '../../types/types';
-
-const HOURS_IN_DAY = 8;
-
-type FormatterOption =
- | { roundingFunc?: (x: number) => number }
- | { decimals?: number; omitExtraDecimalZeros?: boolean };
-
-type Formatter = (value: string | number, options?: FormatterOption) => string;
-/**
- * Format a measure value for a given type
- * ! For Ratings, use formatRating instead
- */
-
-export function formatMeasure(
- value: string | number | undefined,
- type: string,
- options?: FormatterOption,
-): string {
- const formatter = getFormatter(type);
- // eslint-disable-next-line react-hooks/rules-of-hooks
- return useFormatter(value, formatter, options);
-}
-
-function useFormatter(
- value: string | number | undefined,
- formatter: Formatter,
- options?: FormatterOption,
-): string {
- return value !== undefined && value !== '' ? formatter(value, options) : '';
-}
-
-function getFormatter(type: string): Formatter {
- const FORMATTERS: Dict<Formatter> = {
- INT: intFormatter,
- SHORT_INT: shortIntFormatter,
- FLOAT: floatFormatter,
- PERCENT: percentFormatter,
- WORK_DUR: durationFormatter,
- SHORT_WORK_DUR: shortDurationFormatter,
- RATING: ratingFormatter,
- LEVEL: levelFormatter,
- MILLISEC: millisecondsFormatter,
- };
- return FORMATTERS[type] || noFormatter;
-}
-
-function noFormatter(value: string | number): string | number {
- return value;
-}
-
-function numberFormatter(
- value: string | number,
- minimumFractionDigits = 0,
- maximumFractionDigits = minimumFractionDigits,
-) {
- const { format } = new Intl.NumberFormat(getCurrentLocale(), {
- minimumFractionDigits,
- maximumFractionDigits,
- });
- if (typeof value === 'string') {
- return format(parseFloat(value));
- }
- return format(value);
-}
-
-function intFormatter(value: string | number): string {
- return numberFormatter(value);
-}
-
-function shortIntFormatter(
- value: string | number,
- option?: { roundingFunc?: (x: number) => number },
-): string {
- const shortIntFormats = [
- { unit: 10000000000, formatUnit: 1000000000, fraction: 0, suffix: 'short_number_suffix.g' },
- { unit: 1000000000, formatUnit: 1000000000, fraction: 1, suffix: 'short_number_suffix.g' },
- { unit: 10000000, formatUnit: 1000000, fraction: 0, suffix: 'short_number_suffix.m' },
- { unit: 1000000, formatUnit: 1000000, fraction: 1, suffix: 'short_number_suffix.m' },
- { unit: 10000, formatUnit: 1000, fraction: 0, suffix: 'short_number_suffix.k' },
- { unit: 1000, formatUnit: 1000, fraction: 1, suffix: 'short_number_suffix.k' },
- ];
-
- const roundingFunc = option?.roundingFunc;
- if (typeof value === 'string') {
- value = parseFloat(value);
- }
- for (let i = 0; i < shortIntFormats.length; i++) {
- const { unit, formatUnit, fraction, suffix } = shortIntFormats[i];
- const nextFraction = unit / (shortIntFormats[i + 1] ? shortIntFormats[i + 1].unit / 10 : 1);
- const roundedValue = numberRound(value / unit, nextFraction, roundingFunc);
- if (roundedValue >= 1) {
- return (
- numberFormatter(
- numberRound(value / formatUnit, Math.pow(10, fraction), roundingFunc),
- 0,
- fraction,
- ) + translate(suffix)
- );
- }
- }
-
- return numberFormatter(value);
-}
-
-function numberRound(
- value: number,
- fraction = 1000,
- roundingFunc: (x: number) => number = Math.round,
-) {
- return roundingFunc(value * fraction) / fraction;
-}
-
-function floatFormatter(value: string | number): string {
- return numberFormatter(value, 1, 5);
-}
-
-function percentFormatter(
- value: string | number,
- { decimals, omitExtraDecimalZeros }: { decimals?: number; omitExtraDecimalZeros?: boolean } = {},
-): string {
- if (typeof value === 'string') {
- value = parseFloat(value);
- }
- if (value === 100) {
- return '100%';
- } else if (omitExtraDecimalZeros && decimals) {
- // If omitExtraDecimalZeros is true, all trailing decimal 0s will be removed,
- // except for the first decimal.
- // E.g. for decimals=3:
- // - omitExtraDecimalZeros: false, value: 45.450 => 45.450
- // - omitExtraDecimalZeros: true, value: 45.450 => 45.45
- // - omitExtraDecimalZeros: false, value: 85 => 85.000
- // - omitExtraDecimalZeros: true, value: 85 => 85.0
- return `${numberFormatter(value, 1, decimals)}%`;
- }
- return `${numberFormatter(value, decimals || 1)}%`;
-}
-
-function ratingFormatter(value: string | number): string {
- if (typeof value === 'string') {
- value = parseInt(value, 10);
- }
- return String.fromCharCode(97 + value - 1).toUpperCase();
-}
-
-function levelFormatter(value: string | number): string {
- if (typeof value === 'number') {
- value = value.toString();
- }
- const l10nKey = `metric.level.${value}`;
- const result = translate(l10nKey);
-
- // if couldn't translate, return the initial value
- return l10nKey !== result ? result : value;
-}
-
-function millisecondsFormatter(value: string | number): string {
- if (typeof value === 'string') {
- value = parseInt(value, 10);
- }
- const ONE_MINUTE = 60 * ONE_SECOND;
- if (value >= ONE_MINUTE) {
- const minutes = Math.round(value / ONE_MINUTE);
- return `${minutes}min`;
- } else if (value >= ONE_SECOND) {
- const seconds = Math.round(value / ONE_SECOND);
- return `${seconds}s`;
- }
- return `${value}ms`;
-}
-
-function formatDuration(isNegative: boolean, days: number, hours: number, minutes: number): string {
- let formatted = '';
- if (shouldDisplayDays(days)) {
- formatted += translateWithParameters('work_duration.x_days', isNegative ? -1 * days : days);
- }
- if (shouldDisplayHours(days, hours)) {
- formatted = addSpaceIfNeeded(formatted);
- formatted += translateWithParameters(
- 'work_duration.x_hours',
- isNegative && formatted.length === 0 ? -1 * hours : hours,
- );
- }
- if (shouldDisplayMinutes(days, hours, minutes)) {
- formatted = addSpaceIfNeeded(formatted);
- formatted += translateWithParameters(
- 'work_duration.x_minutes',
- isNegative && formatted.length === 0 ? -1 * minutes : minutes,
- );
- }
- return formatted;
-}
-
-function formatDurationShort(
- isNegative: boolean,
- days: number,
- hours: number,
- minutes: number,
-): string {
- if (shouldDisplayDaysInShortFormat(days)) {
- const roundedDays = Math.round(days);
- const formattedDays = formatMeasure(
- isNegative ? -1 * roundedDays : roundedDays,
- MetricType.ShortInteger,
- );
- return translateWithParameters('work_duration.x_days', formattedDays);
- }
-
- if (shouldDisplayHoursInShortFormat(hours)) {
- const roundedHours = Math.round(hours);
- const formattedHours = formatMeasure(
- isNegative ? -1 * roundedHours : roundedHours,
- MetricType.ShortInteger,
- );
- return translateWithParameters('work_duration.x_hours', formattedHours);
- }
-
- const formattedMinutes = formatMeasure(
- isNegative ? -1 * minutes : minutes,
- MetricType.ShortInteger,
- );
- return translateWithParameters('work_duration.x_minutes', formattedMinutes);
-}
-
-function durationFormatter(value: string | number): string {
- if (typeof value === 'string') {
- value = parseInt(value, 10);
- }
- if (value === 0) {
- return '0';
- }
- const hoursInDay = HOURS_IN_DAY;
- const isNegative = value < 0;
- const absValue = Math.abs(value);
- const days = Math.floor(absValue / hoursInDay / 60);
- let remainingValue = absValue - days * hoursInDay * 60;
- const hours = Math.floor(remainingValue / 60);
- remainingValue -= hours * 60;
- return formatDuration(isNegative, days, hours, remainingValue);
-}
-
-function shortDurationFormatter(value: string | number): string {
- if (typeof value === 'string') {
- value = parseInt(value, 10);
- }
- if (value === 0) {
- return '0';
- }
- const hoursInDay = HOURS_IN_DAY;
- const isNegative = value < 0;
- const absValue = Math.abs(value);
- const days = absValue / hoursInDay / 60;
- let remainingValue = absValue - Math.floor(days) * hoursInDay * 60;
- const hours = remainingValue / 60;
- remainingValue -= Math.floor(hours) * 60;
- return formatDurationShort(isNegative, days, hours, remainingValue);
-}
-
-/*
- * Debt Formatters
- */
-function shouldDisplayDays(days: number): boolean {
- return days > 0;
-}
-
-function shouldDisplayDaysInShortFormat(days: number): boolean {
- return days > 0.9;
-}
-
-function shouldDisplayHours(days: number, hours: number): boolean {
- return hours > 0 && days < 10;
-}
-
-function shouldDisplayHoursInShortFormat(hours: number): boolean {
- return hours > 0.9;
-}
-
-function shouldDisplayMinutes(days: number, hours: number, minutes: number): boolean {
- return minutes > 0 && hours < 10 && days === 0;
-}
-
-function addSpaceIfNeeded(value: string): string {
- return value.length > 0 ? `${value} ` : value;
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/branch.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/branch.ts
deleted file mode 100644
index f4590dc3f48..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/branch.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { BranchBase } from '../../types/branch-like';
-
-export function mockBranchBase(overrides: Partial<BranchBase> = {}): BranchBase {
- return {
- analysisDate: '2018-01-01',
- isMain: false,
- name: 'branch-6.7',
- status: { qualityGateStatus: 'OK' },
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/component.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/component.ts
deleted file mode 100644
index 8a073fcf438..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/component.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentBase, ComponentQualifier } from '../../types/component';
-
-export function mockComponentBase(overrides: Partial<ComponentBase> = {}): ComponentBase {
- return {
- breadcrumbs: [],
- key: 'my-project',
- name: 'MyProject',
- qualifier: ComponentQualifier.Project,
- qualityGate: { isDefault: true, key: '30', name: 'Sonar way' },
- qualityProfiles: [
- {
- deleted: false,
- key: 'my-qp',
- language: 'ts',
- name: 'Sonar way',
- },
- ],
- tags: [],
- ...overrides,
- };
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/00-object-simple.json b/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/00-object-simple.json
deleted file mode 100644
index 27d667d4fd4..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/00-object-simple.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "first-key": "foo",
- "nested-object": {
- "boolean": true,
- "null-value": null,
- "second-nested-object": {
- "foo": 13e-4
- }
- },
- "empty-object": {},
- "another-object": {
- "containing-array": ["with a first string", "with a second string"]
- },
- "last-ignored-key": "with some value"
-} \ No newline at end of file
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/01-object-false-flags.json b/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/01-object-false-flags.json
deleted file mode 100644
index e8b20dbf5f8..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/01-object-false-flags.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "\"{}}[]]].:-]\\\\": [
- [
- {
- "\"{}}[]]].:-]\\\\": "\"{}}[]]].:-]\\\\value"
- }
- ]
- ],
- "empty-key-values": {
- "": "",
- "list": [[], [""]]
- }
-} \ No newline at end of file
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/02-object-jupyter-notebook.json b/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/02-object-jupyter-notebook.json
deleted file mode 100644
index 19a11a9e41e..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/02-object-jupyter-notebook.json
+++ /dev/null
@@ -1,466 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": ["# Learning a cosine with keras"]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "import os\n",
- "os.environ['THEANO_FLAGS']='mode=FAST_COMPILE,optimizer=None,device=cpu,floatX=float32'"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": ["(7500,)\n", "(2500,)\n"]
- }
- ],
- "source": [
- "import numpy as np\n",
- "import sklearn.cross_validation as skcv\n",
- "#x = np.linspace(0, 5*np.pi, num=10000, dtype=np.float32)\n",
- "x = np.linspace(0, 4*np.pi, num=10000, dtype=np.float32)\n",
- "y = np.cos(x)\n",
- "\n",
- "train, test = skcv.train_test_split(np.arange(x.shape[0]))\n",
- "print train.shape\n",
- "print test.shape"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "text/plain": ["[<matplotlib.lines.Line2D at 0x7fb588176b90>]"]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- },
- {
- "data": {
- "image/png": "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\nAElFTkSuQmCC\n",
- "text/plain": ["<matplotlib.figure.Figure at 0x7fb58e57c850>"]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": ["import pylab as pl\n", "%matplotlib inline\n", "pl.plot(x, y)"]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": ["x_train : 0.0 12.5664\n", "(7500, 1)\n", "y_train : -1.0 1.0\n", "(7500,)\n"]
- }
- ],
- "source": [
- "X_train = x[train].reshape(-1, 1)\n",
- "y_train = y[train]\n",
- "\n",
- "print \"x_train : \", X_train.min(), X_train.max()\n",
- "print X_train.shape\n",
- "print \"y_train : \", y_train.min(), y_train.max()\n",
- "print y_train.shape\n",
- "assert X_train.dtype == np.float32\n",
- "assert y_train.dtype == np.float32"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "from sklearn.preprocessing import StandardScaler\n",
- "\n",
- "scaler = StandardScaler().fit(X_train)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[array([[-0.33613324, -1.4662143 , 0.05394468, -0.55310005]], dtype=float32), array([ 0., 0., 0., 0.], dtype=float32), array([[ 0.67240888],\n",
- " [-0.77499759],\n",
- " [-0.6044634 ],\n",
- " [-0.53235888]], dtype=float32), array([ 0.], dtype=float32)]\n",
- "Epoch 1/10\n",
- "7500/7500 [==============================] - 1s - loss: 0.3473 \n",
- "Epoch 2/10\n",
- "7500/7500 [==============================] - 1s - loss: 0.0384 \n",
- "Epoch 3/10\n",
- "7500/7500 [==============================] - 1s - loss: 0.0077 \n",
- "Epoch 4/10\n",
- "7500/7500 [==============================] - 1s - loss: 0.0068 \n",
- "Epoch 5/10\n",
- "7500/7500 [==============================] - 1s - loss: 0.0065 \n",
- "Epoch 6/10\n",
- "7500/7500 [==============================] - 1s - loss: 0.0063 \n",
- "Epoch 7/10\n",
- "7500/7500 [==============================] - 1s - loss: 0.0062 \n",
- "Epoch 8/10\n",
- "7500/7500 [==============================] - 1s - loss: 0.0062 \n",
- "Epoch 9/10\n",
- "7500/7500 [==============================] - 1s - loss: 0.0060 \n",
- "Epoch 10/10\n",
- "7500/7500 [==============================] - 1s - loss: 0.0060 \n"
- ]
- }
- ],
- "source": [
- "from keras.models import Sequential\n",
- "from keras.layers.core import Dense, Dropout, Activation\n",
- "from keras.optimizers import SGD\n",
- "\n",
- "model = Sequential()\n",
- "model.add(Dense(1, 4, init='lecun_uniform'))\n",
- "model.add(Activation('tanh'))\n",
- "model.add(Dense(4, 1, init='lecun_uniform'))\n",
- "model.add(Activation('tanh'))\n",
- "\n",
- "sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)\n",
- "model.compile(loss='mean_squared_error', optimizer=sgd)\n",
- "\n",
- "print model.get_weights()\n",
- "history = model.fit(scaler.transform(X_train), y_train, nb_epoch=10, batch_size=64, shuffle=True)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": ["y_pred = model.predict(scaler.transform(x.reshape(-1, 1)))"]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[array([[-1.74586737, -2.69134307, 2.61606312, -1.8561095 ]], dtype=float32),\n",
- " array([-2.22873259, -1.28916156, -1.30692065, 2.32888794], dtype=float32),\n",
- " array([[ 2.76829553],\n",
- " [-2.36732125],\n",
- " [-2.37912202],\n",
- " [-2.66938806]], dtype=float32),\n",
- " array([ 2.50017142], dtype=float32)]"
- ]
- },
- "execution_count": 8,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": ["model.get_weights()"]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "text/plain": ["<matplotlib.legend.Legend at 0x7fb5cf95f650>"]
- },
- "execution_count": 9,
- "metadata": {},
- "output_type": "execute_result"
- },
- {
- "data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX0AAAEACAYAAABfxaZOAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xd8leX5+PHPnQWEEUaQvVeAhJXAOSEEwkZEUMS6imhr\nh9bR2tbRJbbfr7b60/bbaqu1DrRVERUHIIQVICEnYZPB3nvPEELG/fvjPqQByTzjOeN6v155vXJO\nnpznIpznOvdz3UtprRFCCBEcQqwOQAghhPdI0hdCiCAiSV8IIYKIJH0hhAgikvSFECKISNIXQogg\n4nLSV0q9o5Q6ppTKqeKYvyqldiilNimlBrp6TiGEEHXjjpb+u8CEyn6olJoIdNda9wB+CPzDDecU\nQghRBy4nfa31KuBMFYdMBmY5j80CmiqlWrl6XiGEELXnjZp+O+BAhccHgfZeOK8QQojreKsjV133\nWNZ+EEIIC4R54RyHgA4VHrd3PncNpZR8EAghRB1ora9vWFfKGy39r4D7AZRSduCs1vrYjQ7UWnPu\nnOauuzSDB2tOn9Zo7R9fzz33nOUxBGPsV+PPyNC0bKn52980ZWXfPqa0VPPSS5rWrTXr11sfc6D9\n/a2OwVPxHzumiYvTPPigpqDA+lhv9FVb7hiy+RGwGuillDqglPqeUupHSqkfORP5AmC3Umon8Cbw\nSFWv16QJfPQRJCXB2LFQUOBqhCLQHT4Mt90GH3wAjz4K6gZtnpAQ+OUv4bXXYMIEyMvzfpzCv5w5\nA6NHm/fW229DZKTVEbmHy+UdrfU9NTjm0dq8plLw6qvw4IPma/bsG1/IQhw/Dh9/DLNmwfjx1R9/\nxx2mITFlCmRnQ/Pmno9R+J+yMrjvPhg5Ep5/PrDyj8/OyFUK3ngD9u6F11+3OprqpaSkWB1Cnflr\n7GVlcO+9MGVKCrffXvPfu/9+uPVWeOghqMPdsdv569//qkCM/4UXTOPglVcCK+EDqLrUhDxBKaVv\nFMv27abUk5kJ3btbEJjwWW++Ce+9B+npEBpau98tKoL4eHj2WdOiE+Kq3FzTwt+wAdr7weBypRS6\nFh25Pp/0Af7yF/j6a1iyJPA+dUXdHDoEAwZAWhr07Vu311i/3tT3t26VMo+nKLlg3epGOdK/k/7j\nj8Mzz0CbNtf8rKTEXOD/8z+mU0WI734XunSBP/zBtdd55BEIC4O//tU9cYlrOROS1WEEhMr+lrVN\n+r5V0w8Nhbg404tbXFz+dFgY/PnP8ItfmNtyEdw2bIClS+Gpp1x/rd//3owWy893/bWE8Ae+lfRf\nfdUU7xcuhMGDr7kSx46Fnj3h3XctjE/4hGeegd/8Bho3dv21oqPNh8fMma6/lhD+wLfKO1dj0Rre\necdc3X/6E3zvewA4HHDXXbBjB0REWBissEx6uhl9s20bhIe75zULCqBrV1i2rO79A+LGpLzjPoFZ\n3rlKKfj+92HFCnjpJTOrpqwMux1iYuD9960OUFjl6tvBXQkfoGFDePJJ02ckhJVSUlJ4++23PXoO\n30z6V/XpA6tXmyb+vfdCcTG//S388Y9QWmp1cMLb8vLMhKoHHnD/az/yiBkdtnOn+19biJpSSnl8\nxJNvJ30wY+kWL4bz52HGDJLspTRvDgsWWB2Y8LaXX4bHHoMGDdz/2o0bm5tLf5gIKPxDSUmJ1SHc\nkO8nfYD69eGzz+DoUdQjD/P4Y1qG2AWZ48fhiy/g4Yc9d45HHjGlwwsXPHcO4Ttefvllpk2bds1z\njz/+OD/96U8r/Z2UlBSeffZZbDYbUVFR3HbbbZw5Y/aQ2rt3LyEhIbzzzjt06tSJMWPGAPDOO+/Q\np08fmjdvzoQJE9i/f3/56y1evJiYmBiaNm3KY489VudF1GrDP5I+mObdV19BdjZ3HnuN3FwZZhdM\n3n0Xpk6twSSqy5dh3Tozm++998yiPJ98AhkZcOJElb/asaOZiSl9RsFh+vTpLFy4kHPnzgGmZT57\n9mxmzJhR5e998MEHvPvuuxw5coSwsDAef/zxa36+cuVKtm7dysKFC/nyyy958cUXmTt3LidPniQ5\nOZl77jHLlZ08eZI77riDF154gVOnTtGtWzcyMjI8P6HN6mVBK3yy6RrZu1fr1q317767Sz/ySM1+\nRfi30lKtu3bVOiurkgPy87WeOVPr+Hit69fXOi5O61tu0Xr6dK3vv1/radO0ttm0btpU6y5dtH7o\nIa1TU80LX2fFCq1jYrQuK/PsvylY1Oi6NuP1XPuqowkTJui33npLa631119/rfv27Vvl8SkpKfrZ\nZ58tf5yfn68jIiJ0WVmZ3rNnj1ZK6T179lzz+m+//Xb549LSUh0ZGan37dunZ82apRMTE695/fbt\n219zfEWV/S2dz9c41/pPS/+qTp3gww/5fupdfPxRGYWFVgckPG3JErPk9uDB1/1g+XIYMwZGjTJ9\nPq+8AmfPwubNMG+eabLPmgVz5pjBAKdPmzuA3r3h6afNlN7XX79mxl9yslnIzeHw7r8xqLkj7dfR\njBkz+Pe//w3Av//9b6ZPn17t73To8N89oTp27EhxcTEnT5684c/37dvHE088QbNmzWjWrBktWrQA\n4NChQxw5coT21y3uU/F3PcX/kj7AyJF0vD+F+PDNfDFXxgAHujfegB//uMK6S/v3m/U4vv99M2h/\n716T8EeMgHr1Kn8hpcxA/CefNAvvzJljRgT06gXffFN+yIMPyiTAYDFlyhQ2b95Mbm4u8+fP574a\nrL5XsSa/f/9+wsPDiY6OLn+uYnmmY8eO/POf/+TMmTPlXwUFBSQmJtKmTRsOHPjv9uFa62see0xt\nbgs8+UVtb9EuX9YfdnhKj409XLvfE37lxAmtmzTR+tw55xNz5mjdsqXWf/iD1oWF7jlJaqrWnTtr\n/f3va11YqA8dMpWgixfd8/LBrNbXtQUeeughHRcXp0ePHl3tsSNGjNDt27fX+fn5uqCgQE+bNk3f\nd999WmtdXt4prVA2nDt3ro6NjdV5eXlaa63Pnj2rP/nkE6211idOnNCNGzfWn3/+uS4uLtZ/+ctf\ndFhYmJR3KlWvHre9P5V1efXZnyfDLQLVnDlw883QpLE2q6v98pcwf75Zh6F+ffecZOxYUxK6cAGG\nD6cth0lMhM8/d8/LC982Y8YMcnNza1TaUUoxffp0HnjgAdq0acOVK1f4a4WhhNd3wt522208/fTT\n3H333URFRREXF8eiRYsAiI6OZs6cOTzzzDNER0ezc+dOhg0b5t5/3I3+DdqFepg7VbW0clUe7r2c\n9s0L+XXGRA9EJayWlATPPqOZtOgxsy7T/PnQurVnTqa1mZY7axZzfu7gjU+jWbrUM6cKFv6wDMOB\nAweIiYnh2LFjNGrUqMpjR44cyfTp0/mec2kYbwrsZRhq4b6XBvBxVmezII8IKLt3m010xqf/FrKy\nTMetpxI+mIL+b38LDz/MrS8ls35dGUePeu50wnplZWW88sor3HPPPdUm/Kt8/UOsOn6f9Ife0oyz\nDduR/+RbVoci3OzDD+E7fXIJ//JT09HapIl3Tvzzn1P/wXuYFLaITz+84p1zCq8rKCigSZMmLF26\nlOeff778+UaNGtG4ceNrvpo0aUJ6ejrg/xvD+H15B+DJR4to/O7feD5rAsTGujkyYQWtoU/XQt45\n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\n",
- "text/plain": ["<matplotlib.figure.Figure at 0x7fb588201650>"]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": [
- "pl.plot(x, y_pred, c='r', label='y_pred')\n",
- "pl.plot(x, y, c='b', label='y')\n",
- "pl.legend()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": ["## Playing with the number of hidden units"]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "You might want to run the example multiple times as the random initialization influences the result quite a bit."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "def train_plot_prediction(n_hidden):\n",
- " model = Sequential()\n",
- " model.add(Dense(1, n_hidden, init='lecun_uniform'))\n",
- " model.add(Activation('tanh'))\n",
- " model.add(Dense(n_hidden, 1, init='lecun_uniform'))\n",
- " model.add(Activation('tanh'))\n",
- " \n",
- " sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)\n",
- " model.compile(loss='mean_squared_error', optimizer=sgd)\n",
- " \n",
- " history = model.fit(scaler.transform(X_train), y_train, nb_epoch=5, batch_size=64, shuffle=True,\n",
- " verbose=False)\n",
- " \n",
- " y_pred = model.predict(scaler.transform(x.reshape(-1, 1)))\n",
- " \n",
- " pl.figure(figsize=(10, 4))\n",
- " pl.subplot(211)\n",
- " pl.title('train loss')\n",
- " pl.plot(history.epoch, history.history['loss'], label='loss')\n",
- " pl.subplot(212)\n",
- " pl.title('prediction vs ground truth')\n",
- " pl.plot(x, y_pred, c='r', label='y_pred')\n",
- " pl.plot(x, y, c='b', label='y')\n",
- " pl.legend()\n",
- " pl.tight_layout()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "image/png": "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\nHE2ocEcAAAAASUVORK5CYII=\n",
- "text/plain": ["<matplotlib.figure.Figure at 0x7fb57e895ed0>"]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": ["train_plot_prediction(1)"]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "image/png": "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\n",
- "text/plain": ["<matplotlib.figure.Figure at 0x7fb5ceef6310>"]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": ["train_plot_prediction(2)"]
- },
- {
- "cell_type": "code",
- "execution_count": 13,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "image/png": "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\n",
- "text/plain": ["<matplotlib.figure.Figure at 0x7fb5ceaaf2d0>"]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": ["train_plot_prediction(3)"]
- },
- {
- "cell_type": "code",
- "execution_count": 14,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAAsgAAAEaCAYAAAAMtaHPAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3XmclfP7x/HX1bTvKEqLQpTsS4QYCgnxsxaSLWsqa2Ud\nWyRE1mhRQmQNKUVj36WkQkhpo1RavmqmuX5/fE45TTN1Zr3PzLyfj8f96JxzL+c699zNXOdzfz6f\ny9wdEREREREJykUdgIiIiIhIMlGCLCIiIiISRwmyiIiIiEgcJcgiIiIiInGUIIuIiIiIxFGCLCIi\nIiISRwmyiEiSMLMnzOzmfO6bbmYXFXZMIiJlUfmoAxARKQ3MbA5wobu/n99juPvlBQjBY4uIiBSQ\nWpBFRAqHA5bbSjNTg4SISAmhBFlEpIDM7FmgMfCmma00s+vMrImZZZnZhWb2OzAptu0YM1toZsvN\n7AMz2yPuOM+Y2Z2xx6lm9oeZXWNmi81sgZmdn2A8ZmY3m9mc2L4jzKxmbF1lMxtlZkvMbJmZfWlm\n28fWnW9mv5jZP2b2q5mdXbhnSkSkZFCCLCJSQO7eBZgLnOjuNdz9/rjVRwDNgeNiz98GdgXqAt8C\nz8Ufik27SewA1AR2BC4CHjOzWgmEdAHQFUgFdgaqA4/G1nWNHbMhsC1wKfA/M6sGPAy0d/eaQGvg\nuwTeS0Sk1FGCLCJStNLc/X/uvhbA3Z9x99XungHcDuxjZjXito/vppEB3OHu6939HWAVsHsC73kO\n8IC7z3H31UBfoJOZpQDrgO2AZh5McfeVsf2ygL3MrIq7L3b3GQX54CIiJZUSZBGRojVvwwMzK2dm\n95rZbDNbAfwWW1Unl32XuntW3PM1hNbgrakP/B73fC5hUPb2wLPABGC0mc03s/5mVj6WSJ8FXAYs\nMLO3zCyRZFxEpNRRgiwiUjhym0Ei/vVzgI5AW3evBTSNvW65bJ9fC4Amcc8bA5nAYnfPdPc73L0l\ncChwInAegLu/6+7HAvWAWcDThRCLiEiJowRZRKRwLAZ22co21YG1wN+xPr/9sq03tjATRh68AFwd\nGyhYPfY+o909Kzb4b69Yd4uVhG4c681sezM7ORZXBrAaWF8IsYiIlDhKkEVECsc9wM2xmSGuib2W\nvTV4JKHrw3xgOvBZtm2yD9LLb2vyMEJXig+BXwldM66KrasHjAFWADOA9Ni25YCrY7EtBdoABZmX\nWUSkxDL3xH7/mll74CEgBRji7v2zrW8ODAf2A25y9wfi1vUFziUMAPkeuGDDgBURERERkWSSUAty\n7Fbco0B7YA+gs5m1yLbZUkILxf3Z9m0CdAP2d/e9CAl2pwJFLSIiIiJSRBLtYtEKmB2bMigDGA2c\nHL+Bu//l7l8T+q7F+yf2WtVYJamqhFt4IiIiIiJJJ9EEuQFxUxUBf8Re2yp3/xt4gDDN0AJgubtP\nykuQIiIiIiLFpXyC2+V72iEz2wXoRZhyaAUwxszOcffnsm1XGFMbiYiIiIhs5O55nh0o0Rbk+UCj\nuOeNCK3IiTgQ+NTdl7p7JvAqYe7Nzbi7lkJYbrvttshjKC2LzqXOZTIuOpc6l8m46FzqXCbjkl+J\nJshfA81ic2pWJFRbGpvLttmz9FnAIWZWxcwMaEeYWkhEREREJOkk1MXC3TPNrDuhPGkKMNTdZ5rZ\npbH1g82sHvAVUBPIMrOewB7uPtXMRhKS7CzgW+CpIvgsIiIiIiIFlmgfZNz9HeCdbK8Njnu8iE27\nYcRvdx9w39beY+lS2G67RCOS3KSmpkYdQqmhc1l4dC4Lj85l4dG5LDw6l4VH5zJ6CRcKKWpm5nXq\nOH36QPfuUKlS1BGJiIiISElmZngRDtIrFh9+CB98AC1awEsvQZLk7iIiIiJShiScIJtZezObZWY/\nm1nvHNY3N7PPzOxfM7s227raZvaymc00sxlmdkhO79GiBYwdC0OGwL33wmGHwWef5f1DiYiIiIjk\nV0JdLGKlpn8kzEAxnzAYr7O7z4zbpi6wE3AKsMzdH4hbNwL4wN2HxarpVXP3Fdnew+NjycqCUaPg\nppugdeuQMO+8c0E+qoiIiIiUJUXdxSLfpabNrBbQxt2HxbbLzJ4c5xhYOTjvPPjxR9h7b2jVCq67\nDpYtSzBiEREREZF8KPJS00BT4C8zG25m35rZ02ZWNdEAq1aFm2+G6dNh5UrYfXd4+GFYty7RI4iI\niIiIJC7RBLkgw+XKA/sDj7v7/sBqoE9eD1KvHgweDJMnw4QJ0LIlvPqqBvKJiIiISOFKdB7kgpSa\n/gP4w92/ij1/mVwS5LS0tI2PU1NTc5wHsGVLGDcOJk4MXS4GDoQHHghdMERERESk7EpPTyc9Pb3A\nx0l0kF55wiC9tsAC4EuyDdKL2zYNWJltkN6HwMXu/lNsfRV3751tP8/rnMzr18OIEXDLLXDkkdCv\nHzRpkqdDiIiIiEgpVaSD9Nw9E9hQanoG8OKGUtMbyk2bWT0zmwdcDdxsZnPNrHrsEFcBz5nZVGBv\noF9eA81JSgpceGEYyLf77nDAAdC7N6zY6hBAEREREZGcJVUlvYLGsmBBaE1+663w76WXQoUKhRSg\niIiIiJQopaKSXkHtuCMMHRr6J48dC3vtFf5Nku8AIiIiIlIClKoW5HjuYbaL666DunXh/vtDFwwR\nERERKRvUgpyNGbRvD999B507w4knQpcuMG/e1vcVERERkbIr4QTZzNqb2Swz+9nMeuewvrmZfWZm\n/5rZtTmsTzGzKWb2ZkGDzovy5eGSS+Cnn8IMF/vuG8pX//NPcUYhIiIiIiVFQgmymaUAjwLtgT2A\nzmbWIttmSwmzVdyfy2F6EmbAiKRPR40acOedMHUqzJ8fZr148knIzIwiGhERERFJVom2ILcCZrv7\nHHfPAEYDJ8dv4O5/ufvXQEb2nc2sIdABGALkuR9IYWrYEJ55JhQbeekl2HtvePttDeQTERERkSDR\nBLkBEN9794/Ya4kaCFwPZOVhnyK1337w3ntw331hIN8xx4T+yiIiIiJStiVaajrf7atmdiLwp7tP\nMbPULW2bSKnpwmQWBu8ddxwMGRIG9R1/PNx1FzTIS/ovIiIiIpEr7lLThwBp7t4+9rwvkOXu/XPY\n9jZg1YZS02bWD+gCZAKVgZrAK+5+Xrb9CnWat/xYsQL694fBg+HKK+GGG6B69a3vJyIiIiLJp6in\nefsaaGZmTcysInAWMDa3WOKfuPuN7t7I3ZsCnYD3syfHyaJWLejXD6ZMgV9/hd12Cy3L69dHHZmI\niIiIFJeEEmR3zwS6AxMIM1G86O4zzexSM7sUwMzqmdk84GrgZjOba2Y5tb8m/XC4xo1h1KhQhe/Z\nZ8PUcBMmRB2ViIiIiBSHUltJr7C4wxtvhO4WO+8MAwaEEtYiIiIiktxUSa+ImMEpp8APP8AJJ0C7\ndtCtGyxcGHVkIiIiIlIUlCAnqEIFuOoq+PFH2GYb2HNPuOMOWL066shEREREpDAVealpM2tkZpPN\n7Aczm25mPQor+CjUrh3mTv76a5g5M1TkGz5cA/lERERESotEp3lLAX4E2gHzga+Azu4+M26busBO\nwCnAsrhp3uoB9dz9u9igvW+AU+L3jW2XlH2Qt+aLL+Caa0JL8v33hy4YIiIiIhK9ou6DnO9S0+6+\nyN2/iz1eBcwEdsxroMnq4IPh44/hllvgsstCP+UZM6KOSkRERETyq7hKTQNgZk2A/YAv8rpvMjOD\n004LiXG7dpCaGpLlxYujjkxERERE8qrIS01vEOte8TLQM9aSvJniLjVd2CpWhKuvhq5dQ7nqli1D\n94urr4YqVaKOTkRERKR0KzGlpmOvVQDeAt5x94dyeY8S2Qd5S375Bfr0Cf2U774bzjkHymneEBER\nEZFikbSlps3MgKHAjNyS49Jql11gzBh44QV47DE46CAohC81IiIiIlKEEq6kZ2bHAw8BKcBQd79n\nQ5lpdx8cm63iK6AmkAWsBPYA9gU+BKbxX1eNvu4+PtvxS10Lcjx3eOml0KK8997Qvz80bx51VCIi\nIiKlV35bkFVqupj9+y88+mhIkM86C267DerWjToqERERkdJHpaZLiMqV4brrQpGRlBRo0SIky//+\nG3VkIiIiIgJKkCNTpw48/DB8+mkYxNe8OTz/PGRlRR2ZiIiISNlW5KWmE9m3LNttN3j1VRg5EgYO\nhEMOgY8+ijoqERERkbKrOEpNb3Xf2HZlog/ylmRlwejR0LcvHHBA6HrRrFnUUYmIiIiUTElbajqR\nfSUoVw7OPhtmzYJWraB1a+jVC5YujToyERERkbKjOEpNF0qZ6rKkSpUwHdyMGZCREfonP/AArF0b\ndWQiIiIipV9xlJpOeN+SXmq6sG2/fSgw0r079O4dHt97L5xxBliebxaIiIiIlG4lptR0ovuqD/LW\nvf9+mCKuUiV48MHQBUNEREREcpa0pabzuK9swdFHw9dfw+WXw5lnhuXXX6OOSkRERKR0SShBdvdM\noDswAZgBvOjuM83s0g3lps2snpnNA64GbjazuWZWPbd9i+LDlAXlysF558GPP8I++4TBfNdeC8uW\nRR2ZiIiISOmgUtMl3KJFoVz1a6/BTTeF1uWKFaOOSkRERCR6KjVdRtWrB4MHw+TJMGECtGwZCo/o\nu4aIiIhI/qgFuZSZODEM5KtZM0wN16pV1BGJiIiIRKPIW5ATKRdtZoNi66ea2X5xr/c1sx/M7Hsz\ne97MKuU1UEnMMcfAt9/CBRfA//0fdO4Mc+ZEHZWIiIhIyZFQghwrF/0o0B7YA+hsZi2ybdMB2NXd\nmwGXAE/EXm8CdAP2d/e9gBSgUyHFLzlISYELL4SffgpFRg44IMyjvHx51JGJiIiIJL9CKzUNdARG\nALj7F0BtM9sB+IdQfrqqmZUHqgLzCyN42bJq1cIAvu+/D+Wqd98dHn00VOcTERERkZwVZqnpHLdx\n97+BB4C5wAJgubtPyl+4kh877ghDhoT+yWPHwp57whtvaCCfiIiISE4Ku9T0Zp2gzWwXoBfQBFgB\njDGzc9z9uezbqtR00dp77zDTxYQJYSDfwIFhIN8BB0QdmYiIiEjBJV2paTN7Ekh399Gx57OAI4FU\n4Bh3vzj2ehfgEHe/Mtt7aBaLYpSZCcOHhy4YbdtCv37QqFHUUYmIiIgUnmQoNT0WOC8WzCGErhSL\ngR+BQ8ysipkZ0I5QUU8iVL48dOsWKvI1aQL77gs33gj//BN1ZCIiIiLRKrRS0+4+DvjVzGYDg4Er\nYq9/B4wkJNnTYod8qlA/heRbjRpw550wdSosWBAG8j35ZGhhFhERESmLVChENjFlSuifvHAhDBgA\nHTqA5fnGhIiIiEj08tvFQgmybMYd3n4brr8eGjSA++8PXTBERERESpIir6QnZYcZnHhimD/5tNOg\nfftQmW++Zq8WERGRMqC4Sk3XNrOXzWymmc2IDeKTJFe+PFx+eajIV79+mCbu1lth1aqoIxMREREp\nOkVeajrmYWCcu7cA9gZmFkLsUkxq1gzTwE2ZAr/9BrvtBk8/DevXRx2ZiIiISOEr8lLTZlYLaOPu\nw2LrMt19ReGEL8WpcWN49tlQjW/UqNAvecKEqKMSERERKVxFXWq6IdAU+MvMhpvZt2b2tJlVzW/A\nEr0DD4T0dLjrLujRA447LvRXFhERESkNEk2Q81tq2gnlrPcHHnf3/YHVQJ8EjydJygxOPhmmTw8D\n+tq1C4VHFi6MOjIRERGRgimf4HbzgfhCxI0ILcRb2qZh7DUD/nD3r2Kvv0wuCXJaWtrGx6mpqaSm\npiYYnkSlQgW46iro0iX0U95zT+jZE669FqpVizo6ERERKUvS09NJT08v8HESmgfZzMoTSka3BRYA\nXwKd3X1m3DYdgO7u3iE2S8VD7n5IbN2HwMXu/pOZpQFV3L13tvfQPMilwJw50LcvfPRRqNB33nmQ\nkhJ1VCIiIlIWFXmhEDM7HngISAGGuvs9cWWmB8e22TDTxWrgAnf/Nvb6PsAQoCLwS2zdimzHV4Jc\ninzxRWhFXrUqFBpp1y7qiERERKSsUSU9STru8Oqr0Ls37L473HcftGwZdVQiIiJSVqiSniQds1CJ\nb8YMOOYYOOoouOwyWLw46shEREREcqcEWYpcxYrQqxfMmgVVq4ZW5LvvhjVroo5MREREZHNKkKXY\nbLstPPhg6J/83XfQvHkoPJKVFXVkIiIiIv9JOEE2s/ZmNsvMfjaz3rlsMyi2fqqZ7ZdtXYqZTTGz\nNwsatJRsu+wCY8bA6NHw+ONw0EGh8IiIiIhIMkgoQTazFGDDDBV7AJ3NrEW2bToAu7p7M+AS4Ils\nh+kJzCDxoiNSyh16KHz6KdxwA1xwAXTsGLphiIiIiEQp0RbkVsBsd5/j7hnAaODkbNt0BEYAuPsX\nQG0z2wHAzBoCHQhTveV5JKGUXmZw1lkhMT7iCGjTBrp3h7/+ijoyERERKasSTZAbAPPinv8Rey3R\nbQYC1wPqbSo5qlQJrrsOZs4MhUVatID+/eHff6OOTERERMqaREtNJ9otInvrsJnZicCf7j7FzFK3\ntLNKTUudOvDww3DlldCnTxjI168fdOoE5TSkVERERLaguEtNHwKkuXv72PO+QJa794/b5kkg3d1H\nx57PAlKBHkAXIBOoDNQEXnH387K9hwqFyGY+/DBU5DODBx4IXTBEREREElHUhUK+BpqZWRMzqwic\nBYzNts1Y4LxYMIcAy919kbvf6O6N3L0p0Al4P3tyLJKbI44I08L16gXnngunngo//xx1VCIiIlKa\nJZQgu3sm0B2YQJiJ4kV3n2lml5rZpbFtxgG/mtlsYDBwRW6HK3jYUpaUKwdnnx0G8h18MLRuDT17\nwtKlUUcmIiIipVFCXSyKg7pYSKL++gvS0uCll0I/5e7dwyA/ERERkXhF3cVCJGnUrQuPPQYffQQf\nfBBmvHjpJdD3KxERESkMakGWEm/y5DCQr1KlMJDv0EOjjkhERESSQZG3IOe31LSZNTKzyWb2g5lN\nN7MeeQ1SZEuOOgq+/houvzwUHTnzTPjll6ijEhERkZKqOEpNZwBXu3tL4BDgyuz7ihRUuXJw3nnw\n44+wzz5hMN+118KyZVFHJiIiIiVNkZeajk319l3s9VXATGDHQoleJJuqVeGmm2D6dFi9GnbfHR56\nCNatizoyERERKSmKutR0w/gNzKwJsB/wRV6CFMmrevXgySdD/+R334WWLeHVVzWQT0RERLauqEtN\nb9zPzKoDLwM9Yy3Jm1GpaSlsLVvCuHEwcSJcdx0MHBgG8rVqFXVkIiIiUthKSqnpI919sZlVAN4C\n3nH3h3J5D81iIUVq/XoYORJuuSWUrL7nHmjSJOqoREREpKgka6npxWZmwFBgRm7JsUhxSEmBCy4I\nA/maN4cDDoDevWH58qgjExERkWRSHKWmDwPOBY4ysymxpX1hfxCRRFWrBrfdFgbyLV0aBvI9+ihk\nZEQdmYiIiCQDFQqRMm/atNA/+fff4b77oGNHsDzfjBEREZFkk98uFkqQRWLGjw+Jcp06YSDfAQdE\nHZGIiIgUhBJkkUKQmQnDh4cuGEcfDYcdFl43+69VeWuPC3s77VO6z6+IiBSdIk+QY/2GHwJSgCHx\nM1jEbTMIOB5YA5zv7lPysK8S5EKSnp6uKfIKaOVKeOwx+OyzdHbcMXXj/Mnu/y3xz3N7HNV2yRBD\n9uerVqVTrVrynMuoY8guL0l1VlY6KSmpmx+E3JPuvL5eXPtE/f4ZGelUrJga2fsn67Hys8+//6ZT\npUpq7gdM4D2Larso3rMg261eHX5fFud7FmS7ZI7tm2/ylyAnNA9yXKnpdsB84CszG+vuM+O22Vhq\n2swOJpSaPiSRfaVwKUEuuBo1oE8fSEtLJy0tNepwSgWdy83lN+G+++50bropNdfjFfT14tonGd5/\nwIB0rr8+NbL3T8Zj5ff9Bw1Kp0eP1NwPupX3LKrtonjPgm73+OPpXHFFarG+Z363S/bY8lv3INFC\nIRtLTQOY2YZS0/FJ7ialps2stpnVA5omsK+ISJmT364WFSqEsupScNWrww47RB1F6bDttrDrrlFH\nUTpsvz3suWfUUZRtRV1qugGwYwL7ioiIiIgkhUQr6Z0GtHf3brHn5wIHu/tVcdu8Cdzr7p/Enk8C\negNNtrZv7PUEG9VFRERERBJTZH2QCX2HG8U9b0RoCd7SNg1j21RIYN98BS8iIiIiUtiKvNR0gvuK\niIiIiCSFhFqQ3T3TzDaUmk4Bhm4oNR1bP9jdx5lZh1ip6dXABVvatyg+jIiIiIhIQSVNoRARERER\nkWSQaBeLQmFm7c1slpn9bGa9c9lmUGz9VDPbrzjjK0m2di7NLNXMVpjZlNhycxRxlgRmNszMFpvZ\n91vYRtdlArZ2LnVdJs7MGpnZZDP7wcymm1mPXLbTtbkViZxLXZuJMbPKZvaFmX1nZjPM7J5cttN1\nuRWJnEtdl3ljZimx8/RmLusTvi4THaRXYAUpNlJcMZYUeSi+8oG7dyz2AEue4cAjwMicVuq6zJMt\nnssYXZeJyQCudvfvzKw68I2ZTdTvzHzZ6rmM0bW5Fe7+r5kd5e5rzKw88LGZHe7uH2/YRtdlYhI5\nlzG6LhPXE5gB1Mi+Iq/XZXG2IG8sNuLuGcCGgiHxNik2AtQ2M03hvrlEziWAZgZJgLt/BCzbwia6\nLhOUwLkEXZcJcfdF7v5d7PEqQnGlHbNtpmszAQmeS9C1mRB3XxN7WJEwtujvbJvoukxQAucSdF0m\nxMwaAh2AIeR8zvJ0XRZngpzfYiMNiziukiiRc+nAobHbCOPMbI9ii6700XVZeHRd5oOZNQH2A77I\ntkrXZh5t4Vzq2kyQmZUzs++AxcBkd5+RbRNdlwlK4FzqukzcQOB6ICuX9Xm6LoszQU50NGD2rF+j\nCDeXyDn5Fmjk7vsQbnm/XrQhlXq6LguHrss8inUJeBnoGWv93GyTbM91beZiK+dS12aC3D3L3fcl\nJBdHmFlqDpvpukxAAudS12UCzOxE4E93n8KWW9wTvi6LM0HOb7GR+UUcV0m01XPp7is33Lpx93eA\nCma2bfGFWKrouiwkui7zxswqAK8Ao9w9pz+MujYTtLVzqWsz79x9BfA2cGC2Vbou8yi3c6nrMmGH\nAh3N7DfgBeBoM8s+FiZP12VxJsgFKTYim9rquTSzHczMYo9bEab0y6lvk2ydrstCousycbHzNBSY\n4e4P5bKZrs0EJHIudW0mxszqmFnt2OMqwDHAlGyb6bpMQCLnUtdlYtz9Rndv5O5NgU7A++5+XrbN\n8nRdFtssFgUpNiKbSuRcAqcDl5tZJrCGcMFIDszsBeBIoI6ZzQNuI5RI13WZR1s7l+i6zIvDgHOB\naWa24Y/mjUBj0LWZR1s9l+jaTFR9YISZlSM0sj3r7u/pb3m+bPVcousyvxygINelCoWIiIiIiMQp\n1kIhIiIiIiLJTgmyiIiIiEgcJcgiIiIiInGUIIuIiIiIxFGCLCIiIiISRwmyiIiIiEgcJcgiIiIi\nInGUIIuIiIiIxFGCLCIiIiISRwmyiIiIiEgcJcgiUqqZ2RwzOzr2+EYzezqfx5luZkcUbnSln5ml\nmtm8CN53jpm1Le73FZHSoXzUAYiIFDHf+MC9XyI7mNkzwDx3vyVu3z0LPzQxsyxgV3f/tQDHeIZs\nPy/Cz91z3kNEZMvUgiwiJYaZ6Ut9AVlM1HFkk2s8+pmLSBSUIItIpGK3wvuY2Q9m9reZDTOzSrF1\nqWb2h5ndYGYLgaGx/K6Pmc02syVm9qKZbRN3vC5m9nts3Y3Z3ivNzJ6Ne364mX1qZsvMbK6ZdTWz\nbsDZwA1mttLM3oiLs23scSUze8jM5seWgWZWMVvM15jZYjNbYGbn5/LZzzKzr7K9dnXce3aInZd/\nYse8NpfjlDOzB8zsLzP71cy6m1mWmZWLrU83s7vM7BNgNdDUzA41s6/MbLmZfWlmrbP9TNrGPd94\n3sysSezY58XO81/x59nMqpjZM7Gf5Q/AQbn86DGzD2MPp8bO9Rk5/MyHxX4uH2XbN8vMdjGzS3L6\necXsZ2ZTY59x9IbrSkRka5Qgi0gyOBs4FtgF2A24OW7dDsA2QGPgUqAH0BE4AqgPLAMeAzCzPYDH\ngXOAHYHtgIZxx9p4y93MdgLGAQ8DdYB9ge/c/WngOaC/u9dw95Pj9t2w/01AK2Cf2NIqh5hrxmK4\nCHjMzGrl8LnHArub2a7ZzsVzscdDgUvcvSbQEng/h2MAXAK0j8WyP3AKm3cvOBe4GKhOSJLfBh4C\ntgUeBN6O+6KRvXtCTl0VDiP8rNoCt5rZ7rHXbwOaAjsDxwFdc9kfd9/Qp3vv2LkeE3se/zO/hNxb\nmN3dnyLnn5cBZ8RiaArsDZyfy3FERDahBFlEoubAo+4+392XAXcDnePWZwG3uXuGu/9LSJJvdvcF\n7p4B3A6cbmYpwOnAm+7+sbuvA26J7b9BfKJ1NjDR3V909/Xu/re7T81l2+zOBu5w9yXuviQWQ5e4\n9Rmx9evd/R1gFbB79oO4+/+ANzZ8XjNrFttubGyTdUBLM6vp7ivcfUou8ZwJPBQ7J8uBe7LF78Az\n7j7T3bMIX0Z+dPfn3D3L3UcDs4CTcjl+Tufidndf6+7TgKmE5BxCUnq3uy939z8IX0Dy2qUj+888\nEdnfw4FB7r4odl29SfgSJCKyVUqQRSQZxM9yMJfQ8rrBX7Fkd4MmwGuxbhHLgBlAJqHVsT7wx4YN\n3X0NsDSX92wE5Hdg2I7A71uIeWksEd1gDaHlNifP898XgrOB1+KSwtOADsCcWDeJQ3I5Rn02PYd/\n5LBN/PodYzHH+x1okMvxc7Io7nH859uRzX+eeZX9Z55f8TH+j9x/BiIim1CCLCLJoHG2xwvinme/\nPT8XaO/u28QtVd19AbCQkPgCYGZVCd0scjKX0KUjJ1ub/WABIVHPLea8mATUNbN9gE6EhDkE4f61\nu58C1AVeB17K5RibfO5sjzceLu7xfGCnbOt3ir0OoQtGtbh19bbyGbLHkv3nmVfZz/9qoOqGJ2aW\nPZ5EZqvUTFuoAAAgAElEQVTQjBYikjAlyCISNQOuMLMGZrYtoX/v6C1s/yTQz8waA5hZXTPrGFv3\nMnCimR0WGzR3B7n/nnseaBcbGFbezLaLJakAiwl9aHPzAnCzmdUxszrArcCzW9g+V7FuImOA+wn9\nbifGPlcFMzvHzGq5+3pgJbA+l8O8BPQ0sx3NrDbQm80TwvguCOOA3cysc+yznwU0B96Krf8O6BRb\ndyChJTvRBPMloK+Z1TazhsBVW9l+Mbl/UdlgKqGryT5mVhlIy+EYW/p5Qd67eYhIGaYEWUSi5oRk\n9V3gF+Bn4K5s6+M9TOij+66Z/QN8Rhgkh7vPAK6MHW8B8Deb3u7fOPjM3ecSui9cS+iGMYUwkAvC\n4Lg9Yt04Xs0h5ruAr4FpseXrrcS8Nc8TBruNydY141zgNzNbQRisdk4u+z9NOH/TgG8IA/DWZztW\n/HzQfwMnEj77EuA64MTY6xD6bu9CGACZxn+DBhP5fLcTumv8BowHRm5l+zRgROxcn04O8xe7+0+E\nLzuTgB+Bj7Jts7Wf14aY1YosIgkx94L9vjCzYcAJwJ/uvlcu2wwCjif0Uzt/CwNNRKSMMbPfgIvc\nPbcZGiSPzOx44Al3bxJ1LCIiJVFhtCAPJ0wvlCMz60CoktSM0ALyRCG8p4iIxJhZ5dicyeXNrAFh\nqrXcWlJFRGQrCpwgu/tHhNtwuekIjIht+wVQ28x2KOj7iojIRkboqvA38C3wA6FftIiI5ENxlPBs\nwObTDzUkDKoQkTLO3ZtGHUNJF5tPuVXUcYiIlBbFVeM+pwncN93ATIMnRERERKRQuXueZ7EpjgR5\nPpvOydmQ/+ba3EROAwZXr4YffoDvv4evvoIPPoCFC+GII6Bjx7Bsv33RBF5WpKWlkZaWFnUYZY7O\ne/HLyoLPP4frrkvj33/TmD0bDjsMDjkE9t03LI0bg+XxV+maNfDjjzB9OnzxBXz0EfzySzj2ht9T\njXKambgM0nUfHZ376OTl3LvDlCnw2mswaVL4vdKqFbRuHX5H7bcfNG0K5TQPWUIsr7/QY4ojQR4L\ndAdGx6pALXf3hLtXVKsWLoxWreCii8JrixfDe+/B66/DddfB3nvDuedCp05Qs2aRfAYRKcG++QZG\njIBXXoFttoHttoP774eDDoIKFQp+/KpVwx+t/faDLrGC08uXhz9uY8fCrbeGP2hdu0LnzlCnTsHf\nU0RKlxkzYORIGDMmfEk/7TS4+2449FCoXDnq6MqeAn//MLMXgE+B3c1snpldaGaXmtmlAO4+DvjV\nzGYDg4Ercj3YW2+Fr0orV27xPXfYAc4+G156CRYtCkny+PGh5ef880MLjoiUbStXwuDBcMAB4Q/N\ndtv91xpz1FHhj05hJMe5qV0bTj89/MFbvBj69Qut17vuGl6fPDm0FIlI2fXvvzBqFLRpA+3ahcT4\n5Zfh55+hf384+ugEkmN3WLYMpk2Dt9+G2bOLJfbSrsAtyO7eOYFtuid0sMcfhzlzwlKlCjRpEppd\ndt8d9tgDWrSA5s1Dc01M5cr/3cJcvBiefTa0JDdsCNdfDyeeqNsQW5Oamhp1CGWSznvRWLwYHn4Y\nnnoqdMXq1w+OOWbT3wPFfe7Ll4djjw3L8uXwwgtw+eXhV9k118CZZ0LFisUaUmR03UdH5z462c/9\n8uXw2GMwaFDoNnHNNSFfyfVLuzssWBD6cv3yy+aLe2glbNQIevUK38SlQApcKKSwmJlvjMUdliwJ\nifKvv8KsWTBzZrj/8PPPUK8etGwJBx7431Kv3sZjZWaGW6kDBoQ+zGlpcMYZSpRFSrM//oB77gnJ\nZ+fO4c5S0ySeHyMrK9z5euCB0OBz662hC0b54ho6LSLFbsmS8H/+qadCQty7d2j/28SaNaET8rRp\n4ZbX99+Hf8uXDw2Fu+wSlp13/u/xttvmffBEGWFm+Rqkl5wJ8pZkZsJvv4UL5ptv4Ouvw1KlSuio\nfOSRkJoKe+2FWzkmTYKbboKMjNCX5/jjdQ2JlCbLlsG998KQIXDxxaElZocSNtP6p5/CzTfDvHlw\n++3hLpi+0IuUHmvWwMCBYTnzTLjhhnCTHHdM/9kLTU55ZNlJkHPiHlqbP/8c0tPDsnRpuL96zDH4\niSfx+tcNufnmMOPFoEGwV45FsUWkpMjIgEceCcnxySeHO0UNGuTzYO6hM+D//gdr18K6df/9u25d\n+FadkrLpUr586CNRo0b4gl4I37zffx9uvDG0Lj/yCBx8cIEPKSIRysqC4cPhttvCrDZ33w271vwz\n/GefOBEmTcLmzs0xsZO8iSXCub1eRhPknMyfHxLl8eNh3Dho2pT1J57M4IwLSXu6AWefHf6g1q5d\neG8pIsXjww/hiivCWIMHH8zhFuUGS5eGO07z5/+3LFgQRvcuXx6anzf8CyHhrVQpdAiuVCksFSqE\nBHr9+k2XzMzQh2vVqpCtV68ellq1wjfxHXbYdGncONwSbdx4i6MDs7LgueegT5/Qd/reezfpQSYi\nJcR338Fll4W7QQOvmcfBv74Q5m6bOTPc6W7XDtq1w1q0UIJcCJQg50dmJnzyCbzxBrzyCn9Va8KN\nNR7hrTkteWhQCmeeqW4XIiXBn3+GW5PvvQcPPQSnnhr7v7tgQehyNW0a/PTTf8v69SEpbdDgv2XH\nHUPGuc02YaldO/xbkHmUMjJCorxyJaxYEQJdtCiMGNywzJ0bxlQsXBji2Hnn0J9wn33CsueeoSU6\nZuVKuOsuGDYsDDS8+GL9nhIpCVauDGMKnh+1nn5HTOCCn/pSbsmfcMop4ZdWauomX5JzS+wkb5Qg\nF1RWVpjFf+RIPn9pLhf6UFrsU5HHX96eHeqrH5BIshozBq66Cs7plEna8V9S48v3Qreqb78NCeoB\nB4REs3lz2G23sNStm3xZ5bp18PvvYeT5jBkwdWpYfvopdEo89FA4/PAw79POO/P9dOPCC8Mc708/\nHfJqEUlOk8ZnclGXtRxd6VMGrLyMOmceDeedF/5fp6TkuI8S5MKhBLkwrVnDv8+9wu23ZDBsSUce\nOvdrOj1yOFajevHGISK5+vtvuLLLP3z7ZQYjm9zGwbNGhCQ4NTX80TnggDC1UbIlwnmVkRHKhn7y\nCXz8cfgin5UFxx5LZvsTGfjzCfR/uAq33Qbdu5f8jytSmqz+Yxk3nPEbb361A0NaPMixvfcLrcVx\n09LmRgly4VCCXBTc+WrIVM6/bjv2WfsVT/b9nZrXdgv9CUUkGlOn8s5d33Dx6ydwZqWx3H32D1Tt\n2C60rNaqFXV0Rc899J9+550w+f/HH/NTy/+jy6IB1Gm2DcNHVWD77aMOUqSMW7SIz3qO5ryXT6L1\nTgsZNLwGtY/cJ0+HUIKcuNTUVLp06cJFG0orx1GCXITWrIFrLvibiW9nMLrieRzUt124p6sajyLF\nY8kSeO45MoaP4qZfL2K0dWLkfYtJvWQ3NZmuXg3vvkvGqBe57a2DGFHufIb3/Zljbzoo11u3IlJE\nliwh6777GfBoFQba1TzxcAb/d/F2+TqUEuTEHXXUUXTp0oULL7xws3WFnSCr022cqlXhyRe35b4R\nO3BiubcZMGJ7slq0DFVHdPGKFJ2ZM6FbN2jWjLkf/MaRGRP54fBL+faX2qReuruSY4Bq1eD//o8K\nr4ym3+KLGHXl51x0V1Nu2G4omfc/FGbjEJGitW4dDBjAkt0O5aQXz2Fsyz58NatmvpPjsiwzMzPq\nELZICXIOTjsNvvymPK/V7MqpO37OilsfgKOOCn/ERaTwfPNNKCd11FHQqBFvPTqHgz55iFO61ubN\nt4w6daIOMEnVrs1R95/Adwu25/sWZ3LMgGP4s+nBoSrS339HHZ1I6TRhAuy9N5+8upj9K/9Ay7P2\nIv3TSjRqFHVgRWPAgAGcfvrpm7zWo0cPevXqles+qamp9O3bl4MPPphatWpxyimnsCw2jeacOXMo\nV64cw4YNY6eddqJdu3YADBs2jD322INtt92W9u3bM3fu3I3HmzhxIs2bN6d27dpcddVVuHuxtbYr\nQc7FTjuFaZQb7FuXg9d/wsw2l4TCI/36hcE0IpJ/M2fC6adDx47QoQNZv87hDm7l8j61ePXVMJWb\niktt3XZ1jLc+rk2bS1tyYNUf+Hx6dWjWLFQlWLky6vBESoclS6BTJ/yKK3n8qDGc+uv9PP5UBe67\nb4tTmpd4Xbp0Yfz48axYsQIILb4vvvgiXbt23eJ+zz77LMOHD2fhwoWUL1+eHj16bLL+ww8/ZNas\nWYwfP5433niDe+65h9dee40lS5bQpk0bOnfuDMCSJUs47bTT6NevH0uXLmWXXXbhk08+wYrrjuKG\nbDzqJYSSnIYNc69b1/3VJxe7H3ec+777uk+bFnVYIiXPihXuPXuG/1D9+7uvXu0rV7qfeqp769bu\nCxZEHWDJNXZsOK1P3Pmn+7nnujdo4D5qlHtWVtShiZRcr7ziXq+er+15vV9yYYa3bOk+e3bhvsVW\n85/QybPgSz60b9/en376aXd3f/PNN71ly5Zb3D41NdX79u278fmMGTO8YsWKnpWV5b/99pubmf/2\n22+bHH/o0KEbn69fv96rVq3qv//+u48YMcJbt269yfEbNmy4yfbxcjuPsdfznJeqjSYBF1wQBpH3\nvHt7bmv1Dn5VDzj6aHjySfVNFkmEO7z4YiiMsXJlmP/3hhv4bXFVDj001OqYPBnq14860JLrpJPC\nDHGPvFCXq2o/S+bzL8EDD4Q7X7NmRR2eSMmyalWYv7hPH/58+g3afXsfi5aU57PPYJddijmWwkqR\n86Fr166MGjUKgFGjRtGlS5et7tMors9J48aNycjIYMmSJTmu//333+nZsyfbbLMN22yzDdttF/py\nz58/n4ULF9KwYcNcj13UlCAn6KCD4KuvYMK7xrnvXcDa9z8JCfIZZ2hwjMiWLF0KZ54Jd9wBL70E\nQ4dCnTp88AG0bh3G5g0ZEqo6S8E0awaffhpqjnS891D+ee8rOOusUHhk4MAwr7KIbNkPP4Q/+ikp\nTB05lVbdW3HkkaFKdI0aUQdXvE4++WSmTZvG9OnTefvttznnnHO2uk98H+K5c+dSoUIF6sQNKInv\nItG4cWOeeuopli1btnFZvXo1rVu3pn79+sybN2/jtu6+yfOipgQ5D3bYIbRyrVsH7a7YjSVvfR5K\n1rZqpRYakZxMnBiq2zVqFAbkHXYYAKNHh++Wo0aFmRQ1SUXhqVUr3PFq0gQOOyKF30/qHioOvvJK\nGAw5f37UIYokr5EjQxGi3r15t/NwjulYhf794c47y+a4iCpVqnDaaadx9tlnc/DBB2/WopuduzNq\n1ChmzpzJmjVruPXWWznjjDNy7Td82WWX0a9fP2bMmAHAihUrGDNmDAAdOnTghx9+4LXXXiMzM5NB\ngwaxaNGiwv2AW1DgH7eZtTezWWb2s5n1zmF9qpmtMLMpseXmgr5nlKpUCXeKDzsMWh9VmZ96PAp9\n+oTbmO+8E3V4IskhKyu0GF9wAYwYAQ8+CJUr4w733RcG4b33HsQGMUshK18eHnsMLr44FBv88u9d\n4YMP4NhjQ8vY++9HHaJIcsnKgt69w++tyZN5hvPp0gVefTXchCnLunbtyvTp0xPqXmFmdOnShfPP\nP5/69euzbt06Bg0atMn6eKeccgq9e/emU6dO1KpVi7322osJEyYAUKdOHcaMGUOfPn2oU6cOs2fP\n5vDDDy/cD7elz+IF6ENrZinAj0A7YD7wFdDZ3WfGbZMKXOPuHbdyLC9ILFEYMiTMqvTaa3CofxKa\nxK6/Hq6+OurQRKLzzz+h795ff8HLL2/sWLx+fWgt/uST0MK5lYYIKSRvvgkXXhgaxo4/Hpg0Cbp0\ngV69wjcVNd9LWbd6NZx7Lvz9N/7Kq9z5+HY88wyMGxeq2he1ZC8UMm/ePJo3b87ixYupvpUKw1sq\n5FHUkq1QSCtgtrvPcfcMYDRwcg7blcrfwBdfHBrHTj4Zxq04LNzGfPrp8EcniS92kSIzd27oWFy/\n/iaj7tasgVNPhZ9/ho8+UnJcnE46CcaODY35o0YRmu2//DL0B+/WTdNWStm2eHG4A1y7NhnjJtKt\nz3a88Uboy18cyXGyy8rK4oEHHqBz585bTY43SOZkPy8KmiA3AOJ7TP8Rey2eA4ea2VQzG2dmexTw\nPZNK+/b//fF57qPG4a//Rx+FF5K8SoxIoZo+PfQ9uugieOIJqFgRCGNYjznmv76xNWtGHGcZ1Lp1\n6FVx442htwuNGoUuFwsXhgxacyZLWTR3LrRpAyedxP8eG8apnSoyf374r1GvXtTBRW/16tXUrFmT\n9957j9tvv33j69WrV6dGjRqbLDVr1uTjjz8GNu9GUVKVL+D+iXxN+BZo5O5rzOx44HVgt5w2TEtL\n2/g4NTWV1NTUAoZXPDb88WnfHpYs2Y6ekyaF7hanngpjxmh4vpR+n3wSrveBA+Hssze+/OefcNxx\noYFm4MCyOcglWeyxR/gxHXccLFoE/ftXx954A668Mgzee/dd2HbbqMMUKR4//hj65F99NSsv6kXH\nE0JSPHJk6S7+kRfVqlVj1apVm72e02sbTJ48uShDSkh6ejrp6ekFPk5B+yAfAqS5e/vY875Alrv3\n38I+vwEHuPvf2V4vcX2Qs/v99/D/7fTT4a7bMrBzzg73ll99VUmylF4ffRSS4+eeC/8BYubODS3H\nnTuHwm6lpFGhxFu6NFT3btEi9AhLKeehW9jEiaF/sup7S2n3/ffhm+Ldd7O04wUcfzzstx88/jik\npBR/OMneB7mkSLY+yF8DzcysiZlVBM4CxmYLbAeLtbebWStCUv735ocq+XbaCT7+OJRr73FtBbJG\nPR+mvTjtNFi7NurwRArfhpbjF17YJDn+6afQanzZZZCWpuQ4mWy3XciD584N45IyMi1MLdKhQ2hJ\n/vPPqEMUKTqzZoXk+MEHWdj+AlJTw6xuTz4ZTXIsyatACbK7ZwLdgQnADOBFd59pZpea2aWxzU4H\nvjez74CHgE4Fec9kV7dumL7qm2/gsqsqkPXcC1C5cmhWXrcu6vBECs/nn8P//V9oOY6br23q1PAH\n55ZbNKFLsqpWLcxu8c8/YQqrtesM7r4bTjklfNFZsSLqEEUK3+zZ4bbWvfcy55BOtGkDnTpB//76\nEi+bK1AXi8JUGrpYxFu5MtzGbNoUhj6ZQUqnM0Ki/Pzz6ogpJd/MmSELHj48tDzGfP01nHACPPpo\n6IYvyW3t2tAFZu3aUEekciWHHj1g2jQYPz7cARMpDX7/HY48Em68kZ+PuoS2bUPPou7dow5MXSwK\nS2F3sVCCXIRWrw5TwG2/PYx86l/Kn9ge9toLBg3S11UpuRYuDCNT09Lg/PM3vvzVV+FL4dNPQ8ct\nznouySQj479pq994A6pVyQp9L1avDllz+YKO5RaJ2F9/hYo53bvz0/E9ads2/Pq66KKoAwuUIBeO\nZOuDLFuw4Tbm8uXQ6fzKrBvzRhjQdNddUYcmkj///BNajLt12yQ5/vLLkBwPGaLkuKSpUCHMj9yo\nUZiJZ+XqcvDMM6FZuUePqMMTKZg1a8JUhmeeyY/te3L00XD77cmTHEvyUgtyMVi7NvTzy8qClx9d\nRMWjDw/3di65JOrQRBK3fn3IgnfaKcxzHLsL8sUX4e/PsGFhtZRMWVlw+eUwYwa88w5Uz/on3Cm4\n4oowFZxISZOZGQYRb7MNP/Z9hrbtjDvvDGUKkolakAuHuliUUBkZYTBAVha8dM8vVDjq8NBKc9xx\nUYcmkpg+fUJT8YQJGycK/fzz0GI8fHjoeywlW1YWXHppmIVk3DiotvjXUPxl5MgwuEmkpHAP3/h+\n/ZVZ979F2+Mrcvfdm9z4ShpKkAuHuliUUBUqhJmw1q+HzjfvQsYLL0OXLqG5RiTZvfhiWF56aWNy\n/NlnITl+5hklx6VFuXIweDDssku4G7Cm3s7h537uuSFrFikpBgyAzz9nVr9XaXt8Rfr1S87kOJkN\nGDCA008/fZPXevToQa9evSKKqHipBbmYrV0b7vjUqAGjjnuW8nfeFu5R160bdWgiOZs6NUzjNnEi\n7LsvEJLjk08ODYvt20ccnxS69evhwgth/vwwjqLKyMFhapIvvoCqVaMOT2TL3n4bLrmEmaO+od25\n9bjnnjAQNVklawvyokWL2HXXXZk/fz61atUiMzOTBg0aMH78ePbbb7+ow9uMWpBLuEqVwsDwZcvg\n/Pe6sL7TOWHu0X//jTo0kc0tXx7mOn7kkY3J8bffhkt2xAglx6VVSkroU16vXvgi9O95l4RSY5df\nHm5diySrmTPhgguY/dBbJSI5ToRZ4Sx5Va9ePdq0acOYMWMAGD9+PHXr1k3K5LgoKEGOQOXK8Prr\nYbasixfcQVb9BqHjn/7wSDJxD7NVdOgQOtADP/wQnj75JBx/fMTxSZFKSQndZ7bbDv7vVOPfgU+E\nCkhDh0YdmkjOli2Djh2Ze8OjHHPDfqSllfzkGMKv4sJY8qNr166MGjUKgFGjRtGlS5dC/GTJTV0s\nIrR6dUg2dts5g8HfHES5Sy5OjlnLRSBkwYMHh/4UlSsze3aoDXLvvaFLqpQNmZlw9tlhtqxX+82i\nYts2m3S3EUkKmZnQoQOLmrbmiMm3c/nlJaeSZ7J2sQD43//+R4MGDfjwww9p3bo1M2fOpGHDhlGH\nlSPNYlHKrFoVblPvvdMKHpu4G/bKy9CmTdRhSVk3bRq0bQuffAK77ca8eeGyvPFGzU5YFmVkhMqI\nFSvC8x1HU/6OW2HKlDDZu0gyuOYaln77O6lLXubMs4xbbok6oMQlc4IM0K1bN7744gu23357Jk2a\nFHU4uVIf5FKmevUwndI3s2vR+8jP8LM6hZExIlFZvTpM3P3gg7DbbixaFHLlnj2VHJdVFSqEySyW\nL4eLJ3Ui65BD4Zprog5LJBgzhn9enUT7FS9yfAfj5pujDqh06dq1K9OnTy9T3StALchJ4++/w+3r\nM7dP5+bVfSE9PYzoEylu3bqFJsNnnmHp0nBdnnEG3Hpr1IFJ1Favjt3xar6ORyc1xwY+GEZsikTl\nxx9ZfdixtG80nb1a1+Cxx/I3IC1Kyd6CPG/ePJo3b87ixYupXr161OHkSl0sSrFFi+CII5wrKg2j\n12FfhT6gIsXp7bdDP/hp0/jHa9C2LRx1FPTvX/L+6EjRWLEi3FFou/sf3DvpQOy7KVC/ftRhSVm0\nZg1rDzqck/wN6h/UiOHDw1zeJU0yJ8hZWVlcc801rFq1iiFDhkQdzhYpQS7l5s6FI9pkccvaW7io\n3y5hMlKR4rBkCeyzDzz/PGsOOpL27WHPPSmRLTJStDbcWTirznvcXGlA6CdWEjMTKbncyTjvIs5I\nv5LyB+/P6NFG+fJRB5U/yZogr169mh122IGmTZsyfvx4GjRoEHVIW6QEuQz4+WdIPTyDB/53BZ3S\nL4f99486JCnt3EO/40aNWNvvATp2DHPgltQWGSl6G+94rX2IXteVh6uuijokKUPWPzWU827YgWUH\nt+f1N8tTsWLUEeVfsibIJY0G6ZUBzZrBhPcq0KvcIN48/vHQQVmkKI0eDdOnk5F2N2edFSo9Dh2q\n5FhyV68eTJpkPLS+O0/3/RVmz446JCkj/JtvuaxHRRbsfjSvvF6yk2NJXgX+82dm7c1slpn9bGa9\nc9lmUGz9VDMrGyVYCmjPPeGtSVW4aOVA3ms/ALKyog5JSqv586FXL9Y/8yznX1aZdevg+ecpsbcr\npfg0bgwTJ1cgrfydPH/Cc/o9JUXO/17GNUd/x/eNOjB2UlWqVIk6IimtCpQgm1kK8CjQHtgD6Gxm\nLbJt0wHY1d2bAZcATxTkPcuSAw+EV96uQufvbuCzbsOiDkdKI3e4+GL88iu47OkDWLAglEJXi4wk\nqlkzmPBhVa75rTtvdHsr6nCkNHPnttbvMrnisbzz5XbUqBF1QFKaFbQFuRUw293nuHsGMBo4Ods2\nHYERAO7+BVDbzHYo4PuWGW2OKs+zI7I45ZmTmfLIx1GHI6XNU0/hf/7FNctuZvp0GDsWtchInu25\ndznefmkN3Ya35t1hf0QdjpRS/U/4kDFzD+bdKduzzTZRR1O4zExLAZfCVtAEuQEwL+75H7HXtrZN\nctYpTFLHdd6OJ+5YQodezZg5UX98pJDMmQM33cRtrd4h/cMUxo1DLTKSbwec0ohXr0rnnEur8VH6\n+qjDkVLmsWt+YfC7TZj0QQW2b1i6bnG5u5ZCWgpTQXsZJhpN9tQ+x/3S0tI2Pk5NTSU1NTVfQZVG\np97UgtUzJ3DsCfvwwXf/svMelaMOSUqyrCy46CL6t3qZMel1+eADSl2LjBS/wweexguTr+O0k+5i\n3OSqHHhg1BFJaTDikX+4d1AVPnzqRxq0OirqcCTJpaenk56eXuDjFGiaNzM7BEhz9/ax532BLHfv\nH7fNk0C6u4+OPZ8FHOnui7MdS9O8bY07Tx40lPt+PJkPZ9ShYSNNTiv59MQTPNZ/FQ+mXMeHHxpJ\nPr2llCS//srYfW/lkkrPMPH98uy1V9QBSUk25sUsepy3jMldR9D8KZU3l7yLapq3r4FmZtbEzCoC\nZwFjs20zFjgvFuQhwPLsybEkyIzL0jtxZbXhtDtoBX/+GXVAUiLNmcMzN8yg/9peTJqk5FgK2c47\n0/Ge1jxU+3bat3d++inqgKSkevtt6H7RGt5peT3NH+8RdThSxhQoQXb3TKA7MAGYAbzo7jPN7FIz\nuzS2zTjgVzObDQwGrihgzGVb9epc+8HJdF45mGMOW6MpkiVvsrIYc9IIbrR7mJhegaZNow5ISqXL\nL6dTo0+487DxHHMM/P571AFJSfP++3D+Oet4o9JZ7PvWXZp3UoqdKumVUP7Kq1x/4RI+2vUCJqVX\n0OAqSchbV4zjoqcP4d3Pa7LPAfqDI0Vozhw46CAGdfueQS/V46OPoH79qIOSkuDTT+Hkk7IYY2eS\n+r13fCoAABrESURBVMKlcMwxUYckJZgq6ZUxdtqpDLhkNvv/OZ4TT3DWrIk6Ikl2741ayIVPHsSb\no1YoOZai16QJ3H03PSaexIXnr6ddO1iyJOqgJNl9+y2ccoozsuGNpF7ZUsmxREYtyCVZZiZZ7Y7l\n/L8f5K8G+/L661CpUtRBSTL65KMs/q/tCl6+8B2OePLsqMORssIdjjsOjjySvqtu4t13w63zWrWi\nDkyS0Q8/QNu28HibFzj17yHw7ruQkhJ1WFLC5bcFWQlySbd4MZkHHMxZjT/D69Xn/9u79zgd6/SB\n45/LDHIqkR1EZNdxSztSVqQZOVcOUamcdVKxSq1TJXIqoZAlp6VEaootEsmolrTO50WFcRozBhnn\nZ+b7++N6Zox+M9ZhZu6Z57ner9fzmuc0z1xuM/d93d/7+l7fOXOsVMtcaPVqaBpxig9K96bx5lH2\nC2KyV0wM1KiB+2YJPSZXZ80azXsKFfI6MJOT7NwJEREw/LENtJvZVIeSw2xNMXP1rMQiWIWFEfrJ\nLGbtqMnphBN06qQtbo0B2LQJ7mviY5I8ReO53Sw5NtmvbFl46y2kU0feHXGWypWhRQs4fdrrwExO\nsWcPNGgArz0bT7sZjeCjjyw5Np6zBDkQ1K5Nvtf7EXU4kn0xSXTrplc2TXDbsQMaN3aMLjGMFq/c\nClWreh2SCVadOkHp0uQZPpRJk6B4cXj4YTh3zuvAjNcOHNCyir91O8tTnzSEvn3hnnu8DssYK7EI\nGM5B+/YcTypIw18nctddwsiRkAXLk5tcYPduqFcPXqv1NV0PDIboaKvlM97avx/+8hdYuJCzt9Sg\ndWsts5g50341g9Xhw5oLt33E8cr2Dnoc++ADO3CZTGUlFsFOBCZOpMjmH/nqoal8+y2kWbnbBJH9\n+3VEplfbfXRd2g5mzLAMxHivdGkYNQo6diSfO8Mnn0BcHDz1lJWFBaNjx3T+5v33Q/9rx2o92Pvv\nW3JscgwbQQ40O3ZAnTocmv4V97x4O507w9//7nVQJrvExemITPtHz9H3k9vhhRegc2evwzJGOQet\nWkG1ajB0KImJmiTVrAnvvGO5UbA4fhyaNoXwcBjT5jvkkYdhxQps5SKTFayLhTlv3jzo3p19X66l\nXqvi9OwJ3bt7HZTJanFxOnLcogW8ceol+OUXiIqyrMPkLLGxWmrx8cdQrx5Hj0L9+tCkCQwZYr+u\ngS4xEZo1g8qVYWK/3eSpUxv++U9o1Mjr0EyAutIE2aa0B6IWLWDlSm584WGWLFxIZKO85MkDzz3n\ndWAmq8TH6yzwBx6AQZFLof0sWL/esg2T84SFwZQp0K4drFtH0WLFWLQIIiO1EmjQIPu1DVQnTsB9\n90HFijBxxG/kuft+vcRpybHJgWwEOVAlJUHz5lCqFLv6TyIiUnj5ZUuSA9Hhwzpy3KwZDPnbIeT2\nGpqANG7sdWjGZOzFF3U5av9Vjrg4HUlu2dKS5EB04oTWG5cvD1Mm+sjT4gF9MH68/WebLGWT9MyF\nQkL0Eua6dZSfMYjoaBgxAt57z+vATGY6fFhHjps0gSFvJCMd2kOHDpYcm5xv2DBNkCdOBKBECV1l\nb+5cePVVa1UZSE6e1Ktb5crB5MmQp9cLOogzZowlxybHshKLQFa4MMyfD7VrU75MGaKjuxIRoS/Z\nSHLul5AADRvqbdgwkKHD4NQpHX4zJqfLnx9mz4Y6daBuXbjlltQkuX59fcsbb1j+lNulJMdlyuiF\nrZDxY2HJEli+HPLm9To8YzJkCXKgCwuDhQuhXj3KlyrF0qXNiIzUlyxJzr2OHNHEuH59ePNNkO+W\nwbhxsGqVrZZnco9KleDtt6FNG/jpJ7j2WkuSA8ipUzolpmRJmDYNQj79WHdY338PRYt6HZ4xF2U1\nyMFixQrdU0VF8WuZu4mMxGqSc6n4eK2guOcedDGY/fugVi2rOza51zPPaHeLqCjIo5V/KTXJLVpY\nkpwbJSbq/11YmLZiD/12EbRvD4sXQ/XqXodngojVIJuLq11b17dv3Zqb435i6VKtSX7nHa8DM5fj\n4EGIiNBJ3yNHgpw+pX1ln3vOkmOTe737rv5yDxuW+lTKSPK8edCnj9Uk5ybHjum8iHLldGG80NUr\ntWtJVJQlxybXuOIRZBEpBnwMlAN2AQ87546m875dwG9AEnDOOXdnBp9nI8jZYf586NIFFi5kT/Fw\nGjTQk/pXXrERmpwuJka7VXToAP37g6DLi5OUpCc/9h9ocrP9++GOO3QWV9OmqU/Hx2uyVasWjB2b\nOsBscqiEBD1Xr1VL5+Dl2bRBz+inTNEeb8ZkMy9GkPsAi51zlYAl/sfpcUCEcy48o+TYZKP77oN/\n/AOaNuWmoxv47juYM0dbUdr5Sc71889Qrx5065bmZOatt2DbNj3wWHJscrvSpbXzTseOsHlz6tM3\n3KBzujZsgE6dwOfzLkRzcbGxeoUrMtJ/MrNxvWbLY8dacmxynatJkJsD0/33pwMtL/JeO3rnJA8+\nqDushg0puetHli2DZcs0+UpO9jo483tbt+pBp3dvXTkagFmzdFLe3LlQsKCX4RmTeerWhdGjNZna\nvz/16euug6+/hkOH4OGH4cwZD2M06dq7V+dFtG7tnzi8fp0mx2PGwEMPeR2eMZftahLkMOdcrP9+\nLBCWwfsc8I2IrBKRJ6/i55nM9NBDOq34gQcotnYJS5boYGSHDnDunNfBmRRr1mhZxZAhOo8J0Eku\nPXvCggXaO8mYQPL44/DUU5okHz+e+nTBglqPnCeProF04oSHMZoL7NihV7i6dIEBA0BWr9K6mHHj\nLDk2udZFa5BFZDFQMp2X+gPTnXPXp3lvgnOuWDqfUco5d0BESgCLge7Oue/TeZ/VIHth2TLdgU2c\nyMnGrWjTRltTzp4NBQp4HVxw++YbeOwxXUehVSv/k6tX64EnKkqPSMYEIufg6adh927417+0Z7Kf\nzwdPPAE7d8IXX8D111/kc0yWW7VK+xwPHKjnNSxapCc5kydrGwtjPHalNchXM0lvG1pbfFBESgFL\nnXNV/sf3DAASnXMj03nNDRgwIPVxREQEESmrWpistXq17sh69uRs91507iLs2qXHpeLFvQ4uOM2a\npYPEn34Kd9/tf3LtWp28NGGCrsdrTCDz+aBtWzh7Vv8Q8uVLfSk5GXr10ospCxbATTd5GGcQS8mF\nJ03y75JmztQlxKOitFzGGA9ER0cTHR2d+njgwIHZniC/BRx2zr0pIn2Aos65Pr97T0EgxDl3XEQK\nAYuAgc65Rel8no0geykmRocBatYkedx4+g7Ix7x5usZI+fJeBxdcRo+GUaPgq6/gllv8T65Zo8nx\n+PFa5GdMMDh7Vq9whYbqZa3frbw2apT+vXz5Jdx2m0cxBqmPPtI5EVFRULeO0xZ9EybojuvPf/Y6\nPGNSeTGCXAyYA9xEmjZvIlIamOScu09EKgCf+b8lFJjpnBuWwedZguy1xEQdDjh6FGbPZlxUKYYN\n04NPeLjXwQW+5GTt9/rFFzohKXVU7D//gfvv14NPaq2FMUHizBmdWFyggI5Qpim3AG180b27XnW5\n916PYgwizulJyejR/pP4m09A585aDvPZZ3DjjV6HaMwFsj1BzmyWIOcQSUkweLAWvn74IZ8drc8z\nz2izd1uHIuucPKndrfbv/11py/z52ttq6lQd4TcmGJ05oyfvR47A55/Dtdde8HJ0tHa3GD1a32ay\nxrlz0KOHrhS9YAHclPSr1laEh+sJ/DXXeB2iMf+PraRnMkdIiE5DnjED2rXjwY0D+fwTHx07wnvv\nWa/krLB/v7ZHuuYa7feamhxPmgRdu+qQsiXHJpjlz69DxZUqac/DgwcveDkiApYuhX79dPdl7Soz\n39Gj0KyZDhQvXw43LZ+tq4F07aodkSw5NgHGRpBNxg4c0GHNo0f5ZdCHtHi5EnfdpS2U08yXMVdh\n7VqdH/nMM9C3r3+9j7NndQbSwoU6TFOxotdhGpMzOKdXuN5/X4tf77xw7anYWK3GKFkSpk+HwoU9\nijPA/PyzVnk1agQjXz9O6AvdYcUKrWupUcPr8Iy5KBtBNpmvVCkthn3iCSq0r8Py1iM5sC+Zhg0h\nLs7r4HK/zz7TA86oUTryJYJ224+IgD17tPbYkmNjzhOBV189vzLb1KkXvBwWBt9+qwuL1KkDu3Z5\nE2YgiY7WbdmjB7zbdCGhNarrpMk1ayw5NgHNEmRzcSLa3HLVKoqs/Ia5P99KnVK/cOedsH6918Hl\nTj6fTsZ74QWd5NKmjf+FOXPg9tt1qObzz6FoUU/jNCbHatkSvvsORoyAdu30+r9f/vy6+nrnzlC7\ntr7NXD7n4O23tdPeh2OP0O2Hx+HZZ3V+yuTJUKiQ1yEak6UsQTaXplw5WLCAPG8NZ+iqRgwr/jYN\nIn1MmWJ1yZcjNlZHjVev1lvNmkB8vB6FXntNZ+j166fLhRljMla1qv4RXXed9nhbujT1JRHtIz59\nunaJe/NNq0u+HL/9ptttzuxkfuoygQbPVtLuFBs36g7MmCBgR2Fz6UR0stimTbRt4+M7V4/RL+2l\nU+vjtuzrJVixQhPiu+7S8uIbivq0r3G1alC6tBYk16rldZjG5B4FC+rs4QkToH177fgSG5v6cqNG\nWqk0d64uT334sHeh5hZbtsCddzpuOLKD7+OqcNOWhfDDD/DWWzZqbIKKJcjm8l1zDfTpQ9VdX7Hy\n2RmwYD533riPLVFbvY4sR0pKgqFDdTLe+PEw+A1HyOKFWk7xySe6pvSoUba2tzFXqmlT2LoVbrhB\nV9d5911tDYf2E1+2DCpX1pLZH3/0ONYcyjmYMM7HPbVO0+doXyac6kj+Dybr2UXlyl6HZ0y2sy4W\n5qq5hCNMfXIFvef+lQEVPuC54TeRp/n9/2/Vq2C0Z4+WSIaEwIzpjrJbvobXX4fjx2HgQF0VTy57\ncq0xJiObNmmR/4YNOqGvU6fUfdG8efDkk/D889o1xnZRKv6/h3midQIx20/zUc1RVB7SQScL277J\nBABbKMR4bvvmc3Ro+RtF4n5hat6nKdvuHujQAf7yl6Db0TqnbVt79IBez5/hpeLTCJnwnr742mua\nGFudsTFZZ8UKTZB37IDnnoMnnoBixdi7F7p00Xl9M2ZAlSpeB+qR5GT44QcWDVxOl6XteazaegZP\nLEG+Ond4HZkxmcoSZJMj+HwwfDiMGe1jZL15tFv7ElKooNYXNG+ufUsDPDHcvx+e7ebYvu4kM2q8\nQ81lIyEyUg/SkZFBd7JgjKdWr4YxY3QCbOvW0L49ru7dTHg/D6++qjl09+4Bv1tSzmlR9scfkzB7\nEb1ODmKp1GfKFOHeVtf+7+83JheyBNnkKGvWaJulP5RwjH96PRXXztEDVHw8NGmil+8iIqB8eY8j\nzTzJx44zud8v9J9agW4hk+hfcQ75H2sNjz4KZcp4HZ4xwe3gQR0y/vBDHT5+9FF2hD9M57E18CUJ\nEyboxa6Ac/SoLtG5cKH2tS9QgKjqA+m+rDVt2uZlyBAoUsTrII3JOpYgmxzH59O5MsOGaalB796Q\nf+/PupNetkxv+fPD3XfrhLUaNfQIdd11Xod+aeLj4aefYOVK1s3fR4+1nTlduDhTuizn1m51dVlc\nY0zOs2EDzJ4N8+eTHLOPaRWH0m9bex5vdYqBY66nyLW5+CrP3r1aXrJ8uX7dvFlX+mjShB1VHuDF\n9yqwc6cwebI+bUygswTZ5Fh79miCvGmTJstt2virDJyD//4X/v1vbXG2Zo0euEqW1NZnlSqdv/3p\nT/p8aGj2Bu8cHDumdYzbtulM+W3bdJWU+HgO3daQV473Zt6u6gx8HZ58Pj8hIdkbojHmKuzdCwsW\nELdwNX9f1IBFJ+syqPqndGqeQMhtt2hXjD/+Mfv3Pf/LyZO6L9q0SW+bN+t+6cwZXSEl5VarFr+d\nK8DgwbrwYO/euj/On9/rf4Ax2cMSZJPjLVkCL72kO+a334a6ddN5k88H27dr4rx9+/nbzp06Ylui\nhPYMTrldf72uOHfddee/Fiyo09Pz5dOvefPqwc3ng3PnLrwlJuolyLS3Q4f0oLlvn34FTdCrVNHF\nCapU4fjN1Rm7qBKj38lDu3Y67+7667N1cxpjssDKLw7xcm8hIT6ZNytMpNmh6cjBA1ChgpaElSt3\n/usf/qCt5W64AYoXz5y2GElJ2rD50CGIizt/i4nRtbN37YJff9UT94oVNYG/5Ra49Vb9evPNqfMc\nTp+G99/XgYmmTbXdZMmSVx+iMbmJJcgmV0hOhpkz4ZVXdJC4Xz+tsLgkPp8uArBvn86EO3AAjhzR\nA0XaBPfUqfMJ8Nmz+tXn0yQ5JWFOuRUpcmGCXbSoHuzKltW64TJl4Nrzk1dOnNB1CUaOhAYNYMAA\nq6QwJtA4B19+qaOtxYpB/xdP0aTCdmTPbk1Qd+/WS2NxcXriHhcHCQm6kEbBgnorUOD8LW9e/dCU\nY1zK/VOndKeScjt5UrPaokV1MKBECU3CS5TQfVL58udvJUtmOLPw7FldbnvoUAgP146S4eHZtPGM\nyWEsQTa5ypkzOl9m+HBdwbRPH527l1Nnkh84oIt8TJyocwtff10TfGNM4PL5dC2foUM1x+3TBx58\nMINqi+RkXaP5xAlNfE+ePP81KUnfI3K+i42IJs8pSXWhQufvX2GdVkKC7qPee08HkwcN0sZBxgQz\nS5BNruTzwZw5WnJx7Bg8/bR2vyhRwuvIdIDn3//WS5RffqnNKHr0sEWljAk2yckwf76utvzrr9C1\nq7ZVLlvW68h0P7V6tY4Yz56tHTV79gzQjhzGXIErTZCveLxORB4Skc0ikiQiNS7yviYisk1EdohI\n7yv9eSbrREdHe/azQ0Phscd0Bz9rls6Bq1gRWrXSx4mJ2R/T9u06QvynP2nCXr06/PyzjspkZnLs\n5XYPdrbtvZMbt32ePPDAA/D99/DVV1oifNttWtc7bZpWemW33bthxAgtPX7kEa242LIF/vnPjJPj\n3LjtA4Vt+9znai5obwRaAd9l9AYRCQHGAU2AasCjIlL1Kn6myQI54Q9XRC8FTpumJX4tW8IHH2j5\nRYsWMG6cTtjOiosMJ07oBMJevbSeODJSL1XOmaOTw196KWsm4OWE7R6sbNt7J7dv+1tv1f1RTAx0\n7KhXl8qXh8aNdW7CunU64pzZTp+GH37Q+RvVq8Mdd+jJ/D/+oXOYBwyAUqUu/hm5fdvnZrbtc58r\n7lvjnNsGOnR9EXcCO51zu/zvnQ20ALZe6c81ga9oUT3wdOyoierXX8M33+jlTZ8PatbUCSfh4Tra\nXK4cFC78vz/XOZ1Ls22b3jZu1DahW7fqaFCTJnqJMjzcFrszxlxcoULQtq3eEhN1P7VkiZZkJSRc\nuJ+qXFn3U5fS4t05HZFO6Sq5eTP8+KN2cKtWDe69FyZMgFq1rrhU2RhzCbK6seONQEyax3uBWln8\nM00AKVZMa38ffVQPHLt2abvktWth0iT45Rd9rlAhrVsuUkSbToSGnm9ekZioHZMOHdJEukoVvVWr\npge322+Ha67x+l9qjMmtChfWVaxbt9bHe/dq2djatbpw386dWhIRGgphYbqfKlJEW16mNNw5dUr3\nUbGx2qGycmXdR1WtCoMHa0JcqJC3/05jgslFJ+mJyGIgva6J/ZxzX/jfsxTo5Zxbk873twaaOOee\n9D9uB9RyznVP5702Q88YY4wxxmSqK5mkd9ERZOdcwysPB4B9QNp5vmXRUeT0fpZd1DbGGGOMMZ7L\nrK6zGSW3q4CKIlJeRPIBjwD/yqSfaYwxxhhjTKa7mjZvrUQkBvgrMF9EvvI/X1pE5gM453zA88DX\nwBbgY+ecTdAzxhhjjDE5Vo5ZKMQYY4wxxpicwPOFfW0hEW+ISFkRWepf7GWTiPTwOqZgIyIhIrJW\nRL7wOpZgIiJFReRTEdkqIltE5K9exxQsRKSvf5+zUUQ+EpH8XscUqERkqojEisjGNM8VE5HFIrJd\nRBaJSFEvYwxUGWz7Ef59znoR+UxELqHpn7kc6W33NK/1EpFkESl2qZ/naYJsC4l46hzwgnPuz2iZ\nzHO27bPd39DSI7uMk73eBRY456oC1bG+7NlCRMoDTwI1nHO3AiFAWy9jCnDT0GNrWn2Axc65SsAS\n/2OT+dLb9ouAPzvnbgO2A32zParAl952R0TKAg2B3ZfzYV6PIKcuJOKcOwekLCRisphz7qBzbp3/\nfiKaJJT2NqrgISJlgGbAZDKe5GoymX/U5m7n3FTQeRLOuWMehxUsfkNPzAuKSChQEO10ZLKAc+57\n4PeLYDcHpvvvTwdaZmtQQSK9be+cW+ycS1ljcSVQJtsDC3AZ/M4DjAL+frmf53WCnN5CIjd6FEvQ\n8o/shKN/tCZ7jAZeBrJgUVpzETcDcSIyTUTWiMgkESnodVDBwDmXAIwE9gD7gaPOuW+8jSrohDnn\nYv33Y4EwL4MJYl2ABV4HEQxEpAWw1zm34XK/1+sE2S4te0xECgOfAn/zjySbLCYi9wOHnHNrsdHj\n7BYK1ADGO+dqACewy8zZQkT+CPQEyqNXqwqLyOOeBhXEnM7Qt2NwNhOR/sBZ59xHXscS6PyDH/2A\nAWmfvtTv9zpBvuSFREzmE5G8QBTwoXNurtfxBJG7gOYi8iswC6gvIjM8jilY7EVHE/7jf/wpmjCb\nrFcTWO6cO+xvAfoZ+rdgsk+siJQEEJFSwCGP4wkqItIJLa2zE8Ps8Uf0hHy9/3hbBlgtIn+4lG/2\nOkG2hUQ8IiICTAG2OOfe8TqeYOKc6+ecK+ucuxmdpPStc66D13EFA+fcQSBGRCr5n2oAbPYwpGCy\nDfiriBTw738aoJNUTfb5F9DRf78jYAMj2UREmqBldS2cc6e9jicYOOc2OufCnHM3+4+3e9FJwpd0\nYuhpgmwLiXiqDtAOiPS3Glvr/wM22c8uc2av7sBMEVmPdrEY6nE8QcE5tx6YgQ6MpNQDvu9dRIFN\nRGYBy4HKIhIjIp2B4UBDEdkO1Pc/NpksnW3fBRgLFAYW+4+34z0NMgCl2e6V0vzOp3VZx1pbKMQY\nY4wxxpg0vC6xMMYYY4wxJkexBNkYY4wxxpg0LEE2xhhjjDEmDUuQjTHGGGOMScMSZGOMMcYYY9Kw\nBNkYY4wxxpg0LEE2xhhjjDEmjf8Dhw3L+LFjwHYAAAAASUVORK5CYII=\n",
- "text/plain": ["<matplotlib.figure.Figure at 0x7fb57e691fd0>"]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": ["train_plot_prediction(4)"]
- },
- {
- "cell_type": "code",
- "execution_count": 15,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "image/png": "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\njDHGGGNMEv8PaggJNGCcLvoAAAAASUVORK5CYII=\n",
- "text/plain": ["<matplotlib.figure.Figure at 0x7fb5ceb62290>"]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": ["train_plot_prediction(5)"]
- },
- {
- "cell_type": "code",
- "execution_count": 16,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "image/png": "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\nMcYYY9L4P1f5gFgUdniAAAAAAElFTkSuQmCC\n",
- "text/plain": ["<matplotlib.figure.Figure at 0x7fb57e5d4750>"]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": ["train_plot_prediction(10)"]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": ["## With random forest"]
- },
- {
- "cell_type": "code",
- "execution_count": 17,
- "metadata": {
- "collapsed": false
- },
- "outputs": [],
- "source": [
- "from sklearn.ensemble import RandomForestRegressor\n",
- "rf = RandomForestRegressor(n_estimators=10, max_depth=10).fit(scaler.transform(X_train), y_train)\n",
- "\n",
- "y_pred_rf = rf.predict(scaler.transform(x.reshape(-1, 1)))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 18,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "text/plain": ["<matplotlib.legend.Legend at 0x7fb5cec8c210>"]
- },
- "execution_count": 18,
- "metadata": {},
- "output_type": "execute_result"
- },
- {
- "data": {
- "image/png": "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\nCVwRERERHfsJJzrhQWaT1P8AAAAASUVORK5CYII=\n",
- "text/plain": ["<matplotlib.figure.Figure at 0x7fb5ce944850>"]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": [
- "pl.figure(figsize=(10, 4))\n",
- "pl.plot(x, y_pred_rf, c='r', label='y_pred')\n",
- "pl.plot(x, y, c='b', label='y')\n",
- "pl.legend()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": []
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 2",
- "language": "python",
- "name": "python2"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 2
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython2",
- "version": "2.7.10"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-} \ No newline at end of file
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/03-array-simple.json b/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/03-array-simple.json
deleted file mode 100644
index 4af52a4a3d3..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/03-array-simple.json
+++ /dev/null
@@ -1,9 +0,0 @@
-[[
- [], [[[]]], [],
- [
- "string-in-array",
- null,
- 0.123e-3,
- true
- ]
-]]
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/04-object-jupyter-notebook-oneline.json b/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/04-object-jupyter-notebook-oneline.json
deleted file mode 100644
index 3c171a69daf..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/mocks/fixtures/json/04-object-jupyter-notebook-oneline.json
+++ /dev/null
@@ -1 +0,0 @@
-{"cells":[{"cell_type":"markdown","id":"a35eeb9f-df70-4ab1-a243-2d2025888eb0","metadata":{},"source":["# Introduction to the JupyterLab and Jupyter Notebooks\n","\n","This is a short introduction to two of the flagship tools created by [the Jupyter Community](https://jupyter.org).\n","\n","> **⚠️Experimental!⚠️**: This is an experimental interface provided by the [JupyterLite project](https://jupyterlite.readthedocs.io/en/latest/). It embeds an entire JupyterLab interface, with many popular packages for scientific computing, in your browser. There may be minor differences in behavior between JupyterLite and the JupyterLab you install locally. You may also encounter some bugs or unexpected behavior. To report any issues, or to get involved with the JupyterLite project, see [the JupyterLite repository](https://github.com/jupyterlite/jupyterlite/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).\n","\n","## JupyterLab 🧪\n","\n","**JupyterLab** is a next-generation web-based user interface for Project Jupyter. It enables you to work with documents and activities such as Jupyter notebooks, text editors, terminals, and custom components in a flexible, integrated, and extensible manner. It is the interface that you're looking at right now.\n","\n","**For an overview of the JupyterLab interface**, see the **JupyterLab Welcome Tour** on this page, by going to `Help -> Welcome Tour` and following the prompts.\n","\n","> **See Also**: For a more in-depth tour of JupyterLab with a full environment that runs in the cloud, see [the JupyterLab introduction on Binder](https://mybinder.org/v2/gh/jupyterlab/jupyterlab-demo/HEAD?urlpath=lab/tree/demo).\n","\n","## Jupyter Notebooks 📓\n","\n","**Jupyter Notebooks** are a community standard for communicating and performing interactive computing. They are a document that blends computations, outputs, explanatory text, mathematics, images, and rich media representations of objects.\n","\n","JupyterLab is one interface used to create and interact with Jupyter Notebooks.\n","\n","**For an overview of Jupyter Notebooks**, see the **JupyterLab Welcome Tour** on this page, by going to `Help -> Notebook Tour` and following the prompts.\n","\n","> **See Also**: For a more in-depth tour of Jupyter Notebooks and the Classic Jupyter Notebook interface, see [the Jupyter Notebook IPython tutorial on Binder](https://mybinder.org/v2/gh/ipython/ipython-in-depth/HEAD?urlpath=tree/binder/Index.ipynb).\n","\n","## An example: visualizing data in the notebook ✨\n","\n","Below is an example of a code cell. We'll visualize some simple data using two popular packages in Python. We'll use [NumPy](https://numpy.org/) to create some random data, and [Matplotlib](https://matplotlib.org) to visualize it.\n","\n","Note how the code and the results of running the code are bundled together."]},{"cell_type":"code","execution_count":1,"id":"fe55883a-6887-43dd-9498-5333a51799e2","metadata":{"trusted":true},"outputs":[{"data":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Il7ecAAAACXBIWXMAAA9hAAAPYQGoP6dpAADYYUlEQVR4nOzdd3wcxfn48c/sXlMvlmTJslzl3rEdgwvYxlRTDHFoScD0JEBCKAlOAgECIaRQvkBov9BJAIPpmG5sgzu4V7nJRbJ6l67tzu+Pk2Sf1U7S3anNOy+9gvf2ZubqPjflGSGllCiKoiiKoig9htbRDVAURVEURVHCSwWAiqIoiqIoPYwKABVFURRFUXoYFQAqiqIoiqL0MCoAVBRFURRF6WFUAKgoiqIoitLDqABQURRFURSlh1EBoKIoiqIoSg+jAkBFURRFUZQeRgWAiqIoiqIoPYwKABVFURRFUXoYFQAqiqIoiqL0MCoAVBRFURRF6WFUAKgoiqIoitLDqABQURRFURSlh1EBoKIoiqIoSg+jAkBFURRFUZQeRgWAiqIoiqIoPYwKABVFURRFUXoYFQAqiqIoiqL0MCoAVBRFURRF6WFUAKgoiqIoitLDqABQURRFURSlh1EBoKIoiqIoSg+jAkBFURRFUZQeRgWAiqIoiqIoPYwKABVFURRFUXoYFQAqiqIoiqL0MCoAVBRFURRF6WFUAKgoiqIoitLDqABQURRFURSlh1EBoKIoiqIoSg+jAkBFURRFUZQeRgWAiqIoiqIoPYwKABWlE1mwYAEDBgzo6Ga06N5770UI0dHNUI4zYMAAFixYEJKyX3rpJYQQHDhwIOBz169fH5K2KE0bMGAA5513Xkc3Q+kiVACotNmWLVuYP38+/fv3x+FwkJ6ezhlnnMETTzzR0U1TOrF///vfvPTSSx3djA7xySefcO+993Z0M4IiVK9j3Y+LwsLCoJfdFqF8vx44cAAhBP/85z9DUn5zvvnmG4QQfPPNN2GvW+kcVACotMnKlSuZNGkSmzZt4vrrr+fJJ5/kuuuuQ9M0Hn/88Y5untKJ9fQA8L777uvoZrTaz3/+c2pqaujfv3/9sZ7yOvaUx6n0PJaOboDSNT344IPExcWxbt064uPj/W7Lz8/vmEYFmdfrxTRNbDZbRzdFCbOqqiqioqI6uhmdhq7r6Lre0c3oNuq+WxSlI6keQKVN9u7dy6hRoxoEfwApKSl+//Z6vfzlL39h8ODB2O12BgwYwB/+8AdcLpffeXXzV7755hsmTZpEREQEY8aMqR+iWLx4MWPGjMHhcDBx4kQ2bNjQoO6dO3cyf/58EhMTcTgcTJo0iQ8++KDFx3P8UMxjjz1W39bt27fjdru55557mDhxInFxcURFRTFjxgyWLl3aZBnPPfdcfRmTJ09m3bp1Dep87733GD16NA6Hg9GjR/Puu+822raqqipuv/12MjIysNvtDBs2jH/+859IKf3OE0Jw8803s2jRIkaOHElERASnnHIKW7ZsAeDZZ58lMzMTh8PBzJkzA5rPBfDtt98yefJkHA4HgwcP5tlnn230vBdffJHZs2eTkpKC3W5n5MiRPP30037nDBgwgG3btrFs2TKEEAghmDlzJgDFxcXccccdjBkzhujoaGJjYznnnHPYtGlTQO1sys6dO7nkkktITk4mIiKCYcOG8cc//rH+9rohx+3bt3PFFVeQkJDA9OnT629/7bXXmDhxIhERESQmJnLZZZdx6NAhvzpWrFjBT37yE/r164fdbicjI4Pf/va31NTU1J+zYMECnnrqKYD6x378PErTNHnssccYNWoUDoeD3r17c+ONN1JSUuJXl5SSBx54gL59+xIZGcmsWbPYtm1bQM/FSSedxMUXX+x3bMyYMQgh2Lx5c/2xN998EyEEO3bsABrOAWzudazjcrm47bbbSE5OJioqiosuuoiCgoKA2nmipuY3zpw506/eumHNN998kz/84Q+kpqYSFRXFBRdc4Pea/fnPf8ZqtTbanhtuuIH4+HicTmeLj7O0tJRbb721/rOZmZnJww8/7BfcNffdEqhAPlvH+/zzzxk/fjwOh4ORI0eyePHigOtSehCpKG1w5plnypiYGLlly5YWz73qqqskIOfPny+feuopeeWVV0pAzps3z++8/v37y2HDhsm0tDR57733ykcffVSmp6fL6Oho+dprr8l+/frJv/3tb/Jvf/ubjIuLk5mZmdIwjPr7b926VcbFxcmRI0fKhx9+WD755JPy1FNPlUIIuXjx4mbbuH//fgnIkSNHykGDBsm//e1v8tFHH5XZ2dmyoKBApqWlydtuu00+/fTT8u9//7scNmyYtFqtcsOGDQ3KmDBhgszMzJQPP/yw/Pvf/y6TkpJk3759pdvt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888/T0pKSoOAfOLEiTz99NM88MADZGZmkpKSwuzZsznvvPO4//77ufrqq5k6dSpbtmzh9ddfb7SHZ+bMmSxbtqzFQO7//u//mD59OieddBI33HADAwcO5MCBA3z88cds3Lix2fsOHjyYBx54gIULF3LgwAHmzZtHTEwM+/fv59133+WGG27gjjvuYPjw4QwePJg77riDI0eOEBsbyzvvvNNoj9zEiRMB+PWvf81ZZ52FrutcdtllnHbaadx444089NBDbNy4kTPPPBOr1UpWVhaLFi3i8ccfZ/78+SQnJ3PHHXfw0EMPcd5553HuueeyYcMGlixZEnAvaWZmJqmpqezatYtbbrml/vipp57K73//e4CAAsCmXsdQuO6663j77bc5++yzueSSS9i7dy+vvfZak+//xMREpk+fztVXX01eXh6PPfYYmZmZXH/99X7nWa1WLrvsMp588kl0Xefyyy8P+HHeeeedfPDBB5x33nksWLCAiRMnUlVVxZYtW3j77bc5cOBAwK/JV199hdPpbHB83rx5rfpsgW/o+dprr2XdunX07t2bF154gby8vAYB47vvvsvVV1/N0qVLG+RwVHqI8C04VrqTJUuWyGuuuUYOHz5cRkdHS5vNJjMzM+Utt9wi8/Ly/M71eDzyvvvukwMHDpRWq1VmZGTIhQsX+qVrkdKXwmDu3LkN6gLkTTfd5HesqfQJe/fulVdeeaVMTU2VVqtVpqeny/POO0++/fbbzT6e5tIxmKYp//rXv8r+/ftLu90uJ0yYID/66CN51VVX+aVsaa4MQP75z3/2O/bOO+/IESNGSLvdLkeOHCkXL17coEwppayoqJC//e1vZZ8+faTVapVDhgyR//jHP/xSbLT2eapLAbFo0aJmnxcppVy2bJmcOHGitNlsctCgQfKZZ56pT9VxvA8++ECOHTtWOhwOOWDAAPnwww/LF154oUH6kKNHj8q5c+fKmJgYCdSn2HA6nfL222+XaWlpMiIiQk6bNk2uWrWqQaoPKaWcOHGiTE1NbbHtUvryQ1500UUyPj5eOhwOOWzYMHn33XfX395Y2pHjvfPOO3L69OkyKipKRkVFyeHDh8ubbrpJ7tq1q/6c7du3yzlz5sjo6GiZlJQkr7/+erlp0yYJyBdffLH+PK/XK2+55RaZnJwshRANnsPnnntOTpw4UUZERMiYmBg5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hMkkARRBycrKIisrq1/HVldXM3/+fMrLy3nkkUfQNOl4DlQgz7cIH7vdTnl5Oe+8807PIgRd13nnnXe48cYboxucECYxDIObbrqJF154gffff58RI0ZEOyQRBpIAirCqrq5m3rx5FBcXc99991FfX9/zPekxCY+qqioaGhqoqqrC7/ezatUqAMrKykhMTIxucEPA97//fa644gqmT5/OUUcdxe9//3tcLhdXXXVVtEMbstra2tiyZUvPv7dv386qVatIT0+nqKgoipENTTfccANPPvkkL730EklJST3zW1NSUnA6nVGOTphFysCIsHr00Ud7vTHKSy88rrzySh577LFDHn/vvfeYN29e5AMagu6//37uvfdeamtrmTJlCn/4wx+YOXNmtMMast5//33mz59/yONXXHEFjz76aOQDGuKUUod9/JFHHulzKooYPCQBFEIIIYSIMTIZSwghhBAixkgCKIQQQggRYyQBFEIIIYSIMZIACiGEEELEGEkAhRBCCCFijCSAQgghhBAxRhJAIYQQQogYIwmgEEIIIUSMkQRQCCGEECLGSAIohBBCCBFjJAEUQgghhIgxkgAKIYQQQsQYSQCFEEIIIWKMJIBCCCGEEDFGEkAhhBBCiBgjCaAQQgghRIyRBFAIIYQQIsZIAiiEEEIIEWMkARRCCCGEiDGSAAohhBBCxBhJAIUQQgghYowkgEIIIYQQMUYSQCGEEEKIGCMJoBBCCCFEjJEEUAghhBAixkgCKIQQQggRYyQBFEIIIYSIMZIACiGEEELEGEkAhRBCCCFijCSAQgghhBAxRhJAIYQQQogY8//jsbeYXOBKIQAAAABJRU5ErkJggg==","text/plain":["<pyolite.display.Image at 0x97d2f0>"]},"metadata":{},"output_type":"display_data"}],"source":["from matplotlib import pyplot as plt\n","import numpy as np\n","\n","x = None\n","if x is not None:\n"," print(x)\n","\n","# Generate 100 random data points along 3 dimensions\n","x, y, scale = np.random.randn(3, 100)\n","fig, ax = plt.subplots()\n","\n","# Map each onto a scatterplot we'll create with Matplotlib\n","ax.scatter(x=x, y=y, c=scale, s=np.abs(scale)*500)\n","ax.set(title=\"Some random data, created with JupyterLab!\")\n","plt.show()"]},{"cell_type":"markdown","id":"b9670d85-ef29-4dfd-b4b5-e76d279c1f1a","metadata":{},"source":["## Next steps 🏃\n","\n","This is just a short introduction to JupyterLab and Jupyter Notebooks. See below for some more ways to interact with tools in the Jupyter ecosystem, and its community.\n","\n","### Other notebooks in this demo\n","\n","Here are some other notebooks in this demo. Each of the items below corresponds to a file or folder in the **file browser to the left**.\n","\n","- [**`Lorenz.ipynb`**](Lorenz.ipynb) uses Python to demonstrate interactive visualizations and computations around the [Lorenz system](https://en.wikipedia.org/wiki/Lorenz_system). It shows off basic Python functionality, including more visualizations, data structures, and scientific computing libraries.\n","- [**`sqlite.ipynb`**](sqlite.ipynb) demonstrates how an in-browser sqlite kernel to run your own SQL commands from the notebook. It uses the [jupyterlite/xeus-sqlite-kernel](https://github.com/jupyterlite/xeus-sqlite-kernel).\n","\n","### Other sources of information in Jupyter\n","\n","- **More on using JupyterLab**: See [the JupyterLab documentation](https://jupyterlab.readthedocs.io/en/stable/) for more thorough information about how to install and use JupyterLab.\n","- **More interactive demos**: See [try.jupyter.org](https://try.jupyter.org) for more interactive demos with the Jupyter ecosystem.\n","- **Learn more about Jupyter**: See [the Jupyter community documentation](https://docs.jupyter.org) to learn more about the project, its community and tools, and how to get involved.\n","- **Join our discussions**: The [Jupyter Community Forum](https://discourse.jupyter.org) is a place where many in the Jupyter community ask questions, help one another, and discuss issues around interactive computing and our ecosystem."]}],"metadata":{"kernelspec":{"display_name":"Pyolite","language":"python","name":"python"},"language_info":{"codemirror_mode":{"name":"python","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.8"}},"nbformat":4,"nbformat_minor":5} \ No newline at end of file
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/request.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/request.ts
deleted file mode 100644
index c6c195f1ad9..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/request.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { RequestData, get, parseJSON } from '../../helpers/request';
-
-interface CustomHeader {
- accept?: string;
- apiVersion?: string;
- isJSON?: boolean;
-}
-
-interface RequestOptions {
- bypassRedirect?: boolean;
- customHeaders?: CustomHeader; // used only in SonarCloud
- isExternal?: boolean; // used only in SonarCloud
- useQueryParams?: boolean; // used only in SonarCloud
-}
-
-/**
- * Shortcut to do a GET request and return response json
- */
-export function getJSON(
- url: string,
- data?: RequestData,
- options: RequestOptions = {},
-): Promise<any> {
- return get(url, data, options.bypassRedirect).then(parseJSON);
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/router.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/router.ts
deleted file mode 100644
index 4c90c0b46d5..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/router.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { RawQuery } from '../types/router';
-
-export function searchParamsToQuery(searchParams: URLSearchParams, omitKey: string[] = []) {
- const result: RawQuery = {};
-
- searchParams.forEach((value, key) => {
- if (omitKey.includes(key)) {
- return;
- }
- if (result[key]) {
- result[key] = ([] as string[]).concat(result[key], value);
- } else {
- result[key] = value;
- }
- });
-
- return result;
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/testSelector.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/testSelector.ts
deleted file mode 100644
index 73ebc770f00..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/testSelector.ts
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- BoundFunction,
- GetByBoundAttribute,
- GetByRole,
- GetByText,
- screen,
- waitForOptions,
- within,
-} from '@testing-library/react';
-
-function maybeScreen(container?: HTMLElement) {
- return container ? within(container) : screen;
-}
-
-interface ReactTestingQuery {
- find<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ): Promise<T>;
- findAll<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ): Promise<T[]>;
- get<T extends HTMLElement = HTMLElement>(container?: HTMLElement): T;
- getAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement): T[];
- query<T extends HTMLElement = HTMLElement>(container?: HTMLElement): T | null;
- queryAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement): T[] | null;
-}
-
-export class QuerySelector {
- dispatchQuery: ReactTestingQuery;
-
- constructor(dispatchQuery: ReactTestingQuery) {
- this.dispatchQuery = dispatchQuery;
- }
-
- find<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ): Promise<T> {
- return this.dispatchQuery.find<T>(container, waitForOptions);
- }
-
- findAll<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ): Promise<T[]> {
- return this.dispatchQuery.findAll<T>(container, waitForOptions);
- }
-
- get<T extends HTMLElement = HTMLElement>(container?: HTMLElement): T {
- return this.dispatchQuery.get<T>(container);
- }
-
- getAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement): T[] {
- return this.dispatchQuery.getAll<T>(container);
- }
-
- query<T extends HTMLElement = HTMLElement>(container?: HTMLElement): T | null {
- return this.dispatchQuery.query<T>(container);
- }
-
- queryAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement): T[] | null {
- return this.dispatchQuery.queryAll<T>(container);
- }
-
- getAt<T extends HTMLElement = HTMLElement>(index: number, container?: HTMLElement): T {
- return this.getAll<T>(container)[index];
- }
-
- async findAt<T extends HTMLElement = HTMLElement>(
- index: number,
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ): Promise<T> {
- return (await this.findAll<T>(container, waitForOptions))[index];
- }
-
- queryAt<T extends HTMLElement = HTMLElement>(index: number, container?: HTMLElement): T | null {
- const all = this.queryAll<T>(container);
- if (all) {
- return all[index];
- }
- return null;
- }
-
- by(selector: ReactTestingQuery): QuerySelector {
- return new ChainDispatch(this, selector);
- }
-
- byText(...args: Parameters<BoundFunction<GetByText>>): QuerySelector {
- return this.by(new DispatchByText(args));
- }
-
- byRole(...args: Parameters<BoundFunction<GetByRole>>): QuerySelector {
- return this.by(new DispatchByRole(args));
- }
-
- byPlaceholderText(...args: Parameters<BoundFunction<GetByBoundAttribute>>): QuerySelector {
- return this.by(new DispatchByPlaceholderText(args));
- }
-
- byLabelText(...args: Parameters<BoundFunction<GetByText>>): QuerySelector {
- return this.by(new DispatchByLabelText(args));
- }
-
- byTestId(...args: Parameters<BoundFunction<GetByBoundAttribute>>): QuerySelector {
- return this.by(new DispatchByTestId(args));
- }
-
- byDisplayValue(...args: Parameters<BoundFunction<GetByBoundAttribute>>): QuerySelector {
- return this.by(new DispatchByDisplayValue(args));
- }
-
- byTitle(...args: Parameters<BoundFunction<GetByBoundAttribute>>): ReactTestingQuery {
- return this.by(new DispatchByTitle(args));
- }
-}
-
-class ChainDispatch extends QuerySelector {
- innerQuery: QuerySelector;
-
- constructor(insideQuery: QuerySelector, elementQuery: ReactTestingQuery) {
- super(elementQuery);
- this.innerQuery = insideQuery;
- }
-
- async find<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- let inside: HTMLElement;
- try {
- inside = await this.innerQuery.find(container, waitForOptions);
- } catch (e) {
- const elements = this.innerQuery.getAll(container);
- const all = (
- await Promise.all(
- elements.map((e) => this.dispatchQuery.findAll<T>(e, waitForOptions).catch(() => null)),
- )
- )
- .flat()
- .filter((e) => e !== null);
- if (all.length !== 1) {
- throw e;
- }
- return all[0] as T;
- }
- return this.dispatchQuery.find<T>(inside, waitForOptions);
- }
-
- async findAll<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return this.dispatchQuery.findAll<T>(await this.innerQuery.find(container, waitForOptions));
- }
-
- get<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- let inside: HTMLElement;
- try {
- inside = this.innerQuery.get(container);
- } catch (e) {
- const elements = this.innerQuery.getAll(container);
- const all = elements.map((e) => this.dispatchQuery.query<T>(e)).filter((e) => e !== null);
- if (all.length !== 1) {
- throw e;
- }
- return all[0] as T;
- }
- return this.dispatchQuery.get<T>(inside);
- }
-
- getAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- const containers = this.innerQuery.getAll(container);
- return containers.reduce(
- (acc, item) => [...acc, ...(this.dispatchQuery.queryAll<T>(item) ?? [])],
- [],
- );
- }
-
- query<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- let inside: HTMLElement | null;
- try {
- inside = this.innerQuery.query(container);
- } catch (e) {
- const elements = this.innerQuery.queryAll(container);
- const all = elements?.map((e) => this.dispatchQuery.query<T>(e)).filter((e) => e !== null);
- if (all?.length !== 1) {
- throw e;
- }
- return all[0];
- }
- if (inside) {
- return this.dispatchQuery.query<T>(inside);
- }
- return null;
- }
-
- queryAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- const innerContainer = this.innerQuery.query(container);
- if (innerContainer) {
- return this.dispatchQuery.queryAll<T>(innerContainer);
- }
- return null;
- }
-}
-
-class DispatchByText implements ReactTestingQuery {
- readonly args: Parameters<BoundFunction<GetByText>>;
-
- constructor(args: Parameters<BoundFunction<GetByText>>) {
- this.args = args;
- }
-
- find<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return maybeScreen(container).findByText<T>(...this.args, waitForOptions);
- }
-
- findAll<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return maybeScreen(container).findAllByText<T>(...this.args, waitForOptions);
- }
-
- get<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).getByText<T>(...this.args);
- }
-
- getAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).getAllByText<T>(...this.args);
- }
-
- query<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).queryByText<T>(...this.args);
- }
-
- queryAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).queryAllByText<T>(...this.args);
- }
-}
-
-class DispatchByLabelText implements ReactTestingQuery {
- readonly args: Parameters<BoundFunction<GetByText>>;
-
- constructor(args: Parameters<BoundFunction<GetByText>>) {
- this.args = args;
- }
-
- find<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return maybeScreen(container).findByLabelText<T>(...this.args, waitForOptions);
- }
-
- findAll<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return maybeScreen(container).findAllByLabelText<T>(...this.args, waitForOptions);
- }
-
- get<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).getByLabelText<T>(...this.args);
- }
-
- getAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).getAllByLabelText<T>(...this.args);
- }
-
- query<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).queryByLabelText<T>(...this.args);
- }
-
- queryAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).queryAllByLabelText<T>(...this.args);
- }
-}
-
-class DispatchByRole implements ReactTestingQuery {
- readonly args: Parameters<BoundFunction<GetByRole>>;
-
- constructor(args: Parameters<BoundFunction<GetByRole>>) {
- this.args = args;
- }
-
- find<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return maybeScreen(container).findByRole<T>(...this.args, waitForOptions);
- }
-
- findAll<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return maybeScreen(container).findAllByRole<T>(...this.args, waitForOptions);
- }
-
- get<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).getByRole<T>(...this.args);
- }
-
- getAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).getAllByRole<T>(...this.args);
- }
-
- query<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).queryByRole<T>(...this.args);
- }
-
- queryAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).queryAllByRole<T>(...this.args);
- }
-}
-
-class DispatchByTestId implements ReactTestingQuery {
- readonly args: Parameters<BoundFunction<GetByBoundAttribute>>;
-
- constructor(args: Parameters<BoundFunction<GetByBoundAttribute>>) {
- this.args = args;
- }
-
- find<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return maybeScreen(container).findByTestId<T>(...this.args, waitForOptions);
- }
-
- findAll<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return maybeScreen(container).findAllByTestId<T>(...this.args, waitForOptions);
- }
-
- get<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).getByTestId<T>(...this.args);
- }
-
- getAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).getAllByTestId<T>(...this.args);
- }
-
- query<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).queryByTestId<T>(...this.args);
- }
-
- queryAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).queryAllByTestId<T>(...this.args);
- }
-}
-
-class DispatchByTitle implements ReactTestingQuery {
- readonly args: Parameters<BoundFunction<GetByBoundAttribute>>;
-
- constructor(args: Parameters<BoundFunction<GetByBoundAttribute>>) {
- this.args = args;
- }
-
- find<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return maybeScreen(container).findByTitle<T>(...this.args, waitForOptions);
- }
-
- findAll<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return maybeScreen(container).findAllByTitle<T>(...this.args, waitForOptions);
- }
-
- get<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).getByTitle<T>(...this.args);
- }
-
- getAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).getAllByTitle<T>(...this.args);
- }
-
- query<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).queryByTitle<T>(...this.args);
- }
-
- queryAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).queryAllByTitle<T>(...this.args);
- }
-}
-
-class DispatchByDisplayValue implements ReactTestingQuery {
- readonly args: Parameters<BoundFunction<GetByBoundAttribute>>;
-
- constructor(args: Parameters<BoundFunction<GetByBoundAttribute>>) {
- this.args = args;
- }
-
- find<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return maybeScreen(container).findByDisplayValue<T>(...this.args, waitForOptions);
- }
-
- findAll<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return maybeScreen(container).findAllByDisplayValue<T>(...this.args, waitForOptions);
- }
-
- get<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).getByDisplayValue<T>(...this.args);
- }
-
- getAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).getAllByDisplayValue<T>(...this.args);
- }
-
- query<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).queryByDisplayValue<T>(...this.args);
- }
-
- queryAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).queryAllByDisplayValue<T>(...this.args);
- }
-}
-
-class DispatchByPlaceholderText implements ReactTestingQuery {
- readonly args: Parameters<BoundFunction<GetByBoundAttribute>>;
-
- constructor(args: Parameters<BoundFunction<GetByBoundAttribute>>) {
- this.args = args;
- }
-
- find<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return maybeScreen(container).findByPlaceholderText<T>(...this.args, waitForOptions);
- }
-
- findAll<T extends HTMLElement = HTMLElement>(
- container?: HTMLElement,
- waitForOptions?: waitForOptions,
- ) {
- return maybeScreen(container).findAllByPlaceholderText<T>(...this.args, waitForOptions);
- }
-
- get<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).getByPlaceholderText<T>(...this.args);
- }
-
- getAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).getAllByPlaceholderText<T>(...this.args);
- }
-
- query<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).queryByPlaceholderText<T>(...this.args);
- }
-
- queryAll<T extends HTMLElement = HTMLElement>(container?: HTMLElement) {
- return maybeScreen(container).queryAllByPlaceholderText<T>(...this.args);
- }
-}
-
-export function byText(...args: Parameters<BoundFunction<GetByText>>) {
- return new QuerySelector(new DispatchByText(args));
-}
-
-export function byRole(...args: Parameters<BoundFunction<GetByRole>>) {
- return new QuerySelector(new DispatchByRole(args));
-}
-
-export function byPlaceholderText(...args: Parameters<BoundFunction<GetByBoundAttribute>>) {
- return new QuerySelector(new DispatchByPlaceholderText(args));
-}
-
-export function byLabelText(...args: Parameters<BoundFunction<GetByText>>) {
- return new QuerySelector(new DispatchByLabelText(args));
-}
-
-export function byTestId(...args: Parameters<BoundFunction<GetByBoundAttribute>>) {
- return new QuerySelector(new DispatchByTestId(args));
-}
-
-export function byTitle(...args: Parameters<BoundFunction<GetByBoundAttribute>>) {
- return new QuerySelector(new DispatchByTitle(args));
-}
-
-export function byDisplayValue(...args: Parameters<BoundFunction<GetByBoundAttribute>>) {
- return new QuerySelector(new DispatchByDisplayValue(args));
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/urls.ts b/server/sonar-web/src/main/js/sonar-aligned/helpers/urls.ts
deleted file mode 100644
index 4b93d74362f..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/helpers/urls.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { mapValues, omitBy, pick } from 'lodash';
-import { Path, URLSearchParamsInit, createSearchParams } from 'react-router-dom';
-import { cleanQuery } from '../../helpers/query';
-import { Query } from '../../helpers/urls';
-import { SecurityStandard } from '../../types/security';
-import { getBranchLikeQuery } from '../helpers/branch-like';
-import { BranchLikeBase } from '../types/branch-like';
-import { RawQuery } from '../types/router';
-
-export function queryToSearchString(query: RawQuery | URLSearchParamsInit = {}) {
- let filteredQuery = query;
-
- if (typeof query !== 'string' && !Array.isArray(query) && !(query instanceof URLSearchParams)) {
- filteredQuery = cleanQuery(query);
- mapValues(filteredQuery, (value) => (value as string).toString());
- filteredQuery = omitBy(filteredQuery, (value) => value.length === 0);
- }
-
- const queryString = createSearchParams(filteredQuery as URLSearchParamsInit).toString();
-
- return queryString ? `?${queryString}` : undefined;
-}
-
-/**
- * Generate URL for a component's issues page
- */
-export function getComponentIssuesUrl(componentKey: string, query?: Query): Partial<Path> {
- return {
- pathname: '/project/issues',
- search: queryToSearchString({ ...(query || {}), id: componentKey }),
- hash: '',
- };
-}
-
-/**
- * Generate URL for a component's security hotspot page
- */
-export function getComponentSecurityHotspotsUrl(
- componentKey: string,
- branchLike?: BranchLikeBase,
- query: Query = {},
-): Partial<Path> {
- const { inNewCodePeriod, hotspots, assignedToMe, files } = query;
- return {
- pathname: '/security_hotspots',
- search: queryToSearchString({
- id: componentKey,
- inNewCodePeriod,
- hotspots,
- assignedToMe,
- files,
- ...getBranchLikeQuery(branchLike),
- ...pick(query, [
- SecurityStandard.OWASP_TOP10_2021,
- SecurityStandard.OWASP_TOP10,
- SecurityStandard.SONARSOURCE,
- SecurityStandard.CWE,
- SecurityStandard.PCI_DSS_3_2,
- SecurityStandard.PCI_DSS_4_0,
- SecurityStandard.OWASP_ASVS_4_0,
- SecurityStandard.CASA,
- SecurityStandard.STIG_ASD_V5R3,
- 'owaspAsvsLevel',
- ]),
- }),
- hash: '',
- };
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/types/branch-like.ts b/server/sonar-web/src/main/js/sonar-aligned/types/branch-like.ts
deleted file mode 100644
index 40cc6bd8813..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/types/branch-like.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Status } from './common';
-
-/**
- * For Web API V2, use BranchLikeParameters instead
- */
-export type BranchParameters = { branch?: string } | { pullRequest?: string };
-
-export type BranchLikeParameters = { branchKey?: string } | { pullRequestKey?: string };
-
-export type BranchLikeBase = BranchBase | PullRequestBase;
-
-export interface BranchBase {
- analysisDate?: string;
- isMain: boolean;
- name: string;
- status?: { qualityGateStatus: Status };
-}
-
-export interface PullRequestBase {
- analysisDate?: string;
- base: string;
- branch: string;
- isOrphan?: true;
- key: string;
- status?: { qualityGateStatus: Status };
- target: string;
- title: string;
- url?: string;
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/types/common.ts b/server/sonar-web/src/main/js/sonar-aligned/types/common.ts
deleted file mode 100644
index 4eba6477db0..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/types/common.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export type Status = 'ERROR' | 'OK' | 'NONE';
diff --git a/server/sonar-web/src/main/js/sonar-aligned/types/component.ts b/server/sonar-web/src/main/js/sonar-aligned/types/component.ts
deleted file mode 100644
index b7d178728e8..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/types/component.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum ComponentQualifier {
- Application = 'APP',
- Directory = 'DIR',
- Developer = 'DEV',
- File = 'FIL',
- Portfolio = 'VW',
- Project = 'TRK',
- SubPortfolio = 'SVW',
- SubProject = 'BRC',
- TestFile = 'UTS',
-}
-export interface Breadcrumb {
- key: string;
- name: string;
- qualifier: string;
-}
-export interface LightComponent {
- key: string;
- name: string;
- qualifier: string;
-}
-export enum Visibility {
- Public = 'public',
- Private = 'private',
-}
-export interface ComponentBase extends LightComponent {
- alm?: { key: string; url: string };
- analysisDate?: string;
- breadcrumbs: Breadcrumb[];
- description?: string;
- isFavorite?: boolean;
- leakPeriodDate?: string;
- path?: string;
- qualityGate?: { isDefault?: boolean; key: string | number; name: string };
- qualityProfiles?: ComponentQualityProfile[];
- refKey?: string;
- tags?: string[];
- version?: string;
- visibility?: Visibility;
-}
-export interface ComponentQualityProfile {
- deleted?: boolean;
- key: string;
- language: string;
- name: string;
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/types/metrics.ts b/server/sonar-web/src/main/js/sonar-aligned/types/metrics.ts
deleted file mode 100644
index c761dd3553e..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/types/metrics.ts
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum MetricKey {
- accepted_issues = 'accepted_issues',
- alert_status = 'alert_status',
- blocker_violations = 'blocker_violations',
- software_quality_blocker_issues = 'software_quality_blocker_issues',
- branch_coverage = 'branch_coverage',
- bugs = 'bugs',
- software_quality_reliability_issues = 'software_quality_reliability_issues',
- burned_budget = 'burned_budget',
- business_value = 'business_value',
- classes = 'classes',
- code_smells = 'code_smells',
- software_quality_maintainability_issues = 'software_quality_maintainability_issues',
- cognitive_complexity = 'cognitive_complexity',
- comment_lines = 'comment_lines',
- comment_lines_data = 'comment_lines_data',
- comment_lines_density = 'comment_lines_density',
- complexity = 'complexity',
- conditions_to_cover = 'conditions_to_cover',
- confirmed_issues = 'confirmed_issues',
- coverage = 'coverage',
- critical_violations = 'critical_violations',
- software_quality_high_issues = 'software_quality_high_issues',
- development_cost = 'development_cost',
- directories = 'directories',
- duplicated_blocks = 'duplicated_blocks',
- duplicated_files = 'duplicated_files',
- duplicated_lines = 'duplicated_lines',
- duplicated_lines_density = 'duplicated_lines_density',
- duplications_data = 'duplications_data',
- effort_to_reach_maintainability_rating_a = 'effort_to_reach_maintainability_rating_a',
- effort_to_reach_software_quality_maintainability_rating_a = 'effort_to_reach_software_quality_maintainability_rating_a',
- executable_lines_data = 'executable_lines_data',
- false_positive_issues = 'false_positive_issues',
- filename_size = 'filename_size',
- filename_size_rating = 'filename_size_rating',
- files = 'files',
- functions = 'functions',
- generated_lines = 'generated_lines',
- generated_ncloc = 'generated_ncloc',
- high_impact_accepted_issues = 'high_impact_accepted_issues',
- info_violations = 'info_violations',
- software_quality_info_issues = 'software_quality_info_issues',
- issues = 'issues',
- last_change_on_maintainability_rating = 'last_change_on_maintainability_rating',
- last_change_on_releasability_rating = 'last_change_on_releasability_rating',
- last_change_on_reliability_rating = 'last_change_on_reliability_rating',
- last_change_on_security_rating = 'last_change_on_security_rating',
- last_change_on_security_review_rating = 'last_change_on_security_review_rating',
- last_change_on_software_quality_maintainability_rating = 'last_change_on_software_quality_maintainability_rating',
- last_change_on_software_quality_reliability_rating = 'last_change_on_software_quality_reliability_rating',
- last_change_on_software_quality_security_rating = 'last_change_on_software_quality_security_rating',
- last_commit_date = 'last_commit_date',
- leak_projects = 'leak_projects',
- line_coverage = 'line_coverage',
- lines = 'lines',
- lines_to_cover = 'lines_to_cover',
- maintainability_issues = 'maintainability_issues',
- maintainability_rating_distribution = 'maintainability_rating_distribution',
- software_quality_maintainability_rating_distribution = 'software_quality_maintainability_rating_distribution',
- maintainability_rating_effort = 'maintainability_rating_effort',
- software_quality_maintainability_rating_effort = 'software_quality_maintainability_rating_effort',
- major_violations = 'major_violations',
- software_quality_medium_issues = 'software_quality_medium_issues',
- minor_violations = 'minor_violations',
- software_quality_low_issues = 'software_quality_low_issues',
- ncloc = 'ncloc',
- ncloc_data = 'ncloc_data',
- ncloc_language_distribution = 'ncloc_language_distribution',
- new_accepted_issues = 'new_accepted_issues',
- new_blocker_violations = 'new_blocker_violations',
- new_software_quality_blocker_issues = 'new_software_quality_blocker_issues',
- new_branch_coverage = 'new_branch_coverage',
- new_bugs = 'new_bugs',
- new_software_quality_reliability_issues = 'new_software_quality_reliability_issues',
- new_code_smells = 'new_code_smells',
- new_software_quality_maintainability_issues = 'new_software_quality_maintainability_issues',
- new_conditions_to_cover = 'new_conditions_to_cover',
- new_coverage = 'new_coverage',
- new_critical_violations = 'new_critical_violations',
- new_software_quality_high_issues = 'new_software_quality_high_issues',
- new_development_cost = 'new_development_cost',
- new_duplicated_blocks = 'new_duplicated_blocks',
- new_duplicated_lines = 'new_duplicated_lines',
- new_duplicated_lines_density = 'new_duplicated_lines_density',
- new_info_violations = 'new_info_violations',
- new_software_quality_info_issues = 'new_software_quality_info_issues',
- new_issues = 'new_issues',
- new_line_coverage = 'new_line_coverage',
- new_lines = 'new_lines',
- new_lines_to_cover = 'new_lines_to_cover',
- new_maintainability_issues = 'new_maintainability_issues',
- new_maintainability_rating = 'new_maintainability_rating',
- new_software_quality_maintainability_rating = 'new_software_quality_maintainability_rating',
- new_maintainability_rating_distribution = 'new_maintainability_rating_distribution',
- new_software_quality_maintainability_rating_distribution = 'new_software_quality_maintainability_rating_distribution',
- new_major_violations = 'new_major_violations',
- new_software_quality_medium_issues = 'new_software_quality_medium_issues',
- new_minor_violations = 'new_minor_violations',
- new_software_quality_low_issues = 'new_software_quality_low_issues',
- new_reliability_issues = 'new_reliability_issues',
- new_reliability_rating = 'new_reliability_rating',
- new_software_quality_reliability_rating = 'new_software_quality_reliability_rating',
- new_reliability_rating_distribution = 'new_reliability_rating_distribution',
- new_software_quality_reliability_rating_distribution = 'new_software_quality_reliability_rating_distribution',
- new_reliability_remediation_effort = 'new_reliability_remediation_effort',
- new_software_quality_reliability_remediation_effort = 'new_software_quality_reliability_remediation_effort',
- new_security_hotspots = 'new_security_hotspots',
- new_security_hotspots_reviewed = 'new_security_hotspots_reviewed',
- new_security_issues = 'new_security_issues',
- new_security_rating = 'new_security_rating',
- new_software_quality_security_rating = 'new_software_quality_security_rating',
- new_security_rating_distribution = 'new_security_rating_distribution',
- new_software_quality_security_rating_distribution = 'new_software_quality_security_rating_distribution',
- new_security_remediation_effort = 'new_security_remediation_effort',
- new_software_quality_security_remediation_effort = 'new_software_quality_security_remediation_effort',
- new_security_review_rating = 'new_security_review_rating',
- new_security_review_rating_distribution = 'new_security_review_rating_distribution',
- new_sqale_debt_ratio = 'new_sqale_debt_ratio',
- new_software_quality_maintainability_debt_ratio = 'new_software_quality_maintainability_debt_ratio',
- new_technical_debt = 'new_technical_debt',
- new_software_quality_maintainability_remediation_effort = 'new_software_quality_maintainability_remediation_effort',
- new_uncovered_conditions = 'new_uncovered_conditions',
- new_uncovered_lines = 'new_uncovered_lines',
- new_violations = 'new_violations',
- new_violations_rating = 'new_violations_rating',
- new_vulnerabilities = 'new_vulnerabilities',
- new_software_quality_security_issues = 'new_software_quality_security_issues',
- open_issues = 'open_issues',
- prioritized_rule_issues = 'prioritized_rule_issues',
- projects = 'projects',
- public_api = 'public_api',
- public_documented_api_density = 'public_documented_api_density',
- public_undocumented_api = 'public_undocumented_api',
- pull_request_fixed_issues = 'pull_request_fixed_issues',
- quality_gate_details = 'quality_gate_details',
- quality_profiles = 'quality_profiles',
- releasability_effort = 'releasability_effort',
- releasability_rating = 'releasability_rating',
- releasability_rating_distribution = 'releasability_rating_distribution',
- reliability_issues = 'reliability_issues',
- reliability_rating = 'reliability_rating',
- software_quality_reliability_rating = 'software_quality_reliability_rating',
- reliability_rating_distribution = 'reliability_rating_distribution',
- software_quality_reliability_rating_distribution = 'software_quality_reliability_rating_distribution',
- reliability_rating_effort = 'reliability_rating_effort',
- software_quality_reliability_rating_effort = 'software_quality_reliability_rating_effort',
- reliability_remediation_effort = 'reliability_remediation_effort',
- software_quality_reliability_remediation_effort = 'software_quality_reliability_remediation_effort',
- reopened_issues = 'reopened_issues',
- security_hotspots = 'security_hotspots',
- security_hotspots_reviewed = 'security_hotspots_reviewed',
- security_issues = 'security_issues',
- security_rating = 'security_rating',
- software_quality_security_rating = 'software_quality_security_rating',
- security_rating_distribution = 'security_rating_distribution',
- software_quality_security_rating_distribution = 'software_quality_security_rating_distribution',
- security_rating_effort = 'security_rating_effort',
- software_quality_security_rating_effort = 'software_quality_security_rating_effort',
- security_remediation_effort = 'security_remediation_effort',
- software_quality_security_remediation_effort = 'software_quality_security_remediation_effort',
- security_review_rating = 'security_review_rating',
- security_review_rating_distribution = 'security_review_rating_distribution',
- security_review_rating_effort = 'security_review_rating_effort',
- skipped_tests = 'skipped_tests',
- sonarjava_feedback = 'sonarjava_feedback',
- sqale_debt_ratio = 'sqale_debt_ratio',
- software_quality_maintainability_debt_ratio = 'software_quality_maintainability_debt_ratio',
- sqale_index = 'sqale_index',
- software_quality_maintainability_remediation_effort = 'software_quality_maintainability_remediation_effort',
- sqale_rating = 'sqale_rating',
- software_quality_maintainability_rating = 'software_quality_maintainability_rating',
- statements = 'statements',
- team_at_sonarsource = 'team_at_sonarsource',
- team_size = 'team_size',
- test_errors = 'test_errors',
- test_execution_time = 'test_execution_time',
- test_failures = 'test_failures',
- test_success_density = 'test_success_density',
- tests = 'tests',
- uncovered_conditions = 'uncovered_conditions',
- uncovered_lines = 'uncovered_lines',
- violations = 'violations',
- violations_rating = 'violations_rating',
- vulnerabilities = 'vulnerabilities',
- software_quality_security_issues = 'software_quality_security_issues',
- wont_fix_issues = 'wont_fix_issues',
-}
-
-export enum MetricType {
- Rating = 'RATING',
- Percent = 'PERCENT',
- Integer = 'INT',
- Float = 'FLOAT',
- MilliSeconds = 'MILLISEC',
- Level = 'LEVEL',
- ShortInteger = 'SHORT_INT',
- ShortWorkDuration = 'SHORT_WORK_DUR',
- Data = 'DATA',
- Distribution = 'DISTRIB',
- WorkDuration = 'WORK_DUR',
-}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/types/router.ts b/server/sonar-web/src/main/js/sonar-aligned/types/router.ts
deleted file mode 100644
index 0e010dcce7c..00000000000
--- a/server/sonar-web/src/main/js/sonar-aligned/types/router.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- Location as LocationRouter,
- NavigateFunction,
- URLSearchParamsInit,
-} from 'react-router-dom';
-
-export type RawQuery = Record<string, any>;
-
-export interface Location extends LocationRouter {
- query: RawQuery;
-}
-
-export interface Router {
- navigate: NavigateFunction;
- push: (location: string | Partial<Location>) => void;
- replace: (location: string | Partial<Location>) => void;
- searchParams: URLSearchParams;
- setSearchParams: (
- nextInit: URLSearchParamsInit,
- navigateOptions?: { replace?: boolean; state?: any },
- ) => void;
-}
diff --git a/server/sonar-web/src/main/js/types/__tests__/__snapshots__/component-test.ts.snap b/server/sonar-web/src/main/js/types/__tests__/__snapshots__/component-test.ts.snap
deleted file mode 100644
index 705b12fb87f..00000000000
--- a/server/sonar-web/src/main/js/types/__tests__/__snapshots__/component-test.ts.snap
+++ /dev/null
@@ -1,57 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`[Function isApplication] should work properly 1`] = `
-{
- "APP": true,
- "BRC": false,
- "DEV": false,
- "DIR": false,
- "FIL": false,
- "SVW": false,
- "TRK": false,
- "UTS": false,
- "VW": false,
-}
-`;
-
-exports[`[Function isFile] should work properly 1`] = `
-{
- "APP": false,
- "BRC": false,
- "DEV": false,
- "DIR": false,
- "FIL": true,
- "SVW": false,
- "TRK": false,
- "UTS": true,
- "VW": false,
-}
-`;
-
-exports[`[Function isProject] should work properly 1`] = `
-{
- "APP": false,
- "BRC": false,
- "DEV": false,
- "DIR": false,
- "FIL": false,
- "SVW": false,
- "TRK": true,
- "UTS": false,
- "VW": false,
-}
-`;
-
-exports[`[Function isView] should work properly 1`] = `
-{
- "APP": true,
- "BRC": false,
- "DEV": false,
- "DIR": false,
- "FIL": false,
- "SVW": true,
- "TRK": false,
- "UTS": false,
- "VW": true,
-}
-`;
diff --git a/server/sonar-web/src/main/js/types/__tests__/alm-settings-test.ts b/server/sonar-web/src/main/js/types/__tests__/alm-settings-test.ts
deleted file mode 100644
index ac74c89ba64..00000000000
--- a/server/sonar-web/src/main/js/types/__tests__/alm-settings-test.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- mockBitbucketCloudBindingDefinition,
- mockGithubBindingDefinition,
- mockGitlabBindingDefinition,
-} from '../../helpers/mocks/alm-settings';
-import { isGitLabBindingDefinition } from '../alm-settings';
-
-describe('isGitLabBindingDefinition', () => {
- it('correctly returns false for non-GitLab bindings', () => {
- expect(isGitLabBindingDefinition(mockBitbucketCloudBindingDefinition())).toBe(false);
- expect(isGitLabBindingDefinition(mockGithubBindingDefinition())).toBe(false);
- });
-
- it('correctly returns true for GitLab bindings', () => {
- expect(isGitLabBindingDefinition(mockGitlabBindingDefinition())).toBe(true);
- });
-});
diff --git a/server/sonar-web/src/main/js/types/__tests__/component-test.ts b/server/sonar-web/src/main/js/types/__tests__/component-test.ts
deleted file mode 100644
index 3ef86d4c45b..00000000000
--- a/server/sonar-web/src/main/js/types/__tests__/component-test.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { isApplication, isFile, isProject, isView } from '../component';
-
-it.each([[isFile], [isView], [isProject], [isApplication]])(
- '%p should work properly',
- (utilityMethod: (componentQualifier: ComponentQualifier) => void) => {
- const results = Object.values(ComponentQualifier).reduce(
- (prev, qualifier) => ({ ...prev, [qualifier]: utilityMethod(qualifier) }),
- {},
- );
- expect(results).toMatchSnapshot();
- },
-);
diff --git a/server/sonar-web/src/main/js/types/admin.ts b/server/sonar-web/src/main/js/types/admin.ts
deleted file mode 100644
index c6014a166e9..00000000000
--- a/server/sonar-web/src/main/js/types/admin.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Extension } from './types';
-
-export interface AdminPagesContext {
- adminPages: Extension[];
-}
diff --git a/server/sonar-web/src/main/js/types/alm-integration.ts b/server/sonar-web/src/main/js/types/alm-integration.ts
deleted file mode 100644
index 78ef3a7fa27..00000000000
--- a/server/sonar-web/src/main/js/types/alm-integration.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Dict } from './types';
-
-export interface AzureProject {
- description: string;
- name: string;
-}
-
-export interface AzureRepository {
- name: string;
- projectName: string;
- sqProjectKey?: string;
- sqProjectName?: string;
-}
-
-export interface BitbucketProject {
- id: number;
- key: string;
- name: string;
-}
-
-export interface BitbucketRepository {
- id: number;
- name: string;
- projectKey: string;
- slug: string;
- sqProjectKey?: string;
-}
-
-export interface BitbucketCloudRepository {
- name: string;
- projectKey: string;
- slug: string;
- sqProjectKey?: string;
- uuid: number;
- workspace: string;
-}
-
-export type BitbucketProjectRepositories = Dict<{
- allShown: boolean;
- repositories: BitbucketRepository[];
-}>;
-
-export interface GithubOrganization {
- key: string;
- name: string;
-}
-
-export interface GithubRepository {
- id: string;
- key: string;
- name: string;
- sqProjectKey?: string;
- url: string;
-}
-
-export interface GitlabProject {
- id: string;
- name: string;
- pathName: string;
- pathSlug: string;
- slug: string;
- sqProjectKey?: string;
- sqProjectName?: string;
- url: string;
-}
diff --git a/server/sonar-web/src/main/js/types/alm-settings.ts b/server/sonar-web/src/main/js/types/alm-settings.ts
deleted file mode 100644
index d28cc45271f..00000000000
--- a/server/sonar-web/src/main/js/types/alm-settings.ts
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export const enum AlmKeys {
- Azure = 'azure',
- BitbucketServer = 'bitbucket',
- BitbucketCloud = 'bitbucketcloud',
- GitHub = 'github',
- GitLab = 'gitlab',
-}
-
-export type AlmBindingDefinition =
- | AzureBindingDefinition
- | GithubBindingDefinition
- | GitlabBindingDefinition
- | BitbucketServerBindingDefinition
- | BitbucketCloudBindingDefinition;
-
-export interface AlmBindingDefinitionBase {
- key: string;
- url?: string;
-}
-
-export interface AzureBindingDefinition extends AlmBindingDefinitionBase {
- personalAccessToken: string;
- url?: string;
-}
-
-export interface BitbucketServerBindingDefinition extends AlmBindingDefinitionBase {
- personalAccessToken: string;
- url: string;
-}
-
-export interface BitbucketCloudBindingDefinition extends AlmBindingDefinitionBase {
- clientId: string;
- clientSecret: string;
- workspace: string;
-}
-
-export interface GithubBindingDefinition extends AlmBindingDefinitionBase {
- appId: string;
- clientId: string;
- clientSecret: string;
- privateKey: string;
- url: string;
- webhookSecret: string;
-}
-
-export interface GitlabBindingDefinition extends AlmBindingDefinitionBase {
- personalAccessToken: string;
- url?: string;
-}
-
-export interface ProjectAlmBindingResponse {
- alm: AlmKeys;
- key: string;
- monorepo: boolean;
- repository: string;
- slug?: string;
- summaryCommentEnabled?: boolean;
- url?: string;
-}
-
-export interface ProjectAzureBindingResponse extends ProjectAlmBindingResponse {
- alm: AlmKeys.Azure;
- slug: string;
- url: string;
-}
-
-export interface ProjectBitbucketBindingResponse extends ProjectAlmBindingResponse {
- alm: AlmKeys.BitbucketServer;
- slug: string;
-}
-
-export interface ProjectBitbucketCloudBindingResponse extends ProjectAlmBindingResponse {
- alm: AlmKeys.BitbucketCloud;
-}
-
-export interface ProjectGitHubBindingResponse extends ProjectAlmBindingResponse {
- alm: AlmKeys.GitHub;
-}
-
-export interface ProjectGitLabBindingResponse extends ProjectAlmBindingResponse {
- alm: AlmKeys.GitLab;
- url: string;
-}
-
-export interface ProjectAlmBindingParams {
- almSetting: string;
- monorepo: boolean;
- project: string;
-}
-
-export interface AzureProjectAlmBindingParams extends ProjectAlmBindingParams {
- projectName: string;
- repositoryName: string;
-}
-
-export interface BitbucketProjectAlmBindingParams extends ProjectAlmBindingParams {
- repository: string;
- slug: string;
-}
-
-export interface BitbucketCloudProjectAlmBindingParams extends ProjectAlmBindingParams {
- repository: string;
-}
-
-export interface GithubProjectAlmBindingParams extends ProjectAlmBindingParams {
- repository: string;
- summaryCommentEnabled: boolean;
-}
-
-export interface GitlabProjectAlmBindingParams extends ProjectAlmBindingParams {
- repository?: string;
-}
-
-export interface AlmSettingsInstance extends AlmInstanceBase {
- alm: AlmKeys;
-}
-
-export interface AlmInstanceBase {
- key: string;
- url?: string;
-}
-
-export interface AlmSettingsBindingDefinitions {
- [AlmKeys.Azure]: AzureBindingDefinition[];
- [AlmKeys.BitbucketServer]: BitbucketServerBindingDefinition[];
- [AlmKeys.BitbucketCloud]: BitbucketCloudBindingDefinition[];
- [AlmKeys.GitHub]: GithubBindingDefinition[];
- [AlmKeys.GitLab]: GitlabBindingDefinition[];
-}
-
-export interface AlmSettingsBindingStatus {
- alertSuccess: boolean;
- failureMessage: string;
- type: AlmSettingsBindingStatusType;
-}
-
-export enum AlmSettingsBindingStatusType {
- Validating,
- Success,
- Failure,
- Warning,
-}
-
-export enum ProjectAlmBindingConfigurationErrorScope {
- Global = 'GLOBAL',
- Project = 'PROJECT',
- Unknown = 'UNKNOWN',
-}
-
-export interface ProjectAlmBindingConfigurationErrors {
- errors: { msg: string }[];
- scope: ProjectAlmBindingConfigurationErrorScope;
-}
-
-export function isProjectBitbucketBindingResponse(
- binding: ProjectAlmBindingResponse,
-): binding is ProjectBitbucketBindingResponse {
- return binding.alm === AlmKeys.BitbucketServer;
-}
-
-export function isProjectBitbucketCloudBindingResponse(
- binding: ProjectAlmBindingResponse,
-): binding is ProjectBitbucketBindingResponse {
- return binding.alm === AlmKeys.BitbucketCloud;
-}
-
-export function isProjectGitHubBindingResponse(
- binding: ProjectAlmBindingResponse,
-): binding is ProjectGitHubBindingResponse {
- return binding.alm === AlmKeys.GitHub;
-}
-
-export function isProjectGitLabBindingResponse(
- binding: ProjectAlmBindingResponse,
-): binding is ProjectGitLabBindingResponse {
- return binding.alm === AlmKeys.GitLab;
-}
-
-export function isProjectAzureBindingResponse(
- binding: ProjectAlmBindingResponse,
-): binding is ProjectAzureBindingResponse {
- return binding.alm === AlmKeys.Azure;
-}
-
-export function isBitbucketBindingDefinition(
- binding?: AlmBindingDefinitionBase & { url?: string },
-): binding is BitbucketServerBindingDefinition {
- return binding !== undefined && binding.url !== undefined;
-}
-
-export function isBitbucketCloudBindingDefinition(
- binding?: AlmBindingDefinitionBase & { clientId?: string; workspace?: string },
-): binding is BitbucketCloudBindingDefinition {
- return binding !== undefined && binding.clientId !== undefined && binding.workspace !== undefined;
-}
-
-export function isGithubBindingDefinition(
- binding?: AlmBindingDefinitionBase & { appId?: string; url?: string },
-): binding is GithubBindingDefinition {
- return binding !== undefined && binding.appId !== undefined && binding.url !== undefined;
-}
-
-export function isGitLabBindingDefinition(
- binding?: AlmBindingDefinitionBase | GithubBindingDefinition | BitbucketCloudBindingDefinition,
-): binding is GitlabBindingDefinition {
- // There's too much overlap with the others. We must not only validate that certain fields are
- // present, we must also validate that others are NOT present. And even so, we cannot be 100%
- // sure, as right now, Azure, Bitbucket Server, and GitLab have the same signature.
- return (
- binding !== undefined &&
- (binding as GithubBindingDefinition).appId === undefined &&
- (binding as BitbucketCloudBindingDefinition).workspace === undefined
- );
-}
diff --git a/server/sonar-web/src/main/js/types/application.ts b/server/sonar-web/src/main/js/types/application.ts
deleted file mode 100644
index 93b4a2a786f..00000000000
--- a/server/sonar-web/src/main/js/types/application.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Visibility } from '~sonar-aligned/types/component';
-import { Branch } from './branch-like';
-
-export interface ApplicationPeriod {
- date: string;
- project: string;
- projectName: string;
-}
-
-export interface Application {
- branches: Pick<Branch, 'isMain' | 'name'>[];
- description?: string;
- key: string;
- name: string;
- projects: ApplicationProjectBranch[];
- visibility: Visibility;
-}
-
-export interface ApplicationProject {
- accessible?: boolean;
- enabled?: boolean;
- key: string;
- name: string;
- selected?: boolean;
-}
-
-export interface ApplicationProjectBranch {
- accessible?: boolean;
- branch: string;
- enabled?: boolean;
- isMain: boolean;
- key: string;
- name: string;
- selected?: boolean;
-}
diff --git a/server/sonar-web/src/main/js/types/appstate.ts b/server/sonar-web/src/main/js/types/appstate.ts
deleted file mode 100644
index d1244fb8882..00000000000
--- a/server/sonar-web/src/main/js/types/appstate.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { EditionKey } from './editions';
-import { GlobalSettingKeys } from './settings';
-import { Extension } from './types';
-
-export interface AppState {
- authenticationError?: boolean;
- authorizationError?: boolean;
- canAdmin?: boolean;
- documentationUrl: string;
- edition?: EditionKey;
- globalPages?: Extension[];
- instanceUsesDefaultAdminCredentials?: boolean;
- needIssueSync?: boolean;
- productionDatabase: boolean;
- qualifiers: string[];
- settings: { [key in GlobalSettingKeys]?: string };
- standalone?: boolean;
- version: string;
- versionEOL: string;
- webAnalyticsJsPath?: string;
-}
diff --git a/server/sonar-web/src/main/js/types/axios.d.ts b/server/sonar-web/src/main/js/types/axios.d.ts
deleted file mode 100644
index 2984aee51b8..00000000000
--- a/server/sonar-web/src/main/js/types/axios.d.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import 'axios';
-
-type IfEquals<X, Y, A = X, B = never> =
- (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? A : B;
-
-type WritableKeys<T> = {
- [P in keyof T]-?: IfEquals<{ [Q in P]: T[P] }, { -readonly [Q in P]: T[P] }, P>;
-}[keyof T];
-
-type OmitReadonly<T> = Pick<T, WritableKeys<T>>;
-
-declare module 'axios' {
- export interface AxiosInstance {
- defaults: Omit<AxiosDefaults, 'headers'> & {
- headers: HeadersDefaults & {
- [key: string]: AxiosHeaderValue;
- };
- };
- delete<T = void>(url: string, config?: AxiosRequestConfig): Promise<T>;
- get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
- patch<T = any, D = Partial<OmitReadonly<T>>>(
- url: string,
- data?: D,
- config?: AxiosRequestConfig<D>,
- ): Promise<T>;
-
- post<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<T>;
- }
-}
diff --git a/server/sonar-web/src/main/js/types/branch-like.ts b/server/sonar-web/src/main/js/types/branch-like.ts
deleted file mode 100644
index 10fc2e7f470..00000000000
--- a/server/sonar-web/src/main/js/types/branch-like.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { BranchBase, PullRequestBase } from '~sonar-aligned/types/branch-like';
-import { Status } from '~sonar-aligned/types/common';
-import { NewCodeDefinition } from './new-code-definition';
-import { QualityGateStatusCondition } from './quality-gates';
-
-export interface Branch extends BranchBase {
- excludedFromPurge: boolean;
-}
-
-export interface MainBranch extends Branch {
- isMain: true;
-}
-
-export interface PullRequest extends PullRequestBase {}
-
-export type BranchLike = Branch | PullRequest;
-
-export interface BranchTree {
- branch: Branch;
- pullRequests: PullRequest[];
-}
-
-export interface BranchLikeTree {
- branchTree: BranchTree[];
- mainBranchTree?: BranchTree;
- orphanPullRequests: PullRequest[];
- parentlessPullRequests: PullRequest[];
-}
-
-export interface BranchWithNewCodePeriod extends Branch {
- newCodePeriod?: NewCodeDefinition;
-}
-
-export interface BranchStatusData {
- conditions?: QualityGateStatusCondition[];
- ignoredConditions?: boolean;
- status?: Status;
-}
diff --git a/server/sonar-web/src/main/js/types/browser.ts b/server/sonar-web/src/main/js/types/browser.ts
deleted file mode 100644
index f9341085013..00000000000
--- a/server/sonar-web/src/main/js/types/browser.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ExtensionStartMethod } from './extension';
-import { InstanceType } from './system';
-import { SysStatus } from './types';
-
-export interface EnhancedWindow extends Window {
- baseUrl: string;
- instance: InstanceType;
- official: boolean;
- registerExtension: (key: string, start: ExtensionStartMethod, providesCSSFile?: boolean) => void;
-
- serverStatus: SysStatus;
- setWebAnalyticsPageChangeHandler: (pageHandler: (pathname: string) => void) => void;
- t: (...keys: string[]) => string;
- tp: (messageKey: string, ...parameters: Array<string | number>) => string;
-}
-
-export interface AppVariablesElement extends HTMLElement {
- dataset: {
- baseUrl: string;
- instance: InstanceType;
- official: string;
- serverStatus: SysStatus;
- };
-}
diff --git a/server/sonar-web/src/main/js/types/clean-code-taxonomy.ts b/server/sonar-web/src/main/js/types/clean-code-taxonomy.ts
deleted file mode 100644
index 6d14b6d1425..00000000000
--- a/server/sonar-web/src/main/js/types/clean-code-taxonomy.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum SoftwareImpactSeverity {
- Blocker = 'BLOCKER',
- High = 'HIGH',
- Medium = 'MEDIUM',
- Low = 'LOW',
- Info = 'INFO',
-}
-
-export enum CleanCodeAttributeCategory {
- Consistent = 'CONSISTENT',
- Intentional = 'INTENTIONAL',
- Adaptable = 'ADAPTABLE',
- Responsible = 'RESPONSIBLE',
-}
-
-export enum CleanCodeAttribute {
- Clear = 'CLEAR',
- Complete = 'COMPLETE',
- Conventional = 'CONVENTIONAL',
- Distinct = 'DISTINCT',
- Efficient = 'EFFICIENT',
- Focused = 'FOCUSED',
- Formatted = 'FORMATTED',
- Identifiable = 'IDENTIFIABLE',
- Lawful = 'LAWFUL',
- Logical = 'LOGICAL',
- Modular = 'MODULAR',
- Respectful = 'RESPECTFUL',
- Tested = 'TESTED',
- Trustworthy = 'TRUSTWORTHY',
-}
-
-// The order here is important. Please be mindful about the order when adding new software qualities.
-export enum SoftwareQuality {
- Security = 'SECURITY',
- Reliability = 'RELIABILITY',
- Maintainability = 'MAINTAINABILITY',
-}
-
-export interface SoftwareImpact {
- severity: SoftwareImpactSeverity;
- softwareQuality: SoftwareQuality;
-}
-
-export interface SoftwareImpactMeasureData {
- total: number;
- [SoftwareImpactSeverity.Blocker]: number;
- [SoftwareImpactSeverity.High]: number;
- [SoftwareImpactSeverity.Medium]: number;
- [SoftwareImpactSeverity.Low]: number;
- [SoftwareImpactSeverity.Info]: number;
-}
diff --git a/server/sonar-web/src/main/js/types/coding-rules.ts b/server/sonar-web/src/main/js/types/coding-rules.ts
deleted file mode 100644
index a2b7797062d..00000000000
--- a/server/sonar-web/src/main/js/types/coding-rules.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Dict, Paging, Rule, RuleActivation } from './types';
-
-export interface RuleRepository {
- key: string;
- language: string;
- name: string;
-}
-
-export interface GetRulesAppResponse {
- canWrite?: boolean;
- repositories: RuleRepository[];
-}
-
-export interface SearchRulesResponse {
- actives?: Dict<RuleActivation[]>;
- facets?: { property: string; values: { count: number; val: string }[] }[];
- paging: Paging;
- rules: Rule[];
-}
diff --git a/server/sonar-web/src/main/js/types/component-report.ts b/server/sonar-web/src/main/js/types/component-report.ts
deleted file mode 100644
index 588d33d6246..00000000000
--- a/server/sonar-web/src/main/js/types/component-report.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export interface ComponentReportStatus {
- canAdmin: boolean;
- canDownload: boolean;
- canSubscribe: boolean;
- componentFrequency?: string;
- componentRecipients: Array<string>;
- globalFrequency: string;
- globalRecipients: Array<string>;
- subscribed: boolean;
-}
diff --git a/server/sonar-web/src/main/js/types/component.ts b/server/sonar-web/src/main/js/types/component.ts
deleted file mode 100644
index 3678e6b7d0a..00000000000
--- a/server/sonar-web/src/main/js/types/component.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { isPortfolioLike } from '~sonar-aligned/helpers/component';
-import { ComponentQualifier, LightComponent, Visibility } from '~sonar-aligned/types/component';
-import { Task } from './tasks';
-import { Component } from './types';
-
-export enum ProjectKeyValidationResult {
- Valid = 'valid',
- Empty = 'empty',
- TooLong = 'too_long',
- InvalidChar = 'invalid_char',
- OnlyDigits = 'only_digits',
-}
-
-export interface TreeComponent extends LightComponent {
- id?: string;
- path?: string;
- refId?: string;
- refKey?: string;
- tags?: string[];
- visibility: Visibility;
-}
-
-export interface TreeComponentWithPath extends TreeComponent {
- path: string;
-}
-
-export function isApplicationOrPortfolio(
- componentQualifier?: string | ComponentQualifier,
-): componentQualifier is ComponentQualifier.Application | ComponentQualifier.Portfolio {
- return isPortfolioLike(componentQualifier) || isApplication(componentQualifier);
-}
-
-export function isApplication(
- componentQualifier?: string | ComponentQualifier,
-): componentQualifier is ComponentQualifier.Application {
- return componentQualifier === ComponentQualifier.Application;
-}
-
-export function isProject(
- componentQualifier?: string | ComponentQualifier,
-): componentQualifier is ComponentQualifier.Project {
- return componentQualifier === ComponentQualifier.Project;
-}
-
-export function isFile(
- componentQualifier?: string | ComponentQualifier,
-): componentQualifier is ComponentQualifier.File {
- return [ComponentQualifier.File, ComponentQualifier.TestFile].includes(
- componentQualifier as ComponentQualifier,
- );
-}
-
-export function isView(
- componentQualifier?: string | ComponentQualifier,
-): componentQualifier is
- | ComponentQualifier.Application
- | ComponentQualifier.Portfolio
- | ComponentQualifier.SubPortfolio {
- return isPortfolioLike(componentQualifier) || isApplication(componentQualifier);
-}
-
-export interface ComponentContextShape {
- component?: Component;
- currentTask?: Task;
- fetchComponent: () => Promise<void>;
- isInProgress?: boolean;
- isPending?: boolean;
- onComponentChange: (changes: Partial<Component>) => void;
-}
diff --git a/server/sonar-web/src/main/js/types/cves.ts b/server/sonar-web/src/main/js/types/cves.ts
deleted file mode 100644
index bfc8442801a..00000000000
--- a/server/sonar-web/src/main/js/types/cves.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export type Cve = {
- cvssScore?: number;
- cwes: string[];
- description: string;
- epssPercentile: number;
- epssScore: number;
- id: string;
- lastModifiedAt: string;
- publishedAt: string;
-};
diff --git a/server/sonar-web/src/main/js/types/dates.ts b/server/sonar-web/src/main/js/types/dates.ts
deleted file mode 100644
index a34bc4e35b2..00000000000
--- a/server/sonar-web/src/main/js/types/dates.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export type ParsableDate = string | number | Date;
diff --git a/server/sonar-web/src/main/js/types/dependencies.ts b/server/sonar-web/src/main/js/types/dependencies.ts
deleted file mode 100644
index 67a0515d228..00000000000
--- a/server/sonar-web/src/main/js/types/dependencies.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { SoftwareImpactSeverity } from './clean-code-taxonomy';
-import { Paging } from './types';
-
-export interface Dependency {
- description?: string;
- //TODO: Remove optional flag when findings are implemented
- findingsCount?: number;
- findingsExploitableCount?: number;
- findingsSeverities?: FindingsSeverities;
- fixVersion?: string;
- key: string;
- longName: string;
- name: string;
- project: string;
- transitive: boolean;
- version?: string;
-}
-
-export interface DependenciesResponse {
- dependencies: Dependency[];
- page: Paging;
-}
-
-type FindingsSeverities = Partial<Record<SoftwareImpactSeverity, number>>;
diff --git a/server/sonar-web/src/main/js/types/dop-translation.ts b/server/sonar-web/src/main/js/types/dop-translation.ts
deleted file mode 100644
index cfcd1819ea8..00000000000
--- a/server/sonar-web/src/main/js/types/dop-translation.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { AlmInstanceBase, AlmKeys } from './alm-settings';
-import { ProvisioningType } from './provisioning';
-
-export interface DopSetting extends AlmInstanceBase {
- appId?: string;
- id: string;
- type: AlmKeys;
-}
-
-export interface BoundProject {
- devOpsPlatformSettingId: string;
- monorepo: boolean;
- newCodeDefinitionType?: string;
- newCodeDefinitionValue?: string;
- projectIdentifier?: string;
- projectKey: string;
- projectName: string;
- repositoryIdentifier: string;
-}
-
-export interface ProjectBinding {
- dopSetting: string;
- id: string;
- projectId: string;
- projectKey: string;
- repository: string;
- slug: string;
-}
-
-export interface GitHubConfigurationBase {
- allowUsersToSignUp: boolean;
- allowedOrganizations: string[];
- apiUrl: string;
- applicationId: string;
- enabled: boolean;
- projectVisibility: boolean;
- provisioningType: ProvisioningType;
- synchronizeGroups: boolean;
- userConsentRequiredAfterUpgrade: boolean;
- webUrl: string;
-}
-
-export interface GitHubConfigurationPayload extends GitHubConfigurationBase {
- clientId: string;
- clientSecret: string;
- privateKey: string;
-}
-
-export interface GitHubConfigurationResponse extends GitHubConfigurationBase {
- errorMessage?: string;
- id: string;
-}
diff --git a/server/sonar-web/src/main/js/types/editions.ts b/server/sonar-web/src/main/js/types/editions.ts
deleted file mode 100644
index 042b8fe8adc..00000000000
--- a/server/sonar-web/src/main/js/types/editions.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { SystemUpgradeDownloadUrls } from './system';
-
-export enum EditionKey {
- community = 'community',
- developer = 'developer',
- enterprise = 'enterprise',
- datacenter = 'datacenter',
-}
-
-export interface Edition {
- downloadProperty: keyof SystemUpgradeDownloadUrls;
- homeUrl: string;
- key: EditionKey;
- name: string;
-}
-
-export interface License {
- canActivateGracePeriod: boolean;
- contactEmail: string;
- edition: string;
- expiresAt: string;
- gracePeriodEndDate?: string;
- gracePeriodExpired?: boolean;
- isExpired: boolean;
- isOfficialDistribution: boolean;
- isSupported: boolean;
- isValidEdition: boolean;
- isValidServerId: boolean;
- loc: number;
- maxLoc: number;
- plugins: string[];
- remainingLocThreshold: number;
- serverId: string;
- type: string;
-}
diff --git a/server/sonar-web/src/main/js/types/extension.ts b/server/sonar-web/src/main/js/types/extension.ts
deleted file mode 100644
index bf6ba7f7de1..00000000000
--- a/server/sonar-web/src/main/js/types/extension.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Theme } from '@emotion/react';
-import { QueryClient } from '@tanstack/react-query';
-import { IntlShape } from 'react-intl';
-import { Location, Router } from '~sonar-aligned/types/router';
-import { AppState } from './appstate';
-import { BranchLike } from './branch-like';
-import { L10nBundle } from './l10nBundle';
-import { Component } from './types';
-import { CurrentUser, HomePage } from './users';
-
-export enum AdminPageExtension {
- GovernanceConsole = 'governance/views_console',
-}
-
-export interface ExtensionRegistryEntry {
- providesCSSFile: boolean;
- start: ExtensionStartMethod;
-}
-
-export type ExtensionStartMethod = (
- params: ExtensionStartMethodParameter | string,
-) => ExtensionStartMethodReturnType;
-
-export interface ExtensionOptions {
- branchLike?: BranchLike;
- component: Component;
- intl: IntlShape;
- l10nBundle: L10nBundle;
- location: Location;
- router: Router;
- theme: Theme;
-}
-
-export interface ExtensionStartMethodParameter extends Omit<ExtensionOptions, 'component'> {
- appState: AppState;
- baseUrl: string;
- component?: Component;
- currentUser: CurrentUser;
- el: HTMLElement | undefined | null;
- onBranchesChange?: (updateBranches?: boolean, updatePRs?: boolean) => void;
- onComponentChange?: (changes: Partial<Component>) => void;
- queryClient: QueryClient;
- // See SONAR-16207 and core-extension-enterprise-server/src/main/js/portfolios/components/Header.tsx
- // for more information on why we're passing this as a prop to an extension.
- updateCurrentUserHomepage: (homepage: HomePage) => void;
-}
-
-export type ExtensionStartMethodReturnType = React.ReactNode | Function | void;
diff --git a/server/sonar-web/src/main/js/types/features.ts b/server/sonar-web/src/main/js/types/features.ts
deleted file mode 100644
index e5451ab0dbb..00000000000
--- a/server/sonar-web/src/main/js/types/features.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum Feature {
- Announcement = 'announcement',
- BranchSupport = 'branch-support',
- LoginMessage = 'login-message',
- MonoRepositoryPullRequestDecoration = 'monorepo',
- MultipleAlm = 'multiple-alm',
- ProjectImport = 'project-import',
- RegulatoryReport = 'regulatory-reports',
- Scim = 'scim',
- GithubProvisioning = 'github-provisioning',
- GitlabProvisioning = 'gitlab-provisioning',
- PrioritizedRules = 'prioritized-rules',
- FixSuggestions = 'fix-suggestions',
- AiCodeAssurance = 'ai-code-assurance',
-}
diff --git a/server/sonar-web/src/main/js/types/fix-suggestions.ts b/server/sonar-web/src/main/js/types/fix-suggestions.ts
deleted file mode 100644
index 35c52db4448..00000000000
--- a/server/sonar-web/src/main/js/types/fix-suggestions.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum AiCodeFixFeatureEnablement {
- disabled = 'DISABLED',
- allProjects = 'ENABLED_FOR_ALL_PROJECTS',
- someProjects = 'ENABLED_FOR_SOME_PROJECTS',
-}
-
-interface SuggestedChange {
- endLine: number;
- newCode: string;
- startLine: number;
-}
-
-export interface SuggestedFix {
- changes: SuggestedChange[];
- explanation: string;
- id: string;
- issueId: string;
-}
diff --git a/server/sonar-web/src/main/js/types/indexation.ts b/server/sonar-web/src/main/js/types/indexation.ts
deleted file mode 100644
index c660181e21a..00000000000
--- a/server/sonar-web/src/main/js/types/indexation.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-interface IndexationStatusInProgress {
- completedCount: number;
- isCompleted: false;
- total: number;
-}
-
-interface IndexationStatusCompleted {
- completedCount?: number;
- isCompleted: true;
- total?: number;
-}
-
-export type IndexationStatus = {
- hasFailures: boolean;
-} & (IndexationStatusInProgress | IndexationStatusCompleted);
-
-export interface IndexationContextInterface {
- status: IndexationStatus;
-}
-
-export enum IndexationNotificationType {
- InProgress = 'InProgress',
- InProgressWithFailure = 'InProgressWithFailure',
- Completed = 'Completed',
- CompletedWithFailure = 'CompletedWithFailure',
-}
diff --git a/server/sonar-web/src/main/js/types/issues.ts b/server/sonar-web/src/main/js/types/issues.ts
deleted file mode 100644
index 4eaba8127e6..00000000000
--- a/server/sonar-web/src/main/js/types/issues.ts
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import {
- CleanCodeAttribute,
- CleanCodeAttributeCategory,
- SoftwareImpact,
-} from './clean-code-taxonomy';
-import { Issue, Paging, TextRange } from './types';
-import { UserBase } from './users';
-
-export const ASSIGNEE_ME = '__me__';
-
-export enum IssueType {
- CodeSmell = 'CODE_SMELL',
- Vulnerability = 'VULNERABILITY',
- Bug = 'BUG',
- SecurityHotspot = 'SECURITY_HOTSPOT',
-}
-
-// Keep this enum in the correct order (most severe to least severe).
-
-export enum IssueSeverity {
- Blocker = 'BLOCKER',
- Critical = 'CRITICAL',
- Major = 'MAJOR',
- Minor = 'MINOR',
- Info = 'INFO',
-}
-
-export enum IssueScope {
- Main = 'MAIN',
- Test = 'TEST',
-}
-
-export enum IssueResolution {
- Unresolved = '',
- FalsePositive = 'FALSE-POSITIVE',
- Fixed = 'FIXED',
- Removed = 'REMOVED',
- WontFix = 'WONTFIX',
-}
-
-export enum IssueDeprecatedStatus {
- Open = 'OPEN',
- Confirmed = 'CONFIRMED',
- Reopened = 'REOPENED',
- Resolved = 'RESOLVED',
- Closed = 'CLOSED',
-}
-
-export enum IssueStatus {
- Open = 'OPEN',
- Fixed = 'FIXED',
- Confirmed = 'CONFIRMED',
- Accepted = 'ACCEPTED',
- FalsePositive = 'FALSE_POSITIVE',
-}
-
-export enum IssueActions {
- SetType = 'set_type',
- SetTags = 'set_tags',
- SetSeverity = 'set_severity',
- Comment = 'comment',
- Assign = 'assign',
-}
-
-export enum IssueTransition {
- Accept = 'accept',
- Confirm = 'confirm',
- UnConfirm = 'unconfirm',
- Resolve = 'resolve',
- FalsePositive = 'falsepositive',
- WontFix = 'wontfix',
- Reopen = 'reopen',
-}
-
-interface Comment {
- createdAt: string;
- htmlText: string;
- key: string;
- login: string;
- markdown: string;
- updatable: boolean;
-}
-
-export interface MessageFormatting {
- end: number;
- start: number;
- type: MessageFormattingType;
-}
-
-export enum MessageFormattingType {
- CODE = 'CODE',
-}
-
-export interface RawFlowLocation {
- component: string;
- index?: number;
- msg?: string;
- msgFormattings?: MessageFormatting[];
- textRange: TextRange;
-}
-
-export interface RawIssue {
- actions: string[];
- assignee?: string;
- author?: string;
- cleanCodeAttribute: CleanCodeAttribute;
- cleanCodeAttributeCategory: CleanCodeAttributeCategory;
- codeVariants?: string[];
- comments?: Comment[];
- component: string;
- creationDate: string;
- cveId?: string;
- flows?: Array<{
- description?: string;
- locations?: RawFlowLocation[];
- type?: string;
- }>;
- impacts: SoftwareImpact[];
- issueStatus: IssueStatus;
- key: string;
- line?: number;
- message?: string;
- messageFormattings?: MessageFormatting[];
- prioritizedRule?: boolean;
- project: string;
- quickFixAvailable?: boolean;
- resolution?: string;
- rule: string;
- ruleDescriptionContextKey?: string;
- ruleStatus?: string;
- scope: string;
- severity: string;
- status: string;
- tags?: string[];
- textRange?: TextRange;
- transitions: IssueTransition[];
- type: IssueType;
-}
-
-export interface IssueResponse {
- components?: Array<{ key: string; name: string }>;
- issue: RawIssue;
- rules?: Array<{}>;
- users?: UserBase[];
-}
-
-export interface RawIssuesResponse {
- components: ReferencedComponent[];
- effortTotal: number;
- facets: RawFacet[];
- issues: RawIssue[];
- languages: ReferencedLanguage[];
- paging: Paging;
- rules?: Array<{}>;
- users?: UserBase[];
-}
-
-export interface ListIssuesResponse {
- components: ReferencedComponent[];
- issues: RawIssue[];
- paging: Paging;
- rules?: Array<{}>;
-}
-
-export interface FetchIssuesPromise {
- components?: ReferencedComponent[];
- effortTotal?: number;
- facets?: RawFacet[];
- issues: Issue[];
- languages?: ReferencedLanguage[];
- paging: Paging;
- rules: ReferencedRule[];
- users?: UserBase[];
-}
-
-export interface ListIssuesPromise {
- issues: Issue[];
- paging: Paging;
- rules: ReferencedRule[];
-}
-
-export interface ReferencedComponent {
- enabled?: boolean;
- key: string;
- longName?: string;
- name: string;
- path?: string;
- uuid: string;
-}
-
-export interface ReferencedLanguage {
- name: string;
-}
-
-export interface ReferencedRule {
- langName?: string;
- name: string;
-}
-
-export interface RawFacet {
- property: string;
- values: Array<{ count: number; val: string }>;
-}
-
-export interface Facet {
- [value: string]: number;
-}
-
-export enum FacetName {
- AssignedToMe = 'assigned_to_me',
- Assignees = 'assignees',
- Author = 'author',
- CodeVariants = 'codeVariants',
- CreatedAt = 'createdAt',
- Cwe = 'cwe',
- Directories = 'directories',
- Files = 'files',
- Languages = 'languages',
- OwaspTop10 = 'owaspTop10',
- Projects = 'projects',
- Reporters = 'reporters',
- Resolutions = 'resolutions',
- Rules = 'rules',
- Severities = 'severities',
- Statuses = 'statuses',
- Tags = 'tags',
- Types = 'types',
-}
diff --git a/server/sonar-web/src/main/js/types/jest.d.ts b/server/sonar-web/src/main/js/types/jest.d.ts
deleted file mode 100644
index d3ffdb6a54a..00000000000
--- a/server/sonar-web/src/main/js/types/jest.d.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-declare namespace jest {
- interface Matchers<R> {
- toHaveAPopoverWithContent(content: string): Promise<CustomMatcherResult>;
- toHaveATooltipWithContent(content: string): Promise<CustomMatcherResult>;
- toHaveNoA11yViolations(): Promise<CustomMatcherResult>;
- }
-}
diff --git a/server/sonar-web/src/main/js/types/l10nBundle.ts b/server/sonar-web/src/main/js/types/l10nBundle.ts
deleted file mode 100644
index b82c43bc5a0..00000000000
--- a/server/sonar-web/src/main/js/types/l10nBundle.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Dict } from './types';
-
-export interface L10nBundleRequestParams {
- locale?: string;
- ts?: string;
-}
-
-export interface L10nBundleRequestResponse {
- effectiveLocale: string;
- messages: Dict<string>;
-}
-
-export interface L10nBundle {
- locale?: string;
- messages?: Dict<string>;
- timestamp?: string;
-}
diff --git a/server/sonar-web/src/main/js/types/languages.ts b/server/sonar-web/src/main/js/types/languages.ts
deleted file mode 100644
index 1c19c643d43..00000000000
--- a/server/sonar-web/src/main/js/types/languages.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Dict } from './types';
-
-export interface Language {
- key: string;
- name: string;
-}
-
-export type Languages = Dict<Language>;
diff --git a/server/sonar-web/src/main/js/types/measures.ts b/server/sonar-web/src/main/js/types/measures.ts
deleted file mode 100644
index 62a23289592..00000000000
--- a/server/sonar-web/src/main/js/types/measures.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentMeasure, MeasureEnhanced, Metric, Period, PeriodMeasure } from './types';
-
-export interface MeasuresForProjects {
- component: string;
- metric: string;
- period?: PeriodMeasure;
- value?: string;
-}
-
-export interface MeasuresAndMetaWithMetrics {
- component: ComponentMeasure;
- metrics: Metric[];
-}
-
-export interface MeasuresAndMetaWithPeriod {
- component: ComponentMeasure;
- period: Period;
-}
-
-export enum MeasurePageView {
- list = 'list',
- tree = 'tree',
- treemap = 'treemap',
-}
-
-export interface Domain {
- measures: MeasureEnhanced[];
- name: string;
-}
diff --git a/server/sonar-web/src/main/js/types/misc.ts b/server/sonar-web/src/main/js/types/misc.ts
deleted file mode 100644
index 467399208ad..00000000000
--- a/server/sonar-web/src/main/js/types/misc.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export type FCProps<T extends React.FunctionComponent<React.PropsWithChildren<any>>> =
- Parameters<T>[0];
diff --git a/server/sonar-web/src/main/js/types/mode.ts b/server/sonar-web/src/main/js/types/mode.ts
deleted file mode 100644
index e3d923bbdb0..00000000000
--- a/server/sonar-web/src/main/js/types/mode.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum Mode {
- MQR = 'MQR',
- Standard = 'STANDARD_EXPERIENCE',
-}
-
-export interface ModeResponse {
- mode: Mode;
- modified: boolean;
-}
diff --git a/server/sonar-web/src/main/js/types/new-code-definition.ts b/server/sonar-web/src/main/js/types/new-code-definition.ts
deleted file mode 100644
index c88ca14c62d..00000000000
--- a/server/sonar-web/src/main/js/types/new-code-definition.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum NewCodeDefinitionType {
- PreviousVersion = 'PREVIOUS_VERSION',
- NumberOfDays = 'NUMBER_OF_DAYS',
- SpecificAnalysis = 'SPECIFIC_ANALYSIS',
- ReferenceBranch = 'REFERENCE_BRANCH',
- Inherited = 'INHERITED',
-}
-
-export interface NewCodeDefinition {
- effectiveValue?: string;
- inherited?: boolean;
- previousNonCompliantValue?: string;
- projectKey?: string;
- type: NewCodeDefinitionType;
- updatedAt?: number;
- value?: string;
-}
-
-export interface NewCodeDefinitiondWithCompliance {
- isCompliant: boolean;
- type?: NewCodeDefinitionType;
- value?: string;
-}
-
-export interface NewCodeDefinitionBranch extends NewCodeDefinition {
- branchKey: string;
- projectKey: string;
-}
diff --git a/server/sonar-web/src/main/js/types/notifications.ts b/server/sonar-web/src/main/js/types/notifications.ts
deleted file mode 100644
index 9e25685f103..00000000000
--- a/server/sonar-web/src/main/js/types/notifications.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum NotificationGlobalType {
- CeReportTaskFailure = 'CeReportTaskFailure',
- ChangesOnMyIssue = 'ChangesOnMyIssue',
- NewAlerts = 'NewAlerts',
- MyNewIssues = 'SQ-MyNewIssues',
- QualityGateConditionsMismatch = 'QualityGateConditionsMismatch',
-}
-
-export enum NotificationProjectType {
- CeReportTaskFailure = 'CeReportTaskFailure',
- ChangesOnMyIssue = 'ChangesOnMyIssue',
- NewAlerts = 'NewAlerts',
- NewFalsePositiveIssue = 'NewFalsePositiveIssue',
- NewIssues = 'NewIssues',
- MyNewIssues = 'SQ-MyNewIssues',
-}
-
-export interface Notification {
- channel: string;
- project?: string;
- projectName?: string;
- type: string;
-}
-
-export interface NotificationProject {
- project: string;
- projectName: string;
-}
-
-export interface NotificationsResponse {
- channels: string[];
- globalTypes: NotificationGlobalType[];
- notifications: Notification[];
- perProjectTypes: NotificationProjectType[];
-}
-
-export interface AddRemoveNotificationParameters {
- channel: string;
- project?: string;
- type: string;
-}
diff --git a/server/sonar-web/src/main/js/types/permissions.ts b/server/sonar-web/src/main/js/types/permissions.ts
deleted file mode 100644
index a5855c20800..00000000000
--- a/server/sonar-web/src/main/js/types/permissions.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum Permissions {
- Admin = 'admin',
- Browse = 'user',
- ProjectCreation = 'provisioning',
- ApplicationCreation = 'applicationcreator',
- PortfolioCreation = 'portfoliocreator',
- QualityGateAdmin = 'gateadmin',
- QualityProfileAdmin = 'profileadmin',
- Scan = 'scan',
- CodeViewer = 'codeviewer',
- IssueAdmin = 'issueadmin',
- SecurityHotspotAdmin = 'securityhotspotadmin',
-}
diff --git a/server/sonar-web/src/main/js/types/plugins.ts b/server/sonar-web/src/main/js/types/plugins.ts
deleted file mode 100644
index 9c98bd12d3b..00000000000
--- a/server/sonar-web/src/main/js/types/plugins.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export interface Plugin {
- category?: string;
- description?: string;
- editionBundled?: boolean;
- homepageUrl?: string;
- issueTrackerUrl?: string;
- key: string;
- license?: string;
- name: string;
- organizationName?: string;
- organizationUrl?: string;
- termsAndConditionsUrl?: string;
-}
-
-export interface PendingPluginResult {
- installing: PendingPlugin[];
- removing: PendingPlugin[];
- updating: PendingPlugin[];
-}
-
-export interface AvailablePlugin extends Plugin {
- release: Release;
- update: Update;
-}
-
-export interface PendingPlugin extends Plugin {
- implementationBuild: string;
- version: string;
-}
-
-export interface InstalledPlugin extends PendingPlugin {
- documentationPath?: string;
- filename: string;
- hash: string;
- issueTrackerUrl?: string;
- sonarLintSupported: boolean;
- updatedAt: number;
- updates?: Update[];
-}
-
-export interface Release {
- changeLogUrl?: string;
- date: string;
- description?: string;
- version: string;
-}
-
-export interface Update {
- previousUpdates?: Update[];
- release?: Release;
- requires: Plugin[];
- status: string;
-}
-
-export enum PluginType {
- Bundled = 'BUNDLED',
- External = 'EXTERNAL',
-}
-
-export enum RiskConsent {
- Accepted = 'ACCEPTED',
- NotAccepted = 'NOT_ACCEPTED',
- Required = 'REQUIRED',
-}
-
-export function isAvailablePlugin(plugin: Plugin): plugin is AvailablePlugin {
- return (plugin as any).release !== undefined;
-}
-
-export function isInstalledPlugin(plugin: Plugin): plugin is InstalledPlugin {
- return isPendingPlugin(plugin) && (plugin as any).updatedAt !== undefined;
-}
-
-export function isPendingPlugin(plugin: Plugin): plugin is PendingPlugin {
- return (plugin as any).version !== undefined;
-}
diff --git a/server/sonar-web/src/main/js/types/project-activity.ts b/server/sonar-web/src/main/js/types/project-activity.ts
deleted file mode 100644
index 2817b193525..00000000000
--- a/server/sonar-web/src/main/js/types/project-activity.ts
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Status } from '~sonar-aligned/types/common';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-
-interface BaseAnalysis {
- buildString?: string;
- detectedCI?: string;
- events: AnalysisEvent[];
- key: string;
- manualNewCodePeriodBaseline?: boolean;
- projectVersion?: string;
-}
-
-export interface Analysis extends BaseAnalysis {
- date: string;
-}
-
-export interface ParsedAnalysis extends BaseAnalysis {
- date: Date;
-}
-
-export interface AnalysisEvent {
- category: ProjectAnalysisEventCategory | ApplicationAnalysisEventCategory;
- definitionChange?: {
- projects: Array<{
- branch?: string;
- changeType: DefinitionChangeType;
- key: string;
- name: string;
- newBranch?: string;
- oldBranch?: string;
- }>;
- };
- description?: string;
- key: string;
- name: string;
- qualityGate?: {
- failing: Array<{ branch: string; key: string; name: string }>;
- status: Status;
- stillFailing: boolean;
- };
- qualityProfile?: {
- key: string;
- languageKey: string;
- name: string;
- };
-}
-
-export enum GraphType {
- issues = 'issues',
- coverage = 'coverage',
- duplications = 'duplications',
- custom = 'custom',
-}
-
-export enum ProjectAnalysisEventCategory {
- Version = 'VERSION',
- QualityGate = 'QUALITY_GATE',
- QualityProfile = 'QUALITY_PROFILE',
- SqUpgrade = 'SQ_UPGRADE',
- Other = 'OTHER',
-}
-
-export enum ApplicationAnalysisEventCategory {
- QualityGate = 'QUALITY_GATE',
- DefinitionChange = 'DEFINITION_CHANGE',
- Other = 'OTHER',
-}
-
-export enum DefinitionChangeType {
- Added = 'ADDED',
- Removed = 'REMOVED',
- BranchChanged = 'BRANCH_CHANGED',
-}
-
-export interface HistoryItem {
- date: Date;
- value?: string;
-}
-
-export interface MeasureHistory {
- history: HistoryItem[];
- metric: MetricKey;
- splitPointDate?: Date;
-}
-
-export interface Serie {
- data: Point[];
- name: string;
- translatedName: string;
- type: string;
-}
-
-export interface Point {
- x: Date;
- y: number | string | undefined;
-}
-
-export type AnalysisMeasuresVariations = Partial<Record<MetricKey, number>>;
diff --git a/server/sonar-web/src/main/js/types/project-dump.ts b/server/sonar-web/src/main/js/types/project-dump.ts
deleted file mode 100644
index d37f32eaa18..00000000000
--- a/server/sonar-web/src/main/js/types/project-dump.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { TaskStatuses } from './tasks';
-
-export interface DumpStatus {
- canBeExported: boolean;
- canBeImported: boolean;
- dumpToImport?: string;
- exportedDump?: string;
-}
-
-export interface DumpTask {
- executedAt?: string;
- startedAt?: string;
- status: TaskStatuses;
- submittedAt: string;
-}
diff --git a/server/sonar-web/src/main/js/types/provisioning.ts b/server/sonar-web/src/main/js/types/provisioning.ts
deleted file mode 100644
index 3c2a4bfefb7..00000000000
--- a/server/sonar-web/src/main/js/types/provisioning.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { TaskStatuses } from './tasks';
-
-export type GithubStatusDisabled = {
- enabled: false;
- lastSync?: never;
- nextSync?: never;
-};
-export interface GithubStatusEnabled extends AlmSyncStatus {
- enabled: true;
-}
-
-export interface AlmSyncStatus {
- lastSync?: {
- executionTimeMs: number;
- finishedAt: number;
- startedAt: number;
- warningMessage?: string;
- } & (
- | {
- errorMessage?: never;
- status: TaskStatuses.Success;
- summary?: string;
- }
- | {
- errorMessage?: string;
- status: TaskStatuses.Canceled | TaskStatuses.Failed;
- summary?: never;
- }
- );
- nextSync?: { status: TaskStatuses.Pending | TaskStatuses.InProgress };
-}
-
-export type GithubStatus = GithubStatusDisabled | GithubStatusEnabled;
-
-export enum GitHubProvisioningStatus {
- Success = 'SUCCESS',
- Failed = 'FAILED',
-}
-
-type GitHubProvisioning =
- | {
- errorMessage?: never;
- status: GitHubProvisioningStatus.Success;
- }
- | {
- errorMessage: string;
- status: GitHubProvisioningStatus.Failed;
- };
-
-export interface GitHubConfigurationStatus {
- application: {
- autoProvisioning: GitHubProvisioning;
- jit: GitHubProvisioning;
- };
- installations: {
- autoProvisioning: GitHubProvisioning;
- jit: GitHubProvisioning;
- organization: string;
- }[];
-}
-
-export interface DevopsRolesMapping {
- readonly baseRole?: boolean;
- readonly id: string;
- permissions: {
- admin: boolean;
- codeViewer: boolean;
- issueAdmin: boolean;
- scan: boolean;
- securityHotspotAdmin: boolean;
- user: boolean;
- };
- readonly role: string;
-}
-
-export interface GitLabConfigurationCreateBody
- extends Pick<GitlabConfiguration, 'applicationId' | 'synchronizeGroups' | 'url'> {
- secret: string;
-}
-
-export type GitLabConfigurationUpdateBody = {
- allowUsersToSignUp?: boolean;
- allowedGroups?: string[];
- applicationId?: string;
- enabled?: boolean;
- provisioningToken?: string;
- provisioningType?: ProvisioningType;
- secret?: string;
- synchronizeGroups?: boolean;
- url?: string;
-};
-
-export type GitlabConfiguration = {
- allowUsersToSignUp: boolean;
- allowedGroups: string[];
- applicationId: string;
- enabled: boolean;
- errorMessage?: string;
- id: string;
- isProvisioningTokenSet: boolean;
- provisioningType: ProvisioningType;
- synchronizeGroups: boolean;
- url: string;
-};
-
-export enum ProvisioningType {
- jit = 'JIT',
- auto = 'AUTO_PROVISIONING',
-}
diff --git a/server/sonar-web/src/main/js/types/quality-gates.ts b/server/sonar-web/src/main/js/types/quality-gates.ts
deleted file mode 100644
index dcd3a0b7d51..00000000000
--- a/server/sonar-web/src/main/js/types/quality-gates.ts
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Status } from '~sonar-aligned/types/common';
-import { MetricKey } from '~sonar-aligned/types/metrics';
-import { BranchLike } from './branch-like';
-import { CaycStatus, MeasureEnhanced, Metric } from './types';
-import { UserBase } from './users';
-
-export interface QualityGateProjectStatus {
- caycStatus: CaycStatus;
- conditions?: QualityGateProjectStatusCondition[];
- ignoredConditions: boolean;
- status: Status;
-}
-
-export interface QualityGateProjectStatusCondition {
- actualValue: string;
- comparator: string;
- errorThreshold: string;
- metricKey: string;
- periodIndex: number;
- status: Status;
-}
-
-export interface QualityGateApplicationStatus {
- metrics: Metric[];
- projects: QualityGateApplicationStatusChildProject[];
- status: Status;
-}
-
-export interface QualityGateApplicationStatusCondition {
- comparator: string;
- errorThreshold?: string;
- metric: string;
- onLeak?: boolean;
- periodIndex?: number;
- status: Status;
- value: string;
- warningThreshold?: string;
-}
-
-export interface QualityGateApplicationStatusChildProject {
- caycStatus: CaycStatus;
- conditions: QualityGateApplicationStatusCondition[];
- key: string;
- name: string;
- status: Status;
-}
-
-export interface QualityGateStatus {
- branchLike?: BranchLike;
- caycStatus: CaycStatus;
- conditions: QualityGateStatusConditionEnhanced[];
- failedConditions: QualityGateStatusConditionEnhanced[];
- ignoredConditions?: boolean;
- key: string;
- name: string;
- status: Status;
-}
-
-export interface QualityGateStatusCondition {
- actual?: string;
- error?: string;
- level: Status;
- metric: MetricKey;
- op: string;
- period?: number;
- warning?: string;
-}
-
-export interface QualityGateStatusConditionEnhanced extends QualityGateStatusCondition {
- measure: MeasureEnhanced;
-}
-
-export interface SearchPermissionsParameters {
- gateName: string;
- q?: string;
- selected?: 'all' | 'selected' | 'deselected';
-}
-
-export interface AddDeleteUserPermissionsParameters {
- gateName: string;
- login: string;
-}
-
-export interface AddDeleteGroupPermissionsParameters {
- gateName: string;
- groupName: string;
-}
-
-export interface Group {
- name: string;
-}
-
-export function isUser(item: UserBase | Group): item is UserBase {
- return item && (item as UserBase).login !== undefined;
-}
-
-export enum QGBadgeType {
- 'Missing' = 'missing',
- 'Weak' = 'weak',
- 'Ok' = 'ok',
-}
-
-export enum BadgeTarget {
- QualityGate = 'quality_gate',
- Condition = 'condition',
-}
diff --git a/server/sonar-web/src/main/js/types/quality-profiles.ts b/server/sonar-web/src/main/js/types/quality-profiles.ts
deleted file mode 100644
index 4cda221a21e..00000000000
--- a/server/sonar-web/src/main/js/types/quality-profiles.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum QualityProfileChangelogFilterMode {
- MQR = 'MQR',
- STANDARD = 'STANDARD',
-}
diff --git a/server/sonar-web/src/main/js/types/rules.ts b/server/sonar-web/src/main/js/types/rules.ts
deleted file mode 100644
index 5aa70000b6a..00000000000
--- a/server/sonar-web/src/main/js/types/rules.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum RuleStatus {
- Ready = 'READY',
- Beta = 'BETA',
- Deprecated = 'DEPRECATED',
- Removed = 'REMOVED',
-}
-
-export interface SearchRulesQuery {
- activation?: boolean | string;
- active_severities?: string;
- asc?: boolean | string;
- available_since?: string;
- cleanCodeAttributeCategories?: string;
- cwe?: string;
- f?: string;
- facets?: string;
- impactSeverities?: string;
- impactSoftwareQualities?: string;
- include_external?: boolean | string;
- inheritance?: string;
- is_template?: boolean | string;
- languages?: string;
- owaspTop10?: string;
- ['owaspTop10-2021']?: string;
- p?: number;
- prioritizedRule?: boolean | string;
- ps?: number;
- q?: string;
- qprofile?: string;
- repositories?: string;
- rule_key?: string;
- s?: string;
- severities?: string;
- sonarsourceSecurity?: string;
- statuses?: string;
- tags?: string;
- template_key?: string;
- types?: string;
-}
-
-export enum RulesFacetName {
- AvailableSince = 'availableSince',
- CleanCodeAttributeCategories = 'cleanCodeAttributeCategories',
- Cwe = 'cwe',
- Inheritance = 'inheritance',
- ImpactSoftwareQualities = 'impactSoftwareQualities',
- ImpactSeverities = 'impactSeverities',
- Languages = 'languages',
- Profile = 'profile',
- Repositories = 'repositories',
- Statuses = 'statuses',
- Tags = 'tags',
- Template = 'template',
- Types = 'types',
-}
diff --git a/server/sonar-web/src/main/js/types/security-hotspots.ts b/server/sonar-web/src/main/js/types/security-hotspots.ts
deleted file mode 100644
index db653db0067..00000000000
--- a/server/sonar-web/src/main/js/types/security-hotspots.ts
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { HotspotRatingEnum } from '~design-system';
-import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { MessageFormatting } from './issues';
-import { FlowLocation, IssueChangelog, IssueChangelogDiff, Paging, TextRange } from './types';
-import { UserBase } from './users';
-
-export enum HotspotStatus {
- TO_REVIEW = 'TO_REVIEW',
- REVIEWED = 'REVIEWED',
-}
-
-export enum HotspotResolution {
- FIXED = 'FIXED',
- SAFE = 'SAFE',
- ACKNOWLEDGED = 'ACKNOWLEDGED',
-}
-
-export enum HotspotStatusFilter {
- FIXED = 'FIXED',
- SAFE = 'SAFE',
- TO_REVIEW = 'TO_REVIEW',
- ACKNOWLEDGED = 'ACKNOWLEDGED',
-}
-
-export enum HotspotStatusOption {
- FIXED = 'FIXED',
- SAFE = 'SAFE',
- TO_REVIEW = 'TO_REVIEW',
- ACKNOWLEDGED = 'ACKNOWLEDGED',
-}
-
-export interface HotspotFilters {
- assignedToMe: boolean;
- inNewCodePeriod: boolean;
- status: HotspotStatusFilter;
-}
-
-export interface RawHotspot {
- assignee?: string;
- author?: string;
- component: string;
- creationDate: string;
- cveId?: string;
- flows?: Array<{
- locations?: Array<Omit<FlowLocation, 'componentName'>>;
- }>;
- key: string;
- line?: number;
- message: string;
- messageFormattings?: MessageFormatting[];
- project: string;
- resolution?: HotspotResolution;
- rule: string;
- securityCategory: string;
- status: HotspotStatus;
- updateDate: string;
- vulnerabilityProbability: HotspotRatingEnum;
-}
-
-export interface Hotspot {
- assignee?: string;
- assigneeUser?: UserBase;
- author: string;
- authorUser: UserBase;
- canChangeStatus: boolean;
- changelog: IssueChangelog[];
- codeVariants?: string[];
- comment: HotspotComment[];
- component: HotspotComponent;
- creationDate: string;
- cveId?: string;
- flows: { locations: FlowLocation[] }[];
- key: string;
- line?: number;
- message: string;
- messageFormattings?: MessageFormatting[];
- project: HotspotComponent;
- resolution?: HotspotResolution;
- rule: HotspotRule;
- status: HotspotStatus;
- textRange?: TextRange;
- updateDate: string;
- users: UserBase[];
-}
-
-export interface HotspotComponent {
- branch?: string;
- key: string;
- longName: string;
- name: string;
- path: string;
- pullRequest?: string;
- qualifier: ComponentQualifier;
-}
-
-export interface HotspotUpdateFields {
- resolution?: HotspotResolution;
- status: HotspotStatus;
-}
-
-export interface HotspotUpdate extends HotspotUpdateFields {
- key: string;
-}
-
-export interface HotspotRule {
- key: string;
- name: string;
- securityCategory: string;
- vulnerabilityProbability: HotspotRatingEnum;
-}
-
-export interface HotspotComment {
- createdAt: string;
- htmlText: string;
- key: string;
- login: string;
- markdown: string;
- updatable: boolean;
- user: UserBase;
-}
-
-export interface ReviewHistoryElement {
- date: string;
- diffs?: IssueChangelogDiff[];
- html?: string;
- key?: string;
- markdown?: string;
- type: ReviewHistoryType;
- updatable?: boolean;
- user: Pick<UserBase, 'active' | 'avatar' | 'name'>;
-}
-
-export enum ReviewHistoryType {
- Creation,
- Diff,
- Comment,
-}
-
-export interface HotspotSearchResponse {
- components?: { key: string; name: string; qualifier: string }[];
- hotspots: RawHotspot[];
- paging: Paging;
-}
-
-export interface HotspotSetStatusRequest {
- comment?: string;
- resolution?: HotspotResolution;
- status: HotspotStatus;
-}
-
-export interface HotspotAssignRequest {
- assignee?: string;
- comment?: string;
-}
diff --git a/server/sonar-web/src/main/js/types/security.ts b/server/sonar-web/src/main/js/types/security.ts
deleted file mode 100644
index 60a0d1d8d89..00000000000
--- a/server/sonar-web/src/main/js/types/security.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Dict } from './types';
-
-export enum SecurityStandard {
- OWASP_TOP10_2021 = 'owaspTop10-2021',
- OWASP_TOP10 = 'owaspTop10',
- SONARSOURCE = 'sonarsourceSecurity',
- CWE = 'cwe',
- PCI_DSS_3_2 = 'pciDss-3.2',
- PCI_DSS_4_0 = 'pciDss-4.0',
- OWASP_ASVS_4_0 = 'owaspAsvs-4.0',
- STIG_ASD_V5R3 = 'stig-ASD_V5R3',
- CASA = 'casa',
-}
-
-export type StandardType = SecurityStandard;
-
-export type Standards = {
- [key in StandardType]: Dict<{ description?: string; level?: string; title: string }>;
-};
diff --git a/server/sonar-web/src/main/js/types/settings.ts b/server/sonar-web/src/main/js/types/settings.ts
deleted file mode 100644
index 37d03047be2..00000000000
--- a/server/sonar-web/src/main/js/types/settings.ts
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { Dict } from './types';
-
-export const enum SettingsKey {
- AuditHouseKeeping = 'sonar.dbcleaner.auditHousekeeping',
- DaysBeforeDeletingInactiveBranchesAndPRs = 'sonar.dbcleaner.daysBeforeDeletingInactiveBranchesAndPRs',
- DefaultProjectVisibility = 'projects.default.visibility',
- ServerBaseUrl = 'sonar.core.serverBaseURL',
- PluginRiskConsent = 'sonar.plugins.risk.consent',
- LicenceRemainingLocNotificationThreshold = 'sonar.license.notifications.remainingLocThreshold',
- TokenMaxAllowedLifetime = 'sonar.auth.token.max.allowed.lifetime',
- QPAdminCanDisableInheritedRules = 'sonar.qualityProfiles.allowDisableInheritedRules',
- MQRMode = 'sonar.multi-quality-mode.enabled',
- CodeSuggestion = 'sonar.ai.suggestions.enabled',
-}
-
-export enum GlobalSettingKeys {
- LogoUrl = 'sonar.lf.logoUrl',
- LogoWidth = 'sonar.lf.logoWidthPx',
- EnableGravatar = 'sonar.lf.enableGravatar',
- GravatarServerUrl = 'sonar.lf.gravatarServerUrl',
- RatingGrid = 'sonar.technicalDebt.ratingGrid',
- DeveloperAggregatedInfoDisabled = 'sonar.developerAggregatedInfo.disabled',
- UpdatecenterActivated = 'sonar.updatecenter.activate',
- DisplayAnnouncementMessage = 'sonar.announcement.displayMessage',
- AnnouncementMessage = 'sonar.announcement.message',
- MainBranchName = 'sonar.projectCreation.mainBranchName',
-}
-
-export type SettingDefinitionAndValue = {
- definition: ExtendedSettingDefinition;
- settingValue?: SettingValue;
-};
-
-export type Setting = SettingValue & { definition: SettingDefinition; hasValue: boolean };
-export type SettingWithCategory = Setting & { definition: ExtendedSettingDefinition };
-
-export enum SettingType {
- STRING = 'STRING',
- TEXT = 'TEXT',
- JSON = 'JSON',
- PASSWORD = 'PASSWORD',
- BOOLEAN = 'BOOLEAN',
- FLOAT = 'FLOAT',
- INTEGER = 'INTEGER',
- LICENSE = 'LICENSE',
- LONG = 'LONG',
- SINGLE_SELECT_LIST = 'SINGLE_SELECT_LIST',
- PROPERTY_SET = 'PROPERTY_SET',
- FORMATTED_TEXT = 'FORMATTED_TEXT',
- REGULAR_EXPRESSION = 'REGULAR_EXPRESSION',
- USER_LOGIN = 'USER_LOGIN',
-}
-export interface SettingDefinition {
- description?: string;
- key: string;
- multiValues?: boolean;
- name?: string;
- options: string[];
- type?: SettingType;
-}
-
-export interface SettingFieldDefinition extends SettingDefinition {
- name: string;
-}
-
-export interface ExtendedSettingDefinition extends SettingDefinition {
- category: string;
- defaultValue?: string;
- deprecatedKey?: string;
- fields: SettingFieldDefinition[];
- multiValues?: boolean;
- subCategory: string;
-}
-
-export interface DefinitionV2 {
- description?: string;
- key: string;
- multiValues?: boolean;
- name: string;
- secured: boolean;
- type?: SettingType;
-}
-
-export interface SettingValueResponse {
- setSecuredSettings: string[];
- settings: SettingValue[];
-}
-
-export interface SettingValue {
- fieldValues?: Array<Dict<string>>;
- inherited?: boolean;
- key: string;
- parentFieldValues?: Array<Dict<string>>;
- parentValue?: string;
- parentValues?: string[];
- value?: string;
- values?: string[];
-}
diff --git a/server/sonar-web/src/main/js/types/sonarlint.ts b/server/sonar-web/src/main/js/types/sonarlint.ts
deleted file mode 100644
index 6b573395c63..00000000000
--- a/server/sonar-web/src/main/js/types/sonarlint.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export interface Ide {
- capabilities?: Capabilities;
- description: string;
- ideName: string;
- needsToken?: boolean;
- port: number;
-}
-
-export interface Capabilities {
- canOpenFixSuggestion: boolean;
-}
-
-export interface LineRange {
- endLine: number;
- startLine: number;
-}
-
-export interface Changes {
- after: string;
- before: string;
- beforeLineRange: LineRange;
-}
-
-export interface EditFile {
- changes: Changes[];
- path: string;
-}
-
-export interface Fix {
- explanation: string;
- fileEdit: EditFile;
- suggestionId: string;
-}
diff --git a/server/sonar-web/src/main/js/types/system.ts b/server/sonar-web/src/main/js/types/system.ts
deleted file mode 100644
index 64f57531325..00000000000
--- a/server/sonar-web/src/main/js/types/system.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export interface SystemUpgradeDownloadUrls {
- downloadDatacenterUrl?: string;
- downloadDeveloperUrl?: string;
- downloadEnterpriseUrl?: string;
- downloadUrl: string;
-}
-
-export enum ProductName {
- SonarQubeCommunityBuild = 'SonarQube Community Build',
- SonarQubeServer = 'SonarQube Server',
-}
-
-export enum ProductNameForUpgrade {
- SonarQubeCommunityBuild = 'SONARQUBE_COMMUNITY_BUILD',
- SonarQubeServer = 'SONARQUBE_SERVER',
-}
-
-export interface SystemUpgrade extends SystemUpgradeDownloadUrls {
- changeLogUrl?: string;
- description?: string;
- product?: ProductNameForUpgrade;
- releaseDate?: string;
- version: string;
-}
-
-export enum InstanceType {
- SonarQube = 'SonarQube',
- SonarCloud = 'SonarCloud',
-}
-
-export enum MigrationStatus {
- noMigration = 'NO_MIGRATION',
- notSupported = 'NOT_SUPPORTED',
- required = 'MIGRATION_REQUIRED',
- running = 'MIGRATION_RUNNING',
- succeeded = 'MIGRATION_SUCCEEDED',
- failed = 'MIGRATION_FAILED',
-}
-
-export interface MigrationsStatusResponse {
- completedSteps?: number;
- expectedFinishTimestamp?: string;
- message?: string;
- startedAt?: string;
- status: MigrationStatus;
- totalSteps?: number;
-}
-
-export enum AuthMethod {
- Basic = 'BASIC',
- OAuth = 'OAUTH',
-}
-
-export type EmailConfiguration = EmailConfigurationAuth & EmailConfigurationCommon;
-export type EmailConfigurationAuth = EmailNotificationBasicAuth | EmailNotificationOAuth;
-export type EmailConfigurationBasicAuth = EmailNotificationBasicAuth & EmailConfigurationCommon;
-export type EmailConfigurationOAuth = EmailNotificationOAuth & EmailConfigurationCommon;
-
-interface EmailConfigurationCommon {
- fromAddress: string;
- fromName: string;
- host: string;
- id?: string;
- port: string;
- securityProtocol: string;
- subjectPrefix: string;
- username: string;
-}
-
-interface EmailNotificationBasicAuth {
- authMethod: AuthMethod.Basic;
- basicPassword: string;
- readonly isBasicPasswordSet?: boolean;
-}
-
-interface EmailNotificationOAuth {
- authMethod: AuthMethod.OAuth;
- readonly isOauthClientIdSet?: boolean;
- readonly isOauthClientSecretSet?: boolean;
- oauthAuthenticationHost: string;
- oauthClientId: string;
- oauthClientSecret: string;
- oauthTenant: string;
-}
diff --git a/server/sonar-web/src/main/js/types/tasks.ts b/server/sonar-web/src/main/js/types/tasks.ts
deleted file mode 100644
index a09545cdc2f..00000000000
--- a/server/sonar-web/src/main/js/types/tasks.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum TaskTypes {
- Report = 'REPORT',
- IssueSync = 'ISSUE_SYNC',
- GithubProvisioning = 'GITHUB_AUTH_PROVISIONING',
- GithubProjectPermissionsProvisioning = 'GITHUB_PROJECT_PERMISSIONS_PROVISIONING',
- GitlabProvisioning = 'GITLAB_AUTH_PROVISIONING',
- GitlabProjectPermissionsProvisioning = 'GITLAB_PROJECT_PERMISSIONS_PROVISIONING',
- AppRefresh = 'APP_REFRESH',
- ViewRefresh = 'VIEW_REFRESH',
- ProjectExport = 'PROJECT_EXPORT',
- ProjectImport = 'PROJECT_IMPORT',
- ReportSubmit = 'REPORT_SUBMIT',
- AuditPurge = 'AUDIT_PURGE',
-}
-
-export enum TaskStatuses {
- Pending = 'PENDING',
- InProgress = 'IN_PROGRESS',
- Success = 'SUCCESS',
- Failed = 'FAILED',
- Canceled = 'CANCELED',
-}
-
-export interface Task {
- analysisId?: string;
- branch?: string;
- componentKey?: string;
- componentName?: string;
- componentQualifier?: string;
- errorMessage?: string;
- errorStacktrace?: string;
- errorType?: string;
- executedAt?: string;
- executionTimeMs?: number;
- hasErrorStacktrace?: boolean;
- hasScannerContext?: boolean;
- id: string;
- infoMessages?: string[];
- nodeName?: string;
- pullRequest?: string;
- pullRequestTitle?: string;
- scannerContext?: string;
- startedAt?: string;
- status: TaskStatuses;
- submittedAt: string;
- submitterLogin?: string;
- type: TaskTypes;
- warningCount?: number;
- warnings?: string[];
-}
-
-export interface TaskWarning {
- dismissable: boolean;
- key: string;
- message: string;
-}
-
-export interface ActivityRequestParameters {
- component?: string;
- maxExecutedAt?: string;
- minSubmittedAt?: string;
- onlyCurrents?: boolean;
- p?: number;
- ps?: number;
- q?: string;
- status?: string;
- type?: string;
-}
diff --git a/server/sonar-web/src/main/js/types/token.ts b/server/sonar-web/src/main/js/types/token.ts
deleted file mode 100644
index 29ff072b21a..00000000000
--- a/server/sonar-web/src/main/js/types/token.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export enum TokenType {
- Project = 'PROJECT_ANALYSIS_TOKEN',
- Global = 'GLOBAL_ANALYSIS_TOKEN',
- User = 'USER_TOKEN',
-}
-
-export enum TokenExpiration {
- OneMonth = 30,
- ThreeMonths = 90,
- OneYear = 365,
- NoExpiration = 0,
-}
-
-export interface UserToken {
- createdAt: string;
- expirationDate?: string;
- isExpired: boolean;
- lastConnectionDate?: string;
- name: string;
- project?: { key: string; name: string };
- type: TokenType;
-}
-
-export interface NewUserToken extends UserToken {
- login: string;
- token: string;
-}
diff --git a/server/sonar-web/src/main/js/types/types.ts b/server/sonar-web/src/main/js/types/types.ts
deleted file mode 100644
index ad23b911c75..00000000000
--- a/server/sonar-web/src/main/js/types/types.ts
+++ /dev/null
@@ -1,856 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import { ComponentBase, ComponentQualifier } from '~sonar-aligned/types/component';
-import { RuleDescriptionSection } from '../apps/coding-rules/rule';
-import { DocTitleKey } from '../helpers/doc-links';
-import {
- CleanCodeAttribute,
- CleanCodeAttributeCategory,
- SoftwareImpact,
- SoftwareImpactSeverity,
- SoftwareQuality,
-} from './clean-code-taxonomy';
-import { MessageFormatting, RawIssue } from './issues';
-import { NewCodeDefinitionType } from './new-code-definition';
-import { UserActive, UserBase } from './users';
-
-export type Dict<T> = { [key: string]: T };
-export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
-
-export interface A11ySkipLink {
- key: string;
- label: string;
- weight?: number;
-}
-
-export interface AlmApplication extends IdentityProvider {
- installationUrl: string;
-}
-
-export interface AlmRepository {
- installationKey: string;
- label: string;
- linkedProjectKey?: string;
- linkedProjectName?: string;
- private?: boolean;
-}
-
-export interface AlmUnboundApplication {
- installationId: string;
- key: string;
- name: string;
-}
-
-export namespace Chart {
- export interface Point {
- x: Date;
- y: number | string | undefined;
- }
-
- export interface Serie {
- data: Point[];
- name: string;
- translatedName: string;
- type: string;
- }
-}
-
-export interface Component extends ComponentBase {
- branch?: string;
- canBrowseAllChildProjects?: boolean;
- configuration?: ComponentConfiguration;
- extensions?: Extension[];
- isAiCodeFixEnabled?: boolean;
- needIssueSync?: boolean;
-}
-
-export interface NavigationComponent
- extends Omit<Component, 'alm' | 'qualifier' | 'leakPeriodDate' | 'path' | 'tags'> {}
-
-interface ComponentConfiguration {
- canApplyPermissionTemplate?: boolean;
- canBrowseProject?: boolean;
- canUpdateProjectVisibilityToPrivate?: boolean;
- extensions?: Extension[];
- showBackgroundTasks?: boolean;
- showHistory?: boolean;
- showLinks?: boolean;
- showPermissions?: boolean;
- showQualityGates?: boolean;
- showQualityProfiles?: boolean;
- showSettings?: boolean;
- showUpdateKey?: boolean;
-}
-
-export interface ComponentMeasureIntern {
- analysisDate?: string;
- branch?: string;
- canBrowseAllChildProjects?: boolean;
- description?: string;
- isFavorite?: boolean;
- isRecentlyBrowsed?: boolean;
- key: string;
- match?: string;
- name: string;
- path?: string;
- project?: string;
- qualifier: string;
- refKey?: string;
-}
-
-export interface ComponentMeasure extends ComponentMeasureIntern {
- measures?: Measure[];
-}
-
-export interface ComponentMeasureEnhanced extends ComponentMeasureIntern {
- leak?: string;
- measures: MeasureEnhanced[];
- value?: string;
-}
-
-export interface Condition {
- error: string;
- id: string;
- isCaycCondition?: boolean;
- metric: string;
- op?: string;
-}
-
-export interface CustomMeasure {
- createdAt?: string;
- description?: string;
- id: string;
- metric: {
- domain?: string;
- key: string;
- name: string;
- type: string;
- };
- pending?: boolean;
- projectKey: string;
- updatedAt?: string;
- user: UserBase;
- value: string;
-}
-
-export interface Duplication {
- blocks: DuplicationBlock[];
-}
-
-export interface DuplicationBlock {
- _ref?: string;
- from: number;
- size: number;
-}
-
-export interface DuplicatedFile {
- key: string;
- name: string;
- project: string;
- projectName: string;
-}
-
-export type ExpandDirection = 'up' | 'down';
-
-export interface Extension {
- key: string;
- name: string;
-}
-
-export interface FacetValue<T = string> {
- count: number;
- val: T;
-}
-
-export enum FlowType {
- DATA = 'DATA',
- EXECUTION = 'EXECUTION',
-}
-
-export interface Flow {
- description?: string;
- locations: FlowLocation[];
- type: FlowType;
-}
-
-export interface FlowLocation {
- component: string;
- componentName?: string;
- index?: number;
- msg?: string;
- msgFormattings?: MessageFormatting[];
- textRange: TextRange;
-}
-
-export interface Group {
- default?: boolean;
- description?: string;
- id: string;
- managed: boolean;
- name: string;
-}
-
-export interface GroupMembership {
- groupId: string;
- id: string;
- userId: string;
-}
-
-export enum HealthTypes {
- RED = 'RED',
- YELLOW = 'YELLOW',
- GREEN = 'GREEN',
-}
-
-export interface IdentityProvider {
- backgroundColor: string;
- helpMessage?: string;
- iconPath: string;
- key: string;
- manage?: boolean;
- name: string;
-}
-
-export interface Issue extends Omit<RawIssue, 'flows' | 'comments'> {
- assigneeActive?: boolean;
- assigneeAvatar?: string;
- assigneeLogin?: string;
- assigneeName?: string;
- branch?: string;
- comments?: IssueComment[];
- componentEnabled?: boolean;
- componentLongName: string;
- componentQualifier: string;
- componentUuid: string;
- effort?: string;
- externalRuleEngine?: string;
- flows: FlowLocation[][];
- flowsWithType: Flow[];
- fromExternalRule?: boolean;
- message: string;
- projectKey: string;
- projectName: string;
- pullRequest?: string;
- ruleName: string;
- secondaryLocations: FlowLocation[];
-}
-
-export interface IssueChangelog {
- avatar?: string;
- creationDate: string;
- diffs: IssueChangelogDiff[];
- externalUser?: string;
- isUserActive: boolean;
- user: string;
- userName: string;
- webhookSource?: string;
-}
-
-export interface IssueChangelogDiff {
- key: string;
- newValue?: string;
- oldValue?: string;
-}
-
-export interface IssueComment {
- author?: string;
- authorActive?: boolean;
- authorAvatar?: string;
- authorLogin?: string;
- authorName?: string;
- createdAt: string;
- htmlText: string;
- key: string;
- markdown: string;
- updatable: boolean;
-}
-
-export interface IssuesByLine {
- [key: number]: Issue[];
-}
-
-export type IssueType = 'BUG' | 'VULNERABILITY' | 'CODE_SMELL' | 'SECURITY_HOTSPOT';
-
-export interface Language {
- key: string;
- name: string;
-}
-
-export type Languages = Dict<Language>;
-
-export interface LinearIssueLocation {
- from: number;
- index?: number;
- line: number;
- startLine?: number;
- text?: string;
- textFormatting?: MessageFormatting[];
- to: number;
-}
-
-export interface LineMap {
- [line: number]: SourceLine;
-}
-
-export interface LinePopup {
- index?: number;
- line: number;
- name: string;
- open?: boolean;
-}
-
-export interface Measure extends MeasureIntern {
- metric: string;
-}
-
-export interface MeasureEnhanced extends MeasureIntern {
- leak?: string;
- metric: Metric;
-}
-
-export interface MeasureIntern {
- bestValue?: boolean;
- period?: PeriodMeasure;
- value?: string;
-}
-
-export interface Metric {
- bestValue?: string;
- custom?: boolean;
- decimalScale?: number;
- description?: string;
- direction?: number;
- domain?: string;
- hidden?: boolean;
- higherValuesAreBetter?: boolean;
- id?: string;
- key: string;
- name: string;
- qualitative?: boolean;
- type: string;
- worstValue?: string;
-}
-
-export interface MyProject {
- description?: string;
- key: string;
- lastAnalysisDate?: string;
- links: Array<{
- href: string;
- name: string;
- type: string;
- }>;
- name: string;
- qualityGate?: string;
-}
-
-export interface Paging {
- pageIndex: number;
- pageSize: number;
- total: number;
-}
-
-export interface Period {
- date: string;
- index?: number;
- mode: PeriodMode | NewCodeDefinitionType;
- modeParam?: string;
- parameter?: string;
-}
-
-export interface PeriodMeasure {
- bestValue?: boolean;
- index: number;
- value: string;
-}
-
-/*
- * These are old baseline setting types, necessary for
- * backward compatibility.
- */
-export type PeriodMode =
- | 'days'
- | 'date'
- | 'version'
- | 'previous_analysis'
- | 'previous_version'
- | 'manual_baseline';
-
-export interface Permission {
- description: string;
- key: string;
- name: string;
-}
-
-export interface PermissionDefinition {
- description: string;
- key: string;
- name: string;
-}
-
-export type PermissionDefinitions = Array<PermissionDefinition | PermissionDefinitionGroup>;
-
-export interface PermissionDefinitionGroup {
- category: string;
- permissions: PermissionDefinition[];
-}
-
-export interface PermissionGroup {
- description?: string;
- id?: string;
- managed?: boolean;
- name: string;
- permissions: string[];
-}
-
-export interface PermissionUser extends UserActive {
- managed?: boolean;
- permissions: string[];
-}
-
-export interface PermissionTemplateGroup {
- groupsCount: number;
- key: string;
- usersCount: number;
- withProjectCreator?: boolean;
-}
-
-export interface PermissionTemplate {
- createdAt: string;
- defaultFor: string[];
- description?: string;
- id: string;
- name: string;
- permissions: Array<PermissionTemplateGroup>;
- projectKeyPattern?: string;
- updatedAt?: string;
-}
-
-export interface ProfileInheritanceDetails {
- activeRuleCount: number;
- inactiveRuleCount: number;
- isBuiltIn: boolean;
- key: string;
- name: string;
- overridingRuleCount?: number;
-}
-
-export interface ProjectLink {
- id: string;
- name?: string;
- type: string;
- url: string;
-}
-
-export enum CaycStatus {
- Compliant = 'compliant',
- NonCompliant = 'non-compliant',
- OverCompliant = 'over-compliant',
-}
-
-export interface QualityGatePreview {
- isDefault?: boolean;
- name: string;
-}
-
-export interface QualityGate extends QualityGatePreview {
- actions?: {
- associateProjects?: boolean;
- copy?: boolean;
- delegate?: boolean;
- delete?: boolean;
- manageAiCodeAssurance?: boolean;
- manageConditions?: boolean;
- rename?: boolean;
- setAsDefault?: boolean;
- };
- caycStatus?: CaycStatus;
- conditions?: Condition[];
- hasMQRConditions?: boolean;
- hasStandardConditions?: boolean;
- isAiCodeSupported?: boolean;
- isBuiltIn?: boolean;
-}
-
-export interface Rule {
- cleanCodeAttribute?: CleanCodeAttribute;
- cleanCodeAttributeCategory?: CleanCodeAttributeCategory;
- impacts: SoftwareImpact[];
- isTemplate?: boolean;
- key: string;
- lang?: string;
- langName?: string;
- name: string;
- params?: RuleParameter[];
- severity: string;
- status: string;
- sysTags?: string[];
- tags?: string[];
- type: RuleType;
-}
-
-export interface RestRule {
- cleanCodeAttribute?: CleanCodeAttribute;
- cleanCodeAttributeCategory?: CleanCodeAttributeCategory;
- impacts: SoftwareImpact[];
- key: string;
- language?: string;
- languageName?: string;
- name: string;
- parameters?: RestRuleParameter[];
- severity: string;
- status: string;
- systemTags?: string[];
- tags?: string[];
- template?: boolean;
- type: RuleType;
-}
-
-export interface RuleActivation {
- createdAt: string;
- impacts: { severity: SoftwareImpactSeverity; softwareQuality: SoftwareQuality }[];
- inherit: RuleInheritance;
- params: { key: string; value: string }[];
- prioritizedRule: boolean;
- qProfile: string;
- severity: string;
-}
-
-export interface RulesUpdateRequest {
- cleanCodeAttribute?: CleanCodeAttribute;
- impacts?: SoftwareImpact[];
- key: string;
- markdownDescription?: string;
- markdown_note?: string;
- name?: string;
- params?: string;
- remediation_fn_base_effort?: string;
- remediation_fn_type?: string;
- remediation_fy_gap_multiplier?: string;
- severity?: string;
- status?: string;
- tags?: string;
- type?: RuleType;
-}
-
-export interface RuleDetails extends Rule {
- createdAt: string;
- defaultRemFnBaseEffort?: string;
- defaultRemFnType?: string;
- descriptionSections?: RuleDescriptionSection[];
- educationPrinciples?: string[];
- gapDescription?: string;
- htmlDesc?: string;
- htmlNote?: string;
- internalKey?: string;
- isExternal?: boolean;
- mdDesc?: string;
- mdNote?: string;
- remFnBaseEffort?: string;
- remFnGapMultiplier?: string;
- remFnOverloaded?: boolean;
- remFnType?: string;
- repo: string;
- scope?: RuleScope;
- templateKey?: string;
-}
-
-export interface RestRuleDetails extends RestRule {
- createdAt: string;
- descriptionSections?: RuleDescriptionSection[];
- educationPrinciples?: string[];
- external?: boolean;
- gapDescription?: string;
- htmlDesc?: string;
- htmlNote?: string;
- internalKey?: string;
- markdownDescription?: string;
- markdownNote?: string;
- remFnBaseEffort?: string;
- remFnGapMultiplier?: string;
- remFnType?: string;
- repositoryKey: string;
- scope?: RuleScope;
- templateKey?: string;
-}
-
-export type RuleInheritance = 'NONE' | 'INHERITED' | 'OVERRIDES';
-
-export interface RestRuleParameter {
- defaultValue?: string;
- htmlDescription?: string;
- key: string;
- type: string;
-}
-
-export interface RuleParameter {
- defaultValue?: string;
- htmlDesc?: string;
- key: string;
- type: string;
-}
-
-export type RuleScope = 'MAIN' | 'TEST' | 'ALL';
-
-export const RuleTypes = [
- 'BUG',
- 'VULNERABILITY',
- 'CODE_SMELL',
- 'SECURITY_HOTSPOT',
- 'UNKNOWN',
-] as const;
-export type RuleType = (typeof RuleTypes)[number];
-
-export enum CustomRuleType {
- ISSUE = 'ISSUE',
- SECURITY_HOTSPOT = 'SECURITY_HOTSPOT',
-}
-
-export interface Snippet {
- end: number;
- index: number;
- start: number;
- toDelete?: boolean;
-}
-
-export interface SnippetGroup extends SnippetsByComponent {
- locations: FlowLocation[];
-}
-
-export interface SnippetsByComponent {
- component: SourceViewerFile;
- sources: { [line: number]: SourceLine };
-}
-
-export interface SourceLine {
- code?: string;
- conditions?: number;
- coverageBlock?: number;
- coverageStatus?: SourceLineCoverageStatus;
- coveredConditions?: number;
- duplicated?: boolean;
- isNew?: boolean;
- line: number;
- lineHits?: number;
- newCodeBlock?: number;
- scmAuthor?: string;
- scmDate?: string;
- scmRevision?: string;
-}
-
-export type SourceLineCoverageStatus = 'uncovered' | 'partially-covered' | 'covered';
-
-export interface SourceViewerFile {
- canMarkAsFavorite?: boolean;
- fav?: boolean;
- key: string;
- leakPeriodDate?: string;
- longName?: string;
- measures: {
- coverage?: string;
- duplicationDensity?: string;
- issues?: string;
- lines?: string;
- tests?: string;
- };
- name?: string;
- path: string;
- project: string;
- projectName: string;
- q: ComponentQualifier;
- uuid: string;
-}
-
-export type StandardSecurityCategories = Dict<{ description?: string; title: string }>;
-
-export interface SubscriptionPlan {
- maxNcloc: number;
- price: number;
-}
-
-export interface SuggestionLink {
- link: DocTitleKey;
- text: string;
-}
-
-export interface SysInfoAppNode extends SysInfoBase {
- 'Compute Engine Logging': SysInfoLogging;
- Name: string;
- 'Web Logging': SysInfoLogging;
-}
-
-export interface SysInfoBase extends SysInfoValueObject {
- Health: HealthTypes;
- 'Health Causes': string[];
- Plugins?: Dict<string>;
- System: {
- Version: string;
- };
-}
-
-export enum Provider {
- Github = 'github',
- Gitlab = 'gitlab',
- Scim = 'SCIM',
-}
-
-export interface SysInfoCluster extends SysInfoBase {
- 'Application Nodes': SysInfoAppNode[];
- 'Search Nodes': SysInfoSearchNode[];
- Settings: Dict<string>;
- Statistics?: {
- ncloc: number;
- };
- System: {
- 'External Users and Groups Provisioning'?: Provider;
- 'High Availability': true;
- 'Server ID': string;
- Version: string;
- };
-}
-
-export interface SysInfoLogging extends Dict<string> {
- 'Logs Level': string;
-}
-
-export interface SysInfoSearchNode extends SysInfoValueObject {
- Name: string;
-}
-
-export interface SysInfoSection extends Dict<SysInfoValueObject> {}
-
-export interface SysInfoStandalone extends SysInfoBase {
- 'Compute Engine Logging': SysInfoLogging;
- Settings: Dict<string>;
- Statistics?: {
- ncloc: number;
- } & Dict<string | number>;
- System: {
- 'High Availability': false;
- 'Server ID': string;
- Version: string;
- };
- 'Web Logging': SysInfoLogging;
-}
-
-export type SysInfoValue =
- | boolean
- | string
- | number
- | undefined
- | HealthTypes
- | SysInfoValueObject
- | SysInfoValueArray;
-
-export interface SysInfoValueArray extends Array<SysInfoValue> {}
-
-export interface SysInfoValueObject extends Dict<SysInfoValue> {}
-
-export type SysStatus =
- | 'STARTING'
- | 'UP'
- | 'DOWN'
- | 'RESTARTING'
- | 'DB_MIGRATION_NEEDED'
- | 'DB_MIGRATION_RUNNING';
-
-export interface TestCase {
- coveredLines: number;
- durationInMs: number;
- fileId: string;
- fileKey: string;
- fileName: string;
- id: string;
- message?: string;
- name: string;
- stacktrace?: string;
- status: string;
-}
-
-export interface TextRange {
- endLine: number;
- endOffset: number;
- startLine: number;
- startOffset: number;
-}
-
-export interface UserSelected extends UserActive {
- selected: boolean;
-}
-
-export interface UserGroupMember {
- login: string;
- managed: boolean;
- name: string;
- selected: boolean;
-}
-
-export namespace WebApi {
- export interface Action {
- changelog: Changelog[];
- deprecatedSince?: string;
- description: string;
- hasResponseExample: boolean;
- internal: boolean;
- key: string;
- params?: Param[];
- post: boolean;
- since?: string;
- }
-
- export interface Changelog {
- description: string;
- version: string;
- }
-
- export interface Domain {
- actions: Action[];
- deprecatedSince?: string;
- description: string;
- internal?: boolean;
- path: string;
- since?: string;
- }
-
- export interface Example {
- example: string;
- format: string;
- }
-
- export interface Param {
- defaultValue?: string;
- deprecatedKey?: string;
- deprecatedKeySince?: string;
- deprecatedSince?: string;
- description: string;
- exampleValue?: string;
- internal: boolean;
- key: string;
- maxValuesAllowed?: number;
- maximumLength?: number;
- maximumValue?: number;
- minimumLength?: number;
- minimumValue?: number;
- possibleValues?: string[];
- required: boolean;
- since?: string;
- }
-}
diff --git a/server/sonar-web/src/main/js/types/users.ts b/server/sonar-web/src/main/js/types/users.ts
deleted file mode 100644
index d43269c80a7..00000000000
--- a/server/sonar-web/src/main/js/types/users.ts
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export interface CurrentUser {
- dismissedNotices: { [key: string]: boolean };
- isLoggedIn: boolean;
- permissions?: { global: string[] };
- usingSonarLintConnectedMode?: boolean;
-}
-
-export interface Notice {
- key: NoticeType;
- value: boolean;
-}
-
-export enum NoticeType {
- EDUCATION_PRINCIPLES = 'educationPrinciples',
- SONARLINT_AD = 'sonarlintAd',
- ISSUE_GUIDE = 'issueCleanCodeGuide',
- ISSUE_NEW_STATUS_AND_TRANSITION_GUIDE = 'issueNewIssueStatusAndTransitionGuide',
- QG_CAYC_CONDITIONS_SIMPLIFICATION = 'qualityGateCaYCConditionsSimplification',
- OVERVIEW_ZERO_NEW_ISSUES_SIMPLIFICATION = 'overviewZeroNewIssuesSimplification',
- ONBOARDING_CAYC_BRANCH_SUMMARY_GUIDE = 'onboardingDismissCaycBranchSummaryGuide',
- MQR_MODE_ADVERTISEMENT_BANNER = 'showNewModesBanner',
- MODE_TOUR = 'showNewModesTour',
-}
-
-export interface LoggedInUser extends CurrentUser, UserActive {
- externalIdentity?: string;
- externalProvider?: string;
- groups: string[];
- homepage?: HomePage;
- isLoggedIn: true;
- local?: boolean;
- scmAccounts: string[];
- settings?: CurrentUserSetting[];
- sonarLintAdSeen?: boolean;
-}
-
-export type HomePage =
- | { branch: string | undefined; component: string; type: 'APPLICATION' }
- | { type: 'ISSUES' }
- | { type: 'MY_ISSUES' }
- | { type: 'MY_PROJECTS' }
- | { component: string; type: 'PORTFOLIO' }
- | { type: 'PORTFOLIOS' }
- | { branch: string | undefined; component: string; type: 'PROJECT' }
- | { type: 'PROJECTS' };
-
-export interface CurrentUserSetting {
- key: CurrentUserSettingNames;
- value: string;
-}
-
-export type CurrentUserSettingNames =
- | 'notifications.optOut'
- | 'notifications.readDate'
- | 'tutorials.jenkins.skipBitbucketPreReqs';
-
-export interface UserActive extends UserBase {
- active?: true;
- name: string;
-}
-
-export interface User extends UserBase {
- externalIdentity?: string;
- externalProvider?: string;
- groups?: string[];
- lastConnectionDate?: string;
- local: boolean;
- managed: boolean;
- scmAccounts?: string[];
- sonarLintLastConnectionDate?: string;
- tokensCount?: number;
-}
-
-export interface UserBase {
- active?: boolean;
- avatar?: string;
- email?: string | null;
- login: string;
- name?: string;
-}
-
-export interface RestUserBase {
- id: string;
- login: string;
- name: string;
-}
-
-export interface RestUser extends RestUserBase {
- active: boolean;
- avatar: string;
- email: string | null;
- externalProvider: string;
- local: boolean;
-}
-
-export interface RestUserDetailed extends RestUser {
- externalLogin: string;
- managed: boolean;
- scmAccounts: string[];
- sonarLintLastConnectionDate: string | null;
- sonarQubeLastConnectionDate: string | null;
-}
-
-export const enum ChangePasswordResults {
- OldPasswordIncorrect = 'old_password_incorrect',
- NewPasswordSameAsOld = 'new_password_same_as_old',
-}
-
-export function isUserActive(user: UserBase): user is UserActive {
- return user.active !== false && Boolean(user.name);
-}
-
-export function isLoggedIn(user: CurrentUser): user is LoggedInUser {
- return user.isLoggedIn;
-}
diff --git a/server/sonar-web/src/main/js/types/webhook.ts b/server/sonar-web/src/main/js/types/webhook.ts
deleted file mode 100644
index 10fa08903cf..00000000000
--- a/server/sonar-web/src/main/js/types/webhook.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-export interface WebhookResponse {
- hasSecret: boolean;
- key: string;
- latestDelivery?: WebhookDelivery;
- name: string;
- url: string;
-}
-
-export interface WebhookBasePayload {
- name: string;
- secret?: string;
- url: string;
-}
-
-export interface WebhookCreatePayload extends WebhookBasePayload {
- project?: string;
-}
-
-export interface WebhookUpdatePayload extends WebhookBasePayload {
- webhook: string;
-}
-
-export interface WebhookDelivery {
- at: string;
- durationMs: number;
- httpStatus?: number;
- id: string;
- success: boolean;
-}
-
-export type WebhookSearchDeliveriesPayload = {
- ceTaskId?: string;
- componentKey?: string;
- p?: number;
- ps?: number;
- webhook?: string;
-};
diff --git a/server/sonar-web/tailwind-echoes.js b/server/sonar-web/tailwind-echoes.js
deleted file mode 100644
index 90499536334..00000000000
--- a/server/sonar-web/tailwind-echoes.js
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-const plugin = require('tailwindcss/plugin');
-
-module.exports = plugin(({ addUtilities }) => {
- const echoes = {
- '.code': {
- font: 'var(--echoes-typography-code-default)',
- },
- '.code-highlight': {
- font: 'var(--echoes-typography-code-highlight)',
- },
- '.code-comment': {
- font: 'var(--echoes-typography-code-comment)',
- },
- '.heading-xs': {
- font: 'var(--echoes-typography-heading-xsmall)',
- },
- '.heading-sm': {
- font: 'var(--echoes-typography-heading-small)',
- },
- '.heading-md': {
- font: 'var(--echoes-typography-heading-medium)',
- },
- '.heading-lg': {
- font: 'var(--echoes-typography-heading-large)',
- },
- '.heading-xl': {
- font: 'var(--echoes-typography-heading-xlarge)',
- },
- '.typo-default': {
- font: 'var(--echoes-typography-text-default-regular)',
- },
- '.typo-semibold': {
- font: 'var(--echoes-typography-text-default-semi-bold)',
- },
- '.typo-bold': {
- font: 'var(--echoes-typography-text-default-bold)',
- },
- '.typo-sm': {
- font: 'var(--echoes-typography-text-small-medium)',
- },
- '.typo-sm-semibold': {
- font: 'var(--echoes-typography-text-small-semi-bold)',
- },
- '.typo-lg': {
- font: 'var(--echoes-typography-text-large-regular)',
- },
- '.typo-lg-semibold': {
- font: 'var(--echoes-typography-text-large-semi-bold)',
- },
- '.typo-label': {
- font: 'var(--echoes-typography-others-label)',
- },
- '.typo-helper-text': {
- font: 'var(--echoes-typography-others-helper-text)',
- },
- '.typo-display': {
- font: 'var(--echoes-typography-display-default)',
- },
- };
-
- addUtilities(echoes);
-});
diff --git a/server/sonar-web/tailwind.base.config.js b/server/sonar-web/tailwind.base.config.js
deleted file mode 100644
index fcbe1e7115d..00000000000
--- a/server/sonar-web/tailwind.base.config.js
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-const path = require('path');
-const { fontFamily } = require('tailwindcss/defaultTheme');
-const echoesUtilities = require('./tailwind-echoes');
-
-module.exports = {
- prefix: 'sw-', // Prefix all tailwind classes with the sw- prefix to avoid collisions
- theme: {
- colors: {},
- // Define cursors
- cursor: {
- auto: 'auto',
- default: 'default',
- pointer: 'pointer',
- text: 'text',
- 'not-allowed': 'not-allowed',
- },
- // Define font sizes
- fontSize: {
- code: ['0.875rem', '1.125rem'], // 14px / 18px
- xs: ['0.75rem', '1rem'], // 12px / 16px
- sm: ['0.875rem', '1.25rem'], // 14px / 20px
- base: ['1rem', '1.5rem'], // 16px / 24px
- md: ['1.313rem', '1.75rem'], // 21px / 28px
- lg: ['1.5rem', '1.75rem'], // 24px / 28px
- xl: ['2.25rem', '3rem'], // 36px / 48px
- },
- // Define font weights
- fontWeight: {
- regular: 400,
- semibold: 600,
- bold: 700,
- },
- // Define font families
- fontFamily: {
- sans: ['Inter', ...fontFamily.sans],
- mono: ['Ubuntu Mono', ...fontFamily.mono],
- },
- // Define less order properties than default
- order: {
- first: '-9999',
- last: '9999',
- none: '0',
- 1: '1',
- 2: '2',
- 3: '3',
- 4: '4',
- },
- screens: {
- sm: '1280px',
- lg: '1920px',
- },
- // Defined spacing values based on our grid size
- spacing: {
- 0: '0',
- '1/2': '0.125rem', // 2px
- 1: '0.25rem', // 4px
- 2: '0.5rem', // 8px
- 3: '0.75rem', // 12px
- 4: '1rem', // 16px
- 5: '1.25rem', // 20px
- 6: '1.5rem', // 24px
- 7: '1.75rem', // 28px
- 8: '2rem', // 32px
- 9: '2.25rem', // 36px
- 10: '2.5rem', // 40px
- 12: '3rem', // 48px
- 14: '3.75rem', // 60px
- 16: '4rem', // 64px
- 24: '6rem', // 96px
- 32: '8rem', // 128px
- 40: '10rem', // 160px
- 64: '16rem', // 256px
-
- page: '1.25rem', // 20px
- },
- maxHeight: (twTheme) => twTheme('height'),
- maxWidth: (twTheme) => twTheme('width'),
- minHeight: (twTheme) => twTheme('height'),
- minWidth: (twTheme) => twTheme('width'),
- borderRadius: {
- 0: '0',
- '1/2': '0.125rem', // 2px
- 1: '0.25rem', // 4px
- 2: '0.5rem', // 8px
- pill: '625rem',
- },
- zIndex: {
- normal: '2',
- 'issue-header': '10',
- 'project-list-header': '30',
- filterbar: '50',
- 'content-popup': '52',
- 'filterbar-header': '55',
- 'dropdown-menu-page': '100',
- 'top-navbar': '419',
- popup: '420',
- 'global-navbar': '421',
- sidebar: '421',
- 'core-concepts': '422',
- 'global-popup': '5000',
- 'dropdown-menu': '7500',
- 'modal-overlay': 8500,
- modal: '9000',
- tooltip: '9001',
- },
- extend: {
- width: {
- 'abs-150': '150px',
- 'abs-200': '200px',
- 'abs-250': '250px',
- 'abs-300': '300px',
- 'abs-350': '350px',
- 'abs-400': '400px',
- 'abs-500': '500px',
- 'abs-600': '600px',
- 'abs-800': '800px',
- 'input-small': '150px',
- 'input-medium': '250px',
- 'input-large': '350px',
- icon: '1rem', // 16px
- },
- height: {
- 'abs-200': '200px',
- icon: '1rem', // 16px
- control: '2.25rem', // 36px
- },
- },
- },
- corePlugins: {
- // Please respect the alphabetical order in the below plugins
- preflight: false, // disable preflight
- },
- plugins: [echoesUtilities],
- content: [path.resolve(__dirname, './src/**/!(__tests__|@types|api)/*.{ts,tsx}')],
-};
diff --git a/server/sonar-web/tailwind.config.js b/server/sonar-web/tailwind.config.js
deleted file mode 100644
index 011fbbfbd72..00000000000
--- a/server/sonar-web/tailwind.config.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-/** @type {import('tailwindcss').Config} */
-module.exports = {
- important: true,
- presets: [require('./tailwind.base.config')],
-};
diff --git a/server/sonar-web/tsconfig.json b/server/sonar-web/tsconfig.json
deleted file mode 100644
index e381aa38736..00000000000
--- a/server/sonar-web/tsconfig.json
+++ /dev/null
@@ -1,121 +0,0 @@
-{
- "compilerOptions": {
- /* Visit https://aka.ms/tsconfig.json to read more about this file */
-
- /* Projects */
- // "incremental": true, /* Enable incremental compilation */
- // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
- // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
- // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
- // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
- // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
-
- /* Language and Environment */
-
-
- /* ** CAUTION: if the "target" below is changed, */
- /* we must ensure that the version of core-js */
- /* we import polyfills all its features */
- "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
- /* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/
-
-
- // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
- "jsx": "react-jsx", /* Specify what JSX code is generated. */
- // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
- // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
- // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
- // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
- // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
- // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
- // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
- // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
-
- /* Modules */
- "module": "ESNext", /* Specify what module code is generated. */
- // "rootDir": "./", /* Specify the root folder within your source files. */
- "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
- "baseUrl": ".", /* Specify the base directory to resolve non-relative module names. */
- "paths": { /* Specify a set of entries that re-map imports to additional lookup locations. */
- "~sonar-aligned/*": ["src/main/js/sonar-aligned/*"],
- "~design-system": ["src/main/js/design-system/index.ts"],
- "*": ["./src/main/js/@types/*"]
- },
- // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
- // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
- "types": [ /* Specify type package names to be included without being referenced in a source file. */
- "node",
- "jest",
- "@testing-library/jest-dom"
- ],
- // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
- // "resolveJsonModule": true, /* Enable importing .json files */
- // "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
-
- /* JavaScript Support */
- "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
- "checkJs": false, /* Enable error reporting in type-checked JavaScript files. */
- // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
-
- /* Emit */
- // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
- // "declarationMap": true, /* Create sourcemaps for d.ts files. */
- // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
- "sourceMap": true, /* Create source map files for emitted JavaScript files. */
- // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
- // "outDir": "./", /* Specify an output folder for all emitted files. */
- // "removeComments": true, /* Disable emitting comments. */
- // "noEmit": true, /* Disable emitting files from a compilation. */
- // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
- // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
- // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
- // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
- // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
- // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
- // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
- // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
- // "newLine": "crlf", /* Set the newline character for emitting files. */
- // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
- // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
- // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
- // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
- // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
- // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
-
- /* Interop Constraints */
- // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
- // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
- "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
- // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
- "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
-
- /* Type Checking */
- "strict": true, /* Enable all strict type-checking options. */
- "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
- // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
- "strictFunctionTypes": false, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
- // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
- // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
- // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
- // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
- // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
- "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
- "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
- // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
- // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
- // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
- // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
- // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
- // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
- // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
- // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
-
- /* Completeness */
- // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
- // "skipLibCheck": false /* Skip type checking all .d.ts files. */
- },
- "parserOptions": {
- "project": true
- },
- "include": ["./src/main/js/**/*"]
-}